Merge pull request #14683 from kkm000/package-grpc-tools-nits

Minor changes to control files from Tools package rework
diff --git a/.gitmodules b/.gitmodules
index c4b0d24..52db29b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,10 @@
 [submodule "third_party/zlib"]
 	path = third_party/zlib
 	url = https://github.com/madler/zlib
+	# When using CMake to build, the zlib submodule ends up with a
+	# generated file that makes Git consider the submodule dirty. This
+	# state can be ignored for day-to-day development on gRPC.
+	ignore = dirty
 [submodule "third_party/protobuf"]
 	path = third_party/protobuf
 	url = https://github.com/google/protobuf.git
diff --git a/BUILD b/BUILD
index 1779575..54215fe 100644
--- a/BUILD
+++ b/BUILD
@@ -53,12 +53,22 @@
     values = {"define": "GRPC_PORT_ISOLATED_RUNTIME=1"},
 )
 
+config_setting(
+    name = "windows",
+    values = {"cpu": "x64_windows"},
+)
+
+config_setting(
+    name = "windows_msvc",
+    values = {"cpu": "x64_windows_msvc"},
+)
+
 # This should be updated along with build.yaml
-g_stands_for = "glamorous"
+g_stands_for = "gorgeous"
 
 core_version = "6.0.0-dev"
 
-version = "1.10.0-dev"
+version = "1.11.0-dev"
 
 GPR_PUBLIC_HDRS = [
     "include/grpc/support/alloc.h",
@@ -66,34 +76,24 @@
     "include/grpc/support/atm_gcc_atomic.h",
     "include/grpc/support/atm_gcc_sync.h",
     "include/grpc/support/atm_windows.h",
-    "include/grpc/support/avl.h",
-    "include/grpc/support/cmdline.h",
     "include/grpc/support/cpu.h",
-    "include/grpc/support/host_port.h",
     "include/grpc/support/log.h",
     "include/grpc/support/log_windows.h",
     "include/grpc/support/port_platform.h",
     "include/grpc/support/string_util.h",
-    "include/grpc/support/subprocess.h",
     "include/grpc/support/sync.h",
     "include/grpc/support/sync_custom.h",
     "include/grpc/support/sync_generic.h",
     "include/grpc/support/sync_posix.h",
     "include/grpc/support/sync_windows.h",
-    "include/grpc/support/thd.h",
+    "include/grpc/support/thd_id.h",
     "include/grpc/support/time.h",
-    "include/grpc/support/tls.h",
-    "include/grpc/support/tls_gcc.h",
-    "include/grpc/support/tls_msvc.h",
-    "include/grpc/support/tls_pthread.h",
-    "include/grpc/support/useful.h",
 ]
 
 GRPC_PUBLIC_HDRS = [
     "include/grpc/byte_buffer.h",
     "include/grpc/byte_buffer_reader.h",
     "include/grpc/compression.h",
-    "include/grpc/compression_ruby.h",
     "include/grpc/fork.h",
     "include/grpc/grpc.h",
     "include/grpc/grpc_posix.h",
@@ -205,6 +205,53 @@
     "include/grpc++/support/stub_options.h",
     "include/grpc++/support/sync_stream.h",
     "include/grpc++/support/time.h",
+    "include/grpcpp/alarm.h",
+    "include/grpcpp/channel.h",
+    "include/grpcpp/client_context.h",
+    "include/grpcpp/completion_queue.h",
+    "include/grpcpp/create_channel.h",
+    "include/grpcpp/create_channel_posix.h",
+    "include/grpcpp/ext/health_check_service_server_builder_option.h",
+    "include/grpcpp/generic/async_generic_service.h",
+    "include/grpcpp/generic/generic_stub.h",
+    "include/grpcpp/grpcpp.h",
+    "include/grpcpp/health_check_service_interface.h",
+    "include/grpcpp/impl/call.h",
+    "include/grpcpp/impl/channel_argument_option.h",
+    "include/grpcpp/impl/client_unary_call.h",
+    "include/grpcpp/impl/codegen/core_codegen.h",
+    "include/grpcpp/impl/grpc_library.h",
+    "include/grpcpp/impl/method_handler_impl.h",
+    "include/grpcpp/impl/rpc_method.h",
+    "include/grpcpp/impl/rpc_service_method.h",
+    "include/grpcpp/impl/serialization_traits.h",
+    "include/grpcpp/impl/server_builder_option.h",
+    "include/grpcpp/impl/server_builder_plugin.h",
+    "include/grpcpp/impl/server_initializer.h",
+    "include/grpcpp/impl/service_type.h",
+    "include/grpcpp/impl/sync_cxx11.h",
+    "include/grpcpp/impl/sync_no_cxx11.h",
+    "include/grpcpp/resource_quota.h",
+    "include/grpcpp/security/auth_context.h",
+    "include/grpcpp/security/auth_metadata_processor.h",
+    "include/grpcpp/security/credentials.h",
+    "include/grpcpp/security/server_credentials.h",
+    "include/grpcpp/server.h",
+    "include/grpcpp/server_builder.h",
+    "include/grpcpp/server_context.h",
+    "include/grpcpp/server_posix.h",
+    "include/grpcpp/support/async_stream.h",
+    "include/grpcpp/support/async_unary_call.h",
+    "include/grpcpp/support/byte_buffer.h",
+    "include/grpcpp/support/channel_arguments.h",
+    "include/grpcpp/support/config.h",
+    "include/grpcpp/support/slice.h",
+    "include/grpcpp/support/status.h",
+    "include/grpcpp/support/status_code_enum.h",
+    "include/grpcpp/support/string_ref.h",
+    "include/grpcpp/support/stub_options.h",
+    "include/grpcpp/support/sync_stream.h",
+    "include/grpcpp/support/time.h",
 ]
 
 grpc_cc_library(
@@ -260,8 +307,16 @@
     language = "c++",
     deps = [
         "grpc_base",
+        "grpc_deadline_filter",
+        "grpc_lb_policy_pick_first",
         "grpc_http_filters",
+        "grpc_max_age_filter",
+        "grpc_message_size_filter",
+        "grpc_resolver_dns_native",
+        "grpc_resolver_sockaddr",
+        "grpc_server_load_reporting",
         "grpc_transport_chttp2_client_secure",
+        "grpc_transport_chttp2_server_secure",
         "grpc_transport_cronet_client_secure",
     ],
 )
@@ -327,6 +382,7 @@
     ],
     hdrs = [
         "include/grpc++/support/error_details.h",
+        "include/grpcpp/support/error_details.h",
     ],
     language = "c++",
     standalone = True,
@@ -453,13 +509,9 @@
 grpc_cc_library(
     name = "gpr_base",
     srcs = [
-        "src/core/lib/profiling/basic_timers.cc",
-        "src/core/lib/profiling/stap_timers.cc",
         "src/core/lib/gpr/alloc.cc",
         "src/core/lib/gpr/arena.cc",
         "src/core/lib/gpr/atm.cc",
-        "src/core/lib/gpr/avl.cc",
-        "src/core/lib/gpr/cmdline.cc",
         "src/core/lib/gpr/cpu_iphone.cc",
         "src/core/lib/gpr/cpu_linux.cc",
         "src/core/lib/gpr/cpu_posix.cc",
@@ -480,14 +532,9 @@
         "src/core/lib/gpr/string_posix.cc",
         "src/core/lib/gpr/string_util_windows.cc",
         "src/core/lib/gpr/string_windows.cc",
-        "src/core/lib/gpr/subprocess_posix.cc",
-        "src/core/lib/gpr/subprocess_windows.cc",
         "src/core/lib/gpr/sync.cc",
         "src/core/lib/gpr/sync_posix.cc",
         "src/core/lib/gpr/sync_windows.cc",
-        "src/core/lib/gpr/thd.cc",
-        "src/core/lib/gpr/thd_posix.cc",
-        "src/core/lib/gpr/thd_windows.cc",
         "src/core/lib/gpr/time.cc",
         "src/core/lib/gpr/time_posix.cc",
         "src/core/lib/gpr/time_precise.cc",
@@ -497,20 +544,33 @@
         "src/core/lib/gpr/tmpfile_posix.cc",
         "src/core/lib/gpr/tmpfile_windows.cc",
         "src/core/lib/gpr/wrap_memcpy.cc",
+        "src/core/lib/gprpp/thd_posix.cc",
+        "src/core/lib/gprpp/thd_windows.cc",
+        "src/core/lib/profiling/basic_timers.cc",
+        "src/core/lib/profiling/stap_timers.cc",
     ],
     hdrs = [
-        "src/core/lib/profiling/timers.h",
         "src/core/lib/gpr/arena.h",
         "src/core/lib/gpr/env.h",
         "src/core/lib/gpr/fork.h",
+        "src/core/lib/gpr/host_port.h",
         "src/core/lib/gpr/mpscq.h",
         "src/core/lib/gpr/murmur_hash.h",
         "src/core/lib/gpr/spinlock.h",
         "src/core/lib/gpr/string.h",
         "src/core/lib/gpr/string_windows.h",
-        "src/core/lib/gpr/thd_internal.h",
         "src/core/lib/gpr/time_precise.h",
+        "src/core/lib/gpr/tls.h",
+        "src/core/lib/gpr/tls_gcc.h",
+        "src/core/lib/gpr/tls_msvc.h",
+        "src/core/lib/gpr/tls_pthread.h",
         "src/core/lib/gpr/tmpfile.h",
+        "src/core/lib/gpr/useful.h",
+        "src/core/lib/gprpp/abstract.h",
+        "src/core/lib/gprpp/manual_constructor.h",
+        "src/core/lib/gprpp/memory.h",
+        "src/core/lib/gprpp/thd.h",
+        "src/core/lib/profiling/timers.h",
     ],
     language = "c++",
     public_hdrs = GPR_PUBLIC_HDRS,
@@ -552,25 +612,15 @@
 )
 
 grpc_cc_library(
-    name = "gpr++_base",
-    language = "c++",
-    public_hdrs = [
-        "src/core/lib/gprpp/abstract.h",
-        "src/core/lib/gprpp/manual_constructor.h",
-        "src/core/lib/gprpp/memory.h",
-    ],
-)
-
-grpc_cc_library(
     name = "atomic",
-    language = "c++",
-    public_hdrs = [
-        "src/core/lib/gprpp/atomic.h",
-    ],
     hdrs = [
         "src/core/lib/gprpp/atomic_with_atm.h",
         "src/core/lib/gprpp/atomic_with_std.h",
     ],
+    language = "c++",
+    public_hdrs = [
+        "src/core/lib/gprpp/atomic.h",
+    ],
     deps = [
         "gpr",
     ],
@@ -583,7 +633,7 @@
         "src/core/lib/gprpp/inlined_vector.h",
     ],
     deps = [
-        "gpr++_base",
+        "gpr_base",
     ],
 )
 
@@ -599,8 +649,9 @@
     public_hdrs = ["src/core/lib/gprpp/orphanable.h"],
     deps = [
         "debug_location",
-        "gpr++_base",
+        "gpr_base",
         "grpc_trace",
+        "ref_counted_ptr",
     ],
 )
 
@@ -610,8 +661,9 @@
     public_hdrs = ["src/core/lib/gprpp/ref_counted.h"],
     deps = [
         "debug_location",
-        "gpr++_base",
+        "gpr_base",
         "grpc_trace",
+        "ref_counted_ptr",
     ],
 )
 
@@ -620,24 +672,27 @@
     language = "c++",
     public_hdrs = ["src/core/lib/gprpp/ref_counted_ptr.h"],
     deps = [
-        "gpr++_base",
+        "gpr_base",
     ],
 )
 
 grpc_cc_library(
     name = "grpc_base_c",
     srcs = [
+        "src/core/lib/avl/avl.cc",
         "src/core/lib/backoff/backoff.cc",
         "src/core/lib/channel/channel_args.cc",
         "src/core/lib/channel/channel_stack.cc",
         "src/core/lib/channel/channel_stack_builder.cc",
+        "src/core/lib/channel/channel_trace.cc",
+        "src/core/lib/channel/channel_trace_registry.cc",
+        "src/core/lib/channel/status_util.cc",
         "src/core/lib/channel/connected_channel.cc",
         "src/core/lib/channel/handshaker.cc",
         "src/core/lib/channel/handshaker_factory.cc",
         "src/core/lib/channel/handshaker_registry.cc",
         "src/core/lib/compression/compression.cc",
         "src/core/lib/compression/compression_internal.cc",
-        "src/core/lib/compression/compression_ruby.cc",
         "src/core/lib/compression/message_compress.cc",
         "src/core/lib/compression/stream_compression.cc",
         "src/core/lib/compression/stream_compression_gzip.cc",
@@ -669,20 +724,25 @@
         "src/core/lib/iomgr/gethostname_sysconf.cc",
         "src/core/lib/iomgr/iocp_windows.cc",
         "src/core/lib/iomgr/iomgr.cc",
+        "src/core/lib/iomgr/iomgr_custom.cc",
+        "src/core/lib/iomgr/iomgr_internal.cc",
         "src/core/lib/iomgr/iomgr_posix.cc",
-        "src/core/lib/iomgr/iomgr_uv.cc",
         "src/core/lib/iomgr/iomgr_windows.cc",
         "src/core/lib/iomgr/is_epollexclusive_available.cc",
         "src/core/lib/iomgr/load_file.cc",
         "src/core/lib/iomgr/lockfree_event.cc",
         "src/core/lib/iomgr/network_status_tracker.cc",
         "src/core/lib/iomgr/polling_entity.cc",
-        "src/core/lib/iomgr/pollset_set_uv.cc",
+        "src/core/lib/iomgr/pollset.cc",
+        "src/core/lib/iomgr/pollset_custom.cc",
+        "src/core/lib/iomgr/pollset_set.cc",
+        "src/core/lib/iomgr/pollset_set_custom.cc",
         "src/core/lib/iomgr/pollset_set_windows.cc",
         "src/core/lib/iomgr/pollset_uv.cc",
         "src/core/lib/iomgr/pollset_windows.cc",
+        "src/core/lib/iomgr/resolve_address.cc",
+        "src/core/lib/iomgr/resolve_address_custom.cc",
         "src/core/lib/iomgr/resolve_address_posix.cc",
-        "src/core/lib/iomgr/resolve_address_uv.cc",
         "src/core/lib/iomgr/resolve_address_windows.cc",
         "src/core/lib/iomgr/resource_quota.cc",
         "src/core/lib/iomgr/sockaddr_utils.cc",
@@ -691,22 +751,26 @@
         "src/core/lib/iomgr/socket_utils_common_posix.cc",
         "src/core/lib/iomgr/socket_utils_linux.cc",
         "src/core/lib/iomgr/socket_utils_posix.cc",
-        "src/core/lib/iomgr/socket_utils_uv.cc",
         "src/core/lib/iomgr/socket_utils_windows.cc",
         "src/core/lib/iomgr/socket_windows.cc",
+        "src/core/lib/iomgr/tcp_client.cc",
+        "src/core/lib/iomgr/tcp_client_custom.cc",
         "src/core/lib/iomgr/tcp_client_posix.cc",
-        "src/core/lib/iomgr/tcp_client_uv.cc",
         "src/core/lib/iomgr/tcp_client_windows.cc",
+        "src/core/lib/iomgr/tcp_custom.cc",
         "src/core/lib/iomgr/tcp_posix.cc",
+        "src/core/lib/iomgr/tcp_server.cc",
+        "src/core/lib/iomgr/tcp_server_custom.cc",
         "src/core/lib/iomgr/tcp_server_posix.cc",
         "src/core/lib/iomgr/tcp_server_utils_posix_common.cc",
         "src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc",
         "src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc",
-        "src/core/lib/iomgr/tcp_server_uv.cc",
         "src/core/lib/iomgr/tcp_server_windows.cc",
         "src/core/lib/iomgr/tcp_uv.cc",
         "src/core/lib/iomgr/tcp_windows.cc",
         "src/core/lib/iomgr/time_averaged_stats.cc",
+        "src/core/lib/iomgr/timer.cc",
+        "src/core/lib/iomgr/timer_custom.cc",
         "src/core/lib/iomgr/timer_generic.cc",
         "src/core/lib/iomgr/timer_heap.cc",
         "src/core/lib/iomgr/timer_manager.cc",
@@ -727,7 +791,6 @@
         "src/core/lib/slice/percent_encoding.cc",
         "src/core/lib/slice/slice.cc",
         "src/core/lib/slice/slice_buffer.cc",
-        "src/core/lib/slice/slice_hash_table.cc",
         "src/core/lib/slice/slice_intern.cc",
         "src/core/lib/slice/slice_string_helpers.cc",
         "src/core/lib/surface/api_trace.cc",
@@ -757,15 +820,20 @@
         "src/core/lib/transport/service_config.cc",
         "src/core/lib/transport/static_metadata.cc",
         "src/core/lib/transport/status_conversion.cc",
+        "src/core/lib/transport/status_metadata.cc",
         "src/core/lib/transport/timeout_encoding.cc",
         "src/core/lib/transport/transport.cc",
         "src/core/lib/transport/transport_op_string.cc",
     ],
     hdrs = [
+        "src/core/lib/avl/avl.h",
         "src/core/lib/backoff/backoff.h",
         "src/core/lib/channel/channel_args.h",
         "src/core/lib/channel/channel_stack.h",
         "src/core/lib/channel/channel_stack_builder.h",
+        "src/core/lib/channel/channel_trace.h",
+        "src/core/lib/channel/channel_trace_registry.h",
+        "src/core/lib/channel/status_util.h",
         "src/core/lib/channel/connected_channel.h",
         "src/core/lib/channel/context.h",
         "src/core/lib/channel/handshaker.h",
@@ -800,9 +868,9 @@
         "src/core/lib/iomgr/gethostname.h",
         "src/core/lib/iomgr/iocp_windows.h",
         "src/core/lib/iomgr/iomgr.h",
+        "src/core/lib/iomgr/iomgr_custom.h",
         "src/core/lib/iomgr/iomgr_internal.h",
         "src/core/lib/iomgr/iomgr_posix.h",
-        "src/core/lib/iomgr/iomgr_uv.h",
         "src/core/lib/iomgr/is_epollexclusive_available.h",
         "src/core/lib/iomgr/load_file.h",
         "src/core/lib/iomgr/lockfree_event.h",
@@ -810,14 +878,18 @@
         "src/core/lib/iomgr/network_status_tracker.h",
         "src/core/lib/iomgr/polling_entity.h",
         "src/core/lib/iomgr/pollset.h",
+        "src/core/lib/iomgr/pollset_custom.h",
         "src/core/lib/iomgr/pollset_set.h",
+        "src/core/lib/iomgr/pollset_set_custom.h",
         "src/core/lib/iomgr/pollset_set_windows.h",
         "src/core/lib/iomgr/pollset_uv.h",
         "src/core/lib/iomgr/pollset_windows.h",
         "src/core/lib/iomgr/port.h",
         "src/core/lib/iomgr/resolve_address.h",
+        "src/core/lib/iomgr/resolve_address_custom.h",
         "src/core/lib/iomgr/resource_quota.h",
         "src/core/lib/iomgr/sockaddr.h",
+        "src/core/lib/iomgr/sockaddr_custom.h",
         "src/core/lib/iomgr/sockaddr_posix.h",
         "src/core/lib/iomgr/sockaddr_utils.h",
         "src/core/lib/iomgr/sockaddr_windows.h",
@@ -829,17 +901,17 @@
         "src/core/lib/iomgr/sys_epoll_wrapper.h",
         "src/core/lib/iomgr/tcp_client.h",
         "src/core/lib/iomgr/tcp_client_posix.h",
+        "src/core/lib/iomgr/tcp_custom.h",
         "src/core/lib/iomgr/tcp_posix.h",
         "src/core/lib/iomgr/tcp_server.h",
         "src/core/lib/iomgr/tcp_server_utils_posix.h",
-        "src/core/lib/iomgr/tcp_uv.h",
         "src/core/lib/iomgr/tcp_windows.h",
         "src/core/lib/iomgr/time_averaged_stats.h",
         "src/core/lib/iomgr/timer.h",
+        "src/core/lib/iomgr/timer_custom.h",
         "src/core/lib/iomgr/timer_generic.h",
         "src/core/lib/iomgr/timer_heap.h",
         "src/core/lib/iomgr/timer_manager.h",
-        "src/core/lib/iomgr/timer_uv.h",
         "src/core/lib/iomgr/udp_server.h",
         "src/core/lib/iomgr/unix_sockets_posix.h",
         "src/core/lib/iomgr/wakeup_fd_cv.h",
@@ -854,6 +926,7 @@
         "src/core/lib/slice/slice_hash_table.h",
         "src/core/lib/slice/slice_internal.h",
         "src/core/lib/slice/slice_string_helpers.h",
+        "src/core/lib/slice/slice_weak_hash_table.h",
         "src/core/lib/surface/api_trace.h",
         "src/core/lib/surface/call.h",
         "src/core/lib/surface/call_test_only.h",
@@ -878,6 +951,7 @@
         "src/core/lib/transport/service_config.h",
         "src/core/lib/transport/static_metadata.h",
         "src/core/lib/transport/status_conversion.h",
+        "src/core/lib/transport/status_metadata.h",
         "src/core/lib/transport/timeout_encoding.h",
         "src/core/lib/transport/transport.h",
         "src/core/lib/transport/transport_impl.h",
@@ -889,9 +963,12 @@
     public_hdrs = GRPC_PUBLIC_HDRS,
     deps = [
         "gpr_base",
-        "gpr++_base",
         "grpc_codegen",
         "grpc_trace",
+        "inlined_vector",
+        "orphanable",
+        "ref_counted",
+        "ref_counted_ptr",
     ],
 )
 
@@ -946,11 +1023,11 @@
         "src/core/ext/filters/client_channel/lb_policy.cc",
         "src/core/ext/filters/client_channel/lb_policy_factory.cc",
         "src/core/ext/filters/client_channel/lb_policy_registry.cc",
+        "src/core/ext/filters/client_channel/method_params.cc",
         "src/core/ext/filters/client_channel/parse_address.cc",
         "src/core/ext/filters/client_channel/proxy_mapper.cc",
         "src/core/ext/filters/client_channel/proxy_mapper_registry.cc",
         "src/core/ext/filters/client_channel/resolver.cc",
-        "src/core/ext/filters/client_channel/resolver_factory.cc",
         "src/core/ext/filters/client_channel/resolver_registry.cc",
         "src/core/ext/filters/client_channel/retry_throttle.cc",
         "src/core/ext/filters/client_channel/subchannel.cc",
@@ -967,6 +1044,7 @@
         "src/core/ext/filters/client_channel/lb_policy.h",
         "src/core/ext/filters/client_channel/lb_policy_factory.h",
         "src/core/ext/filters/client_channel/lb_policy_registry.h",
+        "src/core/ext/filters/client_channel/method_params.h",
         "src/core/ext/filters/client_channel/parse_address.h",
         "src/core/ext/filters/client_channel/proxy_mapper.h",
         "src/core/ext/filters/client_channel/proxy_mapper_registry.h",
@@ -980,8 +1058,11 @@
     ],
     language = "c++",
     deps = [
+        "gpr_base",
         "grpc_base",
         "grpc_deadline_filter",
+        "inlined_vector",
+        "orphanable",
         "ref_counted",
         "ref_counted_ptr",
     ],
@@ -1093,7 +1174,6 @@
     ],
     hdrs = [
         "src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h",
-        "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h",
         "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h",
         "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h",
         "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h",
@@ -1122,7 +1202,6 @@
     ],
     hdrs = [
         "src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h",
-        "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h",
         "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h",
         "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h",
         "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h",
@@ -1223,6 +1302,7 @@
     ],
     external_deps = [
         "cares",
+        "address_sorting",
     ],
     language = "c++",
     deps = [
@@ -1273,12 +1353,14 @@
         "src/core/lib/security/credentials/oauth2/oauth2_credentials.cc",
         "src/core/lib/security/credentials/plugin/plugin_credentials.cc",
         "src/core/lib/security/credentials/ssl/ssl_credentials.cc",
+        "src/core/lib/security/credentials/alts/alts_credentials.cc",
+        "src/core/lib/security/security_connector/alts_security_connector.cc",
+        "src/core/lib/security/security_connector/security_connector.cc",
         "src/core/lib/security/transport/client_auth_filter.cc",
-        "src/core/lib/security/transport/lb_targets_info.cc",
         "src/core/lib/security/transport/secure_endpoint.cc",
-        "src/core/lib/security/transport/security_connector.cc",
         "src/core/lib/security/transport/security_handshaker.cc",
         "src/core/lib/security/transport/server_auth_filter.cc",
+        "src/core/lib/security/transport/target_authority_table.cc",
         "src/core/lib/security/transport/tsi_error.cc",
         "src/core/lib/security/util/json_util.cc",
         "src/core/lib/surface/init_secure.cc",
@@ -1296,17 +1378,20 @@
         "src/core/lib/security/credentials/oauth2/oauth2_credentials.h",
         "src/core/lib/security/credentials/plugin/plugin_credentials.h",
         "src/core/lib/security/credentials/ssl/ssl_credentials.h",
+        "src/core/lib/security/credentials/alts/alts_credentials.h",
+        "src/core/lib/security/security_connector/alts_security_connector.h",
+        "src/core/lib/security/security_connector/security_connector.h",
         "src/core/lib/security/transport/auth_filters.h",
-        "src/core/lib/security/transport/lb_targets_info.h",
         "src/core/lib/security/transport/secure_endpoint.h",
-        "src/core/lib/security/transport/security_connector.h",
         "src/core/lib/security/transport/security_handshaker.h",
+        "src/core/lib/security/transport/target_authority_table.h",
         "src/core/lib/security/transport/tsi_error.h",
         "src/core/lib/security/util/json_util.h",
     ],
     language = "c++",
     public_hdrs = GRPC_SECURE_PUBLIC_HDRS,
     deps = [
+        "alts_util",
         "grpc_base",
         "grpc_transport_chttp2_alpn",
         "tsi",
@@ -1363,7 +1448,7 @@
     ],
     language = "c++",
     deps = [
-        "gpr++_base",
+        "gpr_base",
         "grpc_base",
         "grpc_http_filters",
         "grpc_transport_chttp2_alpn",
@@ -1530,16 +1615,124 @@
 )
 
 grpc_cc_library(
+    name = "alts_frame_protector",
+    srcs = [
+        "src/core/tsi/alts/crypt/aes_gcm.cc",
+        "src/core/tsi/alts/crypt/gsec.cc",
+        "src/core/tsi/alts/frame_protector/alts_counter.cc",
+        "src/core/tsi/alts/frame_protector/alts_crypter.cc",
+        "src/core/tsi/alts/frame_protector/alts_frame_protector.cc",
+        "src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc",
+        "src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc",
+        "src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc",
+        "src/core/tsi/alts/frame_protector/frame_handler.cc",
+        "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc",
+        "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc",
+        "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc",
+        "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc",
+        "src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc",
+    ],
+    hdrs = [
+        "src/core/tsi/alts/crypt/gsec.h",
+        "src/core/tsi/alts/frame_protector/alts_counter.h",
+        "src/core/tsi/alts/frame_protector/alts_crypter.h",
+        "src/core/tsi/alts/frame_protector/alts_frame_protector.h",
+        "src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h",
+        "src/core/tsi/alts/frame_protector/frame_handler.h",
+        "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h",
+        "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h",
+        "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h",
+        "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h",
+        "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h",
+        "src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h",
+        "src/core/tsi/transport_security_grpc.h",
+    ],
+    external_deps = [
+        "libssl",
+    ],
+    language = "c++",
+    deps = [
+        "gpr",
+        "grpc_base",
+        "tsi_interface",
+    ],
+)
+
+grpc_cc_library(
+    name = "alts_proto",
+    srcs = [
+        "src/core/tsi/alts/handshaker/altscontext.pb.c",
+        "src/core/tsi/alts/handshaker/handshaker.pb.c",
+        "src/core/tsi/alts/handshaker/transport_security_common.pb.c",
+    ],
+    hdrs = [
+        "src/core/tsi/alts/handshaker/altscontext.pb.h",
+        "src/core/tsi/alts/handshaker/handshaker.pb.h",
+        "src/core/tsi/alts/handshaker/transport_security_common.pb.h",
+    ],
+    external_deps = [
+        "nanopb",
+    ],
+    language = "c++",
+)
+
+grpc_cc_library(
+    name = "alts_util",
+    srcs = [
+        "src/core/lib/security/credentials/alts/check_gcp_environment.cc",
+        "src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc",
+        "src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc",
+        "src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc",
+        "src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc",
+        "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc",
+        "src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc",
+        "src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc",
+        "src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc",
+        "src/core/tsi/alts/handshaker/transport_security_common_api.cc",
+    ],
+    hdrs = [
+        "src/core/lib/security/credentials/alts/check_gcp_environment.h",
+        "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h",
+        "src/core/tsi/alts/handshaker/alts_handshaker_service_api.h",
+        "src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h",
+        "src/core/tsi/alts/handshaker/transport_security_common_api.h",
+    ],
+    external_deps = [
+        "nanopb",
+    ],
+    language = "c++",
+    deps = [
+      "alts_proto",
+      "gpr",
+      "grpc_base",
+    ],
+)
+
+grpc_cc_library(
     name = "tsi",
     srcs = [
         "src/core/tsi/alts_transport_security.cc",
+        "src/core/tsi/alts/handshaker/alts_handshaker_client.cc",
+        "src/core/tsi/alts/handshaker/alts_tsi_event.cc",
+        "src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc",
+        "src/core/tsi/alts/handshaker/alts_tsi_utils.cc",
         "src/core/tsi/fake_transport_security.cc",
+        "src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc",
+        "src/core/tsi/ssl/session_cache/ssl_session_cache.cc",
+        "src/core/tsi/ssl/session_cache/ssl_session_openssl.cc",
         "src/core/tsi/ssl_transport_security.cc",
         "src/core/tsi/transport_security_grpc.cc",
     ],
     hdrs = [
         "src/core/tsi/alts_transport_security.h",
+        "src/core/tsi/alts/handshaker/alts_handshaker_client.h",
+        "src/core/tsi/alts/handshaker/alts_tsi_event.h",
+        "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h",
+        "src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h",
+        "src/core/tsi/alts/handshaker/alts_tsi_utils.h",
         "src/core/tsi/fake_transport_security.h",
+        "src/core/tsi/ssl/session_cache/ssl_session.h",
+        "src/core/tsi/ssl/session_cache/ssl_session_cache.h",
         "src/core/tsi/ssl_transport_security.h",
         "src/core/tsi/ssl_types.h",
         "src/core/tsi/transport_security_grpc.h",
@@ -1549,7 +1742,11 @@
     ],
     language = "c++",
     deps = [
+        "alts_frame_protector",
+        "alts_util",
+        "gpr",
         "grpc_base",
+        "grpc_transport_chttp2_client_insecure",
         "tsi_interface",
     ],
 )
@@ -1612,6 +1809,36 @@
         "include/grpc++/impl/codegen/stub_options.h",
         "include/grpc++/impl/codegen/sync_stream.h",
         "include/grpc++/impl/codegen/time.h",
+        "include/grpcpp/impl/codegen/async_stream.h",
+        "include/grpcpp/impl/codegen/async_unary_call.h",
+        "include/grpcpp/impl/codegen/byte_buffer.h",
+        "include/grpcpp/impl/codegen/call.h",
+        "include/grpcpp/impl/codegen/call_hook.h",
+        "include/grpcpp/impl/codegen/channel_interface.h",
+        "include/grpcpp/impl/codegen/client_context.h",
+        "include/grpcpp/impl/codegen/client_unary_call.h",
+        "include/grpcpp/impl/codegen/completion_queue.h",
+        "include/grpcpp/impl/codegen/completion_queue_tag.h",
+        "include/grpcpp/impl/codegen/config.h",
+        "include/grpcpp/impl/codegen/core_codegen_interface.h",
+        "include/grpcpp/impl/codegen/create_auth_context.h",
+        "include/grpcpp/impl/codegen/grpc_library.h",
+        "include/grpcpp/impl/codegen/metadata_map.h",
+        "include/grpcpp/impl/codegen/method_handler_impl.h",
+        "include/grpcpp/impl/codegen/rpc_method.h",
+        "include/grpcpp/impl/codegen/rpc_service_method.h",
+        "include/grpcpp/impl/codegen/security/auth_context.h",
+        "include/grpcpp/impl/codegen/serialization_traits.h",
+        "include/grpcpp/impl/codegen/server_context.h",
+        "include/grpcpp/impl/codegen/server_interface.h",
+        "include/grpcpp/impl/codegen/service_type.h",
+        "include/grpcpp/impl/codegen/slice.h",
+        "include/grpcpp/impl/codegen/status.h",
+        "include/grpcpp/impl/codegen/status_code_enum.h",
+        "include/grpcpp/impl/codegen/string_ref.h",
+        "include/grpcpp/impl/codegen/stub_options.h",
+        "include/grpcpp/impl/codegen/sync_stream.h",
+        "include/grpcpp/impl/codegen/time.h",
     ],
     deps = [
         "grpc_codegen",
@@ -1634,6 +1861,7 @@
     language = "c++",
     public_hdrs = [
         "include/grpc++/impl/codegen/proto_utils.h",
+        "include/grpcpp/impl/codegen/proto_utils.h",
     ],
     deps = [
         "grpc++_codegen_base",
@@ -1649,6 +1877,7 @@
     language = "c++",
     public_hdrs = [
         "include/grpc++/impl/codegen/config_protobuf.h",
+        "include/grpcpp/impl/codegen/config_protobuf.h",
     ],
 )
 
@@ -1664,6 +1893,7 @@
     language = "c++",
     public_hdrs = [
         "include/grpc++/ext/proto_server_reflection_plugin.h",
+        "include/grpcpp/ext/proto_server_reflection_plugin.h",
     ],
     deps = [
         ":grpc++",
@@ -1677,6 +1907,8 @@
     public_hdrs = [
         "include/grpc++/test/mock_stream.h",
         "include/grpc++/test/server_context_test_spouse.h",
+        "include/grpcpp/test/mock_stream.h",
+        "include/grpcpp/test/server_context_test_spouse.h",
     ],
     deps = [
         ":grpc++",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0924f7d..56dd61e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -24,19 +24,20 @@
 cmake_minimum_required(VERSION 2.8)
 
 set(PACKAGE_NAME      "grpc")
-set(PACKAGE_VERSION   "1.10.0-dev")
+set(PACKAGE_VERSION   "1.11.0-dev")
 set(PACKAGE_STRING    "${PACKAGE_NAME} ${PACKAGE_VERSION}")
 set(PACKAGE_TARNAME   "${PACKAGE_NAME}-${PACKAGE_VERSION}")
 set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/")
 project(${PACKAGE_NAME} C CXX)
 
-set(gRPC_INSTALL_BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables")
-set(gRPC_INSTALL_LIBDIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries")
-set(gRPC_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "Installation directory for headers")
-set(gRPC_INSTALL_CMAKEDIR "${CMAKE_INSTALL_PREFIX}/lib/cmake/${PACKAGE_NAME}" CACHE PATH "Installation directory for cmake config files")
+set(gRPC_INSTALL_BINDIR "bin" CACHE STRING "Installation directory for executables")
+set(gRPC_INSTALL_LIBDIR "lib" CACHE STRING "Installation directory for libraries")
+set(gRPC_INSTALL_INCLUDEDIR "include" CACHE STRING "Installation directory for headers")
+set(gRPC_INSTALL_CMAKEDIR "lib/cmake/${PACKAGE_NAME}" CACHE STRING "Installation directory for cmake config files")
 
 # Options
 option(gRPC_BUILD_TESTS "Build tests" OFF)
+option(gRPC_BUILD_CODEGEN "Build codegen" ON)
 
 set(gRPC_INSTALL_default ON)
 if (NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
@@ -78,6 +79,8 @@
     set(_gRPC_PLATFORM_LINUX ON)
   elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
     set(_gRPC_PLATFORM_MAC ON)
+  elseif(${CMAKE_SYSTEM_NAME} MATCHES "Android")
+    set(_gRPC_PLATFORM_ANDROID ON)
   else()
     set(_gRPC_PLATFORM_POSIX ON)
   endif()
@@ -88,6 +91,8 @@
 
 set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
 
+add_definitions(-DPB_FIELD_16BIT)
+
 if (MSVC)
   include(cmake/msvc_static_runtime.cmake)
   add_definitions(-D_WIN32_WINNT=0x600 -D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -D_WINSOCK_DEPRECATED_NO_WARNINGS)
@@ -112,6 +117,7 @@
 include(cmake/ssl.cmake)
 include(cmake/gflags.cmake)
 include(cmake/benchmark.cmake)
+include(cmake/address_sorting.cmake)
 
 if(NOT MSVC)
   set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS} -std=c99")
@@ -120,6 +126,8 @@
 
 if(_gRPC_PLATFORM_MAC)
   set(_gRPC_ALLTARGETS_LIBRARIES ${CMAKE_DL_LIBS} m pthread)
+elseif(_gRPC_PLATFORM_ANDROID)
+  set(_gRPC_ALLTARGETS_LIBRARIES ${CMAKE_DL_LIBS} m)
 elseif(UNIX)
   set(_gRPC_ALLTARGETS_LIBRARIES ${CMAKE_DL_LIBS} rt m pthread)
 endif()
@@ -213,14 +221,15 @@
 add_dependencies(buildtests_c alloc_test)
 add_dependencies(buildtests_c alpn_test)
 add_dependencies(buildtests_c arena_test)
+add_dependencies(buildtests_c avl_test)
 add_dependencies(buildtests_c bad_server_response_test)
 add_dependencies(buildtests_c bin_decoder_test)
 add_dependencies(buildtests_c bin_encoder_test)
-add_dependencies(buildtests_c byte_stream_test)
 add_dependencies(buildtests_c channel_create_test)
 add_dependencies(buildtests_c chttp2_hpack_encoder_test)
 add_dependencies(buildtests_c chttp2_stream_map_test)
 add_dependencies(buildtests_c chttp2_varint_test)
+add_dependencies(buildtests_c cmdline_test)
 add_dependencies(buildtests_c combiner_test)
 add_dependencies(buildtests_c compression_test)
 add_dependencies(buildtests_c concurrent_connectivity_test)
@@ -257,8 +266,6 @@
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 add_dependencies(buildtests_c goaway_server_test)
 endif()
-add_dependencies(buildtests_c gpr_avl_test)
-add_dependencies(buildtests_c gpr_cmdline_test)
 add_dependencies(buildtests_c gpr_cpu_test)
 add_dependencies(buildtests_c gpr_env_test)
 add_dependencies(buildtests_c gpr_host_port_test)
@@ -344,7 +351,6 @@
 add_dependencies(buildtests_c server_chttp2_test)
 add_dependencies(buildtests_c server_test)
 add_dependencies(buildtests_c slice_buffer_test)
-add_dependencies(buildtests_c slice_hash_table_test)
 add_dependencies(buildtests_c slice_string_helpers_test)
 add_dependencies(buildtests_c slice_test)
 add_dependencies(buildtests_c sockaddr_resolver_test)
@@ -388,6 +394,7 @@
 add_dependencies(buildtests_c public_headers_must_be_c89)
 add_dependencies(buildtests_c badreq_bad_client_test)
 add_dependencies(buildtests_c connection_prefix_bad_client_test)
+add_dependencies(buildtests_c duplicate_header_bad_client_test)
 add_dependencies(buildtests_c head_of_line_blocking_bad_client_test)
 add_dependencies(buildtests_c headers_bad_client_test)
 add_dependencies(buildtests_c initial_settings_frame_bad_client_test)
@@ -464,6 +471,19 @@
 
 add_custom_target(buildtests_cxx)
 add_dependencies(buildtests_cxx alarm_test)
+add_dependencies(buildtests_cxx alts_counter_test)
+add_dependencies(buildtests_cxx alts_crypt_test)
+add_dependencies(buildtests_cxx alts_crypter_test)
+add_dependencies(buildtests_cxx alts_frame_handler_test)
+add_dependencies(buildtests_cxx alts_frame_protector_test)
+add_dependencies(buildtests_cxx alts_grpc_record_protocol_test)
+add_dependencies(buildtests_cxx alts_handshaker_client_test)
+add_dependencies(buildtests_cxx alts_handshaker_service_api_test)
+add_dependencies(buildtests_cxx alts_iovec_record_protocol_test)
+add_dependencies(buildtests_cxx alts_security_connector_test)
+add_dependencies(buildtests_cxx alts_tsi_handshaker_test)
+add_dependencies(buildtests_cxx alts_tsi_utils_test)
+add_dependencies(buildtests_cxx alts_zero_copy_grpc_protector_test)
 add_dependencies(buildtests_cxx async_end2end_test)
 add_dependencies(buildtests_cxx auth_property_iterator_test)
 add_dependencies(buildtests_cxx backoff_test)
@@ -510,8 +530,12 @@
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 add_dependencies(buildtests_cxx bm_pollset)
 endif()
+add_dependencies(buildtests_cxx byte_stream_test)
 add_dependencies(buildtests_cxx channel_arguments_test)
 add_dependencies(buildtests_cxx channel_filter_test)
+add_dependencies(buildtests_cxx channel_trace_test)
+add_dependencies(buildtests_cxx check_gcp_environment_linux_test)
+add_dependencies(buildtests_cxx check_gcp_environment_windows_test)
 add_dependencies(buildtests_cxx chttp2_settings_timeout_test)
 add_dependencies(buildtests_cxx cli_call_test)
 add_dependencies(buildtests_cxx client_channel_stress_test)
@@ -533,12 +557,13 @@
 add_dependencies(buildtests_cxx filter_end2end_test)
 add_dependencies(buildtests_cxx generic_end2end_test)
 add_dependencies(buildtests_cxx golden_file_test)
+add_dependencies(buildtests_cxx grpc_alts_credentials_options_test)
 add_dependencies(buildtests_cxx grpc_cli)
 add_dependencies(buildtests_cxx grpc_tool_test)
 add_dependencies(buildtests_cxx grpclb_api_test)
 add_dependencies(buildtests_cxx grpclb_end2end_test)
-add_dependencies(buildtests_cxx grpclb_test)
 add_dependencies(buildtests_cxx h2_ssl_cert_test)
+add_dependencies(buildtests_cxx h2_ssl_session_reuse_test)
 add_dependencies(buildtests_cxx health_service_end2end_test)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 add_dependencies(buildtests_cxx http2_client)
@@ -563,6 +588,7 @@
 add_dependencies(buildtests_cxx memory_test)
 add_dependencies(buildtests_cxx metrics_client)
 add_dependencies(buildtests_cxx mock_test)
+add_dependencies(buildtests_cxx nonblocking_test)
 add_dependencies(buildtests_cxx noop-benchmark)
 add_dependencies(buildtests_cxx orphanable_test)
 add_dependencies(buildtests_cxx proto_server_reflection_test)
@@ -593,8 +619,11 @@
 add_dependencies(buildtests_cxx server_early_return_test)
 add_dependencies(buildtests_cxx server_request_call_test)
 add_dependencies(buildtests_cxx shutdown_test)
+add_dependencies(buildtests_cxx slice_hash_table_test)
+add_dependencies(buildtests_cxx slice_weak_hash_table_test)
 add_dependencies(buildtests_cxx stats_test)
-add_dependencies(buildtests_cxx status_test)
+add_dependencies(buildtests_cxx status_metadata_test)
+add_dependencies(buildtests_cxx status_util_test)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 add_dependencies(buildtests_cxx streaming_throughput_test)
 endif()
@@ -602,6 +631,7 @@
 add_dependencies(buildtests_cxx thread_manager_test)
 add_dependencies(buildtests_cxx thread_stress_test)
 add_dependencies(buildtests_cxx transport_pid_controller_test)
+add_dependencies(buildtests_cxx transport_security_common_api_test)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 add_dependencies(buildtests_cxx writes_per_rpc_test)
 endif()
@@ -617,18 +647,106 @@
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 add_dependencies(buildtests_cxx resolver_component_tests_runner_invoker)
 endif()
+if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
+add_dependencies(buildtests_cxx address_sorting_test_unsecure)
+endif()
+if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
+add_dependencies(buildtests_cxx address_sorting_test)
+endif()
 
 add_custom_target(buildtests
   DEPENDS buildtests_c buildtests_cxx)
 endif (gRPC_BUILD_TESTS)
 
 
+add_library(address_sorting
+  third_party/address_sorting/address_sorting.c
+  third_party/address_sorting/address_sorting_posix.c
+  third_party/address_sorting/address_sorting_windows.c
+)
+
+if(WIN32 AND MSVC)
+  set_target_properties(address_sorting PROPERTIES COMPILE_PDB_NAME "address_sorting"
+    COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
+  )
+  if (gRPC_INSTALL)
+    install(FILES ${CMAKE_CURRENT_BINARY_DIR}/address_sorting.pdb
+      DESTINATION ${gRPC_INSTALL_LIBDIR} OPTIONAL
+    )
+  endif()
+endif()
+
+
+target_include_directories(address_sorting
+  PUBLIC $<INSTALL_INTERFACE:${gRPC_INSTALL_INCLUDEDIR}> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+)
+
+target_link_libraries(address_sorting
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+)
+
+
+
+if (gRPC_INSTALL)
+  install(TARGETS address_sorting EXPORT gRPCTargets
+    RUNTIME DESTINATION ${gRPC_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${gRPC_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${gRPC_INSTALL_LIBDIR}
+  )
+endif()
+
+if (gRPC_BUILD_TESTS)
+
+add_library(alts_test_util
+  test/core/tsi/alts/crypt/gsec_test_util.cc
+  test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.cc
+)
+
+if(WIN32 AND MSVC)
+  set_target_properties(alts_test_util PROPERTIES COMPILE_PDB_NAME "alts_test_util"
+    COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
+  )
+  if (gRPC_INSTALL)
+    install(FILES ${CMAKE_CURRENT_BINARY_DIR}/alts_test_util.pdb
+      DESTINATION ${gRPC_INSTALL_LIBDIR} OPTIONAL
+    )
+  endif()
+endif()
+
+
+target_include_directories(alts_test_util
+  PUBLIC $<INSTALL_INTERFACE:${gRPC_INSTALL_INCLUDEDIR}> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+)
+
+target_link_libraries(alts_test_util
+  ${_gRPC_SSL_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc
+)
+
+
+endif (gRPC_BUILD_TESTS)
+
 add_library(gpr
   src/core/lib/gpr/alloc.cc
   src/core/lib/gpr/arena.cc
   src/core/lib/gpr/atm.cc
-  src/core/lib/gpr/avl.cc
-  src/core/lib/gpr/cmdline.cc
   src/core/lib/gpr/cpu_iphone.cc
   src/core/lib/gpr/cpu_linux.cc
   src/core/lib/gpr/cpu_posix.cc
@@ -649,14 +767,9 @@
   src/core/lib/gpr/string_posix.cc
   src/core/lib/gpr/string_util_windows.cc
   src/core/lib/gpr/string_windows.cc
-  src/core/lib/gpr/subprocess_posix.cc
-  src/core/lib/gpr/subprocess_windows.cc
   src/core/lib/gpr/sync.cc
   src/core/lib/gpr/sync_posix.cc
   src/core/lib/gpr/sync_windows.cc
-  src/core/lib/gpr/thd.cc
-  src/core/lib/gpr/thd_posix.cc
-  src/core/lib/gpr/thd_windows.cc
   src/core/lib/gpr/time.cc
   src/core/lib/gpr/time_posix.cc
   src/core/lib/gpr/time_precise.cc
@@ -666,6 +779,8 @@
   src/core/lib/gpr/tmpfile_posix.cc
   src/core/lib/gpr/tmpfile_windows.cc
   src/core/lib/gpr/wrap_memcpy.cc
+  src/core/lib/gprpp/thd_posix.cc
+  src/core/lib/gprpp/thd_windows.cc
   src/core/lib/profiling/basic_timers.cc
   src/core/lib/profiling/stap_timers.cc
 )
@@ -691,11 +806,18 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(gpr
   ${_gRPC_ALLTARGETS_LIBRARIES}
 )
+if (_gRPC_PLATFORM_ANDROID)
+  target_link_libraries(gpr
+    android
+    log
+  )
+endif (_gRPC_PLATFORM_ANDROID)
 
 foreach(_hdr
   include/grpc/support/alloc.h
@@ -703,27 +825,18 @@
   include/grpc/support/atm_gcc_atomic.h
   include/grpc/support/atm_gcc_sync.h
   include/grpc/support/atm_windows.h
-  include/grpc/support/avl.h
-  include/grpc/support/cmdline.h
   include/grpc/support/cpu.h
-  include/grpc/support/host_port.h
   include/grpc/support/log.h
   include/grpc/support/log_windows.h
   include/grpc/support/port_platform.h
   include/grpc/support/string_util.h
-  include/grpc/support/subprocess.h
   include/grpc/support/sync.h
   include/grpc/support/sync_custom.h
   include/grpc/support/sync_generic.h
   include/grpc/support/sync_posix.h
   include/grpc/support/sync_windows.h
-  include/grpc/support/thd.h
+  include/grpc/support/thd_id.h
   include/grpc/support/time.h
-  include/grpc/support/tls.h
-  include/grpc/support/tls_gcc.h
-  include/grpc/support/tls_msvc.h
-  include/grpc/support/tls_pthread.h
-  include/grpc/support/useful.h
   include/grpc/impl/codegen/atm.h
   include/grpc/impl/codegen/atm_gcc_atomic.h
   include/grpc/impl/codegen/atm_gcc_sync.h
@@ -781,6 +894,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(gpr_test_util
@@ -793,17 +907,20 @@
 
 add_library(grpc
   src/core/lib/surface/init.cc
+  src/core/lib/avl/avl.cc
   src/core/lib/backoff/backoff.cc
   src/core/lib/channel/channel_args.cc
   src/core/lib/channel/channel_stack.cc
   src/core/lib/channel/channel_stack_builder.cc
+  src/core/lib/channel/channel_trace.cc
+  src/core/lib/channel/channel_trace_registry.cc
   src/core/lib/channel/connected_channel.cc
   src/core/lib/channel/handshaker.cc
   src/core/lib/channel/handshaker_factory.cc
   src/core/lib/channel/handshaker_registry.cc
+  src/core/lib/channel/status_util.cc
   src/core/lib/compression/compression.cc
   src/core/lib/compression/compression_internal.cc
-  src/core/lib/compression/compression_ruby.cc
   src/core/lib/compression/message_compress.cc
   src/core/lib/compression/stream_compression.cc
   src/core/lib/compression/stream_compression_gzip.cc
@@ -835,6 +952,8 @@
   src/core/lib/iomgr/gethostname_sysconf.cc
   src/core/lib/iomgr/iocp_windows.cc
   src/core/lib/iomgr/iomgr.cc
+  src/core/lib/iomgr/iomgr_custom.cc
+  src/core/lib/iomgr/iomgr_internal.cc
   src/core/lib/iomgr/iomgr_posix.cc
   src/core/lib/iomgr/iomgr_uv.cc
   src/core/lib/iomgr/iomgr_windows.cc
@@ -843,12 +962,16 @@
   src/core/lib/iomgr/lockfree_event.cc
   src/core/lib/iomgr/network_status_tracker.cc
   src/core/lib/iomgr/polling_entity.cc
-  src/core/lib/iomgr/pollset_set_uv.cc
+  src/core/lib/iomgr/pollset.cc
+  src/core/lib/iomgr/pollset_custom.cc
+  src/core/lib/iomgr/pollset_set.cc
+  src/core/lib/iomgr/pollset_set_custom.cc
   src/core/lib/iomgr/pollset_set_windows.cc
   src/core/lib/iomgr/pollset_uv.cc
   src/core/lib/iomgr/pollset_windows.cc
+  src/core/lib/iomgr/resolve_address.cc
+  src/core/lib/iomgr/resolve_address_custom.cc
   src/core/lib/iomgr/resolve_address_posix.cc
-  src/core/lib/iomgr/resolve_address_uv.cc
   src/core/lib/iomgr/resolve_address_windows.cc
   src/core/lib/iomgr/resource_quota.cc
   src/core/lib/iomgr/sockaddr_utils.cc
@@ -860,19 +983,24 @@
   src/core/lib/iomgr/socket_utils_uv.cc
   src/core/lib/iomgr/socket_utils_windows.cc
   src/core/lib/iomgr/socket_windows.cc
+  src/core/lib/iomgr/tcp_client.cc
+  src/core/lib/iomgr/tcp_client_custom.cc
   src/core/lib/iomgr/tcp_client_posix.cc
-  src/core/lib/iomgr/tcp_client_uv.cc
   src/core/lib/iomgr/tcp_client_windows.cc
+  src/core/lib/iomgr/tcp_custom.cc
   src/core/lib/iomgr/tcp_posix.cc
+  src/core/lib/iomgr/tcp_server.cc
+  src/core/lib/iomgr/tcp_server_custom.cc
   src/core/lib/iomgr/tcp_server_posix.cc
   src/core/lib/iomgr/tcp_server_utils_posix_common.cc
   src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc
   src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc
-  src/core/lib/iomgr/tcp_server_uv.cc
   src/core/lib/iomgr/tcp_server_windows.cc
   src/core/lib/iomgr/tcp_uv.cc
   src/core/lib/iomgr/tcp_windows.cc
   src/core/lib/iomgr/time_averaged_stats.cc
+  src/core/lib/iomgr/timer.cc
+  src/core/lib/iomgr/timer_custom.cc
   src/core/lib/iomgr/timer_generic.cc
   src/core/lib/iomgr/timer_heap.cc
   src/core/lib/iomgr/timer_manager.cc
@@ -893,7 +1021,6 @@
   src/core/lib/slice/percent_encoding.cc
   src/core/lib/slice/slice.cc
   src/core/lib/slice/slice_buffer.cc
-  src/core/lib/slice/slice_hash_table.cc
   src/core/lib/slice/slice_intern.cc
   src/core/lib/slice/slice_string_helpers.cc
   src/core/lib/surface/api_trace.cc
@@ -924,6 +1051,7 @@
   src/core/lib/transport/service_config.cc
   src/core/lib/transport/static_metadata.cc
   src/core/lib/transport/status_conversion.cc
+  src/core/lib/transport/status_metadata.cc
   src/core/lib/transport/timeout_encoding.cc
   src/core/lib/transport/transport.cc
   src/core/lib/transport/transport_op_string.cc
@@ -958,6 +1086,7 @@
   src/core/ext/filters/http/server/http_server_filter.cc
   src/core/lib/http/httpcli_security_connector.cc
   src/core/lib/security/context/security_context.cc
+  src/core/lib/security/credentials/alts/alts_credentials.cc
   src/core/lib/security/credentials/composite/composite_credentials.cc
   src/core/lib/security/credentials/credentials.cc
   src/core/lib/security/credentials/credentials_metadata.cc
@@ -971,23 +1100,55 @@
   src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
   src/core/lib/security/credentials/plugin/plugin_credentials.cc
   src/core/lib/security/credentials/ssl/ssl_credentials.cc
+  src/core/lib/security/security_connector/alts_security_connector.cc
+  src/core/lib/security/security_connector/security_connector.cc
   src/core/lib/security/transport/client_auth_filter.cc
-  src/core/lib/security/transport/lb_targets_info.cc
   src/core/lib/security/transport/secure_endpoint.cc
-  src/core/lib/security/transport/security_connector.cc
   src/core/lib/security/transport/security_handshaker.cc
   src/core/lib/security/transport/server_auth_filter.cc
+  src/core/lib/security/transport/target_authority_table.cc
   src/core/lib/security/transport/tsi_error.cc
   src/core/lib/security/util/json_util.cc
   src/core/lib/surface/init_secure.cc
-  src/core/tsi/alts_transport_security.cc
-  src/core/tsi/fake_transport_security.cc
-  src/core/tsi/ssl_transport_security.cc
-  src/core/tsi/transport_security_grpc.cc
+  src/core/tsi/alts/crypt/aes_gcm.cc
+  src/core/tsi/alts/crypt/gsec.cc
+  src/core/tsi/alts/frame_protector/alts_counter.cc
+  src/core/tsi/alts/frame_protector/alts_crypter.cc
+  src/core/tsi/alts/frame_protector/alts_frame_protector.cc
+  src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc
+  src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc
+  src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc
+  src/core/tsi/alts/frame_protector/frame_handler.cc
+  src/core/tsi/alts/handshaker/alts_handshaker_client.cc
+  src/core/tsi/alts/handshaker/alts_tsi_event.cc
+  src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc
+  src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc
+  src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc
+  src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc
+  src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc
+  src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc
+  src/core/lib/security/credentials/alts/check_gcp_environment.cc
+  src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc
+  src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc
+  src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc
+  src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc
+  src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc
+  src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc
+  src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc
+  src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc
+  src/core/tsi/alts/handshaker/alts_tsi_utils.cc
+  src/core/tsi/alts/handshaker/transport_security_common_api.cc
+  src/core/tsi/alts/handshaker/altscontext.pb.c
+  src/core/tsi/alts/handshaker/handshaker.pb.c
+  src/core/tsi/alts/handshaker/transport_security_common.pb.c
+  third_party/nanopb/pb_common.c
+  third_party/nanopb/pb_decode.c
+  third_party/nanopb/pb_encode.c
   src/core/tsi/transport_security.cc
   src/core/tsi/transport_security_adapter.cc
-  src/core/ext/transport/chttp2/server/chttp2_server.cc
-  src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc
+  src/core/ext/transport/chttp2/client/insecure/channel_create.cc
+  src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc
+  src/core/ext/transport/chttp2/client/chttp2_connector.cc
   src/core/ext/filters/client_channel/backup_poller.cc
   src/core/ext/filters/client_channel/channel_connectivity.cc
   src/core/ext/filters/client_channel/client_channel.cc
@@ -999,22 +1160,28 @@
   src/core/ext/filters/client_channel/lb_policy.cc
   src/core/ext/filters/client_channel/lb_policy_factory.cc
   src/core/ext/filters/client_channel/lb_policy_registry.cc
+  src/core/ext/filters/client_channel/method_params.cc
   src/core/ext/filters/client_channel/parse_address.cc
   src/core/ext/filters/client_channel/proxy_mapper.cc
   src/core/ext/filters/client_channel/proxy_mapper_registry.cc
   src/core/ext/filters/client_channel/resolver.cc
-  src/core/ext/filters/client_channel/resolver_factory.cc
   src/core/ext/filters/client_channel/resolver_registry.cc
   src/core/ext/filters/client_channel/retry_throttle.cc
   src/core/ext/filters/client_channel/subchannel.cc
   src/core/ext/filters/client_channel/subchannel_index.cc
   src/core/ext/filters/client_channel/uri_parser.cc
   src/core/ext/filters/deadline/deadline_filter.cc
-  src/core/ext/transport/chttp2/client/chttp2_connector.cc
+  src/core/tsi/alts_transport_security.cc
+  src/core/tsi/fake_transport_security.cc
+  src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc
+  src/core/tsi/ssl/session_cache/ssl_session_cache.cc
+  src/core/tsi/ssl/session_cache/ssl_session_openssl.cc
+  src/core/tsi/ssl_transport_security.cc
+  src/core/tsi/transport_security_grpc.cc
+  src/core/ext/transport/chttp2/server/chttp2_server.cc
+  src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc
   src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc
   src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc
-  src/core/ext/transport/chttp2/client/insecure/channel_create.cc
-  src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc
   src/core/ext/transport/inproc/inproc_plugin.cc
   src/core/ext/transport/inproc/inproc_transport.cc
   src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc
@@ -1023,9 +1190,6 @@
   src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc
   src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
   src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
-  third_party/nanopb/pb_common.c
-  third_party/nanopb/pb_decode.c
-  third_party/nanopb/pb_encode.c
   src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
   src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
   src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc
@@ -1067,6 +1231,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc
@@ -1074,6 +1239,7 @@
   ${_gRPC_SSL_LIBRARIES}
   ${_gRPC_ZLIB_LIBRARIES}
   ${_gRPC_CARES_LIBRARIES}
+  ${_gRPC_ADDRESS_SORTING_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gpr
 )
@@ -1104,7 +1270,6 @@
   include/grpc/byte_buffer.h
   include/grpc/byte_buffer_reader.h
   include/grpc/compression.h
-  include/grpc/compression_ruby.h
   include/grpc/fork.h
   include/grpc/grpc.h
   include/grpc/grpc_posix.h
@@ -1135,17 +1300,20 @@
 
 add_library(grpc_cronet
   src/core/lib/surface/init.cc
+  src/core/lib/avl/avl.cc
   src/core/lib/backoff/backoff.cc
   src/core/lib/channel/channel_args.cc
   src/core/lib/channel/channel_stack.cc
   src/core/lib/channel/channel_stack_builder.cc
+  src/core/lib/channel/channel_trace.cc
+  src/core/lib/channel/channel_trace_registry.cc
   src/core/lib/channel/connected_channel.cc
   src/core/lib/channel/handshaker.cc
   src/core/lib/channel/handshaker_factory.cc
   src/core/lib/channel/handshaker_registry.cc
+  src/core/lib/channel/status_util.cc
   src/core/lib/compression/compression.cc
   src/core/lib/compression/compression_internal.cc
-  src/core/lib/compression/compression_ruby.cc
   src/core/lib/compression/message_compress.cc
   src/core/lib/compression/stream_compression.cc
   src/core/lib/compression/stream_compression_gzip.cc
@@ -1177,6 +1345,8 @@
   src/core/lib/iomgr/gethostname_sysconf.cc
   src/core/lib/iomgr/iocp_windows.cc
   src/core/lib/iomgr/iomgr.cc
+  src/core/lib/iomgr/iomgr_custom.cc
+  src/core/lib/iomgr/iomgr_internal.cc
   src/core/lib/iomgr/iomgr_posix.cc
   src/core/lib/iomgr/iomgr_uv.cc
   src/core/lib/iomgr/iomgr_windows.cc
@@ -1185,12 +1355,16 @@
   src/core/lib/iomgr/lockfree_event.cc
   src/core/lib/iomgr/network_status_tracker.cc
   src/core/lib/iomgr/polling_entity.cc
-  src/core/lib/iomgr/pollset_set_uv.cc
+  src/core/lib/iomgr/pollset.cc
+  src/core/lib/iomgr/pollset_custom.cc
+  src/core/lib/iomgr/pollset_set.cc
+  src/core/lib/iomgr/pollset_set_custom.cc
   src/core/lib/iomgr/pollset_set_windows.cc
   src/core/lib/iomgr/pollset_uv.cc
   src/core/lib/iomgr/pollset_windows.cc
+  src/core/lib/iomgr/resolve_address.cc
+  src/core/lib/iomgr/resolve_address_custom.cc
   src/core/lib/iomgr/resolve_address_posix.cc
-  src/core/lib/iomgr/resolve_address_uv.cc
   src/core/lib/iomgr/resolve_address_windows.cc
   src/core/lib/iomgr/resource_quota.cc
   src/core/lib/iomgr/sockaddr_utils.cc
@@ -1202,19 +1376,24 @@
   src/core/lib/iomgr/socket_utils_uv.cc
   src/core/lib/iomgr/socket_utils_windows.cc
   src/core/lib/iomgr/socket_windows.cc
+  src/core/lib/iomgr/tcp_client.cc
+  src/core/lib/iomgr/tcp_client_custom.cc
   src/core/lib/iomgr/tcp_client_posix.cc
-  src/core/lib/iomgr/tcp_client_uv.cc
   src/core/lib/iomgr/tcp_client_windows.cc
+  src/core/lib/iomgr/tcp_custom.cc
   src/core/lib/iomgr/tcp_posix.cc
+  src/core/lib/iomgr/tcp_server.cc
+  src/core/lib/iomgr/tcp_server_custom.cc
   src/core/lib/iomgr/tcp_server_posix.cc
   src/core/lib/iomgr/tcp_server_utils_posix_common.cc
   src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc
   src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc
-  src/core/lib/iomgr/tcp_server_uv.cc
   src/core/lib/iomgr/tcp_server_windows.cc
   src/core/lib/iomgr/tcp_uv.cc
   src/core/lib/iomgr/tcp_windows.cc
   src/core/lib/iomgr/time_averaged_stats.cc
+  src/core/lib/iomgr/timer.cc
+  src/core/lib/iomgr/timer_custom.cc
   src/core/lib/iomgr/timer_generic.cc
   src/core/lib/iomgr/timer_heap.cc
   src/core/lib/iomgr/timer_manager.cc
@@ -1235,7 +1414,6 @@
   src/core/lib/slice/percent_encoding.cc
   src/core/lib/slice/slice.cc
   src/core/lib/slice/slice_buffer.cc
-  src/core/lib/slice/slice_hash_table.cc
   src/core/lib/slice/slice_intern.cc
   src/core/lib/slice/slice_string_helpers.cc
   src/core/lib/surface/api_trace.cc
@@ -1266,10 +1444,41 @@
   src/core/lib/transport/service_config.cc
   src/core/lib/transport/static_metadata.cc
   src/core/lib/transport/status_conversion.cc
+  src/core/lib/transport/status_metadata.cc
   src/core/lib/transport/timeout_encoding.cc
   src/core/lib/transport/transport.cc
   src/core/lib/transport/transport_op_string.cc
   src/core/lib/debug/trace.cc
+  src/core/ext/filters/deadline/deadline_filter.cc
+  src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
+  src/core/ext/filters/client_channel/backup_poller.cc
+  src/core/ext/filters/client_channel/channel_connectivity.cc
+  src/core/ext/filters/client_channel/client_channel.cc
+  src/core/ext/filters/client_channel/client_channel_factory.cc
+  src/core/ext/filters/client_channel/client_channel_plugin.cc
+  src/core/ext/filters/client_channel/connector.cc
+  src/core/ext/filters/client_channel/http_connect_handshaker.cc
+  src/core/ext/filters/client_channel/http_proxy.cc
+  src/core/ext/filters/client_channel/lb_policy.cc
+  src/core/ext/filters/client_channel/lb_policy_factory.cc
+  src/core/ext/filters/client_channel/lb_policy_registry.cc
+  src/core/ext/filters/client_channel/method_params.cc
+  src/core/ext/filters/client_channel/parse_address.cc
+  src/core/ext/filters/client_channel/proxy_mapper.cc
+  src/core/ext/filters/client_channel/proxy_mapper_registry.cc
+  src/core/ext/filters/client_channel/resolver.cc
+  src/core/ext/filters/client_channel/resolver_registry.cc
+  src/core/ext/filters/client_channel/retry_throttle.cc
+  src/core/ext/filters/client_channel/subchannel.cc
+  src/core/ext/filters/client_channel/subchannel_index.cc
+  src/core/ext/filters/client_channel/uri_parser.cc
+  src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc
+  src/core/ext/filters/max_age/max_age_filter.cc
+  src/core/ext/filters/message_size/message_size_filter.cc
+  src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
+  src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
+  src/core/ext/filters/load_reporting/server_load_reporting_filter.cc
+  src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc
   src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc
   src/core/ext/transport/cronet/transport/cronet_api_dummy.cc
   src/core/ext/transport/cronet/transport/cronet_transport.cc
@@ -1301,30 +1510,9 @@
   src/core/ext/filters/http/http_filters_plugin.cc
   src/core/ext/filters/http/message_compress/message_compress_filter.cc
   src/core/ext/filters/http/server/http_server_filter.cc
-  src/core/ext/filters/client_channel/backup_poller.cc
-  src/core/ext/filters/client_channel/channel_connectivity.cc
-  src/core/ext/filters/client_channel/client_channel.cc
-  src/core/ext/filters/client_channel/client_channel_factory.cc
-  src/core/ext/filters/client_channel/client_channel_plugin.cc
-  src/core/ext/filters/client_channel/connector.cc
-  src/core/ext/filters/client_channel/http_connect_handshaker.cc
-  src/core/ext/filters/client_channel/http_proxy.cc
-  src/core/ext/filters/client_channel/lb_policy.cc
-  src/core/ext/filters/client_channel/lb_policy_factory.cc
-  src/core/ext/filters/client_channel/lb_policy_registry.cc
-  src/core/ext/filters/client_channel/parse_address.cc
-  src/core/ext/filters/client_channel/proxy_mapper.cc
-  src/core/ext/filters/client_channel/proxy_mapper_registry.cc
-  src/core/ext/filters/client_channel/resolver.cc
-  src/core/ext/filters/client_channel/resolver_factory.cc
-  src/core/ext/filters/client_channel/resolver_registry.cc
-  src/core/ext/filters/client_channel/retry_throttle.cc
-  src/core/ext/filters/client_channel/subchannel.cc
-  src/core/ext/filters/client_channel/subchannel_index.cc
-  src/core/ext/filters/client_channel/uri_parser.cc
-  src/core/ext/filters/deadline/deadline_filter.cc
   src/core/lib/http/httpcli_security_connector.cc
   src/core/lib/security/context/security_context.cc
+  src/core/lib/security/credentials/alts/alts_credentials.cc
   src/core/lib/security/credentials/composite/composite_credentials.cc
   src/core/lib/security/credentials/credentials.cc
   src/core/lib/security/credentials/credentials_metadata.cc
@@ -1338,24 +1526,64 @@
   src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
   src/core/lib/security/credentials/plugin/plugin_credentials.cc
   src/core/lib/security/credentials/ssl/ssl_credentials.cc
+  src/core/lib/security/security_connector/alts_security_connector.cc
+  src/core/lib/security/security_connector/security_connector.cc
   src/core/lib/security/transport/client_auth_filter.cc
-  src/core/lib/security/transport/lb_targets_info.cc
   src/core/lib/security/transport/secure_endpoint.cc
-  src/core/lib/security/transport/security_connector.cc
   src/core/lib/security/transport/security_handshaker.cc
   src/core/lib/security/transport/server_auth_filter.cc
+  src/core/lib/security/transport/target_authority_table.cc
   src/core/lib/security/transport/tsi_error.cc
   src/core/lib/security/util/json_util.cc
   src/core/lib/surface/init_secure.cc
-  src/core/tsi/alts_transport_security.cc
-  src/core/tsi/fake_transport_security.cc
-  src/core/tsi/ssl_transport_security.cc
-  src/core/tsi/transport_security_grpc.cc
+  src/core/tsi/alts/crypt/aes_gcm.cc
+  src/core/tsi/alts/crypt/gsec.cc
+  src/core/tsi/alts/frame_protector/alts_counter.cc
+  src/core/tsi/alts/frame_protector/alts_crypter.cc
+  src/core/tsi/alts/frame_protector/alts_frame_protector.cc
+  src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc
+  src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc
+  src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc
+  src/core/tsi/alts/frame_protector/frame_handler.cc
+  src/core/tsi/alts/handshaker/alts_handshaker_client.cc
+  src/core/tsi/alts/handshaker/alts_tsi_event.cc
+  src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc
+  src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc
+  src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc
+  src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc
+  src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc
+  src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc
+  src/core/lib/security/credentials/alts/check_gcp_environment.cc
+  src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc
+  src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc
+  src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc
+  src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc
+  src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc
+  src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc
+  src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc
+  src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc
+  src/core/tsi/alts/handshaker/alts_tsi_utils.cc
+  src/core/tsi/alts/handshaker/transport_security_common_api.cc
+  src/core/tsi/alts/handshaker/altscontext.pb.c
+  src/core/tsi/alts/handshaker/handshaker.pb.c
+  src/core/tsi/alts/handshaker/transport_security_common.pb.c
+  third_party/nanopb/pb_common.c
+  third_party/nanopb/pb_decode.c
+  third_party/nanopb/pb_encode.c
   src/core/tsi/transport_security.cc
   src/core/tsi/transport_security_adapter.cc
+  src/core/ext/transport/chttp2/client/insecure/channel_create.cc
+  src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc
   src/core/ext/transport/chttp2/client/chttp2_connector.cc
-  src/core/ext/filters/load_reporting/server_load_reporting_filter.cc
-  src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc
+  src/core/tsi/alts_transport_security.cc
+  src/core/tsi/fake_transport_security.cc
+  src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc
+  src/core/tsi/ssl/session_cache/ssl_session_cache.cc
+  src/core/tsi/ssl/session_cache/ssl_session_openssl.cc
+  src/core/tsi/ssl_transport_security.cc
+  src/core/tsi/transport_security_grpc.cc
+  src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc
+  src/core/ext/transport/chttp2/server/chttp2_server.cc
   src/core/plugin_registry/grpc_cronet_plugin_registry.cc
 )
 
@@ -1380,6 +1608,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_cronet
@@ -1387,6 +1616,7 @@
   ${_gRPC_SSL_LIBRARIES}
   ${_gRPC_ZLIB_LIBRARIES}
   ${_gRPC_CARES_LIBRARIES}
+  ${_gRPC_ADDRESS_SORTING_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gpr
 )
@@ -1413,9 +1643,20 @@
   include/grpc/impl/codegen/sync_generic.h
   include/grpc/impl/codegen/sync_posix.h
   include/grpc/impl/codegen/sync_windows.h
+  include/grpc/byte_buffer.h
+  include/grpc/byte_buffer_reader.h
+  include/grpc/compression.h
+  include/grpc/fork.h
+  include/grpc/grpc.h
+  include/grpc/grpc_posix.h
+  include/grpc/grpc_security_constants.h
+  include/grpc/load_reporting.h
+  include/grpc/slice.h
+  include/grpc/slice_buffer.h
+  include/grpc/status.h
+  include/grpc/support/workaround_list.h
   include/grpc/grpc_cronet.h
   include/grpc/grpc_security.h
-  include/grpc/grpc_security_constants.h
 )
   string(REPLACE "include/" "" _path ${_hdr})
   get_filename_component(_path ${_path} PATH)
@@ -1457,19 +1698,25 @@
   test/core/util/port_isolated_runtime_environment.cc
   test/core/util/port_server_client.cc
   test/core/util/slice_splitter.cc
+  test/core/util/subprocess_posix.cc
+  test/core/util/subprocess_windows.cc
   test/core/util/tracer_util.cc
   test/core/util/trickle_endpoint.cc
+  test/core/util/cmdline.cc
+  src/core/lib/avl/avl.cc
   src/core/lib/backoff/backoff.cc
   src/core/lib/channel/channel_args.cc
   src/core/lib/channel/channel_stack.cc
   src/core/lib/channel/channel_stack_builder.cc
+  src/core/lib/channel/channel_trace.cc
+  src/core/lib/channel/channel_trace_registry.cc
   src/core/lib/channel/connected_channel.cc
   src/core/lib/channel/handshaker.cc
   src/core/lib/channel/handshaker_factory.cc
   src/core/lib/channel/handshaker_registry.cc
+  src/core/lib/channel/status_util.cc
   src/core/lib/compression/compression.cc
   src/core/lib/compression/compression_internal.cc
-  src/core/lib/compression/compression_ruby.cc
   src/core/lib/compression/message_compress.cc
   src/core/lib/compression/stream_compression.cc
   src/core/lib/compression/stream_compression_gzip.cc
@@ -1501,6 +1748,8 @@
   src/core/lib/iomgr/gethostname_sysconf.cc
   src/core/lib/iomgr/iocp_windows.cc
   src/core/lib/iomgr/iomgr.cc
+  src/core/lib/iomgr/iomgr_custom.cc
+  src/core/lib/iomgr/iomgr_internal.cc
   src/core/lib/iomgr/iomgr_posix.cc
   src/core/lib/iomgr/iomgr_uv.cc
   src/core/lib/iomgr/iomgr_windows.cc
@@ -1509,12 +1758,16 @@
   src/core/lib/iomgr/lockfree_event.cc
   src/core/lib/iomgr/network_status_tracker.cc
   src/core/lib/iomgr/polling_entity.cc
-  src/core/lib/iomgr/pollset_set_uv.cc
+  src/core/lib/iomgr/pollset.cc
+  src/core/lib/iomgr/pollset_custom.cc
+  src/core/lib/iomgr/pollset_set.cc
+  src/core/lib/iomgr/pollset_set_custom.cc
   src/core/lib/iomgr/pollset_set_windows.cc
   src/core/lib/iomgr/pollset_uv.cc
   src/core/lib/iomgr/pollset_windows.cc
+  src/core/lib/iomgr/resolve_address.cc
+  src/core/lib/iomgr/resolve_address_custom.cc
   src/core/lib/iomgr/resolve_address_posix.cc
-  src/core/lib/iomgr/resolve_address_uv.cc
   src/core/lib/iomgr/resolve_address_windows.cc
   src/core/lib/iomgr/resource_quota.cc
   src/core/lib/iomgr/sockaddr_utils.cc
@@ -1526,19 +1779,24 @@
   src/core/lib/iomgr/socket_utils_uv.cc
   src/core/lib/iomgr/socket_utils_windows.cc
   src/core/lib/iomgr/socket_windows.cc
+  src/core/lib/iomgr/tcp_client.cc
+  src/core/lib/iomgr/tcp_client_custom.cc
   src/core/lib/iomgr/tcp_client_posix.cc
-  src/core/lib/iomgr/tcp_client_uv.cc
   src/core/lib/iomgr/tcp_client_windows.cc
+  src/core/lib/iomgr/tcp_custom.cc
   src/core/lib/iomgr/tcp_posix.cc
+  src/core/lib/iomgr/tcp_server.cc
+  src/core/lib/iomgr/tcp_server_custom.cc
   src/core/lib/iomgr/tcp_server_posix.cc
   src/core/lib/iomgr/tcp_server_utils_posix_common.cc
   src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc
   src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc
-  src/core/lib/iomgr/tcp_server_uv.cc
   src/core/lib/iomgr/tcp_server_windows.cc
   src/core/lib/iomgr/tcp_uv.cc
   src/core/lib/iomgr/tcp_windows.cc
   src/core/lib/iomgr/time_averaged_stats.cc
+  src/core/lib/iomgr/timer.cc
+  src/core/lib/iomgr/timer_custom.cc
   src/core/lib/iomgr/timer_generic.cc
   src/core/lib/iomgr/timer_heap.cc
   src/core/lib/iomgr/timer_manager.cc
@@ -1559,7 +1817,6 @@
   src/core/lib/slice/percent_encoding.cc
   src/core/lib/slice/slice.cc
   src/core/lib/slice/slice_buffer.cc
-  src/core/lib/slice/slice_hash_table.cc
   src/core/lib/slice/slice_intern.cc
   src/core/lib/slice/slice_string_helpers.cc
   src/core/lib/surface/api_trace.cc
@@ -1590,6 +1847,7 @@
   src/core/lib/transport/service_config.cc
   src/core/lib/transport/static_metadata.cc
   src/core/lib/transport/status_conversion.cc
+  src/core/lib/transport/status_metadata.cc
   src/core/lib/transport/timeout_encoding.cc
   src/core/lib/transport/transport.cc
   src/core/lib/transport/transport_op_string.cc
@@ -1605,11 +1863,11 @@
   src/core/ext/filters/client_channel/lb_policy.cc
   src/core/ext/filters/client_channel/lb_policy_factory.cc
   src/core/ext/filters/client_channel/lb_policy_registry.cc
+  src/core/ext/filters/client_channel/method_params.cc
   src/core/ext/filters/client_channel/parse_address.cc
   src/core/ext/filters/client_channel/proxy_mapper.cc
   src/core/ext/filters/client_channel/proxy_mapper_registry.cc
   src/core/ext/filters/client_channel/resolver.cc
-  src/core/ext/filters/client_channel/resolver_factory.cc
   src/core/ext/filters/client_channel/resolver_registry.cc
   src/core/ext/filters/client_channel/retry_throttle.cc
   src/core/ext/filters/client_channel/subchannel.cc
@@ -1666,6 +1924,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_test_util
@@ -1676,14 +1935,23 @@
 )
 
 foreach(_hdr
-  include/grpc/impl/codegen/byte_buffer.h
-  include/grpc/impl/codegen/byte_buffer_reader.h
-  include/grpc/impl/codegen/compression_types.h
-  include/grpc/impl/codegen/connectivity_state.h
-  include/grpc/impl/codegen/grpc_types.h
-  include/grpc/impl/codegen/propagation_bits.h
-  include/grpc/impl/codegen/slice.h
-  include/grpc/impl/codegen/status.h
+  include/grpc/support/alloc.h
+  include/grpc/support/atm.h
+  include/grpc/support/atm_gcc_atomic.h
+  include/grpc/support/atm_gcc_sync.h
+  include/grpc/support/atm_windows.h
+  include/grpc/support/cpu.h
+  include/grpc/support/log.h
+  include/grpc/support/log_windows.h
+  include/grpc/support/port_platform.h
+  include/grpc/support/string_util.h
+  include/grpc/support/sync.h
+  include/grpc/support/sync_custom.h
+  include/grpc/support/sync_generic.h
+  include/grpc/support/sync_posix.h
+  include/grpc/support/sync_windows.h
+  include/grpc/support/thd_id.h
+  include/grpc/support/time.h
   include/grpc/impl/codegen/atm.h
   include/grpc/impl/codegen/atm_gcc_atomic.h
   include/grpc/impl/codegen/atm_gcc_sync.h
@@ -1697,6 +1965,14 @@
   include/grpc/impl/codegen/sync_generic.h
   include/grpc/impl/codegen/sync_posix.h
   include/grpc/impl/codegen/sync_windows.h
+  include/grpc/impl/codegen/byte_buffer.h
+  include/grpc/impl/codegen/byte_buffer_reader.h
+  include/grpc/impl/codegen/compression_types.h
+  include/grpc/impl/codegen/connectivity_state.h
+  include/grpc/impl/codegen/grpc_types.h
+  include/grpc/impl/codegen/propagation_bits.h
+  include/grpc/impl/codegen/slice.h
+  include/grpc/impl/codegen/status.h
 )
   string(REPLACE "include/" "" _path ${_hdr})
   get_filename_component(_path ${_path} PATH)
@@ -1725,19 +2001,25 @@
   test/core/util/port_isolated_runtime_environment.cc
   test/core/util/port_server_client.cc
   test/core/util/slice_splitter.cc
+  test/core/util/subprocess_posix.cc
+  test/core/util/subprocess_windows.cc
   test/core/util/tracer_util.cc
   test/core/util/trickle_endpoint.cc
+  test/core/util/cmdline.cc
+  src/core/lib/avl/avl.cc
   src/core/lib/backoff/backoff.cc
   src/core/lib/channel/channel_args.cc
   src/core/lib/channel/channel_stack.cc
   src/core/lib/channel/channel_stack_builder.cc
+  src/core/lib/channel/channel_trace.cc
+  src/core/lib/channel/channel_trace_registry.cc
   src/core/lib/channel/connected_channel.cc
   src/core/lib/channel/handshaker.cc
   src/core/lib/channel/handshaker_factory.cc
   src/core/lib/channel/handshaker_registry.cc
+  src/core/lib/channel/status_util.cc
   src/core/lib/compression/compression.cc
   src/core/lib/compression/compression_internal.cc
-  src/core/lib/compression/compression_ruby.cc
   src/core/lib/compression/message_compress.cc
   src/core/lib/compression/stream_compression.cc
   src/core/lib/compression/stream_compression_gzip.cc
@@ -1769,6 +2051,8 @@
   src/core/lib/iomgr/gethostname_sysconf.cc
   src/core/lib/iomgr/iocp_windows.cc
   src/core/lib/iomgr/iomgr.cc
+  src/core/lib/iomgr/iomgr_custom.cc
+  src/core/lib/iomgr/iomgr_internal.cc
   src/core/lib/iomgr/iomgr_posix.cc
   src/core/lib/iomgr/iomgr_uv.cc
   src/core/lib/iomgr/iomgr_windows.cc
@@ -1777,12 +2061,16 @@
   src/core/lib/iomgr/lockfree_event.cc
   src/core/lib/iomgr/network_status_tracker.cc
   src/core/lib/iomgr/polling_entity.cc
-  src/core/lib/iomgr/pollset_set_uv.cc
+  src/core/lib/iomgr/pollset.cc
+  src/core/lib/iomgr/pollset_custom.cc
+  src/core/lib/iomgr/pollset_set.cc
+  src/core/lib/iomgr/pollset_set_custom.cc
   src/core/lib/iomgr/pollset_set_windows.cc
   src/core/lib/iomgr/pollset_uv.cc
   src/core/lib/iomgr/pollset_windows.cc
+  src/core/lib/iomgr/resolve_address.cc
+  src/core/lib/iomgr/resolve_address_custom.cc
   src/core/lib/iomgr/resolve_address_posix.cc
-  src/core/lib/iomgr/resolve_address_uv.cc
   src/core/lib/iomgr/resolve_address_windows.cc
   src/core/lib/iomgr/resource_quota.cc
   src/core/lib/iomgr/sockaddr_utils.cc
@@ -1794,19 +2082,24 @@
   src/core/lib/iomgr/socket_utils_uv.cc
   src/core/lib/iomgr/socket_utils_windows.cc
   src/core/lib/iomgr/socket_windows.cc
+  src/core/lib/iomgr/tcp_client.cc
+  src/core/lib/iomgr/tcp_client_custom.cc
   src/core/lib/iomgr/tcp_client_posix.cc
-  src/core/lib/iomgr/tcp_client_uv.cc
   src/core/lib/iomgr/tcp_client_windows.cc
+  src/core/lib/iomgr/tcp_custom.cc
   src/core/lib/iomgr/tcp_posix.cc
+  src/core/lib/iomgr/tcp_server.cc
+  src/core/lib/iomgr/tcp_server_custom.cc
   src/core/lib/iomgr/tcp_server_posix.cc
   src/core/lib/iomgr/tcp_server_utils_posix_common.cc
   src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc
   src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc
-  src/core/lib/iomgr/tcp_server_uv.cc
   src/core/lib/iomgr/tcp_server_windows.cc
   src/core/lib/iomgr/tcp_uv.cc
   src/core/lib/iomgr/tcp_windows.cc
   src/core/lib/iomgr/time_averaged_stats.cc
+  src/core/lib/iomgr/timer.cc
+  src/core/lib/iomgr/timer_custom.cc
   src/core/lib/iomgr/timer_generic.cc
   src/core/lib/iomgr/timer_heap.cc
   src/core/lib/iomgr/timer_manager.cc
@@ -1827,7 +2120,6 @@
   src/core/lib/slice/percent_encoding.cc
   src/core/lib/slice/slice.cc
   src/core/lib/slice/slice_buffer.cc
-  src/core/lib/slice/slice_hash_table.cc
   src/core/lib/slice/slice_intern.cc
   src/core/lib/slice/slice_string_helpers.cc
   src/core/lib/surface/api_trace.cc
@@ -1858,6 +2150,7 @@
   src/core/lib/transport/service_config.cc
   src/core/lib/transport/static_metadata.cc
   src/core/lib/transport/status_conversion.cc
+  src/core/lib/transport/status_metadata.cc
   src/core/lib/transport/timeout_encoding.cc
   src/core/lib/transport/transport.cc
   src/core/lib/transport/transport_op_string.cc
@@ -1873,11 +2166,11 @@
   src/core/ext/filters/client_channel/lb_policy.cc
   src/core/ext/filters/client_channel/lb_policy_factory.cc
   src/core/ext/filters/client_channel/lb_policy_registry.cc
+  src/core/ext/filters/client_channel/method_params.cc
   src/core/ext/filters/client_channel/parse_address.cc
   src/core/ext/filters/client_channel/proxy_mapper.cc
   src/core/ext/filters/client_channel/proxy_mapper_registry.cc
   src/core/ext/filters/client_channel/resolver.cc
-  src/core/ext/filters/client_channel/resolver_factory.cc
   src/core/ext/filters/client_channel/resolver_registry.cc
   src/core/ext/filters/client_channel/retry_throttle.cc
   src/core/ext/filters/client_channel/subchannel.cc
@@ -1934,6 +2227,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_test_util_unsecure
@@ -1944,14 +2238,23 @@
 )
 
 foreach(_hdr
-  include/grpc/impl/codegen/byte_buffer.h
-  include/grpc/impl/codegen/byte_buffer_reader.h
-  include/grpc/impl/codegen/compression_types.h
-  include/grpc/impl/codegen/connectivity_state.h
-  include/grpc/impl/codegen/grpc_types.h
-  include/grpc/impl/codegen/propagation_bits.h
-  include/grpc/impl/codegen/slice.h
-  include/grpc/impl/codegen/status.h
+  include/grpc/support/alloc.h
+  include/grpc/support/atm.h
+  include/grpc/support/atm_gcc_atomic.h
+  include/grpc/support/atm_gcc_sync.h
+  include/grpc/support/atm_windows.h
+  include/grpc/support/cpu.h
+  include/grpc/support/log.h
+  include/grpc/support/log_windows.h
+  include/grpc/support/port_platform.h
+  include/grpc/support/string_util.h
+  include/grpc/support/sync.h
+  include/grpc/support/sync_custom.h
+  include/grpc/support/sync_generic.h
+  include/grpc/support/sync_posix.h
+  include/grpc/support/sync_windows.h
+  include/grpc/support/thd_id.h
+  include/grpc/support/time.h
   include/grpc/impl/codegen/atm.h
   include/grpc/impl/codegen/atm_gcc_atomic.h
   include/grpc/impl/codegen/atm_gcc_sync.h
@@ -1965,6 +2268,14 @@
   include/grpc/impl/codegen/sync_generic.h
   include/grpc/impl/codegen/sync_posix.h
   include/grpc/impl/codegen/sync_windows.h
+  include/grpc/impl/codegen/byte_buffer.h
+  include/grpc/impl/codegen/byte_buffer_reader.h
+  include/grpc/impl/codegen/compression_types.h
+  include/grpc/impl/codegen/connectivity_state.h
+  include/grpc/impl/codegen/grpc_types.h
+  include/grpc/impl/codegen/propagation_bits.h
+  include/grpc/impl/codegen/slice.h
+  include/grpc/impl/codegen/status.h
 )
   string(REPLACE "include/" "" _path ${_hdr})
   get_filename_component(_path ${_path} PATH)
@@ -1978,17 +2289,20 @@
 add_library(grpc_unsecure
   src/core/lib/surface/init.cc
   src/core/lib/surface/init_unsecure.cc
+  src/core/lib/avl/avl.cc
   src/core/lib/backoff/backoff.cc
   src/core/lib/channel/channel_args.cc
   src/core/lib/channel/channel_stack.cc
   src/core/lib/channel/channel_stack_builder.cc
+  src/core/lib/channel/channel_trace.cc
+  src/core/lib/channel/channel_trace_registry.cc
   src/core/lib/channel/connected_channel.cc
   src/core/lib/channel/handshaker.cc
   src/core/lib/channel/handshaker_factory.cc
   src/core/lib/channel/handshaker_registry.cc
+  src/core/lib/channel/status_util.cc
   src/core/lib/compression/compression.cc
   src/core/lib/compression/compression_internal.cc
-  src/core/lib/compression/compression_ruby.cc
   src/core/lib/compression/message_compress.cc
   src/core/lib/compression/stream_compression.cc
   src/core/lib/compression/stream_compression_gzip.cc
@@ -2020,6 +2334,8 @@
   src/core/lib/iomgr/gethostname_sysconf.cc
   src/core/lib/iomgr/iocp_windows.cc
   src/core/lib/iomgr/iomgr.cc
+  src/core/lib/iomgr/iomgr_custom.cc
+  src/core/lib/iomgr/iomgr_internal.cc
   src/core/lib/iomgr/iomgr_posix.cc
   src/core/lib/iomgr/iomgr_uv.cc
   src/core/lib/iomgr/iomgr_windows.cc
@@ -2028,12 +2344,16 @@
   src/core/lib/iomgr/lockfree_event.cc
   src/core/lib/iomgr/network_status_tracker.cc
   src/core/lib/iomgr/polling_entity.cc
-  src/core/lib/iomgr/pollset_set_uv.cc
+  src/core/lib/iomgr/pollset.cc
+  src/core/lib/iomgr/pollset_custom.cc
+  src/core/lib/iomgr/pollset_set.cc
+  src/core/lib/iomgr/pollset_set_custom.cc
   src/core/lib/iomgr/pollset_set_windows.cc
   src/core/lib/iomgr/pollset_uv.cc
   src/core/lib/iomgr/pollset_windows.cc
+  src/core/lib/iomgr/resolve_address.cc
+  src/core/lib/iomgr/resolve_address_custom.cc
   src/core/lib/iomgr/resolve_address_posix.cc
-  src/core/lib/iomgr/resolve_address_uv.cc
   src/core/lib/iomgr/resolve_address_windows.cc
   src/core/lib/iomgr/resource_quota.cc
   src/core/lib/iomgr/sockaddr_utils.cc
@@ -2045,19 +2365,24 @@
   src/core/lib/iomgr/socket_utils_uv.cc
   src/core/lib/iomgr/socket_utils_windows.cc
   src/core/lib/iomgr/socket_windows.cc
+  src/core/lib/iomgr/tcp_client.cc
+  src/core/lib/iomgr/tcp_client_custom.cc
   src/core/lib/iomgr/tcp_client_posix.cc
-  src/core/lib/iomgr/tcp_client_uv.cc
   src/core/lib/iomgr/tcp_client_windows.cc
+  src/core/lib/iomgr/tcp_custom.cc
   src/core/lib/iomgr/tcp_posix.cc
+  src/core/lib/iomgr/tcp_server.cc
+  src/core/lib/iomgr/tcp_server_custom.cc
   src/core/lib/iomgr/tcp_server_posix.cc
   src/core/lib/iomgr/tcp_server_utils_posix_common.cc
   src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc
   src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc
-  src/core/lib/iomgr/tcp_server_uv.cc
   src/core/lib/iomgr/tcp_server_windows.cc
   src/core/lib/iomgr/tcp_uv.cc
   src/core/lib/iomgr/tcp_windows.cc
   src/core/lib/iomgr/time_averaged_stats.cc
+  src/core/lib/iomgr/timer.cc
+  src/core/lib/iomgr/timer_custom.cc
   src/core/lib/iomgr/timer_generic.cc
   src/core/lib/iomgr/timer_heap.cc
   src/core/lib/iomgr/timer_manager.cc
@@ -2078,7 +2403,6 @@
   src/core/lib/slice/percent_encoding.cc
   src/core/lib/slice/slice.cc
   src/core/lib/slice/slice_buffer.cc
-  src/core/lib/slice/slice_hash_table.cc
   src/core/lib/slice/slice_intern.cc
   src/core/lib/slice/slice_string_helpers.cc
   src/core/lib/surface/api_trace.cc
@@ -2109,6 +2433,7 @@
   src/core/lib/transport/service_config.cc
   src/core/lib/transport/static_metadata.cc
   src/core/lib/transport/status_conversion.cc
+  src/core/lib/transport/status_metadata.cc
   src/core/lib/transport/timeout_encoding.cc
   src/core/lib/transport/transport.cc
   src/core/lib/transport/transport_op_string.cc
@@ -2157,11 +2482,11 @@
   src/core/ext/filters/client_channel/lb_policy.cc
   src/core/ext/filters/client_channel/lb_policy_factory.cc
   src/core/ext/filters/client_channel/lb_policy_registry.cc
+  src/core/ext/filters/client_channel/method_params.cc
   src/core/ext/filters/client_channel/parse_address.cc
   src/core/ext/filters/client_channel/proxy_mapper.cc
   src/core/ext/filters/client_channel/proxy_mapper_registry.cc
   src/core/ext/filters/client_channel/resolver.cc
-  src/core/ext/filters/client_channel/resolver_factory.cc
   src/core/ext/filters/client_channel/resolver_registry.cc
   src/core/ext/filters/client_channel/retry_throttle.cc
   src/core/ext/filters/client_channel/subchannel.cc
@@ -2220,12 +2545,14 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_unsecure
   ${_gRPC_BASELIB_LIBRARIES}
   ${_gRPC_ZLIB_LIBRARIES}
   ${_gRPC_CARES_LIBRARIES}
+  ${_gRPC_ADDRESS_SORTING_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gpr
 )
@@ -2255,7 +2582,6 @@
   include/grpc/byte_buffer.h
   include/grpc/byte_buffer_reader.h
   include/grpc/compression.h
-  include/grpc/compression_ruby.h
   include/grpc/fork.h
   include/grpc/grpc.h
   include/grpc/grpc_posix.h
@@ -2310,6 +2636,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(reconnect_server
@@ -2350,6 +2677,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(test_tcp_server
@@ -2430,6 +2758,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -2488,32 +2817,68 @@
   include/grpc++/support/stub_options.h
   include/grpc++/support/sync_stream.h
   include/grpc++/support/time.h
+  include/grpcpp/alarm.h
+  include/grpcpp/channel.h
+  include/grpcpp/client_context.h
+  include/grpcpp/completion_queue.h
+  include/grpcpp/create_channel.h
+  include/grpcpp/create_channel_posix.h
+  include/grpcpp/ext/health_check_service_server_builder_option.h
+  include/grpcpp/generic/async_generic_service.h
+  include/grpcpp/generic/generic_stub.h
+  include/grpcpp/grpcpp.h
+  include/grpcpp/health_check_service_interface.h
+  include/grpcpp/impl/call.h
+  include/grpcpp/impl/channel_argument_option.h
+  include/grpcpp/impl/client_unary_call.h
+  include/grpcpp/impl/codegen/core_codegen.h
+  include/grpcpp/impl/grpc_library.h
+  include/grpcpp/impl/method_handler_impl.h
+  include/grpcpp/impl/rpc_method.h
+  include/grpcpp/impl/rpc_service_method.h
+  include/grpcpp/impl/serialization_traits.h
+  include/grpcpp/impl/server_builder_option.h
+  include/grpcpp/impl/server_builder_plugin.h
+  include/grpcpp/impl/server_initializer.h
+  include/grpcpp/impl/service_type.h
+  include/grpcpp/resource_quota.h
+  include/grpcpp/security/auth_context.h
+  include/grpcpp/security/auth_metadata_processor.h
+  include/grpcpp/security/credentials.h
+  include/grpcpp/security/server_credentials.h
+  include/grpcpp/server.h
+  include/grpcpp/server_builder.h
+  include/grpcpp/server_context.h
+  include/grpcpp/server_posix.h
+  include/grpcpp/support/async_stream.h
+  include/grpcpp/support/async_unary_call.h
+  include/grpcpp/support/byte_buffer.h
+  include/grpcpp/support/channel_arguments.h
+  include/grpcpp/support/config.h
+  include/grpcpp/support/slice.h
+  include/grpcpp/support/status.h
+  include/grpcpp/support/status_code_enum.h
+  include/grpcpp/support/string_ref.h
+  include/grpcpp/support/stub_options.h
+  include/grpcpp/support/sync_stream.h
+  include/grpcpp/support/time.h
   include/grpc/support/alloc.h
   include/grpc/support/atm.h
   include/grpc/support/atm_gcc_atomic.h
   include/grpc/support/atm_gcc_sync.h
   include/grpc/support/atm_windows.h
-  include/grpc/support/avl.h
-  include/grpc/support/cmdline.h
   include/grpc/support/cpu.h
-  include/grpc/support/host_port.h
   include/grpc/support/log.h
   include/grpc/support/log_windows.h
   include/grpc/support/port_platform.h
   include/grpc/support/string_util.h
-  include/grpc/support/subprocess.h
   include/grpc/support/sync.h
   include/grpc/support/sync_custom.h
   include/grpc/support/sync_generic.h
   include/grpc/support/sync_posix.h
   include/grpc/support/sync_windows.h
-  include/grpc/support/thd.h
+  include/grpc/support/thd_id.h
   include/grpc/support/time.h
-  include/grpc/support/tls.h
-  include/grpc/support/tls_gcc.h
-  include/grpc/support/tls_msvc.h
-  include/grpc/support/tls_pthread.h
-  include/grpc/support/useful.h
   include/grpc/impl/codegen/atm.h
   include/grpc/impl/codegen/atm_gcc_atomic.h
   include/grpc/impl/codegen/atm_gcc_sync.h
@@ -2530,7 +2895,6 @@
   include/grpc/byte_buffer.h
   include/grpc/byte_buffer_reader.h
   include/grpc/compression.h
-  include/grpc/compression_ruby.h
   include/grpc/fork.h
   include/grpc/grpc.h
   include/grpc/grpc_posix.h
@@ -2578,8 +2942,40 @@
   include/grpc++/impl/codegen/stub_options.h
   include/grpc++/impl/codegen/sync_stream.h
   include/grpc++/impl/codegen/time.h
+  include/grpcpp/impl/codegen/async_stream.h
+  include/grpcpp/impl/codegen/async_unary_call.h
+  include/grpcpp/impl/codegen/byte_buffer.h
+  include/grpcpp/impl/codegen/call.h
+  include/grpcpp/impl/codegen/call_hook.h
+  include/grpcpp/impl/codegen/channel_interface.h
+  include/grpcpp/impl/codegen/client_context.h
+  include/grpcpp/impl/codegen/client_unary_call.h
+  include/grpcpp/impl/codegen/completion_queue.h
+  include/grpcpp/impl/codegen/completion_queue_tag.h
+  include/grpcpp/impl/codegen/config.h
+  include/grpcpp/impl/codegen/core_codegen_interface.h
+  include/grpcpp/impl/codegen/create_auth_context.h
+  include/grpcpp/impl/codegen/grpc_library.h
+  include/grpcpp/impl/codegen/metadata_map.h
+  include/grpcpp/impl/codegen/method_handler_impl.h
+  include/grpcpp/impl/codegen/rpc_method.h
+  include/grpcpp/impl/codegen/rpc_service_method.h
+  include/grpcpp/impl/codegen/security/auth_context.h
+  include/grpcpp/impl/codegen/serialization_traits.h
+  include/grpcpp/impl/codegen/server_context.h
+  include/grpcpp/impl/codegen/server_interface.h
+  include/grpcpp/impl/codegen/service_type.h
+  include/grpcpp/impl/codegen/slice.h
+  include/grpcpp/impl/codegen/status.h
+  include/grpcpp/impl/codegen/status_code_enum.h
+  include/grpcpp/impl/codegen/string_ref.h
+  include/grpcpp/impl/codegen/stub_options.h
+  include/grpcpp/impl/codegen/sync_stream.h
+  include/grpcpp/impl/codegen/time.h
   include/grpc++/impl/codegen/proto_utils.h
+  include/grpcpp/impl/codegen/proto_utils.h
   include/grpc++/impl/codegen/config_protobuf.h
+  include/grpcpp/impl/codegen/config_protobuf.h
 )
   string(REPLACE "include/" "" _path ${_hdr})
   get_filename_component(_path ${_path} PATH)
@@ -2599,6 +2995,7 @@
 
 if (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(grpc++_core_stats
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/core/stats.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/core/stats.grpc.pb.cc
@@ -2631,6 +3028,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -2644,6 +3042,7 @@
   grpc++
 )
 
+endif (gRPC_BUILD_CODEGEN)
 
 endif (gRPC_BUILD_TESTS)
 
@@ -2712,17 +3111,20 @@
   src/core/ext/transport/chttp2/transport/stream_map.cc
   src/core/ext/transport/chttp2/transport/varint.cc
   src/core/ext/transport/chttp2/transport/writing.cc
+  src/core/lib/avl/avl.cc
   src/core/lib/backoff/backoff.cc
   src/core/lib/channel/channel_args.cc
   src/core/lib/channel/channel_stack.cc
   src/core/lib/channel/channel_stack_builder.cc
+  src/core/lib/channel/channel_trace.cc
+  src/core/lib/channel/channel_trace_registry.cc
   src/core/lib/channel/connected_channel.cc
   src/core/lib/channel/handshaker.cc
   src/core/lib/channel/handshaker_factory.cc
   src/core/lib/channel/handshaker_registry.cc
+  src/core/lib/channel/status_util.cc
   src/core/lib/compression/compression.cc
   src/core/lib/compression/compression_internal.cc
-  src/core/lib/compression/compression_ruby.cc
   src/core/lib/compression/message_compress.cc
   src/core/lib/compression/stream_compression.cc
   src/core/lib/compression/stream_compression_gzip.cc
@@ -2754,6 +3156,8 @@
   src/core/lib/iomgr/gethostname_sysconf.cc
   src/core/lib/iomgr/iocp_windows.cc
   src/core/lib/iomgr/iomgr.cc
+  src/core/lib/iomgr/iomgr_custom.cc
+  src/core/lib/iomgr/iomgr_internal.cc
   src/core/lib/iomgr/iomgr_posix.cc
   src/core/lib/iomgr/iomgr_uv.cc
   src/core/lib/iomgr/iomgr_windows.cc
@@ -2762,12 +3166,16 @@
   src/core/lib/iomgr/lockfree_event.cc
   src/core/lib/iomgr/network_status_tracker.cc
   src/core/lib/iomgr/polling_entity.cc
-  src/core/lib/iomgr/pollset_set_uv.cc
+  src/core/lib/iomgr/pollset.cc
+  src/core/lib/iomgr/pollset_custom.cc
+  src/core/lib/iomgr/pollset_set.cc
+  src/core/lib/iomgr/pollset_set_custom.cc
   src/core/lib/iomgr/pollset_set_windows.cc
   src/core/lib/iomgr/pollset_uv.cc
   src/core/lib/iomgr/pollset_windows.cc
+  src/core/lib/iomgr/resolve_address.cc
+  src/core/lib/iomgr/resolve_address_custom.cc
   src/core/lib/iomgr/resolve_address_posix.cc
-  src/core/lib/iomgr/resolve_address_uv.cc
   src/core/lib/iomgr/resolve_address_windows.cc
   src/core/lib/iomgr/resource_quota.cc
   src/core/lib/iomgr/sockaddr_utils.cc
@@ -2779,19 +3187,24 @@
   src/core/lib/iomgr/socket_utils_uv.cc
   src/core/lib/iomgr/socket_utils_windows.cc
   src/core/lib/iomgr/socket_windows.cc
+  src/core/lib/iomgr/tcp_client.cc
+  src/core/lib/iomgr/tcp_client_custom.cc
   src/core/lib/iomgr/tcp_client_posix.cc
-  src/core/lib/iomgr/tcp_client_uv.cc
   src/core/lib/iomgr/tcp_client_windows.cc
+  src/core/lib/iomgr/tcp_custom.cc
   src/core/lib/iomgr/tcp_posix.cc
+  src/core/lib/iomgr/tcp_server.cc
+  src/core/lib/iomgr/tcp_server_custom.cc
   src/core/lib/iomgr/tcp_server_posix.cc
   src/core/lib/iomgr/tcp_server_utils_posix_common.cc
   src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc
   src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc
-  src/core/lib/iomgr/tcp_server_uv.cc
   src/core/lib/iomgr/tcp_server_windows.cc
   src/core/lib/iomgr/tcp_uv.cc
   src/core/lib/iomgr/tcp_windows.cc
   src/core/lib/iomgr/time_averaged_stats.cc
+  src/core/lib/iomgr/timer.cc
+  src/core/lib/iomgr/timer_custom.cc
   src/core/lib/iomgr/timer_generic.cc
   src/core/lib/iomgr/timer_heap.cc
   src/core/lib/iomgr/timer_manager.cc
@@ -2812,7 +3225,6 @@
   src/core/lib/slice/percent_encoding.cc
   src/core/lib/slice/slice.cc
   src/core/lib/slice/slice_buffer.cc
-  src/core/lib/slice/slice_hash_table.cc
   src/core/lib/slice/slice_intern.cc
   src/core/lib/slice/slice_string_helpers.cc
   src/core/lib/surface/api_trace.cc
@@ -2843,6 +3255,7 @@
   src/core/lib/transport/service_config.cc
   src/core/lib/transport/static_metadata.cc
   src/core/lib/transport/status_conversion.cc
+  src/core/lib/transport/status_metadata.cc
   src/core/lib/transport/timeout_encoding.cc
   src/core/lib/transport/transport.cc
   src/core/lib/transport/transport_op_string.cc
@@ -2863,11 +3276,11 @@
   src/core/ext/filters/client_channel/lb_policy.cc
   src/core/ext/filters/client_channel/lb_policy_factory.cc
   src/core/ext/filters/client_channel/lb_policy_registry.cc
+  src/core/ext/filters/client_channel/method_params.cc
   src/core/ext/filters/client_channel/parse_address.cc
   src/core/ext/filters/client_channel/proxy_mapper.cc
   src/core/ext/filters/client_channel/proxy_mapper_registry.cc
   src/core/ext/filters/client_channel/resolver.cc
-  src/core/ext/filters/client_channel/resolver_factory.cc
   src/core/ext/filters/client_channel/resolver_registry.cc
   src/core/ext/filters/client_channel/retry_throttle.cc
   src/core/ext/filters/client_channel/subchannel.cc
@@ -2904,6 +3317,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -2963,32 +3377,68 @@
   include/grpc++/support/stub_options.h
   include/grpc++/support/sync_stream.h
   include/grpc++/support/time.h
+  include/grpcpp/alarm.h
+  include/grpcpp/channel.h
+  include/grpcpp/client_context.h
+  include/grpcpp/completion_queue.h
+  include/grpcpp/create_channel.h
+  include/grpcpp/create_channel_posix.h
+  include/grpcpp/ext/health_check_service_server_builder_option.h
+  include/grpcpp/generic/async_generic_service.h
+  include/grpcpp/generic/generic_stub.h
+  include/grpcpp/grpcpp.h
+  include/grpcpp/health_check_service_interface.h
+  include/grpcpp/impl/call.h
+  include/grpcpp/impl/channel_argument_option.h
+  include/grpcpp/impl/client_unary_call.h
+  include/grpcpp/impl/codegen/core_codegen.h
+  include/grpcpp/impl/grpc_library.h
+  include/grpcpp/impl/method_handler_impl.h
+  include/grpcpp/impl/rpc_method.h
+  include/grpcpp/impl/rpc_service_method.h
+  include/grpcpp/impl/serialization_traits.h
+  include/grpcpp/impl/server_builder_option.h
+  include/grpcpp/impl/server_builder_plugin.h
+  include/grpcpp/impl/server_initializer.h
+  include/grpcpp/impl/service_type.h
+  include/grpcpp/resource_quota.h
+  include/grpcpp/security/auth_context.h
+  include/grpcpp/security/auth_metadata_processor.h
+  include/grpcpp/security/credentials.h
+  include/grpcpp/security/server_credentials.h
+  include/grpcpp/server.h
+  include/grpcpp/server_builder.h
+  include/grpcpp/server_context.h
+  include/grpcpp/server_posix.h
+  include/grpcpp/support/async_stream.h
+  include/grpcpp/support/async_unary_call.h
+  include/grpcpp/support/byte_buffer.h
+  include/grpcpp/support/channel_arguments.h
+  include/grpcpp/support/config.h
+  include/grpcpp/support/slice.h
+  include/grpcpp/support/status.h
+  include/grpcpp/support/status_code_enum.h
+  include/grpcpp/support/string_ref.h
+  include/grpcpp/support/stub_options.h
+  include/grpcpp/support/sync_stream.h
+  include/grpcpp/support/time.h
   include/grpc/support/alloc.h
   include/grpc/support/atm.h
   include/grpc/support/atm_gcc_atomic.h
   include/grpc/support/atm_gcc_sync.h
   include/grpc/support/atm_windows.h
-  include/grpc/support/avl.h
-  include/grpc/support/cmdline.h
   include/grpc/support/cpu.h
-  include/grpc/support/host_port.h
   include/grpc/support/log.h
   include/grpc/support/log_windows.h
   include/grpc/support/port_platform.h
   include/grpc/support/string_util.h
-  include/grpc/support/subprocess.h
   include/grpc/support/sync.h
   include/grpc/support/sync_custom.h
   include/grpc/support/sync_generic.h
   include/grpc/support/sync_posix.h
   include/grpc/support/sync_windows.h
-  include/grpc/support/thd.h
+  include/grpc/support/thd_id.h
   include/grpc/support/time.h
-  include/grpc/support/tls.h
-  include/grpc/support/tls_gcc.h
-  include/grpc/support/tls_msvc.h
-  include/grpc/support/tls_pthread.h
-  include/grpc/support/useful.h
   include/grpc/impl/codegen/atm.h
   include/grpc/impl/codegen/atm_gcc_atomic.h
   include/grpc/impl/codegen/atm_gcc_sync.h
@@ -3005,7 +3455,6 @@
   include/grpc/byte_buffer.h
   include/grpc/byte_buffer_reader.h
   include/grpc/compression.h
-  include/grpc/compression_ruby.h
   include/grpc/fork.h
   include/grpc/grpc.h
   include/grpc/grpc_posix.h
@@ -3053,6 +3502,36 @@
   include/grpc++/impl/codegen/stub_options.h
   include/grpc++/impl/codegen/sync_stream.h
   include/grpc++/impl/codegen/time.h
+  include/grpcpp/impl/codegen/async_stream.h
+  include/grpcpp/impl/codegen/async_unary_call.h
+  include/grpcpp/impl/codegen/byte_buffer.h
+  include/grpcpp/impl/codegen/call.h
+  include/grpcpp/impl/codegen/call_hook.h
+  include/grpcpp/impl/codegen/channel_interface.h
+  include/grpcpp/impl/codegen/client_context.h
+  include/grpcpp/impl/codegen/client_unary_call.h
+  include/grpcpp/impl/codegen/completion_queue.h
+  include/grpcpp/impl/codegen/completion_queue_tag.h
+  include/grpcpp/impl/codegen/config.h
+  include/grpcpp/impl/codegen/core_codegen_interface.h
+  include/grpcpp/impl/codegen/create_auth_context.h
+  include/grpcpp/impl/codegen/grpc_library.h
+  include/grpcpp/impl/codegen/metadata_map.h
+  include/grpcpp/impl/codegen/method_handler_impl.h
+  include/grpcpp/impl/codegen/rpc_method.h
+  include/grpcpp/impl/codegen/rpc_service_method.h
+  include/grpcpp/impl/codegen/security/auth_context.h
+  include/grpcpp/impl/codegen/serialization_traits.h
+  include/grpcpp/impl/codegen/server_context.h
+  include/grpcpp/impl/codegen/server_interface.h
+  include/grpcpp/impl/codegen/service_type.h
+  include/grpcpp/impl/codegen/slice.h
+  include/grpcpp/impl/codegen/status.h
+  include/grpcpp/impl/codegen/status_code_enum.h
+  include/grpcpp/impl/codegen/string_ref.h
+  include/grpcpp/impl/codegen/stub_options.h
+  include/grpcpp/impl/codegen/sync_stream.h
+  include/grpcpp/impl/codegen/time.h
   include/grpc/census.h
 )
   string(REPLACE "include/" "" _path ${_hdr})
@@ -3072,6 +3551,7 @@
 endif()
 
 
+if (gRPC_BUILD_CODEGEN)
 add_library(grpc++_error_details
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/status/status.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/status/status.grpc.pb.cc
@@ -3104,6 +3584,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -3116,6 +3597,7 @@
 
 foreach(_hdr
   include/grpc++/support/error_details.h
+  include/grpcpp/support/error_details.h
 )
   string(REPLACE "include/" "" _path ${_hdr})
   get_filename_component(_path ${_path} PATH)
@@ -3123,6 +3605,7 @@
     DESTINATION "${gRPC_INSTALL_INCLUDEDIR}/${_path}"
   )
 endforeach()
+endif (gRPC_BUILD_CODEGEN)
 
 
 if (gRPC_INSTALL)
@@ -3135,6 +3618,7 @@
 
 if (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(grpc++_proto_reflection_desc_db
   test/cpp/util/proto_reflection_descriptor_database.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/reflection/v1alpha/reflection.pb.cc
@@ -3167,6 +3651,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -3183,6 +3668,7 @@
 
 foreach(_hdr
   include/grpc++/impl/codegen/config_protobuf.h
+  include/grpcpp/impl/codegen/config_protobuf.h
 )
   string(REPLACE "include/" "" _path ${_hdr})
   get_filename_component(_path ${_path} PATH)
@@ -3190,9 +3676,11 @@
     DESTINATION "${gRPC_INSTALL_INCLUDEDIR}/${_path}"
   )
 endforeach()
+endif (gRPC_BUILD_CODEGEN)
 
 endif (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(grpc++_reflection
   src/cpp/ext/proto_server_reflection.cc
   src/cpp/ext/proto_server_reflection_plugin.cc
@@ -3226,6 +3714,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -3238,6 +3727,7 @@
 
 foreach(_hdr
   include/grpc++/ext/proto_server_reflection_plugin.h
+  include/grpcpp/ext/proto_server_reflection_plugin.h
 )
   string(REPLACE "include/" "" _path ${_hdr})
   get_filename_component(_path ${_path} PATH)
@@ -3245,6 +3735,7 @@
     DESTINATION "${gRPC_INSTALL_INCLUDEDIR}/${_path}"
   )
 endforeach()
+endif (gRPC_BUILD_CODEGEN)
 
 
 if (gRPC_INSTALL)
@@ -3282,6 +3773,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -3298,7 +3790,12 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(grpc++_test_util
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.grpc.pb.h
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/health/v1/health.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/health/v1/health.grpc.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/health/v1/health.pb.h
@@ -3318,6 +3815,7 @@
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h
   test/cpp/end2end/test_service_impl.cc
   test/cpp/util/byte_buffer_proto_helper.cc
+  test/cpp/util/channel_trace_proto_helper.cc
   test/cpp/util/create_test_channel.cc
   test/cpp/util/string_ref_helper.cc
   test/cpp/util/subprocess.cc
@@ -3337,6 +3835,9 @@
 endif()
 
 protobuf_generate_grpc_cpp(
+  src/proto/grpc/channelz/channelz.proto
+)
+protobuf_generate_grpc_cpp(
   src/proto/grpc/health/v1/health.proto
 )
 protobuf_generate_grpc_cpp(
@@ -3358,6 +3859,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -3404,6 +3906,36 @@
   include/grpc++/impl/codegen/stub_options.h
   include/grpc++/impl/codegen/sync_stream.h
   include/grpc++/impl/codegen/time.h
+  include/grpcpp/impl/codegen/async_stream.h
+  include/grpcpp/impl/codegen/async_unary_call.h
+  include/grpcpp/impl/codegen/byte_buffer.h
+  include/grpcpp/impl/codegen/call.h
+  include/grpcpp/impl/codegen/call_hook.h
+  include/grpcpp/impl/codegen/channel_interface.h
+  include/grpcpp/impl/codegen/client_context.h
+  include/grpcpp/impl/codegen/client_unary_call.h
+  include/grpcpp/impl/codegen/completion_queue.h
+  include/grpcpp/impl/codegen/completion_queue_tag.h
+  include/grpcpp/impl/codegen/config.h
+  include/grpcpp/impl/codegen/core_codegen_interface.h
+  include/grpcpp/impl/codegen/create_auth_context.h
+  include/grpcpp/impl/codegen/grpc_library.h
+  include/grpcpp/impl/codegen/metadata_map.h
+  include/grpcpp/impl/codegen/method_handler_impl.h
+  include/grpcpp/impl/codegen/rpc_method.h
+  include/grpcpp/impl/codegen/rpc_service_method.h
+  include/grpcpp/impl/codegen/security/auth_context.h
+  include/grpcpp/impl/codegen/serialization_traits.h
+  include/grpcpp/impl/codegen/server_context.h
+  include/grpcpp/impl/codegen/server_interface.h
+  include/grpcpp/impl/codegen/service_type.h
+  include/grpcpp/impl/codegen/slice.h
+  include/grpcpp/impl/codegen/status.h
+  include/grpcpp/impl/codegen/status_code_enum.h
+  include/grpcpp/impl/codegen/string_ref.h
+  include/grpcpp/impl/codegen/stub_options.h
+  include/grpcpp/impl/codegen/sync_stream.h
+  include/grpcpp/impl/codegen/time.h
   include/grpc/impl/codegen/byte_buffer.h
   include/grpc/impl/codegen/byte_buffer_reader.h
   include/grpc/impl/codegen/compression_types.h
@@ -3426,7 +3958,9 @@
   include/grpc/impl/codegen/sync_posix.h
   include/grpc/impl/codegen/sync_windows.h
   include/grpc++/impl/codegen/proto_utils.h
+  include/grpcpp/impl/codegen/proto_utils.h
   include/grpc++/impl/codegen/config_protobuf.h
+  include/grpcpp/impl/codegen/config_protobuf.h
 )
   string(REPLACE "include/" "" _path ${_hdr})
   get_filename_component(_path ${_path} PATH)
@@ -3434,10 +3968,12 @@
     DESTINATION "${gRPC_INSTALL_INCLUDEDIR}/${_path}"
   )
 endforeach()
+endif (gRPC_BUILD_CODEGEN)
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(grpc++_test_util_unsecure
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/health/v1/health.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/health/v1/health.grpc.pb.cc
@@ -3496,6 +4032,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -3542,6 +4079,36 @@
   include/grpc++/impl/codegen/stub_options.h
   include/grpc++/impl/codegen/sync_stream.h
   include/grpc++/impl/codegen/time.h
+  include/grpcpp/impl/codegen/async_stream.h
+  include/grpcpp/impl/codegen/async_unary_call.h
+  include/grpcpp/impl/codegen/byte_buffer.h
+  include/grpcpp/impl/codegen/call.h
+  include/grpcpp/impl/codegen/call_hook.h
+  include/grpcpp/impl/codegen/channel_interface.h
+  include/grpcpp/impl/codegen/client_context.h
+  include/grpcpp/impl/codegen/client_unary_call.h
+  include/grpcpp/impl/codegen/completion_queue.h
+  include/grpcpp/impl/codegen/completion_queue_tag.h
+  include/grpcpp/impl/codegen/config.h
+  include/grpcpp/impl/codegen/core_codegen_interface.h
+  include/grpcpp/impl/codegen/create_auth_context.h
+  include/grpcpp/impl/codegen/grpc_library.h
+  include/grpcpp/impl/codegen/metadata_map.h
+  include/grpcpp/impl/codegen/method_handler_impl.h
+  include/grpcpp/impl/codegen/rpc_method.h
+  include/grpcpp/impl/codegen/rpc_service_method.h
+  include/grpcpp/impl/codegen/security/auth_context.h
+  include/grpcpp/impl/codegen/serialization_traits.h
+  include/grpcpp/impl/codegen/server_context.h
+  include/grpcpp/impl/codegen/server_interface.h
+  include/grpcpp/impl/codegen/service_type.h
+  include/grpcpp/impl/codegen/slice.h
+  include/grpcpp/impl/codegen/status.h
+  include/grpcpp/impl/codegen/status_code_enum.h
+  include/grpcpp/impl/codegen/string_ref.h
+  include/grpcpp/impl/codegen/stub_options.h
+  include/grpcpp/impl/codegen/sync_stream.h
+  include/grpcpp/impl/codegen/time.h
   include/grpc/impl/codegen/byte_buffer.h
   include/grpc/impl/codegen/byte_buffer_reader.h
   include/grpc/impl/codegen/compression_types.h
@@ -3564,7 +4131,9 @@
   include/grpc/impl/codegen/sync_posix.h
   include/grpc/impl/codegen/sync_windows.h
   include/grpc++/impl/codegen/proto_utils.h
+  include/grpcpp/impl/codegen/proto_utils.h
   include/grpc++/impl/codegen/config_protobuf.h
+  include/grpcpp/impl/codegen/config_protobuf.h
 )
   string(REPLACE "include/" "" _path ${_hdr})
   get_filename_component(_path ${_path} PATH)
@@ -3572,6 +4141,7 @@
     DESTINATION "${gRPC_INSTALL_INCLUDEDIR}/${_path}"
   )
 endforeach()
+endif (gRPC_BUILD_CODEGEN)
 
 endif (gRPC_BUILD_TESTS)
 
@@ -3637,6 +4207,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -3694,32 +4265,68 @@
   include/grpc++/support/stub_options.h
   include/grpc++/support/sync_stream.h
   include/grpc++/support/time.h
+  include/grpcpp/alarm.h
+  include/grpcpp/channel.h
+  include/grpcpp/client_context.h
+  include/grpcpp/completion_queue.h
+  include/grpcpp/create_channel.h
+  include/grpcpp/create_channel_posix.h
+  include/grpcpp/ext/health_check_service_server_builder_option.h
+  include/grpcpp/generic/async_generic_service.h
+  include/grpcpp/generic/generic_stub.h
+  include/grpcpp/grpcpp.h
+  include/grpcpp/health_check_service_interface.h
+  include/grpcpp/impl/call.h
+  include/grpcpp/impl/channel_argument_option.h
+  include/grpcpp/impl/client_unary_call.h
+  include/grpcpp/impl/codegen/core_codegen.h
+  include/grpcpp/impl/grpc_library.h
+  include/grpcpp/impl/method_handler_impl.h
+  include/grpcpp/impl/rpc_method.h
+  include/grpcpp/impl/rpc_service_method.h
+  include/grpcpp/impl/serialization_traits.h
+  include/grpcpp/impl/server_builder_option.h
+  include/grpcpp/impl/server_builder_plugin.h
+  include/grpcpp/impl/server_initializer.h
+  include/grpcpp/impl/service_type.h
+  include/grpcpp/resource_quota.h
+  include/grpcpp/security/auth_context.h
+  include/grpcpp/security/auth_metadata_processor.h
+  include/grpcpp/security/credentials.h
+  include/grpcpp/security/server_credentials.h
+  include/grpcpp/server.h
+  include/grpcpp/server_builder.h
+  include/grpcpp/server_context.h
+  include/grpcpp/server_posix.h
+  include/grpcpp/support/async_stream.h
+  include/grpcpp/support/async_unary_call.h
+  include/grpcpp/support/byte_buffer.h
+  include/grpcpp/support/channel_arguments.h
+  include/grpcpp/support/config.h
+  include/grpcpp/support/slice.h
+  include/grpcpp/support/status.h
+  include/grpcpp/support/status_code_enum.h
+  include/grpcpp/support/string_ref.h
+  include/grpcpp/support/stub_options.h
+  include/grpcpp/support/sync_stream.h
+  include/grpcpp/support/time.h
   include/grpc/support/alloc.h
   include/grpc/support/atm.h
   include/grpc/support/atm_gcc_atomic.h
   include/grpc/support/atm_gcc_sync.h
   include/grpc/support/atm_windows.h
-  include/grpc/support/avl.h
-  include/grpc/support/cmdline.h
   include/grpc/support/cpu.h
-  include/grpc/support/host_port.h
   include/grpc/support/log.h
   include/grpc/support/log_windows.h
   include/grpc/support/port_platform.h
   include/grpc/support/string_util.h
-  include/grpc/support/subprocess.h
   include/grpc/support/sync.h
   include/grpc/support/sync_custom.h
   include/grpc/support/sync_generic.h
   include/grpc/support/sync_posix.h
   include/grpc/support/sync_windows.h
-  include/grpc/support/thd.h
+  include/grpc/support/thd_id.h
   include/grpc/support/time.h
-  include/grpc/support/tls.h
-  include/grpc/support/tls_gcc.h
-  include/grpc/support/tls_msvc.h
-  include/grpc/support/tls_pthread.h
-  include/grpc/support/useful.h
   include/grpc/impl/codegen/atm.h
   include/grpc/impl/codegen/atm_gcc_atomic.h
   include/grpc/impl/codegen/atm_gcc_sync.h
@@ -3736,7 +4343,6 @@
   include/grpc/byte_buffer.h
   include/grpc/byte_buffer_reader.h
   include/grpc/compression.h
-  include/grpc/compression_ruby.h
   include/grpc/fork.h
   include/grpc/grpc.h
   include/grpc/grpc_posix.h
@@ -3784,6 +4390,36 @@
   include/grpc++/impl/codegen/stub_options.h
   include/grpc++/impl/codegen/sync_stream.h
   include/grpc++/impl/codegen/time.h
+  include/grpcpp/impl/codegen/async_stream.h
+  include/grpcpp/impl/codegen/async_unary_call.h
+  include/grpcpp/impl/codegen/byte_buffer.h
+  include/grpcpp/impl/codegen/call.h
+  include/grpcpp/impl/codegen/call_hook.h
+  include/grpcpp/impl/codegen/channel_interface.h
+  include/grpcpp/impl/codegen/client_context.h
+  include/grpcpp/impl/codegen/client_unary_call.h
+  include/grpcpp/impl/codegen/completion_queue.h
+  include/grpcpp/impl/codegen/completion_queue_tag.h
+  include/grpcpp/impl/codegen/config.h
+  include/grpcpp/impl/codegen/core_codegen_interface.h
+  include/grpcpp/impl/codegen/create_auth_context.h
+  include/grpcpp/impl/codegen/grpc_library.h
+  include/grpcpp/impl/codegen/metadata_map.h
+  include/grpcpp/impl/codegen/method_handler_impl.h
+  include/grpcpp/impl/codegen/rpc_method.h
+  include/grpcpp/impl/codegen/rpc_service_method.h
+  include/grpcpp/impl/codegen/security/auth_context.h
+  include/grpcpp/impl/codegen/serialization_traits.h
+  include/grpcpp/impl/codegen/server_context.h
+  include/grpcpp/impl/codegen/server_interface.h
+  include/grpcpp/impl/codegen/service_type.h
+  include/grpcpp/impl/codegen/slice.h
+  include/grpcpp/impl/codegen/status.h
+  include/grpcpp/impl/codegen/status_code_enum.h
+  include/grpcpp/impl/codegen/string_ref.h
+  include/grpcpp/impl/codegen/stub_options.h
+  include/grpcpp/impl/codegen/sync_stream.h
+  include/grpcpp/impl/codegen/time.h
 )
   string(REPLACE "include/" "" _path ${_hdr})
   get_filename_component(_path ${_path} PATH)
@@ -3828,6 +4464,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -3849,6 +4486,7 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(grpc_cli_libs
   test/cpp/util/cli_call.cc
   test/cpp/util/cli_credentials.cc
@@ -3885,6 +4523,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -3902,6 +4541,7 @@
 
 foreach(_hdr
   include/grpc++/impl/codegen/config_protobuf.h
+  include/grpcpp/impl/codegen/config_protobuf.h
 )
   string(REPLACE "include/" "" _path ${_hdr})
   get_filename_component(_path ${_path} PATH)
@@ -3909,6 +4549,7 @@
     DESTINATION "${gRPC_INSTALL_INCLUDEDIR}/${_path}"
   )
 endforeach()
+endif (gRPC_BUILD_CODEGEN)
 
 endif (gRPC_BUILD_TESTS)
 
@@ -3943,6 +4584,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -3954,6 +4596,7 @@
 
 foreach(_hdr
   include/grpc++/impl/codegen/config_protobuf.h
+  include/grpcpp/impl/codegen/config_protobuf.h
 )
   string(REPLACE "include/" "" _path ${_hdr})
   get_filename_component(_path ${_path} PATH)
@@ -3973,6 +4616,7 @@
 
 if (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(http2_client_main
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.grpc.pb.cc
@@ -4019,6 +4663,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -4036,10 +4681,12 @@
   grpc++_test_config
 )
 
+endif (gRPC_BUILD_CODEGEN)
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(interop_client_helper
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/messages.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/messages.grpc.pb.cc
@@ -4072,6 +4719,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -4089,10 +4737,12 @@
   gpr
 )
 
+endif (gRPC_BUILD_CODEGEN)
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(interop_client_main
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.grpc.pb.cc
@@ -4140,6 +4790,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -4160,6 +4811,7 @@
   grpc++_test_config
 )
 
+endif (gRPC_BUILD_CODEGEN)
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
@@ -4189,6 +4841,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -4210,6 +4863,7 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(interop_server_lib
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.grpc.pb.cc
@@ -4256,6 +4910,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -4276,6 +4931,7 @@
   grpc++_test_config
 )
 
+endif (gRPC_BUILD_CODEGEN)
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
@@ -4305,6 +4961,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -4322,6 +4979,7 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(qps
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/messages.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/messages.grpc.pb.cc
@@ -4391,6 +5049,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -4408,6 +5067,7 @@
   grpc
 )
 
+endif (gRPC_BUILD_CODEGEN)
 
 endif (gRPC_BUILD_TESTS)
 
@@ -4436,6 +5096,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_csharp_ext
@@ -4481,6 +5142,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(bad_client_test
@@ -4520,6 +5182,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(bad_ssl_test_server
@@ -4582,6 +5245,21 @@
   test/core/end2end/tests/request_with_flags.cc
   test/core/end2end/tests/request_with_payload.cc
   test/core/end2end/tests/resource_quota_server.cc
+  test/core/end2end/tests/retry.cc
+  test/core/end2end/tests/retry_cancellation.cc
+  test/core/end2end/tests/retry_disabled.cc
+  test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc
+  test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc
+  test/core/end2end/tests/retry_non_retriable_status.cc
+  test/core/end2end/tests/retry_recv_initial_metadata.cc
+  test/core/end2end/tests/retry_recv_message.cc
+  test/core/end2end/tests/retry_server_pushback_delay.cc
+  test/core/end2end/tests/retry_server_pushback_disabled.cc
+  test/core/end2end/tests/retry_streaming.cc
+  test/core/end2end/tests/retry_streaming_after_commit.cc
+  test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc
+  test/core/end2end/tests/retry_throttled.cc
+  test/core/end2end/tests/retry_too_many_attempts.cc
   test/core/end2end/tests/server_finishes_request.cc
   test/core/end2end/tests/shutdown_finishes_calls.cc
   test/core/end2end/tests/shutdown_finishes_tags.cc
@@ -4620,6 +5298,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(end2end_tests
@@ -4682,6 +5361,21 @@
   test/core/end2end/tests/request_with_flags.cc
   test/core/end2end/tests/request_with_payload.cc
   test/core/end2end/tests/resource_quota_server.cc
+  test/core/end2end/tests/retry.cc
+  test/core/end2end/tests/retry_cancellation.cc
+  test/core/end2end/tests/retry_disabled.cc
+  test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc
+  test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc
+  test/core/end2end/tests/retry_non_retriable_status.cc
+  test/core/end2end/tests/retry_recv_initial_metadata.cc
+  test/core/end2end/tests/retry_recv_message.cc
+  test/core/end2end/tests/retry_server_pushback_delay.cc
+  test/core/end2end/tests/retry_server_pushback_disabled.cc
+  test/core/end2end/tests/retry_streaming.cc
+  test/core/end2end/tests/retry_streaming_after_commit.cc
+  test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc
+  test/core/end2end/tests/retry_throttled.cc
+  test/core/end2end/tests/retry_too_many_attempts.cc
   test/core/end2end/tests/server_finishes_request.cc
   test/core/end2end/tests/shutdown_finishes_calls.cc
   test/core/end2end/tests/shutdown_finishes_tags.cc
@@ -4720,6 +5414,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(end2end_nosec_tests
@@ -4749,6 +5444,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(algorithm_test
@@ -4776,6 +5472,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(alloc_test
@@ -4801,6 +5498,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(alpn_test
@@ -4828,6 +5526,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(arena_test
@@ -4839,6 +5538,33 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(avl_test
+  test/core/avl/avl_test.cc
+)
+
+
+target_include_directories(avl_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+)
+
+target_link_libraries(avl_test
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  gpr_test_util
+  gpr
+  grpc
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
 add_executable(bad_server_response_test
   test/core/end2end/bad_server_response_test.cc
 )
@@ -4853,6 +5579,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(bad_server_response_test
@@ -4881,6 +5608,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(bin_decoder_test
@@ -4906,6 +5634,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(bin_encoder_test
@@ -4917,33 +5646,6 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
-add_executable(byte_stream_test
-  test/core/transport/byte_stream_test.cc
-)
-
-
-target_include_directories(byte_stream_test
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
-  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
-  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
-  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
-  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
-  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
-  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
-)
-
-target_link_libraries(byte_stream_test
-  ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
-  grpc
-  gpr_test_util
-  gpr
-)
-
-endif (gRPC_BUILD_TESTS)
-if (gRPC_BUILD_TESTS)
-
 add_executable(channel_create_test
   test/core/surface/channel_create_test.cc
 )
@@ -4958,6 +5660,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(channel_create_test
@@ -4984,6 +5687,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(check_epollexclusive
@@ -5017,6 +5721,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(chttp2_hpack_encoder_test
@@ -5044,6 +5749,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(chttp2_stream_map_test
@@ -5071,6 +5777,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(chttp2_varint_test
@@ -5084,6 +5791,33 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(cmdline_test
+  test/core/util/cmdline_test.cc
+)
+
+
+target_include_directories(cmdline_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+)
+
+target_link_libraries(cmdline_test
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  gpr
+  gpr_test_util
+  grpc_test_util
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
 add_executable(combiner_test
   test/core/iomgr/combiner_test.cc
 )
@@ -5098,6 +5832,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(combiner_test
@@ -5125,6 +5860,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(compression_test
@@ -5152,6 +5888,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(concurrent_connectivity_test
@@ -5179,6 +5916,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(connection_refused_test
@@ -5206,6 +5944,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(dns_resolver_connectivity_test
@@ -5233,6 +5972,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(dns_resolver_cooldown_test
@@ -5260,6 +6000,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(dns_resolver_test
@@ -5288,6 +6029,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(dualstack_socket_test
@@ -5316,6 +6058,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(endpoint_pair_test
@@ -5343,6 +6086,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(error_test
@@ -5371,6 +6115,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(ev_epollsig_linux_test
@@ -5399,6 +6144,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(fake_resolver_test
@@ -5428,6 +6174,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(fake_transport_security_test
@@ -5456,6 +6203,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(fd_conservation_posix_test
@@ -5485,6 +6233,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(fd_posix_test
@@ -5513,6 +6262,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(fling_client
@@ -5540,6 +6290,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(fling_server
@@ -5568,6 +6319,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(fling_stream_test
@@ -5597,6 +6349,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(fling_test
@@ -5626,6 +6379,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(goaway_server_test
@@ -5640,56 +6394,6 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
-add_executable(gpr_avl_test
-  test/core/gpr/avl_test.cc
-)
-
-
-target_include_directories(gpr_avl_test
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
-  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
-  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
-  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
-  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
-  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
-  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
-)
-
-target_link_libraries(gpr_avl_test
-  ${_gRPC_ALLTARGETS_LIBRARIES}
-  gpr_test_util
-  gpr
-)
-
-endif (gRPC_BUILD_TESTS)
-if (gRPC_BUILD_TESTS)
-
-add_executable(gpr_cmdline_test
-  test/core/gpr/cmdline_test.cc
-)
-
-
-target_include_directories(gpr_cmdline_test
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
-  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
-  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
-  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
-  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
-  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
-  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
-)
-
-target_link_libraries(gpr_cmdline_test
-  ${_gRPC_ALLTARGETS_LIBRARIES}
-  gpr_test_util
-  gpr
-)
-
-endif (gRPC_BUILD_TESTS)
-if (gRPC_BUILD_TESTS)
-
 add_executable(gpr_cpu_test
   test/core/gpr/cpu_test.cc
 )
@@ -5704,6 +6408,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(gpr_cpu_test
@@ -5729,6 +6434,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(gpr_env_test
@@ -5754,6 +6460,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(gpr_host_port_test
@@ -5779,6 +6486,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(gpr_log_test
@@ -5804,6 +6512,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(gpr_manual_constructor_test
@@ -5829,6 +6538,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(gpr_mpscq_test
@@ -5854,6 +6564,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(gpr_spinlock_test
@@ -5879,6 +6590,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(gpr_string_test
@@ -5904,6 +6616,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(gpr_sync_test
@@ -5916,7 +6629,7 @@
 if (gRPC_BUILD_TESTS)
 
 add_executable(gpr_thd_test
-  test/core/gpr/thd_test.cc
+  test/core/gprpp/thd_test.cc
 )
 
 
@@ -5929,6 +6642,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(gpr_thd_test
@@ -5954,6 +6668,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(gpr_time_test
@@ -5979,6 +6694,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(gpr_tls_test
@@ -6004,6 +6720,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(gpr_useful_test
@@ -6029,6 +6746,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_auth_context_test
@@ -6056,6 +6774,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_b64_test
@@ -6083,6 +6802,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_byte_buffer_reader_test
@@ -6110,6 +6830,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_channel_args_test
@@ -6137,6 +6858,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_channel_stack_builder_test
@@ -6164,6 +6886,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_channel_stack_test
@@ -6191,6 +6914,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_completion_queue_test
@@ -6218,6 +6942,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_completion_queue_threading_test
@@ -6232,6 +6957,7 @@
 
 add_executable(grpc_create_jwt
   test/core/security/create_jwt.cc
+  test/core/util/cmdline.cc
 )
 
 
@@ -6244,6 +6970,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_create_jwt
@@ -6278,6 +7005,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_credentials_test
@@ -6305,6 +7033,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_fetch_oauth2
@@ -6332,6 +7061,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_invalid_channel_args_test
@@ -6360,6 +7090,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_json_token_test
@@ -6388,6 +7119,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_jwt_verifier_test
@@ -6402,6 +7134,7 @@
 
 add_executable(grpc_print_google_default_creds_token
   test/core/security/print_google_default_creds_token.cc
+  test/core/util/cmdline.cc
 )
 
 
@@ -6414,6 +7147,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_print_google_default_creds_token
@@ -6447,6 +7181,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_security_connector_test
@@ -6474,6 +7209,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_ssl_credentials_test
@@ -6488,6 +7224,7 @@
 
 add_executable(grpc_verify_jwt
   test/core/security/verify_jwt.cc
+  test/core/util/cmdline.cc
 )
 
 
@@ -6500,6 +7237,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(grpc_verify_jwt
@@ -6534,6 +7272,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(handshake_client
@@ -6565,6 +7304,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(handshake_server
@@ -6596,6 +7336,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(handshake_server_with_readahead_handshaker
@@ -6625,6 +7366,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(histogram_test
@@ -6650,6 +7392,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(hpack_parser_test
@@ -6677,6 +7420,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(hpack_table_test
@@ -6704,6 +7448,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(http_parser_test
@@ -6731,6 +7476,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(httpcli_format_request_test
@@ -6759,6 +7505,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(httpcli_test
@@ -6788,6 +7535,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(httpscli_test
@@ -6816,6 +7564,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(init_test
@@ -6843,6 +7592,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(invalid_call_argument_test
@@ -6870,11 +7620,14 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(json_rewrite
   ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_test_util
   grpc
+  gpr_test_util
   gpr
 )
 
@@ -6895,6 +7648,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(json_rewrite_test
@@ -6922,6 +7676,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(json_stream_error_test
@@ -6949,6 +7704,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(json_test
@@ -6976,6 +7732,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(lame_client_test
@@ -7003,6 +7760,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(load_file_test
@@ -7030,6 +7788,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(memory_profile_client
@@ -7057,6 +7816,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(memory_profile_server
@@ -7085,6 +7845,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(memory_profile_test
@@ -7113,6 +7874,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(message_compress_test
@@ -7140,6 +7902,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(minimal_stack_is_minimal_test
@@ -7167,6 +7930,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(multiple_server_queues_test
@@ -7194,6 +7958,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(murmur_hash_test
@@ -7219,6 +7984,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(no_server_test
@@ -7246,6 +8012,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(num_external_connectivity_watchers_test
@@ -7273,6 +8040,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(parse_address_test
@@ -7300,6 +8068,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(percent_encoding_test
@@ -7328,6 +8097,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(pollset_set_test
@@ -7357,6 +8127,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(resolve_address_posix_test
@@ -7385,6 +8156,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(resolve_address_test
@@ -7412,6 +8184,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(resource_quota_test
@@ -7439,6 +8212,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(secure_channel_create_test
@@ -7466,6 +8240,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(secure_endpoint_test
@@ -7493,6 +8268,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(sequential_connectivity_test
@@ -7520,6 +8296,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(server_chttp2_test
@@ -7547,6 +8324,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(server_test
@@ -7574,6 +8352,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(slice_buffer_test
@@ -7587,33 +8366,6 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
-add_executable(slice_hash_table_test
-  test/core/slice/slice_hash_table_test.cc
-)
-
-
-target_include_directories(slice_hash_table_test
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
-  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
-  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
-  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
-  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
-  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
-  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
-)
-
-target_link_libraries(slice_hash_table_test
-  ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
-  grpc
-  gpr_test_util
-  gpr
-)
-
-endif (gRPC_BUILD_TESTS)
-if (gRPC_BUILD_TESTS)
-
 add_executable(slice_string_helpers_test
   test/core/slice/slice_string_helpers_test.cc
 )
@@ -7628,6 +8380,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(slice_string_helpers_test
@@ -7655,6 +8408,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(slice_test
@@ -7682,6 +8436,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(sockaddr_resolver_test
@@ -7709,6 +8464,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(sockaddr_utils_test
@@ -7737,6 +8493,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(socket_utils_test
@@ -7767,6 +8524,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(ssl_transport_security_test
@@ -7794,6 +8552,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(status_conversion_test
@@ -7821,6 +8580,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(stream_compression_test
@@ -7848,6 +8608,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(stream_owned_slice_test
@@ -7876,6 +8637,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(tcp_client_posix_test
@@ -7904,6 +8666,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(tcp_client_uv_test
@@ -7932,6 +8695,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(tcp_posix_test
@@ -7961,6 +8725,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(tcp_server_posix_test
@@ -7989,6 +8754,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(tcp_server_uv_test
@@ -8016,6 +8782,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(time_averaged_stats_test
@@ -8043,6 +8810,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(timeout_encoding_test
@@ -8070,6 +8838,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(timer_heap_test
@@ -8097,6 +8866,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(timer_list_test
@@ -8124,6 +8894,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(transport_connectivity_state_test
@@ -8151,6 +8922,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(transport_metadata_test
@@ -8179,6 +8951,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(transport_security_test
@@ -8208,6 +8981,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(udp_server_test
@@ -8236,6 +9010,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(uri_parser_test
@@ -8264,6 +9039,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(wakeup_fd_cv_test
@@ -8294,6 +9070,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -8316,6 +9093,475 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(alts_counter_test
+  test/core/tsi/alts/frame_protector/alts_counter_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(alts_counter_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(alts_counter_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  alts_test_util
+  gpr
+  grpc
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
+add_executable(alts_crypt_test
+  test/core/tsi/alts/crypt/aes_gcm_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(alts_crypt_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(alts_crypt_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  alts_test_util
+  gpr_test_util
+  gpr
+  grpc
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
+add_executable(alts_crypter_test
+  test/core/tsi/alts/frame_protector/alts_crypter_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(alts_crypter_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(alts_crypter_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  alts_test_util
+  gpr
+  grpc
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
+add_executable(alts_frame_handler_test
+  test/core/tsi/alts/frame_protector/frame_handler_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(alts_frame_handler_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(alts_frame_handler_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  alts_test_util
+  gpr
+  grpc
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
+add_executable(alts_frame_protector_test
+  test/core/tsi/alts/frame_protector/alts_frame_protector_test.cc
+  test/core/tsi/transport_security_test_lib.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(alts_frame_protector_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(alts_frame_protector_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  alts_test_util
+  gpr
+  grpc
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
+add_executable(alts_grpc_record_protocol_test
+  test/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(alts_grpc_record_protocol_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(alts_grpc_record_protocol_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  alts_test_util
+  gpr
+  grpc
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
+add_executable(alts_handshaker_client_test
+  test/core/tsi/alts/handshaker/alts_handshaker_client_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(alts_handshaker_client_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(alts_handshaker_client_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  alts_test_util
+  gpr
+  grpc
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
+add_executable(alts_handshaker_service_api_test
+  test/core/tsi/alts/handshaker/alts_handshaker_service_api_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(alts_handshaker_service_api_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(alts_handshaker_service_api_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  alts_test_util
+  gpr
+  grpc
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
+add_executable(alts_iovec_record_protocol_test
+  test/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(alts_iovec_record_protocol_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(alts_iovec_record_protocol_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  alts_test_util
+  gpr
+  grpc
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
+add_executable(alts_security_connector_test
+  test/core/security/alts_security_connector_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(alts_security_connector_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(alts_security_connector_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  gpr
+  grpc
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
+add_executable(alts_tsi_handshaker_test
+  test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(alts_tsi_handshaker_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(alts_tsi_handshaker_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  alts_test_util
+  gpr
+  grpc
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
+add_executable(alts_tsi_utils_test
+  test/core/tsi/alts/handshaker/alts_tsi_utils_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(alts_tsi_utils_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(alts_tsi_utils_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  alts_test_util
+  gpr
+  grpc
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
+add_executable(alts_zero_copy_grpc_protector_test
+  test/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(alts_zero_copy_grpc_protector_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(alts_zero_copy_grpc_protector_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  alts_test_util
+  gpr
+  grpc
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
 add_executable(async_end2end_test
   test/cpp/end2end/async_end2end_test.cc
   third_party/googletest/googletest/src/gtest-all.cc
@@ -8332,6 +9578,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -8370,6 +9617,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -8408,6 +9656,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -8444,6 +9693,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -8483,6 +9733,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -8525,6 +9776,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -8567,6 +9819,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -8609,6 +9862,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -8651,6 +9905,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -8693,6 +9948,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -8735,6 +9991,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -8777,6 +10034,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -8819,6 +10077,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -8861,6 +10120,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -8903,6 +10163,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -8946,6 +10207,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -8988,6 +10250,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9030,6 +10293,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9055,6 +10319,43 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(byte_stream_test
+  test/core/transport/byte_stream_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(byte_stream_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(byte_stream_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_test_util
+  grpc
+  gpr_test_util
+  gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
 add_executable(channel_arguments_test
   test/cpp/common/channel_arguments_test.cc
   third_party/googletest/googletest/src/gtest-all.cc
@@ -9071,6 +10372,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9106,6 +10408,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9125,6 +10428,122 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(channel_trace_test
+  test/core/channel/channel_trace_test.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.grpc.pb.cc
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.pb.h
+  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.grpc.pb.h
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+protobuf_generate_grpc_cpp(
+  src/proto/grpc/channelz/channelz.proto
+)
+
+target_include_directories(channel_trace_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(channel_trace_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_test_util
+  grpc++_test_util
+  grpc++
+  grpc
+  gpr_test_util
+  gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
+add_executable(check_gcp_environment_linux_test
+  test/core/security/check_gcp_environment_linux_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(check_gcp_environment_linux_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(check_gcp_environment_linux_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc
+  gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
+add_executable(check_gcp_environment_windows_test
+  test/core/security/check_gcp_environment_windows_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(check_gcp_environment_windows_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(check_gcp_environment_windows_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc
+  gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
 add_executable(chttp2_settings_timeout_test
   test/core/transport/chttp2/settings_timeout_test.cc
   third_party/googletest/googletest/src/gtest-all.cc
@@ -9141,6 +10560,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9177,6 +10597,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9223,6 +10644,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9262,6 +10684,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9301,6 +10724,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9339,6 +10763,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9412,6 +10837,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9484,6 +10910,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9519,6 +10946,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9554,6 +10982,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9591,6 +11020,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9628,6 +11058,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9662,6 +11093,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9699,6 +11131,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9744,6 +11177,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9778,6 +11212,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9816,6 +11251,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9854,6 +11290,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9899,6 +11336,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9918,6 +11356,41 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(grpc_alts_credentials_options_test
+  test/core/security/grpc_alts_credentials_options_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(grpc_alts_credentials_options_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(grpc_alts_credentials_options_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc
+  gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
 add_executable(grpc_cli
   test/cpp/util/grpc_cli.cc
   third_party/googletest/googletest/src/gtest-all.cc
@@ -9934,6 +11407,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9954,6 +11428,7 @@
 )
 
 endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_CODEGEN)
 
 add_executable(grpc_cpp_plugin
   src/compiler/cpp_plugin.cc
@@ -9969,6 +11444,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9988,6 +11464,8 @@
   )
 endif()
 
+endif (gRPC_BUILD_CODEGEN)
+if (gRPC_BUILD_CODEGEN)
 
 add_executable(grpc_csharp_plugin
   src/compiler/csharp_plugin.cc
@@ -10003,6 +11481,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10022,6 +11501,8 @@
   )
 endif()
 
+endif (gRPC_BUILD_CODEGEN)
+if (gRPC_BUILD_CODEGEN)
 
 add_executable(grpc_node_plugin
   src/compiler/node_plugin.cc
@@ -10037,6 +11518,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10056,6 +11538,8 @@
   )
 endif()
 
+endif (gRPC_BUILD_CODEGEN)
+if (gRPC_BUILD_CODEGEN)
 
 add_executable(grpc_objective_c_plugin
   src/compiler/objective_c_plugin.cc
@@ -10071,6 +11555,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10090,6 +11575,8 @@
   )
 endif()
 
+endif (gRPC_BUILD_CODEGEN)
+if (gRPC_BUILD_CODEGEN)
 
 add_executable(grpc_php_plugin
   src/compiler/php_plugin.cc
@@ -10105,6 +11592,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10124,6 +11612,8 @@
   )
 endif()
 
+endif (gRPC_BUILD_CODEGEN)
+if (gRPC_BUILD_CODEGEN)
 
 add_executable(grpc_python_plugin
   src/compiler/python_plugin.cc
@@ -10139,6 +11629,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10158,6 +11649,8 @@
   )
 endif()
 
+endif (gRPC_BUILD_CODEGEN)
+if (gRPC_BUILD_CODEGEN)
 
 add_executable(grpc_ruby_plugin
   src/compiler/ruby_plugin.cc
@@ -10173,6 +11666,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10192,6 +11686,7 @@
   )
 endif()
 
+endif (gRPC_BUILD_CODEGEN)
 if (gRPC_BUILD_TESTS)
 
 add_executable(grpc_tool_test
@@ -10224,6 +11719,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10272,6 +11768,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10315,6 +11812,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10337,51 +11835,6 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
-add_executable(grpclb_test
-  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/lb/v1/load_balancer.pb.cc
-  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc
-  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/lb/v1/load_balancer.pb.h
-  ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/lb/v1/load_balancer.grpc.pb.h
-  test/cpp/grpclb/grpclb_test.cc
-  third_party/googletest/googletest/src/gtest-all.cc
-  third_party/googletest/googlemock/src/gmock-all.cc
-)
-
-protobuf_generate_grpc_cpp(
-  src/proto/grpc/lb/v1/load_balancer.proto
-)
-
-target_include_directories(grpclb_test
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
-  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
-  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
-  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
-  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
-  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
-  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
-  PRIVATE third_party/googletest/googletest/include
-  PRIVATE third_party/googletest/googletest
-  PRIVATE third_party/googletest/googlemock/include
-  PRIVATE third_party/googletest/googlemock
-  PRIVATE ${_gRPC_PROTO_GENS_DIR}
-)
-
-target_link_libraries(grpclb_test
-  ${_gRPC_PROTOBUF_LIBRARIES}
-  ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc++_test_util
-  grpc_test_util
-  grpc++
-  grpc
-  gpr_test_util
-  gpr
-  ${_gRPC_GFLAGS_LIBRARIES}
-)
-
-endif (gRPC_BUILD_TESTS)
-if (gRPC_BUILD_TESTS)
-
 add_executable(h2_ssl_cert_test
   test/core/end2end/h2_ssl_cert_test.cc
   third_party/googletest/googletest/src/gtest-all.cc
@@ -10398,6 +11851,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10419,6 +11873,44 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(h2_ssl_session_reuse_test
+  test/core/end2end/h2_ssl_session_reuse_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(h2_ssl_session_reuse_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(h2_ssl_session_reuse_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_test_util
+  grpc++
+  grpc
+  gpr_test_util
+  gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
 add_executable(health_service_end2end_test
   test/cpp/end2end/health_service_end2end_test.cc
   third_party/googletest/googletest/src/gtest-all.cc
@@ -10435,6 +11927,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10473,6 +11966,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10512,6 +12006,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10550,6 +12045,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10588,6 +12084,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10630,6 +12127,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10672,6 +12170,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10716,6 +12215,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10755,6 +12255,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10795,6 +12296,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10839,6 +12341,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10875,6 +12378,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10897,6 +12401,45 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(nonblocking_test
+  test/cpp/end2end/nonblocking_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(nonblocking_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(nonblocking_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc++_test_util
+  grpc_test_util
+  grpc++
+  grpc
+  gpr_test_util
+  gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
 add_executable(noop-benchmark
   test/cpp/microbenchmarks/noop-benchmark.cc
   third_party/googletest/googletest/src/gtest-all.cc
@@ -10913,6 +12456,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10946,6 +12490,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10983,6 +12528,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11023,6 +12569,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11058,6 +12605,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11099,6 +12647,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11141,6 +12690,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11183,6 +12733,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11245,6 +12796,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11305,6 +12857,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11346,6 +12899,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11383,6 +12937,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11420,6 +12975,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11459,6 +13015,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11501,6 +13058,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11553,6 +13111,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11591,6 +13150,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11629,6 +13189,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11668,6 +13229,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11706,6 +13268,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11758,6 +13321,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11796,6 +13360,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11818,6 +13383,80 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(slice_hash_table_test
+  test/core/slice/slice_hash_table_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(slice_hash_table_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(slice_hash_table_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_test_util
+  grpc
+  gpr_test_util
+  gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
+add_executable(slice_weak_hash_table_test
+  test/core/slice/slice_weak_hash_table_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(slice_weak_hash_table_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(slice_weak_hash_table_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_test_util
+  grpc
+  gpr_test_util
+  gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
 add_executable(stats_test
   test/core/debug/stats_test.cc
   third_party/googletest/googletest/src/gtest-all.cc
@@ -11834,6 +13473,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11855,14 +13495,14 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
-add_executable(status_test
-  test/cpp/util/status_test.cc
+add_executable(status_metadata_test
+  test/core/transport/status_metadata_test.cc
   third_party/googletest/googletest/src/gtest-all.cc
   third_party/googletest/googlemock/src/gmock-all.cc
 )
 
 
-target_include_directories(status_test
+target_include_directories(status_metadata_test
   PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
   PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
   PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
@@ -11871,6 +13511,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11878,14 +13519,44 @@
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
-target_link_libraries(status_test
+target_link_libraries(status_metadata_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
-  grpc++
   grpc
-  gpr_test_util
-  gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
+add_executable(status_util_test
+  test/core/channel/status_util_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(status_util_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(status_util_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc
   ${_gRPC_GFLAGS_LIBRARIES}
 )
 
@@ -11909,6 +13580,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11979,6 +13651,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12018,6 +13691,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12054,6 +13728,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12092,6 +13767,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12113,6 +13789,42 @@
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
+
+add_executable(transport_security_common_api_test
+  test/core/tsi/alts/handshaker/transport_security_common_api_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(transport_security_common_api_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(transport_security_common_api_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  alts_test_util
+  gpr
+  grpc
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(writes_per_rpc_test
@@ -12131,6 +13843,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12168,6 +13881,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(public_headers_must_be_c89
@@ -12192,6 +13906,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(gen_hpack_tables
@@ -12224,6 +13939,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(gen_legal_metadata_characters
@@ -12254,6 +13970,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(gen_percent_encoding_tables
@@ -12285,6 +14002,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(badreq_bad_client_test
@@ -12314,6 +14032,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(connection_prefix_bad_client_test
@@ -12329,6 +14048,36 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(duplicate_header_bad_client_test
+  test/core/bad_client/tests/duplicate_header.cc
+)
+
+
+target_include_directories(duplicate_header_bad_client_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+)
+
+target_link_libraries(duplicate_header_bad_client_test
+  ${_gRPC_SSL_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  bad_client_test
+  grpc_test_util_unsecure
+  grpc_unsecure
+  gpr_test_util
+  gpr
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
 add_executable(head_of_line_blocking_bad_client_test
   test/core/bad_client/tests/head_of_line_blocking.cc
 )
@@ -12343,6 +14092,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(head_of_line_blocking_bad_client_test
@@ -12372,6 +14122,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(headers_bad_client_test
@@ -12401,6 +14152,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(initial_settings_frame_bad_client_test
@@ -12430,6 +14182,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(large_metadata_bad_client_test
@@ -12459,6 +14212,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(server_registered_method_bad_client_test
@@ -12488,6 +14242,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(simple_request_bad_client_test
@@ -12517,6 +14272,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(unknown_frame_bad_client_test
@@ -12546,6 +14302,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(window_overflow_bad_client_test
@@ -12576,6 +14333,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(bad_ssl_cert_server
@@ -12606,6 +14364,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(bad_ssl_cert_test
@@ -12634,6 +14393,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_census_test
@@ -12662,6 +14422,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_compress_test
@@ -12690,6 +14451,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_fakesec_test
@@ -12719,6 +14481,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_fd_test
@@ -12748,6 +14511,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_full_test
@@ -12777,6 +14541,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_full+pipe_test
@@ -12806,6 +14571,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_full+trace_test
@@ -12834,6 +14600,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_full+workarounds_test
@@ -12862,6 +14629,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_http_proxy_test
@@ -12890,6 +14658,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_load_reporting_test
@@ -12918,6 +14687,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_oauth2_test
@@ -12946,6 +14716,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_proxy_test
@@ -12974,6 +14745,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_sockpair_test
@@ -13002,6 +14774,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_sockpair+trace_test
@@ -13030,6 +14803,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_sockpair_1byte_test
@@ -13058,6 +14832,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_ssl_test
@@ -13086,6 +14861,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_ssl_proxy_test
@@ -13115,6 +14891,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_uds_test
@@ -13144,6 +14921,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(inproc_test
@@ -13172,6 +14950,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_census_nosec_test
@@ -13200,6 +14979,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_compress_nosec_test
@@ -13229,6 +15009,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_fd_nosec_test
@@ -13258,6 +15039,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_full_nosec_test
@@ -13287,6 +15069,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_full+pipe_nosec_test
@@ -13316,6 +15099,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_full+trace_nosec_test
@@ -13344,6 +15128,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_full+workarounds_nosec_test
@@ -13372,6 +15157,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_http_proxy_nosec_test
@@ -13400,6 +15186,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_load_reporting_nosec_test
@@ -13428,6 +15215,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_proxy_nosec_test
@@ -13456,6 +15244,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_sockpair_nosec_test
@@ -13484,6 +15273,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_sockpair+trace_nosec_test
@@ -13512,6 +15302,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_sockpair_1byte_nosec_test
@@ -13541,6 +15332,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(h2_uds_nosec_test
@@ -13570,6 +15362,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(inproc_nosec_test
@@ -13601,6 +15394,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -13642,6 +15436,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -13683,6 +15478,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -13724,6 +15520,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -13747,6 +15544,90 @@
 endif()
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
+if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
+
+add_executable(address_sorting_test_unsecure
+  test/cpp/naming/address_sorting_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(address_sorting_test_unsecure
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(address_sorting_test_unsecure
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc++_test_util_unsecure
+  grpc_test_util_unsecure
+  gpr_test_util
+  grpc++_unsecure
+  grpc_unsecure
+  gpr
+  grpc++_test_config
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif()
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
+
+add_executable(address_sorting_test
+  test/cpp/naming/address_sorting_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(address_sorting_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(address_sorting_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc++_test_util
+  grpc_test_util
+  gpr_test_util
+  grpc++
+  grpc
+  gpr
+  grpc++_test_config
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif()
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
 
 add_executable(api_fuzzer_one_entry
   test/core/end2end/fuzzers/api_fuzzer.cc
@@ -13763,6 +15644,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(api_fuzzer_one_entry
@@ -13791,6 +15673,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(client_fuzzer_one_entry
@@ -13819,6 +15702,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(hpack_parser_fuzzer_test_one_entry
@@ -13847,6 +15731,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(http_request_fuzzer_test_one_entry
@@ -13875,6 +15760,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(http_response_fuzzer_test_one_entry
@@ -13903,6 +15789,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(json_fuzzer_test_one_entry
@@ -13931,6 +15818,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(nanopb_fuzzer_response_test_one_entry
@@ -13959,6 +15847,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(nanopb_fuzzer_serverlist_test_one_entry
@@ -13987,6 +15876,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(percent_decode_fuzzer_one_entry
@@ -14015,6 +15905,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(percent_encode_fuzzer_one_entry
@@ -14043,6 +15934,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(server_fuzzer_one_entry
@@ -14071,6 +15963,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(ssl_server_fuzzer_one_entry
@@ -14099,6 +15992,7 @@
   PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
   PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
   PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
 )
 
 target_link_libraries(uri_fuzzer_test_one_entry
diff --git a/INSTALL.md b/INSTALL.md
index 430fd71..810f2b5 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -19,7 +19,7 @@
 ## Linux
 
 ```sh
- $ [sudo] apt-get install build-essential autoconf libtool
+ $ [sudo] apt-get install build-essential autoconf libtool pkg-config
 ```
 
 If you plan to build from source and run tests, install the following as well:
@@ -70,6 +70,12 @@
 repository recursively and it detects that you don't already have it
 installed.
 
+If it hasn't been installed, you can run the following commands to install it.
+
+```sh
+$ cd grpc/third_party/protobuf
+$ sudo make install   # 'make' should have been run by core grpc
+```
 
 # Build from Source
 
diff --git a/MANIFEST.md b/MANIFEST.md
index a0e79e8..9581e1c 100644
--- a/MANIFEST.md
+++ b/MANIFEST.md
@@ -3,10 +3,6 @@
 ## Bazel
 * [grpc.bzl](grpc.bzl)
 
-## Node
-* [binding.gyp](binding.gyp)
-* [package.json](package.json)
-
 ## Objective-C
 * [gRPC.podspec](gRPC.podspec)
 
diff --git a/Makefile b/Makefile
index fa13b0d..a6275aa 100644
--- a/Makefile
+++ b/Makefile
@@ -77,7 +77,7 @@
 CXX_opt = $(DEFAULT_CXX)
 LD_opt = $(DEFAULT_CC)
 LDXX_opt = $(DEFAULT_CXX)
-CPPFLAGS_opt = -O2
+CPPFLAGS_opt = -O2 -Wframe-larger-than=16384
 DEFINES_opt = NDEBUG
 
 VALID_CONFIG_asan-trace-cmp = 1
@@ -148,7 +148,7 @@
 LD_noexcept = $(DEFAULT_CC)
 LDXX_noexcept = $(DEFAULT_CXX)
 CXXFLAGS_noexcept = -fno-exceptions
-CPPFLAGS_noexcept = -O2
+CPPFLAGS_noexcept = -O2 -Wframe-larger-than=16384
 DEFINES_noexcept = NDEBUG
 
 VALID_CONFIG_ubsan = 1
@@ -338,6 +338,8 @@
 COREFLAGS += -fno-rtti -fno-exceptions
 LDFLAGS += -g
 
+DEFINES += PB_FIELD_16BIT
+
 CPPFLAGS += $(CPPFLAGS_$(CONFIG))
 CFLAGS += $(CFLAGS_$(CONFIG))
 CXXFLAGS += $(CXXFLAGS_$(CONFIG))
@@ -419,8 +421,8 @@
 endif
 
 CORE_VERSION = 6.0.0-dev
-CPP_VERSION = 1.10.0-dev
-CSHARP_VERSION = 1.10.0-dev
+CPP_VERSION = 1.11.0-dev
+CSHARP_VERSION = 1.11.0-dev
 
 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
 CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
@@ -675,6 +677,11 @@
 EMBED_CARES ?= false
 endif
 
+ADDRESS_SORTING_DEP = $(LIBDIR)/$(CONFIG)/libaddress_sorting.a
+ADDRESS_SORTING_MERGE_OBJS = $(LIBADDRESS_SORTING_OBJS)
+ADDRESS_SORTING_MERGE_LIBS = $(LIBDIR)/$(CONFIG)/libaddress_sorting.a
+CPPFLAGS := -Ithird_party/address_sorting/include $(CPPFLAGS)
+
 ifeq ($(EMBED_CARES),true)
 CARES_DEP = $(LIBDIR)/$(CONFIG)/libares.a
 CARES_MERGE_OBJS = $(LIBARES_OBJS)
@@ -955,16 +962,17 @@
 alpn_test: $(BINDIR)/$(CONFIG)/alpn_test
 api_fuzzer: $(BINDIR)/$(CONFIG)/api_fuzzer
 arena_test: $(BINDIR)/$(CONFIG)/arena_test
+avl_test: $(BINDIR)/$(CONFIG)/avl_test
 bad_server_response_test: $(BINDIR)/$(CONFIG)/bad_server_response_test
 bin_decoder_test: $(BINDIR)/$(CONFIG)/bin_decoder_test
 bin_encoder_test: $(BINDIR)/$(CONFIG)/bin_encoder_test
-byte_stream_test: $(BINDIR)/$(CONFIG)/byte_stream_test
 channel_create_test: $(BINDIR)/$(CONFIG)/channel_create_test
 check_epollexclusive: $(BINDIR)/$(CONFIG)/check_epollexclusive
 chttp2_hpack_encoder_test: $(BINDIR)/$(CONFIG)/chttp2_hpack_encoder_test
 chttp2_stream_map_test: $(BINDIR)/$(CONFIG)/chttp2_stream_map_test
 chttp2_varint_test: $(BINDIR)/$(CONFIG)/chttp2_varint_test
 client_fuzzer: $(BINDIR)/$(CONFIG)/client_fuzzer
+cmdline_test: $(BINDIR)/$(CONFIG)/cmdline_test
 combiner_test: $(BINDIR)/$(CONFIG)/combiner_test
 compression_test: $(BINDIR)/$(CONFIG)/compression_test
 concurrent_connectivity_test: $(BINDIR)/$(CONFIG)/concurrent_connectivity_test
@@ -985,8 +993,6 @@
 fling_stream_test: $(BINDIR)/$(CONFIG)/fling_stream_test
 fling_test: $(BINDIR)/$(CONFIG)/fling_test
 goaway_server_test: $(BINDIR)/$(CONFIG)/goaway_server_test
-gpr_avl_test: $(BINDIR)/$(CONFIG)/gpr_avl_test
-gpr_cmdline_test: $(BINDIR)/$(CONFIG)/gpr_cmdline_test
 gpr_cpu_test: $(BINDIR)/$(CONFIG)/gpr_cpu_test
 gpr_env_test: $(BINDIR)/$(CONFIG)/gpr_env_test
 gpr_host_port_test: $(BINDIR)/$(CONFIG)/gpr_host_port_test
@@ -1067,7 +1073,6 @@
 server_fuzzer: $(BINDIR)/$(CONFIG)/server_fuzzer
 server_test: $(BINDIR)/$(CONFIG)/server_test
 slice_buffer_test: $(BINDIR)/$(CONFIG)/slice_buffer_test
-slice_hash_table_test: $(BINDIR)/$(CONFIG)/slice_hash_table_test
 slice_string_helpers_test: $(BINDIR)/$(CONFIG)/slice_string_helpers_test
 slice_test: $(BINDIR)/$(CONFIG)/slice_test
 sockaddr_resolver_test: $(BINDIR)/$(CONFIG)/sockaddr_resolver_test
@@ -1095,6 +1100,19 @@
 uri_parser_test: $(BINDIR)/$(CONFIG)/uri_parser_test
 wakeup_fd_cv_test: $(BINDIR)/$(CONFIG)/wakeup_fd_cv_test
 alarm_test: $(BINDIR)/$(CONFIG)/alarm_test
+alts_counter_test: $(BINDIR)/$(CONFIG)/alts_counter_test
+alts_crypt_test: $(BINDIR)/$(CONFIG)/alts_crypt_test
+alts_crypter_test: $(BINDIR)/$(CONFIG)/alts_crypter_test
+alts_frame_handler_test: $(BINDIR)/$(CONFIG)/alts_frame_handler_test
+alts_frame_protector_test: $(BINDIR)/$(CONFIG)/alts_frame_protector_test
+alts_grpc_record_protocol_test: $(BINDIR)/$(CONFIG)/alts_grpc_record_protocol_test
+alts_handshaker_client_test: $(BINDIR)/$(CONFIG)/alts_handshaker_client_test
+alts_handshaker_service_api_test: $(BINDIR)/$(CONFIG)/alts_handshaker_service_api_test
+alts_iovec_record_protocol_test: $(BINDIR)/$(CONFIG)/alts_iovec_record_protocol_test
+alts_security_connector_test: $(BINDIR)/$(CONFIG)/alts_security_connector_test
+alts_tsi_handshaker_test: $(BINDIR)/$(CONFIG)/alts_tsi_handshaker_test
+alts_tsi_utils_test: $(BINDIR)/$(CONFIG)/alts_tsi_utils_test
+alts_zero_copy_grpc_protector_test: $(BINDIR)/$(CONFIG)/alts_zero_copy_grpc_protector_test
 async_end2end_test: $(BINDIR)/$(CONFIG)/async_end2end_test
 auth_property_iterator_test: $(BINDIR)/$(CONFIG)/auth_property_iterator_test
 backoff_test: $(BINDIR)/$(CONFIG)/backoff_test
@@ -1113,8 +1131,12 @@
 bm_fullstack_unary_ping_pong: $(BINDIR)/$(CONFIG)/bm_fullstack_unary_ping_pong
 bm_metadata: $(BINDIR)/$(CONFIG)/bm_metadata
 bm_pollset: $(BINDIR)/$(CONFIG)/bm_pollset
+byte_stream_test: $(BINDIR)/$(CONFIG)/byte_stream_test
 channel_arguments_test: $(BINDIR)/$(CONFIG)/channel_arguments_test
 channel_filter_test: $(BINDIR)/$(CONFIG)/channel_filter_test
+channel_trace_test: $(BINDIR)/$(CONFIG)/channel_trace_test
+check_gcp_environment_linux_test: $(BINDIR)/$(CONFIG)/check_gcp_environment_linux_test
+check_gcp_environment_windows_test: $(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test
 chttp2_settings_timeout_test: $(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test
 cli_call_test: $(BINDIR)/$(CONFIG)/cli_call_test
 client_channel_stress_test: $(BINDIR)/$(CONFIG)/client_channel_stress_test
@@ -1134,6 +1156,7 @@
 filter_end2end_test: $(BINDIR)/$(CONFIG)/filter_end2end_test
 generic_end2end_test: $(BINDIR)/$(CONFIG)/generic_end2end_test
 golden_file_test: $(BINDIR)/$(CONFIG)/golden_file_test
+grpc_alts_credentials_options_test: $(BINDIR)/$(CONFIG)/grpc_alts_credentials_options_test
 grpc_cli: $(BINDIR)/$(CONFIG)/grpc_cli
 grpc_cpp_plugin: $(BINDIR)/$(CONFIG)/grpc_cpp_plugin
 grpc_csharp_plugin: $(BINDIR)/$(CONFIG)/grpc_csharp_plugin
@@ -1145,8 +1168,8 @@
 grpc_tool_test: $(BINDIR)/$(CONFIG)/grpc_tool_test
 grpclb_api_test: $(BINDIR)/$(CONFIG)/grpclb_api_test
 grpclb_end2end_test: $(BINDIR)/$(CONFIG)/grpclb_end2end_test
-grpclb_test: $(BINDIR)/$(CONFIG)/grpclb_test
 h2_ssl_cert_test: $(BINDIR)/$(CONFIG)/h2_ssl_cert_test
+h2_ssl_session_reuse_test: $(BINDIR)/$(CONFIG)/h2_ssl_session_reuse_test
 health_service_end2end_test: $(BINDIR)/$(CONFIG)/health_service_end2end_test
 http2_client: $(BINDIR)/$(CONFIG)/http2_client
 hybrid_end2end_test: $(BINDIR)/$(CONFIG)/hybrid_end2end_test
@@ -1159,6 +1182,7 @@
 memory_test: $(BINDIR)/$(CONFIG)/memory_test
 metrics_client: $(BINDIR)/$(CONFIG)/metrics_client
 mock_test: $(BINDIR)/$(CONFIG)/mock_test
+nonblocking_test: $(BINDIR)/$(CONFIG)/nonblocking_test
 noop-benchmark: $(BINDIR)/$(CONFIG)/noop-benchmark
 orphanable_test: $(BINDIR)/$(CONFIG)/orphanable_test
 proto_server_reflection_test: $(BINDIR)/$(CONFIG)/proto_server_reflection_test
@@ -1181,13 +1205,17 @@
 server_early_return_test: $(BINDIR)/$(CONFIG)/server_early_return_test
 server_request_call_test: $(BINDIR)/$(CONFIG)/server_request_call_test
 shutdown_test: $(BINDIR)/$(CONFIG)/shutdown_test
+slice_hash_table_test: $(BINDIR)/$(CONFIG)/slice_hash_table_test
+slice_weak_hash_table_test: $(BINDIR)/$(CONFIG)/slice_weak_hash_table_test
 stats_test: $(BINDIR)/$(CONFIG)/stats_test
-status_test: $(BINDIR)/$(CONFIG)/status_test
+status_metadata_test: $(BINDIR)/$(CONFIG)/status_metadata_test
+status_util_test: $(BINDIR)/$(CONFIG)/status_util_test
 streaming_throughput_test: $(BINDIR)/$(CONFIG)/streaming_throughput_test
 stress_test: $(BINDIR)/$(CONFIG)/stress_test
 thread_manager_test: $(BINDIR)/$(CONFIG)/thread_manager_test
 thread_stress_test: $(BINDIR)/$(CONFIG)/thread_stress_test
 transport_pid_controller_test: $(BINDIR)/$(CONFIG)/transport_pid_controller_test
+transport_security_common_api_test: $(BINDIR)/$(CONFIG)/transport_security_common_api_test
 writes_per_rpc_test: $(BINDIR)/$(CONFIG)/writes_per_rpc_test
 public_headers_must_be_c89: $(BINDIR)/$(CONFIG)/public_headers_must_be_c89
 gen_hpack_tables: $(BINDIR)/$(CONFIG)/gen_hpack_tables
@@ -1197,6 +1225,7 @@
 boringssl_asn1_test: $(BINDIR)/$(CONFIG)/boringssl_asn1_test
 boringssl_base64_test: $(BINDIR)/$(CONFIG)/boringssl_base64_test
 boringssl_bio_test: $(BINDIR)/$(CONFIG)/boringssl_bio_test
+boringssl_buf_test: $(BINDIR)/$(CONFIG)/boringssl_buf_test
 boringssl_bytestring_test: $(BINDIR)/$(CONFIG)/boringssl_bytestring_test
 boringssl_chacha_test: $(BINDIR)/$(CONFIG)/boringssl_chacha_test
 boringssl_aead_test: $(BINDIR)/$(CONFIG)/boringssl_aead_test
@@ -1244,6 +1273,7 @@
 boringssl_ssl_test: $(BINDIR)/$(CONFIG)/boringssl_ssl_test
 badreq_bad_client_test: $(BINDIR)/$(CONFIG)/badreq_bad_client_test
 connection_prefix_bad_client_test: $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test
+duplicate_header_bad_client_test: $(BINDIR)/$(CONFIG)/duplicate_header_bad_client_test
 head_of_line_blocking_bad_client_test: $(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test
 headers_bad_client_test: $(BINDIR)/$(CONFIG)/headers_bad_client_test
 initial_settings_frame_bad_client_test: $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test
@@ -1292,6 +1322,8 @@
 resolver_component_test: $(BINDIR)/$(CONFIG)/resolver_component_test
 resolver_component_tests_runner_invoker_unsecure: $(BINDIR)/$(CONFIG)/resolver_component_tests_runner_invoker_unsecure
 resolver_component_tests_runner_invoker: $(BINDIR)/$(CONFIG)/resolver_component_tests_runner_invoker
+address_sorting_test_unsecure: $(BINDIR)/$(CONFIG)/address_sorting_test_unsecure
+address_sorting_test: $(BINDIR)/$(CONFIG)/address_sorting_test
 api_fuzzer_one_entry: $(BINDIR)/$(CONFIG)/api_fuzzer_one_entry
 client_fuzzer_one_entry: $(BINDIR)/$(CONFIG)/client_fuzzer_one_entry
 hpack_parser_fuzzer_test_one_entry: $(BINDIR)/$(CONFIG)/hpack_parser_fuzzer_test_one_entry
@@ -1332,13 +1364,13 @@
 
 static: static_c static_cxx
 
-static_c: pc_c pc_c_unsecure cache.mk  $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc_cronet.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a
+static_c: pc_c pc_c_unsecure cache.mk  $(LIBDIR)/$(CONFIG)/libaddress_sorting.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc_cronet.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a
 
 static_cxx: pc_cxx pc_cxx_unsecure cache.mk  $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_cronet.a $(LIBDIR)/$(CONFIG)/libgrpc++_error_details.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a
 
 shared: shared_c shared_cxx
 
-shared_c: pc_c pc_c_unsecure cache.mk $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)
+shared_c: pc_c pc_c_unsecure cache.mk $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)
 shared_cxx: pc_cxx pc_cxx_unsecure cache.mk $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)
 
 shared_csharp: shared_c  $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP)
@@ -1348,7 +1380,7 @@
 
 privatelibs: privatelibs_c privatelibs_cxx
 
-privatelibs_c:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libreconnect_server.a $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBDIR)/$(CONFIG)/libz.a $(LIBDIR)/$(CONFIG)/libares.a $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a
+privatelibs_c:  $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libreconnect_server.a $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBDIR)/$(CONFIG)/libz.a $(LIBDIR)/$(CONFIG)/libares.a $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a
 pc_c: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc
 
 pc_c_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc
@@ -1358,7 +1390,7 @@
 pc_cxx_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++_unsecure.pc
 
 ifeq ($(EMBED_OPENSSL),true)
-privatelibs_cxx:  $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBDIR)/$(CONFIG)/libboringssl_crypto_test_data_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_chacha_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_compiler_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_constant_time_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_spake25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_dh_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_dsa_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ecdh_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_err_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_scrypt_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ec_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_p256-x86_64_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_gcm_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ctrdrbg_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_hkdf_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_lhash_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_obj_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs7_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pool_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_refcount_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_rsa_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_file_test_gtest_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_gtest_main_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_thread_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_x509_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_tab_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_v3name_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_span_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ssl_test_lib.a $(LIBDIR)/$(CONFIG)/libbenchmark.a
+privatelibs_cxx:  $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBDIR)/$(CONFIG)/libboringssl_crypto_test_data_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_buf_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_chacha_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_compiler_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_constant_time_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_spake25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_dh_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_dsa_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ecdh_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_err_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_scrypt_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ec_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_p256-x86_64_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_gcm_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ctrdrbg_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_hkdf_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_lhash_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_obj_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs7_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pool_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_refcount_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_rsa_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_file_test_gtest_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_gtest_main_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_thread_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_x509_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_tab_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_v3name_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_span_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ssl_test_lib.a $(LIBDIR)/$(CONFIG)/libbenchmark.a
 else
 privatelibs_cxx:  $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libbenchmark.a
 endif
@@ -1371,14 +1403,15 @@
   $(BINDIR)/$(CONFIG)/alloc_test \
   $(BINDIR)/$(CONFIG)/alpn_test \
   $(BINDIR)/$(CONFIG)/arena_test \
+  $(BINDIR)/$(CONFIG)/avl_test \
   $(BINDIR)/$(CONFIG)/bad_server_response_test \
   $(BINDIR)/$(CONFIG)/bin_decoder_test \
   $(BINDIR)/$(CONFIG)/bin_encoder_test \
-  $(BINDIR)/$(CONFIG)/byte_stream_test \
   $(BINDIR)/$(CONFIG)/channel_create_test \
   $(BINDIR)/$(CONFIG)/chttp2_hpack_encoder_test \
   $(BINDIR)/$(CONFIG)/chttp2_stream_map_test \
   $(BINDIR)/$(CONFIG)/chttp2_varint_test \
+  $(BINDIR)/$(CONFIG)/cmdline_test \
   $(BINDIR)/$(CONFIG)/combiner_test \
   $(BINDIR)/$(CONFIG)/compression_test \
   $(BINDIR)/$(CONFIG)/concurrent_connectivity_test \
@@ -1399,8 +1432,6 @@
   $(BINDIR)/$(CONFIG)/fling_stream_test \
   $(BINDIR)/$(CONFIG)/fling_test \
   $(BINDIR)/$(CONFIG)/goaway_server_test \
-  $(BINDIR)/$(CONFIG)/gpr_avl_test \
-  $(BINDIR)/$(CONFIG)/gpr_cmdline_test \
   $(BINDIR)/$(CONFIG)/gpr_cpu_test \
   $(BINDIR)/$(CONFIG)/gpr_env_test \
   $(BINDIR)/$(CONFIG)/gpr_host_port_test \
@@ -1468,7 +1499,6 @@
   $(BINDIR)/$(CONFIG)/server_chttp2_test \
   $(BINDIR)/$(CONFIG)/server_test \
   $(BINDIR)/$(CONFIG)/slice_buffer_test \
-  $(BINDIR)/$(CONFIG)/slice_hash_table_test \
   $(BINDIR)/$(CONFIG)/slice_string_helpers_test \
   $(BINDIR)/$(CONFIG)/slice_test \
   $(BINDIR)/$(CONFIG)/sockaddr_resolver_test \
@@ -1496,6 +1526,7 @@
   $(BINDIR)/$(CONFIG)/public_headers_must_be_c89 \
   $(BINDIR)/$(CONFIG)/badreq_bad_client_test \
   $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test \
+  $(BINDIR)/$(CONFIG)/duplicate_header_bad_client_test \
   $(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test \
   $(BINDIR)/$(CONFIG)/headers_bad_client_test \
   $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test \
@@ -1558,6 +1589,19 @@
 ifeq ($(EMBED_OPENSSL),true)
 buildtests_cxx: privatelibs_cxx \
   $(BINDIR)/$(CONFIG)/alarm_test \
+  $(BINDIR)/$(CONFIG)/alts_counter_test \
+  $(BINDIR)/$(CONFIG)/alts_crypt_test \
+  $(BINDIR)/$(CONFIG)/alts_crypter_test \
+  $(BINDIR)/$(CONFIG)/alts_frame_handler_test \
+  $(BINDIR)/$(CONFIG)/alts_frame_protector_test \
+  $(BINDIR)/$(CONFIG)/alts_grpc_record_protocol_test \
+  $(BINDIR)/$(CONFIG)/alts_handshaker_client_test \
+  $(BINDIR)/$(CONFIG)/alts_handshaker_service_api_test \
+  $(BINDIR)/$(CONFIG)/alts_iovec_record_protocol_test \
+  $(BINDIR)/$(CONFIG)/alts_security_connector_test \
+  $(BINDIR)/$(CONFIG)/alts_tsi_handshaker_test \
+  $(BINDIR)/$(CONFIG)/alts_tsi_utils_test \
+  $(BINDIR)/$(CONFIG)/alts_zero_copy_grpc_protector_test \
   $(BINDIR)/$(CONFIG)/async_end2end_test \
   $(BINDIR)/$(CONFIG)/auth_property_iterator_test \
   $(BINDIR)/$(CONFIG)/backoff_test \
@@ -1576,8 +1620,12 @@
   $(BINDIR)/$(CONFIG)/bm_fullstack_unary_ping_pong \
   $(BINDIR)/$(CONFIG)/bm_metadata \
   $(BINDIR)/$(CONFIG)/bm_pollset \
+  $(BINDIR)/$(CONFIG)/byte_stream_test \
   $(BINDIR)/$(CONFIG)/channel_arguments_test \
   $(BINDIR)/$(CONFIG)/channel_filter_test \
+  $(BINDIR)/$(CONFIG)/channel_trace_test \
+  $(BINDIR)/$(CONFIG)/check_gcp_environment_linux_test \
+  $(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test \
   $(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test \
   $(BINDIR)/$(CONFIG)/cli_call_test \
   $(BINDIR)/$(CONFIG)/client_channel_stress_test \
@@ -1597,12 +1645,13 @@
   $(BINDIR)/$(CONFIG)/filter_end2end_test \
   $(BINDIR)/$(CONFIG)/generic_end2end_test \
   $(BINDIR)/$(CONFIG)/golden_file_test \
+  $(BINDIR)/$(CONFIG)/grpc_alts_credentials_options_test \
   $(BINDIR)/$(CONFIG)/grpc_cli \
   $(BINDIR)/$(CONFIG)/grpc_tool_test \
   $(BINDIR)/$(CONFIG)/grpclb_api_test \
   $(BINDIR)/$(CONFIG)/grpclb_end2end_test \
-  $(BINDIR)/$(CONFIG)/grpclb_test \
   $(BINDIR)/$(CONFIG)/h2_ssl_cert_test \
+  $(BINDIR)/$(CONFIG)/h2_ssl_session_reuse_test \
   $(BINDIR)/$(CONFIG)/health_service_end2end_test \
   $(BINDIR)/$(CONFIG)/http2_client \
   $(BINDIR)/$(CONFIG)/hybrid_end2end_test \
@@ -1615,6 +1664,7 @@
   $(BINDIR)/$(CONFIG)/memory_test \
   $(BINDIR)/$(CONFIG)/metrics_client \
   $(BINDIR)/$(CONFIG)/mock_test \
+  $(BINDIR)/$(CONFIG)/nonblocking_test \
   $(BINDIR)/$(CONFIG)/noop-benchmark \
   $(BINDIR)/$(CONFIG)/orphanable_test \
   $(BINDIR)/$(CONFIG)/proto_server_reflection_test \
@@ -1637,18 +1687,23 @@
   $(BINDIR)/$(CONFIG)/server_early_return_test \
   $(BINDIR)/$(CONFIG)/server_request_call_test \
   $(BINDIR)/$(CONFIG)/shutdown_test \
+  $(BINDIR)/$(CONFIG)/slice_hash_table_test \
+  $(BINDIR)/$(CONFIG)/slice_weak_hash_table_test \
   $(BINDIR)/$(CONFIG)/stats_test \
-  $(BINDIR)/$(CONFIG)/status_test \
+  $(BINDIR)/$(CONFIG)/status_metadata_test \
+  $(BINDIR)/$(CONFIG)/status_util_test \
   $(BINDIR)/$(CONFIG)/streaming_throughput_test \
   $(BINDIR)/$(CONFIG)/stress_test \
   $(BINDIR)/$(CONFIG)/thread_manager_test \
   $(BINDIR)/$(CONFIG)/thread_stress_test \
   $(BINDIR)/$(CONFIG)/transport_pid_controller_test \
+  $(BINDIR)/$(CONFIG)/transport_security_common_api_test \
   $(BINDIR)/$(CONFIG)/writes_per_rpc_test \
   $(BINDIR)/$(CONFIG)/boringssl_crypto_test_data \
   $(BINDIR)/$(CONFIG)/boringssl_asn1_test \
   $(BINDIR)/$(CONFIG)/boringssl_base64_test \
   $(BINDIR)/$(CONFIG)/boringssl_bio_test \
+  $(BINDIR)/$(CONFIG)/boringssl_buf_test \
   $(BINDIR)/$(CONFIG)/boringssl_bytestring_test \
   $(BINDIR)/$(CONFIG)/boringssl_chacha_test \
   $(BINDIR)/$(CONFIG)/boringssl_aead_test \
@@ -1698,10 +1753,25 @@
   $(BINDIR)/$(CONFIG)/resolver_component_test \
   $(BINDIR)/$(CONFIG)/resolver_component_tests_runner_invoker_unsecure \
   $(BINDIR)/$(CONFIG)/resolver_component_tests_runner_invoker \
+  $(BINDIR)/$(CONFIG)/address_sorting_test_unsecure \
+  $(BINDIR)/$(CONFIG)/address_sorting_test \
 
 else
 buildtests_cxx: privatelibs_cxx \
   $(BINDIR)/$(CONFIG)/alarm_test \
+  $(BINDIR)/$(CONFIG)/alts_counter_test \
+  $(BINDIR)/$(CONFIG)/alts_crypt_test \
+  $(BINDIR)/$(CONFIG)/alts_crypter_test \
+  $(BINDIR)/$(CONFIG)/alts_frame_handler_test \
+  $(BINDIR)/$(CONFIG)/alts_frame_protector_test \
+  $(BINDIR)/$(CONFIG)/alts_grpc_record_protocol_test \
+  $(BINDIR)/$(CONFIG)/alts_handshaker_client_test \
+  $(BINDIR)/$(CONFIG)/alts_handshaker_service_api_test \
+  $(BINDIR)/$(CONFIG)/alts_iovec_record_protocol_test \
+  $(BINDIR)/$(CONFIG)/alts_security_connector_test \
+  $(BINDIR)/$(CONFIG)/alts_tsi_handshaker_test \
+  $(BINDIR)/$(CONFIG)/alts_tsi_utils_test \
+  $(BINDIR)/$(CONFIG)/alts_zero_copy_grpc_protector_test \
   $(BINDIR)/$(CONFIG)/async_end2end_test \
   $(BINDIR)/$(CONFIG)/auth_property_iterator_test \
   $(BINDIR)/$(CONFIG)/backoff_test \
@@ -1720,8 +1790,12 @@
   $(BINDIR)/$(CONFIG)/bm_fullstack_unary_ping_pong \
   $(BINDIR)/$(CONFIG)/bm_metadata \
   $(BINDIR)/$(CONFIG)/bm_pollset \
+  $(BINDIR)/$(CONFIG)/byte_stream_test \
   $(BINDIR)/$(CONFIG)/channel_arguments_test \
   $(BINDIR)/$(CONFIG)/channel_filter_test \
+  $(BINDIR)/$(CONFIG)/channel_trace_test \
+  $(BINDIR)/$(CONFIG)/check_gcp_environment_linux_test \
+  $(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test \
   $(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test \
   $(BINDIR)/$(CONFIG)/cli_call_test \
   $(BINDIR)/$(CONFIG)/client_channel_stress_test \
@@ -1741,12 +1815,13 @@
   $(BINDIR)/$(CONFIG)/filter_end2end_test \
   $(BINDIR)/$(CONFIG)/generic_end2end_test \
   $(BINDIR)/$(CONFIG)/golden_file_test \
+  $(BINDIR)/$(CONFIG)/grpc_alts_credentials_options_test \
   $(BINDIR)/$(CONFIG)/grpc_cli \
   $(BINDIR)/$(CONFIG)/grpc_tool_test \
   $(BINDIR)/$(CONFIG)/grpclb_api_test \
   $(BINDIR)/$(CONFIG)/grpclb_end2end_test \
-  $(BINDIR)/$(CONFIG)/grpclb_test \
   $(BINDIR)/$(CONFIG)/h2_ssl_cert_test \
+  $(BINDIR)/$(CONFIG)/h2_ssl_session_reuse_test \
   $(BINDIR)/$(CONFIG)/health_service_end2end_test \
   $(BINDIR)/$(CONFIG)/http2_client \
   $(BINDIR)/$(CONFIG)/hybrid_end2end_test \
@@ -1759,6 +1834,7 @@
   $(BINDIR)/$(CONFIG)/memory_test \
   $(BINDIR)/$(CONFIG)/metrics_client \
   $(BINDIR)/$(CONFIG)/mock_test \
+  $(BINDIR)/$(CONFIG)/nonblocking_test \
   $(BINDIR)/$(CONFIG)/noop-benchmark \
   $(BINDIR)/$(CONFIG)/orphanable_test \
   $(BINDIR)/$(CONFIG)/proto_server_reflection_test \
@@ -1781,18 +1857,24 @@
   $(BINDIR)/$(CONFIG)/server_early_return_test \
   $(BINDIR)/$(CONFIG)/server_request_call_test \
   $(BINDIR)/$(CONFIG)/shutdown_test \
+  $(BINDIR)/$(CONFIG)/slice_hash_table_test \
+  $(BINDIR)/$(CONFIG)/slice_weak_hash_table_test \
   $(BINDIR)/$(CONFIG)/stats_test \
-  $(BINDIR)/$(CONFIG)/status_test \
+  $(BINDIR)/$(CONFIG)/status_metadata_test \
+  $(BINDIR)/$(CONFIG)/status_util_test \
   $(BINDIR)/$(CONFIG)/streaming_throughput_test \
   $(BINDIR)/$(CONFIG)/stress_test \
   $(BINDIR)/$(CONFIG)/thread_manager_test \
   $(BINDIR)/$(CONFIG)/thread_stress_test \
   $(BINDIR)/$(CONFIG)/transport_pid_controller_test \
+  $(BINDIR)/$(CONFIG)/transport_security_common_api_test \
   $(BINDIR)/$(CONFIG)/writes_per_rpc_test \
   $(BINDIR)/$(CONFIG)/resolver_component_test_unsecure \
   $(BINDIR)/$(CONFIG)/resolver_component_test \
   $(BINDIR)/$(CONFIG)/resolver_component_tests_runner_invoker_unsecure \
   $(BINDIR)/$(CONFIG)/resolver_component_tests_runner_invoker \
+  $(BINDIR)/$(CONFIG)/address_sorting_test_unsecure \
+  $(BINDIR)/$(CONFIG)/address_sorting_test \
 
 endif
 
@@ -1810,14 +1892,14 @@
 	$(Q) $(BINDIR)/$(CONFIG)/alpn_test || ( echo test alpn_test failed ; exit 1 )
 	$(E) "[RUN]     Testing arena_test"
 	$(Q) $(BINDIR)/$(CONFIG)/arena_test || ( echo test arena_test failed ; exit 1 )
+	$(E) "[RUN]     Testing avl_test"
+	$(Q) $(BINDIR)/$(CONFIG)/avl_test || ( echo test avl_test failed ; exit 1 )
 	$(E) "[RUN]     Testing bad_server_response_test"
 	$(Q) $(BINDIR)/$(CONFIG)/bad_server_response_test || ( echo test bad_server_response_test failed ; exit 1 )
 	$(E) "[RUN]     Testing bin_decoder_test"
 	$(Q) $(BINDIR)/$(CONFIG)/bin_decoder_test || ( echo test bin_decoder_test failed ; exit 1 )
 	$(E) "[RUN]     Testing bin_encoder_test"
 	$(Q) $(BINDIR)/$(CONFIG)/bin_encoder_test || ( echo test bin_encoder_test failed ; exit 1 )
-	$(E) "[RUN]     Testing byte_stream_test"
-	$(Q) $(BINDIR)/$(CONFIG)/byte_stream_test || ( echo test byte_stream_test failed ; exit 1 )
 	$(E) "[RUN]     Testing channel_create_test"
 	$(Q) $(BINDIR)/$(CONFIG)/channel_create_test || ( echo test channel_create_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_hpack_encoder_test"
@@ -1826,6 +1908,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_stream_map_test || ( echo test chttp2_stream_map_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_varint_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_varint_test || ( echo test chttp2_varint_test failed ; exit 1 )
+	$(E) "[RUN]     Testing cmdline_test"
+	$(Q) $(BINDIR)/$(CONFIG)/cmdline_test || ( echo test cmdline_test failed ; exit 1 )
 	$(E) "[RUN]     Testing combiner_test"
 	$(Q) $(BINDIR)/$(CONFIG)/combiner_test || ( echo test combiner_test failed ; exit 1 )
 	$(E) "[RUN]     Testing compression_test"
@@ -1862,10 +1946,6 @@
 	$(Q) $(BINDIR)/$(CONFIG)/fling_test || ( echo test fling_test failed ; exit 1 )
 	$(E) "[RUN]     Testing goaway_server_test"
 	$(Q) $(BINDIR)/$(CONFIG)/goaway_server_test || ( echo test goaway_server_test failed ; exit 1 )
-	$(E) "[RUN]     Testing gpr_avl_test"
-	$(Q) $(BINDIR)/$(CONFIG)/gpr_avl_test || ( echo test gpr_avl_test failed ; exit 1 )
-	$(E) "[RUN]     Testing gpr_cmdline_test"
-	$(Q) $(BINDIR)/$(CONFIG)/gpr_cmdline_test || ( echo test gpr_cmdline_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_cpu_test"
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_cpu_test || ( echo test gpr_cpu_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_env_test"
@@ -1992,8 +2072,6 @@
 	$(Q) $(BINDIR)/$(CONFIG)/server_test || ( echo test server_test failed ; exit 1 )
 	$(E) "[RUN]     Testing slice_buffer_test"
 	$(Q) $(BINDIR)/$(CONFIG)/slice_buffer_test || ( echo test slice_buffer_test failed ; exit 1 )
-	$(E) "[RUN]     Testing slice_hash_table_test"
-	$(Q) $(BINDIR)/$(CONFIG)/slice_hash_table_test || ( echo test slice_hash_table_test failed ; exit 1 )
 	$(E) "[RUN]     Testing slice_string_helpers_test"
 	$(Q) $(BINDIR)/$(CONFIG)/slice_string_helpers_test || ( echo test slice_string_helpers_test failed ; exit 1 )
 	$(E) "[RUN]     Testing slice_test"
@@ -2048,6 +2126,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/badreq_bad_client_test || ( echo test badreq_bad_client_test failed ; exit 1 )
 	$(E) "[RUN]     Testing connection_prefix_bad_client_test"
 	$(Q) $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test || ( echo test connection_prefix_bad_client_test failed ; exit 1 )
+	$(E) "[RUN]     Testing duplicate_header_bad_client_test"
+	$(Q) $(BINDIR)/$(CONFIG)/duplicate_header_bad_client_test || ( echo test duplicate_header_bad_client_test failed ; exit 1 )
 	$(E) "[RUN]     Testing head_of_line_blocking_bad_client_test"
 	$(Q) $(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test || ( echo test head_of_line_blocking_bad_client_test failed ; exit 1 )
 	$(E) "[RUN]     Testing headers_bad_client_test"
@@ -2074,6 +2154,32 @@
 test_cxx: buildtests_cxx
 	$(E) "[RUN]     Testing alarm_test"
 	$(Q) $(BINDIR)/$(CONFIG)/alarm_test || ( echo test alarm_test failed ; exit 1 )
+	$(E) "[RUN]     Testing alts_counter_test"
+	$(Q) $(BINDIR)/$(CONFIG)/alts_counter_test || ( echo test alts_counter_test failed ; exit 1 )
+	$(E) "[RUN]     Testing alts_crypt_test"
+	$(Q) $(BINDIR)/$(CONFIG)/alts_crypt_test || ( echo test alts_crypt_test failed ; exit 1 )
+	$(E) "[RUN]     Testing alts_crypter_test"
+	$(Q) $(BINDIR)/$(CONFIG)/alts_crypter_test || ( echo test alts_crypter_test failed ; exit 1 )
+	$(E) "[RUN]     Testing alts_frame_handler_test"
+	$(Q) $(BINDIR)/$(CONFIG)/alts_frame_handler_test || ( echo test alts_frame_handler_test failed ; exit 1 )
+	$(E) "[RUN]     Testing alts_frame_protector_test"
+	$(Q) $(BINDIR)/$(CONFIG)/alts_frame_protector_test || ( echo test alts_frame_protector_test failed ; exit 1 )
+	$(E) "[RUN]     Testing alts_grpc_record_protocol_test"
+	$(Q) $(BINDIR)/$(CONFIG)/alts_grpc_record_protocol_test || ( echo test alts_grpc_record_protocol_test failed ; exit 1 )
+	$(E) "[RUN]     Testing alts_handshaker_client_test"
+	$(Q) $(BINDIR)/$(CONFIG)/alts_handshaker_client_test || ( echo test alts_handshaker_client_test failed ; exit 1 )
+	$(E) "[RUN]     Testing alts_handshaker_service_api_test"
+	$(Q) $(BINDIR)/$(CONFIG)/alts_handshaker_service_api_test || ( echo test alts_handshaker_service_api_test failed ; exit 1 )
+	$(E) "[RUN]     Testing alts_iovec_record_protocol_test"
+	$(Q) $(BINDIR)/$(CONFIG)/alts_iovec_record_protocol_test || ( echo test alts_iovec_record_protocol_test failed ; exit 1 )
+	$(E) "[RUN]     Testing alts_security_connector_test"
+	$(Q) $(BINDIR)/$(CONFIG)/alts_security_connector_test || ( echo test alts_security_connector_test failed ; exit 1 )
+	$(E) "[RUN]     Testing alts_tsi_handshaker_test"
+	$(Q) $(BINDIR)/$(CONFIG)/alts_tsi_handshaker_test || ( echo test alts_tsi_handshaker_test failed ; exit 1 )
+	$(E) "[RUN]     Testing alts_tsi_utils_test"
+	$(Q) $(BINDIR)/$(CONFIG)/alts_tsi_utils_test || ( echo test alts_tsi_utils_test failed ; exit 1 )
+	$(E) "[RUN]     Testing alts_zero_copy_grpc_protector_test"
+	$(Q) $(BINDIR)/$(CONFIG)/alts_zero_copy_grpc_protector_test || ( echo test alts_zero_copy_grpc_protector_test failed ; exit 1 )
 	$(E) "[RUN]     Testing async_end2end_test"
 	$(Q) $(BINDIR)/$(CONFIG)/async_end2end_test || ( echo test async_end2end_test failed ; exit 1 )
 	$(E) "[RUN]     Testing auth_property_iterator_test"
@@ -2110,10 +2216,18 @@
 	$(Q) $(BINDIR)/$(CONFIG)/bm_metadata || ( echo test bm_metadata failed ; exit 1 )
 	$(E) "[RUN]     Testing bm_pollset"
 	$(Q) $(BINDIR)/$(CONFIG)/bm_pollset || ( echo test bm_pollset failed ; exit 1 )
+	$(E) "[RUN]     Testing byte_stream_test"
+	$(Q) $(BINDIR)/$(CONFIG)/byte_stream_test || ( echo test byte_stream_test failed ; exit 1 )
 	$(E) "[RUN]     Testing channel_arguments_test"
 	$(Q) $(BINDIR)/$(CONFIG)/channel_arguments_test || ( echo test channel_arguments_test failed ; exit 1 )
 	$(E) "[RUN]     Testing channel_filter_test"
 	$(Q) $(BINDIR)/$(CONFIG)/channel_filter_test || ( echo test channel_filter_test failed ; exit 1 )
+	$(E) "[RUN]     Testing channel_trace_test"
+	$(Q) $(BINDIR)/$(CONFIG)/channel_trace_test || ( echo test channel_trace_test failed ; exit 1 )
+	$(E) "[RUN]     Testing check_gcp_environment_linux_test"
+	$(Q) $(BINDIR)/$(CONFIG)/check_gcp_environment_linux_test || ( echo test check_gcp_environment_linux_test failed ; exit 1 )
+	$(E) "[RUN]     Testing check_gcp_environment_windows_test"
+	$(Q) $(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test || ( echo test check_gcp_environment_windows_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_settings_timeout_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test || ( echo test chttp2_settings_timeout_test failed ; exit 1 )
 	$(E) "[RUN]     Testing cli_call_test"
@@ -2150,16 +2264,18 @@
 	$(Q) $(BINDIR)/$(CONFIG)/generic_end2end_test || ( echo test generic_end2end_test failed ; exit 1 )
 	$(E) "[RUN]     Testing golden_file_test"
 	$(Q) $(BINDIR)/$(CONFIG)/golden_file_test || ( echo test golden_file_test failed ; exit 1 )
+	$(E) "[RUN]     Testing grpc_alts_credentials_options_test"
+	$(Q) $(BINDIR)/$(CONFIG)/grpc_alts_credentials_options_test || ( echo test grpc_alts_credentials_options_test failed ; exit 1 )
 	$(E) "[RUN]     Testing grpc_tool_test"
 	$(Q) $(BINDIR)/$(CONFIG)/grpc_tool_test || ( echo test grpc_tool_test failed ; exit 1 )
 	$(E) "[RUN]     Testing grpclb_api_test"
 	$(Q) $(BINDIR)/$(CONFIG)/grpclb_api_test || ( echo test grpclb_api_test failed ; exit 1 )
 	$(E) "[RUN]     Testing grpclb_end2end_test"
 	$(Q) $(BINDIR)/$(CONFIG)/grpclb_end2end_test || ( echo test grpclb_end2end_test failed ; exit 1 )
-	$(E) "[RUN]     Testing grpclb_test"
-	$(Q) $(BINDIR)/$(CONFIG)/grpclb_test || ( echo test grpclb_test failed ; exit 1 )
 	$(E) "[RUN]     Testing h2_ssl_cert_test"
 	$(Q) $(BINDIR)/$(CONFIG)/h2_ssl_cert_test || ( echo test h2_ssl_cert_test failed ; exit 1 )
+	$(E) "[RUN]     Testing h2_ssl_session_reuse_test"
+	$(Q) $(BINDIR)/$(CONFIG)/h2_ssl_session_reuse_test || ( echo test h2_ssl_session_reuse_test failed ; exit 1 )
 	$(E) "[RUN]     Testing health_service_end2end_test"
 	$(Q) $(BINDIR)/$(CONFIG)/health_service_end2end_test || ( echo test health_service_end2end_test failed ; exit 1 )
 	$(E) "[RUN]     Testing inlined_vector_test"
@@ -2172,6 +2288,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/memory_test || ( echo test memory_test failed ; exit 1 )
 	$(E) "[RUN]     Testing mock_test"
 	$(Q) $(BINDIR)/$(CONFIG)/mock_test || ( echo test mock_test failed ; exit 1 )
+	$(E) "[RUN]     Testing nonblocking_test"
+	$(Q) $(BINDIR)/$(CONFIG)/nonblocking_test || ( echo test nonblocking_test failed ; exit 1 )
 	$(E) "[RUN]     Testing noop-benchmark"
 	$(Q) $(BINDIR)/$(CONFIG)/noop-benchmark || ( echo test noop-benchmark failed ; exit 1 )
 	$(E) "[RUN]     Testing orphanable_test"
@@ -2204,10 +2322,16 @@
 	$(Q) $(BINDIR)/$(CONFIG)/server_request_call_test || ( echo test server_request_call_test failed ; exit 1 )
 	$(E) "[RUN]     Testing shutdown_test"
 	$(Q) $(BINDIR)/$(CONFIG)/shutdown_test || ( echo test shutdown_test failed ; exit 1 )
+	$(E) "[RUN]     Testing slice_hash_table_test"
+	$(Q) $(BINDIR)/$(CONFIG)/slice_hash_table_test || ( echo test slice_hash_table_test failed ; exit 1 )
+	$(E) "[RUN]     Testing slice_weak_hash_table_test"
+	$(Q) $(BINDIR)/$(CONFIG)/slice_weak_hash_table_test || ( echo test slice_weak_hash_table_test failed ; exit 1 )
 	$(E) "[RUN]     Testing stats_test"
 	$(Q) $(BINDIR)/$(CONFIG)/stats_test || ( echo test stats_test failed ; exit 1 )
-	$(E) "[RUN]     Testing status_test"
-	$(Q) $(BINDIR)/$(CONFIG)/status_test || ( echo test status_test failed ; exit 1 )
+	$(E) "[RUN]     Testing status_metadata_test"
+	$(Q) $(BINDIR)/$(CONFIG)/status_metadata_test || ( echo test status_metadata_test failed ; exit 1 )
+	$(E) "[RUN]     Testing status_util_test"
+	$(Q) $(BINDIR)/$(CONFIG)/status_util_test || ( echo test status_util_test failed ; exit 1 )
 	$(E) "[RUN]     Testing streaming_throughput_test"
 	$(Q) $(BINDIR)/$(CONFIG)/streaming_throughput_test || ( echo test streaming_throughput_test failed ; exit 1 )
 	$(E) "[RUN]     Testing thread_manager_test"
@@ -2216,12 +2340,18 @@
 	$(Q) $(BINDIR)/$(CONFIG)/thread_stress_test || ( echo test thread_stress_test failed ; exit 1 )
 	$(E) "[RUN]     Testing transport_pid_controller_test"
 	$(Q) $(BINDIR)/$(CONFIG)/transport_pid_controller_test || ( echo test transport_pid_controller_test failed ; exit 1 )
+	$(E) "[RUN]     Testing transport_security_common_api_test"
+	$(Q) $(BINDIR)/$(CONFIG)/transport_security_common_api_test || ( echo test transport_security_common_api_test failed ; exit 1 )
 	$(E) "[RUN]     Testing writes_per_rpc_test"
 	$(Q) $(BINDIR)/$(CONFIG)/writes_per_rpc_test || ( echo test writes_per_rpc_test failed ; exit 1 )
 	$(E) "[RUN]     Testing resolver_component_tests_runner_invoker_unsecure"
 	$(Q) $(BINDIR)/$(CONFIG)/resolver_component_tests_runner_invoker_unsecure || ( echo test resolver_component_tests_runner_invoker_unsecure failed ; exit 1 )
 	$(E) "[RUN]     Testing resolver_component_tests_runner_invoker"
 	$(Q) $(BINDIR)/$(CONFIG)/resolver_component_tests_runner_invoker || ( echo test resolver_component_tests_runner_invoker failed ; exit 1 )
+	$(E) "[RUN]     Testing address_sorting_test_unsecure"
+	$(Q) $(BINDIR)/$(CONFIG)/address_sorting_test_unsecure || ( echo test address_sorting_test_unsecure failed ; exit 1 )
+	$(E) "[RUN]     Testing address_sorting_test"
+	$(Q) $(BINDIR)/$(CONFIG)/address_sorting_test || ( echo test address_sorting_test failed ; exit 1 )
 
 
 flaky_test_cxx: buildtests_cxx
@@ -2258,6 +2388,8 @@
 
 strip-static_c: static_c
 ifeq ($(CONFIG),opt)
+	$(E) "[STRIP]   Stripping libaddress_sorting.a"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libaddress_sorting.a
 	$(E) "[STRIP]   Stripping libgpr.a"
 	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[STRIP]   Stripping libgrpc.a"
@@ -2284,6 +2416,8 @@
 
 strip-shared_c: shared_c
 ifeq ($(CONFIG),opt)
+	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)
 	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
 	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)
 	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
@@ -2339,6 +2473,22 @@
 	$(Q) echo "$(GRPCXX_UNSECURE_PC_FILE)" | tr , '\n' >$@
 
 ifeq ($(NO_PROTOC),true)
+$(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc: protoc_dep_error
+$(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc: protoc_dep_error
+else
+
+$(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc: src/proto/grpc/channelz/channelz.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
+	$(E) "[PROTOC]  Generating protobuf CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
+
+$(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc: src/proto/grpc/channelz/channelz.proto $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
+	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
+endif
+
+ifeq ($(NO_PROTOC),true)
 $(GENDIR)/src/proto/grpc/core/stats.pb.cc: protoc_dep_error
 $(GENDIR)/src/proto/grpc/core/stats.grpc.pb.cc: protoc_dep_error
 else
@@ -2680,6 +2830,9 @@
 install-static: install-static_c install-static_cxx
 
 install-static_c: static_c strip-static_c install-pkg-config_c
+	$(E) "[INSTALL] Installing libaddress_sorting.a"
+	$(Q) $(INSTALL) -d $(prefix)/lib
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libaddress_sorting.a $(prefix)/lib/libaddress_sorting.a
 	$(E) "[INSTALL] Installing libgpr.a"
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgpr.a $(prefix)/lib/libgpr.a
@@ -2713,6 +2866,15 @@
 
 
 install-shared_c: shared_c strip-shared_c install-pkg-config_c
+	$(E) "[INSTALL] Installing $(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
+	$(Q) $(INSTALL) -d $(prefix)/lib
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/$(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)
+ifeq ($(SYSTEM),MINGW32)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE)-dll.a $(prefix)/lib/libaddress_sorting.a
+else ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf $(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libaddress_sorting.so.6
+	$(Q) ln -sf $(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libaddress_sorting.so
+endif
 	$(E) "[INSTALL] Installing $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/$(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)
@@ -2843,6 +3005,11 @@
 	$(Q) $(INSTALL) -d $(prefix)/bin
 	$(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_ruby_plugin $(prefix)/bin/grpc_ruby_plugin
 
+install-grpc-cli: grpc_cli
+	$(E) "[INSTALL] Installing grpc cli"
+	$(Q) $(INSTALL) -d $(prefix)/bin
+	$(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_cli $(prefix)/bin/grpc_cli
+
 install-pkg-config_c: pc_c pc_c_unsecure
 	$(E) "[INSTALL] Installing C pkg-config files"
 	$(Q) $(INSTALL) -d $(prefix)/lib/pkgconfig
@@ -2868,12 +3035,94 @@
 # The various libraries
 
 
+LIBADDRESS_SORTING_SRC = \
+    third_party/address_sorting/address_sorting.c \
+    third_party/address_sorting/address_sorting_posix.c \
+    third_party/address_sorting/address_sorting_windows.c \
+
+PUBLIC_HEADERS_C += \
+
+LIBADDRESS_SORTING_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBADDRESS_SORTING_SRC))))
+
+
+$(LIBDIR)/$(CONFIG)/libaddress_sorting.a: $(ZLIB_DEP) $(CARES_DEP)  $(LIBADDRESS_SORTING_OBJS) 
+	$(E) "[AR]      Creating $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libaddress_sorting.a
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libaddress_sorting.a $(LIBADDRESS_SORTING_OBJS) 
+ifeq ($(SYSTEM),Darwin)
+	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libaddress_sorting.a
+endif
+
+
+
+ifeq ($(SYSTEM),MINGW32)
+$(LIBDIR)/$(CONFIG)/address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBADDRESS_SORTING_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/address_sorting$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBADDRESS_SORTING_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
+else
+$(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBADDRESS_SORTING_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+ifeq ($(SYSTEM),Darwin)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBADDRESS_SORTING_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
+else
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libaddress_sorting.so.6 -o $(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBADDRESS_SORTING_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
+	$(Q) ln -sf $(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE).so.6
+	$(Q) ln -sf $(SHARED_PREFIX)address_sorting$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libaddress_sorting$(SHARED_VERSION_CORE).so
+endif
+endif
+
+ifneq ($(NO_DEPS),true)
+-include $(LIBADDRESS_SORTING_OBJS:.o=.dep)
+endif
+
+
+LIBALTS_TEST_UTIL_SRC = \
+    test/core/tsi/alts/crypt/gsec_test_util.cc \
+    test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.cc \
+
+PUBLIC_HEADERS_C += \
+
+LIBALTS_TEST_UTIL_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBALTS_TEST_UTIL_SRC))))
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure libraries if you don't have OpenSSL.
+
+$(LIBDIR)/$(CONFIG)/libalts_test_util.a: openssl_dep_error
+
+
+else
+
+
+$(LIBDIR)/$(CONFIG)/libalts_test_util.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(LIBALTS_TEST_UTIL_OBJS) 
+	$(E) "[AR]      Creating $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libalts_test_util.a
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBALTS_TEST_UTIL_OBJS) 
+ifeq ($(SYSTEM),Darwin)
+	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libalts_test_util.a
+endif
+
+
+
+
+endif
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(LIBALTS_TEST_UTIL_OBJS:.o=.dep)
+endif
+endif
+
+
 LIBGPR_SRC = \
     src/core/lib/gpr/alloc.cc \
     src/core/lib/gpr/arena.cc \
     src/core/lib/gpr/atm.cc \
-    src/core/lib/gpr/avl.cc \
-    src/core/lib/gpr/cmdline.cc \
     src/core/lib/gpr/cpu_iphone.cc \
     src/core/lib/gpr/cpu_linux.cc \
     src/core/lib/gpr/cpu_posix.cc \
@@ -2894,14 +3143,9 @@
     src/core/lib/gpr/string_posix.cc \
     src/core/lib/gpr/string_util_windows.cc \
     src/core/lib/gpr/string_windows.cc \
-    src/core/lib/gpr/subprocess_posix.cc \
-    src/core/lib/gpr/subprocess_windows.cc \
     src/core/lib/gpr/sync.cc \
     src/core/lib/gpr/sync_posix.cc \
     src/core/lib/gpr/sync_windows.cc \
-    src/core/lib/gpr/thd.cc \
-    src/core/lib/gpr/thd_posix.cc \
-    src/core/lib/gpr/thd_windows.cc \
     src/core/lib/gpr/time.cc \
     src/core/lib/gpr/time_posix.cc \
     src/core/lib/gpr/time_precise.cc \
@@ -2911,6 +3155,8 @@
     src/core/lib/gpr/tmpfile_posix.cc \
     src/core/lib/gpr/tmpfile_windows.cc \
     src/core/lib/gpr/wrap_memcpy.cc \
+    src/core/lib/gprpp/thd_posix.cc \
+    src/core/lib/gprpp/thd_windows.cc \
     src/core/lib/profiling/basic_timers.cc \
     src/core/lib/profiling/stap_timers.cc \
 
@@ -2920,27 +3166,18 @@
     include/grpc/support/atm_gcc_atomic.h \
     include/grpc/support/atm_gcc_sync.h \
     include/grpc/support/atm_windows.h \
-    include/grpc/support/avl.h \
-    include/grpc/support/cmdline.h \
     include/grpc/support/cpu.h \
-    include/grpc/support/host_port.h \
     include/grpc/support/log.h \
     include/grpc/support/log_windows.h \
     include/grpc/support/port_platform.h \
     include/grpc/support/string_util.h \
-    include/grpc/support/subprocess.h \
     include/grpc/support/sync.h \
     include/grpc/support/sync_custom.h \
     include/grpc/support/sync_generic.h \
     include/grpc/support/sync_posix.h \
     include/grpc/support/sync_windows.h \
-    include/grpc/support/thd.h \
+    include/grpc/support/thd_id.h \
     include/grpc/support/time.h \
-    include/grpc/support/tls.h \
-    include/grpc/support/tls_gcc.h \
-    include/grpc/support/tls_msvc.h \
-    include/grpc/support/tls_pthread.h \
-    include/grpc/support/useful.h \
     include/grpc/impl/codegen/atm.h \
     include/grpc/impl/codegen/atm_gcc_atomic.h \
     include/grpc/impl/codegen/atm_gcc_sync.h \
@@ -2958,7 +3195,7 @@
 LIBGPR_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGPR_SRC))))
 
 
-$(LIBDIR)/$(CONFIG)/libgpr.a: $(ZLIB_DEP) $(CARES_DEP)  $(LIBGPR_OBJS) 
+$(LIBDIR)/$(CONFIG)/libgpr.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(LIBGPR_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgpr.a
@@ -2970,18 +3207,18 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGPR_OBJS)  $(ZLIB_DEP) $(CARES_DEP)
+$(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGPR_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
 else
-$(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGPR_OBJS)  $(ZLIB_DEP) $(CARES_DEP)
+$(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGPR_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
 else
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgpr.so.6 -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgpr.so.6 -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
 	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).so.6
 	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).so
 endif
@@ -3000,7 +3237,7 @@
 LIBGPR_TEST_UTIL_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGPR_TEST_UTIL_SRC))))
 
 
-$(LIBDIR)/$(CONFIG)/libgpr_test_util.a: $(ZLIB_DEP) $(CARES_DEP)  $(LIBGPR_TEST_UTIL_OBJS) 
+$(LIBDIR)/$(CONFIG)/libgpr_test_util.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(LIBGPR_TEST_UTIL_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgpr_test_util.a
@@ -3019,17 +3256,20 @@
 
 LIBGRPC_SRC = \
     src/core/lib/surface/init.cc \
+    src/core/lib/avl/avl.cc \
     src/core/lib/backoff/backoff.cc \
     src/core/lib/channel/channel_args.cc \
     src/core/lib/channel/channel_stack.cc \
     src/core/lib/channel/channel_stack_builder.cc \
+    src/core/lib/channel/channel_trace.cc \
+    src/core/lib/channel/channel_trace_registry.cc \
     src/core/lib/channel/connected_channel.cc \
     src/core/lib/channel/handshaker.cc \
     src/core/lib/channel/handshaker_factory.cc \
     src/core/lib/channel/handshaker_registry.cc \
+    src/core/lib/channel/status_util.cc \
     src/core/lib/compression/compression.cc \
     src/core/lib/compression/compression_internal.cc \
-    src/core/lib/compression/compression_ruby.cc \
     src/core/lib/compression/message_compress.cc \
     src/core/lib/compression/stream_compression.cc \
     src/core/lib/compression/stream_compression_gzip.cc \
@@ -3061,6 +3301,8 @@
     src/core/lib/iomgr/gethostname_sysconf.cc \
     src/core/lib/iomgr/iocp_windows.cc \
     src/core/lib/iomgr/iomgr.cc \
+    src/core/lib/iomgr/iomgr_custom.cc \
+    src/core/lib/iomgr/iomgr_internal.cc \
     src/core/lib/iomgr/iomgr_posix.cc \
     src/core/lib/iomgr/iomgr_uv.cc \
     src/core/lib/iomgr/iomgr_windows.cc \
@@ -3069,12 +3311,16 @@
     src/core/lib/iomgr/lockfree_event.cc \
     src/core/lib/iomgr/network_status_tracker.cc \
     src/core/lib/iomgr/polling_entity.cc \
-    src/core/lib/iomgr/pollset_set_uv.cc \
+    src/core/lib/iomgr/pollset.cc \
+    src/core/lib/iomgr/pollset_custom.cc \
+    src/core/lib/iomgr/pollset_set.cc \
+    src/core/lib/iomgr/pollset_set_custom.cc \
     src/core/lib/iomgr/pollset_set_windows.cc \
     src/core/lib/iomgr/pollset_uv.cc \
     src/core/lib/iomgr/pollset_windows.cc \
+    src/core/lib/iomgr/resolve_address.cc \
+    src/core/lib/iomgr/resolve_address_custom.cc \
     src/core/lib/iomgr/resolve_address_posix.cc \
-    src/core/lib/iomgr/resolve_address_uv.cc \
     src/core/lib/iomgr/resolve_address_windows.cc \
     src/core/lib/iomgr/resource_quota.cc \
     src/core/lib/iomgr/sockaddr_utils.cc \
@@ -3086,19 +3332,24 @@
     src/core/lib/iomgr/socket_utils_uv.cc \
     src/core/lib/iomgr/socket_utils_windows.cc \
     src/core/lib/iomgr/socket_windows.cc \
+    src/core/lib/iomgr/tcp_client.cc \
+    src/core/lib/iomgr/tcp_client_custom.cc \
     src/core/lib/iomgr/tcp_client_posix.cc \
-    src/core/lib/iomgr/tcp_client_uv.cc \
     src/core/lib/iomgr/tcp_client_windows.cc \
+    src/core/lib/iomgr/tcp_custom.cc \
     src/core/lib/iomgr/tcp_posix.cc \
+    src/core/lib/iomgr/tcp_server.cc \
+    src/core/lib/iomgr/tcp_server_custom.cc \
     src/core/lib/iomgr/tcp_server_posix.cc \
     src/core/lib/iomgr/tcp_server_utils_posix_common.cc \
     src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc \
     src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc \
-    src/core/lib/iomgr/tcp_server_uv.cc \
     src/core/lib/iomgr/tcp_server_windows.cc \
     src/core/lib/iomgr/tcp_uv.cc \
     src/core/lib/iomgr/tcp_windows.cc \
     src/core/lib/iomgr/time_averaged_stats.cc \
+    src/core/lib/iomgr/timer.cc \
+    src/core/lib/iomgr/timer_custom.cc \
     src/core/lib/iomgr/timer_generic.cc \
     src/core/lib/iomgr/timer_heap.cc \
     src/core/lib/iomgr/timer_manager.cc \
@@ -3119,7 +3370,6 @@
     src/core/lib/slice/percent_encoding.cc \
     src/core/lib/slice/slice.cc \
     src/core/lib/slice/slice_buffer.cc \
-    src/core/lib/slice/slice_hash_table.cc \
     src/core/lib/slice/slice_intern.cc \
     src/core/lib/slice/slice_string_helpers.cc \
     src/core/lib/surface/api_trace.cc \
@@ -3150,6 +3400,7 @@
     src/core/lib/transport/service_config.cc \
     src/core/lib/transport/static_metadata.cc \
     src/core/lib/transport/status_conversion.cc \
+    src/core/lib/transport/status_metadata.cc \
     src/core/lib/transport/timeout_encoding.cc \
     src/core/lib/transport/transport.cc \
     src/core/lib/transport/transport_op_string.cc \
@@ -3184,6 +3435,7 @@
     src/core/ext/filters/http/server/http_server_filter.cc \
     src/core/lib/http/httpcli_security_connector.cc \
     src/core/lib/security/context/security_context.cc \
+    src/core/lib/security/credentials/alts/alts_credentials.cc \
     src/core/lib/security/credentials/composite/composite_credentials.cc \
     src/core/lib/security/credentials/credentials.cc \
     src/core/lib/security/credentials/credentials_metadata.cc \
@@ -3197,23 +3449,55 @@
     src/core/lib/security/credentials/oauth2/oauth2_credentials.cc \
     src/core/lib/security/credentials/plugin/plugin_credentials.cc \
     src/core/lib/security/credentials/ssl/ssl_credentials.cc \
+    src/core/lib/security/security_connector/alts_security_connector.cc \
+    src/core/lib/security/security_connector/security_connector.cc \
     src/core/lib/security/transport/client_auth_filter.cc \
-    src/core/lib/security/transport/lb_targets_info.cc \
     src/core/lib/security/transport/secure_endpoint.cc \
-    src/core/lib/security/transport/security_connector.cc \
     src/core/lib/security/transport/security_handshaker.cc \
     src/core/lib/security/transport/server_auth_filter.cc \
+    src/core/lib/security/transport/target_authority_table.cc \
     src/core/lib/security/transport/tsi_error.cc \
     src/core/lib/security/util/json_util.cc \
     src/core/lib/surface/init_secure.cc \
-    src/core/tsi/alts_transport_security.cc \
-    src/core/tsi/fake_transport_security.cc \
-    src/core/tsi/ssl_transport_security.cc \
-    src/core/tsi/transport_security_grpc.cc \
+    src/core/tsi/alts/crypt/aes_gcm.cc \
+    src/core/tsi/alts/crypt/gsec.cc \
+    src/core/tsi/alts/frame_protector/alts_counter.cc \
+    src/core/tsi/alts/frame_protector/alts_crypter.cc \
+    src/core/tsi/alts/frame_protector/alts_frame_protector.cc \
+    src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc \
+    src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc \
+    src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc \
+    src/core/tsi/alts/frame_protector/frame_handler.cc \
+    src/core/tsi/alts/handshaker/alts_handshaker_client.cc \
+    src/core/tsi/alts/handshaker/alts_tsi_event.cc \
+    src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc \
+    src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc \
+    src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc \
+    src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc \
+    src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc \
+    src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc \
+    src/core/lib/security/credentials/alts/check_gcp_environment.cc \
+    src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc \
+    src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc \
+    src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc \
+    src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc \
+    src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc \
+    src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc \
+    src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc \
+    src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc \
+    src/core/tsi/alts/handshaker/alts_tsi_utils.cc \
+    src/core/tsi/alts/handshaker/transport_security_common_api.cc \
+    src/core/tsi/alts/handshaker/altscontext.pb.c \
+    src/core/tsi/alts/handshaker/handshaker.pb.c \
+    src/core/tsi/alts/handshaker/transport_security_common.pb.c \
+    third_party/nanopb/pb_common.c \
+    third_party/nanopb/pb_decode.c \
+    third_party/nanopb/pb_encode.c \
     src/core/tsi/transport_security.cc \
     src/core/tsi/transport_security_adapter.cc \
-    src/core/ext/transport/chttp2/server/chttp2_server.cc \
-    src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc \
+    src/core/ext/transport/chttp2/client/insecure/channel_create.cc \
+    src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc \
+    src/core/ext/transport/chttp2/client/chttp2_connector.cc \
     src/core/ext/filters/client_channel/backup_poller.cc \
     src/core/ext/filters/client_channel/channel_connectivity.cc \
     src/core/ext/filters/client_channel/client_channel.cc \
@@ -3225,22 +3509,28 @@
     src/core/ext/filters/client_channel/lb_policy.cc \
     src/core/ext/filters/client_channel/lb_policy_factory.cc \
     src/core/ext/filters/client_channel/lb_policy_registry.cc \
+    src/core/ext/filters/client_channel/method_params.cc \
     src/core/ext/filters/client_channel/parse_address.cc \
     src/core/ext/filters/client_channel/proxy_mapper.cc \
     src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
     src/core/ext/filters/client_channel/resolver.cc \
-    src/core/ext/filters/client_channel/resolver_factory.cc \
     src/core/ext/filters/client_channel/resolver_registry.cc \
     src/core/ext/filters/client_channel/retry_throttle.cc \
     src/core/ext/filters/client_channel/subchannel.cc \
     src/core/ext/filters/client_channel/subchannel_index.cc \
     src/core/ext/filters/client_channel/uri_parser.cc \
     src/core/ext/filters/deadline/deadline_filter.cc \
-    src/core/ext/transport/chttp2/client/chttp2_connector.cc \
+    src/core/tsi/alts_transport_security.cc \
+    src/core/tsi/fake_transport_security.cc \
+    src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc \
+    src/core/tsi/ssl/session_cache/ssl_session_cache.cc \
+    src/core/tsi/ssl/session_cache/ssl_session_openssl.cc \
+    src/core/tsi/ssl_transport_security.cc \
+    src/core/tsi/transport_security_grpc.cc \
+    src/core/ext/transport/chttp2/server/chttp2_server.cc \
+    src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc \
     src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc \
     src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc \
-    src/core/ext/transport/chttp2/client/insecure/channel_create.cc \
-    src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc \
     src/core/ext/transport/inproc/inproc_plugin.cc \
     src/core/ext/transport/inproc/inproc_transport.cc \
     src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc \
@@ -3249,9 +3539,6 @@
     src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc \
     src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc \
     src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
-    third_party/nanopb/pb_common.c \
-    third_party/nanopb/pb_decode.c \
-    third_party/nanopb/pb_encode.c \
     src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \
     src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
     src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc \
@@ -3297,7 +3584,6 @@
     include/grpc/byte_buffer.h \
     include/grpc/byte_buffer_reader.h \
     include/grpc/compression.h \
-    include/grpc/compression_ruby.h \
     include/grpc/fork.h \
     include/grpc/grpc.h \
     include/grpc/grpc_posix.h \
@@ -3323,11 +3609,11 @@
 else
 
 
-$(LIBDIR)/$(CONFIG)/libgrpc.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(LIBGRPC_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS)  $(OPENSSL_MERGE_OBJS) 
+$(LIBDIR)/$(CONFIG)/libgrpc.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(LIBGRPC_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS)  $(ADDRESS_SORTING_MERGE_OBJS)  $(OPENSSL_MERGE_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc.a
-	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBGRPC_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS)  $(OPENSSL_MERGE_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBGRPC_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS)  $(ADDRESS_SORTING_MERGE_OBJS)  $(OPENSSL_MERGE_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc.a
 endif
@@ -3335,18 +3621,18 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
 else
-$(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
 else
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc.so.6 -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc.so.6 -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
 	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).so.6
 	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).so
 endif
@@ -3363,17 +3649,20 @@
 
 LIBGRPC_CRONET_SRC = \
     src/core/lib/surface/init.cc \
+    src/core/lib/avl/avl.cc \
     src/core/lib/backoff/backoff.cc \
     src/core/lib/channel/channel_args.cc \
     src/core/lib/channel/channel_stack.cc \
     src/core/lib/channel/channel_stack_builder.cc \
+    src/core/lib/channel/channel_trace.cc \
+    src/core/lib/channel/channel_trace_registry.cc \
     src/core/lib/channel/connected_channel.cc \
     src/core/lib/channel/handshaker.cc \
     src/core/lib/channel/handshaker_factory.cc \
     src/core/lib/channel/handshaker_registry.cc \
+    src/core/lib/channel/status_util.cc \
     src/core/lib/compression/compression.cc \
     src/core/lib/compression/compression_internal.cc \
-    src/core/lib/compression/compression_ruby.cc \
     src/core/lib/compression/message_compress.cc \
     src/core/lib/compression/stream_compression.cc \
     src/core/lib/compression/stream_compression_gzip.cc \
@@ -3405,6 +3694,8 @@
     src/core/lib/iomgr/gethostname_sysconf.cc \
     src/core/lib/iomgr/iocp_windows.cc \
     src/core/lib/iomgr/iomgr.cc \
+    src/core/lib/iomgr/iomgr_custom.cc \
+    src/core/lib/iomgr/iomgr_internal.cc \
     src/core/lib/iomgr/iomgr_posix.cc \
     src/core/lib/iomgr/iomgr_uv.cc \
     src/core/lib/iomgr/iomgr_windows.cc \
@@ -3413,12 +3704,16 @@
     src/core/lib/iomgr/lockfree_event.cc \
     src/core/lib/iomgr/network_status_tracker.cc \
     src/core/lib/iomgr/polling_entity.cc \
-    src/core/lib/iomgr/pollset_set_uv.cc \
+    src/core/lib/iomgr/pollset.cc \
+    src/core/lib/iomgr/pollset_custom.cc \
+    src/core/lib/iomgr/pollset_set.cc \
+    src/core/lib/iomgr/pollset_set_custom.cc \
     src/core/lib/iomgr/pollset_set_windows.cc \
     src/core/lib/iomgr/pollset_uv.cc \
     src/core/lib/iomgr/pollset_windows.cc \
+    src/core/lib/iomgr/resolve_address.cc \
+    src/core/lib/iomgr/resolve_address_custom.cc \
     src/core/lib/iomgr/resolve_address_posix.cc \
-    src/core/lib/iomgr/resolve_address_uv.cc \
     src/core/lib/iomgr/resolve_address_windows.cc \
     src/core/lib/iomgr/resource_quota.cc \
     src/core/lib/iomgr/sockaddr_utils.cc \
@@ -3430,19 +3725,24 @@
     src/core/lib/iomgr/socket_utils_uv.cc \
     src/core/lib/iomgr/socket_utils_windows.cc \
     src/core/lib/iomgr/socket_windows.cc \
+    src/core/lib/iomgr/tcp_client.cc \
+    src/core/lib/iomgr/tcp_client_custom.cc \
     src/core/lib/iomgr/tcp_client_posix.cc \
-    src/core/lib/iomgr/tcp_client_uv.cc \
     src/core/lib/iomgr/tcp_client_windows.cc \
+    src/core/lib/iomgr/tcp_custom.cc \
     src/core/lib/iomgr/tcp_posix.cc \
+    src/core/lib/iomgr/tcp_server.cc \
+    src/core/lib/iomgr/tcp_server_custom.cc \
     src/core/lib/iomgr/tcp_server_posix.cc \
     src/core/lib/iomgr/tcp_server_utils_posix_common.cc \
     src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc \
     src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc \
-    src/core/lib/iomgr/tcp_server_uv.cc \
     src/core/lib/iomgr/tcp_server_windows.cc \
     src/core/lib/iomgr/tcp_uv.cc \
     src/core/lib/iomgr/tcp_windows.cc \
     src/core/lib/iomgr/time_averaged_stats.cc \
+    src/core/lib/iomgr/timer.cc \
+    src/core/lib/iomgr/timer_custom.cc \
     src/core/lib/iomgr/timer_generic.cc \
     src/core/lib/iomgr/timer_heap.cc \
     src/core/lib/iomgr/timer_manager.cc \
@@ -3463,7 +3763,6 @@
     src/core/lib/slice/percent_encoding.cc \
     src/core/lib/slice/slice.cc \
     src/core/lib/slice/slice_buffer.cc \
-    src/core/lib/slice/slice_hash_table.cc \
     src/core/lib/slice/slice_intern.cc \
     src/core/lib/slice/slice_string_helpers.cc \
     src/core/lib/surface/api_trace.cc \
@@ -3494,10 +3793,41 @@
     src/core/lib/transport/service_config.cc \
     src/core/lib/transport/static_metadata.cc \
     src/core/lib/transport/status_conversion.cc \
+    src/core/lib/transport/status_metadata.cc \
     src/core/lib/transport/timeout_encoding.cc \
     src/core/lib/transport/transport.cc \
     src/core/lib/transport/transport_op_string.cc \
     src/core/lib/debug/trace.cc \
+    src/core/ext/filters/deadline/deadline_filter.cc \
+    src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
+    src/core/ext/filters/client_channel/backup_poller.cc \
+    src/core/ext/filters/client_channel/channel_connectivity.cc \
+    src/core/ext/filters/client_channel/client_channel.cc \
+    src/core/ext/filters/client_channel/client_channel_factory.cc \
+    src/core/ext/filters/client_channel/client_channel_plugin.cc \
+    src/core/ext/filters/client_channel/connector.cc \
+    src/core/ext/filters/client_channel/http_connect_handshaker.cc \
+    src/core/ext/filters/client_channel/http_proxy.cc \
+    src/core/ext/filters/client_channel/lb_policy.cc \
+    src/core/ext/filters/client_channel/lb_policy_factory.cc \
+    src/core/ext/filters/client_channel/lb_policy_registry.cc \
+    src/core/ext/filters/client_channel/method_params.cc \
+    src/core/ext/filters/client_channel/parse_address.cc \
+    src/core/ext/filters/client_channel/proxy_mapper.cc \
+    src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
+    src/core/ext/filters/client_channel/resolver.cc \
+    src/core/ext/filters/client_channel/resolver_registry.cc \
+    src/core/ext/filters/client_channel/retry_throttle.cc \
+    src/core/ext/filters/client_channel/subchannel.cc \
+    src/core/ext/filters/client_channel/subchannel_index.cc \
+    src/core/ext/filters/client_channel/uri_parser.cc \
+    src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc \
+    src/core/ext/filters/max_age/max_age_filter.cc \
+    src/core/ext/filters/message_size/message_size_filter.cc \
+    src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc \
+    src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \
+    src/core/ext/filters/load_reporting/server_load_reporting_filter.cc \
+    src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc \
     src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc \
     src/core/ext/transport/cronet/transport/cronet_api_dummy.cc \
     src/core/ext/transport/cronet/transport/cronet_transport.cc \
@@ -3529,30 +3859,9 @@
     src/core/ext/filters/http/http_filters_plugin.cc \
     src/core/ext/filters/http/message_compress/message_compress_filter.cc \
     src/core/ext/filters/http/server/http_server_filter.cc \
-    src/core/ext/filters/client_channel/backup_poller.cc \
-    src/core/ext/filters/client_channel/channel_connectivity.cc \
-    src/core/ext/filters/client_channel/client_channel.cc \
-    src/core/ext/filters/client_channel/client_channel_factory.cc \
-    src/core/ext/filters/client_channel/client_channel_plugin.cc \
-    src/core/ext/filters/client_channel/connector.cc \
-    src/core/ext/filters/client_channel/http_connect_handshaker.cc \
-    src/core/ext/filters/client_channel/http_proxy.cc \
-    src/core/ext/filters/client_channel/lb_policy.cc \
-    src/core/ext/filters/client_channel/lb_policy_factory.cc \
-    src/core/ext/filters/client_channel/lb_policy_registry.cc \
-    src/core/ext/filters/client_channel/parse_address.cc \
-    src/core/ext/filters/client_channel/proxy_mapper.cc \
-    src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
-    src/core/ext/filters/client_channel/resolver.cc \
-    src/core/ext/filters/client_channel/resolver_factory.cc \
-    src/core/ext/filters/client_channel/resolver_registry.cc \
-    src/core/ext/filters/client_channel/retry_throttle.cc \
-    src/core/ext/filters/client_channel/subchannel.cc \
-    src/core/ext/filters/client_channel/subchannel_index.cc \
-    src/core/ext/filters/client_channel/uri_parser.cc \
-    src/core/ext/filters/deadline/deadline_filter.cc \
     src/core/lib/http/httpcli_security_connector.cc \
     src/core/lib/security/context/security_context.cc \
+    src/core/lib/security/credentials/alts/alts_credentials.cc \
     src/core/lib/security/credentials/composite/composite_credentials.cc \
     src/core/lib/security/credentials/credentials.cc \
     src/core/lib/security/credentials/credentials_metadata.cc \
@@ -3566,24 +3875,64 @@
     src/core/lib/security/credentials/oauth2/oauth2_credentials.cc \
     src/core/lib/security/credentials/plugin/plugin_credentials.cc \
     src/core/lib/security/credentials/ssl/ssl_credentials.cc \
+    src/core/lib/security/security_connector/alts_security_connector.cc \
+    src/core/lib/security/security_connector/security_connector.cc \
     src/core/lib/security/transport/client_auth_filter.cc \
-    src/core/lib/security/transport/lb_targets_info.cc \
     src/core/lib/security/transport/secure_endpoint.cc \
-    src/core/lib/security/transport/security_connector.cc \
     src/core/lib/security/transport/security_handshaker.cc \
     src/core/lib/security/transport/server_auth_filter.cc \
+    src/core/lib/security/transport/target_authority_table.cc \
     src/core/lib/security/transport/tsi_error.cc \
     src/core/lib/security/util/json_util.cc \
     src/core/lib/surface/init_secure.cc \
-    src/core/tsi/alts_transport_security.cc \
-    src/core/tsi/fake_transport_security.cc \
-    src/core/tsi/ssl_transport_security.cc \
-    src/core/tsi/transport_security_grpc.cc \
+    src/core/tsi/alts/crypt/aes_gcm.cc \
+    src/core/tsi/alts/crypt/gsec.cc \
+    src/core/tsi/alts/frame_protector/alts_counter.cc \
+    src/core/tsi/alts/frame_protector/alts_crypter.cc \
+    src/core/tsi/alts/frame_protector/alts_frame_protector.cc \
+    src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc \
+    src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc \
+    src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc \
+    src/core/tsi/alts/frame_protector/frame_handler.cc \
+    src/core/tsi/alts/handshaker/alts_handshaker_client.cc \
+    src/core/tsi/alts/handshaker/alts_tsi_event.cc \
+    src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc \
+    src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc \
+    src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc \
+    src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc \
+    src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc \
+    src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc \
+    src/core/lib/security/credentials/alts/check_gcp_environment.cc \
+    src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc \
+    src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc \
+    src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc \
+    src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc \
+    src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc \
+    src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc \
+    src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc \
+    src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc \
+    src/core/tsi/alts/handshaker/alts_tsi_utils.cc \
+    src/core/tsi/alts/handshaker/transport_security_common_api.cc \
+    src/core/tsi/alts/handshaker/altscontext.pb.c \
+    src/core/tsi/alts/handshaker/handshaker.pb.c \
+    src/core/tsi/alts/handshaker/transport_security_common.pb.c \
+    third_party/nanopb/pb_common.c \
+    third_party/nanopb/pb_decode.c \
+    third_party/nanopb/pb_encode.c \
     src/core/tsi/transport_security.cc \
     src/core/tsi/transport_security_adapter.cc \
+    src/core/ext/transport/chttp2/client/insecure/channel_create.cc \
+    src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc \
     src/core/ext/transport/chttp2/client/chttp2_connector.cc \
-    src/core/ext/filters/load_reporting/server_load_reporting_filter.cc \
-    src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc \
+    src/core/tsi/alts_transport_security.cc \
+    src/core/tsi/fake_transport_security.cc \
+    src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc \
+    src/core/tsi/ssl/session_cache/ssl_session_cache.cc \
+    src/core/tsi/ssl/session_cache/ssl_session_openssl.cc \
+    src/core/tsi/ssl_transport_security.cc \
+    src/core/tsi/transport_security_grpc.cc \
+    src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc \
+    src/core/ext/transport/chttp2/server/chttp2_server.cc \
     src/core/plugin_registry/grpc_cronet_plugin_registry.cc \
 
 PUBLIC_HEADERS_C += \
@@ -3608,9 +3957,20 @@
     include/grpc/impl/codegen/sync_generic.h \
     include/grpc/impl/codegen/sync_posix.h \
     include/grpc/impl/codegen/sync_windows.h \
+    include/grpc/byte_buffer.h \
+    include/grpc/byte_buffer_reader.h \
+    include/grpc/compression.h \
+    include/grpc/fork.h \
+    include/grpc/grpc.h \
+    include/grpc/grpc_posix.h \
+    include/grpc/grpc_security_constants.h \
+    include/grpc/load_reporting.h \
+    include/grpc/slice.h \
+    include/grpc/slice_buffer.h \
+    include/grpc/status.h \
+    include/grpc/support/workaround_list.h \
     include/grpc/grpc_cronet.h \
     include/grpc/grpc_security.h \
-    include/grpc/grpc_security_constants.h \
 
 LIBGRPC_CRONET_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_CRONET_SRC))))
 
@@ -3626,11 +3986,11 @@
 else
 
 
-$(LIBDIR)/$(CONFIG)/libgrpc_cronet.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(LIBGRPC_CRONET_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS)  $(OPENSSL_MERGE_OBJS) 
+$(LIBDIR)/$(CONFIG)/libgrpc_cronet.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(LIBGRPC_CRONET_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS)  $(ADDRESS_SORTING_MERGE_OBJS)  $(OPENSSL_MERGE_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_cronet.a
-	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc_cronet.a $(LIBGRPC_CRONET_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS)  $(OPENSSL_MERGE_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc_cronet.a $(LIBGRPC_CRONET_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS)  $(ADDRESS_SORTING_MERGE_OBJS)  $(OPENSSL_MERGE_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc_cronet.a
 endif
@@ -3638,18 +3998,18 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_CRONET_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_CRONET_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_cronet$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CRONET_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_cronet$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CRONET_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
 else
-$(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_CRONET_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_CRONET_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CRONET_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CRONET_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
 else
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_cronet.so.6 -o $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CRONET_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_cronet.so.6 -o $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CRONET_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
 	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).so.6
 	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).so
 endif
@@ -3686,19 +4046,25 @@
     test/core/util/port_isolated_runtime_environment.cc \
     test/core/util/port_server_client.cc \
     test/core/util/slice_splitter.cc \
+    test/core/util/subprocess_posix.cc \
+    test/core/util/subprocess_windows.cc \
     test/core/util/tracer_util.cc \
     test/core/util/trickle_endpoint.cc \
+    test/core/util/cmdline.cc \
+    src/core/lib/avl/avl.cc \
     src/core/lib/backoff/backoff.cc \
     src/core/lib/channel/channel_args.cc \
     src/core/lib/channel/channel_stack.cc \
     src/core/lib/channel/channel_stack_builder.cc \
+    src/core/lib/channel/channel_trace.cc \
+    src/core/lib/channel/channel_trace_registry.cc \
     src/core/lib/channel/connected_channel.cc \
     src/core/lib/channel/handshaker.cc \
     src/core/lib/channel/handshaker_factory.cc \
     src/core/lib/channel/handshaker_registry.cc \
+    src/core/lib/channel/status_util.cc \
     src/core/lib/compression/compression.cc \
     src/core/lib/compression/compression_internal.cc \
-    src/core/lib/compression/compression_ruby.cc \
     src/core/lib/compression/message_compress.cc \
     src/core/lib/compression/stream_compression.cc \
     src/core/lib/compression/stream_compression_gzip.cc \
@@ -3730,6 +4096,8 @@
     src/core/lib/iomgr/gethostname_sysconf.cc \
     src/core/lib/iomgr/iocp_windows.cc \
     src/core/lib/iomgr/iomgr.cc \
+    src/core/lib/iomgr/iomgr_custom.cc \
+    src/core/lib/iomgr/iomgr_internal.cc \
     src/core/lib/iomgr/iomgr_posix.cc \
     src/core/lib/iomgr/iomgr_uv.cc \
     src/core/lib/iomgr/iomgr_windows.cc \
@@ -3738,12 +4106,16 @@
     src/core/lib/iomgr/lockfree_event.cc \
     src/core/lib/iomgr/network_status_tracker.cc \
     src/core/lib/iomgr/polling_entity.cc \
-    src/core/lib/iomgr/pollset_set_uv.cc \
+    src/core/lib/iomgr/pollset.cc \
+    src/core/lib/iomgr/pollset_custom.cc \
+    src/core/lib/iomgr/pollset_set.cc \
+    src/core/lib/iomgr/pollset_set_custom.cc \
     src/core/lib/iomgr/pollset_set_windows.cc \
     src/core/lib/iomgr/pollset_uv.cc \
     src/core/lib/iomgr/pollset_windows.cc \
+    src/core/lib/iomgr/resolve_address.cc \
+    src/core/lib/iomgr/resolve_address_custom.cc \
     src/core/lib/iomgr/resolve_address_posix.cc \
-    src/core/lib/iomgr/resolve_address_uv.cc \
     src/core/lib/iomgr/resolve_address_windows.cc \
     src/core/lib/iomgr/resource_quota.cc \
     src/core/lib/iomgr/sockaddr_utils.cc \
@@ -3755,19 +4127,24 @@
     src/core/lib/iomgr/socket_utils_uv.cc \
     src/core/lib/iomgr/socket_utils_windows.cc \
     src/core/lib/iomgr/socket_windows.cc \
+    src/core/lib/iomgr/tcp_client.cc \
+    src/core/lib/iomgr/tcp_client_custom.cc \
     src/core/lib/iomgr/tcp_client_posix.cc \
-    src/core/lib/iomgr/tcp_client_uv.cc \
     src/core/lib/iomgr/tcp_client_windows.cc \
+    src/core/lib/iomgr/tcp_custom.cc \
     src/core/lib/iomgr/tcp_posix.cc \
+    src/core/lib/iomgr/tcp_server.cc \
+    src/core/lib/iomgr/tcp_server_custom.cc \
     src/core/lib/iomgr/tcp_server_posix.cc \
     src/core/lib/iomgr/tcp_server_utils_posix_common.cc \
     src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc \
     src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc \
-    src/core/lib/iomgr/tcp_server_uv.cc \
     src/core/lib/iomgr/tcp_server_windows.cc \
     src/core/lib/iomgr/tcp_uv.cc \
     src/core/lib/iomgr/tcp_windows.cc \
     src/core/lib/iomgr/time_averaged_stats.cc \
+    src/core/lib/iomgr/timer.cc \
+    src/core/lib/iomgr/timer_custom.cc \
     src/core/lib/iomgr/timer_generic.cc \
     src/core/lib/iomgr/timer_heap.cc \
     src/core/lib/iomgr/timer_manager.cc \
@@ -3788,7 +4165,6 @@
     src/core/lib/slice/percent_encoding.cc \
     src/core/lib/slice/slice.cc \
     src/core/lib/slice/slice_buffer.cc \
-    src/core/lib/slice/slice_hash_table.cc \
     src/core/lib/slice/slice_intern.cc \
     src/core/lib/slice/slice_string_helpers.cc \
     src/core/lib/surface/api_trace.cc \
@@ -3819,6 +4195,7 @@
     src/core/lib/transport/service_config.cc \
     src/core/lib/transport/static_metadata.cc \
     src/core/lib/transport/status_conversion.cc \
+    src/core/lib/transport/status_metadata.cc \
     src/core/lib/transport/timeout_encoding.cc \
     src/core/lib/transport/transport.cc \
     src/core/lib/transport/transport_op_string.cc \
@@ -3834,11 +4211,11 @@
     src/core/ext/filters/client_channel/lb_policy.cc \
     src/core/ext/filters/client_channel/lb_policy_factory.cc \
     src/core/ext/filters/client_channel/lb_policy_registry.cc \
+    src/core/ext/filters/client_channel/method_params.cc \
     src/core/ext/filters/client_channel/parse_address.cc \
     src/core/ext/filters/client_channel/proxy_mapper.cc \
     src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
     src/core/ext/filters/client_channel/resolver.cc \
-    src/core/ext/filters/client_channel/resolver_factory.cc \
     src/core/ext/filters/client_channel/resolver_registry.cc \
     src/core/ext/filters/client_channel/retry_throttle.cc \
     src/core/ext/filters/client_channel/subchannel.cc \
@@ -3874,14 +4251,23 @@
     src/core/ext/filters/http/server/http_server_filter.cc \
 
 PUBLIC_HEADERS_C += \
-    include/grpc/impl/codegen/byte_buffer.h \
-    include/grpc/impl/codegen/byte_buffer_reader.h \
-    include/grpc/impl/codegen/compression_types.h \
-    include/grpc/impl/codegen/connectivity_state.h \
-    include/grpc/impl/codegen/grpc_types.h \
-    include/grpc/impl/codegen/propagation_bits.h \
-    include/grpc/impl/codegen/slice.h \
-    include/grpc/impl/codegen/status.h \
+    include/grpc/support/alloc.h \
+    include/grpc/support/atm.h \
+    include/grpc/support/atm_gcc_atomic.h \
+    include/grpc/support/atm_gcc_sync.h \
+    include/grpc/support/atm_windows.h \
+    include/grpc/support/cpu.h \
+    include/grpc/support/log.h \
+    include/grpc/support/log_windows.h \
+    include/grpc/support/port_platform.h \
+    include/grpc/support/string_util.h \
+    include/grpc/support/sync.h \
+    include/grpc/support/sync_custom.h \
+    include/grpc/support/sync_generic.h \
+    include/grpc/support/sync_posix.h \
+    include/grpc/support/sync_windows.h \
+    include/grpc/support/thd_id.h \
+    include/grpc/support/time.h \
     include/grpc/impl/codegen/atm.h \
     include/grpc/impl/codegen/atm_gcc_atomic.h \
     include/grpc/impl/codegen/atm_gcc_sync.h \
@@ -3895,6 +4281,14 @@
     include/grpc/impl/codegen/sync_generic.h \
     include/grpc/impl/codegen/sync_posix.h \
     include/grpc/impl/codegen/sync_windows.h \
+    include/grpc/impl/codegen/byte_buffer.h \
+    include/grpc/impl/codegen/byte_buffer_reader.h \
+    include/grpc/impl/codegen/compression_types.h \
+    include/grpc/impl/codegen/connectivity_state.h \
+    include/grpc/impl/codegen/grpc_types.h \
+    include/grpc/impl/codegen/propagation_bits.h \
+    include/grpc/impl/codegen/slice.h \
+    include/grpc/impl/codegen/status.h \
 
 LIBGRPC_TEST_UTIL_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_TEST_UTIL_SRC))))
 
@@ -3909,7 +4303,7 @@
 else
 
 
-$(LIBDIR)/$(CONFIG)/libgrpc_test_util.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(LIBGRPC_TEST_UTIL_OBJS) 
+$(LIBDIR)/$(CONFIG)/libgrpc_test_util.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(LIBGRPC_TEST_UTIL_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a
@@ -3947,19 +4341,25 @@
     test/core/util/port_isolated_runtime_environment.cc \
     test/core/util/port_server_client.cc \
     test/core/util/slice_splitter.cc \
+    test/core/util/subprocess_posix.cc \
+    test/core/util/subprocess_windows.cc \
     test/core/util/tracer_util.cc \
     test/core/util/trickle_endpoint.cc \
+    test/core/util/cmdline.cc \
+    src/core/lib/avl/avl.cc \
     src/core/lib/backoff/backoff.cc \
     src/core/lib/channel/channel_args.cc \
     src/core/lib/channel/channel_stack.cc \
     src/core/lib/channel/channel_stack_builder.cc \
+    src/core/lib/channel/channel_trace.cc \
+    src/core/lib/channel/channel_trace_registry.cc \
     src/core/lib/channel/connected_channel.cc \
     src/core/lib/channel/handshaker.cc \
     src/core/lib/channel/handshaker_factory.cc \
     src/core/lib/channel/handshaker_registry.cc \
+    src/core/lib/channel/status_util.cc \
     src/core/lib/compression/compression.cc \
     src/core/lib/compression/compression_internal.cc \
-    src/core/lib/compression/compression_ruby.cc \
     src/core/lib/compression/message_compress.cc \
     src/core/lib/compression/stream_compression.cc \
     src/core/lib/compression/stream_compression_gzip.cc \
@@ -3991,6 +4391,8 @@
     src/core/lib/iomgr/gethostname_sysconf.cc \
     src/core/lib/iomgr/iocp_windows.cc \
     src/core/lib/iomgr/iomgr.cc \
+    src/core/lib/iomgr/iomgr_custom.cc \
+    src/core/lib/iomgr/iomgr_internal.cc \
     src/core/lib/iomgr/iomgr_posix.cc \
     src/core/lib/iomgr/iomgr_uv.cc \
     src/core/lib/iomgr/iomgr_windows.cc \
@@ -3999,12 +4401,16 @@
     src/core/lib/iomgr/lockfree_event.cc \
     src/core/lib/iomgr/network_status_tracker.cc \
     src/core/lib/iomgr/polling_entity.cc \
-    src/core/lib/iomgr/pollset_set_uv.cc \
+    src/core/lib/iomgr/pollset.cc \
+    src/core/lib/iomgr/pollset_custom.cc \
+    src/core/lib/iomgr/pollset_set.cc \
+    src/core/lib/iomgr/pollset_set_custom.cc \
     src/core/lib/iomgr/pollset_set_windows.cc \
     src/core/lib/iomgr/pollset_uv.cc \
     src/core/lib/iomgr/pollset_windows.cc \
+    src/core/lib/iomgr/resolve_address.cc \
+    src/core/lib/iomgr/resolve_address_custom.cc \
     src/core/lib/iomgr/resolve_address_posix.cc \
-    src/core/lib/iomgr/resolve_address_uv.cc \
     src/core/lib/iomgr/resolve_address_windows.cc \
     src/core/lib/iomgr/resource_quota.cc \
     src/core/lib/iomgr/sockaddr_utils.cc \
@@ -4016,19 +4422,24 @@
     src/core/lib/iomgr/socket_utils_uv.cc \
     src/core/lib/iomgr/socket_utils_windows.cc \
     src/core/lib/iomgr/socket_windows.cc \
+    src/core/lib/iomgr/tcp_client.cc \
+    src/core/lib/iomgr/tcp_client_custom.cc \
     src/core/lib/iomgr/tcp_client_posix.cc \
-    src/core/lib/iomgr/tcp_client_uv.cc \
     src/core/lib/iomgr/tcp_client_windows.cc \
+    src/core/lib/iomgr/tcp_custom.cc \
     src/core/lib/iomgr/tcp_posix.cc \
+    src/core/lib/iomgr/tcp_server.cc \
+    src/core/lib/iomgr/tcp_server_custom.cc \
     src/core/lib/iomgr/tcp_server_posix.cc \
     src/core/lib/iomgr/tcp_server_utils_posix_common.cc \
     src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc \
     src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc \
-    src/core/lib/iomgr/tcp_server_uv.cc \
     src/core/lib/iomgr/tcp_server_windows.cc \
     src/core/lib/iomgr/tcp_uv.cc \
     src/core/lib/iomgr/tcp_windows.cc \
     src/core/lib/iomgr/time_averaged_stats.cc \
+    src/core/lib/iomgr/timer.cc \
+    src/core/lib/iomgr/timer_custom.cc \
     src/core/lib/iomgr/timer_generic.cc \
     src/core/lib/iomgr/timer_heap.cc \
     src/core/lib/iomgr/timer_manager.cc \
@@ -4049,7 +4460,6 @@
     src/core/lib/slice/percent_encoding.cc \
     src/core/lib/slice/slice.cc \
     src/core/lib/slice/slice_buffer.cc \
-    src/core/lib/slice/slice_hash_table.cc \
     src/core/lib/slice/slice_intern.cc \
     src/core/lib/slice/slice_string_helpers.cc \
     src/core/lib/surface/api_trace.cc \
@@ -4080,6 +4490,7 @@
     src/core/lib/transport/service_config.cc \
     src/core/lib/transport/static_metadata.cc \
     src/core/lib/transport/status_conversion.cc \
+    src/core/lib/transport/status_metadata.cc \
     src/core/lib/transport/timeout_encoding.cc \
     src/core/lib/transport/transport.cc \
     src/core/lib/transport/transport_op_string.cc \
@@ -4095,11 +4506,11 @@
     src/core/ext/filters/client_channel/lb_policy.cc \
     src/core/ext/filters/client_channel/lb_policy_factory.cc \
     src/core/ext/filters/client_channel/lb_policy_registry.cc \
+    src/core/ext/filters/client_channel/method_params.cc \
     src/core/ext/filters/client_channel/parse_address.cc \
     src/core/ext/filters/client_channel/proxy_mapper.cc \
     src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
     src/core/ext/filters/client_channel/resolver.cc \
-    src/core/ext/filters/client_channel/resolver_factory.cc \
     src/core/ext/filters/client_channel/resolver_registry.cc \
     src/core/ext/filters/client_channel/retry_throttle.cc \
     src/core/ext/filters/client_channel/subchannel.cc \
@@ -4135,14 +4546,23 @@
     src/core/ext/filters/http/server/http_server_filter.cc \
 
 PUBLIC_HEADERS_C += \
-    include/grpc/impl/codegen/byte_buffer.h \
-    include/grpc/impl/codegen/byte_buffer_reader.h \
-    include/grpc/impl/codegen/compression_types.h \
-    include/grpc/impl/codegen/connectivity_state.h \
-    include/grpc/impl/codegen/grpc_types.h \
-    include/grpc/impl/codegen/propagation_bits.h \
-    include/grpc/impl/codegen/slice.h \
-    include/grpc/impl/codegen/status.h \
+    include/grpc/support/alloc.h \
+    include/grpc/support/atm.h \
+    include/grpc/support/atm_gcc_atomic.h \
+    include/grpc/support/atm_gcc_sync.h \
+    include/grpc/support/atm_windows.h \
+    include/grpc/support/cpu.h \
+    include/grpc/support/log.h \
+    include/grpc/support/log_windows.h \
+    include/grpc/support/port_platform.h \
+    include/grpc/support/string_util.h \
+    include/grpc/support/sync.h \
+    include/grpc/support/sync_custom.h \
+    include/grpc/support/sync_generic.h \
+    include/grpc/support/sync_posix.h \
+    include/grpc/support/sync_windows.h \
+    include/grpc/support/thd_id.h \
+    include/grpc/support/time.h \
     include/grpc/impl/codegen/atm.h \
     include/grpc/impl/codegen/atm_gcc_atomic.h \
     include/grpc/impl/codegen/atm_gcc_sync.h \
@@ -4156,11 +4576,19 @@
     include/grpc/impl/codegen/sync_generic.h \
     include/grpc/impl/codegen/sync_posix.h \
     include/grpc/impl/codegen/sync_windows.h \
+    include/grpc/impl/codegen/byte_buffer.h \
+    include/grpc/impl/codegen/byte_buffer_reader.h \
+    include/grpc/impl/codegen/compression_types.h \
+    include/grpc/impl/codegen/connectivity_state.h \
+    include/grpc/impl/codegen/grpc_types.h \
+    include/grpc/impl/codegen/propagation_bits.h \
+    include/grpc/impl/codegen/slice.h \
+    include/grpc/impl/codegen/status.h \
 
 LIBGRPC_TEST_UTIL_UNSECURE_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_TEST_UTIL_UNSECURE_SRC))))
 
 
-$(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a: $(ZLIB_DEP) $(CARES_DEP)  $(LIBGRPC_TEST_UTIL_UNSECURE_OBJS) 
+$(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(LIBGRPC_TEST_UTIL_UNSECURE_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a
@@ -4180,17 +4608,20 @@
 LIBGRPC_UNSECURE_SRC = \
     src/core/lib/surface/init.cc \
     src/core/lib/surface/init_unsecure.cc \
+    src/core/lib/avl/avl.cc \
     src/core/lib/backoff/backoff.cc \
     src/core/lib/channel/channel_args.cc \
     src/core/lib/channel/channel_stack.cc \
     src/core/lib/channel/channel_stack_builder.cc \
+    src/core/lib/channel/channel_trace.cc \
+    src/core/lib/channel/channel_trace_registry.cc \
     src/core/lib/channel/connected_channel.cc \
     src/core/lib/channel/handshaker.cc \
     src/core/lib/channel/handshaker_factory.cc \
     src/core/lib/channel/handshaker_registry.cc \
+    src/core/lib/channel/status_util.cc \
     src/core/lib/compression/compression.cc \
     src/core/lib/compression/compression_internal.cc \
-    src/core/lib/compression/compression_ruby.cc \
     src/core/lib/compression/message_compress.cc \
     src/core/lib/compression/stream_compression.cc \
     src/core/lib/compression/stream_compression_gzip.cc \
@@ -4222,6 +4653,8 @@
     src/core/lib/iomgr/gethostname_sysconf.cc \
     src/core/lib/iomgr/iocp_windows.cc \
     src/core/lib/iomgr/iomgr.cc \
+    src/core/lib/iomgr/iomgr_custom.cc \
+    src/core/lib/iomgr/iomgr_internal.cc \
     src/core/lib/iomgr/iomgr_posix.cc \
     src/core/lib/iomgr/iomgr_uv.cc \
     src/core/lib/iomgr/iomgr_windows.cc \
@@ -4230,12 +4663,16 @@
     src/core/lib/iomgr/lockfree_event.cc \
     src/core/lib/iomgr/network_status_tracker.cc \
     src/core/lib/iomgr/polling_entity.cc \
-    src/core/lib/iomgr/pollset_set_uv.cc \
+    src/core/lib/iomgr/pollset.cc \
+    src/core/lib/iomgr/pollset_custom.cc \
+    src/core/lib/iomgr/pollset_set.cc \
+    src/core/lib/iomgr/pollset_set_custom.cc \
     src/core/lib/iomgr/pollset_set_windows.cc \
     src/core/lib/iomgr/pollset_uv.cc \
     src/core/lib/iomgr/pollset_windows.cc \
+    src/core/lib/iomgr/resolve_address.cc \
+    src/core/lib/iomgr/resolve_address_custom.cc \
     src/core/lib/iomgr/resolve_address_posix.cc \
-    src/core/lib/iomgr/resolve_address_uv.cc \
     src/core/lib/iomgr/resolve_address_windows.cc \
     src/core/lib/iomgr/resource_quota.cc \
     src/core/lib/iomgr/sockaddr_utils.cc \
@@ -4247,19 +4684,24 @@
     src/core/lib/iomgr/socket_utils_uv.cc \
     src/core/lib/iomgr/socket_utils_windows.cc \
     src/core/lib/iomgr/socket_windows.cc \
+    src/core/lib/iomgr/tcp_client.cc \
+    src/core/lib/iomgr/tcp_client_custom.cc \
     src/core/lib/iomgr/tcp_client_posix.cc \
-    src/core/lib/iomgr/tcp_client_uv.cc \
     src/core/lib/iomgr/tcp_client_windows.cc \
+    src/core/lib/iomgr/tcp_custom.cc \
     src/core/lib/iomgr/tcp_posix.cc \
+    src/core/lib/iomgr/tcp_server.cc \
+    src/core/lib/iomgr/tcp_server_custom.cc \
     src/core/lib/iomgr/tcp_server_posix.cc \
     src/core/lib/iomgr/tcp_server_utils_posix_common.cc \
     src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc \
     src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc \
-    src/core/lib/iomgr/tcp_server_uv.cc \
     src/core/lib/iomgr/tcp_server_windows.cc \
     src/core/lib/iomgr/tcp_uv.cc \
     src/core/lib/iomgr/tcp_windows.cc \
     src/core/lib/iomgr/time_averaged_stats.cc \
+    src/core/lib/iomgr/timer.cc \
+    src/core/lib/iomgr/timer_custom.cc \
     src/core/lib/iomgr/timer_generic.cc \
     src/core/lib/iomgr/timer_heap.cc \
     src/core/lib/iomgr/timer_manager.cc \
@@ -4280,7 +4722,6 @@
     src/core/lib/slice/percent_encoding.cc \
     src/core/lib/slice/slice.cc \
     src/core/lib/slice/slice_buffer.cc \
-    src/core/lib/slice/slice_hash_table.cc \
     src/core/lib/slice/slice_intern.cc \
     src/core/lib/slice/slice_string_helpers.cc \
     src/core/lib/surface/api_trace.cc \
@@ -4311,6 +4752,7 @@
     src/core/lib/transport/service_config.cc \
     src/core/lib/transport/static_metadata.cc \
     src/core/lib/transport/status_conversion.cc \
+    src/core/lib/transport/status_metadata.cc \
     src/core/lib/transport/timeout_encoding.cc \
     src/core/lib/transport/transport.cc \
     src/core/lib/transport/transport_op_string.cc \
@@ -4359,11 +4801,11 @@
     src/core/ext/filters/client_channel/lb_policy.cc \
     src/core/ext/filters/client_channel/lb_policy_factory.cc \
     src/core/ext/filters/client_channel/lb_policy_registry.cc \
+    src/core/ext/filters/client_channel/method_params.cc \
     src/core/ext/filters/client_channel/parse_address.cc \
     src/core/ext/filters/client_channel/proxy_mapper.cc \
     src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
     src/core/ext/filters/client_channel/resolver.cc \
-    src/core/ext/filters/client_channel/resolver_factory.cc \
     src/core/ext/filters/client_channel/resolver_registry.cc \
     src/core/ext/filters/client_channel/retry_throttle.cc \
     src/core/ext/filters/client_channel/subchannel.cc \
@@ -4425,7 +4867,6 @@
     include/grpc/byte_buffer.h \
     include/grpc/byte_buffer_reader.h \
     include/grpc/compression.h \
-    include/grpc/compression_ruby.h \
     include/grpc/fork.h \
     include/grpc/grpc.h \
     include/grpc/grpc_posix.h \
@@ -4440,11 +4881,11 @@
 LIBGRPC_UNSECURE_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_UNSECURE_SRC))))
 
 
-$(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a: $(ZLIB_DEP) $(CARES_DEP)  $(LIBGRPC_UNSECURE_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS) 
+$(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(LIBGRPC_UNSECURE_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS)  $(ADDRESS_SORTING_MERGE_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a
-	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBGRPC_UNSECURE_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBGRPC_UNSECURE_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS)  $(ADDRESS_SORTING_MERGE_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a
 endif
@@ -4452,18 +4893,18 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_UNSECURE_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a
+$(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_UNSECURE_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
 else
-$(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_UNSECURE_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a
+$(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_UNSECURE_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
 else
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_unsecure.so.6 -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_unsecure.so.6 -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
 	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).so.6
 	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).so
 endif
@@ -4492,7 +4933,7 @@
 else
 
 
-$(LIBDIR)/$(CONFIG)/libreconnect_server.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(LIBRECONNECT_SERVER_OBJS) 
+$(LIBDIR)/$(CONFIG)/libreconnect_server.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(LIBRECONNECT_SERVER_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libreconnect_server.a
@@ -4531,7 +4972,7 @@
 else
 
 
-$(LIBDIR)/$(CONFIG)/libtest_tcp_server.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(LIBTEST_TCP_SERVER_OBJS) 
+$(LIBDIR)/$(CONFIG)/libtest_tcp_server.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(LIBTEST_TCP_SERVER_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a
@@ -4643,32 +5084,68 @@
     include/grpc++/support/stub_options.h \
     include/grpc++/support/sync_stream.h \
     include/grpc++/support/time.h \
+    include/grpcpp/alarm.h \
+    include/grpcpp/channel.h \
+    include/grpcpp/client_context.h \
+    include/grpcpp/completion_queue.h \
+    include/grpcpp/create_channel.h \
+    include/grpcpp/create_channel_posix.h \
+    include/grpcpp/ext/health_check_service_server_builder_option.h \
+    include/grpcpp/generic/async_generic_service.h \
+    include/grpcpp/generic/generic_stub.h \
+    include/grpcpp/grpcpp.h \
+    include/grpcpp/health_check_service_interface.h \
+    include/grpcpp/impl/call.h \
+    include/grpcpp/impl/channel_argument_option.h \
+    include/grpcpp/impl/client_unary_call.h \
+    include/grpcpp/impl/codegen/core_codegen.h \
+    include/grpcpp/impl/grpc_library.h \
+    include/grpcpp/impl/method_handler_impl.h \
+    include/grpcpp/impl/rpc_method.h \
+    include/grpcpp/impl/rpc_service_method.h \
+    include/grpcpp/impl/serialization_traits.h \
+    include/grpcpp/impl/server_builder_option.h \
+    include/grpcpp/impl/server_builder_plugin.h \
+    include/grpcpp/impl/server_initializer.h \
+    include/grpcpp/impl/service_type.h \
+    include/grpcpp/resource_quota.h \
+    include/grpcpp/security/auth_context.h \
+    include/grpcpp/security/auth_metadata_processor.h \
+    include/grpcpp/security/credentials.h \
+    include/grpcpp/security/server_credentials.h \
+    include/grpcpp/server.h \
+    include/grpcpp/server_builder.h \
+    include/grpcpp/server_context.h \
+    include/grpcpp/server_posix.h \
+    include/grpcpp/support/async_stream.h \
+    include/grpcpp/support/async_unary_call.h \
+    include/grpcpp/support/byte_buffer.h \
+    include/grpcpp/support/channel_arguments.h \
+    include/grpcpp/support/config.h \
+    include/grpcpp/support/slice.h \
+    include/grpcpp/support/status.h \
+    include/grpcpp/support/status_code_enum.h \
+    include/grpcpp/support/string_ref.h \
+    include/grpcpp/support/stub_options.h \
+    include/grpcpp/support/sync_stream.h \
+    include/grpcpp/support/time.h \
     include/grpc/support/alloc.h \
     include/grpc/support/atm.h \
     include/grpc/support/atm_gcc_atomic.h \
     include/grpc/support/atm_gcc_sync.h \
     include/grpc/support/atm_windows.h \
-    include/grpc/support/avl.h \
-    include/grpc/support/cmdline.h \
     include/grpc/support/cpu.h \
-    include/grpc/support/host_port.h \
     include/grpc/support/log.h \
     include/grpc/support/log_windows.h \
     include/grpc/support/port_platform.h \
     include/grpc/support/string_util.h \
-    include/grpc/support/subprocess.h \
     include/grpc/support/sync.h \
     include/grpc/support/sync_custom.h \
     include/grpc/support/sync_generic.h \
     include/grpc/support/sync_posix.h \
     include/grpc/support/sync_windows.h \
-    include/grpc/support/thd.h \
+    include/grpc/support/thd_id.h \
     include/grpc/support/time.h \
-    include/grpc/support/tls.h \
-    include/grpc/support/tls_gcc.h \
-    include/grpc/support/tls_msvc.h \
-    include/grpc/support/tls_pthread.h \
-    include/grpc/support/useful.h \
     include/grpc/impl/codegen/atm.h \
     include/grpc/impl/codegen/atm_gcc_atomic.h \
     include/grpc/impl/codegen/atm_gcc_sync.h \
@@ -4685,7 +5162,6 @@
     include/grpc/byte_buffer.h \
     include/grpc/byte_buffer_reader.h \
     include/grpc/compression.h \
-    include/grpc/compression_ruby.h \
     include/grpc/fork.h \
     include/grpc/grpc.h \
     include/grpc/grpc_posix.h \
@@ -4733,8 +5209,40 @@
     include/grpc++/impl/codegen/stub_options.h \
     include/grpc++/impl/codegen/sync_stream.h \
     include/grpc++/impl/codegen/time.h \
+    include/grpcpp/impl/codegen/async_stream.h \
+    include/grpcpp/impl/codegen/async_unary_call.h \
+    include/grpcpp/impl/codegen/byte_buffer.h \
+    include/grpcpp/impl/codegen/call.h \
+    include/grpcpp/impl/codegen/call_hook.h \
+    include/grpcpp/impl/codegen/channel_interface.h \
+    include/grpcpp/impl/codegen/client_context.h \
+    include/grpcpp/impl/codegen/client_unary_call.h \
+    include/grpcpp/impl/codegen/completion_queue.h \
+    include/grpcpp/impl/codegen/completion_queue_tag.h \
+    include/grpcpp/impl/codegen/config.h \
+    include/grpcpp/impl/codegen/core_codegen_interface.h \
+    include/grpcpp/impl/codegen/create_auth_context.h \
+    include/grpcpp/impl/codegen/grpc_library.h \
+    include/grpcpp/impl/codegen/metadata_map.h \
+    include/grpcpp/impl/codegen/method_handler_impl.h \
+    include/grpcpp/impl/codegen/rpc_method.h \
+    include/grpcpp/impl/codegen/rpc_service_method.h \
+    include/grpcpp/impl/codegen/security/auth_context.h \
+    include/grpcpp/impl/codegen/serialization_traits.h \
+    include/grpcpp/impl/codegen/server_context.h \
+    include/grpcpp/impl/codegen/server_interface.h \
+    include/grpcpp/impl/codegen/service_type.h \
+    include/grpcpp/impl/codegen/slice.h \
+    include/grpcpp/impl/codegen/status.h \
+    include/grpcpp/impl/codegen/status_code_enum.h \
+    include/grpcpp/impl/codegen/string_ref.h \
+    include/grpcpp/impl/codegen/stub_options.h \
+    include/grpcpp/impl/codegen/sync_stream.h \
+    include/grpcpp/impl/codegen/time.h \
     include/grpc++/impl/codegen/proto_utils.h \
+    include/grpcpp/impl/codegen/proto_utils.h \
     include/grpc++/impl/codegen/config_protobuf.h \
+    include/grpcpp/impl/codegen/config_protobuf.h \
 
 LIBGRPC++_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_SRC))))
 
@@ -4759,11 +5267,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libgrpc++.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS) 
+$(LIBDIR)/$(CONFIG)/libgrpc++.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS)  $(ADDRESS_SORTING_MERGE_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++.a
-	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBGRPC++_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBGRPC++_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS)  $(ADDRESS_SORTING_MERGE_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc++.a
 endif
@@ -4771,18 +5279,18 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc$(SHARED_VERSION_CORE)-dll -lgpr$(SHARED_VERSION_CORE)-dll
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc$(SHARED_VERSION_CORE)-dll -lgpr$(SHARED_VERSION_CORE)-dll
 else
-$(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT_CORE) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT_CORE) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc -lgpr
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc -lgpr
 else
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc -lgpr
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc -lgpr
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).so.1
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).so
 endif
@@ -4826,7 +5334,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_CORE_STATS_OBJS) 
+$(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_CORE_STATS_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a
@@ -4915,17 +5423,20 @@
     src/core/ext/transport/chttp2/transport/stream_map.cc \
     src/core/ext/transport/chttp2/transport/varint.cc \
     src/core/ext/transport/chttp2/transport/writing.cc \
+    src/core/lib/avl/avl.cc \
     src/core/lib/backoff/backoff.cc \
     src/core/lib/channel/channel_args.cc \
     src/core/lib/channel/channel_stack.cc \
     src/core/lib/channel/channel_stack_builder.cc \
+    src/core/lib/channel/channel_trace.cc \
+    src/core/lib/channel/channel_trace_registry.cc \
     src/core/lib/channel/connected_channel.cc \
     src/core/lib/channel/handshaker.cc \
     src/core/lib/channel/handshaker_factory.cc \
     src/core/lib/channel/handshaker_registry.cc \
+    src/core/lib/channel/status_util.cc \
     src/core/lib/compression/compression.cc \
     src/core/lib/compression/compression_internal.cc \
-    src/core/lib/compression/compression_ruby.cc \
     src/core/lib/compression/message_compress.cc \
     src/core/lib/compression/stream_compression.cc \
     src/core/lib/compression/stream_compression_gzip.cc \
@@ -4957,6 +5468,8 @@
     src/core/lib/iomgr/gethostname_sysconf.cc \
     src/core/lib/iomgr/iocp_windows.cc \
     src/core/lib/iomgr/iomgr.cc \
+    src/core/lib/iomgr/iomgr_custom.cc \
+    src/core/lib/iomgr/iomgr_internal.cc \
     src/core/lib/iomgr/iomgr_posix.cc \
     src/core/lib/iomgr/iomgr_uv.cc \
     src/core/lib/iomgr/iomgr_windows.cc \
@@ -4965,12 +5478,16 @@
     src/core/lib/iomgr/lockfree_event.cc \
     src/core/lib/iomgr/network_status_tracker.cc \
     src/core/lib/iomgr/polling_entity.cc \
-    src/core/lib/iomgr/pollset_set_uv.cc \
+    src/core/lib/iomgr/pollset.cc \
+    src/core/lib/iomgr/pollset_custom.cc \
+    src/core/lib/iomgr/pollset_set.cc \
+    src/core/lib/iomgr/pollset_set_custom.cc \
     src/core/lib/iomgr/pollset_set_windows.cc \
     src/core/lib/iomgr/pollset_uv.cc \
     src/core/lib/iomgr/pollset_windows.cc \
+    src/core/lib/iomgr/resolve_address.cc \
+    src/core/lib/iomgr/resolve_address_custom.cc \
     src/core/lib/iomgr/resolve_address_posix.cc \
-    src/core/lib/iomgr/resolve_address_uv.cc \
     src/core/lib/iomgr/resolve_address_windows.cc \
     src/core/lib/iomgr/resource_quota.cc \
     src/core/lib/iomgr/sockaddr_utils.cc \
@@ -4982,19 +5499,24 @@
     src/core/lib/iomgr/socket_utils_uv.cc \
     src/core/lib/iomgr/socket_utils_windows.cc \
     src/core/lib/iomgr/socket_windows.cc \
+    src/core/lib/iomgr/tcp_client.cc \
+    src/core/lib/iomgr/tcp_client_custom.cc \
     src/core/lib/iomgr/tcp_client_posix.cc \
-    src/core/lib/iomgr/tcp_client_uv.cc \
     src/core/lib/iomgr/tcp_client_windows.cc \
+    src/core/lib/iomgr/tcp_custom.cc \
     src/core/lib/iomgr/tcp_posix.cc \
+    src/core/lib/iomgr/tcp_server.cc \
+    src/core/lib/iomgr/tcp_server_custom.cc \
     src/core/lib/iomgr/tcp_server_posix.cc \
     src/core/lib/iomgr/tcp_server_utils_posix_common.cc \
     src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc \
     src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc \
-    src/core/lib/iomgr/tcp_server_uv.cc \
     src/core/lib/iomgr/tcp_server_windows.cc \
     src/core/lib/iomgr/tcp_uv.cc \
     src/core/lib/iomgr/tcp_windows.cc \
     src/core/lib/iomgr/time_averaged_stats.cc \
+    src/core/lib/iomgr/timer.cc \
+    src/core/lib/iomgr/timer_custom.cc \
     src/core/lib/iomgr/timer_generic.cc \
     src/core/lib/iomgr/timer_heap.cc \
     src/core/lib/iomgr/timer_manager.cc \
@@ -5015,7 +5537,6 @@
     src/core/lib/slice/percent_encoding.cc \
     src/core/lib/slice/slice.cc \
     src/core/lib/slice/slice_buffer.cc \
-    src/core/lib/slice/slice_hash_table.cc \
     src/core/lib/slice/slice_intern.cc \
     src/core/lib/slice/slice_string_helpers.cc \
     src/core/lib/surface/api_trace.cc \
@@ -5046,6 +5567,7 @@
     src/core/lib/transport/service_config.cc \
     src/core/lib/transport/static_metadata.cc \
     src/core/lib/transport/status_conversion.cc \
+    src/core/lib/transport/status_metadata.cc \
     src/core/lib/transport/timeout_encoding.cc \
     src/core/lib/transport/transport.cc \
     src/core/lib/transport/transport_op_string.cc \
@@ -5066,11 +5588,11 @@
     src/core/ext/filters/client_channel/lb_policy.cc \
     src/core/ext/filters/client_channel/lb_policy_factory.cc \
     src/core/ext/filters/client_channel/lb_policy_registry.cc \
+    src/core/ext/filters/client_channel/method_params.cc \
     src/core/ext/filters/client_channel/parse_address.cc \
     src/core/ext/filters/client_channel/proxy_mapper.cc \
     src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
     src/core/ext/filters/client_channel/resolver.cc \
-    src/core/ext/filters/client_channel/resolver_factory.cc \
     src/core/ext/filters/client_channel/resolver_registry.cc \
     src/core/ext/filters/client_channel/retry_throttle.cc \
     src/core/ext/filters/client_channel/subchannel.cc \
@@ -5131,32 +5653,68 @@
     include/grpc++/support/stub_options.h \
     include/grpc++/support/sync_stream.h \
     include/grpc++/support/time.h \
+    include/grpcpp/alarm.h \
+    include/grpcpp/channel.h \
+    include/grpcpp/client_context.h \
+    include/grpcpp/completion_queue.h \
+    include/grpcpp/create_channel.h \
+    include/grpcpp/create_channel_posix.h \
+    include/grpcpp/ext/health_check_service_server_builder_option.h \
+    include/grpcpp/generic/async_generic_service.h \
+    include/grpcpp/generic/generic_stub.h \
+    include/grpcpp/grpcpp.h \
+    include/grpcpp/health_check_service_interface.h \
+    include/grpcpp/impl/call.h \
+    include/grpcpp/impl/channel_argument_option.h \
+    include/grpcpp/impl/client_unary_call.h \
+    include/grpcpp/impl/codegen/core_codegen.h \
+    include/grpcpp/impl/grpc_library.h \
+    include/grpcpp/impl/method_handler_impl.h \
+    include/grpcpp/impl/rpc_method.h \
+    include/grpcpp/impl/rpc_service_method.h \
+    include/grpcpp/impl/serialization_traits.h \
+    include/grpcpp/impl/server_builder_option.h \
+    include/grpcpp/impl/server_builder_plugin.h \
+    include/grpcpp/impl/server_initializer.h \
+    include/grpcpp/impl/service_type.h \
+    include/grpcpp/resource_quota.h \
+    include/grpcpp/security/auth_context.h \
+    include/grpcpp/security/auth_metadata_processor.h \
+    include/grpcpp/security/credentials.h \
+    include/grpcpp/security/server_credentials.h \
+    include/grpcpp/server.h \
+    include/grpcpp/server_builder.h \
+    include/grpcpp/server_context.h \
+    include/grpcpp/server_posix.h \
+    include/grpcpp/support/async_stream.h \
+    include/grpcpp/support/async_unary_call.h \
+    include/grpcpp/support/byte_buffer.h \
+    include/grpcpp/support/channel_arguments.h \
+    include/grpcpp/support/config.h \
+    include/grpcpp/support/slice.h \
+    include/grpcpp/support/status.h \
+    include/grpcpp/support/status_code_enum.h \
+    include/grpcpp/support/string_ref.h \
+    include/grpcpp/support/stub_options.h \
+    include/grpcpp/support/sync_stream.h \
+    include/grpcpp/support/time.h \
     include/grpc/support/alloc.h \
     include/grpc/support/atm.h \
     include/grpc/support/atm_gcc_atomic.h \
     include/grpc/support/atm_gcc_sync.h \
     include/grpc/support/atm_windows.h \
-    include/grpc/support/avl.h \
-    include/grpc/support/cmdline.h \
     include/grpc/support/cpu.h \
-    include/grpc/support/host_port.h \
     include/grpc/support/log.h \
     include/grpc/support/log_windows.h \
     include/grpc/support/port_platform.h \
     include/grpc/support/string_util.h \
-    include/grpc/support/subprocess.h \
     include/grpc/support/sync.h \
     include/grpc/support/sync_custom.h \
     include/grpc/support/sync_generic.h \
     include/grpc/support/sync_posix.h \
     include/grpc/support/sync_windows.h \
-    include/grpc/support/thd.h \
+    include/grpc/support/thd_id.h \
     include/grpc/support/time.h \
-    include/grpc/support/tls.h \
-    include/grpc/support/tls_gcc.h \
-    include/grpc/support/tls_msvc.h \
-    include/grpc/support/tls_pthread.h \
-    include/grpc/support/useful.h \
     include/grpc/impl/codegen/atm.h \
     include/grpc/impl/codegen/atm_gcc_atomic.h \
     include/grpc/impl/codegen/atm_gcc_sync.h \
@@ -5173,7 +5731,6 @@
     include/grpc/byte_buffer.h \
     include/grpc/byte_buffer_reader.h \
     include/grpc/compression.h \
-    include/grpc/compression_ruby.h \
     include/grpc/fork.h \
     include/grpc/grpc.h \
     include/grpc/grpc_posix.h \
@@ -5221,6 +5778,36 @@
     include/grpc++/impl/codegen/stub_options.h \
     include/grpc++/impl/codegen/sync_stream.h \
     include/grpc++/impl/codegen/time.h \
+    include/grpcpp/impl/codegen/async_stream.h \
+    include/grpcpp/impl/codegen/async_unary_call.h \
+    include/grpcpp/impl/codegen/byte_buffer.h \
+    include/grpcpp/impl/codegen/call.h \
+    include/grpcpp/impl/codegen/call_hook.h \
+    include/grpcpp/impl/codegen/channel_interface.h \
+    include/grpcpp/impl/codegen/client_context.h \
+    include/grpcpp/impl/codegen/client_unary_call.h \
+    include/grpcpp/impl/codegen/completion_queue.h \
+    include/grpcpp/impl/codegen/completion_queue_tag.h \
+    include/grpcpp/impl/codegen/config.h \
+    include/grpcpp/impl/codegen/core_codegen_interface.h \
+    include/grpcpp/impl/codegen/create_auth_context.h \
+    include/grpcpp/impl/codegen/grpc_library.h \
+    include/grpcpp/impl/codegen/metadata_map.h \
+    include/grpcpp/impl/codegen/method_handler_impl.h \
+    include/grpcpp/impl/codegen/rpc_method.h \
+    include/grpcpp/impl/codegen/rpc_service_method.h \
+    include/grpcpp/impl/codegen/security/auth_context.h \
+    include/grpcpp/impl/codegen/serialization_traits.h \
+    include/grpcpp/impl/codegen/server_context.h \
+    include/grpcpp/impl/codegen/server_interface.h \
+    include/grpcpp/impl/codegen/service_type.h \
+    include/grpcpp/impl/codegen/slice.h \
+    include/grpcpp/impl/codegen/status.h \
+    include/grpcpp/impl/codegen/status_code_enum.h \
+    include/grpcpp/impl/codegen/string_ref.h \
+    include/grpcpp/impl/codegen/stub_options.h \
+    include/grpcpp/impl/codegen/sync_stream.h \
+    include/grpcpp/impl/codegen/time.h \
     include/grpc/census.h \
 
 LIBGRPC++_CRONET_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_CRONET_SRC))))
@@ -5246,11 +5833,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libgrpc++_cronet.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_CRONET_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS)  $(OPENSSL_MERGE_OBJS) 
+$(LIBDIR)/$(CONFIG)/libgrpc++_cronet.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_CRONET_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS)  $(ADDRESS_SORTING_MERGE_OBJS)  $(OPENSSL_MERGE_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_cronet.a
-	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet.a $(LIBGRPC++_CRONET_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS)  $(OPENSSL_MERGE_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet.a $(LIBGRPC++_CRONET_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS)  $(ADDRESS_SORTING_MERGE_OBJS)  $(OPENSSL_MERGE_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc++_cronet.a
 endif
@@ -5258,18 +5845,18 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_CRONET_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_CRONET_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_cronet$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_CRONET_OBJS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgpr$(SHARED_VERSION_CORE)-dll -lgrpc_cronet$(SHARED_VERSION_CORE)-dll -lgrpc$(SHARED_VERSION_CORE)-dll
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_cronet$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_CRONET_OBJS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgpr$(SHARED_VERSION_CORE)-dll -lgrpc_cronet$(SHARED_VERSION_CORE)-dll -lgrpc$(SHARED_VERSION_CORE)-dll
 else
-$(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_CRONET_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_cronet.$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT_CORE) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_CRONET_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_cronet.$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT_CORE) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_CRONET_OBJS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgpr -lgrpc_cronet -lgrpc
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_CRONET_OBJS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgpr -lgrpc_cronet -lgrpc
 else
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_cronet.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_CRONET_OBJS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgpr -lgrpc_cronet -lgrpc
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_cronet.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_CRONET_OBJS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgpr -lgrpc_cronet -lgrpc
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).so.1
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).so
 endif
@@ -5292,6 +5879,7 @@
 
 PUBLIC_HEADERS_CXX += \
     include/grpc++/support/error_details.h \
+    include/grpcpp/support/error_details.h \
 
 LIBGRPC++_ERROR_DETAILS_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_ERROR_DETAILS_SRC))))
 
@@ -5316,11 +5904,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libgrpc++_error_details.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_ERROR_DETAILS_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS) 
+$(LIBDIR)/$(CONFIG)/libgrpc++_error_details.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_ERROR_DETAILS_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS)  $(ADDRESS_SORTING_MERGE_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_error_details.a
-	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc++_error_details.a $(LIBGRPC++_ERROR_DETAILS_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc++_error_details.a $(LIBGRPC++_ERROR_DETAILS_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS)  $(ADDRESS_SORTING_MERGE_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc++_error_details.a
 endif
@@ -5328,18 +5916,18 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_ERROR_DETAILS_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_ERROR_DETAILS_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_error_details$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_error_details$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_ERROR_DETAILS_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc++$(SHARED_VERSION_CPP)-dll
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_error_details$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_error_details$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_ERROR_DETAILS_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc++$(SHARED_VERSION_CPP)-dll
 else
-$(LIBDIR)/$(CONFIG)/libgrpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_ERROR_DETAILS_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT_CPP) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/libgrpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_ERROR_DETAILS_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT_CPP) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_ERROR_DETAILS_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc++
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_ERROR_DETAILS_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc++
 else
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_error_details.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_ERROR_DETAILS_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc++
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_error_details.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_ERROR_DETAILS_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc++
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_error_details$(SHARED_VERSION_CPP).so.1
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_error_details$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_error_details$(SHARED_VERSION_CPP).so
 endif
@@ -5363,6 +5951,7 @@
 
 PUBLIC_HEADERS_CXX += \
     include/grpc++/impl/codegen/config_protobuf.h \
+    include/grpcpp/impl/codegen/config_protobuf.h \
 
 LIBGRPC++_PROTO_REFLECTION_DESC_DB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_PROTO_REFLECTION_DESC_DB_SRC))))
 
@@ -5385,7 +5974,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_PROTO_REFLECTION_DESC_DB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_PROTO_REFLECTION_DESC_DB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a
@@ -5416,6 +6005,7 @@
 
 PUBLIC_HEADERS_CXX += \
     include/grpc++/ext/proto_server_reflection_plugin.h \
+    include/grpcpp/ext/proto_server_reflection_plugin.h \
 
 LIBGRPC++_REFLECTION_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_REFLECTION_SRC))))
 
@@ -5440,7 +6030,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_REFLECTION_OBJS) 
+$(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_REFLECTION_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a
@@ -5452,18 +6042,18 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_REFLECTION_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_REFLECTION_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_reflection$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_REFLECTION_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc++$(SHARED_VERSION_CPP)-dll -lgrpc$(SHARED_VERSION_CORE)-dll
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_reflection$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_REFLECTION_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc++$(SHARED_VERSION_CPP)-dll -lgrpc$(SHARED_VERSION_CORE)-dll
 else
-$(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_REFLECTION_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT_CORE) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_REFLECTION_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT_CORE) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_REFLECTION_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc++ -lgrpc
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_REFLECTION_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc++ -lgrpc
 else
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_reflection.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_REFLECTION_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc++ -lgrpc
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_reflection.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_REFLECTION_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgrpc++ -lgrpc
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).so.1
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).so
 endif
@@ -5508,7 +6098,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_TEST_CONFIG_OBJS) 
+$(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_TEST_CONFIG_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
@@ -5532,12 +6122,14 @@
 
 
 LIBGRPC++_TEST_UTIL_SRC = \
+    $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc \
     $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc \
     $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc \
     $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc \
     $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc \
     test/cpp/end2end/test_service_impl.cc \
     test/cpp/util/byte_buffer_proto_helper.cc \
+    test/cpp/util/channel_trace_proto_helper.cc \
     test/cpp/util/create_test_channel.cc \
     test/cpp/util/string_ref_helper.cc \
     test/cpp/util/subprocess.cc \
@@ -5575,6 +6167,36 @@
     include/grpc++/impl/codegen/stub_options.h \
     include/grpc++/impl/codegen/sync_stream.h \
     include/grpc++/impl/codegen/time.h \
+    include/grpcpp/impl/codegen/async_stream.h \
+    include/grpcpp/impl/codegen/async_unary_call.h \
+    include/grpcpp/impl/codegen/byte_buffer.h \
+    include/grpcpp/impl/codegen/call.h \
+    include/grpcpp/impl/codegen/call_hook.h \
+    include/grpcpp/impl/codegen/channel_interface.h \
+    include/grpcpp/impl/codegen/client_context.h \
+    include/grpcpp/impl/codegen/client_unary_call.h \
+    include/grpcpp/impl/codegen/completion_queue.h \
+    include/grpcpp/impl/codegen/completion_queue_tag.h \
+    include/grpcpp/impl/codegen/config.h \
+    include/grpcpp/impl/codegen/core_codegen_interface.h \
+    include/grpcpp/impl/codegen/create_auth_context.h \
+    include/grpcpp/impl/codegen/grpc_library.h \
+    include/grpcpp/impl/codegen/metadata_map.h \
+    include/grpcpp/impl/codegen/method_handler_impl.h \
+    include/grpcpp/impl/codegen/rpc_method.h \
+    include/grpcpp/impl/codegen/rpc_service_method.h \
+    include/grpcpp/impl/codegen/security/auth_context.h \
+    include/grpcpp/impl/codegen/serialization_traits.h \
+    include/grpcpp/impl/codegen/server_context.h \
+    include/grpcpp/impl/codegen/server_interface.h \
+    include/grpcpp/impl/codegen/service_type.h \
+    include/grpcpp/impl/codegen/slice.h \
+    include/grpcpp/impl/codegen/status.h \
+    include/grpcpp/impl/codegen/status_code_enum.h \
+    include/grpcpp/impl/codegen/string_ref.h \
+    include/grpcpp/impl/codegen/stub_options.h \
+    include/grpcpp/impl/codegen/sync_stream.h \
+    include/grpcpp/impl/codegen/time.h \
     include/grpc/impl/codegen/byte_buffer.h \
     include/grpc/impl/codegen/byte_buffer_reader.h \
     include/grpc/impl/codegen/compression_types.h \
@@ -5597,7 +6219,9 @@
     include/grpc/impl/codegen/sync_posix.h \
     include/grpc/impl/codegen/sync_windows.h \
     include/grpc++/impl/codegen/proto_utils.h \
+    include/grpcpp/impl/codegen/proto_utils.h \
     include/grpc++/impl/codegen/config_protobuf.h \
+    include/grpcpp/impl/codegen/config_protobuf.h \
 
 LIBGRPC++_TEST_UTIL_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_TEST_UTIL_SRC))))
 
@@ -5620,7 +6244,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_TEST_UTIL_OBJS) 
+$(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_TEST_UTIL_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a
@@ -5641,13 +6265,14 @@
 -include $(LIBGRPC++_TEST_UTIL_OBJS:.o=.dep)
 endif
 endif
-$(OBJDIR)/$(CONFIG)/test/cpp/end2end/test_service_impl.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/byte_buffer_proto_helper.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/create_test_channel.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/string_ref_helper.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/subprocess.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/test_credentials_provider.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/src/cpp/codegen/codegen_init.o: $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/test_service_impl.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/byte_buffer_proto_helper.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/channel_trace_proto_helper.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/create_test_channel.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/string_ref_helper.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/subprocess.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/test_credentials_provider.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/src/cpp/codegen/codegen_init.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
 
 
 LIBGRPC++_TEST_UTIL_UNSECURE_SRC = \
@@ -5692,6 +6317,36 @@
     include/grpc++/impl/codegen/stub_options.h \
     include/grpc++/impl/codegen/sync_stream.h \
     include/grpc++/impl/codegen/time.h \
+    include/grpcpp/impl/codegen/async_stream.h \
+    include/grpcpp/impl/codegen/async_unary_call.h \
+    include/grpcpp/impl/codegen/byte_buffer.h \
+    include/grpcpp/impl/codegen/call.h \
+    include/grpcpp/impl/codegen/call_hook.h \
+    include/grpcpp/impl/codegen/channel_interface.h \
+    include/grpcpp/impl/codegen/client_context.h \
+    include/grpcpp/impl/codegen/client_unary_call.h \
+    include/grpcpp/impl/codegen/completion_queue.h \
+    include/grpcpp/impl/codegen/completion_queue_tag.h \
+    include/grpcpp/impl/codegen/config.h \
+    include/grpcpp/impl/codegen/core_codegen_interface.h \
+    include/grpcpp/impl/codegen/create_auth_context.h \
+    include/grpcpp/impl/codegen/grpc_library.h \
+    include/grpcpp/impl/codegen/metadata_map.h \
+    include/grpcpp/impl/codegen/method_handler_impl.h \
+    include/grpcpp/impl/codegen/rpc_method.h \
+    include/grpcpp/impl/codegen/rpc_service_method.h \
+    include/grpcpp/impl/codegen/security/auth_context.h \
+    include/grpcpp/impl/codegen/serialization_traits.h \
+    include/grpcpp/impl/codegen/server_context.h \
+    include/grpcpp/impl/codegen/server_interface.h \
+    include/grpcpp/impl/codegen/service_type.h \
+    include/grpcpp/impl/codegen/slice.h \
+    include/grpcpp/impl/codegen/status.h \
+    include/grpcpp/impl/codegen/status_code_enum.h \
+    include/grpcpp/impl/codegen/string_ref.h \
+    include/grpcpp/impl/codegen/stub_options.h \
+    include/grpcpp/impl/codegen/sync_stream.h \
+    include/grpcpp/impl/codegen/time.h \
     include/grpc/impl/codegen/byte_buffer.h \
     include/grpc/impl/codegen/byte_buffer_reader.h \
     include/grpc/impl/codegen/compression_types.h \
@@ -5714,7 +6369,9 @@
     include/grpc/impl/codegen/sync_posix.h \
     include/grpc/impl/codegen/sync_windows.h \
     include/grpc++/impl/codegen/proto_utils.h \
+    include/grpcpp/impl/codegen/proto_utils.h \
     include/grpc++/impl/codegen/config_protobuf.h \
+    include/grpcpp/impl/codegen/config_protobuf.h \
 
 LIBGRPC++_TEST_UTIL_UNSECURE_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_TEST_UTIL_UNSECURE_SRC))))
 
@@ -5737,7 +6394,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_TEST_UTIL_UNSECURE_OBJS) 
+$(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_TEST_UTIL_UNSECURE_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a
@@ -5851,32 +6508,68 @@
     include/grpc++/support/stub_options.h \
     include/grpc++/support/sync_stream.h \
     include/grpc++/support/time.h \
+    include/grpcpp/alarm.h \
+    include/grpcpp/channel.h \
+    include/grpcpp/client_context.h \
+    include/grpcpp/completion_queue.h \
+    include/grpcpp/create_channel.h \
+    include/grpcpp/create_channel_posix.h \
+    include/grpcpp/ext/health_check_service_server_builder_option.h \
+    include/grpcpp/generic/async_generic_service.h \
+    include/grpcpp/generic/generic_stub.h \
+    include/grpcpp/grpcpp.h \
+    include/grpcpp/health_check_service_interface.h \
+    include/grpcpp/impl/call.h \
+    include/grpcpp/impl/channel_argument_option.h \
+    include/grpcpp/impl/client_unary_call.h \
+    include/grpcpp/impl/codegen/core_codegen.h \
+    include/grpcpp/impl/grpc_library.h \
+    include/grpcpp/impl/method_handler_impl.h \
+    include/grpcpp/impl/rpc_method.h \
+    include/grpcpp/impl/rpc_service_method.h \
+    include/grpcpp/impl/serialization_traits.h \
+    include/grpcpp/impl/server_builder_option.h \
+    include/grpcpp/impl/server_builder_plugin.h \
+    include/grpcpp/impl/server_initializer.h \
+    include/grpcpp/impl/service_type.h \
+    include/grpcpp/resource_quota.h \
+    include/grpcpp/security/auth_context.h \
+    include/grpcpp/security/auth_metadata_processor.h \
+    include/grpcpp/security/credentials.h \
+    include/grpcpp/security/server_credentials.h \
+    include/grpcpp/server.h \
+    include/grpcpp/server_builder.h \
+    include/grpcpp/server_context.h \
+    include/grpcpp/server_posix.h \
+    include/grpcpp/support/async_stream.h \
+    include/grpcpp/support/async_unary_call.h \
+    include/grpcpp/support/byte_buffer.h \
+    include/grpcpp/support/channel_arguments.h \
+    include/grpcpp/support/config.h \
+    include/grpcpp/support/slice.h \
+    include/grpcpp/support/status.h \
+    include/grpcpp/support/status_code_enum.h \
+    include/grpcpp/support/string_ref.h \
+    include/grpcpp/support/stub_options.h \
+    include/grpcpp/support/sync_stream.h \
+    include/grpcpp/support/time.h \
     include/grpc/support/alloc.h \
     include/grpc/support/atm.h \
     include/grpc/support/atm_gcc_atomic.h \
     include/grpc/support/atm_gcc_sync.h \
     include/grpc/support/atm_windows.h \
-    include/grpc/support/avl.h \
-    include/grpc/support/cmdline.h \
     include/grpc/support/cpu.h \
-    include/grpc/support/host_port.h \
     include/grpc/support/log.h \
     include/grpc/support/log_windows.h \
     include/grpc/support/port_platform.h \
     include/grpc/support/string_util.h \
-    include/grpc/support/subprocess.h \
     include/grpc/support/sync.h \
     include/grpc/support/sync_custom.h \
     include/grpc/support/sync_generic.h \
     include/grpc/support/sync_posix.h \
     include/grpc/support/sync_windows.h \
-    include/grpc/support/thd.h \
+    include/grpc/support/thd_id.h \
     include/grpc/support/time.h \
-    include/grpc/support/tls.h \
-    include/grpc/support/tls_gcc.h \
-    include/grpc/support/tls_msvc.h \
-    include/grpc/support/tls_pthread.h \
-    include/grpc/support/useful.h \
     include/grpc/impl/codegen/atm.h \
     include/grpc/impl/codegen/atm_gcc_atomic.h \
     include/grpc/impl/codegen/atm_gcc_sync.h \
@@ -5893,7 +6586,6 @@
     include/grpc/byte_buffer.h \
     include/grpc/byte_buffer_reader.h \
     include/grpc/compression.h \
-    include/grpc/compression_ruby.h \
     include/grpc/fork.h \
     include/grpc/grpc.h \
     include/grpc/grpc_posix.h \
@@ -5941,6 +6633,36 @@
     include/grpc++/impl/codegen/stub_options.h \
     include/grpc++/impl/codegen/sync_stream.h \
     include/grpc++/impl/codegen/time.h \
+    include/grpcpp/impl/codegen/async_stream.h \
+    include/grpcpp/impl/codegen/async_unary_call.h \
+    include/grpcpp/impl/codegen/byte_buffer.h \
+    include/grpcpp/impl/codegen/call.h \
+    include/grpcpp/impl/codegen/call_hook.h \
+    include/grpcpp/impl/codegen/channel_interface.h \
+    include/grpcpp/impl/codegen/client_context.h \
+    include/grpcpp/impl/codegen/client_unary_call.h \
+    include/grpcpp/impl/codegen/completion_queue.h \
+    include/grpcpp/impl/codegen/completion_queue_tag.h \
+    include/grpcpp/impl/codegen/config.h \
+    include/grpcpp/impl/codegen/core_codegen_interface.h \
+    include/grpcpp/impl/codegen/create_auth_context.h \
+    include/grpcpp/impl/codegen/grpc_library.h \
+    include/grpcpp/impl/codegen/metadata_map.h \
+    include/grpcpp/impl/codegen/method_handler_impl.h \
+    include/grpcpp/impl/codegen/rpc_method.h \
+    include/grpcpp/impl/codegen/rpc_service_method.h \
+    include/grpcpp/impl/codegen/security/auth_context.h \
+    include/grpcpp/impl/codegen/serialization_traits.h \
+    include/grpcpp/impl/codegen/server_context.h \
+    include/grpcpp/impl/codegen/server_interface.h \
+    include/grpcpp/impl/codegen/service_type.h \
+    include/grpcpp/impl/codegen/slice.h \
+    include/grpcpp/impl/codegen/status.h \
+    include/grpcpp/impl/codegen/status_code_enum.h \
+    include/grpcpp/impl/codegen/string_ref.h \
+    include/grpcpp/impl/codegen/stub_options.h \
+    include/grpcpp/impl/codegen/sync_stream.h \
+    include/grpcpp/impl/codegen/time.h \
 
 LIBGRPC++_UNSECURE_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_UNSECURE_SRC))))
 
@@ -5955,11 +6677,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBGRPC++_UNSECURE_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS) 
+$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBGRPC++_UNSECURE_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS)  $(ADDRESS_SORTING_MERGE_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a
-	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBGRPC++_UNSECURE_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBGRPC++_UNSECURE_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(CARES_MERGE_OBJS)  $(ADDRESS_SORTING_MERGE_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a
 endif
@@ -5967,18 +6689,18 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_UNSECURE_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)
+$(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_UNSECURE_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_UNSECURE_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgpr$(SHARED_VERSION_CORE)-dll -lgrpc_unsecure$(SHARED_VERSION_CORE)-dll
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_UNSECURE_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgpr$(SHARED_VERSION_CORE)-dll -lgrpc_unsecure$(SHARED_VERSION_CORE)-dll
 else
-$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_UNSECURE_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT_CORE)
+$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_UNSECURE_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT_CORE)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_UNSECURE_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgpr -lgrpc_unsecure
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_UNSECURE_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgpr -lgrpc_unsecure
 else
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_unsecure.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_UNSECURE_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgpr -lgrpc_unsecure
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_unsecure.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_UNSECURE_OBJS) $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) -lgpr -lgrpc_unsecure
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).so.1
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).so
 endif
@@ -6018,7 +6740,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBGRPC_BENCHMARK_OBJS) 
+$(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBGRPC_BENCHMARK_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a
@@ -6051,6 +6773,7 @@
 
 PUBLIC_HEADERS_CXX += \
     include/grpc++/impl/codegen/config_protobuf.h \
+    include/grpcpp/impl/codegen/config_protobuf.h \
 
 LIBGRPC_CLI_LIBS_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_CLI_LIBS_SRC))))
 
@@ -6073,7 +6796,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBGRPC_CLI_LIBS_OBJS) 
+$(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBGRPC_CLI_LIBS_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a
@@ -6112,6 +6835,7 @@
 
 PUBLIC_HEADERS_CXX += \
     include/grpc++/impl/codegen/config_protobuf.h \
+    include/grpcpp/impl/codegen/config_protobuf.h \
 
 LIBGRPC_PLUGIN_SUPPORT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_PLUGIN_SUPPORT_SRC))))
 
@@ -6125,7 +6849,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBGRPC_PLUGIN_SUPPORT_OBJS) 
+$(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBGRPC_PLUGIN_SUPPORT_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a
@@ -6173,7 +6897,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libhttp2_client_main.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBHTTP2_CLIENT_MAIN_OBJS) 
+$(LIBDIR)/$(CONFIG)/libhttp2_client_main.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBHTTP2_CLIENT_MAIN_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a
@@ -6224,7 +6948,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libinterop_client_helper.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_CLIENT_HELPER_OBJS) 
+$(LIBDIR)/$(CONFIG)/libinterop_client_helper.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_CLIENT_HELPER_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a
@@ -6278,7 +7002,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libinterop_client_main.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_CLIENT_MAIN_OBJS) 
+$(LIBDIR)/$(CONFIG)/libinterop_client_main.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_CLIENT_MAIN_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libinterop_client_main.a
@@ -6329,7 +7053,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libinterop_server_helper.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_SERVER_HELPER_OBJS) 
+$(LIBDIR)/$(CONFIG)/libinterop_server_helper.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_SERVER_HELPER_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a
@@ -6381,7 +7105,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libinterop_server_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_SERVER_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libinterop_server_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_SERVER_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a
@@ -6431,7 +7155,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libinterop_server_main.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_SERVER_MAIN_OBJS) 
+$(LIBDIR)/$(CONFIG)/libinterop_server_main.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_SERVER_MAIN_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libinterop_server_main.a
@@ -6494,7 +7218,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libqps.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(PROTOBUF_DEP) $(LIBQPS_OBJS) 
+$(LIBDIR)/$(CONFIG)/libqps.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBQPS_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libqps.a
@@ -6546,7 +7270,7 @@
 else
 
 
-$(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(LIBGRPC_CSHARP_EXT_OBJS) 
+$(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(LIBGRPC_CSHARP_EXT_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.a
@@ -6558,18 +7282,18 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP): $(LIBGRPC_CSHARP_EXT_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP): $(LIBGRPC_CSHARP_EXT_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_csharp_ext$(SHARED_VERSION_CSHARP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBGRPC_CSHARP_EXT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
+	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_csharp_ext$(SHARED_VERSION_CSHARP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBGRPC_CSHARP_EXT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
 else
-$(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP): $(LIBGRPC_CSHARP_EXT_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP): $(LIBGRPC_CSHARP_EXT_OBJS)  $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBGRPC_CSHARP_EXT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
+	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBGRPC_CSHARP_EXT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
 else
-	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_csharp_ext.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBGRPC_CSHARP_EXT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(LDLIBS)
+	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_csharp_ext.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBGRPC_CSHARP_EXT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS) $(LDLIBS)
 	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).so.1
 	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).so
 endif
@@ -6654,7 +7378,6 @@
     third_party/boringssl/crypto/cpu-intel.c \
     third_party/boringssl/crypto/cpu-ppc64le.c \
     third_party/boringssl/crypto/crypto.c \
-    third_party/boringssl/crypto/curve25519/curve25519.c \
     third_party/boringssl/crypto/curve25519/spake25519.c \
     third_party/boringssl/crypto/curve25519/x25519-x86_64.c \
     third_party/boringssl/crypto/dh/check.c \
@@ -6840,6 +7563,7 @@
     third_party/boringssl/ssl/tls13_server.cc \
     third_party/boringssl/ssl/tls_method.cc \
     third_party/boringssl/ssl/tls_record.cc \
+    third_party/boringssl/third_party/fiat/curve25519.c \
 
 PUBLIC_HEADERS_C += \
 
@@ -6849,7 +7573,7 @@
 $(LIBBORINGSSL_OBJS): CXXFLAGS += -fno-rtti -fno-exceptions
 $(LIBBORINGSSL_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare -Wno-implicit-fallthrough $(NO_W_EXTRA_SEMI)
 
-$(LIBDIR)/$(CONFIG)/libboringssl.a: $(ZLIB_DEP) $(CARES_DEP)  $(LIBBORINGSSL_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(LIBBORINGSSL_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl.a
@@ -6888,7 +7612,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_test_util.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_TEST_UTIL_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_test_util.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_TEST_UTIL_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a
@@ -6927,7 +7651,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_crypto_test_data_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_CRYPTO_TEST_DATA_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_crypto_test_data_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_CRYPTO_TEST_DATA_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_crypto_test_data_lib.a
@@ -6966,7 +7690,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_ASN1_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_ASN1_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a
@@ -7005,7 +7729,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_BASE64_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_BASE64_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a
@@ -7044,7 +7768,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_BIO_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_BIO_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a
@@ -7063,6 +7787,45 @@
 endif
 
 
+LIBBORINGSSL_BUF_TEST_LIB_SRC = \
+    third_party/boringssl/crypto/buf/buf_test.cc \
+
+PUBLIC_HEADERS_CXX += \
+
+LIBBORINGSSL_BUF_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_BUF_TEST_LIB_SRC))))
+
+$(LIBBORINGSSL_BUF_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_BUF_TEST_LIB_OBJS): CXXFLAGS += -fno-rtti -fno-exceptions
+$(LIBBORINGSSL_BUF_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare -Wno-implicit-fallthrough $(NO_W_EXTRA_SEMI)
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build a C++ library if you don't have protobuf - a bit overreached, but still okay.
+
+$(LIBDIR)/$(CONFIG)/libboringssl_buf_test_lib.a: protobuf_dep_error
+
+
+else
+
+$(LIBDIR)/$(CONFIG)/libboringssl_buf_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_BUF_TEST_LIB_OBJS) 
+	$(E) "[AR]      Creating $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_buf_test_lib.a
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_buf_test_lib.a $(LIBBORINGSSL_BUF_TEST_LIB_OBJS) 
+ifeq ($(SYSTEM),Darwin)
+	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_buf_test_lib.a
+endif
+
+
+
+
+endif
+
+ifneq ($(NO_DEPS),true)
+-include $(LIBBORINGSSL_BUF_TEST_LIB_OBJS:.o=.dep)
+endif
+
+
 LIBBORINGSSL_BYTESTRING_TEST_LIB_SRC = \
     third_party/boringssl/crypto/bytestring/bytestring_test.cc \
 
@@ -7083,7 +7846,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_BYTESTRING_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_BYTESTRING_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a
@@ -7122,7 +7885,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_chacha_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_CHACHA_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_chacha_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_CHACHA_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_chacha_test_lib.a
@@ -7161,7 +7924,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_AEAD_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_AEAD_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a
@@ -7200,7 +7963,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_CIPHER_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_CIPHER_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a
@@ -7239,7 +8002,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_CMAC_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_CMAC_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a
@@ -7278,7 +8041,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_compiler_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_COMPILER_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_compiler_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_COMPILER_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_compiler_test_lib.a
@@ -7317,7 +8080,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_constant_time_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_CONSTANT_TIME_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_constant_time_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_CONSTANT_TIME_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_constant_time_test_lib.a
@@ -7356,7 +8119,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_ED25519_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_ED25519_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a
@@ -7395,7 +8158,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_spake25519_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_SPAKE25519_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_spake25519_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_SPAKE25519_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_spake25519_test_lib.a
@@ -7434,7 +8197,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_X25519_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_X25519_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a
@@ -7473,7 +8236,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_dh_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_DH_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_dh_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_DH_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_dh_test_lib.a
@@ -7512,7 +8275,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_DIGEST_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_DIGEST_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a
@@ -7551,7 +8314,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_dsa_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_DSA_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_dsa_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_DSA_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_dsa_test_lib.a
@@ -7590,7 +8353,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_ecdh_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_ECDH_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_ecdh_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_ECDH_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_ecdh_test_lib.a
@@ -7629,7 +8392,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_err_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_ERR_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_err_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_ERR_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_err_test_lib.a
@@ -7668,7 +8431,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_EVP_EXTRA_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_EVP_EXTRA_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a
@@ -7707,7 +8470,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_EVP_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_EVP_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a
@@ -7746,7 +8509,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_PBKDF_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_PBKDF_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a
@@ -7785,7 +8548,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_scrypt_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_SCRYPT_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_scrypt_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_SCRYPT_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_scrypt_test_lib.a
@@ -7824,7 +8587,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_AES_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_AES_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a
@@ -7863,7 +8626,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_BN_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_BN_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a
@@ -7902,7 +8665,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_ec_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_EC_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_ec_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_EC_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_ec_test_lib.a
@@ -7941,7 +8704,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_p256-x86_64_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_P256-X86_64_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_p256-x86_64_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_P256-X86_64_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_p256-x86_64_test_lib.a
@@ -7980,7 +8743,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_ECDSA_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_ECDSA_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a
@@ -8019,7 +8782,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_gcm_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_GCM_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_gcm_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_GCM_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_gcm_test_lib.a
@@ -8058,7 +8821,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_ctrdrbg_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_CTRDRBG_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_ctrdrbg_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_CTRDRBG_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_ctrdrbg_test_lib.a
@@ -8097,7 +8860,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_hkdf_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_HKDF_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_hkdf_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_HKDF_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_hkdf_test_lib.a
@@ -8136,7 +8899,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_HMAC_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_HMAC_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a
@@ -8175,7 +8938,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_lhash_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_LHASH_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_lhash_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_LHASH_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_lhash_test_lib.a
@@ -8214,7 +8977,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_obj_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_OBJ_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_obj_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_OBJ_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_obj_test_lib.a
@@ -8253,7 +9016,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_pkcs7_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_PKCS7_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_pkcs7_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_PKCS7_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_pkcs7_test_lib.a
@@ -8292,7 +9055,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_PKCS12_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_PKCS12_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a
@@ -8331,7 +9094,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_PKCS8_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_PKCS8_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a
@@ -8370,7 +9133,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_POLY1305_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_POLY1305_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a
@@ -8409,7 +9172,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_pool_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_POOL_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_pool_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_POOL_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_pool_test_lib.a
@@ -8448,7 +9211,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_refcount_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_REFCOUNT_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_refcount_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_REFCOUNT_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_refcount_test_lib.a
@@ -8487,7 +9250,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_rsa_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_RSA_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_rsa_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_RSA_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_rsa_test_lib.a
@@ -8526,7 +9289,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_file_test_gtest_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_FILE_TEST_GTEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_file_test_gtest_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_FILE_TEST_GTEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_file_test_gtest_lib.a
@@ -8565,7 +9328,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_gtest_main_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_GTEST_MAIN_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_gtest_main_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_GTEST_MAIN_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_gtest_main_lib.a
@@ -8604,7 +9367,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_thread_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_THREAD_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_thread_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_THREAD_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_thread_test_lib.a
@@ -8643,7 +9406,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_x509_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_X509_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_x509_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_X509_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_x509_test_lib.a
@@ -8682,7 +9445,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_tab_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_TAB_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_tab_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_TAB_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_tab_test_lib.a
@@ -8721,7 +9484,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_v3name_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_V3NAME_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_v3name_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_V3NAME_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_v3name_test_lib.a
@@ -8760,7 +9523,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_span_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_SPAN_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_span_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_SPAN_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_span_test_lib.a
@@ -8799,7 +9562,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_ssl_test_lib.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_SSL_TEST_LIB_OBJS) 
+$(LIBDIR)/$(CONFIG)/libboringssl_ssl_test_lib.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_SSL_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_ssl_test_lib.a
@@ -8849,7 +9612,7 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libbenchmark.a: $(ZLIB_DEP) $(CARES_DEP)  $(PROTOBUF_DEP) $(LIBBENCHMARK_OBJS) 
+$(LIBDIR)/$(CONFIG)/libbenchmark.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(PROTOBUF_DEP) $(LIBBENCHMARK_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libbenchmark.a
@@ -8891,7 +9654,7 @@
 
 $(LIBZ_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-implicit-function-declaration -Wno-implicit-fallthrough $(W_NO_SHIFT_NEGATIVE_VALUE) -fvisibility=hidden
 
-$(LIBDIR)/$(CONFIG)/libz.a: $(CARES_DEP)  $(LIBZ_OBJS) 
+$(LIBDIR)/$(CONFIG)/libz.a: $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(LIBZ_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libz.a
@@ -8966,7 +9729,7 @@
 $(LIBARES_OBJS): CPPFLAGS += -Ithird_party/cares -Ithird_party/cares/cares -fvisibility=hidden -D_GNU_SOURCE $(if $(subst Darwin,,$(SYSTEM)),,-Ithird_party/cares/config_darwin) $(if $(subst FreeBSD,,$(SYSTEM)),,-Ithird_party/cares/config_freebsd) $(if $(subst Linux,,$(SYSTEM)),,-Ithird_party/cares/config_linux) $(if $(subst OpenBSD,,$(SYSTEM)),,-Ithird_party/cares/config_openbsd) -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX $(if $(subst MINGW32,,$(SYSTEM)),-DHAVE_CONFIG_H,)
 $(LIBARES_OBJS): CFLAGS += -Wno-sign-conversion $(if $(subst Darwin,,$(SYSTEM)),,-Wno-shorten-64-to-32) $(if $(subst MINGW32,,$(SYSTEM)),-Wno-invalid-source-encoding,)
 
-$(LIBDIR)/$(CONFIG)/libares.a: $(ZLIB_DEP)  $(LIBARES_OBJS) 
+$(LIBDIR)/$(CONFIG)/libares.a: $(ZLIB_DEP) $(ADDRESS_SORTING_DEP)  $(LIBARES_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libares.a
@@ -9001,7 +9764,7 @@
 else
 
 
-$(LIBDIR)/$(CONFIG)/libbad_client_test.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(LIBBAD_CLIENT_TEST_OBJS) 
+$(LIBDIR)/$(CONFIG)/libbad_client_test.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(LIBBAD_CLIENT_TEST_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libbad_client_test.a
@@ -9040,7 +9803,7 @@
 else
 
 
-$(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(LIBBAD_SSL_TEST_SERVER_OBJS) 
+$(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(LIBBAD_SSL_TEST_SERVER_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a
@@ -9109,6 +9872,21 @@
     test/core/end2end/tests/request_with_flags.cc \
     test/core/end2end/tests/request_with_payload.cc \
     test/core/end2end/tests/resource_quota_server.cc \
+    test/core/end2end/tests/retry.cc \
+    test/core/end2end/tests/retry_cancellation.cc \
+    test/core/end2end/tests/retry_disabled.cc \
+    test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc \
+    test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc \
+    test/core/end2end/tests/retry_non_retriable_status.cc \
+    test/core/end2end/tests/retry_recv_initial_metadata.cc \
+    test/core/end2end/tests/retry_recv_message.cc \
+    test/core/end2end/tests/retry_server_pushback_delay.cc \
+    test/core/end2end/tests/retry_server_pushback_disabled.cc \
+    test/core/end2end/tests/retry_streaming.cc \
+    test/core/end2end/tests/retry_streaming_after_commit.cc \
+    test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc \
+    test/core/end2end/tests/retry_throttled.cc \
+    test/core/end2end/tests/retry_too_many_attempts.cc \
     test/core/end2end/tests/server_finishes_request.cc \
     test/core/end2end/tests/shutdown_finishes_calls.cc \
     test/core/end2end/tests/shutdown_finishes_tags.cc \
@@ -9140,7 +9918,7 @@
 else
 
 
-$(LIBDIR)/$(CONFIG)/libend2end_tests.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(LIBEND2END_TESTS_OBJS) 
+$(LIBDIR)/$(CONFIG)/libend2end_tests.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(LIBEND2END_TESTS_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libend2end_tests.a
@@ -9208,6 +9986,21 @@
     test/core/end2end/tests/request_with_flags.cc \
     test/core/end2end/tests/request_with_payload.cc \
     test/core/end2end/tests/resource_quota_server.cc \
+    test/core/end2end/tests/retry.cc \
+    test/core/end2end/tests/retry_cancellation.cc \
+    test/core/end2end/tests/retry_disabled.cc \
+    test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc \
+    test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc \
+    test/core/end2end/tests/retry_non_retriable_status.cc \
+    test/core/end2end/tests/retry_recv_initial_metadata.cc \
+    test/core/end2end/tests/retry_recv_message.cc \
+    test/core/end2end/tests/retry_server_pushback_delay.cc \
+    test/core/end2end/tests/retry_server_pushback_disabled.cc \
+    test/core/end2end/tests/retry_streaming.cc \
+    test/core/end2end/tests/retry_streaming_after_commit.cc \
+    test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc \
+    test/core/end2end/tests/retry_throttled.cc \
+    test/core/end2end/tests/retry_too_many_attempts.cc \
     test/core/end2end/tests/server_finishes_request.cc \
     test/core/end2end/tests/shutdown_finishes_calls.cc \
     test/core/end2end/tests/shutdown_finishes_tags.cc \
@@ -9229,7 +10022,7 @@
 LIBEND2END_NOSEC_TESTS_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBEND2END_NOSEC_TESTS_SRC))))
 
 
-$(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a: $(ZLIB_DEP) $(CARES_DEP)  $(LIBEND2END_NOSEC_TESTS_OBJS) 
+$(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a: $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)  $(LIBEND2END_NOSEC_TESTS_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a
@@ -9410,6 +10203,38 @@
 endif
 
 
+AVL_TEST_SRC = \
+    test/core/avl/avl_test.cc \
+
+AVL_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(AVL_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/avl_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/avl_test: $(AVL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(AVL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/avl_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/avl/avl_test.o:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+
+deps_avl_test: $(AVL_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(AVL_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 BAD_SERVER_RESPONSE_TEST_SRC = \
     test/core/end2end/bad_server_response_test.cc \
 
@@ -9506,38 +10331,6 @@
 endif
 
 
-BYTE_STREAM_TEST_SRC = \
-    test/core/transport/byte_stream_test.cc \
-
-BYTE_STREAM_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BYTE_STREAM_TEST_SRC))))
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL.
-
-$(BINDIR)/$(CONFIG)/byte_stream_test: openssl_dep_error
-
-else
-
-
-
-$(BINDIR)/$(CONFIG)/byte_stream_test: $(BYTE_STREAM_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-	$(E) "[LD]      Linking $@"
-	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) $(BYTE_STREAM_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/byte_stream_test
-
-endif
-
-$(OBJDIR)/$(CONFIG)/test/core/transport/byte_stream_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-
-deps_byte_stream_test: $(BYTE_STREAM_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(BYTE_STREAM_TEST_OBJS:.o=.dep)
-endif
-endif
-
-
 CHANNEL_CREATE_TEST_SRC = \
     test/core/surface/channel_create_test.cc \
 
@@ -9730,6 +10523,38 @@
 endif
 
 
+CMDLINE_TEST_SRC = \
+    test/core/util/cmdline_test.cc \
+
+CMDLINE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CMDLINE_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/cmdline_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/cmdline_test: $(CMDLINE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(CMDLINE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/cmdline_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/util/cmdline_test.o:  $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a
+
+deps_cmdline_test: $(CMDLINE_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(CMDLINE_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 COMBINER_TEST_SRC = \
     test/core/iomgr/combiner_test.cc \
 
@@ -10373,70 +11198,6 @@
 endif
 
 
-GPR_AVL_TEST_SRC = \
-    test/core/gpr/avl_test.cc \
-
-GPR_AVL_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_AVL_TEST_SRC))))
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL.
-
-$(BINDIR)/$(CONFIG)/gpr_avl_test: openssl_dep_error
-
-else
-
-
-
-$(BINDIR)/$(CONFIG)/gpr_avl_test: $(GPR_AVL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-	$(E) "[LD]      Linking $@"
-	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) $(GPR_AVL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gpr_avl_test
-
-endif
-
-$(OBJDIR)/$(CONFIG)/test/core/gpr/avl_test.o:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-
-deps_gpr_avl_test: $(GPR_AVL_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(GPR_AVL_TEST_OBJS:.o=.dep)
-endif
-endif
-
-
-GPR_CMDLINE_TEST_SRC = \
-    test/core/gpr/cmdline_test.cc \
-
-GPR_CMDLINE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_CMDLINE_TEST_SRC))))
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL.
-
-$(BINDIR)/$(CONFIG)/gpr_cmdline_test: openssl_dep_error
-
-else
-
-
-
-$(BINDIR)/$(CONFIG)/gpr_cmdline_test: $(GPR_CMDLINE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-	$(E) "[LD]      Linking $@"
-	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) $(GPR_CMDLINE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gpr_cmdline_test
-
-endif
-
-$(OBJDIR)/$(CONFIG)/test/core/gpr/cmdline_test.o:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-
-deps_gpr_cmdline_test: $(GPR_CMDLINE_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(GPR_CMDLINE_TEST_OBJS:.o=.dep)
-endif
-endif
-
-
 GPR_CPU_TEST_SRC = \
     test/core/gpr/cpu_test.cc \
 
@@ -10726,7 +11487,7 @@
 
 
 GPR_THD_TEST_SRC = \
-    test/core/gpr/thd_test.cc \
+    test/core/gprpp/thd_test.cc \
 
 GPR_THD_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_THD_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
@@ -10746,7 +11507,7 @@
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/gpr/thd_test.o:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/core/gprpp/thd_test.o:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_gpr_thd_test: $(GPR_THD_TEST_OBJS:.o=.dep)
 
@@ -11111,6 +11872,7 @@
 
 GRPC_CREATE_JWT_SRC = \
     test/core/security/create_jwt.cc \
+    test/core/util/cmdline.cc \
 
 GRPC_CREATE_JWT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_CREATE_JWT_SRC))))
 ifeq ($(NO_SECURE),true)
@@ -11132,6 +11894,8 @@
 
 $(OBJDIR)/$(CONFIG)/test/core/security/create_jwt.o:  $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
+$(OBJDIR)/$(CONFIG)/test/core/util/cmdline.o:  $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
 deps_grpc_create_jwt: $(GRPC_CREATE_JWT_OBJS:.o=.dep)
 
 ifneq ($(NO_SECURE),true)
@@ -11303,6 +12067,7 @@
 
 GRPC_PRINT_GOOGLE_DEFAULT_CREDS_TOKEN_SRC = \
     test/core/security/print_google_default_creds_token.cc \
+    test/core/util/cmdline.cc \
 
 GRPC_PRINT_GOOGLE_DEFAULT_CREDS_TOKEN_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_PRINT_GOOGLE_DEFAULT_CREDS_TOKEN_SRC))))
 ifeq ($(NO_SECURE),true)
@@ -11324,6 +12089,8 @@
 
 $(OBJDIR)/$(CONFIG)/test/core/security/print_google_default_creds_token.o:  $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
+$(OBJDIR)/$(CONFIG)/test/core/util/cmdline.o:  $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
 deps_grpc_print_google_default_creds_token: $(GRPC_PRINT_GOOGLE_DEFAULT_CREDS_TOKEN_OBJS:.o=.dep)
 
 ifneq ($(NO_SECURE),true)
@@ -11399,6 +12166,7 @@
 
 GRPC_VERIFY_JWT_SRC = \
     test/core/security/verify_jwt.cc \
+    test/core/util/cmdline.cc \
 
 GRPC_VERIFY_JWT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_VERIFY_JWT_SRC))))
 ifeq ($(NO_SECURE),true)
@@ -11420,6 +12188,8 @@
 
 $(OBJDIR)/$(CONFIG)/test/core/security/verify_jwt.o:  $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
+$(OBJDIR)/$(CONFIG)/test/core/util/cmdline.o:  $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
 deps_grpc_verify_jwt: $(GRPC_VERIFY_JWT_OBJS:.o=.dep)
 
 ifneq ($(NO_SECURE),true)
@@ -11961,14 +12731,14 @@
 
 
 
-$(BINDIR)/$(CONFIG)/json_rewrite: $(JSON_REWRITE_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/json_rewrite: $(JSON_REWRITE_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) $(JSON_REWRITE_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/json_rewrite
+	$(Q) $(LD) $(LDFLAGS) $(JSON_REWRITE_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/json_rewrite
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/json/json_rewrite.o:  $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/core/json/json_rewrite.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_json_rewrite: $(JSON_REWRITE_OBJS:.o=.dep)
 
@@ -13003,38 +13773,6 @@
 endif
 
 
-SLICE_HASH_TABLE_TEST_SRC = \
-    test/core/slice/slice_hash_table_test.cc \
-
-SLICE_HASH_TABLE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SLICE_HASH_TABLE_TEST_SRC))))
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL.
-
-$(BINDIR)/$(CONFIG)/slice_hash_table_test: openssl_dep_error
-
-else
-
-
-
-$(BINDIR)/$(CONFIG)/slice_hash_table_test: $(SLICE_HASH_TABLE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-	$(E) "[LD]      Linking $@"
-	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) $(SLICE_HASH_TABLE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/slice_hash_table_test
-
-endif
-
-$(OBJDIR)/$(CONFIG)/test/core/slice/slice_hash_table_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-
-deps_slice_hash_table_test: $(SLICE_HASH_TABLE_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(SLICE_HASH_TABLE_TEST_OBJS:.o=.dep)
-endif
-endif
-
-
 SLICE_STRING_HELPERS_TEST_SRC = \
     test/core/slice/slice_string_helpers_test.cc \
 
@@ -13913,6 +14651,568 @@
 endif
 
 
+ALTS_COUNTER_TEST_SRC = \
+    test/core/tsi/alts/frame_protector/alts_counter_test.cc \
+
+ALTS_COUNTER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ALTS_COUNTER_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/alts_counter_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/alts_counter_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/alts_counter_test: $(PROTOBUF_DEP) $(ALTS_COUNTER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(ALTS_COUNTER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/alts_counter_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/tsi/alts/frame_protector/alts_counter_test.o:  $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+
+deps_alts_counter_test: $(ALTS_COUNTER_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(ALTS_COUNTER_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+ALTS_CRYPT_TEST_SRC = \
+    test/core/tsi/alts/crypt/aes_gcm_test.cc \
+
+ALTS_CRYPT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ALTS_CRYPT_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/alts_crypt_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/alts_crypt_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/alts_crypt_test: $(PROTOBUF_DEP) $(ALTS_CRYPT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(ALTS_CRYPT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/alts_crypt_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/tsi/alts/crypt/aes_gcm_test.o:  $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+
+deps_alts_crypt_test: $(ALTS_CRYPT_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(ALTS_CRYPT_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+ALTS_CRYPTER_TEST_SRC = \
+    test/core/tsi/alts/frame_protector/alts_crypter_test.cc \
+
+ALTS_CRYPTER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ALTS_CRYPTER_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/alts_crypter_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/alts_crypter_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/alts_crypter_test: $(PROTOBUF_DEP) $(ALTS_CRYPTER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(ALTS_CRYPTER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/alts_crypter_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/tsi/alts/frame_protector/alts_crypter_test.o:  $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+
+deps_alts_crypter_test: $(ALTS_CRYPTER_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(ALTS_CRYPTER_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+ALTS_FRAME_HANDLER_TEST_SRC = \
+    test/core/tsi/alts/frame_protector/frame_handler_test.cc \
+
+ALTS_FRAME_HANDLER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ALTS_FRAME_HANDLER_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/alts_frame_handler_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/alts_frame_handler_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/alts_frame_handler_test: $(PROTOBUF_DEP) $(ALTS_FRAME_HANDLER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(ALTS_FRAME_HANDLER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/alts_frame_handler_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/tsi/alts/frame_protector/frame_handler_test.o:  $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+
+deps_alts_frame_handler_test: $(ALTS_FRAME_HANDLER_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(ALTS_FRAME_HANDLER_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+ALTS_FRAME_PROTECTOR_TEST_SRC = \
+    test/core/tsi/alts/frame_protector/alts_frame_protector_test.cc \
+    test/core/tsi/transport_security_test_lib.cc \
+
+ALTS_FRAME_PROTECTOR_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ALTS_FRAME_PROTECTOR_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/alts_frame_protector_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/alts_frame_protector_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/alts_frame_protector_test: $(PROTOBUF_DEP) $(ALTS_FRAME_PROTECTOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(ALTS_FRAME_PROTECTOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/alts_frame_protector_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/tsi/alts/frame_protector/alts_frame_protector_test.o:  $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+
+$(OBJDIR)/$(CONFIG)/test/core/tsi/transport_security_test_lib.o:  $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+
+deps_alts_frame_protector_test: $(ALTS_FRAME_PROTECTOR_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(ALTS_FRAME_PROTECTOR_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+ALTS_GRPC_RECORD_PROTOCOL_TEST_SRC = \
+    test/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_test.cc \
+
+ALTS_GRPC_RECORD_PROTOCOL_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ALTS_GRPC_RECORD_PROTOCOL_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/alts_grpc_record_protocol_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/alts_grpc_record_protocol_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/alts_grpc_record_protocol_test: $(PROTOBUF_DEP) $(ALTS_GRPC_RECORD_PROTOCOL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(ALTS_GRPC_RECORD_PROTOCOL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/alts_grpc_record_protocol_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_test.o:  $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+
+deps_alts_grpc_record_protocol_test: $(ALTS_GRPC_RECORD_PROTOCOL_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(ALTS_GRPC_RECORD_PROTOCOL_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+ALTS_HANDSHAKER_CLIENT_TEST_SRC = \
+    test/core/tsi/alts/handshaker/alts_handshaker_client_test.cc \
+
+ALTS_HANDSHAKER_CLIENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ALTS_HANDSHAKER_CLIENT_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/alts_handshaker_client_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/alts_handshaker_client_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/alts_handshaker_client_test: $(PROTOBUF_DEP) $(ALTS_HANDSHAKER_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(ALTS_HANDSHAKER_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/alts_handshaker_client_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/tsi/alts/handshaker/alts_handshaker_client_test.o:  $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+
+deps_alts_handshaker_client_test: $(ALTS_HANDSHAKER_CLIENT_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(ALTS_HANDSHAKER_CLIENT_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+ALTS_HANDSHAKER_SERVICE_API_TEST_SRC = \
+    test/core/tsi/alts/handshaker/alts_handshaker_service_api_test.cc \
+
+ALTS_HANDSHAKER_SERVICE_API_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ALTS_HANDSHAKER_SERVICE_API_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/alts_handshaker_service_api_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/alts_handshaker_service_api_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/alts_handshaker_service_api_test: $(PROTOBUF_DEP) $(ALTS_HANDSHAKER_SERVICE_API_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(ALTS_HANDSHAKER_SERVICE_API_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/alts_handshaker_service_api_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/tsi/alts/handshaker/alts_handshaker_service_api_test.o:  $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+
+deps_alts_handshaker_service_api_test: $(ALTS_HANDSHAKER_SERVICE_API_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(ALTS_HANDSHAKER_SERVICE_API_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+ALTS_IOVEC_RECORD_PROTOCOL_TEST_SRC = \
+    test/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol_test.cc \
+
+ALTS_IOVEC_RECORD_PROTOCOL_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ALTS_IOVEC_RECORD_PROTOCOL_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/alts_iovec_record_protocol_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/alts_iovec_record_protocol_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/alts_iovec_record_protocol_test: $(PROTOBUF_DEP) $(ALTS_IOVEC_RECORD_PROTOCOL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(ALTS_IOVEC_RECORD_PROTOCOL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/alts_iovec_record_protocol_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol_test.o:  $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+
+deps_alts_iovec_record_protocol_test: $(ALTS_IOVEC_RECORD_PROTOCOL_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(ALTS_IOVEC_RECORD_PROTOCOL_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+ALTS_SECURITY_CONNECTOR_TEST_SRC = \
+    test/core/security/alts_security_connector_test.cc \
+
+ALTS_SECURITY_CONNECTOR_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ALTS_SECURITY_CONNECTOR_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/alts_security_connector_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/alts_security_connector_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/alts_security_connector_test: $(PROTOBUF_DEP) $(ALTS_SECURITY_CONNECTOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(ALTS_SECURITY_CONNECTOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/alts_security_connector_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/security/alts_security_connector_test.o:  $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+
+deps_alts_security_connector_test: $(ALTS_SECURITY_CONNECTOR_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(ALTS_SECURITY_CONNECTOR_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+ALTS_TSI_HANDSHAKER_TEST_SRC = \
+    test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc \
+
+ALTS_TSI_HANDSHAKER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ALTS_TSI_HANDSHAKER_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/alts_tsi_handshaker_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/alts_tsi_handshaker_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/alts_tsi_handshaker_test: $(PROTOBUF_DEP) $(ALTS_TSI_HANDSHAKER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(ALTS_TSI_HANDSHAKER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/alts_tsi_handshaker_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.o:  $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+
+deps_alts_tsi_handshaker_test: $(ALTS_TSI_HANDSHAKER_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(ALTS_TSI_HANDSHAKER_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+ALTS_TSI_UTILS_TEST_SRC = \
+    test/core/tsi/alts/handshaker/alts_tsi_utils_test.cc \
+
+ALTS_TSI_UTILS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ALTS_TSI_UTILS_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/alts_tsi_utils_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/alts_tsi_utils_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/alts_tsi_utils_test: $(PROTOBUF_DEP) $(ALTS_TSI_UTILS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(ALTS_TSI_UTILS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/alts_tsi_utils_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/tsi/alts/handshaker/alts_tsi_utils_test.o:  $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+
+deps_alts_tsi_utils_test: $(ALTS_TSI_UTILS_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(ALTS_TSI_UTILS_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+ALTS_ZERO_COPY_GRPC_PROTECTOR_TEST_SRC = \
+    test/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector_test.cc \
+
+ALTS_ZERO_COPY_GRPC_PROTECTOR_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ALTS_ZERO_COPY_GRPC_PROTECTOR_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/alts_zero_copy_grpc_protector_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/alts_zero_copy_grpc_protector_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/alts_zero_copy_grpc_protector_test: $(PROTOBUF_DEP) $(ALTS_ZERO_COPY_GRPC_PROTECTOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(ALTS_ZERO_COPY_GRPC_PROTECTOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/alts_zero_copy_grpc_protector_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector_test.o:  $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+
+deps_alts_zero_copy_grpc_protector_test: $(ALTS_ZERO_COPY_GRPC_PROTECTOR_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(ALTS_ZERO_COPY_GRPC_PROTECTOR_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 ASYNC_END2END_TEST_SRC = \
     test/cpp/end2end/async_end2end_test.cc \
 
@@ -14701,6 +16001,49 @@
 endif
 
 
+BYTE_STREAM_TEST_SRC = \
+    test/core/transport/byte_stream_test.cc \
+
+BYTE_STREAM_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BYTE_STREAM_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/byte_stream_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/byte_stream_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/byte_stream_test: $(PROTOBUF_DEP) $(BYTE_STREAM_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(BYTE_STREAM_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/byte_stream_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/transport/byte_stream_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_byte_stream_test: $(BYTE_STREAM_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(BYTE_STREAM_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 CHANNEL_ARGUMENTS_TEST_SRC = \
     test/cpp/common/channel_arguments_test.cc \
 
@@ -14787,6 +16130,139 @@
 endif
 
 
+CHANNEL_TRACE_TEST_SRC = \
+    test/core/channel/channel_trace_test.cc \
+    $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc \
+
+CHANNEL_TRACE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CHANNEL_TRACE_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/channel_trace_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/channel_trace_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/channel_trace_test: $(PROTOBUF_DEP) $(CHANNEL_TRACE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(CHANNEL_TRACE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/channel_trace_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/channel/channel_trace_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/channelz/channelz.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_channel_trace_test: $(CHANNEL_TRACE_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(CHANNEL_TRACE_TEST_OBJS:.o=.dep)
+endif
+endif
+$(OBJDIR)/$(CONFIG)/test/core/channel/channel_trace_test.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc
+
+
+CHECK_GCP_ENVIRONMENT_LINUX_TEST_SRC = \
+    test/core/security/check_gcp_environment_linux_test.cc \
+
+CHECK_GCP_ENVIRONMENT_LINUX_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CHECK_GCP_ENVIRONMENT_LINUX_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/check_gcp_environment_linux_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/check_gcp_environment_linux_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/check_gcp_environment_linux_test: $(PROTOBUF_DEP) $(CHECK_GCP_ENVIRONMENT_LINUX_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(CHECK_GCP_ENVIRONMENT_LINUX_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/check_gcp_environment_linux_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/security/check_gcp_environment_linux_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_check_gcp_environment_linux_test: $(CHECK_GCP_ENVIRONMENT_LINUX_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(CHECK_GCP_ENVIRONMENT_LINUX_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+CHECK_GCP_ENVIRONMENT_WINDOWS_TEST_SRC = \
+    test/core/security/check_gcp_environment_windows_test.cc \
+
+CHECK_GCP_ENVIRONMENT_WINDOWS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CHECK_GCP_ENVIRONMENT_WINDOWS_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test: $(PROTOBUF_DEP) $(CHECK_GCP_ENVIRONMENT_WINDOWS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(CHECK_GCP_ENVIRONMENT_WINDOWS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/security/check_gcp_environment_windows_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_check_gcp_environment_windows_test: $(CHECK_GCP_ENVIRONMENT_WINDOWS_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(CHECK_GCP_ENVIRONMENT_WINDOWS_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 CHTTP2_SETTINGS_TIMEOUT_TEST_SRC = \
     test/core/transport/chttp2/settings_timeout_test.cc \
 
@@ -15652,6 +17128,49 @@
 $(OBJDIR)/$(CONFIG)/test/cpp/codegen/golden_file_test.o: $(GENDIR)/src/proto/grpc/testing/compiler_test.pb.cc $(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.cc
 
 
+GRPC_ALTS_CREDENTIALS_OPTIONS_TEST_SRC = \
+    test/core/security/grpc_alts_credentials_options_test.cc \
+
+GRPC_ALTS_CREDENTIALS_OPTIONS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_ALTS_CREDENTIALS_OPTIONS_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/grpc_alts_credentials_options_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/grpc_alts_credentials_options_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/grpc_alts_credentials_options_test: $(PROTOBUF_DEP) $(GRPC_ALTS_CREDENTIALS_OPTIONS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(GRPC_ALTS_CREDENTIALS_OPTIONS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/grpc_alts_credentials_options_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/security/grpc_alts_credentials_options_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_grpc_alts_credentials_options_test: $(GRPC_ALTS_CREDENTIALS_OPTIONS_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(GRPC_ALTS_CREDENTIALS_OPTIONS_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 GRPC_CLI_SRC = \
     test/cpp/util/grpc_cli.cc \
 
@@ -16056,53 +17575,6 @@
 $(OBJDIR)/$(CONFIG)/test/cpp/end2end/grpclb_end2end_test.o: $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc
 
 
-GRPCLB_TEST_SRC = \
-    $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc \
-    test/cpp/grpclb/grpclb_test.cc \
-
-GRPCLB_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPCLB_TEST_SRC))))
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL.
-
-$(BINDIR)/$(CONFIG)/grpclb_test: openssl_dep_error
-
-else
-
-
-
-
-ifeq ($(NO_PROTOBUF),true)
-
-# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
-
-$(BINDIR)/$(CONFIG)/grpclb_test: protobuf_dep_error
-
-else
-
-$(BINDIR)/$(CONFIG)/grpclb_test: $(PROTOBUF_DEP) $(GRPCLB_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-	$(E) "[LD]      Linking $@"
-	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(GRPCLB_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/grpclb_test
-
-endif
-
-endif
-
-$(OBJDIR)/$(CONFIG)/src/proto/grpc/lb/v1/load_balancer.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-
-$(OBJDIR)/$(CONFIG)/test/cpp/grpclb/grpclb_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-
-deps_grpclb_test: $(GRPCLB_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(GRPCLB_TEST_OBJS:.o=.dep)
-endif
-endif
-$(OBJDIR)/$(CONFIG)/test/cpp/grpclb/grpclb_test.o: $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc
-
-
 H2_SSL_CERT_TEST_SRC = \
     test/core/end2end/h2_ssl_cert_test.cc \
 
@@ -16146,6 +17618,49 @@
 endif
 
 
+H2_SSL_SESSION_REUSE_TEST_SRC = \
+    test/core/end2end/h2_ssl_session_reuse_test.cc \
+
+H2_SSL_SESSION_REUSE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(H2_SSL_SESSION_REUSE_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/h2_ssl_session_reuse_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/h2_ssl_session_reuse_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/h2_ssl_session_reuse_test: $(PROTOBUF_DEP) $(H2_SSL_SESSION_REUSE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(H2_SSL_SESSION_REUSE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/h2_ssl_session_reuse_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/end2end/h2_ssl_session_reuse_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_h2_ssl_session_reuse_test: $(H2_SSL_SESSION_REUSE_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(H2_SSL_SESSION_REUSE_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 HEALTH_SERVICE_END2END_TEST_SRC = \
     test/cpp/end2end/health_service_end2end_test.cc \
 
@@ -16630,6 +18145,49 @@
 endif
 
 
+NONBLOCKING_TEST_SRC = \
+    test/cpp/end2end/nonblocking_test.cc \
+
+NONBLOCKING_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(NONBLOCKING_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/nonblocking_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/nonblocking_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/nonblocking_test: $(PROTOBUF_DEP) $(NONBLOCKING_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(NONBLOCKING_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/nonblocking_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/nonblocking_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_nonblocking_test: $(NONBLOCKING_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(NONBLOCKING_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 NOOP-BENCHMARK_SRC = \
     test/cpp/microbenchmarks/noop-benchmark.cc \
 
@@ -17611,6 +19169,92 @@
 endif
 
 
+SLICE_HASH_TABLE_TEST_SRC = \
+    test/core/slice/slice_hash_table_test.cc \
+
+SLICE_HASH_TABLE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SLICE_HASH_TABLE_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/slice_hash_table_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/slice_hash_table_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/slice_hash_table_test: $(PROTOBUF_DEP) $(SLICE_HASH_TABLE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(SLICE_HASH_TABLE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/slice_hash_table_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/slice/slice_hash_table_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_slice_hash_table_test: $(SLICE_HASH_TABLE_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(SLICE_HASH_TABLE_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+SLICE_WEAK_HASH_TABLE_TEST_SRC = \
+    test/core/slice/slice_weak_hash_table_test.cc \
+
+SLICE_WEAK_HASH_TABLE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SLICE_WEAK_HASH_TABLE_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/slice_weak_hash_table_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/slice_weak_hash_table_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/slice_weak_hash_table_test: $(PROTOBUF_DEP) $(SLICE_WEAK_HASH_TABLE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(SLICE_WEAK_HASH_TABLE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/slice_weak_hash_table_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/slice/slice_weak_hash_table_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_slice_weak_hash_table_test: $(SLICE_WEAK_HASH_TABLE_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(SLICE_WEAK_HASH_TABLE_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 STATS_TEST_SRC = \
     test/core/debug/stats_test.cc \
 
@@ -17654,15 +19298,15 @@
 endif
 
 
-STATUS_TEST_SRC = \
-    test/cpp/util/status_test.cc \
+STATUS_METADATA_TEST_SRC = \
+    test/core/transport/status_metadata_test.cc \
 
-STATUS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(STATUS_TEST_SRC))))
+STATUS_METADATA_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(STATUS_METADATA_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
 # You can't build secure targets if you don't have OpenSSL.
 
-$(BINDIR)/$(CONFIG)/status_test: openssl_dep_error
+$(BINDIR)/$(CONFIG)/status_metadata_test: openssl_dep_error
 
 else
 
@@ -17673,26 +19317,69 @@
 
 # You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
 
-$(BINDIR)/$(CONFIG)/status_test: protobuf_dep_error
+$(BINDIR)/$(CONFIG)/status_metadata_test: protobuf_dep_error
 
 else
 
-$(BINDIR)/$(CONFIG)/status_test: $(PROTOBUF_DEP) $(STATUS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/status_metadata_test: $(PROTOBUF_DEP) $(STATUS_METADATA_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(STATUS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/status_test
+	$(Q) $(LDXX) $(LDFLAGS) $(STATUS_METADATA_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/status_metadata_test
 
 endif
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/cpp/util/status_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/core/transport/status_metadata_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc.a
 
-deps_status_test: $(STATUS_TEST_OBJS:.o=.dep)
+deps_status_metadata_test: $(STATUS_METADATA_TEST_OBJS:.o=.dep)
 
 ifneq ($(NO_SECURE),true)
 ifneq ($(NO_DEPS),true)
--include $(STATUS_TEST_OBJS:.o=.dep)
+-include $(STATUS_METADATA_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+STATUS_UTIL_TEST_SRC = \
+    test/core/channel/status_util_test.cc \
+
+STATUS_UTIL_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(STATUS_UTIL_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/status_util_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/status_util_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/status_util_test: $(PROTOBUF_DEP) $(STATUS_UTIL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(STATUS_UTIL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/status_util_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/channel/status_util_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc.a
+
+deps_status_util_test: $(STATUS_UTIL_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(STATUS_UTIL_TEST_OBJS:.o=.dep)
 endif
 endif
 
@@ -17937,6 +19624,49 @@
 endif
 
 
+TRANSPORT_SECURITY_COMMON_API_TEST_SRC = \
+    test/core/tsi/alts/handshaker/transport_security_common_api_test.cc \
+
+TRANSPORT_SECURITY_COMMON_API_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(TRANSPORT_SECURITY_COMMON_API_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/transport_security_common_api_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/transport_security_common_api_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/transport_security_common_api_test: $(PROTOBUF_DEP) $(TRANSPORT_SECURITY_COMMON_API_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(TRANSPORT_SECURITY_COMMON_API_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/transport_security_common_api_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/tsi/alts/handshaker/transport_security_common_api_test.o:  $(LIBDIR)/$(CONFIG)/libalts_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a
+
+deps_transport_security_common_api_test: $(TRANSPORT_SECURITY_COMMON_API_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(TRANSPORT_SECURITY_COMMON_API_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 WRITES_PER_RPC_TEST_SRC = \
     test/cpp/performance/writes_per_rpc_test.cc \
 
@@ -18272,6 +20002,46 @@
 endif
 
 
+BORINGSSL_BUF_TEST_SRC = \
+    third_party/boringssl/crypto/test/gtest_main.cc \
+
+BORINGSSL_BUF_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BORINGSSL_BUF_TEST_SRC))))
+
+# boringssl needs an override to ensure that it does not include
+# system openssl headers regardless of other configuration
+# we do so here with a target specific variable assignment
+$(BORINGSSL_BUF_TEST_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value $(NO_W_EXTRA_SEMI)
+$(BORINGSSL_BUF_TEST_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS)
+$(BORINGSSL_BUF_TEST_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/boringssl_buf_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/boringssl_buf_test: $(PROTOBUF_DEP) $(BORINGSSL_BUF_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libboringssl_buf_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBDIR)/$(CONFIG)/libboringssl.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(BORINGSSL_BUF_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libboringssl_buf_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBDIR)/$(CONFIG)/libboringssl.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/boringssl_buf_test
+
+endif
+
+$(BORINGSSL_BUF_TEST_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(BORINGSSL_BUF_TEST_OBJS): CXXFLAGS += -fno-rtti -fno-exceptions
+$(BORINGSSL_BUF_TEST_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare -Wno-implicit-fallthrough $(NO_W_EXTRA_SEMI)
+$(OBJDIR)/$(CONFIG)/third_party/boringssl/crypto/test/gtest_main.o:  $(LIBDIR)/$(CONFIG)/libboringssl_buf_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBDIR)/$(CONFIG)/libboringssl.a
+
+deps_boringssl_buf_test: $(BORINGSSL_BUF_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_DEPS),true)
+-include $(BORINGSSL_BUF_TEST_OBJS:.o=.dep)
+endif
+
+
 BORINGSSL_BYTESTRING_TEST_SRC = \
     third_party/boringssl/crypto/test/gtest_main.cc \
 
@@ -20112,6 +21882,26 @@
 endif
 
 
+DUPLICATE_HEADER_BAD_CLIENT_TEST_SRC = \
+    test/core/bad_client/tests/duplicate_header.cc \
+
+DUPLICATE_HEADER_BAD_CLIENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(DUPLICATE_HEADER_BAD_CLIENT_TEST_SRC))))
+
+
+$(BINDIR)/$(CONFIG)/duplicate_header_bad_client_test: $(DUPLICATE_HEADER_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(DUPLICATE_HEADER_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/duplicate_header_bad_client_test
+
+$(OBJDIR)/$(CONFIG)/test/core/bad_client/tests/duplicate_header.o:  $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_duplicate_header_bad_client_test: $(DUPLICATE_HEADER_BAD_CLIENT_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_DEPS),true)
+-include $(DUPLICATE_HEADER_BAD_CLIENT_TEST_OBJS:.o=.dep)
+endif
+
+
 HEAD_OF_LINE_BLOCKING_BAD_CLIENT_TEST_SRC = \
     test/core/bad_client/tests/head_of_line_blocking.cc \
 
@@ -21416,6 +23206,92 @@
 endif
 
 
+ADDRESS_SORTING_TEST_UNSECURE_SRC = \
+    test/cpp/naming/address_sorting_test.cc \
+
+ADDRESS_SORTING_TEST_UNSECURE_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ADDRESS_SORTING_TEST_UNSECURE_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/address_sorting_test_unsecure: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/address_sorting_test_unsecure: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/address_sorting_test_unsecure: $(PROTOBUF_DEP) $(ADDRESS_SORTING_TEST_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(ADDRESS_SORTING_TEST_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/address_sorting_test_unsecure
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/naming/address_sorting_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+
+deps_address_sorting_test_unsecure: $(ADDRESS_SORTING_TEST_UNSECURE_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(ADDRESS_SORTING_TEST_UNSECURE_OBJS:.o=.dep)
+endif
+endif
+
+
+ADDRESS_SORTING_TEST_SRC = \
+    test/cpp/naming/address_sorting_test.cc \
+
+ADDRESS_SORTING_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ADDRESS_SORTING_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/address_sorting_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/address_sorting_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/address_sorting_test: $(PROTOBUF_DEP) $(ADDRESS_SORTING_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(ADDRESS_SORTING_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/address_sorting_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/naming/address_sorting_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+
+deps_address_sorting_test: $(ADDRESS_SORTING_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(ADDRESS_SORTING_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 API_FUZZER_ONE_ENTRY_SRC = \
     test/core/end2end/fuzzers/api_fuzzer.cc \
     test/core/util/one_corpus_entry_fuzzer.cc \
@@ -21887,6 +23763,14 @@
 src/core/ext/transport/cronet/transport/cronet_transport.cc: $(OPENSSL_DEP)
 src/core/lib/http/httpcli_security_connector.cc: $(OPENSSL_DEP)
 src/core/lib/security/context/security_context.cc: $(OPENSSL_DEP)
+src/core/lib/security/credentials/alts/alts_credentials.cc: $(OPENSSL_DEP)
+src/core/lib/security/credentials/alts/check_gcp_environment.cc: $(OPENSSL_DEP)
+src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc: $(OPENSSL_DEP)
+src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc: $(OPENSSL_DEP)
+src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc: $(OPENSSL_DEP)
+src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc: $(OPENSSL_DEP)
+src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc: $(OPENSSL_DEP)
+src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc: $(OPENSSL_DEP)
 src/core/lib/security/credentials/composite/composite_credentials.cc: $(OPENSSL_DEP)
 src/core/lib/security/credentials/credentials.cc: $(OPENSSL_DEP)
 src/core/lib/security/credentials/credentials_metadata.cc: $(OPENSSL_DEP)
@@ -21900,19 +23784,47 @@
 src/core/lib/security/credentials/oauth2/oauth2_credentials.cc: $(OPENSSL_DEP)
 src/core/lib/security/credentials/plugin/plugin_credentials.cc: $(OPENSSL_DEP)
 src/core/lib/security/credentials/ssl/ssl_credentials.cc: $(OPENSSL_DEP)
+src/core/lib/security/security_connector/alts_security_connector.cc: $(OPENSSL_DEP)
+src/core/lib/security/security_connector/security_connector.cc: $(OPENSSL_DEP)
 src/core/lib/security/transport/client_auth_filter.cc: $(OPENSSL_DEP)
-src/core/lib/security/transport/lb_targets_info.cc: $(OPENSSL_DEP)
 src/core/lib/security/transport/secure_endpoint.cc: $(OPENSSL_DEP)
-src/core/lib/security/transport/security_connector.cc: $(OPENSSL_DEP)
 src/core/lib/security/transport/security_handshaker.cc: $(OPENSSL_DEP)
 src/core/lib/security/transport/server_auth_filter.cc: $(OPENSSL_DEP)
+src/core/lib/security/transport/target_authority_table.cc: $(OPENSSL_DEP)
 src/core/lib/security/transport/tsi_error.cc: $(OPENSSL_DEP)
 src/core/lib/security/util/json_util.cc: $(OPENSSL_DEP)
 src/core/lib/surface/init_secure.cc: $(OPENSSL_DEP)
 src/core/plugin_registry/grpc_cronet_plugin_registry.cc: $(OPENSSL_DEP)
 src/core/plugin_registry/grpc_plugin_registry.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/crypt/aes_gcm.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/crypt/gsec.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/frame_protector/alts_counter.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/frame_protector/alts_crypter.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/frame_protector/alts_frame_protector.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/frame_protector/frame_handler.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/handshaker/alts_handshaker_client.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/handshaker/alts_tsi_event.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/handshaker/alts_tsi_utils.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/handshaker/altscontext.pb.c: $(OPENSSL_DEP)
+src/core/tsi/alts/handshaker/handshaker.pb.c: $(OPENSSL_DEP)
+src/core/tsi/alts/handshaker/transport_security_common.pb.c: $(OPENSSL_DEP)
+src/core/tsi/alts/handshaker/transport_security_common_api.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc: $(OPENSSL_DEP)
+src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc: $(OPENSSL_DEP)
 src/core/tsi/alts_transport_security.cc: $(OPENSSL_DEP)
 src/core/tsi/fake_transport_security.cc: $(OPENSSL_DEP)
+src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc: $(OPENSSL_DEP)
+src/core/tsi/ssl/session_cache/ssl_session_cache.cc: $(OPENSSL_DEP)
+src/core/tsi/ssl/session_cache/ssl_session_openssl.cc: $(OPENSSL_DEP)
 src/core/tsi/ssl_transport_security.cc: $(OPENSSL_DEP)
 src/core/tsi/transport_security.cc: $(OPENSSL_DEP)
 src/core/tsi/transport_security_adapter.cc: $(OPENSSL_DEP)
@@ -21938,6 +23850,8 @@
 test/core/end2end/end2end_tests.cc: $(OPENSSL_DEP)
 test/core/end2end/tests/call_creds.cc: $(OPENSSL_DEP)
 test/core/security/oauth2_utils.cc: $(OPENSSL_DEP)
+test/core/tsi/alts/crypt/gsec_test_util.cc: $(OPENSSL_DEP)
+test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.cc: $(OPENSSL_DEP)
 test/core/util/reconnect_server.cc: $(OPENSSL_DEP)
 test/core/util/test_tcp_server.cc: $(OPENSSL_DEP)
 test/cpp/end2end/test_service_impl.cc: $(OPENSSL_DEP)
@@ -21960,6 +23874,7 @@
 test/cpp/qps/server_sync.cc: $(OPENSSL_DEP)
 test/cpp/qps/usage_timer.cc: $(OPENSSL_DEP)
 test/cpp/util/byte_buffer_proto_helper.cc: $(OPENSSL_DEP)
+test/cpp/util/channel_trace_proto_helper.cc: $(OPENSSL_DEP)
 test/cpp/util/cli_call.cc: $(OPENSSL_DEP)
 test/cpp/util/cli_credentials.cc: $(OPENSSL_DEP)
 test/cpp/util/create_test_channel.cc: $(OPENSSL_DEP)
diff --git a/README.md b/README.md
index fc72c7c..e66c0b1 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,3 @@
-[![Build Status](https://grpc-testing.appspot.com/job/gRPC_master/badge/icon)](https://grpc-testing.appspot.com/job/gRPC_master)
-
 [gRPC - An RPC library and framework](http://github.com/grpc/grpc)
 ===================================
 
@@ -36,10 +34,12 @@
 | C#                      | [src/csharp](src/csharp)            |
 | Objective-C             | [src/objective-c](src/objective-c)  |
 
-Java source code is in the [grpc-java](http://github.com/grpc/grpc-java)
-repository. Go source code is in the
-[grpc-go](http://github.com/grpc/grpc-go) repository. NodeJS source code is in the
-[grpc-node](https://github.com/grpc/grpc-node) repository.
+| Language                | Source repo                                          |
+|-------------------------|------------------------------------------------------|
+| Java                    | [grpc-java](http://github.com/grpc/grpc-java)        |
+| Go                      | [grpc-go](http://github.com/grpc/grpc-go)            |
+| NodeJS                  | [grpc-node](https://github.com/grpc/grpc-node)       |
+| Dart                    | [grpc-dart](https://github.com/grpc/grpc-dart)       |
 
 See [MANIFEST.md](MANIFEST.md) for a listing of top-level items in the
 repository.
diff --git a/Rakefile b/Rakefile
index 1eac37d..0068a3b 100755
--- a/Rakefile
+++ b/Rakefile
@@ -23,6 +23,12 @@
 
 # Add the extension compiler task
 Rake::ExtensionTask.new('grpc_c', spec) do |ext|
+  unless RUBY_PLATFORM =~ /darwin/
+    # TODO: also set "no_native to true" for mac if possible. As is,
+    # "no_native" can only be set if the RUBY_PLATFORM doing
+    # cross-compilation is contained in the "ext.cross_platform" array.
+    ext.no_native = true
+  end
   ext.source_pattern = '**/*.{c,h}'
   ext.ext_dir = File.join('src', 'ruby', 'ext', 'grpc')
   ext.lib_dir = File.join('src', 'ruby', 'lib', 'grpc')
diff --git a/WORKSPACE b/WORKSPACE
index adce809..8b68c0d 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -1,4 +1,5 @@
 workspace(name = "com_github_grpc_grpc")
 
-load("//bazel:grpc_deps.bzl", "grpc_deps")
+load("//bazel:grpc_deps.bzl", "grpc_deps", "grpc_test_only_deps")
 grpc_deps()
+grpc_test_only_deps()
diff --git a/bazel/cc_grpc_library.bzl b/bazel/cc_grpc_library.bzl
index 94781ed..5216a7a 100644
--- a/bazel/cc_grpc_library.bzl
+++ b/bazel/cc_grpc_library.bzl
@@ -2,7 +2,7 @@
 
 load("//:bazel/generate_cc.bzl", "generate_cc")
 
-def cc_grpc_library(name, srcs, deps, proto_only, well_known_protos, generate_mock, use_external = False, **kwargs):
+def cc_grpc_library(name, srcs, deps, proto_only, well_known_protos, generate_mocks = False, use_external = False, **kwargs):
   """Generates C++ grpc classes from a .proto file.
 
   Assumes the generated classes will be used in cc_api_version = 2.
@@ -16,7 +16,7 @@
         protos
       use_external: When True the grpc deps are prefixed with //external. This
         allows grpc to be used as a dependency in other bazel projects.
-      generate_mock: When true GMOCk code for client stub is generated.
+      generate_mocks: When True, Google Mock code for client stub is generated.
       **kwargs: rest of arguments, e.g., compatible_with and visibility.
   """
   if len(srcs) > 1:
@@ -54,7 +54,7 @@
         srcs = [proto_target],
         plugin = plugin,
         well_known_protos = well_known_protos,
-        generate_mock = generate_mock,
+        generate_mocks = generate_mocks,
         **kwargs
     )
 
diff --git a/bazel/generate_cc.bzl b/bazel/generate_cc.bzl
index f88ee2f..e610123 100644
--- a/bazel/generate_cc.bzl
+++ b/bazel/generate_cc.bzl
@@ -14,7 +14,7 @@
   if ctx.executable.plugin:
     outs += [proto.path[label_len:-len(".proto")] + ".grpc.pb.h" for proto in protos]
     outs += [proto.path[label_len:-len(".proto")] + ".grpc.pb.cc" for proto in protos]
-    if ctx.attr.generate_mock:
+    if ctx.attr.generate_mocks:
       outs += [proto.path[label_len:-len(".proto")] + "_mock.grpc.pb.h" for proto in protos]
   else:
     outs += [proto.path[label_len:-len(".proto")] + ".pb.h" for proto in protos]
@@ -26,7 +26,7 @@
   if ctx.executable.plugin:
     arguments += ["--plugin=protoc-gen-PLUGIN=" + ctx.executable.plugin.path]
     flags = list(ctx.attr.flags)
-    if ctx.attr.generate_mock:
+    if ctx.attr.generate_mocks:
       flags.append("generate_mock_code=true")
     arguments += ["--PLUGIN_out=" + ",".join(flags) + ":" + dir_out]
     additional_input = [ctx.executable.plugin]
@@ -76,7 +76,7 @@
         "well_known_protos" : attr.label(
             mandatory = False,
         ),
-        "generate_mock" : attr.bool(
+        "generate_mocks" : attr.bool(
             default = False,
             mandatory = False,
         ),
diff --git a/bazel/grpc_build_system.bzl b/bazel/grpc_build_system.bzl
index 3fbefc4..095b159 100644
--- a/bazel/grpc_build_system.bzl
+++ b/bazel/grpc_build_system.bzl
@@ -26,11 +26,20 @@
 # The set of pollers to test against if a test exercises polling
 POLLERS = ['epollex', 'epollsig', 'epoll1', 'poll', 'poll-cv']
 
+def if_not_windows(a):
+  return select({
+      "//:windows": [],
+      "//:windows_msvc": [],
+      "//conditions:default": a,
+  })
+
 def _get_external_deps(external_deps):
   ret = []
   for dep in external_deps:
     if dep == "nanopb":
-      ret += ["//third_party/nanopb"]
+      ret += ["grpc_nanopb"]
+    elif dep == "address_sorting":
+      ret += ["//third_party/address_sorting"]
     elif dep == "cares":
       ret += select({"//:grpc_no_ares": [],
                      "//conditions:default": ["//external:cares"],})
@@ -56,7 +65,7 @@
                     alwayslink = 0):
   copts = []
   if language.upper() == "C":
-    copts = ["-std=c99"]
+    copts = if_not_windows(["-std=c99"])
   native.cc_library(
     name = name,
     srcs = srcs,
@@ -73,7 +82,7 @@
     copts = copts,
     visibility = visibility,
     testonly = testonly,
-    linkopts = ["-pthread"],
+    linkopts = if_not_windows(["-pthread"]),
     includes = [
         "include"
     ],
@@ -90,7 +99,7 @@
 load("//:bazel/cc_grpc_library.bzl", "cc_grpc_library")
 
 def grpc_proto_library(name, srcs = [], deps = [], well_known_protos = False,
-                       has_services = True, use_external = False, generate_mock = False):
+                       has_services = True, use_external = False, generate_mocks = False):
   cc_grpc_library(
     name = name,
     srcs = srcs,
@@ -98,13 +107,13 @@
     well_known_protos = well_known_protos,
     proto_only = not has_services,
     use_external = use_external,
-    generate_mock = generate_mock,
+    generate_mocks = generate_mocks,
   )
 
-def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data = [], uses_polling = True, language = "C++"):
+def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data = [], uses_polling = True, language = "C++", size = "medium", timeout = "moderate"):
   copts = []
   if language.upper() == "C":
-    copts = ["-std=c99"]
+    copts = if_not_windows(["-std=c99"])
   args = {
     'name': name,
     'srcs': srcs,
@@ -112,7 +121,9 @@
     'data': data,
     'deps': deps + _get_external_deps(external_deps),
     'copts': copts,
-    'linkopts': ["-pthread"],
+    'linkopts': if_not_windows(["-pthread"]),
+    'size': size,
+    'timeout': timeout,
   }
   if uses_polling:
     native.cc_test(testonly=True, tags=['manual'], **args)
@@ -123,9 +134,11 @@
         srcs = [
           '//test/core/util:run_with_poller_sh',
         ],
+        size = size,
+        timeout = timeout,
         args = [
           poller,
-          '$(location %s)' % name
+          '$(location %s)' % name,
         ] + args['args'],
       )
   else:
@@ -144,11 +157,27 @@
     linkshared = linkshared,
     deps = deps + _get_external_deps(external_deps),
     copts = copts,
-    linkopts = ["-pthread"] + linkopts,
+    linkopts = if_not_windows(["-pthread"]) + linkopts,
   )
 
 def grpc_generate_one_off_targets():
-  pass
+  native.cc_library(
+    name = "grpc_nanopb",
+    hdrs = [
+      "//third_party/nanopb:pb.h",
+      "//third_party/nanopb:pb_common.h",
+      "//third_party/nanopb:pb_decode.h",
+      "//third_party/nanopb:pb_encode.h",
+    ],
+    srcs = [
+      "//third_party/nanopb:pb_common.c",
+      "//third_party/nanopb:pb_decode.c",
+      "//third_party/nanopb:pb_encode.c",
+    ],
+    defines = [
+      "PB_FIELD_16BIT=1",
+    ],
+  )
 
 def grpc_sh_test(name, srcs, args = [], data = []):
   native.sh_test(
@@ -163,15 +192,14 @@
     srcs = srcs,
     data = data)
 
-def grpc_py_binary(name, srcs, data = [], deps = []):
-  if name == "test_dns_server":
-    # TODO: allow running test_dns_server in oss bazel test suite
-    deps = []
+def grpc_py_binary(name, srcs, data = [], deps = [], external_deps = [], testonly = False):
   native.py_binary(
     name = name,
     srcs = srcs,
+    testonly = testonly,
     data = data,
-    deps = deps)
+    deps = deps + _get_external_deps(external_deps)
+  )
 
 def grpc_package(name, visibility = "private", features = []):
   if visibility == "tests":
diff --git a/bazel/grpc_deps.bzl b/bazel/grpc_deps.bzl
index e465312..a441c3f 100644
--- a/bazel/grpc_deps.bzl
+++ b/bazel/grpc_deps.bzl
@@ -120,10 +120,64 @@
     if "com_github_bazelbuild_bazeltoolchains" not in native.existing_rules():
         native.http_archive(
             name = "com_github_bazelbuild_bazeltoolchains",
-            strip_prefix = "bazel-toolchains-af4681c3d19f063f090222ec3d04108c4e0ca255",
+            strip_prefix = "bazel-toolchains-b850ccdf53fed1ccab7670f52d6b297d74348d1b",
             urls = [
-                "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/af4681c3d19f063f090222ec3d04108c4e0ca255.tar.gz",
-                "https://github.com/bazelbuild/bazel-toolchains/archive/af4681c3d19f063f090222ec3d04108c4e0ca255.tar.gz",
+                "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/b850ccdf53fed1ccab7670f52d6b297d74348d1b.tar.gz",
+                "https://github.com/bazelbuild/bazel-toolchains/archive/b850ccdf53fed1ccab7670f52d6b297d74348d1b.tar.gz",
             ],
-            sha256 = "d58bb2d6c8603f600d522b6104d6192a65339aa26cbba9f11ff5c4b36dedb928",
+            sha256 = "d84d6b2fe88ef99963febf91ddce33503eed14c155ace922e2122271b483be64",
+        )
+
+# TODO: move some dependencies from "grpc_deps" here?
+def grpc_test_only_deps():
+    """Internal, not intended for use by packages that are consuming grpc.
+       Loads dependencies that are only needed to run grpc library's tests."""
+    native.bind(
+        name = "twisted",
+        actual = "@com_github_twisted_twisted//:twisted",
+    )
+
+    native.bind(
+        name = "yaml",
+        actual = "@com_github_yaml_pyyaml//:yaml",
+    )
+
+    if "com_github_twisted_twisted" not in native.existing_rules():
+        native.new_http_archive(
+            name = "com_github_twisted_twisted",
+            strip_prefix = "twisted-twisted-17.5.0",
+            url = "https://github.com/twisted/twisted/archive/twisted-17.5.0.zip",
+            build_file = "@com_github_grpc_grpc//third_party:twisted.BUILD",
+        )
+
+    if "com_github_yaml_pyyaml" not in native.existing_rules():
+        native.new_http_archive(
+            name = "com_github_yaml_pyyaml",
+            strip_prefix = "pyyaml-3.12",
+            url = "https://github.com/yaml/pyyaml/archive/3.12.zip",
+            build_file = "@com_github_grpc_grpc//third_party:yaml.BUILD",
+        )
+
+    if "com_github_twisted_incremental" not in native.existing_rules():
+        native.new_http_archive(
+            name = "com_github_twisted_incremental",
+            strip_prefix = "incremental-incremental-17.5.0",
+            url = "https://github.com/twisted/incremental/archive/incremental-17.5.0.zip",
+            build_file = "@com_github_grpc_grpc//third_party:incremental.BUILD",
+        )
+
+    if "com_github_zopefoundation_zope_interface" not in native.existing_rules():
+        native.new_http_archive(
+            name = "com_github_zopefoundation_zope_interface",
+            strip_prefix = "zope.interface-4.4.3",
+            url = "https://github.com/zopefoundation/zope.interface/archive/4.4.3.zip",
+            build_file = "@com_github_grpc_grpc//third_party:zope_interface.BUILD",
+        )
+
+    if "com_github_twisted_constantly" not in native.existing_rules():
+        native.new_http_archive(
+            name = "com_github_twisted_constantly",
+            strip_prefix = "constantly-15.1.0",
+            url = "https://github.com/twisted/constantly/archive/15.1.0.zip",
+            build_file = "@com_github_grpc_grpc//third_party:constantly.BUILD",
         )
diff --git a/build.yaml b/build.yaml
index eca90dd..88f2283 100644
--- a/build.yaml
+++ b/build.yaml
@@ -13,9 +13,87 @@
   '#09': Per-language overrides are possible with (eg) ruby_version tag here
   '#10': See the expand_version.py for all the quirks here
   core_version: 6.0.0-dev
-  g_stands_for: glossy
-  version: 1.10.0-dev
+  g_stands_for: gorgeous
+  version: 1.11.0-dev
 filegroups:
+- name: alts_proto
+  headers:
+  - src/core/tsi/alts/handshaker/altscontext.pb.h
+  - src/core/tsi/alts/handshaker/handshaker.pb.h
+  - src/core/tsi/alts/handshaker/transport_security_common.pb.h
+  src:
+  - src/core/tsi/alts/handshaker/altscontext.pb.c
+  - src/core/tsi/alts/handshaker/handshaker.pb.c
+  - src/core/tsi/alts/handshaker/transport_security_common.pb.c
+  uses:
+  - nanopb
+- name: alts_tsi
+  headers:
+  - src/core/tsi/alts/crypt/gsec.h
+  - src/core/tsi/alts/frame_protector/alts_counter.h
+  - src/core/tsi/alts/frame_protector/alts_crypter.h
+  - src/core/tsi/alts/frame_protector/alts_frame_protector.h
+  - src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h
+  - src/core/tsi/alts/frame_protector/frame_handler.h
+  - src/core/tsi/alts/handshaker/alts_handshaker_client.h
+  - src/core/tsi/alts/handshaker/alts_tsi_event.h
+  - src/core/tsi/alts/handshaker/alts_tsi_handshaker.h
+  - src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h
+  - src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h
+  - src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h
+  - src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h
+  - src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h
+  - src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h
+  - src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h
+  src:
+  - src/core/tsi/alts/crypt/aes_gcm.cc
+  - src/core/tsi/alts/crypt/gsec.cc
+  - src/core/tsi/alts/frame_protector/alts_counter.cc
+  - src/core/tsi/alts/frame_protector/alts_crypter.cc
+  - src/core/tsi/alts/frame_protector/alts_frame_protector.cc
+  - src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc
+  - src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc
+  - src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc
+  - src/core/tsi/alts/frame_protector/frame_handler.cc
+  - src/core/tsi/alts/handshaker/alts_handshaker_client.cc
+  - src/core/tsi/alts/handshaker/alts_tsi_event.cc
+  - src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc
+  - src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc
+  - src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc
+  - src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc
+  - src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc
+  - src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc
+  uses:
+  - alts_util
+  - grpc_base
+  - grpc_transport_chttp2_client_insecure
+  - tsi_interface
+  - tsi
+- name: alts_util
+  headers:
+  - src/core/lib/security/credentials/alts/check_gcp_environment.h
+  - src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h
+  - src/core/tsi/alts/handshaker/alts_handshaker_service_api.h
+  - src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h
+  - src/core/tsi/alts/handshaker/alts_tsi_utils.h
+  - src/core/tsi/alts/handshaker/transport_security_common_api.h
+  src:
+  - src/core/lib/security/credentials/alts/check_gcp_environment.cc
+  - src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc
+  - src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc
+  - src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc
+  - src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc
+  - src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc
+  - src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc
+  - src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc
+  - src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc
+  - src/core/tsi/alts/handshaker/alts_tsi_utils.cc
+  - src/core/tsi/alts/handshaker/transport_security_common_api.cc
+  uses:
+  - alts_proto
+  - grpc_base
+  - tsi_interface
+  - nanopb
 - name: census
   public_headers:
   - include/grpc/census.h
@@ -24,13 +102,18 @@
   uses:
   - grpc_base
   - nanopb
+- name: cmdline
+  headers:
+  - test/core/util/cmdline.h
+  src:
+  - test/core/util/cmdline.cc
+  uses:
+  - gpr_base_headers
 - name: gpr_base
   src:
   - src/core/lib/gpr/alloc.cc
   - src/core/lib/gpr/arena.cc
   - src/core/lib/gpr/atm.cc
-  - src/core/lib/gpr/avl.cc
-  - src/core/lib/gpr/cmdline.cc
   - src/core/lib/gpr/cpu_iphone.cc
   - src/core/lib/gpr/cpu_linux.cc
   - src/core/lib/gpr/cpu_posix.cc
@@ -51,14 +134,9 @@
   - src/core/lib/gpr/string_posix.cc
   - src/core/lib/gpr/string_util_windows.cc
   - src/core/lib/gpr/string_windows.cc
-  - src/core/lib/gpr/subprocess_posix.cc
-  - src/core/lib/gpr/subprocess_windows.cc
   - src/core/lib/gpr/sync.cc
   - src/core/lib/gpr/sync_posix.cc
   - src/core/lib/gpr/sync_windows.cc
-  - src/core/lib/gpr/thd.cc
-  - src/core/lib/gpr/thd_posix.cc
-  - src/core/lib/gpr/thd_windows.cc
   - src/core/lib/gpr/time.cc
   - src/core/lib/gpr/time_posix.cc
   - src/core/lib/gpr/time_precise.cc
@@ -68,6 +146,8 @@
   - src/core/lib/gpr/tmpfile_posix.cc
   - src/core/lib/gpr/tmpfile_windows.cc
   - src/core/lib/gpr/wrap_memcpy.cc
+  - src/core/lib/gprpp/thd_posix.cc
+  - src/core/lib/gprpp/thd_windows.cc
   - src/core/lib/profiling/basic_timers.cc
   - src/core/lib/profiling/stap_timers.cc
   uses:
@@ -79,45 +159,42 @@
   - include/grpc/support/atm_gcc_atomic.h
   - include/grpc/support/atm_gcc_sync.h
   - include/grpc/support/atm_windows.h
-  - include/grpc/support/avl.h
-  - include/grpc/support/cmdline.h
   - include/grpc/support/cpu.h
-  - include/grpc/support/host_port.h
   - include/grpc/support/log.h
   - include/grpc/support/log_windows.h
   - include/grpc/support/port_platform.h
   - include/grpc/support/string_util.h
-  - include/grpc/support/subprocess.h
   - include/grpc/support/sync.h
   - include/grpc/support/sync_custom.h
   - include/grpc/support/sync_generic.h
   - include/grpc/support/sync_posix.h
   - include/grpc/support/sync_windows.h
-  - include/grpc/support/thd.h
+  - include/grpc/support/thd_id.h
   - include/grpc/support/time.h
-  - include/grpc/support/tls.h
-  - include/grpc/support/tls_gcc.h
-  - include/grpc/support/tls_msvc.h
-  - include/grpc/support/tls_pthread.h
-  - include/grpc/support/useful.h
   headers:
   - src/core/lib/gpr/arena.h
   - src/core/lib/gpr/env.h
   - src/core/lib/gpr/fork.h
+  - src/core/lib/gpr/host_port.h
   - src/core/lib/gpr/mpscq.h
   - src/core/lib/gpr/murmur_hash.h
   - src/core/lib/gpr/spinlock.h
   - src/core/lib/gpr/string.h
   - src/core/lib/gpr/string_windows.h
-  - src/core/lib/gpr/thd_internal.h
   - src/core/lib/gpr/time_precise.h
+  - src/core/lib/gpr/tls.h
+  - src/core/lib/gpr/tls_gcc.h
+  - src/core/lib/gpr/tls_msvc.h
+  - src/core/lib/gpr/tls_pthread.h
   - src/core/lib/gpr/tmpfile.h
+  - src/core/lib/gpr/useful.h
   - src/core/lib/gprpp/abstract.h
   - src/core/lib/gprpp/atomic.h
   - src/core/lib/gprpp/atomic_with_atm.h
   - src/core/lib/gprpp/atomic_with_std.h
   - src/core/lib/gprpp/manual_constructor.h
   - src/core/lib/gprpp/memory.h
+  - src/core/lib/gprpp/thd.h
   - src/core/lib/profiling/timers.h
   uses:
   - gpr_codegen
@@ -150,17 +227,20 @@
   - grpc++_codegen_base
 - name: grpc_base
   src:
+  - src/core/lib/avl/avl.cc
   - src/core/lib/backoff/backoff.cc
   - src/core/lib/channel/channel_args.cc
   - src/core/lib/channel/channel_stack.cc
   - src/core/lib/channel/channel_stack_builder.cc
+  - src/core/lib/channel/channel_trace.cc
+  - src/core/lib/channel/channel_trace_registry.cc
   - src/core/lib/channel/connected_channel.cc
   - src/core/lib/channel/handshaker.cc
   - src/core/lib/channel/handshaker_factory.cc
   - src/core/lib/channel/handshaker_registry.cc
+  - src/core/lib/channel/status_util.cc
   - src/core/lib/compression/compression.cc
   - src/core/lib/compression/compression_internal.cc
-  - src/core/lib/compression/compression_ruby.cc
   - src/core/lib/compression/message_compress.cc
   - src/core/lib/compression/stream_compression.cc
   - src/core/lib/compression/stream_compression_gzip.cc
@@ -192,6 +272,8 @@
   - src/core/lib/iomgr/gethostname_sysconf.cc
   - src/core/lib/iomgr/iocp_windows.cc
   - src/core/lib/iomgr/iomgr.cc
+  - src/core/lib/iomgr/iomgr_custom.cc
+  - src/core/lib/iomgr/iomgr_internal.cc
   - src/core/lib/iomgr/iomgr_posix.cc
   - src/core/lib/iomgr/iomgr_uv.cc
   - src/core/lib/iomgr/iomgr_windows.cc
@@ -200,12 +282,16 @@
   - src/core/lib/iomgr/lockfree_event.cc
   - src/core/lib/iomgr/network_status_tracker.cc
   - src/core/lib/iomgr/polling_entity.cc
-  - src/core/lib/iomgr/pollset_set_uv.cc
+  - src/core/lib/iomgr/pollset.cc
+  - src/core/lib/iomgr/pollset_custom.cc
+  - src/core/lib/iomgr/pollset_set.cc
+  - src/core/lib/iomgr/pollset_set_custom.cc
   - src/core/lib/iomgr/pollset_set_windows.cc
   - src/core/lib/iomgr/pollset_uv.cc
   - src/core/lib/iomgr/pollset_windows.cc
+  - src/core/lib/iomgr/resolve_address.cc
+  - src/core/lib/iomgr/resolve_address_custom.cc
   - src/core/lib/iomgr/resolve_address_posix.cc
-  - src/core/lib/iomgr/resolve_address_uv.cc
   - src/core/lib/iomgr/resolve_address_windows.cc
   - src/core/lib/iomgr/resource_quota.cc
   - src/core/lib/iomgr/sockaddr_utils.cc
@@ -217,19 +303,24 @@
   - src/core/lib/iomgr/socket_utils_uv.cc
   - src/core/lib/iomgr/socket_utils_windows.cc
   - src/core/lib/iomgr/socket_windows.cc
+  - src/core/lib/iomgr/tcp_client.cc
+  - src/core/lib/iomgr/tcp_client_custom.cc
   - src/core/lib/iomgr/tcp_client_posix.cc
-  - src/core/lib/iomgr/tcp_client_uv.cc
   - src/core/lib/iomgr/tcp_client_windows.cc
+  - src/core/lib/iomgr/tcp_custom.cc
   - src/core/lib/iomgr/tcp_posix.cc
+  - src/core/lib/iomgr/tcp_server.cc
+  - src/core/lib/iomgr/tcp_server_custom.cc
   - src/core/lib/iomgr/tcp_server_posix.cc
   - src/core/lib/iomgr/tcp_server_utils_posix_common.cc
   - src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc
   - src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc
-  - src/core/lib/iomgr/tcp_server_uv.cc
   - src/core/lib/iomgr/tcp_server_windows.cc
   - src/core/lib/iomgr/tcp_uv.cc
   - src/core/lib/iomgr/tcp_windows.cc
   - src/core/lib/iomgr/time_averaged_stats.cc
+  - src/core/lib/iomgr/timer.cc
+  - src/core/lib/iomgr/timer_custom.cc
   - src/core/lib/iomgr/timer_generic.cc
   - src/core/lib/iomgr/timer_heap.cc
   - src/core/lib/iomgr/timer_manager.cc
@@ -250,7 +341,6 @@
   - src/core/lib/slice/percent_encoding.cc
   - src/core/lib/slice/slice.cc
   - src/core/lib/slice/slice_buffer.cc
-  - src/core/lib/slice/slice_hash_table.cc
   - src/core/lib/slice/slice_intern.cc
   - src/core/lib/slice/slice_string_helpers.cc
   - src/core/lib/surface/api_trace.cc
@@ -281,6 +371,7 @@
   - src/core/lib/transport/service_config.cc
   - src/core/lib/transport/static_metadata.cc
   - src/core/lib/transport/status_conversion.cc
+  - src/core/lib/transport/status_metadata.cc
   - src/core/lib/transport/timeout_encoding.cc
   - src/core/lib/transport/transport.cc
   - src/core/lib/transport/transport_op_string.cc
@@ -296,7 +387,6 @@
   - include/grpc/byte_buffer.h
   - include/grpc/byte_buffer_reader.h
   - include/grpc/compression.h
-  - include/grpc/compression_ruby.h
   - include/grpc/fork.h
   - include/grpc/grpc.h
   - include/grpc/grpc_posix.h
@@ -307,15 +397,19 @@
   - include/grpc/status.h
   - include/grpc/support/workaround_list.h
   headers:
+  - src/core/lib/avl/avl.h
   - src/core/lib/backoff/backoff.h
   - src/core/lib/channel/channel_args.h
   - src/core/lib/channel/channel_stack.h
   - src/core/lib/channel/channel_stack_builder.h
+  - src/core/lib/channel/channel_trace.h
+  - src/core/lib/channel/channel_trace_registry.h
   - src/core/lib/channel/connected_channel.h
   - src/core/lib/channel/context.h
   - src/core/lib/channel/handshaker.h
   - src/core/lib/channel/handshaker_factory.h
   - src/core/lib/channel/handshaker_registry.h
+  - src/core/lib/channel/status_util.h
   - src/core/lib/compression/algorithm_metadata.h
   - src/core/lib/compression/compression_internal.h
   - src/core/lib/compression/message_compress.h
@@ -350,9 +444,9 @@
   - src/core/lib/iomgr/gethostname.h
   - src/core/lib/iomgr/iocp_windows.h
   - src/core/lib/iomgr/iomgr.h
+  - src/core/lib/iomgr/iomgr_custom.h
   - src/core/lib/iomgr/iomgr_internal.h
   - src/core/lib/iomgr/iomgr_posix.h
-  - src/core/lib/iomgr/iomgr_uv.h
   - src/core/lib/iomgr/is_epollexclusive_available.h
   - src/core/lib/iomgr/load_file.h
   - src/core/lib/iomgr/lockfree_event.h
@@ -360,14 +454,17 @@
   - src/core/lib/iomgr/network_status_tracker.h
   - src/core/lib/iomgr/polling_entity.h
   - src/core/lib/iomgr/pollset.h
+  - src/core/lib/iomgr/pollset_custom.h
   - src/core/lib/iomgr/pollset_set.h
+  - src/core/lib/iomgr/pollset_set_custom.h
   - src/core/lib/iomgr/pollset_set_windows.h
-  - src/core/lib/iomgr/pollset_uv.h
   - src/core/lib/iomgr/pollset_windows.h
   - src/core/lib/iomgr/port.h
   - src/core/lib/iomgr/resolve_address.h
+  - src/core/lib/iomgr/resolve_address_custom.h
   - src/core/lib/iomgr/resource_quota.h
   - src/core/lib/iomgr/sockaddr.h
+  - src/core/lib/iomgr/sockaddr_custom.h
   - src/core/lib/iomgr/sockaddr_posix.h
   - src/core/lib/iomgr/sockaddr_utils.h
   - src/core/lib/iomgr/sockaddr_windows.h
@@ -379,17 +476,16 @@
   - src/core/lib/iomgr/sys_epoll_wrapper.h
   - src/core/lib/iomgr/tcp_client.h
   - src/core/lib/iomgr/tcp_client_posix.h
+  - src/core/lib/iomgr/tcp_custom.h
   - src/core/lib/iomgr/tcp_posix.h
   - src/core/lib/iomgr/tcp_server.h
   - src/core/lib/iomgr/tcp_server_utils_posix.h
-  - src/core/lib/iomgr/tcp_uv.h
   - src/core/lib/iomgr/tcp_windows.h
   - src/core/lib/iomgr/time_averaged_stats.h
   - src/core/lib/iomgr/timer.h
-  - src/core/lib/iomgr/timer_generic.h
+  - src/core/lib/iomgr/timer_custom.h
   - src/core/lib/iomgr/timer_heap.h
   - src/core/lib/iomgr/timer_manager.h
-  - src/core/lib/iomgr/timer_uv.h
   - src/core/lib/iomgr/udp_server.h
   - src/core/lib/iomgr/unix_sockets_posix.h
   - src/core/lib/iomgr/wakeup_fd_cv.h
@@ -404,6 +500,7 @@
   - src/core/lib/slice/slice_hash_table.h
   - src/core/lib/slice/slice_internal.h
   - src/core/lib/slice/slice_string_helpers.h
+  - src/core/lib/slice/slice_weak_hash_table.h
   - src/core/lib/surface/api_trace.h
   - src/core/lib/surface/call.h
   - src/core/lib/surface/call_test_only.h
@@ -428,6 +525,7 @@
   - src/core/lib/transport/service_config.h
   - src/core/lib/transport/static_metadata.h
   - src/core/lib/transport/status_conversion.h
+  - src/core/lib/transport/status_metadata.h
   - src/core/lib/transport/timeout_encoding.h
   - src/core/lib/transport/transport.h
   - src/core/lib/transport/transport_impl.h
@@ -447,6 +545,7 @@
   - src/core/ext/filters/client_channel/lb_policy.h
   - src/core/ext/filters/client_channel/lb_policy_factory.h
   - src/core/ext/filters/client_channel/lb_policy_registry.h
+  - src/core/ext/filters/client_channel/method_params.h
   - src/core/ext/filters/client_channel/parse_address.h
   - src/core/ext/filters/client_channel/proxy_mapper.h
   - src/core/ext/filters/client_channel/proxy_mapper_registry.h
@@ -469,11 +568,11 @@
   - src/core/ext/filters/client_channel/lb_policy.cc
   - src/core/ext/filters/client_channel/lb_policy_factory.cc
   - src/core/ext/filters/client_channel/lb_policy_registry.cc
+  - src/core/ext/filters/client_channel/method_params.cc
   - src/core/ext/filters/client_channel/parse_address.cc
   - src/core/ext/filters/client_channel/proxy_mapper.cc
   - src/core/ext/filters/client_channel/proxy_mapper_registry.cc
   - src/core/ext/filters/client_channel/resolver.cc
-  - src/core/ext/filters/client_channel/resolver_factory.cc
   - src/core/ext/filters/client_channel/resolver_registry.cc
   - src/core/ext/filters/client_channel/retry_throttle.cc
   - src/core/ext/filters/client_channel/subchannel.cc
@@ -519,7 +618,6 @@
 - name: grpc_lb_policy_grpclb
   headers:
   - src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h
-  - src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h
   - src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
   - src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h
   - src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
@@ -540,7 +638,6 @@
 - name: grpc_lb_policy_grpclb_secure
   headers:
   - src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h
-  - src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h
   - src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
   - src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h
   - src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
@@ -640,6 +737,7 @@
   - include/grpc/grpc_security.h
   headers:
   - src/core/lib/security/context/security_context.h
+  - src/core/lib/security/credentials/alts/alts_credentials.h
   - src/core/lib/security/credentials/composite/composite_credentials.h
   - src/core/lib/security/credentials/credentials.h
   - src/core/lib/security/credentials/fake/fake_credentials.h
@@ -651,16 +749,18 @@
   - src/core/lib/security/credentials/oauth2/oauth2_credentials.h
   - src/core/lib/security/credentials/plugin/plugin_credentials.h
   - src/core/lib/security/credentials/ssl/ssl_credentials.h
+  - src/core/lib/security/security_connector/alts_security_connector.h
+  - src/core/lib/security/security_connector/security_connector.h
   - src/core/lib/security/transport/auth_filters.h
-  - src/core/lib/security/transport/lb_targets_info.h
   - src/core/lib/security/transport/secure_endpoint.h
-  - src/core/lib/security/transport/security_connector.h
   - src/core/lib/security/transport/security_handshaker.h
+  - src/core/lib/security/transport/target_authority_table.h
   - src/core/lib/security/transport/tsi_error.h
   - src/core/lib/security/util/json_util.h
   src:
   - src/core/lib/http/httpcli_security_connector.cc
   - src/core/lib/security/context/security_context.cc
+  - src/core/lib/security/credentials/alts/alts_credentials.cc
   - src/core/lib/security/credentials/composite/composite_credentials.cc
   - src/core/lib/security/credentials/credentials.cc
   - src/core/lib/security/credentials/credentials_metadata.cc
@@ -674,17 +774,19 @@
   - src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
   - src/core/lib/security/credentials/plugin/plugin_credentials.cc
   - src/core/lib/security/credentials/ssl/ssl_credentials.cc
+  - src/core/lib/security/security_connector/alts_security_connector.cc
+  - src/core/lib/security/security_connector/security_connector.cc
   - src/core/lib/security/transport/client_auth_filter.cc
-  - src/core/lib/security/transport/lb_targets_info.cc
   - src/core/lib/security/transport/secure_endpoint.cc
-  - src/core/lib/security/transport/security_connector.cc
   - src/core/lib/security/transport/security_handshaker.cc
   - src/core/lib/security/transport/server_auth_filter.cc
+  - src/core/lib/security/transport/target_authority_table.cc
   - src/core/lib/security/transport/tsi_error.cc
   - src/core/lib/security/util/json_util.cc
   - src/core/lib/surface/init_secure.cc
   secure: true
   uses:
+  - alts_tsi
   - grpc_base
   - grpc_transport_chttp2_alpn
   - tsi
@@ -723,6 +825,7 @@
   - test/core/util/port.h
   - test/core/util/port_server_client.h
   - test/core/util/slice_splitter.h
+  - test/core/util/subprocess.h
   - test/core/util/tracer_util.h
   - test/core/util/trickle_endpoint.h
   src:
@@ -742,12 +845,15 @@
   - test/core/util/port_isolated_runtime_environment.cc
   - test/core/util/port_server_client.cc
   - test/core/util/slice_splitter.cc
+  - test/core/util/subprocess_posix.cc
+  - test/core/util/subprocess_windows.cc
   - test/core/util/tracer_util.cc
   - test/core/util/trickle_endpoint.cc
   deps:
   - gpr_test_util
   - gpr
   uses:
+  - cmdline
   - grpc_base
   - grpc_client_channel
   - grpc_transport_chttp2
@@ -935,12 +1041,17 @@
   headers:
   - src/core/tsi/alts_transport_security.h
   - src/core/tsi/fake_transport_security.h
+  - src/core/tsi/ssl/session_cache/ssl_session.h
+  - src/core/tsi/ssl/session_cache/ssl_session_cache.h
   - src/core/tsi/ssl_transport_security.h
   - src/core/tsi/ssl_types.h
   - src/core/tsi/transport_security_grpc.h
   src:
   - src/core/tsi/alts_transport_security.cc
   - src/core/tsi/fake_transport_security.cc
+  - src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc
+  - src/core/tsi/ssl/session_cache/ssl_session_cache.cc
+  - src/core/tsi/ssl/session_cache/ssl_session_openssl.cc
   - src/core/tsi/ssl_transport_security.cc
   - src/core/tsi/transport_security_grpc.cc
   deps:
@@ -964,6 +1075,10 @@
   secure: true
   uses:
   - grpc_trace
+- name: grpc++_channelz_proto
+  language: c++
+  src:
+  - src/proto/grpc/channelz/channelz.proto
 - name: grpc++_codegen_base
   language: c++
   public_headers:
@@ -997,6 +1112,36 @@
   - include/grpc++/impl/codegen/stub_options.h
   - include/grpc++/impl/codegen/sync_stream.h
   - include/grpc++/impl/codegen/time.h
+  - include/grpcpp/impl/codegen/async_stream.h
+  - include/grpcpp/impl/codegen/async_unary_call.h
+  - include/grpcpp/impl/codegen/byte_buffer.h
+  - include/grpcpp/impl/codegen/call.h
+  - include/grpcpp/impl/codegen/call_hook.h
+  - include/grpcpp/impl/codegen/channel_interface.h
+  - include/grpcpp/impl/codegen/client_context.h
+  - include/grpcpp/impl/codegen/client_unary_call.h
+  - include/grpcpp/impl/codegen/completion_queue.h
+  - include/grpcpp/impl/codegen/completion_queue_tag.h
+  - include/grpcpp/impl/codegen/config.h
+  - include/grpcpp/impl/codegen/core_codegen_interface.h
+  - include/grpcpp/impl/codegen/create_auth_context.h
+  - include/grpcpp/impl/codegen/grpc_library.h
+  - include/grpcpp/impl/codegen/metadata_map.h
+  - include/grpcpp/impl/codegen/method_handler_impl.h
+  - include/grpcpp/impl/codegen/rpc_method.h
+  - include/grpcpp/impl/codegen/rpc_service_method.h
+  - include/grpcpp/impl/codegen/security/auth_context.h
+  - include/grpcpp/impl/codegen/serialization_traits.h
+  - include/grpcpp/impl/codegen/server_context.h
+  - include/grpcpp/impl/codegen/server_interface.h
+  - include/grpcpp/impl/codegen/service_type.h
+  - include/grpcpp/impl/codegen/slice.h
+  - include/grpcpp/impl/codegen/status.h
+  - include/grpcpp/impl/codegen/status_code_enum.h
+  - include/grpcpp/impl/codegen/string_ref.h
+  - include/grpcpp/impl/codegen/stub_options.h
+  - include/grpcpp/impl/codegen/sync_stream.h
+  - include/grpcpp/impl/codegen/time.h
   uses:
   - grpc_codegen
 - name: grpc++_codegen_base_src
@@ -1009,6 +1154,7 @@
   language: c++
   public_headers:
   - include/grpc++/impl/codegen/proto_utils.h
+  - include/grpcpp/impl/codegen/proto_utils.h
   uses:
   - grpc++_codegen_base
   - grpc++_config_proto
@@ -1060,6 +1206,51 @@
   - include/grpc++/support/stub_options.h
   - include/grpc++/support/sync_stream.h
   - include/grpc++/support/time.h
+  - include/grpcpp/alarm.h
+  - include/grpcpp/channel.h
+  - include/grpcpp/client_context.h
+  - include/grpcpp/completion_queue.h
+  - include/grpcpp/create_channel.h
+  - include/grpcpp/create_channel_posix.h
+  - include/grpcpp/ext/health_check_service_server_builder_option.h
+  - include/grpcpp/generic/async_generic_service.h
+  - include/grpcpp/generic/generic_stub.h
+  - include/grpcpp/grpcpp.h
+  - include/grpcpp/health_check_service_interface.h
+  - include/grpcpp/impl/call.h
+  - include/grpcpp/impl/channel_argument_option.h
+  - include/grpcpp/impl/client_unary_call.h
+  - include/grpcpp/impl/codegen/core_codegen.h
+  - include/grpcpp/impl/grpc_library.h
+  - include/grpcpp/impl/method_handler_impl.h
+  - include/grpcpp/impl/rpc_method.h
+  - include/grpcpp/impl/rpc_service_method.h
+  - include/grpcpp/impl/serialization_traits.h
+  - include/grpcpp/impl/server_builder_option.h
+  - include/grpcpp/impl/server_builder_plugin.h
+  - include/grpcpp/impl/server_initializer.h
+  - include/grpcpp/impl/service_type.h
+  - include/grpcpp/resource_quota.h
+  - include/grpcpp/security/auth_context.h
+  - include/grpcpp/security/auth_metadata_processor.h
+  - include/grpcpp/security/credentials.h
+  - include/grpcpp/security/server_credentials.h
+  - include/grpcpp/server.h
+  - include/grpcpp/server_builder.h
+  - include/grpcpp/server_context.h
+  - include/grpcpp/server_posix.h
+  - include/grpcpp/support/async_stream.h
+  - include/grpcpp/support/async_unary_call.h
+  - include/grpcpp/support/byte_buffer.h
+  - include/grpcpp/support/channel_arguments.h
+  - include/grpcpp/support/config.h
+  - include/grpcpp/support/slice.h
+  - include/grpcpp/support/status.h
+  - include/grpcpp/support/status_code_enum.h
+  - include/grpcpp/support/string_ref.h
+  - include/grpcpp/support/stub_options.h
+  - include/grpcpp/support/sync_stream.h
+  - include/grpcpp/support/time.h
   headers:
   - src/cpp/client/create_channel_internal.h
   - src/cpp/common/channel_filter.h
@@ -1113,6 +1304,7 @@
   language: c++
   public_headers:
   - include/grpc++/impl/codegen/config_protobuf.h
+  - include/grpcpp/impl/codegen/config_protobuf.h
 - name: grpc++_reflection_proto
   language: c++
   src:
@@ -1122,10 +1314,35 @@
   public_headers:
   - include/grpc++/test/mock_stream.h
   - include/grpc++/test/server_context_test_spouse.h
+  - include/grpcpp/test/mock_stream.h
+  - include/grpcpp/test/server_context_test_spouse.h
   deps:
   - grpc++
   - grpc
 libs:
+- name: address_sorting
+  build: all
+  language: c
+  headers:
+  - third_party/address_sorting/address_sorting_internal.h
+  - third_party/address_sorting/include/address_sorting/address_sorting.h
+  src:
+  - third_party/address_sorting/address_sorting.c
+  - third_party/address_sorting/address_sorting_posix.c
+  - third_party/address_sorting/address_sorting_windows.c
+  secure: false
+- name: alts_test_util
+  build: private
+  language: c
+  headers:
+  - test/core/tsi/alts/crypt/gsec_test_util.h
+  - test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.h
+  src:
+  - test/core/tsi/alts/crypt/gsec_test_util.cc
+  - test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.cc
+  deps:
+  - grpc
+  secure: true
 - name: gpr
   build: all
   language: c
@@ -1190,9 +1407,17 @@
   dll: true
   filegroups:
   - grpc_base
+  - grpc_base_headers
+  - grpc_deadline_filter
+  - grpc_lb_policy_pick_first
+  - grpc_max_age_filter
+  - grpc_message_size_filter
+  - grpc_resolver_dns_native
+  - grpc_resolver_sockaddr
+  - grpc_server_load_reporting
   - grpc_transport_cronet_client_secure
   - grpc_transport_chttp2_client_secure
-  - grpc_server_load_reporting
+  - grpc_transport_chttp2_server_secure
   generate_plugin_registry: true
   platforms:
   - linux
@@ -1309,6 +1534,7 @@
   language: c++
   headers:
   - include/grpc++/impl/codegen/core_codegen.h
+  - include/grpcpp/impl/codegen/core_codegen.h
   - src/cpp/client/secure_credentials.h
   - src/cpp/common/secure_auth_context.h
   - src/cpp/server/secure_server_credentials.h
@@ -1370,6 +1596,7 @@
   language: c++
   public_headers:
   - include/grpc++/support/error_details.h
+  - include/grpcpp/support/error_details.h
   src:
   - src/proto/grpc/status/status.proto
   - src/cpp/util/error_details.cc
@@ -1395,6 +1622,7 @@
   language: c++
   public_headers:
   - include/grpc++/ext/proto_server_reflection_plugin.h
+  - include/grpcpp/ext/proto_server_reflection_plugin.h
   headers:
   - src/cpp/ext/proto_server_reflection.h
   src:
@@ -1418,17 +1646,20 @@
   headers:
   - test/cpp/end2end/test_service_impl.h
   - test/cpp/util/byte_buffer_proto_helper.h
+  - test/cpp/util/channel_trace_proto_helper.h
   - test/cpp/util/create_test_channel.h
   - test/cpp/util/string_ref_helper.h
   - test/cpp/util/subprocess.h
   - test/cpp/util/test_credentials_provider.h
   src:
+  - src/proto/grpc/channelz/channelz.proto
   - src/proto/grpc/health/v1/health.proto
   - src/proto/grpc/testing/echo_messages.proto
   - src/proto/grpc/testing/echo.proto
   - src/proto/grpc/testing/duplicate/echo_duplicate.proto
   - test/cpp/end2end/test_service_impl.cc
   - test/cpp/util/byte_buffer_proto_helper.cc
+  - test/cpp/util/channel_trace_proto_helper.cc
   - test/cpp/util/create_test_channel.cc
   - test/cpp/util/string_ref_helper.cc
   - test/cpp/util/subprocess.cc
@@ -1762,6 +1993,16 @@
   - gpr_test_util
   - gpr
   uses_polling: false
+- name: avl_test
+  build: test
+  language: c
+  src:
+  - test/core/avl/avl_test.cc
+  deps:
+  - gpr_test_util
+  - gpr
+  - grpc
+  uses_polling: false
 - name: bad_server_response_test
   build: test
   language: c
@@ -1793,17 +2034,6 @@
   - grpc_test_util
   - grpc
   uses_polling: false
-- name: byte_stream_test
-  build: test
-  language: c
-  src:
-  - test/core/transport/byte_stream_test.cc
-  deps:
-  - grpc_test_util
-  - grpc
-  - gpr_test_util
-  - gpr
-  uses_polling: false
 - name: channel_create_test
   build: test
   language: c
@@ -1869,6 +2099,16 @@
   - test/core/end2end/fuzzers/client_fuzzer_corpus
   dict: test/core/end2end/fuzzers/hpack.dictionary
   maxlen: 2048
+- name: cmdline_test
+  build: test
+  language: c
+  src:
+  - test/core/util/cmdline_test.cc
+  deps:
+  - gpr
+  - gpr_test_util
+  - grpc_test_util
+  uses_polling: false
 - name: combiner_test
   cpu_cost: 10
   build: test
@@ -2130,24 +2370,6 @@
   - mac
   - linux
   - posix
-- name: gpr_avl_test
-  build: test
-  language: c
-  src:
-  - test/core/gpr/avl_test.cc
-  deps:
-  - gpr_test_util
-  - gpr
-  uses_polling: false
-- name: gpr_cmdline_test
-  build: test
-  language: c
-  src:
-  - test/core/gpr/cmdline_test.cc
-  deps:
-  - gpr_test_util
-  - gpr
-  uses_polling: false
 - name: gpr_cpu_test
   cpu_cost: 30
   build: test
@@ -2239,7 +2461,7 @@
   build: test
   language: c
   src:
-  - test/core/gpr/thd_test.cc
+  - test/core/gprpp/thd_test.cc
   deps:
   - gpr_test_util
   - gpr
@@ -2366,6 +2588,8 @@
   deps:
   - grpc
   - gpr
+  filegroups:
+  - cmdline
   secure: true
   uses_polling: false
 - name: grpc_credentials_test
@@ -2434,6 +2658,8 @@
   deps:
   - grpc
   - gpr
+  filegroups:
+  - cmdline
   uses_polling: false
 - name: grpc_security_connector_test
   build: test
@@ -2463,6 +2689,8 @@
   deps:
   - grpc
   - gpr
+  filegroups:
+  - cmdline
   uses_polling: false
 - name: handshake_client
   build: test
@@ -2677,7 +2905,9 @@
   src:
   - test/core/json/json_rewrite.cc
   deps:
+  - grpc_test_util
   - grpc
+  - gpr_test_util
   - gpr
   uses_polling: false
 - name: json_rewrite_test
@@ -3054,17 +3284,6 @@
   - gpr_test_util
   - gpr
   uses_polling: false
-- name: slice_hash_table_test
-  build: test
-  language: c
-  src:
-  - test/core/slice/slice_hash_table_test.cc
-  deps:
-  - grpc_test_util
-  - grpc
-  - gpr_test_util
-  - gpr
-  uses_polling: false
 - name: slice_string_helpers_test
   build: test
   language: c
@@ -3409,6 +3628,125 @@
   - grpc_unsecure
   - gpr_test_util
   - gpr
+- name: alts_counter_test
+  build: test
+  language: c++
+  src:
+  - test/core/tsi/alts/frame_protector/alts_counter_test.cc
+  deps:
+  - alts_test_util
+  - gpr
+  - grpc
+- name: alts_crypt_test
+  build: test
+  language: c++
+  src:
+  - test/core/tsi/alts/crypt/aes_gcm_test.cc
+  deps:
+  - alts_test_util
+  - gpr_test_util
+  - gpr
+  - grpc
+- name: alts_crypter_test
+  build: test
+  language: c++
+  src:
+  - test/core/tsi/alts/frame_protector/alts_crypter_test.cc
+  deps:
+  - alts_test_util
+  - gpr
+  - grpc
+- name: alts_frame_handler_test
+  build: test
+  language: c++
+  src:
+  - test/core/tsi/alts/frame_protector/frame_handler_test.cc
+  deps:
+  - alts_test_util
+  - gpr
+  - grpc
+- name: alts_frame_protector_test
+  build: test
+  language: c++
+  src:
+  - test/core/tsi/alts/frame_protector/alts_frame_protector_test.cc
+  deps:
+  - alts_test_util
+  - gpr
+  - grpc
+  filegroups:
+  - transport_security_test_lib
+- name: alts_grpc_record_protocol_test
+  build: test
+  language: c++
+  src:
+  - test/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_test.cc
+  deps:
+  - alts_test_util
+  - gpr
+  - grpc
+- name: alts_handshaker_client_test
+  build: test
+  language: c++
+  src:
+  - test/core/tsi/alts/handshaker/alts_handshaker_client_test.cc
+  deps:
+  - alts_test_util
+  - gpr
+  - grpc
+- name: alts_handshaker_service_api_test
+  build: test
+  language: c++
+  src:
+  - test/core/tsi/alts/handshaker/alts_handshaker_service_api_test.cc
+  deps:
+  - alts_test_util
+  - gpr
+  - grpc
+- name: alts_iovec_record_protocol_test
+  build: test
+  language: c++
+  src:
+  - test/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol_test.cc
+  deps:
+  - alts_test_util
+  - gpr
+  - grpc
+- name: alts_security_connector_test
+  build: test
+  language: c++
+  src:
+  - test/core/security/alts_security_connector_test.cc
+  deps:
+  - gpr
+  - grpc
+- name: alts_tsi_handshaker_test
+  build: test
+  language: c++
+  src:
+  - test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc
+  deps:
+  - alts_test_util
+  - gpr
+  - grpc
+- name: alts_tsi_utils_test
+  build: test
+  language: c++
+  src:
+  - test/core/tsi/alts/handshaker/alts_tsi_utils_test.cc
+  deps:
+  - alts_test_util
+  - gpr
+  - grpc
+- name: alts_zero_copy_grpc_protector_test
+  build: test
+  language: c++
+  src:
+  - test/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector_test.cc
+  deps:
+  - alts_test_util
+  - gpr
+  - grpc
 - name: async_end2end_test
   gtest: true
   build: test
@@ -3770,6 +4108,18 @@
   - mac
   - linux
   - posix
+- name: byte_stream_test
+  gtest: true
+  build: test
+  language: c++
+  src:
+  - test/core/transport/byte_stream_test.cc
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
+  uses_polling: false
 - name: channel_arguments_test
   gtest: true
   build: test
@@ -3792,6 +4142,40 @@
   - grpc
   - gpr
   uses_polling: false
+- name: channel_trace_test
+  gtest: true
+  build: test
+  language: c++
+  src:
+  - test/core/channel/channel_trace_test.cc
+  deps:
+  - grpc_test_util
+  - grpc++_test_util
+  - grpc++
+  - grpc
+  - gpr_test_util
+  - gpr
+  filegroups:
+  - grpc++_channelz_proto
+  uses:
+  - grpc++_test
+  uses_polling: false
+- name: check_gcp_environment_linux_test
+  build: test
+  language: c++
+  src:
+  - test/core/security/check_gcp_environment_linux_test.cc
+  deps:
+  - grpc
+  - gpr
+- name: check_gcp_environment_windows_test
+  build: test
+  language: c++
+  src:
+  - test/core/security/check_gcp_environment_windows_test.cc
+  deps:
+  - grpc
+  - gpr
 - name: chttp2_settings_timeout_test
   gtest: true
   build: test
@@ -4050,6 +4434,14 @@
   args:
   - --generated_file_path=gens/src/proto/grpc/testing/
   uses_polling: false
+- name: grpc_alts_credentials_options_test
+  build: test
+  language: c++
+  src:
+  - test/core/security/grpc_alts_credentials_options_test.cc
+  deps:
+  - grpc
+  - gpr
 - name: grpc_cli
   build: test
   run: false
@@ -4177,20 +4569,6 @@
   - grpc
   - gpr_test_util
   - gpr
-- name: grpclb_test
-  gtest: false
-  build: test
-  language: c++
-  src:
-  - src/proto/grpc/lb/v1/load_balancer.proto
-  - test/cpp/grpclb/grpclb_test.cc
-  deps:
-  - grpc++_test_util
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr_test_util
-  - gpr
 - name: h2_ssl_cert_test
   gtest: true
   build: test
@@ -4207,6 +4585,22 @@
   - gpr
   uses:
   - grpc++_test
+- name: h2_ssl_session_reuse_test
+  gtest: true
+  build: test
+  language: c++
+  headers:
+  - test/core/end2end/end2end_tests.h
+  src:
+  - test/core/end2end/h2_ssl_session_reuse_test.cc
+  deps:
+  - grpc_test_util
+  - grpc++
+  - grpc
+  - gpr_test_util
+  - gpr
+  uses:
+  - grpc++_test
 - name: health_service_end2end_test
   gtest: true
   build: test
@@ -4390,6 +4784,7 @@
   language: c++
   headers:
   - include/grpc++/test/mock_stream.h
+  - include/grpcpp/test/mock_stream.h
   src:
   - test/cpp/end2end/mock_test.cc
   deps:
@@ -4399,6 +4794,19 @@
   - grpc
   - gpr_test_util
   - gpr
+- name: nonblocking_test
+  gtest: true
+  build: test
+  language: c++
+  src:
+  - test/cpp/end2end/nonblocking_test.cc
+  deps:
+  - grpc++_test_util
+  - grpc_test_util
+  - grpc++
+  - grpc
+  - gpr_test_util
+  - gpr
 - name: noop-benchmark
   build: test
   language: c++
@@ -4734,6 +5142,30 @@
   - grpc
   - gpr_test_util
   - gpr
+- name: slice_hash_table_test
+  gtest: true
+  build: test
+  language: c++
+  src:
+  - test/core/slice/slice_hash_table_test.cc
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
+  uses_polling: false
+- name: slice_weak_hash_table_test
+  gtest: true
+  build: test
+  language: c++
+  src:
+  - test/core/slice/slice_weak_hash_table_test.cc
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
+  uses_polling: false
 - name: stats_test
   gtest: true
   build: test
@@ -4750,17 +5182,24 @@
   - tsan
   timeout_seconds: 1200
   uses_polling: false
-- name: status_test
+- name: status_metadata_test
+  gtest: true
   build: test
   language: c++
   src:
-  - test/cpp/util/status_test.cc
+  - test/core/transport/status_metadata_test.cc
   deps:
-  - grpc_test_util
-  - grpc++
   - grpc
-  - gpr_test_util
-  - gpr
+  uses_polling: false
+- name: status_util_test
+  gtest: true
+  cpu_cost: 0.1
+  build: test
+  language: c++
+  src:
+  - test/core/channel/status_util_test.cc
+  deps:
+  - grpc
   uses_polling: false
 - name: streaming_throughput_test
   gtest: true
@@ -4842,6 +5281,15 @@
   - grpc
   - gpr_test_util
   - gpr
+- name: transport_security_common_api_test
+  build: test
+  language: c++
+  src:
+  - test/core/tsi/alts/handshaker/transport_security_common_api_test.cc
+  deps:
+  - alts_test_util
+  - gpr
+  - grpc
 - name: writes_per_rpc_test
   gtest: true
   cpu_cost: 0.5
@@ -4998,11 +5446,11 @@
     DEFINES: NDEBUG
     LDFLAGS: -rdynamic
   noexcept:
-    CPPFLAGS: -O2
+    CPPFLAGS: -O2 -Wframe-larger-than=16384
     CXXFLAGS: -fno-exceptions
     DEFINES: NDEBUG
   opt:
-    CPPFLAGS: -O2
+    CPPFLAGS: -O2 -Wframe-larger-than=16384
     DEFINES: NDEBUG
   stapprof:
     CPPFLAGS: -O2 -DGRPC_STAP_PROFILER
@@ -5067,6 +5515,7 @@
   - gpr
   - boringssl
   - z
+  - address_sorting
   headers:
   - src/php/ext/grpc/byte_buffer.h
   - src/php/ext/grpc/call.h
@@ -5098,6 +5547,7 @@
   - ares
   - boringssl
   - z
+  - address_sorting
 ruby_gem:
   deps:
   - grpc
@@ -5105,3 +5555,4 @@
   - ares
   - boringssl
   - z
+  - address_sorting
diff --git a/tools/dockerfile/distribtest/ruby_ubuntu1510_x64/Dockerfile b/cmake/address_sorting.cmake
similarity index 73%
rename from tools/dockerfile/distribtest/ruby_ubuntu1510_x64/Dockerfile
rename to cmake/address_sorting.cmake
index 1fc7820..f7203b3 100644
--- a/tools/dockerfile/distribtest/ruby_ubuntu1510_x64/Dockerfile
+++ b/cmake/address_sorting.cmake
@@ -1,4 +1,4 @@
-# Copyright 2015 gRPC authors.
+# Copyright 2017 gRPC authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -12,8 +12,5 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM ubuntu:15.10
-
-RUN apt-get update -y && apt-get install -y ruby-full
-
-RUN gem install bundler
+set(_gRPC_ADDRESS_SORTING_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/address_sorting/include")
+set(_gRPC_ADDRESS_SORTING_LIBRARIES address_sorting)
diff --git a/cmake/benchmark.cmake b/cmake/benchmark.cmake
index 753dc06..2b4c20f 100644
--- a/cmake/benchmark.cmake
+++ b/cmake/benchmark.cmake
@@ -26,11 +26,12 @@
       message(WARNING "gRPC_BENCHMARK_PROVIDER is \"module\" but BENCHMARK_ROOT_DIR is wrong")
   endif()
 elseif("${gRPC_BENCHMARK_PROVIDER}" STREQUAL "package")
-  find_package(benchmark REQUIRED)
+  # Use "CONFIG" as there is no built-in cmake module for benchmark.
+  find_package(benchmark REQUIRED CONFIG)
   if(TARGET benchmark::benchmark)
     set(_gRPC_BENCHMARK_LIBRARIES benchmark::benchmark)
     # extract the include dir from target's properties
     get_target_property(_gRPC_BENCHMARK_INCLUDE_DIR benchmark::benchmark INTERFACE_INCLUDE_DIRECTORIES)
   endif()
-  set(_gRPC_FIND_BENCHMARK "if(NOT benchmark_FOUND)\n  find_package(benchmark)\nendif()")
+  set(_gRPC_FIND_BENCHMARK "if(NOT benchmark_FOUND)\n  find_package(benchmark CONFIG)\nendif()")
 endif()
diff --git a/cmake/cares.cmake b/cmake/cares.cmake
index 53d7582..3d4a0ca 100644
--- a/cmake/cares.cmake
+++ b/cmake/cares.cmake
@@ -30,6 +30,7 @@
     set(gRPC_INSTALL FALSE)
   endif()
 elseif("${gRPC_CARES_PROVIDER}" STREQUAL "package")
+  # Use "CONFIG" as there is no built-in cmake module for c-ares.
   find_package(c-ares REQUIRED CONFIG)
   if(TARGET c-ares::cares)
     set(_gRPC_CARES_LIBRARIES c-ares::cares)
diff --git a/cmake/gflags.cmake b/cmake/gflags.cmake
index f86a141..01e0a75 100644
--- a/cmake/gflags.cmake
+++ b/cmake/gflags.cmake
@@ -26,10 +26,11 @@
     message(WARNING "gRPC_GFLAGS_PROVIDER is \"module\" but GFLAGS_ROOT_DIR is wrong")
   endif()
 elseif("${gRPC_GFLAGS_PROVIDER}" STREQUAL "package")
-  find_package(gflags REQUIRED)
+  # Use "CONFIG" as there is no built-in cmake module for gflags.
+  find_package(gflags REQUIRED CONFIG)
   if(TARGET gflags::gflags)
     set(_gRPC_GFLAGS_LIBRARIES gflags::gflags)
     set(_gRPC_GFLAGS_INCLUDE_DIR ${GFLAGS_INCLUDE_DIR})
   endif()
-  set(_gRPC_FIND_GFLAGS "if(NOT gflags_FOUND)\n  find_package(gflags)\nendif()")
+  set(_gRPC_FIND_GFLAGS "if(NOT gflags_FOUND)\n  find_package(gflags CONFIG)\nendif()")
 endif()
diff --git a/cmake/ssl.cmake b/cmake/ssl.cmake
index 75ce069..83f642a 100644
--- a/cmake/ssl.cmake
+++ b/cmake/ssl.cmake
@@ -31,8 +31,18 @@
     set(gRPC_INSTALL FALSE)
   endif()
 elseif("${gRPC_SSL_PROVIDER}" STREQUAL "package")
+  # OpenSSL installation directory can be configured by setting OPENSSL_ROOT_DIR
+  # We expect to locate OpenSSL using the built-in cmake module as the openssl
+  # project itself does not provide installation support in its CMakeLists.txt
+  # See https://cmake.org/cmake/help/v3.6/module/FindOpenSSL.html
   find_package(OpenSSL REQUIRED)
-  set(_gRPC_SSL_LIBRARIES ${OPENSSL_LIBRARIES})
+  
+  if(TARGET OpenSSL::SSL)
+    set(_gRPC_SSL_LIBRARIES OpenSSL::SSL OpenSSL::Crypto)
+  else()
+    set(_gRPC_SSL_LIBRARIES ${OPENSSL_LIBRARIES})
+  endif()
   set(_gRPC_SSL_INCLUDE_DIR ${OPENSSL_INCLUDE_DIR})
+  
   set(_gRPC_FIND_SSL "if(NOT OPENSSL_FOUND)\n  find_package(OpenSSL)\nendif()")
 endif()
diff --git a/cmake/zlib.cmake b/cmake/zlib.cmake
index 4a9d2f0..ed7c9c2 100644
--- a/cmake/zlib.cmake
+++ b/cmake/zlib.cmake
@@ -33,8 +33,19 @@
     set(gRPC_INSTALL FALSE)
   endif()
 elseif("${gRPC_ZLIB_PROVIDER}" STREQUAL "package")
+  # zlib installation directory can be configured by setting ZLIB_ROOT
+  # We allow locating zlib using both "CONFIG" and "MODULE" as the expectation
+  # is that many Linux systems will have zlib installed via a distribution
+  # package ("MODULE"), while on Windows the user is likely to have installed
+  # zlib using cmake ("CONFIG").
+  # See https://cmake.org/cmake/help/v3.6/module/FindZLIB.html
   find_package(ZLIB REQUIRED)
-  set(_gRPC_ZLIB_LIBRARIES ${ZLIB_LIBRARIES})
+
+  if(TARGET ZLIB::ZLIB)
+    set(_gRPC_ZLIB_LIBRARIES ZLIB::ZLIB)
+  else()
+    set(_gRPC_ZLIB_LIBRARIES ${ZLIB_LIBRARIES})
+  endif()
   set(_gRPC_ZLIB_INCLUDE_DIR ${ZLIB_INCLUDE_DIRS})
   set(_gRPC_FIND_ZLIB "if(NOT ZLIB_FOUND)\n  find_package(ZLIB)\nendif()")
 endif()
diff --git a/config.m4 b/config.m4
index c60c252..d7cda0b 100644
--- a/config.m4
+++ b/config.m4
@@ -11,8 +11,8 @@
 
   LIBS="-lpthread $LIBS"
 
-  CFLAGS="-Wall -Werror -Wno-parentheses-equality -Wno-unused-value -std=c11"
-  CXXFLAGS="-std=c++11 -fno-exceptions -fno-rtti"
+  CFLAGS="-Wall -Werror -Wno-parentheses-equality -Wno-unused-value -std=c11 -g -O2 -D PB_FIELD_16BIT=1"
+  CXXFLAGS="-std=c++11 -fno-exceptions -fno-rtti -g -O2 -D PB_FIELD_16BIT=1"
   GRPC_SHARED_LIBADD="-lpthread $GRPC_SHARED_LIBADD"
   PHP_REQUIRE_CXX()
   PHP_ADD_LIBRARY(pthread)
@@ -39,11 +39,12 @@
     src/php/ext/grpc/server.c \
     src/php/ext/grpc/server_credentials.c \
     src/php/ext/grpc/timeval.c \
+    third_party/address_sorting/address_sorting.c \
+    third_party/address_sorting/address_sorting_posix.c \
+    third_party/address_sorting/address_sorting_windows.c \
     src/core/lib/gpr/alloc.cc \
     src/core/lib/gpr/arena.cc \
     src/core/lib/gpr/atm.cc \
-    src/core/lib/gpr/avl.cc \
-    src/core/lib/gpr/cmdline.cc \
     src/core/lib/gpr/cpu_iphone.cc \
     src/core/lib/gpr/cpu_linux.cc \
     src/core/lib/gpr/cpu_posix.cc \
@@ -64,14 +65,9 @@
     src/core/lib/gpr/string_posix.cc \
     src/core/lib/gpr/string_util_windows.cc \
     src/core/lib/gpr/string_windows.cc \
-    src/core/lib/gpr/subprocess_posix.cc \
-    src/core/lib/gpr/subprocess_windows.cc \
     src/core/lib/gpr/sync.cc \
     src/core/lib/gpr/sync_posix.cc \
     src/core/lib/gpr/sync_windows.cc \
-    src/core/lib/gpr/thd.cc \
-    src/core/lib/gpr/thd_posix.cc \
-    src/core/lib/gpr/thd_windows.cc \
     src/core/lib/gpr/time.cc \
     src/core/lib/gpr/time_posix.cc \
     src/core/lib/gpr/time_precise.cc \
@@ -81,20 +77,25 @@
     src/core/lib/gpr/tmpfile_posix.cc \
     src/core/lib/gpr/tmpfile_windows.cc \
     src/core/lib/gpr/wrap_memcpy.cc \
+    src/core/lib/gprpp/thd_posix.cc \
+    src/core/lib/gprpp/thd_windows.cc \
     src/core/lib/profiling/basic_timers.cc \
     src/core/lib/profiling/stap_timers.cc \
     src/core/lib/surface/init.cc \
+    src/core/lib/avl/avl.cc \
     src/core/lib/backoff/backoff.cc \
     src/core/lib/channel/channel_args.cc \
     src/core/lib/channel/channel_stack.cc \
     src/core/lib/channel/channel_stack_builder.cc \
+    src/core/lib/channel/channel_trace.cc \
+    src/core/lib/channel/channel_trace_registry.cc \
     src/core/lib/channel/connected_channel.cc \
     src/core/lib/channel/handshaker.cc \
     src/core/lib/channel/handshaker_factory.cc \
     src/core/lib/channel/handshaker_registry.cc \
+    src/core/lib/channel/status_util.cc \
     src/core/lib/compression/compression.cc \
     src/core/lib/compression/compression_internal.cc \
-    src/core/lib/compression/compression_ruby.cc \
     src/core/lib/compression/message_compress.cc \
     src/core/lib/compression/stream_compression.cc \
     src/core/lib/compression/stream_compression_gzip.cc \
@@ -126,6 +127,8 @@
     src/core/lib/iomgr/gethostname_sysconf.cc \
     src/core/lib/iomgr/iocp_windows.cc \
     src/core/lib/iomgr/iomgr.cc \
+    src/core/lib/iomgr/iomgr_custom.cc \
+    src/core/lib/iomgr/iomgr_internal.cc \
     src/core/lib/iomgr/iomgr_posix.cc \
     src/core/lib/iomgr/iomgr_uv.cc \
     src/core/lib/iomgr/iomgr_windows.cc \
@@ -134,12 +137,16 @@
     src/core/lib/iomgr/lockfree_event.cc \
     src/core/lib/iomgr/network_status_tracker.cc \
     src/core/lib/iomgr/polling_entity.cc \
-    src/core/lib/iomgr/pollset_set_uv.cc \
+    src/core/lib/iomgr/pollset.cc \
+    src/core/lib/iomgr/pollset_custom.cc \
+    src/core/lib/iomgr/pollset_set.cc \
+    src/core/lib/iomgr/pollset_set_custom.cc \
     src/core/lib/iomgr/pollset_set_windows.cc \
     src/core/lib/iomgr/pollset_uv.cc \
     src/core/lib/iomgr/pollset_windows.cc \
+    src/core/lib/iomgr/resolve_address.cc \
+    src/core/lib/iomgr/resolve_address_custom.cc \
     src/core/lib/iomgr/resolve_address_posix.cc \
-    src/core/lib/iomgr/resolve_address_uv.cc \
     src/core/lib/iomgr/resolve_address_windows.cc \
     src/core/lib/iomgr/resource_quota.cc \
     src/core/lib/iomgr/sockaddr_utils.cc \
@@ -151,19 +158,24 @@
     src/core/lib/iomgr/socket_utils_uv.cc \
     src/core/lib/iomgr/socket_utils_windows.cc \
     src/core/lib/iomgr/socket_windows.cc \
+    src/core/lib/iomgr/tcp_client.cc \
+    src/core/lib/iomgr/tcp_client_custom.cc \
     src/core/lib/iomgr/tcp_client_posix.cc \
-    src/core/lib/iomgr/tcp_client_uv.cc \
     src/core/lib/iomgr/tcp_client_windows.cc \
+    src/core/lib/iomgr/tcp_custom.cc \
     src/core/lib/iomgr/tcp_posix.cc \
+    src/core/lib/iomgr/tcp_server.cc \
+    src/core/lib/iomgr/tcp_server_custom.cc \
     src/core/lib/iomgr/tcp_server_posix.cc \
     src/core/lib/iomgr/tcp_server_utils_posix_common.cc \
     src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc \
     src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc \
-    src/core/lib/iomgr/tcp_server_uv.cc \
     src/core/lib/iomgr/tcp_server_windows.cc \
     src/core/lib/iomgr/tcp_uv.cc \
     src/core/lib/iomgr/tcp_windows.cc \
     src/core/lib/iomgr/time_averaged_stats.cc \
+    src/core/lib/iomgr/timer.cc \
+    src/core/lib/iomgr/timer_custom.cc \
     src/core/lib/iomgr/timer_generic.cc \
     src/core/lib/iomgr/timer_heap.cc \
     src/core/lib/iomgr/timer_manager.cc \
@@ -184,7 +196,6 @@
     src/core/lib/slice/percent_encoding.cc \
     src/core/lib/slice/slice.cc \
     src/core/lib/slice/slice_buffer.cc \
-    src/core/lib/slice/slice_hash_table.cc \
     src/core/lib/slice/slice_intern.cc \
     src/core/lib/slice/slice_string_helpers.cc \
     src/core/lib/surface/api_trace.cc \
@@ -215,6 +226,7 @@
     src/core/lib/transport/service_config.cc \
     src/core/lib/transport/static_metadata.cc \
     src/core/lib/transport/status_conversion.cc \
+    src/core/lib/transport/status_metadata.cc \
     src/core/lib/transport/timeout_encoding.cc \
     src/core/lib/transport/transport.cc \
     src/core/lib/transport/transport_op_string.cc \
@@ -249,6 +261,7 @@
     src/core/ext/filters/http/server/http_server_filter.cc \
     src/core/lib/http/httpcli_security_connector.cc \
     src/core/lib/security/context/security_context.cc \
+    src/core/lib/security/credentials/alts/alts_credentials.cc \
     src/core/lib/security/credentials/composite/composite_credentials.cc \
     src/core/lib/security/credentials/credentials.cc \
     src/core/lib/security/credentials/credentials_metadata.cc \
@@ -262,23 +275,55 @@
     src/core/lib/security/credentials/oauth2/oauth2_credentials.cc \
     src/core/lib/security/credentials/plugin/plugin_credentials.cc \
     src/core/lib/security/credentials/ssl/ssl_credentials.cc \
+    src/core/lib/security/security_connector/alts_security_connector.cc \
+    src/core/lib/security/security_connector/security_connector.cc \
     src/core/lib/security/transport/client_auth_filter.cc \
-    src/core/lib/security/transport/lb_targets_info.cc \
     src/core/lib/security/transport/secure_endpoint.cc \
-    src/core/lib/security/transport/security_connector.cc \
     src/core/lib/security/transport/security_handshaker.cc \
     src/core/lib/security/transport/server_auth_filter.cc \
+    src/core/lib/security/transport/target_authority_table.cc \
     src/core/lib/security/transport/tsi_error.cc \
     src/core/lib/security/util/json_util.cc \
     src/core/lib/surface/init_secure.cc \
-    src/core/tsi/alts_transport_security.cc \
-    src/core/tsi/fake_transport_security.cc \
-    src/core/tsi/ssl_transport_security.cc \
-    src/core/tsi/transport_security_grpc.cc \
+    src/core/tsi/alts/crypt/aes_gcm.cc \
+    src/core/tsi/alts/crypt/gsec.cc \
+    src/core/tsi/alts/frame_protector/alts_counter.cc \
+    src/core/tsi/alts/frame_protector/alts_crypter.cc \
+    src/core/tsi/alts/frame_protector/alts_frame_protector.cc \
+    src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc \
+    src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc \
+    src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc \
+    src/core/tsi/alts/frame_protector/frame_handler.cc \
+    src/core/tsi/alts/handshaker/alts_handshaker_client.cc \
+    src/core/tsi/alts/handshaker/alts_tsi_event.cc \
+    src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc \
+    src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc \
+    src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc \
+    src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc \
+    src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc \
+    src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc \
+    src/core/lib/security/credentials/alts/check_gcp_environment.cc \
+    src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc \
+    src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc \
+    src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc \
+    src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc \
+    src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc \
+    src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc \
+    src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc \
+    src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc \
+    src/core/tsi/alts/handshaker/alts_tsi_utils.cc \
+    src/core/tsi/alts/handshaker/transport_security_common_api.cc \
+    src/core/tsi/alts/handshaker/altscontext.pb.c \
+    src/core/tsi/alts/handshaker/handshaker.pb.c \
+    src/core/tsi/alts/handshaker/transport_security_common.pb.c \
+    third_party/nanopb/pb_common.c \
+    third_party/nanopb/pb_decode.c \
+    third_party/nanopb/pb_encode.c \
     src/core/tsi/transport_security.cc \
     src/core/tsi/transport_security_adapter.cc \
-    src/core/ext/transport/chttp2/server/chttp2_server.cc \
-    src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc \
+    src/core/ext/transport/chttp2/client/insecure/channel_create.cc \
+    src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc \
+    src/core/ext/transport/chttp2/client/chttp2_connector.cc \
     src/core/ext/filters/client_channel/backup_poller.cc \
     src/core/ext/filters/client_channel/channel_connectivity.cc \
     src/core/ext/filters/client_channel/client_channel.cc \
@@ -290,22 +335,28 @@
     src/core/ext/filters/client_channel/lb_policy.cc \
     src/core/ext/filters/client_channel/lb_policy_factory.cc \
     src/core/ext/filters/client_channel/lb_policy_registry.cc \
+    src/core/ext/filters/client_channel/method_params.cc \
     src/core/ext/filters/client_channel/parse_address.cc \
     src/core/ext/filters/client_channel/proxy_mapper.cc \
     src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
     src/core/ext/filters/client_channel/resolver.cc \
-    src/core/ext/filters/client_channel/resolver_factory.cc \
     src/core/ext/filters/client_channel/resolver_registry.cc \
     src/core/ext/filters/client_channel/retry_throttle.cc \
     src/core/ext/filters/client_channel/subchannel.cc \
     src/core/ext/filters/client_channel/subchannel_index.cc \
     src/core/ext/filters/client_channel/uri_parser.cc \
     src/core/ext/filters/deadline/deadline_filter.cc \
-    src/core/ext/transport/chttp2/client/chttp2_connector.cc \
+    src/core/tsi/alts_transport_security.cc \
+    src/core/tsi/fake_transport_security.cc \
+    src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc \
+    src/core/tsi/ssl/session_cache/ssl_session_cache.cc \
+    src/core/tsi/ssl/session_cache/ssl_session_openssl.cc \
+    src/core/tsi/ssl_transport_security.cc \
+    src/core/tsi/transport_security_grpc.cc \
+    src/core/ext/transport/chttp2/server/chttp2_server.cc \
+    src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc \
     src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc \
     src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc \
-    src/core/ext/transport/chttp2/client/insecure/channel_create.cc \
-    src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc \
     src/core/ext/transport/inproc/inproc_plugin.cc \
     src/core/ext/transport/inproc/inproc_transport.cc \
     src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc \
@@ -314,9 +365,6 @@
     src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc \
     src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc \
     src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
-    third_party/nanopb/pb_common.c \
-    third_party/nanopb/pb_decode.c \
-    third_party/nanopb/pb_encode.c \
     src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \
     src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
     src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc \
@@ -404,7 +452,6 @@
     third_party/boringssl/crypto/cpu-intel.c \
     third_party/boringssl/crypto/cpu-ppc64le.c \
     third_party/boringssl/crypto/crypto.c \
-    third_party/boringssl/crypto/curve25519/curve25519.c \
     third_party/boringssl/crypto/curve25519/spake25519.c \
     third_party/boringssl/crypto/curve25519/x25519-x86_64.c \
     third_party/boringssl/crypto/dh/check.c \
@@ -590,6 +637,7 @@
     third_party/boringssl/ssl/tls13_server.cc \
     third_party/boringssl/ssl/tls_method.cc \
     third_party/boringssl/ssl/tls_record.cc \
+    third_party/boringssl/third_party/fiat/curve25519.c \
     , $ext_shared, , -fvisibility=hidden \
     -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN \
     -D_HAS_EXCEPTIONS=0 -DNOMINMAX -DGRPC_ARES=0)
@@ -626,17 +674,20 @@
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/server/secure)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/transport)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/inproc)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/avl)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/backoff)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/channel)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/compression)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/debug)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/gpr)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/gprpp)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/http)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/iomgr)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/json)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/profiling)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/context)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/credentials)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/credentials/alts)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/credentials/composite)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/credentials/fake)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/credentials/google_default)
@@ -645,6 +696,7 @@
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/credentials/oauth2)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/credentials/plugin)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/credentials/ssl)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/security_connector)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/transport)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/util)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/slice)
@@ -652,6 +704,12 @@
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/transport)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/plugin_registry)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi/alts/crypt)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi/alts/frame_protector)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi/alts/handshaker)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi/alts/zero_copy_frame_protector)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi/ssl/session_cache)
+  PHP_ADD_BUILD_DIR($ext_builddir/third_party/address_sorting)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/asn1)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/base64)
@@ -689,5 +747,6 @@
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/x509)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/x509v3)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/ssl)
+  PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/third_party/fiat)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/nanopb)
 fi
diff --git a/config.w32 b/config.w32
index 888596b..5e80781 100644
--- a/config.w32
+++ b/config.w32
@@ -16,11 +16,12 @@
     "src\\php\\ext\\grpc\\server.c " +
     "src\\php\\ext\\grpc\\server_credentials.c " +
     "src\\php\\ext\\grpc\\timeval.c " +
+    "third_party\\address_sorting\\address_sorting.c " +
+    "third_party\\address_sorting\\address_sorting_posix.c " +
+    "third_party\\address_sorting\\address_sorting_windows.c " +
     "src\\core\\lib\\gpr\\alloc.cc " +
     "src\\core\\lib\\gpr\\arena.cc " +
     "src\\core\\lib\\gpr\\atm.cc " +
-    "src\\core\\lib\\gpr\\avl.cc " +
-    "src\\core\\lib\\gpr\\cmdline.cc " +
     "src\\core\\lib\\gpr\\cpu_iphone.cc " +
     "src\\core\\lib\\gpr\\cpu_linux.cc " +
     "src\\core\\lib\\gpr\\cpu_posix.cc " +
@@ -41,14 +42,9 @@
     "src\\core\\lib\\gpr\\string_posix.cc " +
     "src\\core\\lib\\gpr\\string_util_windows.cc " +
     "src\\core\\lib\\gpr\\string_windows.cc " +
-    "src\\core\\lib\\gpr\\subprocess_posix.cc " +
-    "src\\core\\lib\\gpr\\subprocess_windows.cc " +
     "src\\core\\lib\\gpr\\sync.cc " +
     "src\\core\\lib\\gpr\\sync_posix.cc " +
     "src\\core\\lib\\gpr\\sync_windows.cc " +
-    "src\\core\\lib\\gpr\\thd.cc " +
-    "src\\core\\lib\\gpr\\thd_posix.cc " +
-    "src\\core\\lib\\gpr\\thd_windows.cc " +
     "src\\core\\lib\\gpr\\time.cc " +
     "src\\core\\lib\\gpr\\time_posix.cc " +
     "src\\core\\lib\\gpr\\time_precise.cc " +
@@ -58,20 +54,25 @@
     "src\\core\\lib\\gpr\\tmpfile_posix.cc " +
     "src\\core\\lib\\gpr\\tmpfile_windows.cc " +
     "src\\core\\lib\\gpr\\wrap_memcpy.cc " +
+    "src\\core\\lib\\gprpp\\thd_posix.cc " +
+    "src\\core\\lib\\gprpp\\thd_windows.cc " +
     "src\\core\\lib\\profiling\\basic_timers.cc " +
     "src\\core\\lib\\profiling\\stap_timers.cc " +
     "src\\core\\lib\\surface\\init.cc " +
+    "src\\core\\lib\\avl\\avl.cc " +
     "src\\core\\lib\\backoff\\backoff.cc " +
     "src\\core\\lib\\channel\\channel_args.cc " +
     "src\\core\\lib\\channel\\channel_stack.cc " +
     "src\\core\\lib\\channel\\channel_stack_builder.cc " +
+    "src\\core\\lib\\channel\\channel_trace.cc " +
+    "src\\core\\lib\\channel\\channel_trace_registry.cc " +
     "src\\core\\lib\\channel\\connected_channel.cc " +
     "src\\core\\lib\\channel\\handshaker.cc " +
     "src\\core\\lib\\channel\\handshaker_factory.cc " +
     "src\\core\\lib\\channel\\handshaker_registry.cc " +
+    "src\\core\\lib\\channel\\status_util.cc " +
     "src\\core\\lib\\compression\\compression.cc " +
     "src\\core\\lib\\compression\\compression_internal.cc " +
-    "src\\core\\lib\\compression\\compression_ruby.cc " +
     "src\\core\\lib\\compression\\message_compress.cc " +
     "src\\core\\lib\\compression\\stream_compression.cc " +
     "src\\core\\lib\\compression\\stream_compression_gzip.cc " +
@@ -103,6 +104,8 @@
     "src\\core\\lib\\iomgr\\gethostname_sysconf.cc " +
     "src\\core\\lib\\iomgr\\iocp_windows.cc " +
     "src\\core\\lib\\iomgr\\iomgr.cc " +
+    "src\\core\\lib\\iomgr\\iomgr_custom.cc " +
+    "src\\core\\lib\\iomgr\\iomgr_internal.cc " +
     "src\\core\\lib\\iomgr\\iomgr_posix.cc " +
     "src\\core\\lib\\iomgr\\iomgr_uv.cc " +
     "src\\core\\lib\\iomgr\\iomgr_windows.cc " +
@@ -111,12 +114,16 @@
     "src\\core\\lib\\iomgr\\lockfree_event.cc " +
     "src\\core\\lib\\iomgr\\network_status_tracker.cc " +
     "src\\core\\lib\\iomgr\\polling_entity.cc " +
-    "src\\core\\lib\\iomgr\\pollset_set_uv.cc " +
+    "src\\core\\lib\\iomgr\\pollset.cc " +
+    "src\\core\\lib\\iomgr\\pollset_custom.cc " +
+    "src\\core\\lib\\iomgr\\pollset_set.cc " +
+    "src\\core\\lib\\iomgr\\pollset_set_custom.cc " +
     "src\\core\\lib\\iomgr\\pollset_set_windows.cc " +
     "src\\core\\lib\\iomgr\\pollset_uv.cc " +
     "src\\core\\lib\\iomgr\\pollset_windows.cc " +
+    "src\\core\\lib\\iomgr\\resolve_address.cc " +
+    "src\\core\\lib\\iomgr\\resolve_address_custom.cc " +
     "src\\core\\lib\\iomgr\\resolve_address_posix.cc " +
-    "src\\core\\lib\\iomgr\\resolve_address_uv.cc " +
     "src\\core\\lib\\iomgr\\resolve_address_windows.cc " +
     "src\\core\\lib\\iomgr\\resource_quota.cc " +
     "src\\core\\lib\\iomgr\\sockaddr_utils.cc " +
@@ -128,19 +135,24 @@
     "src\\core\\lib\\iomgr\\socket_utils_uv.cc " +
     "src\\core\\lib\\iomgr\\socket_utils_windows.cc " +
     "src\\core\\lib\\iomgr\\socket_windows.cc " +
+    "src\\core\\lib\\iomgr\\tcp_client.cc " +
+    "src\\core\\lib\\iomgr\\tcp_client_custom.cc " +
     "src\\core\\lib\\iomgr\\tcp_client_posix.cc " +
-    "src\\core\\lib\\iomgr\\tcp_client_uv.cc " +
     "src\\core\\lib\\iomgr\\tcp_client_windows.cc " +
+    "src\\core\\lib\\iomgr\\tcp_custom.cc " +
     "src\\core\\lib\\iomgr\\tcp_posix.cc " +
+    "src\\core\\lib\\iomgr\\tcp_server.cc " +
+    "src\\core\\lib\\iomgr\\tcp_server_custom.cc " +
     "src\\core\\lib\\iomgr\\tcp_server_posix.cc " +
     "src\\core\\lib\\iomgr\\tcp_server_utils_posix_common.cc " +
     "src\\core\\lib\\iomgr\\tcp_server_utils_posix_ifaddrs.cc " +
     "src\\core\\lib\\iomgr\\tcp_server_utils_posix_noifaddrs.cc " +
-    "src\\core\\lib\\iomgr\\tcp_server_uv.cc " +
     "src\\core\\lib\\iomgr\\tcp_server_windows.cc " +
     "src\\core\\lib\\iomgr\\tcp_uv.cc " +
     "src\\core\\lib\\iomgr\\tcp_windows.cc " +
     "src\\core\\lib\\iomgr\\time_averaged_stats.cc " +
+    "src\\core\\lib\\iomgr\\timer.cc " +
+    "src\\core\\lib\\iomgr\\timer_custom.cc " +
     "src\\core\\lib\\iomgr\\timer_generic.cc " +
     "src\\core\\lib\\iomgr\\timer_heap.cc " +
     "src\\core\\lib\\iomgr\\timer_manager.cc " +
@@ -161,7 +173,6 @@
     "src\\core\\lib\\slice\\percent_encoding.cc " +
     "src\\core\\lib\\slice\\slice.cc " +
     "src\\core\\lib\\slice\\slice_buffer.cc " +
-    "src\\core\\lib\\slice\\slice_hash_table.cc " +
     "src\\core\\lib\\slice\\slice_intern.cc " +
     "src\\core\\lib\\slice\\slice_string_helpers.cc " +
     "src\\core\\lib\\surface\\api_trace.cc " +
@@ -192,6 +203,7 @@
     "src\\core\\lib\\transport\\service_config.cc " +
     "src\\core\\lib\\transport\\static_metadata.cc " +
     "src\\core\\lib\\transport\\status_conversion.cc " +
+    "src\\core\\lib\\transport\\status_metadata.cc " +
     "src\\core\\lib\\transport\\timeout_encoding.cc " +
     "src\\core\\lib\\transport\\transport.cc " +
     "src\\core\\lib\\transport\\transport_op_string.cc " +
@@ -226,6 +238,7 @@
     "src\\core\\ext\\filters\\http\\server\\http_server_filter.cc " +
     "src\\core\\lib\\http\\httpcli_security_connector.cc " +
     "src\\core\\lib\\security\\context\\security_context.cc " +
+    "src\\core\\lib\\security\\credentials\\alts\\alts_credentials.cc " +
     "src\\core\\lib\\security\\credentials\\composite\\composite_credentials.cc " +
     "src\\core\\lib\\security\\credentials\\credentials.cc " +
     "src\\core\\lib\\security\\credentials\\credentials_metadata.cc " +
@@ -239,23 +252,55 @@
     "src\\core\\lib\\security\\credentials\\oauth2\\oauth2_credentials.cc " +
     "src\\core\\lib\\security\\credentials\\plugin\\plugin_credentials.cc " +
     "src\\core\\lib\\security\\credentials\\ssl\\ssl_credentials.cc " +
+    "src\\core\\lib\\security\\security_connector\\alts_security_connector.cc " +
+    "src\\core\\lib\\security\\security_connector\\security_connector.cc " +
     "src\\core\\lib\\security\\transport\\client_auth_filter.cc " +
-    "src\\core\\lib\\security\\transport\\lb_targets_info.cc " +
     "src\\core\\lib\\security\\transport\\secure_endpoint.cc " +
-    "src\\core\\lib\\security\\transport\\security_connector.cc " +
     "src\\core\\lib\\security\\transport\\security_handshaker.cc " +
     "src\\core\\lib\\security\\transport\\server_auth_filter.cc " +
+    "src\\core\\lib\\security\\transport\\target_authority_table.cc " +
     "src\\core\\lib\\security\\transport\\tsi_error.cc " +
     "src\\core\\lib\\security\\util\\json_util.cc " +
     "src\\core\\lib\\surface\\init_secure.cc " +
-    "src\\core\\tsi\\alts_transport_security.cc " +
-    "src\\core\\tsi\\fake_transport_security.cc " +
-    "src\\core\\tsi\\ssl_transport_security.cc " +
-    "src\\core\\tsi\\transport_security_grpc.cc " +
+    "src\\core\\tsi\\alts\\crypt\\aes_gcm.cc " +
+    "src\\core\\tsi\\alts\\crypt\\gsec.cc " +
+    "src\\core\\tsi\\alts\\frame_protector\\alts_counter.cc " +
+    "src\\core\\tsi\\alts\\frame_protector\\alts_crypter.cc " +
+    "src\\core\\tsi\\alts\\frame_protector\\alts_frame_protector.cc " +
+    "src\\core\\tsi\\alts\\frame_protector\\alts_record_protocol_crypter_common.cc " +
+    "src\\core\\tsi\\alts\\frame_protector\\alts_seal_privacy_integrity_crypter.cc " +
+    "src\\core\\tsi\\alts\\frame_protector\\alts_unseal_privacy_integrity_crypter.cc " +
+    "src\\core\\tsi\\alts\\frame_protector\\frame_handler.cc " +
+    "src\\core\\tsi\\alts\\handshaker\\alts_handshaker_client.cc " +
+    "src\\core\\tsi\\alts\\handshaker\\alts_tsi_event.cc " +
+    "src\\core\\tsi\\alts\\handshaker\\alts_tsi_handshaker.cc " +
+    "src\\core\\tsi\\alts\\zero_copy_frame_protector\\alts_grpc_integrity_only_record_protocol.cc " +
+    "src\\core\\tsi\\alts\\zero_copy_frame_protector\\alts_grpc_privacy_integrity_record_protocol.cc " +
+    "src\\core\\tsi\\alts\\zero_copy_frame_protector\\alts_grpc_record_protocol_common.cc " +
+    "src\\core\\tsi\\alts\\zero_copy_frame_protector\\alts_iovec_record_protocol.cc " +
+    "src\\core\\tsi\\alts\\zero_copy_frame_protector\\alts_zero_copy_grpc_protector.cc " +
+    "src\\core\\lib\\security\\credentials\\alts\\check_gcp_environment.cc " +
+    "src\\core\\lib\\security\\credentials\\alts\\check_gcp_environment_linux.cc " +
+    "src\\core\\lib\\security\\credentials\\alts\\check_gcp_environment_no_op.cc " +
+    "src\\core\\lib\\security\\credentials\\alts\\check_gcp_environment_windows.cc " +
+    "src\\core\\lib\\security\\credentials\\alts\\grpc_alts_credentials_client_options.cc " +
+    "src\\core\\lib\\security\\credentials\\alts\\grpc_alts_credentials_options.cc " +
+    "src\\core\\lib\\security\\credentials\\alts\\grpc_alts_credentials_server_options.cc " +
+    "src\\core\\tsi\\alts\\handshaker\\alts_handshaker_service_api.cc " +
+    "src\\core\\tsi\\alts\\handshaker\\alts_handshaker_service_api_util.cc " +
+    "src\\core\\tsi\\alts\\handshaker\\alts_tsi_utils.cc " +
+    "src\\core\\tsi\\alts\\handshaker\\transport_security_common_api.cc " +
+    "src\\core\\tsi\\alts\\handshaker\\altscontext.pb.c " +
+    "src\\core\\tsi\\alts\\handshaker\\handshaker.pb.c " +
+    "src\\core\\tsi\\alts\\handshaker\\transport_security_common.pb.c " +
+    "third_party\\nanopb\\pb_common.c " +
+    "third_party\\nanopb\\pb_decode.c " +
+    "third_party\\nanopb\\pb_encode.c " +
     "src\\core\\tsi\\transport_security.cc " +
     "src\\core\\tsi\\transport_security_adapter.cc " +
-    "src\\core\\ext\\transport\\chttp2\\server\\chttp2_server.cc " +
-    "src\\core\\ext\\transport\\chttp2\\client\\secure\\secure_channel_create.cc " +
+    "src\\core\\ext\\transport\\chttp2\\client\\insecure\\channel_create.cc " +
+    "src\\core\\ext\\transport\\chttp2\\client\\insecure\\channel_create_posix.cc " +
+    "src\\core\\ext\\transport\\chttp2\\client\\chttp2_connector.cc " +
     "src\\core\\ext\\filters\\client_channel\\backup_poller.cc " +
     "src\\core\\ext\\filters\\client_channel\\channel_connectivity.cc " +
     "src\\core\\ext\\filters\\client_channel\\client_channel.cc " +
@@ -267,22 +312,28 @@
     "src\\core\\ext\\filters\\client_channel\\lb_policy.cc " +
     "src\\core\\ext\\filters\\client_channel\\lb_policy_factory.cc " +
     "src\\core\\ext\\filters\\client_channel\\lb_policy_registry.cc " +
+    "src\\core\\ext\\filters\\client_channel\\method_params.cc " +
     "src\\core\\ext\\filters\\client_channel\\parse_address.cc " +
     "src\\core\\ext\\filters\\client_channel\\proxy_mapper.cc " +
     "src\\core\\ext\\filters\\client_channel\\proxy_mapper_registry.cc " +
     "src\\core\\ext\\filters\\client_channel\\resolver.cc " +
-    "src\\core\\ext\\filters\\client_channel\\resolver_factory.cc " +
     "src\\core\\ext\\filters\\client_channel\\resolver_registry.cc " +
     "src\\core\\ext\\filters\\client_channel\\retry_throttle.cc " +
     "src\\core\\ext\\filters\\client_channel\\subchannel.cc " +
     "src\\core\\ext\\filters\\client_channel\\subchannel_index.cc " +
     "src\\core\\ext\\filters\\client_channel\\uri_parser.cc " +
     "src\\core\\ext\\filters\\deadline\\deadline_filter.cc " +
-    "src\\core\\ext\\transport\\chttp2\\client\\chttp2_connector.cc " +
+    "src\\core\\tsi\\alts_transport_security.cc " +
+    "src\\core\\tsi\\fake_transport_security.cc " +
+    "src\\core\\tsi\\ssl\\session_cache\\ssl_session_boringssl.cc " +
+    "src\\core\\tsi\\ssl\\session_cache\\ssl_session_cache.cc " +
+    "src\\core\\tsi\\ssl\\session_cache\\ssl_session_openssl.cc " +
+    "src\\core\\tsi\\ssl_transport_security.cc " +
+    "src\\core\\tsi\\transport_security_grpc.cc " +
+    "src\\core\\ext\\transport\\chttp2\\server\\chttp2_server.cc " +
+    "src\\core\\ext\\transport\\chttp2\\client\\secure\\secure_channel_create.cc " +
     "src\\core\\ext\\transport\\chttp2\\server\\insecure\\server_chttp2.cc " +
     "src\\core\\ext\\transport\\chttp2\\server\\insecure\\server_chttp2_posix.cc " +
-    "src\\core\\ext\\transport\\chttp2\\client\\insecure\\channel_create.cc " +
-    "src\\core\\ext\\transport\\chttp2\\client\\insecure\\channel_create_posix.cc " +
     "src\\core\\ext\\transport\\inproc\\inproc_plugin.cc " +
     "src\\core\\ext\\transport\\inproc\\inproc_transport.cc " +
     "src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\client_load_reporting_filter.cc " +
@@ -291,9 +342,6 @@
     "src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\grpclb_client_stats.cc " +
     "src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\load_balancer_api.cc " +
     "src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\proto\\grpc\\lb\\v1\\load_balancer.pb.c " +
-    "third_party\\nanopb\\pb_common.c " +
-    "third_party\\nanopb\\pb_decode.c " +
-    "third_party\\nanopb\\pb_encode.c " +
     "src\\core\\ext\\filters\\client_channel\\resolver\\fake\\fake_resolver.cc " +
     "src\\core\\ext\\filters\\client_channel\\lb_policy\\pick_first\\pick_first.cc " +
     "src\\core\\ext\\filters\\client_channel\\lb_policy\\subchannel_list.cc " +
@@ -381,7 +429,6 @@
     "third_party\\boringssl\\crypto\\cpu-intel.c " +
     "third_party\\boringssl\\crypto\\cpu-ppc64le.c " +
     "third_party\\boringssl\\crypto\\crypto.c " +
-    "third_party\\boringssl\\crypto\\curve25519\\curve25519.c " +
     "third_party\\boringssl\\crypto\\curve25519\\spake25519.c " +
     "third_party\\boringssl\\crypto\\curve25519\\x25519-x86_64.c " +
     "third_party\\boringssl\\crypto\\dh\\check.c " +
@@ -567,6 +614,7 @@
     "third_party\\boringssl\\ssl\\tls13_server.cc " +
     "third_party\\boringssl\\ssl\\tls_method.cc " +
     "third_party\\boringssl\\ssl\\tls_record.cc " +
+    "third_party\\boringssl\\third_party\\fiat\\curve25519.c " +
     "third_party\\zlib\\adler32.c " +
     "third_party\\zlib\\compress.c " +
     "third_party\\zlib\\crc32.c " +
@@ -638,11 +686,13 @@
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\transport\\chttp2\\transport");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\transport\\inproc");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\avl");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\backoff");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\channel");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\compression");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\debug");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\gpr");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\gprpp");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\http");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\iomgr");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\json");
@@ -650,6 +700,7 @@
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\context");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\credentials");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\credentials\\alts");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\credentials\\composite");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\credentials\\fake");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\credentials\\google_default");
@@ -658,6 +709,7 @@
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\credentials\\oauth2");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\credentials\\plugin");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\credentials\\ssl");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\security_connector");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\transport");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\util");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\slice");
@@ -665,10 +717,18 @@
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\transport");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\plugin_registry");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\tsi");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\tsi\\alts");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\tsi\\alts\\crypt");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\tsi\\alts\\frame_protector");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\tsi\\alts\\handshaker");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\tsi\\alts\\zero_copy_frame_protector");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\tsi\\ssl");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\tsi\\ssl\\session_cache");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\php");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\php\\ext");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\php\\ext\\grpc");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\address_sorting");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl\\crypto");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl\\crypto\\asn1");
@@ -707,6 +767,8 @@
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl\\crypto\\x509");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl\\crypto\\x509v3");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl\\ssl");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl\\third_party");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl\\third_party\\fiat");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\nanopb");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\zlib");
   _build_dirs = new Array();
diff --git a/doc/PROTOCOL-HTTP2.md b/doc/PROTOCOL-HTTP2.md
index 107a8e8..bdd00ca3 100644
--- a/doc/PROTOCOL-HTTP2.md
+++ b/doc/PROTOCOL-HTTP2.md
@@ -191,7 +191,7 @@
 Unless explicitly defined to be, gRPC Calls are not assumed to be idempotent.  Specifically:
 
 * Calls that cannot be proven to have started will not be retried.
-* There is no mechanisim for duplicate suppression as it is not necessary.
+* There is no mechanism for duplicate suppression as it is not necessary.
 * Calls that are marked as idempotent may be sent multiple times.
 
 
diff --git a/doc/PROTOCOL-WEB.md b/doc/PROTOCOL-WEB.md
index c31a048..c157cd7 100644
--- a/doc/PROTOCOL-WEB.md
+++ b/doc/PROTOCOL-WEB.md
@@ -106,19 +106,6 @@
 
 # Other features
 
-Compression
-
-* Full-body compression is supported and expected for all unary
-requests/responses. The compression/decompression will be done
-by browsers, using standard Content-Encoding headers
-  * “grpc-encoding” header is not used
-  * SDCH, Brotli will be supported
-* Message-level compression for streamed requests/responses is not supported
-because manual compression/decompression is prohibitively expensive using JS
-  * Per-message compression may be feasible in future with wasm
-
----
-
 Retries, caching
 
 * Will spec out the support after their respective gRPC spec extensions
@@ -128,24 +115,6 @@
 
 ---
 
-Security
-
-* XSRF, XSS etc to be specified
-
----
-
-CORS preflight
-
-* Should follow the [CORS spec](https://developer.mozilla.org/en-US/docs/Web/HTTP/Server-Side_Access_Control)
-  * Access-Control-Allow-Credentials to allow Authorization headers
-  * Access-Control-Allow-Methods to allow POST and (preflight) OPTIONS only
-  * Access-Control-Allow-Headers to whatever the preflight request carries
-* The client library may support header overwrites to avoid preflight
-  * https://github.com/whatwg/fetch/issues/210
-* CSP support to be specified
-
----
-
 Keep-alive
 
 * HTTP/2 PING is not supported or used
@@ -165,3 +134,8 @@
 
 * Special headers may be introduced to support features that may break compatiblity.
 
+---
+
+Browser-specific features
+
+* For features that are unique to browser or HTML clients, check the [spec doc](https://github.com/grpc/grpc-web/blob/master/PROTOCOL-WEB.md) published in the grpc/grpc-web repo.
diff --git a/doc/compression.md b/doc/compression.md
index bf38e3b..b8cdfb3 100644
--- a/doc/compression.md
+++ b/doc/compression.md
@@ -63,7 +63,7 @@
 
 If the user (through the previously described mechanisms) requests to disable
 compression the next message MUST be sent uncompressed. This is instrumental in
-preventing BEAST/CRIME attacks. This applies to both the the unary and streaming
+preventing BEAST/CRIME attacks. This applies to both the unary and streaming
 cases.
 
 ### Compression Levels and Algorithms
diff --git a/doc/cpp/pending_api_cleanups.md b/doc/cpp/pending_api_cleanups.md
index 517d503..fa19b52 100644
--- a/doc/cpp/pending_api_cleanups.md
+++ b/doc/cpp/pending_api_cleanups.md
@@ -15,3 +15,5 @@
   `include/grpc++/server_builder.h` (commit `6980362`)
 - remove `ClientContext::set_fail_fast()` method from
   `include/grpc++/impl/codegen/client_context.h` (commit `9477724`)
+- remove directory `include/grpc++` and all headers in it
+  (commit `eb06572`)
diff --git a/doc/environment_variables.md b/doc/environment_variables.md
index 5f0042e..ed46a48 100644
--- a/doc/environment_variables.md
+++ b/doc/environment_variables.md
@@ -18,7 +18,7 @@
 * GRPC_SSL_CIPHER_SUITES
   A colon separated list of cipher suites to use with OpenSSL
   Defaults to:
-    ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-GCM-SHA384
+    ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384
 
 * GRPC_DEFAULT_SSL_ROOTS_FILE_PATH
   PEM file to load SSL roots from
diff --git a/doc/g_stands_for.md b/doc/g_stands_for.md
index 19875c3..47ae7c5 100644
--- a/doc/g_stands_for.md
+++ b/doc/g_stands_for.md
@@ -14,3 +14,4 @@
 - 1.8 'g' stands for 'generous'
 - 1.9 'g' stands for 'glossy'
 - 1.10 'g' stands for 'glamorous'
+- 1.11 'g' stands for 'gorgeous'
diff --git a/doc/unit_testing.md b/doc/unit_testing.md
index 0aa9be9..ca56481 100644
--- a/doc/unit_testing.md
+++ b/doc/unit_testing.md
@@ -56,7 +56,7 @@
 
 
 1.  Setting flag(generate_mock_code=true) on grpc plugin for protoc, or
-1.  Setting an attribute(generate_mock) in your bazel rule.
+1.  Setting an attribute(generate_mocks) in your bazel rule.
 
 Protoc plugin flag:
 
@@ -70,7 +70,7 @@
 grpc_proto_library(
   name = "echo_proto",
   srcs = ["echo.proto"],
-  generate_mock = True, 
+  generate_mocks = True,
 )
 ```
 
diff --git a/etc/roots.pem b/etc/roots.pem
index cd6a0c2..15d819b 100644
--- a/etc/roots.pem
+++ b/etc/roots.pem
@@ -359,33 +359,6 @@
 398znM/jra6O1I7mT1GvFpLgXPYHDw==
 -----END CERTIFICATE-----
 
-# Issuer: CN=Certum CA O=Unizeto Sp. z o.o.
-# Subject: CN=Certum CA O=Unizeto Sp. z o.o.
-# Label: "Certum Root CA"
-# Serial: 65568
-# MD5 Fingerprint: 2c:8f:9f:66:1d:18:90:b1:47:26:9d:8e:86:82:8c:a9
-# SHA1 Fingerprint: 62:52:dc:40:f7:11:43:a2:2f:de:9e:f7:34:8e:06:42:51:b1:81:18
-# SHA256 Fingerprint: d8:e0:fe:bc:1d:b2:e3:8d:00:94:0f:37:d2:7d:41:34:4d:99:3e:73:4b:99:d5:65:6d:97:78:d4:d8:14:36:24
------BEGIN CERTIFICATE-----
-MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM
-MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
-QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM
-MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
-QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E
-jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo
-ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI
-ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu
-Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg
-AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7
-HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA
-uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa
-TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg
-xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q
-CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x
-O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs
-6GAqm4VKQPNriiTsBhYscw==
------END CERTIFICATE-----
-
 # Issuer: CN=AAA Certificate Services O=Comodo CA Limited
 # Subject: CN=AAA Certificate Services O=Comodo CA Limited
 # Label: "Comodo AAA Services root"
@@ -603,78 +576,6 @@
 ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M
 -----END CERTIFICATE-----
 
-# Issuer: CN=Chambers of Commerce Root O=AC Camerfirma SA CIF A82743287 OU=http://www.chambersign.org
-# Subject: CN=Chambers of Commerce Root O=AC Camerfirma SA CIF A82743287 OU=http://www.chambersign.org
-# Label: "Camerfirma Chambers of Commerce Root"
-# Serial: 0
-# MD5 Fingerprint: b0:01:ee:14:d9:af:29:18:94:76:8e:f1:69:33:2a:84
-# SHA1 Fingerprint: 6e:3a:55:a4:19:0c:19:5c:93:84:3c:c0:db:72:2e:31:30:61:f0:b1
-# SHA256 Fingerprint: 0c:25:8a:12:a5:67:4a:ef:25:f2:8b:a7:dc:fa:ec:ee:a3:48:e5:41:e6:f5:cc:4e:e6:3b:71:b3:61:60:6a:c3
------BEGIN CERTIFICATE-----
-MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn
-MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL
-ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg
-b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa
-MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB
-ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw
-IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B
-AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb
-unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d
-BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq
-7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3
-0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX
-roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG
-A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j
-aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p
-26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA
-BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud
-EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN
-BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz
-aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB
-AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd
-p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi
-1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc
-XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0
-eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu
-tGWaIZDgqtCYvDi1czyL+Nw=
------END CERTIFICATE-----
-
-# Issuer: CN=Global Chambersign Root O=AC Camerfirma SA CIF A82743287 OU=http://www.chambersign.org
-# Subject: CN=Global Chambersign Root O=AC Camerfirma SA CIF A82743287 OU=http://www.chambersign.org
-# Label: "Camerfirma Global Chambersign Root"
-# Serial: 0
-# MD5 Fingerprint: c5:e6:7b:bf:06:d0:4f:43:ed:c4:7a:65:8a:fb:6b:19
-# SHA1 Fingerprint: 33:9b:6b:14:50:24:9b:55:7a:01:87:72:84:d9:e0:2f:c3:d2:d8:e9
-# SHA256 Fingerprint: ef:3c:b4:17:fc:8e:bf:6f:97:87:6c:9e:4e:ce:39:de:1e:a5:fe:64:91:41:d1:02:8b:7d:11:c0:b2:29:8c:ed
------BEGIN CERTIFICATE-----
-MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn
-MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL
-ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo
-YW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9
-MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgy
-NzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4G
-A1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUA
-A4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0
-Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s
-QJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpV
-eAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795
-B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWh
-z0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0T
-AQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1i
-ZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w
-TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAH
-MCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5vcmcwKgYD
-VR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE
-VDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh
-bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0B
-AQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUM
-bKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXi
-ryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWG
-VwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3c
-ecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/
-AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A==
------END CERTIFICATE-----
-
 # Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com
 # Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com
 # Label: "XRamp Global CA Root"
@@ -772,58 +673,6 @@
 WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
 -----END CERTIFICATE-----
 
-# Issuer: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
-# Subject: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
-# Label: "StartCom Certification Authority"
-# Serial: 1
-# MD5 Fingerprint: 22:4d:8f:8a:fc:f7:35:c2:bb:57:34:90:7b:8b:22:16
-# SHA1 Fingerprint: 3e:2b:f7:f2:03:1b:96:f3:8c:e6:c4:d8:a8:5d:3e:2d:58:47:6a:0f
-# SHA256 Fingerprint: c7:66:a9:be:f2:d4:07:1c:86:3a:31:aa:49:20:e8:13:b2:d1:98:60:8c:b7:b7:cf:e2:11:43:b8:36:df:09:ea
------BEGIN CERTIFICATE-----
-MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
-MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
-Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
-dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9
-MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
-U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
-cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
-A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
-pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
-OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
-Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
-Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
-HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
-Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
-+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
-Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
-Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
-26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
-AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
-FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j
-ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js
-LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM
-BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0
-Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy
-dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh
-cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh
-YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg
-dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp
-bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ
-YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT
-TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ
-9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8
-jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW
-FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz
-ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1
-ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L
-EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu
-L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
-yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC
-O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V
-um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
-NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
------END CERTIFICATE-----
-
 # Issuer: O=Government Root Certification Authority
 # Subject: O=Government Root Certification Authority
 # Label: "Taiwan GRCA"
@@ -1013,38 +862,6 @@
 Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
 -----END CERTIFICATE-----
 
-# Issuer: CN=DST ACES CA X6 O=Digital Signature Trust OU=DST ACES
-# Subject: CN=DST ACES CA X6 O=Digital Signature Trust OU=DST ACES
-# Label: "DST ACES CA X6"
-# Serial: 17771143917277623872238992636097467865
-# MD5 Fingerprint: 21:d8:4c:82:2b:99:09:33:a2:eb:14:24:8d:8e:5f:e8
-# SHA1 Fingerprint: 40:54:da:6f:1c:3f:40:74:ac:ed:0f:ec:cd:db:79:d1:53:fb:90:1d
-# SHA256 Fingerprint: 76:7c:95:5a:76:41:2c:89:af:68:8e:90:a1:c7:0f:55:6c:fd:6b:60:25:db:ea:10:41:6d:7e:b6:83:1f:8c:40
------BEGIN CERTIFICATE-----
-MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBb
-MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3Qx
-ETAPBgNVBAsTCERTVCBBQ0VTMRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0w
-MzExMjAyMTE5NThaFw0xNzExMjAyMTE5NThaMFsxCzAJBgNVBAYTAlVTMSAwHgYD
-VQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UECxMIRFNUIEFDRVMx
-FzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
-MIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPu
-ktKe1jzIDZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7
-gLFViYsx+tC3dr5BPTCapCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZH
-fAjIgrrep4c9oW24MFbCswKBXy314powGCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4a
-ahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPyMjwmR/onJALJfh1biEIT
-ajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1UdEwEB/wQF
-MAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rk
-c3QuY29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjto
-dHRwOi8vd3d3LnRydXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMt
-aW5kZXguaHRtbDAdBgNVHQ4EFgQUCXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZI
-hvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V25FYrnJmQ6AgwbN99Pe7lv7Uk
-QIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6tFr8hlxCBPeP/
-h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq
-nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpR
-rscL9yuwNwXsvFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf2
-9w4LTJxoeHtxMcfrHuBnQfO3oKfN5XozNmr6mis=
------END CERTIFICATE-----
-
 # Issuer: CN=SwissSign Gold CA - G2 O=SwissSign AG
 # Subject: CN=SwissSign Gold CA - G2 O=SwissSign AG
 # Label: "SwissSign Gold CA - G2"
@@ -1373,35 +1190,6 @@
 GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
 -----END CERTIFICATE-----
 
-# Issuer: O=SECOM Trust Systems CO.,LTD. OU=Security Communication EV RootCA1
-# Subject: O=SECOM Trust Systems CO.,LTD. OU=Security Communication EV RootCA1
-# Label: "Security Communication EV RootCA1"
-# Serial: 0
-# MD5 Fingerprint: 22:2d:a6:01:ea:7c:0a:f7:f0:6c:56:43:3f:77:76:d3
-# SHA1 Fingerprint: fe:b8:c4:32:dc:f9:76:9a:ce:ae:3d:d8:90:8f:fd:28:86:65:64:7d
-# SHA256 Fingerprint: a2:2d:ba:68:1e:97:37:6e:2d:39:7d:72:8a:ae:3a:9b:62:96:b9:fd:ba:60:bc:2e:11:f6:47:f2:c6:75:fb:37
------BEGIN CERTIFICATE-----
-MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDEl
-MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMh
-U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIz
-MloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09N
-IFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNlY3VyaXR5IENvbW11
-bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSE
-RMqm4miO/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gO
-zXppFodEtZDkBp2uoQSXWHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5
-bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4zZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDF
-MxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4bepJz11sS6/vmsJWXMY1
-VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK9U2vP9eC
-OKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G
-CSqGSIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HW
-tWS3irO4G8za+6xmiEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZ
-q51ihPZRwSzJIxXYKLerJRO1RuGGAv8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDb
-EJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnWmHyojf6GPgcWkuF75x3sM3Z+
-Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEWT1MKZPlO9L9O
-VL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490
------END CERTIFICATE-----
-
 # Issuer: CN=OISTE WISeKey Global Root GA CA O=WISeKey OU=Copyright (c) 2005/OISTE Foundation Endorsed
 # Subject: CN=OISTE WISeKey Global Root GA CA O=WISeKey OU=Copyright (c) 2005/OISTE Foundation Endorsed
 # Label: "OISTE WISeKey Global Root GA CA"
@@ -1565,44 +1353,6 @@
 hNQ+IIX3Sj0rnP0qCglN6oH4EZw=
 -----END CERTIFICATE-----
 
-# Issuer: CN=TÜBİTAK UEKAE Kök Sertifika Hizmet Sağlayıcısı - Sürüm 3 O=Türkiye Bilimsel ve Teknolojik Araştırma Kurumu - TÜBİTAK OU=Ulusal Elektronik ve Kriptoloji Araştırma Enstitüsü - UEKAE/Kamu Sertifikasyon Merkezi
-# Subject: CN=TÜBİTAK UEKAE Kök Sertifika Hizmet Sağlayıcısı - Sürüm 3 O=Türkiye Bilimsel ve Teknolojik Araştırma Kurumu - TÜBİTAK OU=Ulusal Elektronik ve Kriptoloji Araştırma Enstitüsü - UEKAE/Kamu Sertifikasyon Merkezi
-# Label: "T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3"
-# Serial: 17
-# MD5 Fingerprint: ed:41:f5:8c:50:c5:2b:9c:73:e6:ee:6c:eb:c2:a8:26
-# SHA1 Fingerprint: 1b:4b:39:61:26:27:6b:64:91:a2:68:6d:d7:02:43:21:2d:1f:1d:96
-# SHA256 Fingerprint: e4:c7:34:30:d7:a5:b5:09:25:df:43:37:0a:0d:21:6e:9a:79:b9:d6:db:83:73:a0:c6:9e:b1:cc:31:c7:c5:2a
------BEGIN CERTIFICATE-----
-MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRS
-MRgwFgYDVQQHDA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJp
-bGltc2VsIHZlIFRla25vbG9qaWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSw
-VEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ryb25payB2ZSBLcmlwdG9sb2ppIEFy
-YcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNVBAsMGkthbXUgU2Vy
-dGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUgS8O2
-ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAe
-Fw0wNzA4MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIx
-GDAWBgNVBAcMD0dlYnplIC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmls
-aW1zZWwgdmUgVGVrbm9sb2ppayBBcmHFn3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBU
-QUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZlIEtyaXB0b2xvamkgQXJh
-xZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2FtdSBTZXJ0
-aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7Zr
-IFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIB
-IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4h
-gb46ezzb8R1Sf1n68yJMlaCQvEhOEav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yK
-O7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1xnnRFDDtG1hba+818qEhTsXO
-fJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR6Oqeyjh1jmKw
-lZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL
-hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQID
-AQABo0IwQDAdBgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/
-BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmP
-NOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4N5EY3ATIZJkrGG2AA1nJrvhY0D7t
-wyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLTy9LQQfMmNkqblWwM
-7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYhLBOh
-gLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5n
-oN+J1q2MdqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUs
-yZyQ2uypQjyttgI=
------END CERTIFICATE-----
-
 # Issuer: O=certSIGN OU=certSIGN ROOT CA
 # Subject: O=certSIGN OU=certSIGN ROOT CA
 # Label: "certSIGN ROOT CA"
@@ -1940,47 +1690,6 @@
 QSdJQO7e5iNEOdyhIta6A/I=
 -----END CERTIFICATE-----
 
-# Issuer: CN=ACEDICOM Root O=EDICOM OU=PKI
-# Subject: CN=ACEDICOM Root O=EDICOM OU=PKI
-# Label: "ACEDICOM Root"
-# Serial: 7029493972724711941
-# MD5 Fingerprint: 42:81:a0:e2:1c:e3:55:10:de:55:89:42:65:96:22:e6
-# SHA1 Fingerprint: e0:b4:32:2e:b2:f6:a5:68:b6:54:53:84:48:18:4a:50:36:87:43:84
-# SHA256 Fingerprint: 03:95:0f:b4:9a:53:1f:3e:19:91:94:23:98:df:a9:e0:ea:32:d7:ba:1c:dd:9b:c8:5d:b5:7e:d9:40:0b:43:4a
------BEGIN CERTIFICATE-----
-MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UE
-AwwNQUNFRElDT00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00x
-CzAJBgNVBAYTAkVTMB4XDTA4MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEW
-MBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZF
-RElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
-AgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHkWLn7
-09gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7
-XBZXehuDYAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5P
-Grjm6gSSrj0RuVFCPYewMYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAK
-t0SdE3QrwqXrIhWYENiLxQSfHY9g5QYbm8+5eaA9oiM/Qj9r+hwDezCNzmzAv+Yb
-X79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbkHQl/Sog4P75n/TSW9R28
-MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTTxKJxqvQU
-fecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI
-2Sf23EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyH
-K9caUPgn6C9D4zq92Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEae
-ZAwUswdbxcJzbPEHXEUkFDWug/FqTYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAP
-BgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz4SsrSbbXc6GqlPUB53NlTKxQ
-MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU9QHnc2VMrFAw
-RAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv
-bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWIm
-fQwng4/F9tqgaHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3
-gvoFNTPhNahXwOf9jU8/kzJPeGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKe
-I6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1PwkzQSulgUV1qzOMPPKC8W64iLgpq0i
-5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1ThCojz2GuHURwCRi
-ipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oIKiMn
-MCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZ
-o5NjEFIqnxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6
-zqylfDJKZ0DcMDQj3dcEI2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacN
-GHk0vFQYXlPKNFHtRQrmjseCNj6nOGOpMCwXEGCSn1WHElkQwg9naRHMTh5+Spqt
-r0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3otkYNbn5XOmeUwssfnHdK
-Z05phkOTOPu220+DkdRgfks+KzgHVZhepA==
------END CERTIFICATE-----
-
 # Issuer: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd.
 # Subject: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd.
 # Label: "Microsec e-Szigno Root CA 2009"
@@ -2466,46 +2175,6 @@
 03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=
 -----END CERTIFICATE-----
 
-# Issuer: CN=Certinomis - Autorité Racine O=Certinomis OU=0002 433998903
-# Subject: CN=Certinomis - Autorité Racine O=Certinomis OU=0002 433998903
-# Label: "Certinomis - Autorité Racine"
-# Serial: 1
-# MD5 Fingerprint: 7f:30:78:8c:03:e3:ca:c9:0a:e2:c9:ea:1e:aa:55:1a
-# SHA1 Fingerprint: 2e:14:da:ec:28:f0:fa:1e:8e:38:9a:4e:ab:eb:26:c0:0a:d3:83:c3
-# SHA256 Fingerprint: fc:bf:e2:88:62:06:f7:2b:27:59:3c:8b:07:02:97:e1:2d:76:9e:d1:0e:d7:93:07:05:a8:09:8e:ff:c1:4d:17
------BEGIN CERTIFICATE-----
-MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjET
-MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAk
-BgNVBAMMHUNlcnRpbm9taXMgLSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4
-Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNl
-cnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYwJAYDVQQDDB1DZXJ0
-aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-ADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jY
-F1AMnmHawE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N
-8y4oH3DfVS9O7cdxbwlyLu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWe
-rP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K
-/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92NjMD2AR5vpTESOH2VwnHu
-7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9qc1pkIuVC
-28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6
-lSTClrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1E
-nn1So2+WLhl+HPNbxxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB
-0iSVL1N6aaLwD4ZFjliCK0wi1F6g530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql09
-5gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna4NH4+ej9Uji29YnfAgMBAAGj
-WzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQN
-jLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ
-KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9s
-ov3/4gbIOZ/xWqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZM
-OH8oMDX/nyNTt7buFHAAQCvaR6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q
-619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40nJ+U8/aGH88bc62UeYdocMMzpXDn
-2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1BCxMjidPJC+iKunqj
-o3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjvJL1v
-nxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG
-5ERQL1TEqkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWq
-pdEdnV1j6CTmNhTih60bWfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZb
-dsLLO7XSAPCjDuGtbkD326C00EauFddEwk01+dIL8hf2rGbVJLJP0RyZwG71fet0
-BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/vgt2Fl43N+bYdJeimUV5
------END CERTIFICATE-----
-
 # Issuer: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA
 # Subject: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA
 # Label: "TWCA Root Certification Authority"
@@ -2706,96 +2375,6 @@
 ZetX2fNXlrtIzYE=
 -----END CERTIFICATE-----
 
-# Issuer: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
-# Subject: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
-# Label: "StartCom Certification Authority"
-# Serial: 45
-# MD5 Fingerprint: c9:3b:0d:84:41:fc:a4:76:79:23:08:57:de:10:19:16
-# SHA1 Fingerprint: a3:f1:33:3f:e2:42:bf:cf:c5:d1:4e:8f:39:42:98:40:68:10:d1:a0
-# SHA256 Fingerprint: e1:78:90:ee:09:a3:fb:f4:f4:8b:9c:41:4a:17:d6:37:b7:a5:06:47:e9:bc:75:23:22:72:7f:cc:17:42:a9:11
------BEGIN CERTIFICATE-----
-MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEW
-MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
-Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
-dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM3WhcNMzYwOTE3MTk0NjM2WjB9
-MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
-U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
-cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
-A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
-pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
-OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
-Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
-Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
-HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
-Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
-+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
-Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
-Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
-26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
-AQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
-VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFul
-F2mHMMo0aEPQQa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCC
-ATgwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w
-ZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2ludGVybWVk
-aWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENvbW1lcmNpYWwgKFN0
-YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0aGUg
-c2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0
-aWZpY2F0aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93
-d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgG
-CWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1
-dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5fPGFf59Jb2vKXfuM/gTF
-wWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWmN3PH/UvS
-Ta0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst
-0OcNOrg+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNc
-pRJvkrKTlMeIFw6Ttn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKl
-CcWw0bdT82AUuoVpaiF8H3VhFyAXe2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVF
-P0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA2MFrLH9ZXF2RsXAiV+uKa0hK
-1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBsHvUwyKMQ5bLm
-KhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE
-JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ
-8dCAWZvLMdibD4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnm
-fyWl8kgAwKQB2j8=
------END CERTIFICATE-----
-
-# Issuer: CN=StartCom Certification Authority G2 O=StartCom Ltd.
-# Subject: CN=StartCom Certification Authority G2 O=StartCom Ltd.
-# Label: "StartCom Certification Authority G2"
-# Serial: 59
-# MD5 Fingerprint: 78:4b:fb:9e:64:82:0a:d3:b8:4c:62:f3:64:f2:90:64
-# SHA1 Fingerprint: 31:f1:fd:68:22:63:20:ee:c6:3b:3f:9d:ea:4a:3e:53:7c:7c:39:17
-# SHA256 Fingerprint: c7:ba:65:67:de:93:a7:98:ae:1f:aa:79:1e:71:2d:37:8f:ae:1f:93:c4:39:7f:ea:44:1b:b7:cb:e6:fd:59:95
------BEGIN CERTIFICATE-----
-MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEW
-MBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlm
-aWNhdGlvbiBBdXRob3JpdHkgRzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1
-OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoG
-A1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRzIwggIiMA0G
-CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8Oo1XJ
-JZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsD
-vfOpL9HG4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnoo
-D/Uefyf3lLE3PbfHkffiAez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/
-Q0kGi4xDuFby2X8hQxfqp0iVAXV16iulQ5XqFYSdCI0mblWbq9zSOdIxHWDirMxW
-RST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbsO+wmETRIjfaAKxojAuuK
-HDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8HvKTlXcxN
-nw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM
-0D4LnMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/i
-UUjXuG+v+E5+M5iSFGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9
-Ha90OrInwMEePnWjFqmveiJdnxMaz6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHg
-TuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
-AwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJKoZIhvcNAQEL
-BQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K
-2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfX
-UfEpY9Z1zRbkJ4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl
-6/2o1PXWT6RbdejF0mCy2wl+JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK
-9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG/+gyRr61M3Z3qAFdlsHB1b6uJcDJ
-HgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTcnIhT76IxW1hPkWLI
-wpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/XldblhY
-XzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5l
-IxKVCCIcl85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoo
-hdVddLHRDiBYmxOlsGOm7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulr
-so8uBtjRkcfGEvRM/TAXw8HaOFvjqermobp573PYtlNXLfbQ4ddI
------END CERTIFICATE-----
-
 # Issuer: CN=Buypass Class 2 Root CA O=Buypass AS-983163327
 # Subject: CN=Buypass Class 2 Root CA O=Buypass AS-983163327
 # Label: "Buypass Class 2 Root CA"
@@ -2937,39 +2516,6 @@
 GVCJYMzpJJUPwssd8m92kMfMdcGWxZ0=
 -----END CERTIFICATE-----
 
-# Issuer: CN=TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı O=TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş. (c) Aralık 2007
-# Subject: CN=TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı O=TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş. (c) Aralık 2007
-# Label: "TURKTRUST Certificate Services Provider Root 2007"
-# Serial: 1
-# MD5 Fingerprint: 2b:70:20:56:86:82:a0:18:c8:07:53:12:28:70:21:72
-# SHA1 Fingerprint: f1:7f:6f:b6:31:dc:99:e3:a3:c8:7f:fe:1c:f1:81:10:88:d9:60:33
-# SHA256 Fingerprint: 97:8c:d9:66:f2:fa:a0:7b:a7:aa:95:00:d9:c0:2e:9d:77:f2:cd:ad:a6:ad:6b:a7:4a:f4:b9:1c:66:59:3c:50
------BEGIN CERTIFICATE-----
-MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOc
-UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx
-c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xS
-S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg
-SGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4XDTA3MTIyNTE4Mzcx
-OVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxla3Ry
-b25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMC
-VFIxDzANBgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDE
-sGxldGnFn2ltIHZlIEJpbGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7F
-ni4gKGMpIEFyYWzEsWsgMjAwNzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9NYvDdE3ePYakqtdTyuTFY
-KTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQvKUmi8wUG
-+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveG
-HtyaKhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6P
-IzdezKKqdfcYbwnTrqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M
-733WB2+Y8a+xwXrXgTW4qhe04MsCAwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHk
-Yb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G
-CSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/sPx+EnWVUXKgW
-AkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I
-aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5
-mxRZNTZPz/OOXl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsa
-XRik7r4EW5nVcV9VZWRi1aKbBFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZ
-qxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAKpoRq0Tl9
------END CERTIFICATE-----
-
 # Issuer: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH
 # Subject: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH
 # Label: "D-TRUST Root Class 3 CA 2 2009"
@@ -3036,106 +2582,6 @@
 KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1
 -----END CERTIFICATE-----
 
-# Issuer: CN=Autoridad de Certificacion Raiz del Estado Venezolano O=Sistema Nacional de Certificacion Electronica OU=Superintendencia de Servicios de Certificacion Electronica
-# Subject: CN=PSCProcert O=Sistema Nacional de Certificacion Electronica OU=Proveedor de Certificados PROCERT
-# Label: "PSCProcert"
-# Serial: 11
-# MD5 Fingerprint: e6:24:e9:12:01:ae:0c:de:8e:85:c4:ce:a3:12:dd:ec
-# SHA1 Fingerprint: 70:c1:8d:74:b4:28:81:0a:e4:fd:a5:75:d7:01:9f:99:b0:3d:50:74
-# SHA256 Fingerprint: 3c:fc:3c:14:d1:f6:84:ff:17:e3:8c:43:ca:44:0c:00:b9:67:ec:93:3e:8b:fe:06:4c:a1:d7:2c:90:f2:ad:b0
------BEGIN CERTIFICATE-----
-MIIJhjCCB26gAwIBAgIBCzANBgkqhkiG9w0BAQsFADCCAR4xPjA8BgNVBAMTNUF1
-dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9s
-YW5vMQswCQYDVQQGEwJWRTEQMA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlz
-dHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0
-aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBlcmludGVuZGVuY2lh
-IGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUwIwYJ
-KoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyODE2NTEw
-MFoXDTIwMTIyNTIzNTk1OVowgdExJjAkBgkqhkiG9w0BCQEWF2NvbnRhY3RvQHBy
-b2NlcnQubmV0LnZlMQ8wDQYDVQQHEwZDaGFjYW8xEDAOBgNVBAgTB01pcmFuZGEx
-KjAoBgNVBAsTIVByb3ZlZWRvciBkZSBDZXJ0aWZpY2Fkb3MgUFJPQ0VSVDE2MDQG
-A1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9u
-aWNhMQswCQYDVQQGEwJWRTETMBEGA1UEAxMKUFNDUHJvY2VydDCCAiIwDQYJKoZI
-hvcNAQEBBQADggIPADCCAgoCggIBANW39KOUM6FGqVVhSQ2oh3NekS1wwQYalNo9
-7BVCwfWMrmoX8Yqt/ICV6oNEolt6Vc5Pp6XVurgfoCfAUFM+jbnADrgV3NZs+J74
-BCXfgI8Qhd19L3uA3VcAZCP4bsm+lU/hdezgfl6VzbHvvnpC2Mks0+saGiKLt38G
-ieU89RLAu9MLmV+QfI4tL3czkkohRqipCKzx9hEC2ZUWno0vluYC3XXCFCpa1sl9
-JcLB/KpnheLsvtF8PPqv1W7/U0HU9TI4seJfxPmOEO8GqQKJ/+MMbpfg353bIdD0
-PghpbNjU5Db4g7ayNo+c7zo3Fn2/omnXO1ty0K+qP1xmk6wKImG20qCZyFSTXai2
-0b1dCl53lKItwIKOvMoDKjSuc/HUtQy9vmebVOvh+qBa7Dh+PsHMosdEMXXqP+UH
-0quhJZb25uSgXTcYOWEAM11G1ADEtMo88aKjPvM6/2kwLkDd9p+cJsmWN63nOaK/
-6mnbVSKVUyqUtd+tFjiBdWbjxywbk5yqjKPK2Ww8F22c3HxT4CAnQzb5EuE8XL1m
-v6JpIzi4mWCZDlZTOpx+FIywBm/xhnaQr/2v/pDGj59/i5IjnOcVdo/Vi5QTcmn7
-K2FjiO/mpF7moxdqWEfLcU8UC17IAggmosvpr2uKGcfLFFb14dq12fy/czja+eev
-bqQ34gcnAgMBAAGjggMXMIIDEzASBgNVHRMBAf8ECDAGAQH/AgEBMDcGA1UdEgQw
-MC6CD3N1c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAzNi0w
-MB0GA1UdDgQWBBRBDxk4qpl/Qguk1yeYVKIXTC1RVDCCAVAGA1UdIwSCAUcwggFD
-gBStuyIdxuDSAaj9dlBSk+2YwU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0
-b3JpZGFkIGRlIENlcnRpZmljYWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xh
-bm8xCzAJBgNVBAYTAlZFMRAwDgYDVQQHEwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0
-cml0byBDYXBpdGFsMTYwNAYDVQQKEy1TaXN0ZW1hIE5hY2lvbmFsIGRlIENlcnRp
-ZmljYWNpb24gRWxlY3Ryb25pY2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5kZW5jaWEg
-ZGUgU2VydmljaW9zIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkq
-hkiG9w0BCQEWFmFjcmFpekBzdXNjZXJ0ZS5nb2IudmWCAQowDgYDVR0PAQH/BAQD
-AgEGME0GA1UdEQRGMESCDnByb2NlcnQubmV0LnZloBUGBWCGXgIBoAwMClBTQy0w
-MDAwMDKgGwYFYIZeAgKgEgwQUklGLUotMzE2MzUzNzMtNzB2BgNVHR8EbzBtMEag
-RKBChkBodHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52ZS9sY3IvQ0VSVElGSUNBRE8t
-UkFJWi1TSEEzODRDUkxERVIuY3JsMCOgIaAfhh1sZGFwOi8vYWNyYWl6LnN1c2Nl
-cnRlLmdvYi52ZTA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9v
-Y3NwLnN1c2NlcnRlLmdvYi52ZTBBBgNVHSAEOjA4MDYGBmCGXgMBAjAsMCoGCCsG
-AQUFBwIBFh5odHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52ZS9kcGMwDQYJKoZIhvcN
-AQELBQADggIBACtZ6yKZu4SqT96QxtGGcSOeSwORR3C7wJJg7ODU523G0+1ng3dS
-1fLld6c2suNUvtm7CpsR72H0xpkzmfWvADmNg7+mvTV+LFwxNG9s2/NkAZiqlCxB
-3RWGymspThbASfzXg0gTB1GEMVKIu4YXx2sviiCtxQuPcD4quxtxj7mkoP3Yldmv
-Wb8lK5jpY5MvYB7Eqvh39YtsL+1+LrVPQA3uvFd359m21D+VJzog1eWuq2w1n8Gh
-HVnchIHuTQfiSLaeS5UtQbHh6N5+LwUeaO6/u5BlOsju6rEYNxxik6SgMexxbJHm
-pHmJWhSnFFAFTKQAVzAswbVhltw+HoSvOULP5dAssSS830DD7X9jSr3hTxJkhpXz
-sOfIt+FTvZLm8wyWuevo5pLtp4EJFAv8lXrPj9Y0TzYS3F7RNHXGRoAvlQSMx4bE
-qCaJqD8Zm4G7UaRKhqsLEQ+xrmNTbSjq3TNWOByyrYDT13K9mmyZY+gAu0F2Bbdb
-mRiKw7gSXFbPVgx96OLP7bx0R/vu0xdOIk9W/1DzLuY5poLWccret9W6aAjtmcz9
-opLLabid+Qqkpj5PkygqYWwHJgD/ll9ohri4zspV4KuxPX+Y1zMOWj3YeMLEYC/H
-YvBhkdI4sPaeVdtAgAUSM84dkpvRabP/v/GSCmE1P93+hvS84Bpxs2Km
------END CERTIFICATE-----
-
-# Issuer: CN=CA Disig Root R1 O=Disig a.s.
-# Subject: CN=CA Disig Root R1 O=Disig a.s.
-# Label: "CA Disig Root R1"
-# Serial: 14052245610670616104
-# MD5 Fingerprint: be:ec:11:93:9a:f5:69:21:bc:d7:c1:c0:67:89:cc:2a
-# SHA1 Fingerprint: 8e:1c:74:f8:a6:20:b9:e5:8a:f4:61:fa:ec:2b:47:56:51:1a:52:c6
-# SHA256 Fingerprint: f9:6f:23:f4:c3:e7:9c:07:7a:46:98:8d:5a:f5:90:06:76:a0:f0:39:cb:64:5d:d1:75:49:b2:16:c8:24:40:ce
------BEGIN CERTIFICATE-----
-MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNV
-BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu
-MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQy
-MDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx
-EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjEw
-ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy3QRk
-D2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/o
-OI7bm+V8u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3A
-fQ+lekLZWnDZv6fXARz2m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJe
-IgpFy4QxTaz+29FHuvlglzmxZcfe+5nkCiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8n
-oc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTaYVKvJrT1cU/J19IG32PK
-/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6vpmumwKj
-rckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD
-3AjLLhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE
-7cderVC6xkGbrPAXZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkC
-yC2fg69naQanMVXVz0tv/wQFx1isXxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLd
-qvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud
-DwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ04IwDQYJKoZI
-hvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR
-xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaA
-SfX8MPWbTx9BLxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXo
-HqJPYNcHKfyyo6SdbhWSVhlMCrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpB
-emOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5GfbVSUZP/3oNn6z4eGBrxEWi1CXYBmC
-AMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85YmLLW1AL14FABZyb
-7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKSds+x
-DzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvk
-F7mGnjixlAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqF
-a3qdnom2piiZk4hA9z7NUaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsT
-Q6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJa7+h89n07eLw4+1knj0vllJPgFOL
------END CERTIFICATE-----
-
 # Issuer: CN=CA Disig Root R2 O=Disig a.s.
 # Subject: CN=CA Disig Root R2 O=Disig a.s.
 # Label: "CA Disig Root R2"
@@ -3671,85 +3117,6 @@
 gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+
 -----END CERTIFICATE-----
 
-# Issuer: CN=Certification Authority of WoSign O=WoSign CA Limited
-# Subject: CN=Certification Authority of WoSign O=WoSign CA Limited
-# Label: "WoSign"
-# Serial: 125491772294754854453622855443212256657
-# MD5 Fingerprint: a1:f2:f9:b5:d2:c8:7a:74:b8:f3:05:f1:d7:e1:84:8d
-# SHA1 Fingerprint: b9:42:94:bf:91:ea:8f:b6:4b:e6:10:97:c7:fb:00:13:59:b6:76:cb
-# SHA256 Fingerprint: 4b:22:d5:a6:ae:c9:9f:3c:db:79:aa:5e:c0:68:38:47:9c:d5:ec:ba:71:64:f7:f2:2d:c1:d6:5f:63:d8:57:08
------BEGIN CERTIFICATE-----
-MIIFdjCCA16gAwIBAgIQXmjWEXGUY1BWAGjzPsnFkTANBgkqhkiG9w0BAQUFADBV
-MQswCQYDVQQGEwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxKjAoBgNV
-BAMTIUNlcnRpZmljYXRpb24gQXV0aG9yaXR5IG9mIFdvU2lnbjAeFw0wOTA4MDgw
-MTAwMDFaFw0zOTA4MDgwMTAwMDFaMFUxCzAJBgNVBAYTAkNOMRowGAYDVQQKExFX
-b1NpZ24gQ0EgTGltaXRlZDEqMCgGA1UEAxMhQ2VydGlmaWNhdGlvbiBBdXRob3Jp
-dHkgb2YgV29TaWduMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvcqN
-rLiRFVaXe2tcesLea9mhsMMQI/qnobLMMfo+2aYpbxY94Gv4uEBf2zmoAHqLoE1U
-fcIiePyOCbiohdfMlZdLdNiefvAA5A6JrkkoRBoQmTIPJYhTpA2zDxIIFgsDcScc
-f+Hb0v1naMQFXQoOXXDX2JegvFNBmpGN9J42Znp+VsGQX+axaCA2pIwkLCxHC1l2
-ZjC1vt7tj/id07sBMOby8w7gLJKA84X5KIq0VC6a7fd2/BVoFutKbOsuEo/Uz/4M
-x1wdC34FMr5esAkqQtXJTpCzWQ27en7N1QhatH/YHGkR+ScPewavVIMYe+HdVHpR
-aG53/Ma/UkpmRqGyZxq7o093oL5d//xWC0Nyd5DKnvnyOfUNqfTq1+ezEC8wQjch
-zDBwyYaYD8xYTYO7feUapTeNtqwylwA6Y3EkHp43xP901DfA4v6IRmAR3Qg/UDar
-uHqklWJqbrDKaiFaafPz+x1wOZXzp26mgYmhiMU7ccqjUu6Du/2gd/Tkb+dC221K
-mYo0SLwX3OSACCK28jHAPwQ+658geda4BmRkAjHXqc1S+4RFaQkAKtxVi8QGRkvA
-Sh0JWzko/amrzgD5LkhLJuYwTKVYyrREgk/nkR4zw7CT/xH8gdLKH3Ep3XZPkiWv
-HYG3Dy+MwwbMLyejSuQOmbp8HkUff6oZRZb9/D0CAwEAAaNCMEAwDgYDVR0PAQH/
-BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOFmzw7R8bNLtwYgFP6H
-EtX2/vs+MA0GCSqGSIb3DQEBBQUAA4ICAQCoy3JAsnbBfnv8rWTjMnvMPLZdRtP1
-LOJwXcgu2AZ9mNELIaCJWSQBnfmvCX0KI4I01fx8cpm5o9dU9OpScA7F9dY74ToJ
-MuYhOZO9sxXqT2r09Ys/L3yNWC7F4TmgPsc9SnOeQHrAK2GpZ8nzJLmzbVUsWh2e
-JXLOC62qx1ViC777Y7NhRCOjy+EaDveaBk3e1CNOIZZbOVtXHS9dCF4Jef98l7VN
-g64N1uajeeAz0JmWAjCnPv/So0M/BVoG6kQC2nz4SNAzqfkHx5Xh9T71XXG68pWp
-dIhhWeO/yloTunK0jF02h+mmxTwTv97QRCbut+wucPrXnbes5cVAWubXbHssw1ab
-R80LzvobtCHXt2a49CUwi1wNuepnsvRtrtWhnk/Yn+knArAdBtaP4/tIEp9/EaEQ
-PkxROpaw0RPxx9gmrjrKkcRpnd8BKWRRb2jaFOwIQZeQjdCygPLPwj2/kWjFgGce
-xGATVdVhmVd8upUPYUk6ynW8yQqTP2cOEvIo4jEbwFcW3wh8GcF+Dx+FHgo2fFt+
-J7x6v+Db9NpSvd4MVHAxkUOVyLzwPt0JfjBkUO1/AaQzZ01oT74V77D2AhGiGxMl
-OtzCWfHjXEa7ZywCRuoeSKbmW9m1vFGikpbbqsY3Iqb+zCB0oy2pLmvLwIIRIbWT
-ee5Ehr7XHuQe+w==
------END CERTIFICATE-----
-
-# Issuer: CN=CA 沃通根证书 O=WoSign CA Limited
-# Subject: CN=CA 沃通根证书 O=WoSign CA Limited
-# Label: "WoSign China"
-# Serial: 106921963437422998931660691310149453965
-# MD5 Fingerprint: 78:83:5b:52:16:76:c4:24:3b:83:78:e8:ac:da:9a:93
-# SHA1 Fingerprint: 16:32:47:8d:89:f9:21:3a:92:00:85:63:f5:a4:a7:d3:12:40:8a:d6
-# SHA256 Fingerprint: d6:f0:34:bd:94:aa:23:3f:02:97:ec:a4:24:5b:28:39:73:e4:47:aa:59:0f:31:0c:77:f4:8f:df:83:11:22:54
------BEGIN CERTIFICATE-----
-MIIFWDCCA0CgAwIBAgIQUHBrzdgT/BtOOzNy0hFIjTANBgkqhkiG9w0BAQsFADBG
-MQswCQYDVQQGEwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNV
-BAMMEkNBIOayg+mAmuagueivgeS5pjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgw
-MTAwMDFaMEYxCzAJBgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRl
-ZDEbMBkGA1UEAwwSQ0Eg5rKD6YCa5qC56K+B5LmmMIICIjANBgkqhkiG9w0BAQEF
-AAOCAg8AMIICCgKCAgEA0EkhHiX8h8EqwqzbdoYGTufQdDTc7WU1/FDWiD+k8H/r
-D195L4mx/bxjWDeTmzj4t1up+thxx7S8gJeNbEvxUNUqKaqoGXqW5pWOdO2XCld1
-9AXbbQs5uQF/qvbW2mzmBeCkTVL829B0txGMe41P/4eDrv8FAxNXUDf+jJZSEExf
-v5RxadmWPgxDT74wwJ85dE8GRV2j1lY5aAfMh09Qd5Nx2UQIsYo06Yms25tO4dnk
-UkWMLhQfkWsZHWgpLFbE4h4TV2TwYeO5Ed+w4VegG63XX9Gv2ystP9Bojg/qnw+L
-NVgbExz03jWhCl3W6t8Sb8D7aQdGctyB9gQjF+BNdeFyb7Ao65vh4YOhn0pdr8yb
-+gIgthhid5E7o9Vlrdx8kHccREGkSovrlXLp9glk3Kgtn3R46MGiCWOc76DbT52V
-qyBPt7D3h1ymoOQ3OMdc4zUPLK2jgKLsLl3Az+2LBcLmc272idX10kaO6m1jGx6K
-yX2m+Jzr5dVjhU1zZmkR/sgO9MHHZklTfuQZa/HpelmjbX7FF+Ynxu8b22/8DU0G
-AbQOXDBGVWCvOGU6yke6rCzMRh+yRpY/8+0mBe53oWprfi1tWFxK1I5nuPHa1UaK
-J/kR8slC/k7e3x9cxKSGhxYzoacXGKUN5AXlK8IrC6KVkLn9YDxOiT7nnO4fuwEC
-AwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O
-BBYEFOBNv9ybQV0T6GTwp+kVpOGBwboxMA0GCSqGSIb3DQEBCwUAA4ICAQBqinA4
-WbbaixjIvirTthnVZil6Xc1bL3McJk6jfW+rtylNpumlEYOnOXOvEESS5iVdT2H6
-yAa+Tkvv/vMx/sZ8cApBWNromUuWyXi8mHwCKe0JgOYKOoICKuLJL8hWGSbueBwj
-/feTZU7n85iYr83d2Z5AiDEoOqsuC7CsDCT6eiaY8xJhEPRdF/d+4niXVOKM6Cm6
-jBAyvd0zaziGfjk9DgNyp115j0WKWa5bIW4xRtVZjc8VX90xJc/bYNaBRHIpAlf2
-ltTW/+op2znFuCyKGo3Oy+dCMYYFaA6eFN0AkLppRQjbbpCBhqcqBT/mhDn4t/lX
-X0ykeVoQDF7Va/81XwVRHmyjdanPUIPTfPRm94KNPQx96N97qA4bLJyuQHCH2u2n
-FoJavjVsIE4iYdm8UXrNemHcSxH5/mc0zy4EZmFcV5cjjPOGG0jfKq+nwf/Yjj4D
-u9gqsPoUJbJRa4ZDhS4HIxaAjUz7tGM7zMN07RujHv41D198HRaG9Q7DlfEvr10l
-O1Hm13ZBONFLAzkopR6RctR9q5czxNM+4Gm2KHmgCY0c0f9BckgG/Jou5yD5m6Le
-ie2uPAmvylezkolwQOQvT8Jwg0DXJCxr5wkf09XHwQj02w47HAcLQxGEIYbpgNR1
-2KvxAmLBsX5VYc8T1yaw15zLKYs4SgsOkI26oQ==
------END CERTIFICATE-----
-
 # Issuer: CN=COMODO RSA Certification Authority O=COMODO CA Limited
 # Subject: CN=COMODO RSA Certification Authority O=COMODO CA Limited
 # Label: "COMODO RSA Certification Authority"
@@ -4261,56 +3628,6 @@
 Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=
 -----END CERTIFICATE-----
 
-# Issuer: CN=Certification Authority of WoSign G2 O=WoSign CA Limited
-# Subject: CN=Certification Authority of WoSign G2 O=WoSign CA Limited
-# Label: "Certification Authority of WoSign G2"
-# Serial: 142423943073812161787490648904721057092
-# MD5 Fingerprint: c8:1c:7d:19:aa:cb:71:93:f2:50:f8:52:a8:1e:ba:60
-# SHA1 Fingerprint: fb:ed:dc:90:65:b7:27:20:37:bc:55:0c:9c:56:de:bb:f2:78:94:e1
-# SHA256 Fingerprint: d4:87:a5:6f:83:b0:74:82:e8:5e:96:33:94:c1:ec:c2:c9:e5:1d:09:03:ee:94:6b:02:c3:01:58:1e:d9:9e:16
------BEGIN CERTIFICATE-----
-MIIDfDCCAmSgAwIBAgIQayXaioidfLwPBbOxemFFRDANBgkqhkiG9w0BAQsFADBY
-MQswCQYDVQQGEwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxLTArBgNV
-BAMTJENlcnRpZmljYXRpb24gQXV0aG9yaXR5IG9mIFdvU2lnbiBHMjAeFw0xNDEx
-MDgwMDU4NThaFw00NDExMDgwMDU4NThaMFgxCzAJBgNVBAYTAkNOMRowGAYDVQQK
-ExFXb1NpZ24gQ0EgTGltaXRlZDEtMCsGA1UEAxMkQ2VydGlmaWNhdGlvbiBBdXRo
-b3JpdHkgb2YgV29TaWduIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEAvsXEoCKASU+/2YcRxlPhuw+9YH+v9oIOH9ywjj2X4FA8jzrvZjtFB5sg+OPX
-JYY1kBaiXW8wGQiHC38Gsp1ij96vkqVg1CuAmlI/9ZqD6TRay9nVYlzmDuDfBpgO
-gHzKtB0TiGsOqCR3A9DuW/PKaZE1OVbFbeP3PU9ekzgkyhjpJMuSA93MHD0JcOQg
-5PGurLtzaaNjOg9FD6FKmsLRY6zLEPg95k4ot+vElbGs/V6r+kHLXZ1L3PR8du9n
-fwB6jdKgGlxNIuG12t12s9R23164i5jIFFTMaxeSt+BKv0mUYQs4kI9dJGwlezt5
-2eJ+na2fmKEG/HgUYFf47oB3sQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD
-VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU+mCp62XF3RYUCE4MD42b4Pdkr2cwDQYJ
-KoZIhvcNAQELBQADggEBAFfDejaCnI2Y4qtAqkePx6db7XznPWZaOzG73/MWM5H8
-fHulwqZm46qwtyeYP0nXYGdnPzZPSsvxFPpahygc7Y9BMsaV+X3avXtbwrAh449G
-3CE4Q3RM+zD4F3LBMvzIkRfEzFg3TgvMWvchNSiDbGAtROtSjFA9tWwS1/oJu2yy
-SrHFieT801LYYRf+epSEj3m2M1m6D8QL4nCgS3gu+sif/a+RZQp4OBXllxcU3fng
-LDT4ONCEIgDAFFEYKwLcMFrw6AF8NTojrwjkr6qOKEJJLvD1mTS+7Q9LGOHSJDy7
-XUe3IfKN0QqZjuNuPq1w4I+5ysxugTH2e5x6eeRncRg=
------END CERTIFICATE-----
-
-# Issuer: CN=CA WoSign ECC Root O=WoSign CA Limited
-# Subject: CN=CA WoSign ECC Root O=WoSign CA Limited
-# Label: "CA WoSign ECC Root"
-# Serial: 138625735294506723296996289575837012112
-# MD5 Fingerprint: 80:c6:53:ee:61:82:28:72:f0:ff:21:b9:17:ca:b2:20
-# SHA1 Fingerprint: d2:7a:d2:be:ed:94:c0:a1:3c:c7:25:21:ea:5d:71:be:81:19:f3:2b
-# SHA256 Fingerprint: 8b:45:da:1c:06:f7:91:eb:0c:ab:f2:6b:e5:88:f5:fb:23:16:5c:2e:61:4b:f8:85:56:2d:0d:ce:50:b2:9b:02
------BEGIN CERTIFICATE-----
-MIICCTCCAY+gAwIBAgIQaEpYcIBr8I8C+vbe6LCQkDAKBggqhkjOPQQDAzBGMQsw
-CQYDVQQGEwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNVBAMT
-EkNBIFdvU2lnbiBFQ0MgUm9vdDAeFw0xNDExMDgwMDU4NThaFw00NDExMDgwMDU4
-NThaMEYxCzAJBgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEb
-MBkGA1UEAxMSQ0EgV29TaWduIEVDQyBSb290MHYwEAYHKoZIzj0CAQYFK4EEACID
-YgAE4f2OuEMkq5Z7hcK6C62N4DrjJLnSsb6IOsq/Srj57ywvr1FQPEd1bPiUt5v8
-KB7FVMxjnRZLU8HnIKvNrCXSf4/CwVqCXjCLelTOA7WRf6qU0NGKSMyCBSah1VES
-1ns2o0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
-FgQUqv3VWqP2h4syhf3RMluARZPzA7gwCgYIKoZIzj0EAwMDaAAwZQIxAOSkhLCB
-1T2wdKyUpOgOPQB0TKGXa/kNUTyh2Tv0Daupn75OcsqF1NnstTJFGG+rrQIwfcf3
-aWMvoeGY7xMQ0Xk/0f7qO3/eVvSQsRUR2LIiFdAvwyYua/GRspBl9JrmkO5K
------END CERTIFICATE-----
-
 # Issuer: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A.
 # Subject: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A.
 # Label: "SZAFIR ROOT CA2"
@@ -4874,3 +4191,285 @@
 8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf
 lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM=
 -----END CERTIFICATE-----
+
+# Issuer: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD.
+# Subject: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD.
+# Label: "GDCA TrustAUTH R5 ROOT"
+# Serial: 9009899650740120186
+# MD5 Fingerprint: 63:cc:d9:3d:34:35:5c:6f:53:a3:e2:08:70:48:1f:b4
+# SHA1 Fingerprint: 0f:36:38:5b:81:1a:25:c3:9b:31:4e:83:ca:e9:34:66:70:cc:74:b4
+# SHA256 Fingerprint: bf:ff:8f:d0:44:33:48:7d:6a:8a:a6:0c:1a:29:76:7a:9f:c2:bb:b0:5e:42:0f:71:3a:13:b9:92:89:1d:38:93
+-----BEGIN CERTIFICATE-----
+MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE
+BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ
+IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0
+MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVowYjELMAkGA1UEBhMCQ04xMjAwBgNV
+BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8w
+HQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJj
+Dp6L3TQsAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBj
+TnnEt1u9ol2x8kECK62pOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+u
+KU49tm7srsHwJ5uu4/Ts765/94Y9cnrrpftZTqfrlYwiOXnhLQiPzLyRuEH3FMEj
+qcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ9Cy5WmYqsBebnh52nUpm
+MUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQxXABZG12
+ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloP
+zgsMR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3Gk
+L30SgLdTMEZeS1SZD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeC
+jGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4oR24qoAATILnsn8JuLwwoC8N9VKejveSswoA
+HQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx9hoh49pwBiFYFIeFd3mqgnkC
+AwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlRMA8GA1UdEwEB
+/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg
+p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZm
+DRd9FBUb1Ov9H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5
+COmSdI31R9KrO9b7eGZONn356ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ry
+L3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd+PwyvzeG5LuOmCd+uh8W4XAR8gPf
+JWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQHtZa37dG/OaG+svg
+IHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBDF8Io
+2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV
+09tL7ECQ8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQ
+XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq
+T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe
+MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g==
+-----END CERTIFICATE-----
+
+# Issuer: CN=TrustCor RootCert CA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority
+# Subject: CN=TrustCor RootCert CA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority
+# Label: "TrustCor RootCert CA-1"
+# Serial: 15752444095811006489
+# MD5 Fingerprint: 6e:85:f1:dc:1a:00:d3:22:d5:b2:b2:ac:6b:37:05:45
+# SHA1 Fingerprint: ff:bd:cd:e7:82:c8:43:5e:3c:6f:26:86:5c:ca:a8:3a:45:5b:c3:0a
+# SHA256 Fingerprint: d4:0e:9c:86:cd:8f:e4:68:c1:77:69:59:f4:9e:a7:74:fa:54:86:84:b6:c4:06:f3:90:92:61:f4:dc:e2:57:5c
+-----BEGIN CERTIFICATE-----
+MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYD
+VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk
+MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U
+cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29y
+IFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkxMjMxMTcyMzE2WjCB
+pDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFuYW1h
+IENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUG
+A1UECwweVHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZU
+cnVzdENvciBSb290Q2VydCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAv463leLCJhJrMxnHQFgKq1mqjQCj/IDHUHuO1CAmujIS2CNUSSUQIpid
+RtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4pQa81QBeCQryJ3pS/C3V
+seq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0JEsq1pme
+9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CV
+EY4hgLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorW
+hnAbJN7+KIor0Gqw/Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/
+DeOxCbeKyKsZn3MzUOcwHwYDVR0jBBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcw
+DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD
+ggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5mDo4Nvu7Zp5I
+/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf
+ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZ
+yonnMlo2HD6CqFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djts
+L1Ac59v2Z3kf9YKVmgenFK+P3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdN
+zl/HHk484IkzlQsPpTLWPFp5LBk=
+-----END CERTIFICATE-----
+
+# Issuer: CN=TrustCor RootCert CA-2 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority
+# Subject: CN=TrustCor RootCert CA-2 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority
+# Label: "TrustCor RootCert CA-2"
+# Serial: 2711694510199101698
+# MD5 Fingerprint: a2:e1:f8:18:0b:ba:45:d5:c7:41:2a:bb:37:52:45:64
+# SHA1 Fingerprint: b8:be:6d:cb:56:f1:55:b9:63:d4:12:ca:4e:06:34:c7:94:b2:1c:c0
+# SHA256 Fingerprint: 07:53:e9:40:37:8c:1b:d5:e3:83:6e:39:5d:ae:a5:cb:83:9e:50:46:f1:bd:0e:ae:19:51:cf:10:fe:c7:c9:65
+-----BEGIN CERTIFICATE-----
+MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNV
+BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw
+IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy
+dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEfMB0GA1UEAwwWVHJ1c3RDb3Ig
+Um9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEyMzExNzI2MzlaMIGk
+MQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEg
+Q2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYD
+VQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRy
+dXN0Q29yIFJvb3RDZXJ0IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
+AoICAQCnIG7CKqJiJJWQdsg4foDSq8GbZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+
+QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9NkRvRUqdw6VC0xK5mC8tkq
+1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1oYxOdqHp
+2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nK
+DOObXUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hape
+az6LMvYHL1cEksr1/p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF
+3wP+TfSvPd9cW436cOGlfifHhi5qjxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88
+oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQPeSghYA2FFn3XVDjxklb9tTNM
+g9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+CtgrKAmrhQhJ8Z3
+mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh
+8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAd
+BgNVHQ4EFgQU2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6U
+nrybPZx9mCAZ5YwwYrIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYw
+DQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/hOsh80QA9z+LqBrWyOrsGS2h60COX
+dKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnpkpfbsEZC89NiqpX+
+MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv2wnL
+/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RX
+CI/hOWB3S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYa
+ZH9bDTMJBzN7Bj8RpFxwPIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW
+2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dvDDqPys/cA8GiCcjl/YBeyGBCARsaU1q7
+N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYURpFHmygk71dSTlxCnKr3
+Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANExdqtvArB
+As8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp
+5KeXRKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu
+1uwJ
+-----END CERTIFICATE-----
+
+# Issuer: CN=TrustCor ECA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority
+# Subject: CN=TrustCor ECA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority
+# Label: "TrustCor ECA-1"
+# Serial: 9548242946988625984
+# MD5 Fingerprint: 27:92:23:1d:0a:f5:40:7c:e9:e6:6b:9d:d8:f5:e7:6c
+# SHA1 Fingerprint: 58:d1:df:95:95:67:6b:63:c0:f0:5b:1c:17:4d:8b:84:0b:c8:78:bd
+# SHA256 Fingerprint: 5a:88:5d:b1:9c:01:d9:12:c5:75:93:88:93:8c:af:bb:df:03:1a:b2:d4:8e:91:ee:15:58:9b:42:97:1d:03:9c
+-----BEGIN CERTIFICATE-----
+MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYD
+VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk
+MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U
+cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFzAVBgNVBAMMDlRydXN0Q29y
+IEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3MjgwN1owgZwxCzAJBgNV
+BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw
+IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy
+dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3Ig
+RUNBLTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb
+3w9U73NjKYKtR8aja+3+XzP4Q1HpGjORMRegdMTUpwHmspI+ap3tDvl0mEDTPwOA
+BoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23xFUfJ3zSCNV2HykVh0A5
+3ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmcp0yJF4Ou
+owReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/
+wZ0+fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZF
+ZtS6mFjBAgMBAAGjYzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAf
+BgNVHSMEGDAWgBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/
+MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEABT41XBVwm8nHc2Fv
+civUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u/ukZMjgDfxT2
+AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F
+hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50
+soIipX1TH0XsJ5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BI
+WJZpTdwHjFGTot+fDz2LYLSCjaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1Wi
+tJ/X5g==
+-----END CERTIFICATE-----
+
+# Issuer: CN=SSL.com Root Certification Authority RSA O=SSL Corporation
+# Subject: CN=SSL.com Root Certification Authority RSA O=SSL Corporation
+# Label: "SSL.com Root Certification Authority RSA"
+# Serial: 8875640296558310041
+# MD5 Fingerprint: 86:69:12:c0:70:f1:ec:ac:ac:c2:d5:bc:a5:5b:a1:29
+# SHA1 Fingerprint: b7:ab:33:08:d1:ea:44:77:ba:14:80:12:5a:6f:bd:a9:36:49:0c:bb
+# SHA256 Fingerprint: 85:66:6a:56:2e:e0:be:5c:e9:25:c1:d8:89:0a:6f:76:a8:7e:c1:6d:4d:7d:5f:29:ea:74:19:cf:20:12:3b:69
+-----BEGIN CERTIFICATE-----
+MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE
+BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK
+DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp
+Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz
+OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv
+dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv
+bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN
+AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R
+xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX
+qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC
+C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3
+6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh
+/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF
+YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E
+JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc
+US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8
+ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm
++Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi
+M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV
+HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G
+A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV
+cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc
+Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs
+PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/
+q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0
+cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr
+a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I
+H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y
+K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu
+nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf
+oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY
+Ic2wBlX7Jz9TkHCpBB5XJ7k=
+-----END CERTIFICATE-----
+
+# Issuer: CN=SSL.com Root Certification Authority ECC O=SSL Corporation
+# Subject: CN=SSL.com Root Certification Authority ECC O=SSL Corporation
+# Label: "SSL.com Root Certification Authority ECC"
+# Serial: 8495723813297216424
+# MD5 Fingerprint: 2e:da:e4:39:7f:9c:8f:37:d1:70:9f:26:17:51:3a:8e
+# SHA1 Fingerprint: c3:19:7c:39:24:e6:54:af:1b:c4:ab:20:95:7a:e2:c3:0e:13:02:6a
+# SHA256 Fingerprint: 34:17:bb:06:cc:60:07:da:1b:96:1c:92:0b:8a:b4:ce:3f:ad:82:0e:4a:a3:0b:9a:cb:c4:a7:4e:bd:ce:bc:65
+-----BEGIN CERTIFICATE-----
+MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC
+VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T
+U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0
+aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz
+WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0
+b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS
+b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB
+BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI
+7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg
+CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud
+EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD
+VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T
+kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+
+gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl
+-----END CERTIFICATE-----
+
+# Issuer: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation
+# Subject: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation
+# Label: "SSL.com EV Root Certification Authority RSA R2"
+# Serial: 6248227494352943350
+# MD5 Fingerprint: e1:1e:31:58:1a:ae:54:53:02:f6:17:6a:11:7b:4d:95
+# SHA1 Fingerprint: 74:3a:f0:52:9b:d0:32:a0:f4:4a:83:cd:d4:ba:a9:7b:7c:2e:c4:9a
+# SHA256 Fingerprint: 2e:7b:f1:6c:c2:24:85:a7:bb:e2:aa:86:96:75:07:61:b0:ae:39:be:3b:2f:e9:d0:cc:6d:4e:f7:34:91:42:5c
+-----BEGIN CERTIFICATE-----
+MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV
+BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE
+CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy
+dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy
+MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G
+A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD
+DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq
+M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf
+OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa
+4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9
+HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR
+aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA
+b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ
+Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV
+PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO
+pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu
+UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY
+MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV
+HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4
+9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW
+s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5
+Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg
+cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM
+79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz
+/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt
+ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm
+Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK
+QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ
+w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi
+S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07
+mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w==
+-----END CERTIFICATE-----
+
+# Issuer: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation
+# Subject: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation
+# Label: "SSL.com EV Root Certification Authority ECC"
+# Serial: 3182246526754555285
+# MD5 Fingerprint: 59:53:22:65:83:42:01:54:c0:ce:42:b9:5a:7c:f2:90
+# SHA1 Fingerprint: 4c:dd:51:a3:d1:f5:20:32:14:b0:c6:c5:32:23:03:91:c7:46:42:6d
+# SHA256 Fingerprint: 22:a2:c1:f7:bd:ed:70:4c:c1:e7:01:b5:f4:08:c3:10:88:0f:e9:56:b5:de:2a:4a:44:f9:9c:87:3a:25:a7:c8
+-----BEGIN CERTIFICATE-----
+MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC
+VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T
+U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp
+Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx
+NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv
+dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv
+bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49
+AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA
+VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku
+WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP
+MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX
+5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ
+ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg
+h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg==
+-----END CERTIFICATE-----
diff --git a/examples/android/helloworld/.gitignore b/examples/android/helloworld/.gitignore
new file mode 100644
index 0000000..39fb081
--- /dev/null
+++ b/examples/android/helloworld/.gitignore
@@ -0,0 +1,9 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
+.externalNativeBuild
diff --git a/examples/android/helloworld/README.md b/examples/android/helloworld/README.md
new file mode 100644
index 0000000..ebb16d1
--- /dev/null
+++ b/examples/android/helloworld/README.md
@@ -0,0 +1,24 @@
+gRPC on Android
+==============
+
+Note: Building the protobuf dependency for Android requires
+https://github.com/google/protobuf/pull/3878. This fix will be in the next
+protobuf release, but until then must be manually patched in to
+`third_party/protobuf` to build gRPC for Android.
+
+PREREQUISITES
+-------------
+
+- Android SDK
+- Android NDK
+- `protoc` and `grpc_cpp_plugin` binaries on the host system
+
+INSTALL
+-------
+
+The example application can be built via Android Studio or on the command line
+using `gradle`:
+
+  ```sh
+  $ ./gradlew installDebug
+  ```
diff --git a/examples/android/helloworld/app/.gitignore b/examples/android/helloworld/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/examples/android/helloworld/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/examples/android/helloworld/app/CMakeLists.txt b/examples/android/helloworld/app/CMakeLists.txt
new file mode 100644
index 0000000..ad6c1b8
--- /dev/null
+++ b/examples/android/helloworld/app/CMakeLists.txt
@@ -0,0 +1,128 @@
+cmake_minimum_required(VERSION 3.4.1)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+
+set(helloworld_PROTOBUF_PROTOC_EXECUTABLE "/usr/local/bin/protoc" CACHE STRING "Protoc binary on host")
+set(helloworld_GRPC_CPP_PLUGIN_EXECUTABLE "/usr/local/bin/grpc_cpp_plugin" CACHE STRING "gRPC CPP plugin binary on host")
+
+set(GRPC_SRC_DIR ../../../../)
+
+set(GRPC_BUILD_DIR ../grpc/outputs/${ANDROID_ABI})
+file(MAKE_DIRECTORY ${GRPC_BUILD_DIR})
+
+add_subdirectory(${GRPC_SRC_DIR} ${GRPC_BUILD_DIR})
+
+include_directories(${GRPC_SRC_DIR}/include)
+
+add_library(libgrpc STATIC IMPORTED)
+set_target_properties(libgrpc PROPERTIES IMPORTED_LOCATION
+  ${GRPC_BUILD_DIR}/libgrpc.a)
+
+add_library(libgrpc++ STATIC IMPORTED)
+set_target_properties(libgrpc++ PROPERTIES IMPORTED_LOCATION
+  ${GRPC_BUILD_DIR}/libgrpc++.a)
+
+add_library(libgpr STATIC IMPORTED)
+set_target_properties(libgpr PROPERTIES IMPORTED_LOCATION
+  ${GRPC_BUILD_DIR}/libgpr.a)
+
+add_library(libaddress_sorting STATIC IMPORTED)
+set_target_properties(libaddress_sorting PROPERTIES IMPORTED_LOCATION
+  ${GRPC_BUILD_DIR}/libaddress_sorting.a)
+
+add_library(libcares STATIC IMPORTED)
+set_target_properties(libcares PROPERTIES IMPORTED_LOCATION
+  ${GRPC_BUILD_DIR}/third_party/cares/cares/lib/libcares.a)
+
+add_library(libzlib STATIC IMPORTED)
+set_target_properties(libzlib PROPERTIES IMPORTED_LOCATION
+  ${GRPC_BUILD_DIR}/third_party/zlib/libz.a)
+
+add_library(libcrypto STATIC IMPORTED)
+set_target_properties(libcrypto PROPERTIES IMPORTED_LOCATION
+  ${GRPC_BUILD_DIR}/third_party/boringssl/crypto/libcrypto.a)
+
+add_library(libssl STATIC IMPORTED)
+set_target_properties(libssl PROPERTIES IMPORTED_LOCATION
+  ${GRPC_BUILD_DIR}/third_party/boringssl/ssl/libssl.a)
+
+set(GRPC_PROTO_GENS_DIR ${CMAKE_BINARY_DIR}/gens)
+file(MAKE_DIRECTORY ${GRPC_PROTO_GENS_DIR})
+include_directories(${GRPC_PROTO_GENS_DIR})
+
+function(android_protobuf_grpc_generate_cpp SRC_FILES HDR_FILES INCLUDE_ROOT)
+  if(NOT ARGN)
+    message(SEND_ERROR "Error: android_protobuf_grpc_generate_cpp() called without any proto files")
+    return()
+  endif()
+
+  set(${SRC_FILES})
+  set(${HDR_FILES})
+  set(PROTOBUF_INCLUDE_PATH -I ${INCLUDE_ROOT})
+  foreach(FIL ${ARGN})
+    get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
+    get_filename_component(FIL_WE ${FIL} NAME_WE)
+    file(RELATIVE_PATH REL_FIL ${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_ROOT} ${ABS_FIL})
+    get_filename_component(REL_DIR ${REL_FIL} DIRECTORY)
+    set(RELFIL_WE "${REL_DIR}/${FIL_WE}")
+
+    list(APPEND ${SRC_FILES} "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.pb.cc")
+    list(APPEND ${HDR_FILES} "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.pb.h")
+    list(APPEND ${SRC_FILES} "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.grpc.pb.cc")
+    list(APPEND ${HDR_FILES} "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.grpc.pb.h")
+
+    add_custom_command(
+      OUTPUT "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.grpc.pb.cc"
+             "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.grpc.pb.h"
+             "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.pb.cc"
+             "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.pb.h"
+      COMMAND ${helloworld_PROTOBUF_PROTOC_EXECUTABLE}
+      ARGS --grpc_out=${GRPC_PROTO_GENS_DIR}
+        --cpp_out=${GRPC_PROTO_GENS_DIR}
+        --plugin=protoc-gen-grpc=${helloworld_GRPC_CPP_PLUGIN_EXECUTABLE}
+        ${PROTOBUF_INCLUDE_PATH}
+        ${REL_FIL}
+      WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+      DEPENDS ${helloworld_PROTOBUF_PROTOC_EXECUTABLE} ${helloworld_GRPC_CPP_PLUGIN_EXECUTABLE} ${ABS_FIL} )
+  endforeach()
+
+  set_source_files_properties(${${SRC_FILES}} ${${HDR_FILES}} PROPERTIES GENERATED TRUE)
+  set(${SRC_FILES} ${${SRC_FILES}} PARENT_SCOPE)
+  set(${HDR_FILES} ${${HDR_FILES}} PARENT_SCOPE)
+endfunction()
+
+set(PROTO_BASE_DIR ${GRPC_SRC_DIR}/examples/protos)
+
+android_protobuf_grpc_generate_cpp(
+  HELLOWORLD_PROTO_SRCS HELLOWORLD_PROTO_HDRS ${PROTO_BASE_DIR} ${PROTO_BASE_DIR}/helloworld.proto)
+
+add_library(helloworld_proto_lib
+  SHARED ${HELLOWORLD_PROTO_HDRS} ${HELLOWORLD_PROTO_SRCS})
+
+target_link_libraries(helloworld_proto_lib
+  libprotobuf
+  libgrpc++
+  android
+  log)
+
+find_library(log-lib
+ log)
+
+add_library(grpc-helloworld
+  SHARED src/main/cpp/grpc-helloworld.cc)
+
+target_include_directories(grpc-helloworld
+  PRIVATE ${HELLOWORLD_PROTO_HEADERS})
+
+target_link_libraries(grpc-helloworld
+  libgrpc++
+  libgrpc
+  libaddress_sorting
+  libzlib
+  libcares
+  libssl
+  libcrypto
+  helloworld_proto_lib
+  libgpr
+  android
+  ${log-lib})
diff --git a/examples/android/helloworld/app/build.gradle b/examples/android/helloworld/app/build.gradle
new file mode 100644
index 0000000..1d09fdc
--- /dev/null
+++ b/examples/android/helloworld/app/build.gradle
@@ -0,0 +1,56 @@
+apply plugin: 'com.android.application'
+
+android {
+    compileSdkVersion 26
+    defaultConfig {
+        applicationId "io.grpc.android.cpp.helloworldexample"
+        minSdkVersion 14
+        targetSdkVersion 26
+        versionCode 1
+        versionName "1.0"
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        externalNativeBuild {
+            cmake {
+                // The paths to the protoc and grpc_cpp_plugin binaries on the host system (codegen
+                // is not cross-compiled to Android)
+                def protoc = project.hasProperty('protoc') ?
+                        project.property('protoc') : '/usr/local/bin/protoc'
+                def grpc_cpp_plugin = project.hasProperty('grpc_cpp_plugin') ?
+                        project.property('grpc_cpp_plugin') : '/usr/local/bin/grpc_cpp_plugin'
+
+                cppFlags "-std=c++14 -frtti -fexceptions"
+                arguments '-DANDROID_STL=c++_static'
+                arguments '-DRUN_HAVE_POSIX_REGEX=0'
+                arguments '-DRUN_HAVE_STD_REGEX=0'
+                arguments '-DRUN_HAVE_STEADY_CLOCK=0'
+                arguments '-Dprotobuf_BUILD_PROTOC_BINARIES=off'
+                arguments '-DgRPC_BUILD_CODEGEN=off'
+                arguments '-Dhelloworld_PROTOBUF_PROTOC_EXECUTABLE=' + protoc
+                arguments '-Dhelloworld_GRPC_CPP_PLUGIN_EXECUTABLE=' + grpc_cpp_plugin
+            }
+        }
+        ndk.abiFilters 'x86'
+    }
+    buildTypes {
+        debug {
+            minifyEnabled false
+        }
+        release {
+            minifyEnabled true
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+    externalNativeBuild {
+        cmake {
+            path "CMakeLists.txt"
+        }
+    }
+}
+
+dependencies {
+    implementation fileTree(dir: 'libs', include: ['*.jar'])
+    implementation 'com.android.support:appcompat-v7:26.1.0'
+    testImplementation 'junit:junit:4.12'
+    androidTestImplementation 'com.android.support.test:runner:1.0.1'
+    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
+}
diff --git a/examples/android/helloworld/app/proguard-rules.pro b/examples/android/helloworld/app/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/examples/android/helloworld/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/examples/android/helloworld/app/src/main/AndroidManifest.xml b/examples/android/helloworld/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..8109da9
--- /dev/null
+++ b/examples/android/helloworld/app/src/main/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="io.grpc.helloworldexample.cpp" >
+
+    <uses-permission android:name="android.permission.INTERNET" />
+
+    <application
+        android:allowBackup="false"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/Base.V7.Theme.AppCompat.Light" >
+        <activity
+            android:name=".HelloworldActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/examples/android/helloworld/app/src/main/cpp/grpc-helloworld.cc b/examples/android/helloworld/app/src/main/cpp/grpc-helloworld.cc
new file mode 100644
index 0000000..7a31b78
--- /dev/null
+++ b/examples/android/helloworld/app/src/main/cpp/grpc-helloworld.cc
@@ -0,0 +1,142 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <atomic>
+
+#include <grpc++/grpc++.h>
+#include <jni.h>
+
+#include "helloworld.grpc.pb.h"
+
+using grpc::Channel;
+using grpc::ClientContext;
+using grpc::Server;
+using grpc::ServerBuilder;
+using grpc::ServerContext;
+using grpc::Status;
+using helloworld::Greeter;
+using helloworld::HelloReply;
+using helloworld::HelloRequest;
+
+std::atomic<bool> stop_server(false);
+
+// Logic and data behind the server's behavior.
+class GreeterServiceImpl final : public Greeter::Service {
+  Status SayHello(ServerContext* context, const HelloRequest* request,
+                  HelloReply* reply) override {
+    std::string prefix("Hello ");
+    reply->set_message(prefix + request->name());
+    return Status::OK;
+  }
+};
+
+void StartServer(JNIEnv* env, jobject obj, jmethodID is_cancelled_mid,
+                 int port) {
+  const int host_port_buf_size = 1024;
+  char host_port[host_port_buf_size];
+  snprintf(host_port, host_port_buf_size, "0.0.0.0:%d", port);
+
+  GreeterServiceImpl service;
+  ServerBuilder builder;
+  // Listen on the given address without any authentication mechanism.
+  builder.AddListeningPort(host_port, grpc::InsecureServerCredentials());
+  // Register "service" as the instance through which we'll communicate with
+  // clients. In this case it corresponds to an *synchronous* service.
+  builder.RegisterService(&service);
+  // Finally assemble the server.
+  std::unique_ptr<Server> server(builder.BuildAndStart());
+  while (!stop_server.load()) {
+    // Check with the Java code to see if the user has requested the server stop or the app is no
+    // longer in the foreground.
+    jboolean is_cancelled = env->CallBooleanMethod(obj, is_cancelled_mid);
+    if (is_cancelled == JNI_TRUE) {
+      stop_server = true;
+    }
+  }
+}
+
+class GreeterClient {
+ public:
+  GreeterClient(std::shared_ptr<Channel> channel)
+      : stub_(Greeter::NewStub(channel)) {}
+
+  // Assembles the client's payload, sends it and presents the response back
+  // from the server.
+  std::string SayHello(const std::string& user) {
+    // Data we are sending to the server.
+    HelloRequest request;
+    request.set_name(user);
+
+    // Container for the data we expect from the server.
+    HelloReply reply;
+
+    // Context for the client. It could be used to convey extra information to
+    // the server and/or tweak certain RPC behaviors.
+    ClientContext context;
+    // The actual RPC.
+    Status status = stub_->SayHello(&context, request, &reply);
+
+    if (status.ok()) {
+      return reply.message();
+    } else {
+      return status.error_message();
+    }
+  }
+
+ private:
+  std::unique_ptr<Greeter::Stub> stub_;
+};
+
+// Send an RPC and return the response. Invoked from Java code.
+extern "C" JNIEXPORT jstring JNICALL
+Java_io_grpc_helloworldexample_cpp_HelloworldActivity_sayHello(
+    JNIEnv* env, jobject obj_unused, jstring host_raw, jint port_raw,
+    jstring message_raw) {
+  const char* host_chars = env->GetStringUTFChars(host_raw, (jboolean*)0);
+  std::string host(host_chars, env->GetStringUTFLength(host_raw));
+
+  int port = static_cast<int>(port_raw);
+
+  const char* message_chars = env->GetStringUTFChars(message_raw, (jboolean*)0);
+  std::string message(message_chars, env->GetStringUTFLength(message_raw));
+
+  const int host_port_buf_size = 1024;
+  char host_port[host_port_buf_size];
+  snprintf(host_port, host_port_buf_size, "%s:%d", host.c_str(), port);
+
+  GreeterClient greeter(
+      grpc::CreateChannel(host_port, grpc::InsecureChannelCredentials()));
+  std::string reply = greeter.SayHello(message);
+
+  return env->NewStringUTF(reply.c_str());
+}
+
+// Start the server. Invoked from Java code.
+extern "C" JNIEXPORT void JNICALL
+Java_io_grpc_helloworldexample_cpp_HelloworldActivity_startServer(
+    JNIEnv* env, jobject obj_this, jint port_raw) {
+  int port = static_cast<int>(port_raw);
+
+  jclass cls = env->GetObjectClass(obj_this);
+  jmethodID is_cancelled_mid =
+      env->GetMethodID(cls, "isRunServerTaskCancelled", "()Z");
+
+  stop_server = false;
+
+  StartServer(env, obj_this, is_cancelled_mid, port);
+}
diff --git a/examples/android/helloworld/app/src/main/java/io/grpc/helloworldexample/cpp/HelloworldActivity.java b/examples/android/helloworld/app/src/main/java/io/grpc/helloworldexample/cpp/HelloworldActivity.java
new file mode 100644
index 0000000..ae5c88b
--- /dev/null
+++ b/examples/android/helloworld/app/src/main/java/io/grpc/helloworldexample/cpp/HelloworldActivity.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2018, gRPC Authors 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.
+ */
+
+package io.grpc.helloworldexample.cpp;
+
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.text.TextUtils;
+import android.text.method.ScrollingMovementMethod;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+import java.lang.ref.WeakReference;
+
+public class HelloworldActivity extends AppCompatActivity {
+
+  static {
+    System.loadLibrary("grpc-helloworld");
+  }
+
+  private Button sendButton;
+  private Button serverButton;
+  private EditText hostEdit;
+  private EditText portEdit;
+  private EditText messageEdit;
+  private EditText serverPortEdit;
+  private TextView resultText;
+  private GrpcTask grpcTask;
+  private RunServerTask runServerTask;
+
+  @Override
+  protected void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+    setContentView(R.layout.activity_helloworld);
+    sendButton = (Button) findViewById(R.id.send_button);
+    serverButton = (Button) findViewById(R.id.server_button);
+    hostEdit = (EditText) findViewById(R.id.host_edit_text);
+    portEdit = (EditText) findViewById(R.id.port_edit_text);
+    messageEdit = (EditText) findViewById(R.id.message_edit_text);
+    serverPortEdit = (EditText) findViewById(R.id.server_port_edit_text);
+    resultText = (TextView) findViewById(R.id.grpc_response_text);
+    resultText.setMovementMethod(new ScrollingMovementMethod());
+  }
+
+  @Override
+  protected void onPause() {
+    super.onPause();
+    if (runServerTask != null) {
+      runServerTask.cancel(true);
+      runServerTask = null;
+      serverButton.setText("Start gRPC Server");
+    }
+    if (grpcTask != null) {
+      grpcTask.cancel(true);
+      grpcTask = null;
+    }
+  }
+
+  public void sendMessage(View view) {
+    ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE))
+        .hideSoftInputFromWindow(hostEdit.getWindowToken(), 0);
+    sendButton.setEnabled(false);
+    resultText.setText("");
+    grpcTask = new GrpcTask(this);
+    grpcTask.executeOnExecutor(
+        AsyncTask.THREAD_POOL_EXECUTOR,
+        hostEdit.getText().toString(),
+        messageEdit.getText().toString(),
+        portEdit.getText().toString());
+  }
+
+  public void startOrStopServer(View view) {
+    if (runServerTask != null) {
+      runServerTask.cancel(true);
+      runServerTask = null;
+      serverButton.setText("Start gRPC Server");
+      Toast.makeText(this, "Server stopped", Toast.LENGTH_SHORT).show();
+    } else {
+      runServerTask = new RunServerTask(this);
+      String portStr = serverPortEdit.getText().toString();
+      int port = TextUtils.isEmpty(portStr) ? 50051 : Integer.valueOf(portStr);
+      runServerTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, port);
+      serverButton.setText("Stop gRPC Server");
+      Toast.makeText(this, "Server started on port " + port, Toast.LENGTH_SHORT).show();
+    }
+  }
+
+  private static class RunServerTask extends AsyncTask<Integer, Void, Void> {
+    private final WeakReference<HelloworldActivity> activityReference;
+
+    private RunServerTask(HelloworldActivity activity) {
+      this.activityReference = new WeakReference<HelloworldActivity>(activity);
+    }
+
+    @Override
+    protected Void doInBackground(Integer... params) {
+      int port = params[0];
+      HelloworldActivity activity = activityReference.get();
+      if (activity != null) {
+        activity.startServer(port);
+      }
+      return null;
+    }
+  }
+
+  private static class GrpcTask extends AsyncTask<String, Void, String> {
+    private final WeakReference<HelloworldActivity> activityReference;
+
+    private GrpcTask(HelloworldActivity activity) {
+      this.activityReference = new WeakReference<HelloworldActivity>(activity);
+    }
+
+    @Override
+    protected String doInBackground(String... params) {
+      String host = params[0];
+      String message = params[1];
+      String portStr = params[2];
+      int port = TextUtils.isEmpty(portStr) ? 50051 : Integer.valueOf(portStr);
+      return sayHello(host, port, message);
+    }
+
+    @Override
+    protected void onPostExecute(String result) {
+      HelloworldActivity activity = activityReference.get();
+      if (activity == null || isCancelled()) {
+        return;
+      }
+      TextView resultText = (TextView) activity.findViewById(R.id.grpc_response_text);
+      Button sendButton = (Button) activity.findViewById(R.id.send_button);
+      resultText.setText(result);
+      sendButton.setEnabled(true);
+    }
+  }
+
+  /**
+   * Invoked by native code to stop server when RunServerTask has been canceled, either by user
+   * request or upon app moving to background.
+   */
+  public boolean isRunServerTaskCancelled() {
+    if (runServerTask != null) {
+      return runServerTask.isCancelled();
+    }
+    return false;
+  }
+
+  public static native String sayHello(String host, int port, String message);
+
+  public native void startServer(int port);
+}
diff --git a/examples/android/helloworld/app/src/main/res/layout/activity_helloworld.xml b/examples/android/helloworld/app/src/main/res/layout/activity_helloworld.xml
new file mode 100644
index 0000000..5280469
--- /dev/null
+++ b/examples/android/helloworld/app/src/main/res/layout/activity_helloworld.xml
@@ -0,0 +1,86 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              tools:context=".HelloworldActivity"
+              android:orientation="vertical" >
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="12dp"
+        android:paddingBottom="12dp"
+        android:textSize="16sp"
+        android:text="gRPC Client Configuration"
+        android:textStyle="bold" />
+
+    <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal">
+        <EditText
+                android:id="@+id/host_edit_text"
+                android:layout_weight="2"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:hint="Enter Host" />
+        <EditText
+                android:id="@+id/port_edit_text"
+                android:layout_weight="1"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:inputType="numberDecimal"
+                android:hint="Enter Port" />
+    </LinearLayout>
+
+
+    <EditText
+            android:id="@+id/message_edit_text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:hint="Enter message to send" />
+
+    <Button
+            android:id="@+id/send_button"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:onClick="sendMessage"
+            android:text="Send gRPC Request" />
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="12dp"
+        android:paddingBottom="12dp"
+        android:textSize="16sp"
+        android:text="Response:" />
+
+    <TextView
+        android:id="@+id/grpc_response_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:scrollbars = "vertical"
+        android:textSize="16sp" />
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="12dp"
+        android:paddingBottom="12dp"
+        android:textSize="16sp"
+        android:text="gRPC Server Configuration"
+        android:textStyle="bold" />
+
+    <EditText
+        android:id="@+id/server_port_edit_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:hint="Server port" />
+
+    <Button
+        android:id="@+id/server_button"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:onClick="startOrStopServer"
+        android:text="Start gRPC Server" />
+
+</LinearLayout>
diff --git a/examples/android/helloworld/app/src/main/res/mipmap-hdpi/ic_launcher.png b/examples/android/helloworld/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
--- /dev/null
+++ b/examples/android/helloworld/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/examples/android/helloworld/app/src/main/res/mipmap-mdpi/ic_launcher.png b/examples/android/helloworld/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
--- /dev/null
+++ b/examples/android/helloworld/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/examples/android/helloworld/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/examples/android/helloworld/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
--- /dev/null
+++ b/examples/android/helloworld/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/examples/android/helloworld/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/examples/android/helloworld/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
--- /dev/null
+++ b/examples/android/helloworld/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/examples/android/helloworld/app/src/main/res/values/strings.xml b/examples/android/helloworld/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..7e916e3
--- /dev/null
+++ b/examples/android/helloworld/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+    <string name="app_name">GrpcHelloworldCppExample</string>
+</resources>
diff --git a/examples/android/helloworld/build.gradle b/examples/android/helloworld/build.gradle
new file mode 100644
index 0000000..bd5f337
--- /dev/null
+++ b/examples/android/helloworld/build.gradle
@@ -0,0 +1,24 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+    repositories {
+        google()
+        jcenter()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.0.1'
+        // NOTE: Do not place your application dependencies here; they belong
+        // in the individual module build.gradle files
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        jcenter()
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
diff --git a/examples/android/helloworld/gradle.properties b/examples/android/helloworld/gradle.properties
new file mode 100644
index 0000000..aac7c9b
--- /dev/null
+++ b/examples/android/helloworld/gradle.properties
@@ -0,0 +1,17 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/examples/android/helloworld/gradle/wrapper/gradle-wrapper.jar b/examples/android/helloworld/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..13372ae
--- /dev/null
+++ b/examples/android/helloworld/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/examples/android/helloworld/gradle/wrapper/gradle-wrapper.properties b/examples/android/helloworld/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..4c81831
--- /dev/null
+++ b/examples/android/helloworld/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Thu Jan 25 11:45:30 PST 2018
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
diff --git a/examples/android/helloworld/gradlew b/examples/android/helloworld/gradlew
new file mode 100755
index 0000000..9d82f78
--- /dev/null
+++ b/examples/android/helloworld/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/examples/android/helloworld/gradlew.bat b/examples/android/helloworld/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/examples/android/helloworld/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/examples/android/helloworld/settings.gradle b/examples/android/helloworld/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/examples/android/helloworld/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/examples/cpp/helloworld/cocoapods/HelloWorldCpp/ViewController.mm b/examples/cpp/helloworld/cocoapods/HelloWorldCpp/ViewController.mm
index 6ff1ca5..18a0972 100644
--- a/examples/cpp/helloworld/cocoapods/HelloWorldCpp/ViewController.mm
+++ b/examples/cpp/helloworld/cocoapods/HelloWorldCpp/ViewController.mm
@@ -17,9 +17,9 @@
  */
 
 #import "ViewController.h"
-#import <grpc++/grpc++.h>
-#include <grpc++/generic/generic_stub.h>
-#include <grpc++/generic/async_generic_service.h>
+#import <grpcpp/grpcpp.h>
+#include <grpcpp/generic/generic_stub.h>
+#include <grpcpp/generic/async_generic_service.h>
 
 static void* tag(int i) { return (void*)(intptr_t)i; }
 
diff --git a/examples/cpp/helloworld/greeter_async_client.cc b/examples/cpp/helloworld/greeter_async_client.cc
index ddf6c1a..d7a9d52 100644
--- a/examples/cpp/helloworld/greeter_async_client.cc
+++ b/examples/cpp/helloworld/greeter_async_client.cc
@@ -20,7 +20,7 @@
 #include <memory>
 #include <string>
 
-#include <grpc++/grpc++.h>
+#include <grpcpp/grpcpp.h>
 #include <grpc/support/log.h>
 
 #include "helloworld.grpc.pb.h"
diff --git a/examples/cpp/helloworld/greeter_async_client2.cc b/examples/cpp/helloworld/greeter_async_client2.cc
index 3154e84..d5098b9 100644
--- a/examples/cpp/helloworld/greeter_async_client2.cc
+++ b/examples/cpp/helloworld/greeter_async_client2.cc
@@ -20,7 +20,7 @@
 #include <memory>
 #include <string>
 
-#include <grpc++/grpc++.h>
+#include <grpcpp/grpcpp.h>
 #include <grpc/support/log.h>
 #include <thread>
 
diff --git a/examples/cpp/helloworld/greeter_async_server.cc b/examples/cpp/helloworld/greeter_async_server.cc
index e40889a..a74673d 100644
--- a/examples/cpp/helloworld/greeter_async_server.cc
+++ b/examples/cpp/helloworld/greeter_async_server.cc
@@ -21,7 +21,7 @@
 #include <string>
 #include <thread>
 
-#include <grpc++/grpc++.h>
+#include <grpcpp/grpcpp.h>
 #include <grpc/support/log.h>
 
 #include "helloworld.grpc.pb.h"
diff --git a/examples/cpp/helloworld/greeter_client.cc b/examples/cpp/helloworld/greeter_client.cc
index 555fd8d..932583c 100644
--- a/examples/cpp/helloworld/greeter_client.cc
+++ b/examples/cpp/helloworld/greeter_client.cc
@@ -20,7 +20,7 @@
 #include <memory>
 #include <string>
 
-#include <grpc++/grpc++.h>
+#include <grpcpp/grpcpp.h>
 
 #ifdef BAZEL_BUILD
 #include "examples/protos/helloworld.grpc.pb.h"
diff --git a/examples/cpp/helloworld/greeter_server.cc b/examples/cpp/helloworld/greeter_server.cc
index 832f440..f36ad90 100644
--- a/examples/cpp/helloworld/greeter_server.cc
+++ b/examples/cpp/helloworld/greeter_server.cc
@@ -20,7 +20,7 @@
 #include <memory>
 #include <string>
 
-#include <grpc++/grpc++.h>
+#include <grpcpp/grpcpp.h>
 
 #ifdef BAZEL_BUILD
 #include "examples/protos/helloworld.grpc.pb.h"
diff --git a/examples/cpp/route_guide/route_guide_client.cc b/examples/cpp/route_guide/route_guide_client.cc
index b829866..a89ec16 100644
--- a/examples/cpp/route_guide/route_guide_client.cc
+++ b/examples/cpp/route_guide/route_guide_client.cc
@@ -24,10 +24,10 @@
 #include <thread>
 
 #include <grpc/grpc.h>
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/security/credentials.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/security/credentials.h>
 #include "helper.h"
 #include "route_guide.grpc.pb.h"
 
diff --git a/examples/cpp/route_guide/route_guide_server.cc b/examples/cpp/route_guide/route_guide_server.cc
index b071e35..5867c16 100644
--- a/examples/cpp/route_guide/route_guide_server.cc
+++ b/examples/cpp/route_guide/route_guide_server.cc
@@ -24,10 +24,10 @@
 #include <string>
 
 #include <grpc/grpc.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
-#include <grpc++/security/server_credentials.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
+#include <grpcpp/security/server_credentials.h>
 #include "helper.h"
 #include "route_guide.grpc.pb.h"
 
@@ -51,6 +51,7 @@
   return num * 3.1415926 /180;
 }
 
+// The formula is based on http://mathforum.org/library/drmath/view/51879.html
 float GetDistance(const Point& start, const Point& end) {
   const float kCoordFactor = 10000000.0;
   float lat_1 = start.latitude() / kCoordFactor;
diff --git a/examples/csharp/route_guide/RouteGuide/RouteGuideUtil.cs b/examples/csharp/route_guide/RouteGuide/RouteGuideUtil.cs
index 66c4a94..f9af190 100644
--- a/examples/csharp/route_guide/RouteGuide/RouteGuideUtil.cs
+++ b/examples/csharp/route_guide/RouteGuide/RouteGuideUtil.cs
@@ -52,26 +52,23 @@
 
         /// <summary>
         /// Calculate the distance between two points using the "haversine" formula.
-        /// This code was taken from http://www.movable-type.co.uk/scripts/latlong.html.
+        /// The formula is based on http://mathforum.org/library/drmath/view/51879.html
         /// </summary>
         /// <param name="start">the starting point</param>
         /// <param name="end">the end point</param>
         /// <returns>the distance between the points in meters</returns>
         public static double GetDistance(this Point start, Point end)
         {
-            double lat1 = start.GetLatitude();
-            double lat2 = end.GetLatitude();
-            double lon1 = start.GetLongitude();
-            double lon2 = end.GetLongitude();
-            int r = 6371000; // metres
-            double phi1 = ToRadians(lat1);
-            double phi2 = ToRadians(lat2);
-            double deltaPhi = ToRadians(lat2 - lat1);
-            double deltaLambda = ToRadians(lon2 - lon1);
+            int r = 6371000;  // earth radius in metres
+            double lat1 = ToRadians(start.GetLatitude());
+            double lat2 = ToRadians(end.GetLatitude());
+            double lon1 = ToRadians(start.GetLongitude());
+            double lon2 = ToRadians(end.GetLongitude());
+            double deltalat = lat2 - lat1;
+            double deltalon = lon2 - lon1;
 
-            double a = Math.Sin(deltaPhi / 2) * Math.Sin(deltaPhi / 2) + Math.Cos(phi1) * Math.Cos(phi2) * Math.Sin(deltaLambda / 2) * Math.Sin(deltaLambda / 2);
+            double a = Math.Sin(deltalat / 2) * Math.Sin(deltalat / 2) + Math.Cos(lat1) * Math.Cos(lat2) * Math.Sin(deltalon / 2) * Math.Sin(deltalon / 2);
             double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
-
             return r * c;
         }
 
diff --git a/examples/node/dynamic_codegen/route_guide/route_guide_server.js b/examples/node/dynamic_codegen/route_guide/route_guide_server.js
index ab537ff..f9028e8 100644
--- a/examples/node/dynamic_codegen/route_guide/route_guide_server.js
+++ b/examples/node/dynamic_codegen/route_guide/route_guide_server.js
@@ -103,7 +103,7 @@
 
 /**
  * Calculate the distance between two points using the "haversine" formula.
- * This code was taken from http://www.movable-type.co.uk/scripts/latlong.html.
+ * The formula is based on http://mathforum.org/library/drmath/view/51879.html.
  * @param start The starting point
  * @param end The end point
  * @return The distance between the points in meters
@@ -112,21 +112,18 @@
   function toRadians(num) {
     return num * Math.PI / 180;
   }
-  var lat1 = start.latitude / COORD_FACTOR;
-  var lat2 = end.latitude / COORD_FACTOR;
-  var lon1 = start.longitude / COORD_FACTOR;
-  var lon2 = end.longitude / COORD_FACTOR;
-  var R = 6371000; // metres
-  var φ1 = toRadians(lat1);
-  var φ2 = toRadians(lat2);
-  var Δφ = toRadians(lat2-lat1);
-  var Δλ = toRadians(lon2-lon1);
+  var R = 6371000;  // earth radius in metres
+  var lat1 = toRadians(start.latitude / COORD_FACTOR);
+  var lat2 = toRadians(end.latitude / COORD_FACTOR);
+  var lon1 = toRadians(start.longitude / COORD_FACTOR);
+  var lon2 = toRadians(end.longitude / COORD_FACTOR);
 
-  var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
-      Math.cos(φ1) * Math.cos(φ2) *
-      Math.sin(Δλ/2) * Math.sin(Δλ/2);
+  var deltalat = lat2-lat1;
+  var deltalon = lon2-lon1;
+  var a = Math.sin(deltalat/2) * Math.sin(deltalat/2) +
+      Math.cos(lat1) * Math.cos(lat2) *
+      Math.sin(dlon/2) * Math.sin(dlon/2);
   var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
-
   return R * c;
 }
 
diff --git a/examples/node/static_codegen/route_guide/route_guide_server.js b/examples/node/static_codegen/route_guide/route_guide_server.js
index ef00bbb..eecac62 100644
--- a/examples/node/static_codegen/route_guide/route_guide_server.js
+++ b/examples/node/static_codegen/route_guide/route_guide_server.js
@@ -102,7 +102,7 @@
 
 /**
  * Calculate the distance between two points using the "haversine" formula.
- * This code was taken from http://www.movable-type.co.uk/scripts/latlong.html.
+ * The formula is based on http://mathforum.org/library/drmath/view/51879.html.
  * @param start The starting point
  * @param end The end point
  * @return The distance between the points in meters
@@ -111,21 +111,18 @@
   function toRadians(num) {
     return num * Math.PI / 180;
   }
-  var lat1 = start.getLatitude() / COORD_FACTOR;
-  var lat2 = end.getLatitude() / COORD_FACTOR;
-  var lon1 = start.getLongitude() / COORD_FACTOR;
-  var lon2 = end.getLongitude() / COORD_FACTOR;
-  var R = 6371000; // metres
-  var φ1 = toRadians(lat1);
-  var φ2 = toRadians(lat2);
-  var Δφ = toRadians(lat2-lat1);
-  var Δλ = toRadians(lon2-lon1);
+  var R = 6371000;  // earth radius in metres
+  var lat1 = toRadians(start.getLatitude() / COORD_FACTOR);
+  var lat2 = toRadians(end.getLatitude() / COORD_FACTOR);
+  var lon1 = toRadians(start.getLongitude() / COORD_FACTOR);
+  var lon2 = toRadians(end.getLongitude() / COORD_FACTOR);
 
-  var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
-      Math.cos(φ1) * Math.cos(φ2) *
-      Math.sin(Δλ/2) * Math.sin(Δλ/2);
+  var deltalat = lat2-lat1;
+  var deltalon = lon2-lon1;
+  var a = Math.sin(deltalat/2) * Math.sin(deltalat/2) +
+      Math.cos(lat1) * Math.cos(lat2) *
+      Math.sin(deltalon/2) * Math.sin(deltalon/2);
   var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
-
   return R * c;
 }
 
diff --git a/examples/python/interceptors/headers/generic_client_interceptor.py b/examples/python/interceptors/headers/generic_client_interceptor.py
index 30b0755..d2bb7e5 100644
--- a/examples/python/interceptors/headers/generic_client_interceptor.py
+++ b/examples/python/interceptors/headers/generic_client_interceptor.py
@@ -33,14 +33,14 @@
                                request):
         new_details, new_request_iterator, postprocess = self._fn(
             client_call_details, iter((request,)), False, True)
-        response_it = continuation(new_details, new_request_iterator)
+        response_it = continuation(new_details, next(new_request_iterator))
         return postprocess(response_it) if postprocess else response_it
 
     def intercept_stream_unary(self, continuation, client_call_details,
                                request_iterator):
         new_details, new_request_iterator, postprocess = self._fn(
             client_call_details, request_iterator, True, False)
-        response = continuation(new_details, next(new_request_iterator))
+        response = continuation(new_details, new_request_iterator)
         return postprocess(response) if postprocess else response
 
     def intercept_stream_stream(self, continuation, client_call_details,
diff --git a/examples/python/route_guide/route_guide_server.py b/examples/python/route_guide/route_guide_server.py
index f10008f..1969fdd 100644
--- a/examples/python/route_guide/route_guide_server.py
+++ b/examples/python/route_guide/route_guide_server.py
@@ -46,6 +46,7 @@
     delta_lat_rad = math.radians(lat_2 - lat_1)
     delta_lon_rad = math.radians(lon_2 - lon_1)
 
+    # Formula is based on http://mathforum.org/library/drmath/view/51879.html
     a = (pow(math.sin(delta_lat_rad / 2), 2) +
          (math.cos(lat_rad_1) * math.cos(lat_rad_2) * pow(
              math.sin(delta_lon_rad / 2), 2)))
diff --git a/examples/ruby/route_guide/route_guide_server.rb b/examples/ruby/route_guide/route_guide_server.rb
index 8ea07a2..5eb268b 100755
--- a/examples/ruby/route_guide/route_guide_server.rb
+++ b/examples/ruby/route_guide/route_guide_server.rb
@@ -32,19 +32,18 @@
 RADIUS = 637_100
 
 # Determines the distance between two points.
+# The formula is based on http://mathforum.org/library/drmath/view/51879.html.
 def calculate_distance(point_a, point_b)
   to_radians = proc { |x| x * Math::PI / 180 }
-  lat_a = point_a.latitude / COORD_FACTOR
-  lat_b = point_b.latitude / COORD_FACTOR
-  long_a = point_a.longitude / COORD_FACTOR
-  long_b = point_b.longitude / COORD_FACTOR
-  φ1 = to_radians.call(lat_a)
-  φ2 = to_radians.call(lat_b)
-  Δφ = to_radians.call(lat_a - lat_b)
-  Δλ = to_radians.call(long_a - long_b)
-  a = Math.sin(Δφ / 2)**2 +
-      Math.cos(φ1) * Math.cos(φ2) +
-      Math.sin(Δλ / 2)**2
+  lat_a = to_radians.call(point_a.latitude / COORD_FACTOR)
+  lat_b = to_radians.call(point_b.latitude / COORD_FACTOR)
+  lon_a = to_radians.call(point_a.longitude / COORD_FACTOR)
+  lon_b = to_radians.call(point_b.longitude / COORD_FACTOR)
+  delta_lat = lat_a - lat_b
+  delta_lon = lon_a - lon_b
+  a = Math.sin(delta_lat / 2)**2 +
+      Math.cos(lat_a) * Math.cos(lat_b) +
+      Math.sin(delta_lon / 2)**2
   (2 * RADIUS *  Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))).to_i
 end
 
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index bbf3f7f..f53e9db 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -23,15 +23,15 @@
 Pod::Spec.new do |s|
   s.name     = 'gRPC-C++'
   # TODO (mxyan): use version that match gRPC version when pod is stabilized
-  # version = '1.10.0-dev'
-  version = '0.0.1'
+  # version = '1.11.0-dev'
+  version = '0.0.2'
   s.version  = version
   s.summary  = 'gRPC C++ library'
   s.homepage = 'https://grpc.io'
   s.license  = 'Apache License, Version 2.0'
   s.authors  = { 'The gRPC contributors' => 'grpc-packages@google.com' }
 
-  grpc_version = '1.10.0-dev'
+  grpc_version = '1.11.0-dev'
 
   s.source = {
     :git => 'https://github.com/grpc/grpc.git',
@@ -42,8 +42,14 @@
   s.osx.deployment_target = '10.9'
   s.requires_arc = false
 
-  # Add include prefix `grpc++` (i.e. `#include <grpc++/xxx.h>`).
-  s.header_dir = 'grpc++'
+  name = 'grpcpp'
+  # Use `grpcpp` as framework name so that `#include <grpcpp/xxx.h>` works when built as
+  # framework.
+  s.module_name = name
+
+  # Add include prefix `grpcpp` so that `#include <grpcpp/xxx.h>` works when built as static
+  # library.
+  s.header_dir = name
 
   s.pod_target_xcconfig = {
     'HEADER_SEARCH_PATHS' => '"$(inherited)" "$(PODS_TARGET_SRCROOT)/include"',
@@ -63,84 +69,86 @@
 
   s.default_subspecs = 'Interface', 'Implementation'
 
-  s.subspec 'Interface' do |ss|
-    ss.header_mappings_dir = 'include/grpc++'
+  s.header_mappings_dir = 'include/grpcpp'
 
-    ss.source_files = 'include/grpc++/alarm.h',
-                      'include/grpc++/channel.h',
-                      'include/grpc++/client_context.h',
-                      'include/grpc++/completion_queue.h',
-                      'include/grpc++/create_channel.h',
-                      'include/grpc++/create_channel_posix.h',
-                      'include/grpc++/ext/health_check_service_server_builder_option.h',
-                      'include/grpc++/generic/async_generic_service.h',
-                      'include/grpc++/generic/generic_stub.h',
-                      'include/grpc++/grpc++.h',
-                      'include/grpc++/health_check_service_interface.h',
-                      'include/grpc++/impl/call.h',
-                      'include/grpc++/impl/channel_argument_option.h',
-                      'include/grpc++/impl/client_unary_call.h',
-                      'include/grpc++/impl/codegen/core_codegen.h',
-                      'include/grpc++/impl/grpc_library.h',
-                      'include/grpc++/impl/method_handler_impl.h',
-                      'include/grpc++/impl/rpc_method.h',
-                      'include/grpc++/impl/rpc_service_method.h',
-                      'include/grpc++/impl/serialization_traits.h',
-                      'include/grpc++/impl/server_builder_option.h',
-                      'include/grpc++/impl/server_builder_plugin.h',
-                      'include/grpc++/impl/server_initializer.h',
-                      'include/grpc++/impl/service_type.h',
-                      'include/grpc++/resource_quota.h',
-                      'include/grpc++/security/auth_context.h',
-                      'include/grpc++/security/auth_metadata_processor.h',
-                      'include/grpc++/security/credentials.h',
-                      'include/grpc++/security/server_credentials.h',
-                      'include/grpc++/server.h',
-                      'include/grpc++/server_builder.h',
-                      'include/grpc++/server_context.h',
-                      'include/grpc++/server_posix.h',
-                      'include/grpc++/support/async_stream.h',
-                      'include/grpc++/support/async_unary_call.h',
-                      'include/grpc++/support/byte_buffer.h',
-                      'include/grpc++/support/channel_arguments.h',
-                      'include/grpc++/support/config.h',
-                      'include/grpc++/support/slice.h',
-                      'include/grpc++/support/status.h',
-                      'include/grpc++/support/status_code_enum.h',
-                      'include/grpc++/support/string_ref.h',
-                      'include/grpc++/support/stub_options.h',
-                      'include/grpc++/support/sync_stream.h',
-                      'include/grpc++/support/time.h',
-                      'include/grpc++/impl/codegen/async_stream.h',
-                      'include/grpc++/impl/codegen/async_unary_call.h',
-                      'include/grpc++/impl/codegen/byte_buffer.h',
-                      'include/grpc++/impl/codegen/call.h',
-                      'include/grpc++/impl/codegen/call_hook.h',
-                      'include/grpc++/impl/codegen/channel_interface.h',
-                      'include/grpc++/impl/codegen/client_context.h',
-                      'include/grpc++/impl/codegen/client_unary_call.h',
-                      'include/grpc++/impl/codegen/completion_queue.h',
-                      'include/grpc++/impl/codegen/completion_queue_tag.h',
-                      'include/grpc++/impl/codegen/config.h',
-                      'include/grpc++/impl/codegen/core_codegen_interface.h',
-                      'include/grpc++/impl/codegen/create_auth_context.h',
-                      'include/grpc++/impl/codegen/grpc_library.h',
-                      'include/grpc++/impl/codegen/metadata_map.h',
-                      'include/grpc++/impl/codegen/method_handler_impl.h',
-                      'include/grpc++/impl/codegen/rpc_method.h',
-                      'include/grpc++/impl/codegen/rpc_service_method.h',
-                      'include/grpc++/impl/codegen/security/auth_context.h',
-                      'include/grpc++/impl/codegen/serialization_traits.h',
-                      'include/grpc++/impl/codegen/server_context.h',
-                      'include/grpc++/impl/codegen/server_interface.h',
-                      'include/grpc++/impl/codegen/service_type.h',
-                      'include/grpc++/impl/codegen/slice.h',
-                      'include/grpc++/impl/codegen/status.h',
-                      'include/grpc++/impl/codegen/status_code_enum.h',
-                      'include/grpc++/impl/codegen/string_ref.h',
-                      'include/grpc++/impl/codegen/stub_options.h',
-                      'include/grpc++/impl/codegen/sync_stream.h',
-                      'include/grpc++/impl/codegen/time.h'
+  s.subspec 'Interface' do |ss|
+    ss.header_mappings_dir = 'include/grpcpp'
+
+    ss.source_files = 'include/grpcpp/alarm.h',
+                      'include/grpcpp/channel.h',
+                      'include/grpcpp/client_context.h',
+                      'include/grpcpp/completion_queue.h',
+                      'include/grpcpp/create_channel.h',
+                      'include/grpcpp/create_channel_posix.h',
+                      'include/grpcpp/ext/health_check_service_server_builder_option.h',
+                      'include/grpcpp/generic/async_generic_service.h',
+                      'include/grpcpp/generic/generic_stub.h',
+                      'include/grpcpp/grpcpp.h',
+                      'include/grpcpp/health_check_service_interface.h',
+                      'include/grpcpp/impl/call.h',
+                      'include/grpcpp/impl/channel_argument_option.h',
+                      'include/grpcpp/impl/client_unary_call.h',
+                      'include/grpcpp/impl/codegen/core_codegen.h',
+                      'include/grpcpp/impl/grpc_library.h',
+                      'include/grpcpp/impl/method_handler_impl.h',
+                      'include/grpcpp/impl/rpc_method.h',
+                      'include/grpcpp/impl/rpc_service_method.h',
+                      'include/grpcpp/impl/serialization_traits.h',
+                      'include/grpcpp/impl/server_builder_option.h',
+                      'include/grpcpp/impl/server_builder_plugin.h',
+                      'include/grpcpp/impl/server_initializer.h',
+                      'include/grpcpp/impl/service_type.h',
+                      'include/grpcpp/resource_quota.h',
+                      'include/grpcpp/security/auth_context.h',
+                      'include/grpcpp/security/auth_metadata_processor.h',
+                      'include/grpcpp/security/credentials.h',
+                      'include/grpcpp/security/server_credentials.h',
+                      'include/grpcpp/server.h',
+                      'include/grpcpp/server_builder.h',
+                      'include/grpcpp/server_context.h',
+                      'include/grpcpp/server_posix.h',
+                      'include/grpcpp/support/async_stream.h',
+                      'include/grpcpp/support/async_unary_call.h',
+                      'include/grpcpp/support/byte_buffer.h',
+                      'include/grpcpp/support/channel_arguments.h',
+                      'include/grpcpp/support/config.h',
+                      'include/grpcpp/support/slice.h',
+                      'include/grpcpp/support/status.h',
+                      'include/grpcpp/support/status_code_enum.h',
+                      'include/grpcpp/support/string_ref.h',
+                      'include/grpcpp/support/stub_options.h',
+                      'include/grpcpp/support/sync_stream.h',
+                      'include/grpcpp/support/time.h',
+                      'include/grpcpp/impl/codegen/async_stream.h',
+                      'include/grpcpp/impl/codegen/async_unary_call.h',
+                      'include/grpcpp/impl/codegen/byte_buffer.h',
+                      'include/grpcpp/impl/codegen/call.h',
+                      'include/grpcpp/impl/codegen/call_hook.h',
+                      'include/grpcpp/impl/codegen/channel_interface.h',
+                      'include/grpcpp/impl/codegen/client_context.h',
+                      'include/grpcpp/impl/codegen/client_unary_call.h',
+                      'include/grpcpp/impl/codegen/completion_queue.h',
+                      'include/grpcpp/impl/codegen/completion_queue_tag.h',
+                      'include/grpcpp/impl/codegen/config.h',
+                      'include/grpcpp/impl/codegen/core_codegen_interface.h',
+                      'include/grpcpp/impl/codegen/create_auth_context.h',
+                      'include/grpcpp/impl/codegen/grpc_library.h',
+                      'include/grpcpp/impl/codegen/metadata_map.h',
+                      'include/grpcpp/impl/codegen/method_handler_impl.h',
+                      'include/grpcpp/impl/codegen/rpc_method.h',
+                      'include/grpcpp/impl/codegen/rpc_service_method.h',
+                      'include/grpcpp/impl/codegen/security/auth_context.h',
+                      'include/grpcpp/impl/codegen/serialization_traits.h',
+                      'include/grpcpp/impl/codegen/server_context.h',
+                      'include/grpcpp/impl/codegen/server_interface.h',
+                      'include/grpcpp/impl/codegen/service_type.h',
+                      'include/grpcpp/impl/codegen/slice.h',
+                      'include/grpcpp/impl/codegen/status.h',
+                      'include/grpcpp/impl/codegen/status_code_enum.h',
+                      'include/grpcpp/impl/codegen/string_ref.h',
+                      'include/grpcpp/impl/codegen/stub_options.h',
+                      'include/grpcpp/impl/codegen/sync_stream.h',
+                      'include/grpcpp/impl/codegen/time.h'
   end
 
   s.subspec 'Implementation' do |ss|
@@ -149,7 +157,7 @@
     ss.dependency 'gRPC-Core', grpc_version
     ss.dependency 'nanopb', '~> 0.3'
 
-    ss.source_files = 'include/grpc++/impl/codegen/core_codegen.h',
+    ss.source_files = 'include/grpcpp/impl/codegen/core_codegen.h',
                       'src/cpp/client/secure_credentials.h',
                       'src/cpp/common/secure_auth_context.h',
                       'src/cpp/server/secure_server_credentials.h',
@@ -206,20 +214,26 @@
                       'src/core/lib/gpr/arena.h',
                       'src/core/lib/gpr/env.h',
                       'src/core/lib/gpr/fork.h',
+                      'src/core/lib/gpr/host_port.h',
                       'src/core/lib/gpr/mpscq.h',
                       'src/core/lib/gpr/murmur_hash.h',
                       'src/core/lib/gpr/spinlock.h',
                       'src/core/lib/gpr/string.h',
                       'src/core/lib/gpr/string_windows.h',
-                      'src/core/lib/gpr/thd_internal.h',
                       'src/core/lib/gpr/time_precise.h',
+                      'src/core/lib/gpr/tls.h',
+                      'src/core/lib/gpr/tls_gcc.h',
+                      'src/core/lib/gpr/tls_msvc.h',
+                      'src/core/lib/gpr/tls_pthread.h',
                       'src/core/lib/gpr/tmpfile.h',
+                      'src/core/lib/gpr/useful.h',
                       'src/core/lib/gprpp/abstract.h',
                       'src/core/lib/gprpp/atomic.h',
                       'src/core/lib/gprpp/atomic_with_atm.h',
                       'src/core/lib/gprpp/atomic_with_std.h',
                       'src/core/lib/gprpp/manual_constructor.h',
                       'src/core/lib/gprpp/memory.h',
+                      'src/core/lib/gprpp/thd.h',
                       'src/core/lib/profiling/timers.h',
                       'src/core/ext/transport/chttp2/transport/bin_decoder.h',
                       'src/core/ext/transport/chttp2/transport/bin_encoder.h',
@@ -246,6 +260,7 @@
                       'src/core/ext/filters/http/message_compress/message_compress_filter.h',
                       'src/core/ext/filters/http/server/http_server_filter.h',
                       'src/core/lib/security/context/security_context.h',
+                      'src/core/lib/security/credentials/alts/alts_credentials.h',
                       'src/core/lib/security/credentials/composite/composite_credentials.h',
                       'src/core/lib/security/credentials/credentials.h',
                       'src/core/lib/security/credentials/fake/fake_credentials.h',
@@ -257,22 +272,43 @@
                       'src/core/lib/security/credentials/oauth2/oauth2_credentials.h',
                       'src/core/lib/security/credentials/plugin/plugin_credentials.h',
                       'src/core/lib/security/credentials/ssl/ssl_credentials.h',
+                      'src/core/lib/security/security_connector/alts_security_connector.h',
+                      'src/core/lib/security/security_connector/security_connector.h',
                       'src/core/lib/security/transport/auth_filters.h',
-                      'src/core/lib/security/transport/lb_targets_info.h',
                       'src/core/lib/security/transport/secure_endpoint.h',
-                      'src/core/lib/security/transport/security_connector.h',
                       'src/core/lib/security/transport/security_handshaker.h',
+                      'src/core/lib/security/transport/target_authority_table.h',
                       'src/core/lib/security/transport/tsi_error.h',
                       'src/core/lib/security/util/json_util.h',
-                      'src/core/tsi/alts_transport_security.h',
-                      'src/core/tsi/fake_transport_security.h',
-                      'src/core/tsi/ssl_transport_security.h',
-                      'src/core/tsi/ssl_types.h',
-                      'src/core/tsi/transport_security_grpc.h',
+                      'src/core/tsi/alts/crypt/gsec.h',
+                      'src/core/tsi/alts/frame_protector/alts_counter.h',
+                      'src/core/tsi/alts/frame_protector/alts_crypter.h',
+                      'src/core/tsi/alts/frame_protector/alts_frame_protector.h',
+                      'src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h',
+                      'src/core/tsi/alts/frame_protector/frame_handler.h',
+                      'src/core/tsi/alts/handshaker/alts_handshaker_client.h',
+                      'src/core/tsi/alts/handshaker/alts_tsi_event.h',
+                      'src/core/tsi/alts/handshaker/alts_tsi_handshaker.h',
+                      'src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h',
+                      'src/core/lib/security/credentials/alts/check_gcp_environment.h',
+                      'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h',
+                      'src/core/tsi/alts/handshaker/alts_handshaker_service_api.h',
+                      'src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h',
+                      'src/core/tsi/alts/handshaker/alts_tsi_utils.h',
+                      'src/core/tsi/alts/handshaker/transport_security_common_api.h',
+                      'src/core/tsi/alts/handshaker/altscontext.pb.h',
+                      'src/core/tsi/alts/handshaker/handshaker.pb.h',
+                      'src/core/tsi/alts/handshaker/transport_security_common.pb.h',
                       'src/core/tsi/transport_security.h',
                       'src/core/tsi/transport_security_adapter.h',
                       'src/core/tsi/transport_security_interface.h',
-                      'src/core/ext/transport/chttp2/server/chttp2_server.h',
+                      'src/core/ext/transport/chttp2/client/chttp2_connector.h',
                       'src/core/ext/filters/client_channel/backup_poller.h',
                       'src/core/ext/filters/client_channel/client_channel.h',
                       'src/core/ext/filters/client_channel/client_channel_factory.h',
@@ -282,6 +318,7 @@
                       'src/core/ext/filters/client_channel/lb_policy.h',
                       'src/core/ext/filters/client_channel/lb_policy_factory.h',
                       'src/core/ext/filters/client_channel/lb_policy_registry.h',
+                      'src/core/ext/filters/client_channel/method_params.h',
                       'src/core/ext/filters/client_channel/parse_address.h',
                       'src/core/ext/filters/client_channel/proxy_mapper.h',
                       'src/core/ext/filters/client_channel/proxy_mapper_registry.h',
@@ -293,17 +330,28 @@
                       'src/core/ext/filters/client_channel/subchannel_index.h',
                       'src/core/ext/filters/client_channel/uri_parser.h',
                       'src/core/ext/filters/deadline/deadline_filter.h',
-                      'src/core/ext/transport/chttp2/client/chttp2_connector.h',
+                      'src/core/tsi/alts_transport_security.h',
+                      'src/core/tsi/fake_transport_security.h',
+                      'src/core/tsi/ssl/session_cache/ssl_session.h',
+                      'src/core/tsi/ssl/session_cache/ssl_session_cache.h',
+                      'src/core/tsi/ssl_transport_security.h',
+                      'src/core/tsi/ssl_types.h',
+                      'src/core/tsi/transport_security_grpc.h',
+                      'src/core/ext/transport/chttp2/server/chttp2_server.h',
                       'src/core/ext/transport/inproc/inproc_transport.h',
+                      'src/core/lib/avl/avl.h',
                       'src/core/lib/backoff/backoff.h',
                       'src/core/lib/channel/channel_args.h',
                       'src/core/lib/channel/channel_stack.h',
                       'src/core/lib/channel/channel_stack_builder.h',
+                      'src/core/lib/channel/channel_trace.h',
+                      'src/core/lib/channel/channel_trace_registry.h',
                       'src/core/lib/channel/connected_channel.h',
                       'src/core/lib/channel/context.h',
                       'src/core/lib/channel/handshaker.h',
                       'src/core/lib/channel/handshaker_factory.h',
                       'src/core/lib/channel/handshaker_registry.h',
+                      'src/core/lib/channel/status_util.h',
                       'src/core/lib/compression/algorithm_metadata.h',
                       'src/core/lib/compression/compression_internal.h',
                       'src/core/lib/compression/message_compress.h',
@@ -338,9 +386,9 @@
                       'src/core/lib/iomgr/gethostname.h',
                       'src/core/lib/iomgr/iocp_windows.h',
                       'src/core/lib/iomgr/iomgr.h',
+                      'src/core/lib/iomgr/iomgr_custom.h',
                       'src/core/lib/iomgr/iomgr_internal.h',
                       'src/core/lib/iomgr/iomgr_posix.h',
-                      'src/core/lib/iomgr/iomgr_uv.h',
                       'src/core/lib/iomgr/is_epollexclusive_available.h',
                       'src/core/lib/iomgr/load_file.h',
                       'src/core/lib/iomgr/lockfree_event.h',
@@ -348,14 +396,17 @@
                       'src/core/lib/iomgr/network_status_tracker.h',
                       'src/core/lib/iomgr/polling_entity.h',
                       'src/core/lib/iomgr/pollset.h',
+                      'src/core/lib/iomgr/pollset_custom.h',
                       'src/core/lib/iomgr/pollset_set.h',
+                      'src/core/lib/iomgr/pollset_set_custom.h',
                       'src/core/lib/iomgr/pollset_set_windows.h',
-                      'src/core/lib/iomgr/pollset_uv.h',
                       'src/core/lib/iomgr/pollset_windows.h',
                       'src/core/lib/iomgr/port.h',
                       'src/core/lib/iomgr/resolve_address.h',
+                      'src/core/lib/iomgr/resolve_address_custom.h',
                       'src/core/lib/iomgr/resource_quota.h',
                       'src/core/lib/iomgr/sockaddr.h',
+                      'src/core/lib/iomgr/sockaddr_custom.h',
                       'src/core/lib/iomgr/sockaddr_posix.h',
                       'src/core/lib/iomgr/sockaddr_utils.h',
                       'src/core/lib/iomgr/sockaddr_windows.h',
@@ -367,17 +418,16 @@
                       'src/core/lib/iomgr/sys_epoll_wrapper.h',
                       'src/core/lib/iomgr/tcp_client.h',
                       'src/core/lib/iomgr/tcp_client_posix.h',
+                      'src/core/lib/iomgr/tcp_custom.h',
                       'src/core/lib/iomgr/tcp_posix.h',
                       'src/core/lib/iomgr/tcp_server.h',
                       'src/core/lib/iomgr/tcp_server_utils_posix.h',
-                      'src/core/lib/iomgr/tcp_uv.h',
                       'src/core/lib/iomgr/tcp_windows.h',
                       'src/core/lib/iomgr/time_averaged_stats.h',
                       'src/core/lib/iomgr/timer.h',
-                      'src/core/lib/iomgr/timer_generic.h',
+                      'src/core/lib/iomgr/timer_custom.h',
                       'src/core/lib/iomgr/timer_heap.h',
                       'src/core/lib/iomgr/timer_manager.h',
-                      'src/core/lib/iomgr/timer_uv.h',
                       'src/core/lib/iomgr/udp_server.h',
                       'src/core/lib/iomgr/unix_sockets_posix.h',
                       'src/core/lib/iomgr/wakeup_fd_cv.h',
@@ -392,6 +442,7 @@
                       'src/core/lib/slice/slice_hash_table.h',
                       'src/core/lib/slice/slice_internal.h',
                       'src/core/lib/slice/slice_string_helpers.h',
+                      'src/core/lib/slice/slice_weak_hash_table.h',
                       'src/core/lib/surface/api_trace.h',
                       'src/core/lib/surface/call.h',
                       'src/core/lib/surface/call_test_only.h',
@@ -416,12 +467,12 @@
                       'src/core/lib/transport/service_config.h',
                       'src/core/lib/transport/static_metadata.h',
                       'src/core/lib/transport/status_conversion.h',
+                      'src/core/lib/transport/status_metadata.h',
                       'src/core/lib/transport/timeout_encoding.h',
                       'src/core/lib/transport/transport.h',
                       'src/core/lib/transport/transport_impl.h',
                       'src/core/lib/debug/trace.h',
                       'src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h',
-                      'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h',
                       'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h',
                       'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h',
                       'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h',
@@ -437,7 +488,7 @@
                       'src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h',
                       'src/core/ext/filters/workarounds/workaround_utils.h'
 
-    ss.private_header_files = 'include/grpc++/impl/codegen/core_codegen.h',
+    ss.private_header_files = 'include/grpcpp/impl/codegen/core_codegen.h',
                               'src/cpp/client/secure_credentials.h',
                               'src/cpp/common/secure_auth_context.h',
                               'src/cpp/server/secure_server_credentials.h',
@@ -451,30 +502,40 @@
                               'src/core/lib/gpr/arena.h',
                               'src/core/lib/gpr/env.h',
                               'src/core/lib/gpr/fork.h',
+                              'src/core/lib/gpr/host_port.h',
                               'src/core/lib/gpr/mpscq.h',
                               'src/core/lib/gpr/murmur_hash.h',
                               'src/core/lib/gpr/spinlock.h',
                               'src/core/lib/gpr/string.h',
                               'src/core/lib/gpr/string_windows.h',
-                              'src/core/lib/gpr/thd_internal.h',
                               'src/core/lib/gpr/time_precise.h',
+                              'src/core/lib/gpr/tls.h',
+                              'src/core/lib/gpr/tls_gcc.h',
+                              'src/core/lib/gpr/tls_msvc.h',
+                              'src/core/lib/gpr/tls_pthread.h',
                               'src/core/lib/gpr/tmpfile.h',
+                              'src/core/lib/gpr/useful.h',
                               'src/core/lib/gprpp/abstract.h',
                               'src/core/lib/gprpp/atomic.h',
                               'src/core/lib/gprpp/atomic_with_atm.h',
                               'src/core/lib/gprpp/atomic_with_std.h',
                               'src/core/lib/gprpp/manual_constructor.h',
                               'src/core/lib/gprpp/memory.h',
+                              'src/core/lib/gprpp/thd.h',
                               'src/core/lib/profiling/timers.h',
+                              'src/core/lib/avl/avl.h',
                               'src/core/lib/backoff/backoff.h',
                               'src/core/lib/channel/channel_args.h',
                               'src/core/lib/channel/channel_stack.h',
                               'src/core/lib/channel/channel_stack_builder.h',
+                              'src/core/lib/channel/channel_trace.h',
+                              'src/core/lib/channel/channel_trace_registry.h',
                               'src/core/lib/channel/connected_channel.h',
                               'src/core/lib/channel/context.h',
                               'src/core/lib/channel/handshaker.h',
                               'src/core/lib/channel/handshaker_factory.h',
                               'src/core/lib/channel/handshaker_registry.h',
+                              'src/core/lib/channel/status_util.h',
                               'src/core/lib/compression/algorithm_metadata.h',
                               'src/core/lib/compression/compression_internal.h',
                               'src/core/lib/compression/message_compress.h',
@@ -509,9 +570,9 @@
                               'src/core/lib/iomgr/gethostname.h',
                               'src/core/lib/iomgr/iocp_windows.h',
                               'src/core/lib/iomgr/iomgr.h',
+                              'src/core/lib/iomgr/iomgr_custom.h',
                               'src/core/lib/iomgr/iomgr_internal.h',
                               'src/core/lib/iomgr/iomgr_posix.h',
-                              'src/core/lib/iomgr/iomgr_uv.h',
                               'src/core/lib/iomgr/is_epollexclusive_available.h',
                               'src/core/lib/iomgr/load_file.h',
                               'src/core/lib/iomgr/lockfree_event.h',
@@ -519,14 +580,17 @@
                               'src/core/lib/iomgr/network_status_tracker.h',
                               'src/core/lib/iomgr/polling_entity.h',
                               'src/core/lib/iomgr/pollset.h',
+                              'src/core/lib/iomgr/pollset_custom.h',
                               'src/core/lib/iomgr/pollset_set.h',
+                              'src/core/lib/iomgr/pollset_set_custom.h',
                               'src/core/lib/iomgr/pollset_set_windows.h',
-                              'src/core/lib/iomgr/pollset_uv.h',
                               'src/core/lib/iomgr/pollset_windows.h',
                               'src/core/lib/iomgr/port.h',
                               'src/core/lib/iomgr/resolve_address.h',
+                              'src/core/lib/iomgr/resolve_address_custom.h',
                               'src/core/lib/iomgr/resource_quota.h',
                               'src/core/lib/iomgr/sockaddr.h',
+                              'src/core/lib/iomgr/sockaddr_custom.h',
                               'src/core/lib/iomgr/sockaddr_posix.h',
                               'src/core/lib/iomgr/sockaddr_utils.h',
                               'src/core/lib/iomgr/sockaddr_windows.h',
@@ -538,17 +602,16 @@
                               'src/core/lib/iomgr/sys_epoll_wrapper.h',
                               'src/core/lib/iomgr/tcp_client.h',
                               'src/core/lib/iomgr/tcp_client_posix.h',
+                              'src/core/lib/iomgr/tcp_custom.h',
                               'src/core/lib/iomgr/tcp_posix.h',
                               'src/core/lib/iomgr/tcp_server.h',
                               'src/core/lib/iomgr/tcp_server_utils_posix.h',
-                              'src/core/lib/iomgr/tcp_uv.h',
                               'src/core/lib/iomgr/tcp_windows.h',
                               'src/core/lib/iomgr/time_averaged_stats.h',
                               'src/core/lib/iomgr/timer.h',
-                              'src/core/lib/iomgr/timer_generic.h',
+                              'src/core/lib/iomgr/timer_custom.h',
                               'src/core/lib/iomgr/timer_heap.h',
                               'src/core/lib/iomgr/timer_manager.h',
-                              'src/core/lib/iomgr/timer_uv.h',
                               'src/core/lib/iomgr/udp_server.h',
                               'src/core/lib/iomgr/unix_sockets_posix.h',
                               'src/core/lib/iomgr/wakeup_fd_cv.h',
@@ -563,6 +626,7 @@
                               'src/core/lib/slice/slice_hash_table.h',
                               'src/core/lib/slice/slice_internal.h',
                               'src/core/lib/slice/slice_string_helpers.h',
+                              'src/core/lib/slice/slice_weak_hash_table.h',
                               'src/core/lib/surface/api_trace.h',
                               'src/core/lib/surface/call.h',
                               'src/core/lib/surface/call_test_only.h',
@@ -587,6 +651,7 @@
                               'src/core/lib/transport/service_config.h',
                               'src/core/lib/transport/static_metadata.h',
                               'src/core/lib/transport/status_conversion.h',
+                              'src/core/lib/transport/status_metadata.h',
                               'src/core/lib/transport/timeout_encoding.h',
                               'src/core/lib/transport/transport.h',
                               'src/core/lib/transport/transport_impl.h',
@@ -594,87 +659,6 @@
                               'src/core/ext/transport/inproc/inproc_transport.h'
   end
 
-  s.subspec 'Tests' do |ss|
-    ss.header_mappings_dir = '.'
-
-    ss.dependency "#{s.name}/Interface", version
-    ss.dependency "#{s.name}/Implementation", version
-    ss.dependency "gRPC-Core/Tests", grpc_version
-
-    ss.source_files = 'test/cpp/util/create_test_channel.cc',
-                      'test/cpp/util/string_ref_helper.cc',
-                      'test/cpp/util/subprocess.cc',
-                      'test/cpp/util/test_credentials_provider.cc',
-                      'test/cpp/util/create_test_channel.h',
-                      'test/cpp/util/string_ref_helper.h',
-                      'test/cpp/util/subprocess.h',
-                      'test/cpp/util/test_credentials_provider.h',
-                      'test/core/util/test_config.h',
-                      'test/core/end2end/data/ssl_test_data.h',
-                      'test/core/security/oauth2_utils.h',
-                      'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
-                      'test/core/end2end/cq_verifier.h',
-                      'test/core/end2end/fixtures/http_proxy_fixture.h',
-                      'test/core/end2end/fixtures/proxy.h',
-                      'test/core/iomgr/endpoint_tests.h',
-                      'test/core/util/debugger_macros.h',
-                      'test/core/util/grpc_profiler.h',
-                      'test/core/util/histogram.h',
-                      'test/core/util/memory_counters.h',
-                      'test/core/util/mock_endpoint.h',
-                      'test/core/util/parse_hexstring.h',
-                      'test/core/util/passthru_endpoint.h',
-                      'test/core/util/port.h',
-                      'test/core/util/port_server_client.h',
-                      'test/core/util/slice_splitter.h',
-                      'test/core/util/tracer_util.h',
-                      'test/core/util/trickle_endpoint.h',
-                      'src/core/ext/filters/client_channel/backup_poller.h',
-                      'src/core/ext/filters/client_channel/client_channel.h',
-                      'src/core/ext/filters/client_channel/client_channel_factory.h',
-                      'src/core/ext/filters/client_channel/connector.h',
-                      'src/core/ext/filters/client_channel/http_connect_handshaker.h',
-                      'src/core/ext/filters/client_channel/http_proxy.h',
-                      'src/core/ext/filters/client_channel/lb_policy.h',
-                      'src/core/ext/filters/client_channel/lb_policy_factory.h',
-                      'src/core/ext/filters/client_channel/lb_policy_registry.h',
-                      'src/core/ext/filters/client_channel/parse_address.h',
-                      'src/core/ext/filters/client_channel/proxy_mapper.h',
-                      'src/core/ext/filters/client_channel/proxy_mapper_registry.h',
-                      'src/core/ext/filters/client_channel/resolver.h',
-                      'src/core/ext/filters/client_channel/resolver_factory.h',
-                      'src/core/ext/filters/client_channel/resolver_registry.h',
-                      'src/core/ext/filters/client_channel/retry_throttle.h',
-                      'src/core/ext/filters/client_channel/subchannel.h',
-                      'src/core/ext/filters/client_channel/subchannel_index.h',
-                      'src/core/ext/filters/client_channel/uri_parser.h',
-                      'src/core/ext/filters/deadline/deadline_filter.h',
-                      'src/core/ext/transport/chttp2/transport/bin_decoder.h',
-                      'src/core/ext/transport/chttp2/transport/bin_encoder.h',
-                      'src/core/ext/transport/chttp2/transport/chttp2_transport.h',
-                      'src/core/ext/transport/chttp2/transport/flow_control.h',
-                      'src/core/ext/transport/chttp2/transport/frame.h',
-                      'src/core/ext/transport/chttp2/transport/frame_data.h',
-                      'src/core/ext/transport/chttp2/transport/frame_goaway.h',
-                      'src/core/ext/transport/chttp2/transport/frame_ping.h',
-                      'src/core/ext/transport/chttp2/transport/frame_rst_stream.h',
-                      'src/core/ext/transport/chttp2/transport/frame_settings.h',
-                      'src/core/ext/transport/chttp2/transport/frame_window_update.h',
-                      'src/core/ext/transport/chttp2/transport/hpack_encoder.h',
-                      'src/core/ext/transport/chttp2/transport/hpack_parser.h',
-                      'src/core/ext/transport/chttp2/transport/hpack_table.h',
-                      'src/core/ext/transport/chttp2/transport/http2_settings.h',
-                      'src/core/ext/transport/chttp2/transport/huffsyms.h',
-                      'src/core/ext/transport/chttp2/transport/incoming_metadata.h',
-                      'src/core/ext/transport/chttp2/transport/internal.h',
-                      'src/core/ext/transport/chttp2/transport/stream_map.h',
-                      'src/core/ext/transport/chttp2/transport/varint.h',
-                      'src/core/ext/transport/chttp2/alpn/alpn.h',
-                      'src/core/ext/filters/http/client/http_client_filter.h',
-                      'src/core/ext/filters/http/message_compress/message_compress_filter.h',
-                      'src/core/ext/filters/http/server/http_server_filter.h'
-  end
-
   s.prepare_command = <<-END_OF_COMMAND
     find src/cpp/ -type f -exec sed -E -i'.back' 's;#include "third_party/nanopb/(.*)";#include <nanopb/\\1>;g' {} \\\;
     find src/cpp/ -name "*.back" -type f -delete
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index b28459e..f93dded 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -22,7 +22,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-Core'
-  version = '1.10.0-dev'
+  version = '1.11.0-dev'
   s.version  = version
   s.summary  = 'Core cross-platform gRPC library, written in C'
   s.homepage = 'https://grpc.io'
@@ -93,7 +93,7 @@
   }
 
   s.default_subspecs = 'Interface', 'Implementation'
-  s.compiler_flags = '-DGRPC_ARES=0'
+  s.compiler_flags = '-DGRPC_ARES=0', '-DPB_FIELD_16BIT'
   s.libraries = 'c++'
 
   # Like many other C libraries, gRPC-Core has its public headers under `include/<libname>/` and its
@@ -114,27 +114,18 @@
                       'include/grpc/support/atm_gcc_atomic.h',
                       'include/grpc/support/atm_gcc_sync.h',
                       'include/grpc/support/atm_windows.h',
-                      'include/grpc/support/avl.h',
-                      'include/grpc/support/cmdline.h',
                       'include/grpc/support/cpu.h',
-                      'include/grpc/support/host_port.h',
                       'include/grpc/support/log.h',
                       'include/grpc/support/log_windows.h',
                       'include/grpc/support/port_platform.h',
                       'include/grpc/support/string_util.h',
-                      'include/grpc/support/subprocess.h',
                       'include/grpc/support/sync.h',
                       'include/grpc/support/sync_custom.h',
                       'include/grpc/support/sync_generic.h',
                       'include/grpc/support/sync_posix.h',
                       'include/grpc/support/sync_windows.h',
-                      'include/grpc/support/thd.h',
+                      'include/grpc/support/thd_id.h',
                       'include/grpc/support/time.h',
-                      'include/grpc/support/tls.h',
-                      'include/grpc/support/tls_gcc.h',
-                      'include/grpc/support/tls_msvc.h',
-                      'include/grpc/support/tls_pthread.h',
-                      'include/grpc/support/useful.h',
                       'include/grpc/impl/codegen/atm.h',
                       'include/grpc/impl/codegen/atm_gcc_atomic.h',
                       'include/grpc/impl/codegen/atm_gcc_sync.h',
@@ -173,7 +164,6 @@
                       'include/grpc/byte_buffer.h',
                       'include/grpc/byte_buffer_reader.h',
                       'include/grpc/compression.h',
-                      'include/grpc/compression_ruby.h',
                       'include/grpc/fork.h',
                       'include/grpc/grpc.h',
                       'include/grpc/grpc_posix.h',
@@ -192,30 +182,33 @@
     ss.dependency 'BoringSSL', '~> 10.0'
     ss.dependency 'nanopb', '~> 0.3'
 
-    # To save you from scrolling, this is the last part of the podspec.
     ss.source_files = 'src/core/lib/gpr/arena.h',
                       'src/core/lib/gpr/env.h',
                       'src/core/lib/gpr/fork.h',
+                      'src/core/lib/gpr/host_port.h',
                       'src/core/lib/gpr/mpscq.h',
                       'src/core/lib/gpr/murmur_hash.h',
                       'src/core/lib/gpr/spinlock.h',
                       'src/core/lib/gpr/string.h',
                       'src/core/lib/gpr/string_windows.h',
-                      'src/core/lib/gpr/thd_internal.h',
                       'src/core/lib/gpr/time_precise.h',
+                      'src/core/lib/gpr/tls.h',
+                      'src/core/lib/gpr/tls_gcc.h',
+                      'src/core/lib/gpr/tls_msvc.h',
+                      'src/core/lib/gpr/tls_pthread.h',
                       'src/core/lib/gpr/tmpfile.h',
+                      'src/core/lib/gpr/useful.h',
                       'src/core/lib/gprpp/abstract.h',
                       'src/core/lib/gprpp/atomic.h',
                       'src/core/lib/gprpp/atomic_with_atm.h',
                       'src/core/lib/gprpp/atomic_with_std.h',
                       'src/core/lib/gprpp/manual_constructor.h',
                       'src/core/lib/gprpp/memory.h',
+                      'src/core/lib/gprpp/thd.h',
                       'src/core/lib/profiling/timers.h',
                       'src/core/lib/gpr/alloc.cc',
                       'src/core/lib/gpr/arena.cc',
                       'src/core/lib/gpr/atm.cc',
-                      'src/core/lib/gpr/avl.cc',
-                      'src/core/lib/gpr/cmdline.cc',
                       'src/core/lib/gpr/cpu_iphone.cc',
                       'src/core/lib/gpr/cpu_linux.cc',
                       'src/core/lib/gpr/cpu_posix.cc',
@@ -236,14 +229,9 @@
                       'src/core/lib/gpr/string_posix.cc',
                       'src/core/lib/gpr/string_util_windows.cc',
                       'src/core/lib/gpr/string_windows.cc',
-                      'src/core/lib/gpr/subprocess_posix.cc',
-                      'src/core/lib/gpr/subprocess_windows.cc',
                       'src/core/lib/gpr/sync.cc',
                       'src/core/lib/gpr/sync_posix.cc',
                       'src/core/lib/gpr/sync_windows.cc',
-                      'src/core/lib/gpr/thd.cc',
-                      'src/core/lib/gpr/thd_posix.cc',
-                      'src/core/lib/gpr/thd_windows.cc',
                       'src/core/lib/gpr/time.cc',
                       'src/core/lib/gpr/time_posix.cc',
                       'src/core/lib/gpr/time_precise.cc',
@@ -253,6 +241,8 @@
                       'src/core/lib/gpr/tmpfile_posix.cc',
                       'src/core/lib/gpr/tmpfile_windows.cc',
                       'src/core/lib/gpr/wrap_memcpy.cc',
+                      'src/core/lib/gprpp/thd_posix.cc',
+                      'src/core/lib/gprpp/thd_windows.cc',
                       'src/core/lib/profiling/basic_timers.cc',
                       'src/core/lib/profiling/stap_timers.cc',
                       'src/core/ext/transport/chttp2/transport/bin_decoder.h',
@@ -280,6 +270,7 @@
                       'src/core/ext/filters/http/message_compress/message_compress_filter.h',
                       'src/core/ext/filters/http/server/http_server_filter.h',
                       'src/core/lib/security/context/security_context.h',
+                      'src/core/lib/security/credentials/alts/alts_credentials.h',
                       'src/core/lib/security/credentials/composite/composite_credentials.h',
                       'src/core/lib/security/credentials/credentials.h',
                       'src/core/lib/security/credentials/fake/fake_credentials.h',
@@ -291,22 +282,43 @@
                       'src/core/lib/security/credentials/oauth2/oauth2_credentials.h',
                       'src/core/lib/security/credentials/plugin/plugin_credentials.h',
                       'src/core/lib/security/credentials/ssl/ssl_credentials.h',
+                      'src/core/lib/security/security_connector/alts_security_connector.h',
+                      'src/core/lib/security/security_connector/security_connector.h',
                       'src/core/lib/security/transport/auth_filters.h',
-                      'src/core/lib/security/transport/lb_targets_info.h',
                       'src/core/lib/security/transport/secure_endpoint.h',
-                      'src/core/lib/security/transport/security_connector.h',
                       'src/core/lib/security/transport/security_handshaker.h',
+                      'src/core/lib/security/transport/target_authority_table.h',
                       'src/core/lib/security/transport/tsi_error.h',
                       'src/core/lib/security/util/json_util.h',
-                      'src/core/tsi/alts_transport_security.h',
-                      'src/core/tsi/fake_transport_security.h',
-                      'src/core/tsi/ssl_transport_security.h',
-                      'src/core/tsi/ssl_types.h',
-                      'src/core/tsi/transport_security_grpc.h',
+                      'src/core/tsi/alts/crypt/gsec.h',
+                      'src/core/tsi/alts/frame_protector/alts_counter.h',
+                      'src/core/tsi/alts/frame_protector/alts_crypter.h',
+                      'src/core/tsi/alts/frame_protector/alts_frame_protector.h',
+                      'src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h',
+                      'src/core/tsi/alts/frame_protector/frame_handler.h',
+                      'src/core/tsi/alts/handshaker/alts_handshaker_client.h',
+                      'src/core/tsi/alts/handshaker/alts_tsi_event.h',
+                      'src/core/tsi/alts/handshaker/alts_tsi_handshaker.h',
+                      'src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h',
+                      'src/core/lib/security/credentials/alts/check_gcp_environment.h',
+                      'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h',
+                      'src/core/tsi/alts/handshaker/alts_handshaker_service_api.h',
+                      'src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h',
+                      'src/core/tsi/alts/handshaker/alts_tsi_utils.h',
+                      'src/core/tsi/alts/handshaker/transport_security_common_api.h',
+                      'src/core/tsi/alts/handshaker/altscontext.pb.h',
+                      'src/core/tsi/alts/handshaker/handshaker.pb.h',
+                      'src/core/tsi/alts/handshaker/transport_security_common.pb.h',
                       'src/core/tsi/transport_security.h',
                       'src/core/tsi/transport_security_adapter.h',
                       'src/core/tsi/transport_security_interface.h',
-                      'src/core/ext/transport/chttp2/server/chttp2_server.h',
+                      'src/core/ext/transport/chttp2/client/chttp2_connector.h',
                       'src/core/ext/filters/client_channel/backup_poller.h',
                       'src/core/ext/filters/client_channel/client_channel.h',
                       'src/core/ext/filters/client_channel/client_channel_factory.h',
@@ -316,6 +328,7 @@
                       'src/core/ext/filters/client_channel/lb_policy.h',
                       'src/core/ext/filters/client_channel/lb_policy_factory.h',
                       'src/core/ext/filters/client_channel/lb_policy_registry.h',
+                      'src/core/ext/filters/client_channel/method_params.h',
                       'src/core/ext/filters/client_channel/parse_address.h',
                       'src/core/ext/filters/client_channel/proxy_mapper.h',
                       'src/core/ext/filters/client_channel/proxy_mapper_registry.h',
@@ -327,17 +340,28 @@
                       'src/core/ext/filters/client_channel/subchannel_index.h',
                       'src/core/ext/filters/client_channel/uri_parser.h',
                       'src/core/ext/filters/deadline/deadline_filter.h',
-                      'src/core/ext/transport/chttp2/client/chttp2_connector.h',
+                      'src/core/tsi/alts_transport_security.h',
+                      'src/core/tsi/fake_transport_security.h',
+                      'src/core/tsi/ssl/session_cache/ssl_session.h',
+                      'src/core/tsi/ssl/session_cache/ssl_session_cache.h',
+                      'src/core/tsi/ssl_transport_security.h',
+                      'src/core/tsi/ssl_types.h',
+                      'src/core/tsi/transport_security_grpc.h',
+                      'src/core/ext/transport/chttp2/server/chttp2_server.h',
                       'src/core/ext/transport/inproc/inproc_transport.h',
+                      'src/core/lib/avl/avl.h',
                       'src/core/lib/backoff/backoff.h',
                       'src/core/lib/channel/channel_args.h',
                       'src/core/lib/channel/channel_stack.h',
                       'src/core/lib/channel/channel_stack_builder.h',
+                      'src/core/lib/channel/channel_trace.h',
+                      'src/core/lib/channel/channel_trace_registry.h',
                       'src/core/lib/channel/connected_channel.h',
                       'src/core/lib/channel/context.h',
                       'src/core/lib/channel/handshaker.h',
                       'src/core/lib/channel/handshaker_factory.h',
                       'src/core/lib/channel/handshaker_registry.h',
+                      'src/core/lib/channel/status_util.h',
                       'src/core/lib/compression/algorithm_metadata.h',
                       'src/core/lib/compression/compression_internal.h',
                       'src/core/lib/compression/message_compress.h',
@@ -372,9 +396,9 @@
                       'src/core/lib/iomgr/gethostname.h',
                       'src/core/lib/iomgr/iocp_windows.h',
                       'src/core/lib/iomgr/iomgr.h',
+                      'src/core/lib/iomgr/iomgr_custom.h',
                       'src/core/lib/iomgr/iomgr_internal.h',
                       'src/core/lib/iomgr/iomgr_posix.h',
-                      'src/core/lib/iomgr/iomgr_uv.h',
                       'src/core/lib/iomgr/is_epollexclusive_available.h',
                       'src/core/lib/iomgr/load_file.h',
                       'src/core/lib/iomgr/lockfree_event.h',
@@ -382,14 +406,17 @@
                       'src/core/lib/iomgr/network_status_tracker.h',
                       'src/core/lib/iomgr/polling_entity.h',
                       'src/core/lib/iomgr/pollset.h',
+                      'src/core/lib/iomgr/pollset_custom.h',
                       'src/core/lib/iomgr/pollset_set.h',
+                      'src/core/lib/iomgr/pollset_set_custom.h',
                       'src/core/lib/iomgr/pollset_set_windows.h',
-                      'src/core/lib/iomgr/pollset_uv.h',
                       'src/core/lib/iomgr/pollset_windows.h',
                       'src/core/lib/iomgr/port.h',
                       'src/core/lib/iomgr/resolve_address.h',
+                      'src/core/lib/iomgr/resolve_address_custom.h',
                       'src/core/lib/iomgr/resource_quota.h',
                       'src/core/lib/iomgr/sockaddr.h',
+                      'src/core/lib/iomgr/sockaddr_custom.h',
                       'src/core/lib/iomgr/sockaddr_posix.h',
                       'src/core/lib/iomgr/sockaddr_utils.h',
                       'src/core/lib/iomgr/sockaddr_windows.h',
@@ -401,17 +428,16 @@
                       'src/core/lib/iomgr/sys_epoll_wrapper.h',
                       'src/core/lib/iomgr/tcp_client.h',
                       'src/core/lib/iomgr/tcp_client_posix.h',
+                      'src/core/lib/iomgr/tcp_custom.h',
                       'src/core/lib/iomgr/tcp_posix.h',
                       'src/core/lib/iomgr/tcp_server.h',
                       'src/core/lib/iomgr/tcp_server_utils_posix.h',
-                      'src/core/lib/iomgr/tcp_uv.h',
                       'src/core/lib/iomgr/tcp_windows.h',
                       'src/core/lib/iomgr/time_averaged_stats.h',
                       'src/core/lib/iomgr/timer.h',
-                      'src/core/lib/iomgr/timer_generic.h',
+                      'src/core/lib/iomgr/timer_custom.h',
                       'src/core/lib/iomgr/timer_heap.h',
                       'src/core/lib/iomgr/timer_manager.h',
-                      'src/core/lib/iomgr/timer_uv.h',
                       'src/core/lib/iomgr/udp_server.h',
                       'src/core/lib/iomgr/unix_sockets_posix.h',
                       'src/core/lib/iomgr/wakeup_fd_cv.h',
@@ -426,6 +452,7 @@
                       'src/core/lib/slice/slice_hash_table.h',
                       'src/core/lib/slice/slice_internal.h',
                       'src/core/lib/slice/slice_string_helpers.h',
+                      'src/core/lib/slice/slice_weak_hash_table.h',
                       'src/core/lib/surface/api_trace.h',
                       'src/core/lib/surface/call.h',
                       'src/core/lib/surface/call_test_only.h',
@@ -450,12 +477,12 @@
                       'src/core/lib/transport/service_config.h',
                       'src/core/lib/transport/static_metadata.h',
                       'src/core/lib/transport/status_conversion.h',
+                      'src/core/lib/transport/status_metadata.h',
                       'src/core/lib/transport/timeout_encoding.h',
                       'src/core/lib/transport/transport.h',
                       'src/core/lib/transport/transport_impl.h',
                       'src/core/lib/debug/trace.h',
                       'src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h',
-                      'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h',
                       'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h',
                       'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h',
                       'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h',
@@ -471,17 +498,20 @@
                       'src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h',
                       'src/core/ext/filters/workarounds/workaround_utils.h',
                       'src/core/lib/surface/init.cc',
+                      'src/core/lib/avl/avl.cc',
                       'src/core/lib/backoff/backoff.cc',
                       'src/core/lib/channel/channel_args.cc',
                       'src/core/lib/channel/channel_stack.cc',
                       'src/core/lib/channel/channel_stack_builder.cc',
+                      'src/core/lib/channel/channel_trace.cc',
+                      'src/core/lib/channel/channel_trace_registry.cc',
                       'src/core/lib/channel/connected_channel.cc',
                       'src/core/lib/channel/handshaker.cc',
                       'src/core/lib/channel/handshaker_factory.cc',
                       'src/core/lib/channel/handshaker_registry.cc',
+                      'src/core/lib/channel/status_util.cc',
                       'src/core/lib/compression/compression.cc',
                       'src/core/lib/compression/compression_internal.cc',
-                      'src/core/lib/compression/compression_ruby.cc',
                       'src/core/lib/compression/message_compress.cc',
                       'src/core/lib/compression/stream_compression.cc',
                       'src/core/lib/compression/stream_compression_gzip.cc',
@@ -513,6 +543,8 @@
                       'src/core/lib/iomgr/gethostname_sysconf.cc',
                       'src/core/lib/iomgr/iocp_windows.cc',
                       'src/core/lib/iomgr/iomgr.cc',
+                      'src/core/lib/iomgr/iomgr_custom.cc',
+                      'src/core/lib/iomgr/iomgr_internal.cc',
                       'src/core/lib/iomgr/iomgr_posix.cc',
                       'src/core/lib/iomgr/iomgr_uv.cc',
                       'src/core/lib/iomgr/iomgr_windows.cc',
@@ -521,12 +553,16 @@
                       'src/core/lib/iomgr/lockfree_event.cc',
                       'src/core/lib/iomgr/network_status_tracker.cc',
                       'src/core/lib/iomgr/polling_entity.cc',
-                      'src/core/lib/iomgr/pollset_set_uv.cc',
+                      'src/core/lib/iomgr/pollset.cc',
+                      'src/core/lib/iomgr/pollset_custom.cc',
+                      'src/core/lib/iomgr/pollset_set.cc',
+                      'src/core/lib/iomgr/pollset_set_custom.cc',
                       'src/core/lib/iomgr/pollset_set_windows.cc',
                       'src/core/lib/iomgr/pollset_uv.cc',
                       'src/core/lib/iomgr/pollset_windows.cc',
+                      'src/core/lib/iomgr/resolve_address.cc',
+                      'src/core/lib/iomgr/resolve_address_custom.cc',
                       'src/core/lib/iomgr/resolve_address_posix.cc',
-                      'src/core/lib/iomgr/resolve_address_uv.cc',
                       'src/core/lib/iomgr/resolve_address_windows.cc',
                       'src/core/lib/iomgr/resource_quota.cc',
                       'src/core/lib/iomgr/sockaddr_utils.cc',
@@ -538,19 +574,24 @@
                       'src/core/lib/iomgr/socket_utils_uv.cc',
                       'src/core/lib/iomgr/socket_utils_windows.cc',
                       'src/core/lib/iomgr/socket_windows.cc',
+                      'src/core/lib/iomgr/tcp_client.cc',
+                      'src/core/lib/iomgr/tcp_client_custom.cc',
                       'src/core/lib/iomgr/tcp_client_posix.cc',
-                      'src/core/lib/iomgr/tcp_client_uv.cc',
                       'src/core/lib/iomgr/tcp_client_windows.cc',
+                      'src/core/lib/iomgr/tcp_custom.cc',
                       'src/core/lib/iomgr/tcp_posix.cc',
+                      'src/core/lib/iomgr/tcp_server.cc',
+                      'src/core/lib/iomgr/tcp_server_custom.cc',
                       'src/core/lib/iomgr/tcp_server_posix.cc',
                       'src/core/lib/iomgr/tcp_server_utils_posix_common.cc',
                       'src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc',
                       'src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc',
-                      'src/core/lib/iomgr/tcp_server_uv.cc',
                       'src/core/lib/iomgr/tcp_server_windows.cc',
                       'src/core/lib/iomgr/tcp_uv.cc',
                       'src/core/lib/iomgr/tcp_windows.cc',
                       'src/core/lib/iomgr/time_averaged_stats.cc',
+                      'src/core/lib/iomgr/timer.cc',
+                      'src/core/lib/iomgr/timer_custom.cc',
                       'src/core/lib/iomgr/timer_generic.cc',
                       'src/core/lib/iomgr/timer_heap.cc',
                       'src/core/lib/iomgr/timer_manager.cc',
@@ -571,7 +612,6 @@
                       'src/core/lib/slice/percent_encoding.cc',
                       'src/core/lib/slice/slice.cc',
                       'src/core/lib/slice/slice_buffer.cc',
-                      'src/core/lib/slice/slice_hash_table.cc',
                       'src/core/lib/slice/slice_intern.cc',
                       'src/core/lib/slice/slice_string_helpers.cc',
                       'src/core/lib/surface/api_trace.cc',
@@ -602,6 +642,7 @@
                       'src/core/lib/transport/service_config.cc',
                       'src/core/lib/transport/static_metadata.cc',
                       'src/core/lib/transport/status_conversion.cc',
+                      'src/core/lib/transport/status_metadata.cc',
                       'src/core/lib/transport/timeout_encoding.cc',
                       'src/core/lib/transport/transport.cc',
                       'src/core/lib/transport/transport_op_string.cc',
@@ -636,6 +677,7 @@
                       'src/core/ext/filters/http/server/http_server_filter.cc',
                       'src/core/lib/http/httpcli_security_connector.cc',
                       'src/core/lib/security/context/security_context.cc',
+                      'src/core/lib/security/credentials/alts/alts_credentials.cc',
                       'src/core/lib/security/credentials/composite/composite_credentials.cc',
                       'src/core/lib/security/credentials/credentials.cc',
                       'src/core/lib/security/credentials/credentials_metadata.cc',
@@ -649,23 +691,52 @@
                       'src/core/lib/security/credentials/oauth2/oauth2_credentials.cc',
                       'src/core/lib/security/credentials/plugin/plugin_credentials.cc',
                       'src/core/lib/security/credentials/ssl/ssl_credentials.cc',
+                      'src/core/lib/security/security_connector/alts_security_connector.cc',
+                      'src/core/lib/security/security_connector/security_connector.cc',
                       'src/core/lib/security/transport/client_auth_filter.cc',
-                      'src/core/lib/security/transport/lb_targets_info.cc',
                       'src/core/lib/security/transport/secure_endpoint.cc',
-                      'src/core/lib/security/transport/security_connector.cc',
                       'src/core/lib/security/transport/security_handshaker.cc',
                       'src/core/lib/security/transport/server_auth_filter.cc',
+                      'src/core/lib/security/transport/target_authority_table.cc',
                       'src/core/lib/security/transport/tsi_error.cc',
                       'src/core/lib/security/util/json_util.cc',
                       'src/core/lib/surface/init_secure.cc',
-                      'src/core/tsi/alts_transport_security.cc',
-                      'src/core/tsi/fake_transport_security.cc',
-                      'src/core/tsi/ssl_transport_security.cc',
-                      'src/core/tsi/transport_security_grpc.cc',
+                      'src/core/tsi/alts/crypt/aes_gcm.cc',
+                      'src/core/tsi/alts/crypt/gsec.cc',
+                      'src/core/tsi/alts/frame_protector/alts_counter.cc',
+                      'src/core/tsi/alts/frame_protector/alts_crypter.cc',
+                      'src/core/tsi/alts/frame_protector/alts_frame_protector.cc',
+                      'src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc',
+                      'src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc',
+                      'src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc',
+                      'src/core/tsi/alts/frame_protector/frame_handler.cc',
+                      'src/core/tsi/alts/handshaker/alts_handshaker_client.cc',
+                      'src/core/tsi/alts/handshaker/alts_tsi_event.cc',
+                      'src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc',
+                      'src/core/lib/security/credentials/alts/check_gcp_environment.cc',
+                      'src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc',
+                      'src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc',
+                      'src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc',
+                      'src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc',
+                      'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc',
+                      'src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc',
+                      'src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc',
+                      'src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc',
+                      'src/core/tsi/alts/handshaker/alts_tsi_utils.cc',
+                      'src/core/tsi/alts/handshaker/transport_security_common_api.cc',
+                      'src/core/tsi/alts/handshaker/altscontext.pb.c',
+                      'src/core/tsi/alts/handshaker/handshaker.pb.c',
+                      'src/core/tsi/alts/handshaker/transport_security_common.pb.c',
                       'src/core/tsi/transport_security.cc',
                       'src/core/tsi/transport_security_adapter.cc',
-                      'src/core/ext/transport/chttp2/server/chttp2_server.cc',
-                      'src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc',
+                      'src/core/ext/transport/chttp2/client/insecure/channel_create.cc',
+                      'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc',
+                      'src/core/ext/transport/chttp2/client/chttp2_connector.cc',
                       'src/core/ext/filters/client_channel/backup_poller.cc',
                       'src/core/ext/filters/client_channel/channel_connectivity.cc',
                       'src/core/ext/filters/client_channel/client_channel.cc',
@@ -677,22 +748,28 @@
                       'src/core/ext/filters/client_channel/lb_policy.cc',
                       'src/core/ext/filters/client_channel/lb_policy_factory.cc',
                       'src/core/ext/filters/client_channel/lb_policy_registry.cc',
+                      'src/core/ext/filters/client_channel/method_params.cc',
                       'src/core/ext/filters/client_channel/parse_address.cc',
                       'src/core/ext/filters/client_channel/proxy_mapper.cc',
                       'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
                       'src/core/ext/filters/client_channel/resolver.cc',
-                      'src/core/ext/filters/client_channel/resolver_factory.cc',
                       'src/core/ext/filters/client_channel/resolver_registry.cc',
                       'src/core/ext/filters/client_channel/retry_throttle.cc',
                       'src/core/ext/filters/client_channel/subchannel.cc',
                       'src/core/ext/filters/client_channel/subchannel_index.cc',
                       'src/core/ext/filters/client_channel/uri_parser.cc',
                       'src/core/ext/filters/deadline/deadline_filter.cc',
-                      'src/core/ext/transport/chttp2/client/chttp2_connector.cc',
+                      'src/core/tsi/alts_transport_security.cc',
+                      'src/core/tsi/fake_transport_security.cc',
+                      'src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc',
+                      'src/core/tsi/ssl/session_cache/ssl_session_cache.cc',
+                      'src/core/tsi/ssl/session_cache/ssl_session_openssl.cc',
+                      'src/core/tsi/ssl_transport_security.cc',
+                      'src/core/tsi/transport_security_grpc.cc',
+                      'src/core/ext/transport/chttp2/server/chttp2_server.cc',
+                      'src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc',
                       'src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc',
                       'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc',
-                      'src/core/ext/transport/chttp2/client/insecure/channel_create.cc',
-                      'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc',
                       'src/core/ext/transport/inproc/inproc_plugin.cc',
                       'src/core/ext/transport/inproc/inproc_transport.cc',
                       'src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc',
@@ -723,20 +800,26 @@
     ss.private_header_files = 'src/core/lib/gpr/arena.h',
                               'src/core/lib/gpr/env.h',
                               'src/core/lib/gpr/fork.h',
+                              'src/core/lib/gpr/host_port.h',
                               'src/core/lib/gpr/mpscq.h',
                               'src/core/lib/gpr/murmur_hash.h',
                               'src/core/lib/gpr/spinlock.h',
                               'src/core/lib/gpr/string.h',
                               'src/core/lib/gpr/string_windows.h',
-                              'src/core/lib/gpr/thd_internal.h',
                               'src/core/lib/gpr/time_precise.h',
+                              'src/core/lib/gpr/tls.h',
+                              'src/core/lib/gpr/tls_gcc.h',
+                              'src/core/lib/gpr/tls_msvc.h',
+                              'src/core/lib/gpr/tls_pthread.h',
                               'src/core/lib/gpr/tmpfile.h',
+                              'src/core/lib/gpr/useful.h',
                               'src/core/lib/gprpp/abstract.h',
                               'src/core/lib/gprpp/atomic.h',
                               'src/core/lib/gprpp/atomic_with_atm.h',
                               'src/core/lib/gprpp/atomic_with_std.h',
                               'src/core/lib/gprpp/manual_constructor.h',
                               'src/core/lib/gprpp/memory.h',
+                              'src/core/lib/gprpp/thd.h',
                               'src/core/lib/profiling/timers.h',
                               'src/core/ext/transport/chttp2/transport/bin_decoder.h',
                               'src/core/ext/transport/chttp2/transport/bin_encoder.h',
@@ -763,6 +846,7 @@
                               'src/core/ext/filters/http/message_compress/message_compress_filter.h',
                               'src/core/ext/filters/http/server/http_server_filter.h',
                               'src/core/lib/security/context/security_context.h',
+                              'src/core/lib/security/credentials/alts/alts_credentials.h',
                               'src/core/lib/security/credentials/composite/composite_credentials.h',
                               'src/core/lib/security/credentials/credentials.h',
                               'src/core/lib/security/credentials/fake/fake_credentials.h',
@@ -774,22 +858,43 @@
                               'src/core/lib/security/credentials/oauth2/oauth2_credentials.h',
                               'src/core/lib/security/credentials/plugin/plugin_credentials.h',
                               'src/core/lib/security/credentials/ssl/ssl_credentials.h',
+                              'src/core/lib/security/security_connector/alts_security_connector.h',
+                              'src/core/lib/security/security_connector/security_connector.h',
                               'src/core/lib/security/transport/auth_filters.h',
-                              'src/core/lib/security/transport/lb_targets_info.h',
                               'src/core/lib/security/transport/secure_endpoint.h',
-                              'src/core/lib/security/transport/security_connector.h',
                               'src/core/lib/security/transport/security_handshaker.h',
+                              'src/core/lib/security/transport/target_authority_table.h',
                               'src/core/lib/security/transport/tsi_error.h',
                               'src/core/lib/security/util/json_util.h',
-                              'src/core/tsi/alts_transport_security.h',
-                              'src/core/tsi/fake_transport_security.h',
-                              'src/core/tsi/ssl_transport_security.h',
-                              'src/core/tsi/ssl_types.h',
-                              'src/core/tsi/transport_security_grpc.h',
+                              'src/core/tsi/alts/crypt/gsec.h',
+                              'src/core/tsi/alts/frame_protector/alts_counter.h',
+                              'src/core/tsi/alts/frame_protector/alts_crypter.h',
+                              'src/core/tsi/alts/frame_protector/alts_frame_protector.h',
+                              'src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h',
+                              'src/core/tsi/alts/frame_protector/frame_handler.h',
+                              'src/core/tsi/alts/handshaker/alts_handshaker_client.h',
+                              'src/core/tsi/alts/handshaker/alts_tsi_event.h',
+                              'src/core/tsi/alts/handshaker/alts_tsi_handshaker.h',
+                              'src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h',
+                              'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h',
+                              'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h',
+                              'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h',
+                              'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h',
+                              'src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h',
+                              'src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h',
+                              'src/core/lib/security/credentials/alts/check_gcp_environment.h',
+                              'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h',
+                              'src/core/tsi/alts/handshaker/alts_handshaker_service_api.h',
+                              'src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h',
+                              'src/core/tsi/alts/handshaker/alts_tsi_utils.h',
+                              'src/core/tsi/alts/handshaker/transport_security_common_api.h',
+                              'src/core/tsi/alts/handshaker/altscontext.pb.h',
+                              'src/core/tsi/alts/handshaker/handshaker.pb.h',
+                              'src/core/tsi/alts/handshaker/transport_security_common.pb.h',
                               'src/core/tsi/transport_security.h',
                               'src/core/tsi/transport_security_adapter.h',
                               'src/core/tsi/transport_security_interface.h',
-                              'src/core/ext/transport/chttp2/server/chttp2_server.h',
+                              'src/core/ext/transport/chttp2/client/chttp2_connector.h',
                               'src/core/ext/filters/client_channel/backup_poller.h',
                               'src/core/ext/filters/client_channel/client_channel.h',
                               'src/core/ext/filters/client_channel/client_channel_factory.h',
@@ -799,6 +904,7 @@
                               'src/core/ext/filters/client_channel/lb_policy.h',
                               'src/core/ext/filters/client_channel/lb_policy_factory.h',
                               'src/core/ext/filters/client_channel/lb_policy_registry.h',
+                              'src/core/ext/filters/client_channel/method_params.h',
                               'src/core/ext/filters/client_channel/parse_address.h',
                               'src/core/ext/filters/client_channel/proxy_mapper.h',
                               'src/core/ext/filters/client_channel/proxy_mapper_registry.h',
@@ -810,17 +916,28 @@
                               'src/core/ext/filters/client_channel/subchannel_index.h',
                               'src/core/ext/filters/client_channel/uri_parser.h',
                               'src/core/ext/filters/deadline/deadline_filter.h',
-                              'src/core/ext/transport/chttp2/client/chttp2_connector.h',
+                              'src/core/tsi/alts_transport_security.h',
+                              'src/core/tsi/fake_transport_security.h',
+                              'src/core/tsi/ssl/session_cache/ssl_session.h',
+                              'src/core/tsi/ssl/session_cache/ssl_session_cache.h',
+                              'src/core/tsi/ssl_transport_security.h',
+                              'src/core/tsi/ssl_types.h',
+                              'src/core/tsi/transport_security_grpc.h',
+                              'src/core/ext/transport/chttp2/server/chttp2_server.h',
                               'src/core/ext/transport/inproc/inproc_transport.h',
+                              'src/core/lib/avl/avl.h',
                               'src/core/lib/backoff/backoff.h',
                               'src/core/lib/channel/channel_args.h',
                               'src/core/lib/channel/channel_stack.h',
                               'src/core/lib/channel/channel_stack_builder.h',
+                              'src/core/lib/channel/channel_trace.h',
+                              'src/core/lib/channel/channel_trace_registry.h',
                               'src/core/lib/channel/connected_channel.h',
                               'src/core/lib/channel/context.h',
                               'src/core/lib/channel/handshaker.h',
                               'src/core/lib/channel/handshaker_factory.h',
                               'src/core/lib/channel/handshaker_registry.h',
+                              'src/core/lib/channel/status_util.h',
                               'src/core/lib/compression/algorithm_metadata.h',
                               'src/core/lib/compression/compression_internal.h',
                               'src/core/lib/compression/message_compress.h',
@@ -855,9 +972,9 @@
                               'src/core/lib/iomgr/gethostname.h',
                               'src/core/lib/iomgr/iocp_windows.h',
                               'src/core/lib/iomgr/iomgr.h',
+                              'src/core/lib/iomgr/iomgr_custom.h',
                               'src/core/lib/iomgr/iomgr_internal.h',
                               'src/core/lib/iomgr/iomgr_posix.h',
-                              'src/core/lib/iomgr/iomgr_uv.h',
                               'src/core/lib/iomgr/is_epollexclusive_available.h',
                               'src/core/lib/iomgr/load_file.h',
                               'src/core/lib/iomgr/lockfree_event.h',
@@ -865,14 +982,17 @@
                               'src/core/lib/iomgr/network_status_tracker.h',
                               'src/core/lib/iomgr/polling_entity.h',
                               'src/core/lib/iomgr/pollset.h',
+                              'src/core/lib/iomgr/pollset_custom.h',
                               'src/core/lib/iomgr/pollset_set.h',
+                              'src/core/lib/iomgr/pollset_set_custom.h',
                               'src/core/lib/iomgr/pollset_set_windows.h',
-                              'src/core/lib/iomgr/pollset_uv.h',
                               'src/core/lib/iomgr/pollset_windows.h',
                               'src/core/lib/iomgr/port.h',
                               'src/core/lib/iomgr/resolve_address.h',
+                              'src/core/lib/iomgr/resolve_address_custom.h',
                               'src/core/lib/iomgr/resource_quota.h',
                               'src/core/lib/iomgr/sockaddr.h',
+                              'src/core/lib/iomgr/sockaddr_custom.h',
                               'src/core/lib/iomgr/sockaddr_posix.h',
                               'src/core/lib/iomgr/sockaddr_utils.h',
                               'src/core/lib/iomgr/sockaddr_windows.h',
@@ -884,17 +1004,16 @@
                               'src/core/lib/iomgr/sys_epoll_wrapper.h',
                               'src/core/lib/iomgr/tcp_client.h',
                               'src/core/lib/iomgr/tcp_client_posix.h',
+                              'src/core/lib/iomgr/tcp_custom.h',
                               'src/core/lib/iomgr/tcp_posix.h',
                               'src/core/lib/iomgr/tcp_server.h',
                               'src/core/lib/iomgr/tcp_server_utils_posix.h',
-                              'src/core/lib/iomgr/tcp_uv.h',
                               'src/core/lib/iomgr/tcp_windows.h',
                               'src/core/lib/iomgr/time_averaged_stats.h',
                               'src/core/lib/iomgr/timer.h',
-                              'src/core/lib/iomgr/timer_generic.h',
+                              'src/core/lib/iomgr/timer_custom.h',
                               'src/core/lib/iomgr/timer_heap.h',
                               'src/core/lib/iomgr/timer_manager.h',
-                              'src/core/lib/iomgr/timer_uv.h',
                               'src/core/lib/iomgr/udp_server.h',
                               'src/core/lib/iomgr/unix_sockets_posix.h',
                               'src/core/lib/iomgr/wakeup_fd_cv.h',
@@ -909,6 +1028,7 @@
                               'src/core/lib/slice/slice_hash_table.h',
                               'src/core/lib/slice/slice_internal.h',
                               'src/core/lib/slice/slice_string_helpers.h',
+                              'src/core/lib/slice/slice_weak_hash_table.h',
                               'src/core/lib/surface/api_trace.h',
                               'src/core/lib/surface/call.h',
                               'src/core/lib/surface/call_test_only.h',
@@ -933,12 +1053,12 @@
                               'src/core/lib/transport/service_config.h',
                               'src/core/lib/transport/static_metadata.h',
                               'src/core/lib/transport/status_conversion.h',
+                              'src/core/lib/transport/status_metadata.h',
                               'src/core/lib/transport/timeout_encoding.h',
                               'src/core/lib/transport/transport.h',
                               'src/core/lib/transport/transport_impl.h',
                               'src/core/lib/debug/trace.h',
                               'src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h',
-                              'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h',
                               'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h',
                               'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h',
                               'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h',
@@ -957,27 +1077,954 @@
 
   s.subspec 'Cronet-Interface' do |ss|
     ss.header_mappings_dir = 'include/grpc'
-    ss.source_files = 'include/grpc/grpc_cronet.h'
+    ss.source_files = 'include/grpc/support/alloc.h',
+                      'include/grpc/support/atm.h',
+                      'include/grpc/support/atm_gcc_atomic.h',
+                      'include/grpc/support/atm_gcc_sync.h',
+                      'include/grpc/support/atm_windows.h',
+                      'include/grpc/support/cpu.h',
+                      'include/grpc/support/log.h',
+                      'include/grpc/support/log_windows.h',
+                      'include/grpc/support/port_platform.h',
+                      'include/grpc/support/string_util.h',
+                      'include/grpc/support/sync.h',
+                      'include/grpc/support/sync_custom.h',
+                      'include/grpc/support/sync_generic.h',
+                      'include/grpc/support/sync_posix.h',
+                      'include/grpc/support/sync_windows.h',
+                      'include/grpc/support/thd_id.h',
+                      'include/grpc/support/time.h',
+                      'include/grpc/impl/codegen/atm.h',
+                      'include/grpc/impl/codegen/atm_gcc_atomic.h',
+                      'include/grpc/impl/codegen/atm_gcc_sync.h',
+                      'include/grpc/impl/codegen/atm_windows.h',
+                      'include/grpc/impl/codegen/fork.h',
+                      'include/grpc/impl/codegen/gpr_slice.h',
+                      'include/grpc/impl/codegen/gpr_types.h',
+                      'include/grpc/impl/codegen/port_platform.h',
+                      'include/grpc/impl/codegen/sync.h',
+                      'include/grpc/impl/codegen/sync_custom.h',
+                      'include/grpc/impl/codegen/sync_generic.h',
+                      'include/grpc/impl/codegen/sync_posix.h',
+                      'include/grpc/impl/codegen/sync_windows.h',
+                      'include/grpc/impl/codegen/byte_buffer.h',
+                      'include/grpc/impl/codegen/byte_buffer_reader.h',
+                      'include/grpc/impl/codegen/compression_types.h',
+                      'include/grpc/impl/codegen/connectivity_state.h',
+                      'include/grpc/impl/codegen/grpc_types.h',
+                      'include/grpc/impl/codegen/propagation_bits.h',
+                      'include/grpc/impl/codegen/slice.h',
+                      'include/grpc/impl/codegen/status.h',
+                      'include/grpc/impl/codegen/atm.h',
+                      'include/grpc/impl/codegen/atm_gcc_atomic.h',
+                      'include/grpc/impl/codegen/atm_gcc_sync.h',
+                      'include/grpc/impl/codegen/atm_windows.h',
+                      'include/grpc/impl/codegen/fork.h',
+                      'include/grpc/impl/codegen/gpr_slice.h',
+                      'include/grpc/impl/codegen/gpr_types.h',
+                      'include/grpc/impl/codegen/port_platform.h',
+                      'include/grpc/impl/codegen/sync.h',
+                      'include/grpc/impl/codegen/sync_custom.h',
+                      'include/grpc/impl/codegen/sync_generic.h',
+                      'include/grpc/impl/codegen/sync_posix.h',
+                      'include/grpc/impl/codegen/sync_windows.h',
+                      'include/grpc/byte_buffer.h',
+                      'include/grpc/byte_buffer_reader.h',
+                      'include/grpc/compression.h',
+                      'include/grpc/fork.h',
+                      'include/grpc/grpc.h',
+                      'include/grpc/grpc_posix.h',
+                      'include/grpc/grpc_security_constants.h',
+                      'include/grpc/load_reporting.h',
+                      'include/grpc/slice.h',
+                      'include/grpc/slice_buffer.h',
+                      'include/grpc/status.h',
+                      'include/grpc/support/workaround_list.h',
+                      'include/grpc/grpc_cronet.h',
+                      'include/grpc/grpc_security.h'
   end
 
   s.subspec 'Cronet-Implementation' do |ss|
     ss.header_mappings_dir = '.'
-
-    ss.dependency "#{s.name}/Interface", version
-    ss.dependency "#{s.name}/Implementation", version
+    ss.libraries = 'z'
     ss.dependency "#{s.name}/Cronet-Interface", version
+    ss.dependency 'BoringSSL', '~> 10.0'
+    ss.dependency 'nanopb', '~> 0.3'
 
-    ss.source_files = 'src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc',
-                      'src/core/ext/transport/cronet/transport/cronet_transport.cc',
+    ss.source_files = 'src/core/lib/gpr/arena.h',
+                      'src/core/lib/gpr/env.h',
+                      'src/core/lib/gpr/fork.h',
+                      'src/core/lib/gpr/host_port.h',
+                      'src/core/lib/gpr/mpscq.h',
+                      'src/core/lib/gpr/murmur_hash.h',
+                      'src/core/lib/gpr/spinlock.h',
+                      'src/core/lib/gpr/string.h',
+                      'src/core/lib/gpr/string_windows.h',
+                      'src/core/lib/gpr/time_precise.h',
+                      'src/core/lib/gpr/tls.h',
+                      'src/core/lib/gpr/tls_gcc.h',
+                      'src/core/lib/gpr/tls_msvc.h',
+                      'src/core/lib/gpr/tls_pthread.h',
+                      'src/core/lib/gpr/tmpfile.h',
+                      'src/core/lib/gpr/useful.h',
+                      'src/core/lib/gprpp/abstract.h',
+                      'src/core/lib/gprpp/atomic.h',
+                      'src/core/lib/gprpp/atomic_with_atm.h',
+                      'src/core/lib/gprpp/atomic_with_std.h',
+                      'src/core/lib/gprpp/manual_constructor.h',
+                      'src/core/lib/gprpp/memory.h',
+                      'src/core/lib/gprpp/thd.h',
+                      'src/core/lib/profiling/timers.h',
+                      'src/core/lib/gpr/alloc.cc',
+                      'src/core/lib/gpr/arena.cc',
+                      'src/core/lib/gpr/atm.cc',
+                      'src/core/lib/gpr/cpu_iphone.cc',
+                      'src/core/lib/gpr/cpu_linux.cc',
+                      'src/core/lib/gpr/cpu_posix.cc',
+                      'src/core/lib/gpr/cpu_windows.cc',
+                      'src/core/lib/gpr/env_linux.cc',
+                      'src/core/lib/gpr/env_posix.cc',
+                      'src/core/lib/gpr/env_windows.cc',
+                      'src/core/lib/gpr/fork.cc',
+                      'src/core/lib/gpr/host_port.cc',
+                      'src/core/lib/gpr/log.cc',
+                      'src/core/lib/gpr/log_android.cc',
+                      'src/core/lib/gpr/log_linux.cc',
+                      'src/core/lib/gpr/log_posix.cc',
+                      'src/core/lib/gpr/log_windows.cc',
+                      'src/core/lib/gpr/mpscq.cc',
+                      'src/core/lib/gpr/murmur_hash.cc',
+                      'src/core/lib/gpr/string.cc',
+                      'src/core/lib/gpr/string_posix.cc',
+                      'src/core/lib/gpr/string_util_windows.cc',
+                      'src/core/lib/gpr/string_windows.cc',
+                      'src/core/lib/gpr/sync.cc',
+                      'src/core/lib/gpr/sync_posix.cc',
+                      'src/core/lib/gpr/sync_windows.cc',
+                      'src/core/lib/gpr/time.cc',
+                      'src/core/lib/gpr/time_posix.cc',
+                      'src/core/lib/gpr/time_precise.cc',
+                      'src/core/lib/gpr/time_windows.cc',
+                      'src/core/lib/gpr/tls_pthread.cc',
+                      'src/core/lib/gpr/tmpfile_msys.cc',
+                      'src/core/lib/gpr/tmpfile_posix.cc',
+                      'src/core/lib/gpr/tmpfile_windows.cc',
+                      'src/core/lib/gpr/wrap_memcpy.cc',
+                      'src/core/lib/gprpp/thd_posix.cc',
+                      'src/core/lib/gprpp/thd_windows.cc',
+                      'src/core/lib/profiling/basic_timers.cc',
+                      'src/core/lib/profiling/stap_timers.cc',
+                      'src/core/lib/avl/avl.h',
+                      'src/core/lib/backoff/backoff.h',
+                      'src/core/lib/channel/channel_args.h',
+                      'src/core/lib/channel/channel_stack.h',
+                      'src/core/lib/channel/channel_stack_builder.h',
+                      'src/core/lib/channel/channel_trace.h',
+                      'src/core/lib/channel/channel_trace_registry.h',
+                      'src/core/lib/channel/connected_channel.h',
+                      'src/core/lib/channel/context.h',
+                      'src/core/lib/channel/handshaker.h',
+                      'src/core/lib/channel/handshaker_factory.h',
+                      'src/core/lib/channel/handshaker_registry.h',
+                      'src/core/lib/channel/status_util.h',
+                      'src/core/lib/compression/algorithm_metadata.h',
+                      'src/core/lib/compression/compression_internal.h',
+                      'src/core/lib/compression/message_compress.h',
+                      'src/core/lib/compression/stream_compression.h',
+                      'src/core/lib/compression/stream_compression_gzip.h',
+                      'src/core/lib/compression/stream_compression_identity.h',
+                      'src/core/lib/debug/stats.h',
+                      'src/core/lib/debug/stats_data.h',
+                      'src/core/lib/gprpp/debug_location.h',
+                      'src/core/lib/gprpp/inlined_vector.h',
+                      'src/core/lib/gprpp/orphanable.h',
+                      'src/core/lib/gprpp/ref_counted.h',
+                      'src/core/lib/gprpp/ref_counted_ptr.h',
+                      'src/core/lib/http/format_request.h',
+                      'src/core/lib/http/httpcli.h',
+                      'src/core/lib/http/parser.h',
+                      'src/core/lib/iomgr/block_annotate.h',
+                      'src/core/lib/iomgr/call_combiner.h',
+                      'src/core/lib/iomgr/closure.h',
+                      'src/core/lib/iomgr/combiner.h',
+                      'src/core/lib/iomgr/endpoint.h',
+                      'src/core/lib/iomgr/endpoint_pair.h',
+                      'src/core/lib/iomgr/error.h',
+                      'src/core/lib/iomgr/error_internal.h',
+                      'src/core/lib/iomgr/ev_epoll1_linux.h',
+                      'src/core/lib/iomgr/ev_epollex_linux.h',
+                      'src/core/lib/iomgr/ev_epollsig_linux.h',
+                      'src/core/lib/iomgr/ev_poll_posix.h',
+                      'src/core/lib/iomgr/ev_posix.h',
+                      'src/core/lib/iomgr/exec_ctx.h',
+                      'src/core/lib/iomgr/executor.h',
+                      'src/core/lib/iomgr/gethostname.h',
+                      'src/core/lib/iomgr/iocp_windows.h',
+                      'src/core/lib/iomgr/iomgr.h',
+                      'src/core/lib/iomgr/iomgr_custom.h',
+                      'src/core/lib/iomgr/iomgr_internal.h',
+                      'src/core/lib/iomgr/iomgr_posix.h',
+                      'src/core/lib/iomgr/is_epollexclusive_available.h',
+                      'src/core/lib/iomgr/load_file.h',
+                      'src/core/lib/iomgr/lockfree_event.h',
+                      'src/core/lib/iomgr/nameser.h',
+                      'src/core/lib/iomgr/network_status_tracker.h',
+                      'src/core/lib/iomgr/polling_entity.h',
+                      'src/core/lib/iomgr/pollset.h',
+                      'src/core/lib/iomgr/pollset_custom.h',
+                      'src/core/lib/iomgr/pollset_set.h',
+                      'src/core/lib/iomgr/pollset_set_custom.h',
+                      'src/core/lib/iomgr/pollset_set_windows.h',
+                      'src/core/lib/iomgr/pollset_windows.h',
+                      'src/core/lib/iomgr/port.h',
+                      'src/core/lib/iomgr/resolve_address.h',
+                      'src/core/lib/iomgr/resolve_address_custom.h',
+                      'src/core/lib/iomgr/resource_quota.h',
+                      'src/core/lib/iomgr/sockaddr.h',
+                      'src/core/lib/iomgr/sockaddr_custom.h',
+                      'src/core/lib/iomgr/sockaddr_posix.h',
+                      'src/core/lib/iomgr/sockaddr_utils.h',
+                      'src/core/lib/iomgr/sockaddr_windows.h',
+                      'src/core/lib/iomgr/socket_factory_posix.h',
+                      'src/core/lib/iomgr/socket_mutator.h',
+                      'src/core/lib/iomgr/socket_utils.h',
+                      'src/core/lib/iomgr/socket_utils_posix.h',
+                      'src/core/lib/iomgr/socket_windows.h',
+                      'src/core/lib/iomgr/sys_epoll_wrapper.h',
+                      'src/core/lib/iomgr/tcp_client.h',
+                      'src/core/lib/iomgr/tcp_client_posix.h',
+                      'src/core/lib/iomgr/tcp_custom.h',
+                      'src/core/lib/iomgr/tcp_posix.h',
+                      'src/core/lib/iomgr/tcp_server.h',
+                      'src/core/lib/iomgr/tcp_server_utils_posix.h',
+                      'src/core/lib/iomgr/tcp_windows.h',
+                      'src/core/lib/iomgr/time_averaged_stats.h',
+                      'src/core/lib/iomgr/timer.h',
+                      'src/core/lib/iomgr/timer_custom.h',
+                      'src/core/lib/iomgr/timer_heap.h',
+                      'src/core/lib/iomgr/timer_manager.h',
+                      'src/core/lib/iomgr/udp_server.h',
+                      'src/core/lib/iomgr/unix_sockets_posix.h',
+                      'src/core/lib/iomgr/wakeup_fd_cv.h',
+                      'src/core/lib/iomgr/wakeup_fd_pipe.h',
+                      'src/core/lib/iomgr/wakeup_fd_posix.h',
+                      'src/core/lib/json/json.h',
+                      'src/core/lib/json/json_common.h',
+                      'src/core/lib/json/json_reader.h',
+                      'src/core/lib/json/json_writer.h',
+                      'src/core/lib/slice/b64.h',
+                      'src/core/lib/slice/percent_encoding.h',
+                      'src/core/lib/slice/slice_hash_table.h',
+                      'src/core/lib/slice/slice_internal.h',
+                      'src/core/lib/slice/slice_string_helpers.h',
+                      'src/core/lib/slice/slice_weak_hash_table.h',
+                      'src/core/lib/surface/api_trace.h',
+                      'src/core/lib/surface/call.h',
+                      'src/core/lib/surface/call_test_only.h',
+                      'src/core/lib/surface/channel.h',
+                      'src/core/lib/surface/channel_init.h',
+                      'src/core/lib/surface/channel_stack_type.h',
+                      'src/core/lib/surface/completion_queue.h',
+                      'src/core/lib/surface/completion_queue_factory.h',
+                      'src/core/lib/surface/event_string.h',
+                      'src/core/lib/surface/init.h',
+                      'src/core/lib/surface/lame_client.h',
+                      'src/core/lib/surface/server.h',
+                      'src/core/lib/surface/validate_metadata.h',
+                      'src/core/lib/transport/bdp_estimator.h',
+                      'src/core/lib/transport/byte_stream.h',
+                      'src/core/lib/transport/connectivity_state.h',
+                      'src/core/lib/transport/error_utils.h',
+                      'src/core/lib/transport/http2_errors.h',
+                      'src/core/lib/transport/metadata.h',
+                      'src/core/lib/transport/metadata_batch.h',
+                      'src/core/lib/transport/pid_controller.h',
+                      'src/core/lib/transport/service_config.h',
+                      'src/core/lib/transport/static_metadata.h',
+                      'src/core/lib/transport/status_conversion.h',
+                      'src/core/lib/transport/status_metadata.h',
+                      'src/core/lib/transport/timeout_encoding.h',
+                      'src/core/lib/transport/transport.h',
+                      'src/core/lib/transport/transport_impl.h',
+                      'src/core/lib/debug/trace.h',
+                      'src/core/ext/filters/deadline/deadline_filter.h',
+                      'src/core/ext/filters/client_channel/backup_poller.h',
+                      'src/core/ext/filters/client_channel/client_channel.h',
+                      'src/core/ext/filters/client_channel/client_channel_factory.h',
+                      'src/core/ext/filters/client_channel/connector.h',
+                      'src/core/ext/filters/client_channel/http_connect_handshaker.h',
+                      'src/core/ext/filters/client_channel/http_proxy.h',
+                      'src/core/ext/filters/client_channel/lb_policy.h',
+                      'src/core/ext/filters/client_channel/lb_policy_factory.h',
+                      'src/core/ext/filters/client_channel/lb_policy_registry.h',
+                      'src/core/ext/filters/client_channel/method_params.h',
+                      'src/core/ext/filters/client_channel/parse_address.h',
+                      'src/core/ext/filters/client_channel/proxy_mapper.h',
+                      'src/core/ext/filters/client_channel/proxy_mapper_registry.h',
+                      'src/core/ext/filters/client_channel/resolver.h',
+                      'src/core/ext/filters/client_channel/resolver_factory.h',
+                      'src/core/ext/filters/client_channel/resolver_registry.h',
+                      'src/core/ext/filters/client_channel/retry_throttle.h',
+                      'src/core/ext/filters/client_channel/subchannel.h',
+                      'src/core/ext/filters/client_channel/subchannel_index.h',
+                      'src/core/ext/filters/client_channel/uri_parser.h',
+                      'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h',
+                      'src/core/ext/filters/max_age/max_age_filter.h',
+                      'src/core/ext/filters/message_size/message_size_filter.h',
+                      'src/core/ext/filters/load_reporting/server_load_reporting_filter.h',
+                      'src/core/ext/filters/load_reporting/server_load_reporting_plugin.h',
                       'src/core/ext/transport/cronet/transport/cronet_transport.h',
-                      'third_party/objective_c/Cronet/bidirectional_stream_c.h'
+                      'third_party/objective_c/Cronet/bidirectional_stream_c.h',
+                      'src/core/ext/transport/chttp2/transport/bin_decoder.h',
+                      'src/core/ext/transport/chttp2/transport/bin_encoder.h',
+                      'src/core/ext/transport/chttp2/transport/chttp2_transport.h',
+                      'src/core/ext/transport/chttp2/transport/flow_control.h',
+                      'src/core/ext/transport/chttp2/transport/frame.h',
+                      'src/core/ext/transport/chttp2/transport/frame_data.h',
+                      'src/core/ext/transport/chttp2/transport/frame_goaway.h',
+                      'src/core/ext/transport/chttp2/transport/frame_ping.h',
+                      'src/core/ext/transport/chttp2/transport/frame_rst_stream.h',
+                      'src/core/ext/transport/chttp2/transport/frame_settings.h',
+                      'src/core/ext/transport/chttp2/transport/frame_window_update.h',
+                      'src/core/ext/transport/chttp2/transport/hpack_encoder.h',
+                      'src/core/ext/transport/chttp2/transport/hpack_parser.h',
+                      'src/core/ext/transport/chttp2/transport/hpack_table.h',
+                      'src/core/ext/transport/chttp2/transport/http2_settings.h',
+                      'src/core/ext/transport/chttp2/transport/huffsyms.h',
+                      'src/core/ext/transport/chttp2/transport/incoming_metadata.h',
+                      'src/core/ext/transport/chttp2/transport/internal.h',
+                      'src/core/ext/transport/chttp2/transport/stream_map.h',
+                      'src/core/ext/transport/chttp2/transport/varint.h',
+                      'src/core/ext/transport/chttp2/alpn/alpn.h',
+                      'src/core/ext/filters/http/client/http_client_filter.h',
+                      'src/core/ext/filters/http/message_compress/message_compress_filter.h',
+                      'src/core/ext/filters/http/server/http_server_filter.h',
+                      'src/core/lib/security/context/security_context.h',
+                      'src/core/lib/security/credentials/alts/alts_credentials.h',
+                      'src/core/lib/security/credentials/composite/composite_credentials.h',
+                      'src/core/lib/security/credentials/credentials.h',
+                      'src/core/lib/security/credentials/fake/fake_credentials.h',
+                      'src/core/lib/security/credentials/google_default/google_default_credentials.h',
+                      'src/core/lib/security/credentials/iam/iam_credentials.h',
+                      'src/core/lib/security/credentials/jwt/json_token.h',
+                      'src/core/lib/security/credentials/jwt/jwt_credentials.h',
+                      'src/core/lib/security/credentials/jwt/jwt_verifier.h',
+                      'src/core/lib/security/credentials/oauth2/oauth2_credentials.h',
+                      'src/core/lib/security/credentials/plugin/plugin_credentials.h',
+                      'src/core/lib/security/credentials/ssl/ssl_credentials.h',
+                      'src/core/lib/security/security_connector/alts_security_connector.h',
+                      'src/core/lib/security/security_connector/security_connector.h',
+                      'src/core/lib/security/transport/auth_filters.h',
+                      'src/core/lib/security/transport/secure_endpoint.h',
+                      'src/core/lib/security/transport/security_handshaker.h',
+                      'src/core/lib/security/transport/target_authority_table.h',
+                      'src/core/lib/security/transport/tsi_error.h',
+                      'src/core/lib/security/util/json_util.h',
+                      'src/core/tsi/alts/crypt/gsec.h',
+                      'src/core/tsi/alts/frame_protector/alts_counter.h',
+                      'src/core/tsi/alts/frame_protector/alts_crypter.h',
+                      'src/core/tsi/alts/frame_protector/alts_frame_protector.h',
+                      'src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h',
+                      'src/core/tsi/alts/frame_protector/frame_handler.h',
+                      'src/core/tsi/alts/handshaker/alts_handshaker_client.h',
+                      'src/core/tsi/alts/handshaker/alts_tsi_event.h',
+                      'src/core/tsi/alts/handshaker/alts_tsi_handshaker.h',
+                      'src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h',
+                      'src/core/lib/security/credentials/alts/check_gcp_environment.h',
+                      'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h',
+                      'src/core/tsi/alts/handshaker/alts_handshaker_service_api.h',
+                      'src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h',
+                      'src/core/tsi/alts/handshaker/alts_tsi_utils.h',
+                      'src/core/tsi/alts/handshaker/transport_security_common_api.h',
+                      'src/core/tsi/alts/handshaker/altscontext.pb.h',
+                      'src/core/tsi/alts/handshaker/handshaker.pb.h',
+                      'src/core/tsi/alts/handshaker/transport_security_common.pb.h',
+                      'third_party/nanopb/pb.h',
+                      'third_party/nanopb/pb_common.h',
+                      'third_party/nanopb/pb_decode.h',
+                      'third_party/nanopb/pb_encode.h',
+                      'src/core/tsi/transport_security.h',
+                      'src/core/tsi/transport_security_adapter.h',
+                      'src/core/tsi/transport_security_interface.h',
+                      'src/core/ext/transport/chttp2/client/chttp2_connector.h',
+                      'src/core/tsi/alts_transport_security.h',
+                      'src/core/tsi/fake_transport_security.h',
+                      'src/core/tsi/ssl/session_cache/ssl_session.h',
+                      'src/core/tsi/ssl/session_cache/ssl_session_cache.h',
+                      'src/core/tsi/ssl_transport_security.h',
+                      'src/core/tsi/ssl_types.h',
+                      'src/core/tsi/transport_security_grpc.h',
+                      'src/core/ext/transport/chttp2/server/chttp2_server.h',
+                      'src/core/lib/surface/init.cc',
+                      'src/core/lib/avl/avl.cc',
+                      'src/core/lib/backoff/backoff.cc',
+                      'src/core/lib/channel/channel_args.cc',
+                      'src/core/lib/channel/channel_stack.cc',
+                      'src/core/lib/channel/channel_stack_builder.cc',
+                      'src/core/lib/channel/channel_trace.cc',
+                      'src/core/lib/channel/channel_trace_registry.cc',
+                      'src/core/lib/channel/connected_channel.cc',
+                      'src/core/lib/channel/handshaker.cc',
+                      'src/core/lib/channel/handshaker_factory.cc',
+                      'src/core/lib/channel/handshaker_registry.cc',
+                      'src/core/lib/channel/status_util.cc',
+                      'src/core/lib/compression/compression.cc',
+                      'src/core/lib/compression/compression_internal.cc',
+                      'src/core/lib/compression/message_compress.cc',
+                      'src/core/lib/compression/stream_compression.cc',
+                      'src/core/lib/compression/stream_compression_gzip.cc',
+                      'src/core/lib/compression/stream_compression_identity.cc',
+                      'src/core/lib/debug/stats.cc',
+                      'src/core/lib/debug/stats_data.cc',
+                      'src/core/lib/http/format_request.cc',
+                      'src/core/lib/http/httpcli.cc',
+                      'src/core/lib/http/parser.cc',
+                      'src/core/lib/iomgr/call_combiner.cc',
+                      'src/core/lib/iomgr/combiner.cc',
+                      'src/core/lib/iomgr/endpoint.cc',
+                      'src/core/lib/iomgr/endpoint_pair_posix.cc',
+                      'src/core/lib/iomgr/endpoint_pair_uv.cc',
+                      'src/core/lib/iomgr/endpoint_pair_windows.cc',
+                      'src/core/lib/iomgr/error.cc',
+                      'src/core/lib/iomgr/ev_epoll1_linux.cc',
+                      'src/core/lib/iomgr/ev_epollex_linux.cc',
+                      'src/core/lib/iomgr/ev_epollsig_linux.cc',
+                      'src/core/lib/iomgr/ev_poll_posix.cc',
+                      'src/core/lib/iomgr/ev_posix.cc',
+                      'src/core/lib/iomgr/ev_windows.cc',
+                      'src/core/lib/iomgr/exec_ctx.cc',
+                      'src/core/lib/iomgr/executor.cc',
+                      'src/core/lib/iomgr/fork_posix.cc',
+                      'src/core/lib/iomgr/fork_windows.cc',
+                      'src/core/lib/iomgr/gethostname_fallback.cc',
+                      'src/core/lib/iomgr/gethostname_host_name_max.cc',
+                      'src/core/lib/iomgr/gethostname_sysconf.cc',
+                      'src/core/lib/iomgr/iocp_windows.cc',
+                      'src/core/lib/iomgr/iomgr.cc',
+                      'src/core/lib/iomgr/iomgr_custom.cc',
+                      'src/core/lib/iomgr/iomgr_internal.cc',
+                      'src/core/lib/iomgr/iomgr_posix.cc',
+                      'src/core/lib/iomgr/iomgr_uv.cc',
+                      'src/core/lib/iomgr/iomgr_windows.cc',
+                      'src/core/lib/iomgr/is_epollexclusive_available.cc',
+                      'src/core/lib/iomgr/load_file.cc',
+                      'src/core/lib/iomgr/lockfree_event.cc',
+                      'src/core/lib/iomgr/network_status_tracker.cc',
+                      'src/core/lib/iomgr/polling_entity.cc',
+                      'src/core/lib/iomgr/pollset.cc',
+                      'src/core/lib/iomgr/pollset_custom.cc',
+                      'src/core/lib/iomgr/pollset_set.cc',
+                      'src/core/lib/iomgr/pollset_set_custom.cc',
+                      'src/core/lib/iomgr/pollset_set_windows.cc',
+                      'src/core/lib/iomgr/pollset_uv.cc',
+                      'src/core/lib/iomgr/pollset_windows.cc',
+                      'src/core/lib/iomgr/resolve_address.cc',
+                      'src/core/lib/iomgr/resolve_address_custom.cc',
+                      'src/core/lib/iomgr/resolve_address_posix.cc',
+                      'src/core/lib/iomgr/resolve_address_windows.cc',
+                      'src/core/lib/iomgr/resource_quota.cc',
+                      'src/core/lib/iomgr/sockaddr_utils.cc',
+                      'src/core/lib/iomgr/socket_factory_posix.cc',
+                      'src/core/lib/iomgr/socket_mutator.cc',
+                      'src/core/lib/iomgr/socket_utils_common_posix.cc',
+                      'src/core/lib/iomgr/socket_utils_linux.cc',
+                      'src/core/lib/iomgr/socket_utils_posix.cc',
+                      'src/core/lib/iomgr/socket_utils_uv.cc',
+                      'src/core/lib/iomgr/socket_utils_windows.cc',
+                      'src/core/lib/iomgr/socket_windows.cc',
+                      'src/core/lib/iomgr/tcp_client.cc',
+                      'src/core/lib/iomgr/tcp_client_custom.cc',
+                      'src/core/lib/iomgr/tcp_client_posix.cc',
+                      'src/core/lib/iomgr/tcp_client_windows.cc',
+                      'src/core/lib/iomgr/tcp_custom.cc',
+                      'src/core/lib/iomgr/tcp_posix.cc',
+                      'src/core/lib/iomgr/tcp_server.cc',
+                      'src/core/lib/iomgr/tcp_server_custom.cc',
+                      'src/core/lib/iomgr/tcp_server_posix.cc',
+                      'src/core/lib/iomgr/tcp_server_utils_posix_common.cc',
+                      'src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc',
+                      'src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc',
+                      'src/core/lib/iomgr/tcp_server_windows.cc',
+                      'src/core/lib/iomgr/tcp_uv.cc',
+                      'src/core/lib/iomgr/tcp_windows.cc',
+                      'src/core/lib/iomgr/time_averaged_stats.cc',
+                      'src/core/lib/iomgr/timer.cc',
+                      'src/core/lib/iomgr/timer_custom.cc',
+                      'src/core/lib/iomgr/timer_generic.cc',
+                      'src/core/lib/iomgr/timer_heap.cc',
+                      'src/core/lib/iomgr/timer_manager.cc',
+                      'src/core/lib/iomgr/timer_uv.cc',
+                      'src/core/lib/iomgr/udp_server.cc',
+                      'src/core/lib/iomgr/unix_sockets_posix.cc',
+                      'src/core/lib/iomgr/unix_sockets_posix_noop.cc',
+                      'src/core/lib/iomgr/wakeup_fd_cv.cc',
+                      'src/core/lib/iomgr/wakeup_fd_eventfd.cc',
+                      'src/core/lib/iomgr/wakeup_fd_nospecial.cc',
+                      'src/core/lib/iomgr/wakeup_fd_pipe.cc',
+                      'src/core/lib/iomgr/wakeup_fd_posix.cc',
+                      'src/core/lib/json/json.cc',
+                      'src/core/lib/json/json_reader.cc',
+                      'src/core/lib/json/json_string.cc',
+                      'src/core/lib/json/json_writer.cc',
+                      'src/core/lib/slice/b64.cc',
+                      'src/core/lib/slice/percent_encoding.cc',
+                      'src/core/lib/slice/slice.cc',
+                      'src/core/lib/slice/slice_buffer.cc',
+                      'src/core/lib/slice/slice_intern.cc',
+                      'src/core/lib/slice/slice_string_helpers.cc',
+                      'src/core/lib/surface/api_trace.cc',
+                      'src/core/lib/surface/byte_buffer.cc',
+                      'src/core/lib/surface/byte_buffer_reader.cc',
+                      'src/core/lib/surface/call.cc',
+                      'src/core/lib/surface/call_details.cc',
+                      'src/core/lib/surface/call_log_batch.cc',
+                      'src/core/lib/surface/channel.cc',
+                      'src/core/lib/surface/channel_init.cc',
+                      'src/core/lib/surface/channel_ping.cc',
+                      'src/core/lib/surface/channel_stack_type.cc',
+                      'src/core/lib/surface/completion_queue.cc',
+                      'src/core/lib/surface/completion_queue_factory.cc',
+                      'src/core/lib/surface/event_string.cc',
+                      'src/core/lib/surface/lame_client.cc',
+                      'src/core/lib/surface/metadata_array.cc',
+                      'src/core/lib/surface/server.cc',
+                      'src/core/lib/surface/validate_metadata.cc',
+                      'src/core/lib/surface/version.cc',
+                      'src/core/lib/transport/bdp_estimator.cc',
+                      'src/core/lib/transport/byte_stream.cc',
+                      'src/core/lib/transport/connectivity_state.cc',
+                      'src/core/lib/transport/error_utils.cc',
+                      'src/core/lib/transport/metadata.cc',
+                      'src/core/lib/transport/metadata_batch.cc',
+                      'src/core/lib/transport/pid_controller.cc',
+                      'src/core/lib/transport/service_config.cc',
+                      'src/core/lib/transport/static_metadata.cc',
+                      'src/core/lib/transport/status_conversion.cc',
+                      'src/core/lib/transport/status_metadata.cc',
+                      'src/core/lib/transport/timeout_encoding.cc',
+                      'src/core/lib/transport/transport.cc',
+                      'src/core/lib/transport/transport_op_string.cc',
+                      'src/core/lib/debug/trace.cc',
+                      'src/core/ext/filters/deadline/deadline_filter.cc',
+                      'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
+                      'src/core/ext/filters/client_channel/backup_poller.cc',
+                      'src/core/ext/filters/client_channel/channel_connectivity.cc',
+                      'src/core/ext/filters/client_channel/client_channel.cc',
+                      'src/core/ext/filters/client_channel/client_channel_factory.cc',
+                      'src/core/ext/filters/client_channel/client_channel_plugin.cc',
+                      'src/core/ext/filters/client_channel/connector.cc',
+                      'src/core/ext/filters/client_channel/http_connect_handshaker.cc',
+                      'src/core/ext/filters/client_channel/http_proxy.cc',
+                      'src/core/ext/filters/client_channel/lb_policy.cc',
+                      'src/core/ext/filters/client_channel/lb_policy_factory.cc',
+                      'src/core/ext/filters/client_channel/lb_policy_registry.cc',
+                      'src/core/ext/filters/client_channel/method_params.cc',
+                      'src/core/ext/filters/client_channel/parse_address.cc',
+                      'src/core/ext/filters/client_channel/proxy_mapper.cc',
+                      'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
+                      'src/core/ext/filters/client_channel/resolver.cc',
+                      'src/core/ext/filters/client_channel/resolver_registry.cc',
+                      'src/core/ext/filters/client_channel/retry_throttle.cc',
+                      'src/core/ext/filters/client_channel/subchannel.cc',
+                      'src/core/ext/filters/client_channel/subchannel_index.cc',
+                      'src/core/ext/filters/client_channel/uri_parser.cc',
+                      'src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc',
+                      'src/core/ext/filters/max_age/max_age_filter.cc',
+                      'src/core/ext/filters/message_size/message_size_filter.cc',
+                      'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc',
+                      'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc',
+                      'src/core/ext/filters/load_reporting/server_load_reporting_filter.cc',
+                      'src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc',
+                      'src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc',
+                      'src/core/ext/transport/cronet/transport/cronet_transport.cc',
+                      'src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc',
+                      'src/core/ext/transport/chttp2/transport/bin_decoder.cc',
+                      'src/core/ext/transport/chttp2/transport/bin_encoder.cc',
+                      'src/core/ext/transport/chttp2/transport/chttp2_plugin.cc',
+                      'src/core/ext/transport/chttp2/transport/chttp2_transport.cc',
+                      'src/core/ext/transport/chttp2/transport/flow_control.cc',
+                      'src/core/ext/transport/chttp2/transport/frame_data.cc',
+                      'src/core/ext/transport/chttp2/transport/frame_goaway.cc',
+                      'src/core/ext/transport/chttp2/transport/frame_ping.cc',
+                      'src/core/ext/transport/chttp2/transport/frame_rst_stream.cc',
+                      'src/core/ext/transport/chttp2/transport/frame_settings.cc',
+                      'src/core/ext/transport/chttp2/transport/frame_window_update.cc',
+                      'src/core/ext/transport/chttp2/transport/hpack_encoder.cc',
+                      'src/core/ext/transport/chttp2/transport/hpack_parser.cc',
+                      'src/core/ext/transport/chttp2/transport/hpack_table.cc',
+                      'src/core/ext/transport/chttp2/transport/http2_settings.cc',
+                      'src/core/ext/transport/chttp2/transport/huffsyms.cc',
+                      'src/core/ext/transport/chttp2/transport/incoming_metadata.cc',
+                      'src/core/ext/transport/chttp2/transport/parsing.cc',
+                      'src/core/ext/transport/chttp2/transport/stream_lists.cc',
+                      'src/core/ext/transport/chttp2/transport/stream_map.cc',
+                      'src/core/ext/transport/chttp2/transport/varint.cc',
+                      'src/core/ext/transport/chttp2/transport/writing.cc',
+                      'src/core/ext/transport/chttp2/alpn/alpn.cc',
+                      'src/core/ext/filters/http/client/http_client_filter.cc',
+                      'src/core/ext/filters/http/http_filters_plugin.cc',
+                      'src/core/ext/filters/http/message_compress/message_compress_filter.cc',
+                      'src/core/ext/filters/http/server/http_server_filter.cc',
+                      'src/core/lib/http/httpcli_security_connector.cc',
+                      'src/core/lib/security/context/security_context.cc',
+                      'src/core/lib/security/credentials/alts/alts_credentials.cc',
+                      'src/core/lib/security/credentials/composite/composite_credentials.cc',
+                      'src/core/lib/security/credentials/credentials.cc',
+                      'src/core/lib/security/credentials/credentials_metadata.cc',
+                      'src/core/lib/security/credentials/fake/fake_credentials.cc',
+                      'src/core/lib/security/credentials/google_default/credentials_generic.cc',
+                      'src/core/lib/security/credentials/google_default/google_default_credentials.cc',
+                      'src/core/lib/security/credentials/iam/iam_credentials.cc',
+                      'src/core/lib/security/credentials/jwt/json_token.cc',
+                      'src/core/lib/security/credentials/jwt/jwt_credentials.cc',
+                      'src/core/lib/security/credentials/jwt/jwt_verifier.cc',
+                      'src/core/lib/security/credentials/oauth2/oauth2_credentials.cc',
+                      'src/core/lib/security/credentials/plugin/plugin_credentials.cc',
+                      'src/core/lib/security/credentials/ssl/ssl_credentials.cc',
+                      'src/core/lib/security/security_connector/alts_security_connector.cc',
+                      'src/core/lib/security/security_connector/security_connector.cc',
+                      'src/core/lib/security/transport/client_auth_filter.cc',
+                      'src/core/lib/security/transport/secure_endpoint.cc',
+                      'src/core/lib/security/transport/security_handshaker.cc',
+                      'src/core/lib/security/transport/server_auth_filter.cc',
+                      'src/core/lib/security/transport/target_authority_table.cc',
+                      'src/core/lib/security/transport/tsi_error.cc',
+                      'src/core/lib/security/util/json_util.cc',
+                      'src/core/lib/surface/init_secure.cc',
+                      'src/core/tsi/alts/crypt/aes_gcm.cc',
+                      'src/core/tsi/alts/crypt/gsec.cc',
+                      'src/core/tsi/alts/frame_protector/alts_counter.cc',
+                      'src/core/tsi/alts/frame_protector/alts_crypter.cc',
+                      'src/core/tsi/alts/frame_protector/alts_frame_protector.cc',
+                      'src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc',
+                      'src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc',
+                      'src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc',
+                      'src/core/tsi/alts/frame_protector/frame_handler.cc',
+                      'src/core/tsi/alts/handshaker/alts_handshaker_client.cc',
+                      'src/core/tsi/alts/handshaker/alts_tsi_event.cc',
+                      'src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc',
+                      'src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc',
+                      'src/core/lib/security/credentials/alts/check_gcp_environment.cc',
+                      'src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc',
+                      'src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc',
+                      'src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc',
+                      'src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc',
+                      'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc',
+                      'src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc',
+                      'src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc',
+                      'src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc',
+                      'src/core/tsi/alts/handshaker/alts_tsi_utils.cc',
+                      'src/core/tsi/alts/handshaker/transport_security_common_api.cc',
+                      'src/core/tsi/alts/handshaker/altscontext.pb.c',
+                      'src/core/tsi/alts/handshaker/handshaker.pb.c',
+                      'src/core/tsi/alts/handshaker/transport_security_common.pb.c',
+                      'third_party/nanopb/pb_common.c',
+                      'third_party/nanopb/pb_decode.c',
+                      'third_party/nanopb/pb_encode.c',
+                      'src/core/tsi/transport_security.cc',
+                      'src/core/tsi/transport_security_adapter.cc',
+                      'src/core/ext/transport/chttp2/client/insecure/channel_create.cc',
+                      'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc',
+                      'src/core/ext/transport/chttp2/client/chttp2_connector.cc',
+                      'src/core/tsi/alts_transport_security.cc',
+                      'src/core/tsi/fake_transport_security.cc',
+                      'src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc',
+                      'src/core/tsi/ssl/session_cache/ssl_session_cache.cc',
+                      'src/core/tsi/ssl/session_cache/ssl_session_openssl.cc',
+                      'src/core/tsi/ssl_transport_security.cc',
+                      'src/core/tsi/transport_security_grpc.cc',
+                      'src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc',
+                      'src/core/ext/transport/chttp2/server/chttp2_server.cc',
+                      'src/core/plugin_registry/grpc_cronet_plugin_registry.cc'
+
+    ss.private_header_files = 'src/core/lib/gpr/arena.h',
+                              'src/core/lib/gpr/env.h',
+                              'src/core/lib/gpr/fork.h',
+                              'src/core/lib/gpr/host_port.h',
+                              'src/core/lib/gpr/mpscq.h',
+                              'src/core/lib/gpr/murmur_hash.h',
+                              'src/core/lib/gpr/spinlock.h',
+                              'src/core/lib/gpr/string.h',
+                              'src/core/lib/gpr/string_windows.h',
+                              'src/core/lib/gpr/time_precise.h',
+                              'src/core/lib/gpr/tls.h',
+                              'src/core/lib/gpr/tls_gcc.h',
+                              'src/core/lib/gpr/tls_msvc.h',
+                              'src/core/lib/gpr/tls_pthread.h',
+                              'src/core/lib/gpr/tmpfile.h',
+                              'src/core/lib/gpr/useful.h',
+                              'src/core/lib/gprpp/abstract.h',
+                              'src/core/lib/gprpp/atomic.h',
+                              'src/core/lib/gprpp/atomic_with_atm.h',
+                              'src/core/lib/gprpp/atomic_with_std.h',
+                              'src/core/lib/gprpp/manual_constructor.h',
+                              'src/core/lib/gprpp/memory.h',
+                              'src/core/lib/gprpp/thd.h',
+                              'src/core/lib/profiling/timers.h',
+                              'src/core/lib/avl/avl.h',
+                              'src/core/lib/backoff/backoff.h',
+                              'src/core/lib/channel/channel_args.h',
+                              'src/core/lib/channel/channel_stack.h',
+                              'src/core/lib/channel/channel_stack_builder.h',
+                              'src/core/lib/channel/channel_trace.h',
+                              'src/core/lib/channel/channel_trace_registry.h',
+                              'src/core/lib/channel/connected_channel.h',
+                              'src/core/lib/channel/context.h',
+                              'src/core/lib/channel/handshaker.h',
+                              'src/core/lib/channel/handshaker_factory.h',
+                              'src/core/lib/channel/handshaker_registry.h',
+                              'src/core/lib/channel/status_util.h',
+                              'src/core/lib/compression/algorithm_metadata.h',
+                              'src/core/lib/compression/compression_internal.h',
+                              'src/core/lib/compression/message_compress.h',
+                              'src/core/lib/compression/stream_compression.h',
+                              'src/core/lib/compression/stream_compression_gzip.h',
+                              'src/core/lib/compression/stream_compression_identity.h',
+                              'src/core/lib/debug/stats.h',
+                              'src/core/lib/debug/stats_data.h',
+                              'src/core/lib/gprpp/debug_location.h',
+                              'src/core/lib/gprpp/inlined_vector.h',
+                              'src/core/lib/gprpp/orphanable.h',
+                              'src/core/lib/gprpp/ref_counted.h',
+                              'src/core/lib/gprpp/ref_counted_ptr.h',
+                              'src/core/lib/http/format_request.h',
+                              'src/core/lib/http/httpcli.h',
+                              'src/core/lib/http/parser.h',
+                              'src/core/lib/iomgr/block_annotate.h',
+                              'src/core/lib/iomgr/call_combiner.h',
+                              'src/core/lib/iomgr/closure.h',
+                              'src/core/lib/iomgr/combiner.h',
+                              'src/core/lib/iomgr/endpoint.h',
+                              'src/core/lib/iomgr/endpoint_pair.h',
+                              'src/core/lib/iomgr/error.h',
+                              'src/core/lib/iomgr/error_internal.h',
+                              'src/core/lib/iomgr/ev_epoll1_linux.h',
+                              'src/core/lib/iomgr/ev_epollex_linux.h',
+                              'src/core/lib/iomgr/ev_epollsig_linux.h',
+                              'src/core/lib/iomgr/ev_poll_posix.h',
+                              'src/core/lib/iomgr/ev_posix.h',
+                              'src/core/lib/iomgr/exec_ctx.h',
+                              'src/core/lib/iomgr/executor.h',
+                              'src/core/lib/iomgr/gethostname.h',
+                              'src/core/lib/iomgr/iocp_windows.h',
+                              'src/core/lib/iomgr/iomgr.h',
+                              'src/core/lib/iomgr/iomgr_custom.h',
+                              'src/core/lib/iomgr/iomgr_internal.h',
+                              'src/core/lib/iomgr/iomgr_posix.h',
+                              'src/core/lib/iomgr/is_epollexclusive_available.h',
+                              'src/core/lib/iomgr/load_file.h',
+                              'src/core/lib/iomgr/lockfree_event.h',
+                              'src/core/lib/iomgr/nameser.h',
+                              'src/core/lib/iomgr/network_status_tracker.h',
+                              'src/core/lib/iomgr/polling_entity.h',
+                              'src/core/lib/iomgr/pollset.h',
+                              'src/core/lib/iomgr/pollset_custom.h',
+                              'src/core/lib/iomgr/pollset_set.h',
+                              'src/core/lib/iomgr/pollset_set_custom.h',
+                              'src/core/lib/iomgr/pollset_set_windows.h',
+                              'src/core/lib/iomgr/pollset_windows.h',
+                              'src/core/lib/iomgr/port.h',
+                              'src/core/lib/iomgr/resolve_address.h',
+                              'src/core/lib/iomgr/resolve_address_custom.h',
+                              'src/core/lib/iomgr/resource_quota.h',
+                              'src/core/lib/iomgr/sockaddr.h',
+                              'src/core/lib/iomgr/sockaddr_custom.h',
+                              'src/core/lib/iomgr/sockaddr_posix.h',
+                              'src/core/lib/iomgr/sockaddr_utils.h',
+                              'src/core/lib/iomgr/sockaddr_windows.h',
+                              'src/core/lib/iomgr/socket_factory_posix.h',
+                              'src/core/lib/iomgr/socket_mutator.h',
+                              'src/core/lib/iomgr/socket_utils.h',
+                              'src/core/lib/iomgr/socket_utils_posix.h',
+                              'src/core/lib/iomgr/socket_windows.h',
+                              'src/core/lib/iomgr/sys_epoll_wrapper.h',
+                              'src/core/lib/iomgr/tcp_client.h',
+                              'src/core/lib/iomgr/tcp_client_posix.h',
+                              'src/core/lib/iomgr/tcp_custom.h',
+                              'src/core/lib/iomgr/tcp_posix.h',
+                              'src/core/lib/iomgr/tcp_server.h',
+                              'src/core/lib/iomgr/tcp_server_utils_posix.h',
+                              'src/core/lib/iomgr/tcp_windows.h',
+                              'src/core/lib/iomgr/time_averaged_stats.h',
+                              'src/core/lib/iomgr/timer.h',
+                              'src/core/lib/iomgr/timer_custom.h',
+                              'src/core/lib/iomgr/timer_heap.h',
+                              'src/core/lib/iomgr/timer_manager.h',
+                              'src/core/lib/iomgr/udp_server.h',
+                              'src/core/lib/iomgr/unix_sockets_posix.h',
+                              'src/core/lib/iomgr/wakeup_fd_cv.h',
+                              'src/core/lib/iomgr/wakeup_fd_pipe.h',
+                              'src/core/lib/iomgr/wakeup_fd_posix.h',
+                              'src/core/lib/json/json.h',
+                              'src/core/lib/json/json_common.h',
+                              'src/core/lib/json/json_reader.h',
+                              'src/core/lib/json/json_writer.h',
+                              'src/core/lib/slice/b64.h',
+                              'src/core/lib/slice/percent_encoding.h',
+                              'src/core/lib/slice/slice_hash_table.h',
+                              'src/core/lib/slice/slice_internal.h',
+                              'src/core/lib/slice/slice_string_helpers.h',
+                              'src/core/lib/slice/slice_weak_hash_table.h',
+                              'src/core/lib/surface/api_trace.h',
+                              'src/core/lib/surface/call.h',
+                              'src/core/lib/surface/call_test_only.h',
+                              'src/core/lib/surface/channel.h',
+                              'src/core/lib/surface/channel_init.h',
+                              'src/core/lib/surface/channel_stack_type.h',
+                              'src/core/lib/surface/completion_queue.h',
+                              'src/core/lib/surface/completion_queue_factory.h',
+                              'src/core/lib/surface/event_string.h',
+                              'src/core/lib/surface/init.h',
+                              'src/core/lib/surface/lame_client.h',
+                              'src/core/lib/surface/server.h',
+                              'src/core/lib/surface/validate_metadata.h',
+                              'src/core/lib/transport/bdp_estimator.h',
+                              'src/core/lib/transport/byte_stream.h',
+                              'src/core/lib/transport/connectivity_state.h',
+                              'src/core/lib/transport/error_utils.h',
+                              'src/core/lib/transport/http2_errors.h',
+                              'src/core/lib/transport/metadata.h',
+                              'src/core/lib/transport/metadata_batch.h',
+                              'src/core/lib/transport/pid_controller.h',
+                              'src/core/lib/transport/service_config.h',
+                              'src/core/lib/transport/static_metadata.h',
+                              'src/core/lib/transport/status_conversion.h',
+                              'src/core/lib/transport/status_metadata.h',
+                              'src/core/lib/transport/timeout_encoding.h',
+                              'src/core/lib/transport/transport.h',
+                              'src/core/lib/transport/transport_impl.h',
+                              'src/core/lib/debug/trace.h',
+                              'src/core/ext/filters/deadline/deadline_filter.h',
+                              'src/core/ext/filters/client_channel/backup_poller.h',
+                              'src/core/ext/filters/client_channel/client_channel.h',
+                              'src/core/ext/filters/client_channel/client_channel_factory.h',
+                              'src/core/ext/filters/client_channel/connector.h',
+                              'src/core/ext/filters/client_channel/http_connect_handshaker.h',
+                              'src/core/ext/filters/client_channel/http_proxy.h',
+                              'src/core/ext/filters/client_channel/lb_policy.h',
+                              'src/core/ext/filters/client_channel/lb_policy_factory.h',
+                              'src/core/ext/filters/client_channel/lb_policy_registry.h',
+                              'src/core/ext/filters/client_channel/method_params.h',
+                              'src/core/ext/filters/client_channel/parse_address.h',
+                              'src/core/ext/filters/client_channel/proxy_mapper.h',
+                              'src/core/ext/filters/client_channel/proxy_mapper_registry.h',
+                              'src/core/ext/filters/client_channel/resolver.h',
+                              'src/core/ext/filters/client_channel/resolver_factory.h',
+                              'src/core/ext/filters/client_channel/resolver_registry.h',
+                              'src/core/ext/filters/client_channel/retry_throttle.h',
+                              'src/core/ext/filters/client_channel/subchannel.h',
+                              'src/core/ext/filters/client_channel/subchannel_index.h',
+                              'src/core/ext/filters/client_channel/uri_parser.h',
+                              'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h',
+                              'src/core/ext/filters/max_age/max_age_filter.h',
+                              'src/core/ext/filters/message_size/message_size_filter.h',
+                              'src/core/ext/filters/load_reporting/server_load_reporting_filter.h',
+                              'src/core/ext/filters/load_reporting/server_load_reporting_plugin.h',
+                              'src/core/ext/transport/cronet/transport/cronet_transport.h',
+                              'third_party/objective_c/Cronet/bidirectional_stream_c.h',
+                              'src/core/ext/transport/chttp2/transport/bin_decoder.h',
+                              'src/core/ext/transport/chttp2/transport/bin_encoder.h',
+                              'src/core/ext/transport/chttp2/transport/chttp2_transport.h',
+                              'src/core/ext/transport/chttp2/transport/flow_control.h',
+                              'src/core/ext/transport/chttp2/transport/frame.h',
+                              'src/core/ext/transport/chttp2/transport/frame_data.h',
+                              'src/core/ext/transport/chttp2/transport/frame_goaway.h',
+                              'src/core/ext/transport/chttp2/transport/frame_ping.h',
+                              'src/core/ext/transport/chttp2/transport/frame_rst_stream.h',
+                              'src/core/ext/transport/chttp2/transport/frame_settings.h',
+                              'src/core/ext/transport/chttp2/transport/frame_window_update.h',
+                              'src/core/ext/transport/chttp2/transport/hpack_encoder.h',
+                              'src/core/ext/transport/chttp2/transport/hpack_parser.h',
+                              'src/core/ext/transport/chttp2/transport/hpack_table.h',
+                              'src/core/ext/transport/chttp2/transport/http2_settings.h',
+                              'src/core/ext/transport/chttp2/transport/huffsyms.h',
+                              'src/core/ext/transport/chttp2/transport/incoming_metadata.h',
+                              'src/core/ext/transport/chttp2/transport/internal.h',
+                              'src/core/ext/transport/chttp2/transport/stream_map.h',
+                              'src/core/ext/transport/chttp2/transport/varint.h',
+                              'src/core/ext/transport/chttp2/alpn/alpn.h',
+                              'src/core/ext/filters/http/client/http_client_filter.h',
+                              'src/core/ext/filters/http/message_compress/message_compress_filter.h',
+                              'src/core/ext/filters/http/server/http_server_filter.h',
+                              'src/core/lib/security/context/security_context.h',
+                              'src/core/lib/security/credentials/alts/alts_credentials.h',
+                              'src/core/lib/security/credentials/composite/composite_credentials.h',
+                              'src/core/lib/security/credentials/credentials.h',
+                              'src/core/lib/security/credentials/fake/fake_credentials.h',
+                              'src/core/lib/security/credentials/google_default/google_default_credentials.h',
+                              'src/core/lib/security/credentials/iam/iam_credentials.h',
+                              'src/core/lib/security/credentials/jwt/json_token.h',
+                              'src/core/lib/security/credentials/jwt/jwt_credentials.h',
+                              'src/core/lib/security/credentials/jwt/jwt_verifier.h',
+                              'src/core/lib/security/credentials/oauth2/oauth2_credentials.h',
+                              'src/core/lib/security/credentials/plugin/plugin_credentials.h',
+                              'src/core/lib/security/credentials/ssl/ssl_credentials.h',
+                              'src/core/lib/security/security_connector/alts_security_connector.h',
+                              'src/core/lib/security/security_connector/security_connector.h',
+                              'src/core/lib/security/transport/auth_filters.h',
+                              'src/core/lib/security/transport/secure_endpoint.h',
+                              'src/core/lib/security/transport/security_handshaker.h',
+                              'src/core/lib/security/transport/target_authority_table.h',
+                              'src/core/lib/security/transport/tsi_error.h',
+                              'src/core/lib/security/util/json_util.h',
+                              'src/core/tsi/alts/crypt/gsec.h',
+                              'src/core/tsi/alts/frame_protector/alts_counter.h',
+                              'src/core/tsi/alts/frame_protector/alts_crypter.h',
+                              'src/core/tsi/alts/frame_protector/alts_frame_protector.h',
+                              'src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h',
+                              'src/core/tsi/alts/frame_protector/frame_handler.h',
+                              'src/core/tsi/alts/handshaker/alts_handshaker_client.h',
+                              'src/core/tsi/alts/handshaker/alts_tsi_event.h',
+                              'src/core/tsi/alts/handshaker/alts_tsi_handshaker.h',
+                              'src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h',
+                              'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h',
+                              'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h',
+                              'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h',
+                              'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h',
+                              'src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h',
+                              'src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h',
+                              'src/core/lib/security/credentials/alts/check_gcp_environment.h',
+                              'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h',
+                              'src/core/tsi/alts/handshaker/alts_handshaker_service_api.h',
+                              'src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h',
+                              'src/core/tsi/alts/handshaker/alts_tsi_utils.h',
+                              'src/core/tsi/alts/handshaker/transport_security_common_api.h',
+                              'src/core/tsi/alts/handshaker/altscontext.pb.h',
+                              'src/core/tsi/alts/handshaker/handshaker.pb.h',
+                              'src/core/tsi/alts/handshaker/transport_security_common.pb.h',
+                              'third_party/nanopb/pb.h',
+                              'third_party/nanopb/pb_common.h',
+                              'third_party/nanopb/pb_decode.h',
+                              'third_party/nanopb/pb_encode.h',
+                              'src/core/tsi/transport_security.h',
+                              'src/core/tsi/transport_security_adapter.h',
+                              'src/core/tsi/transport_security_interface.h',
+                              'src/core/ext/transport/chttp2/client/chttp2_connector.h',
+                              'src/core/tsi/alts_transport_security.h',
+                              'src/core/tsi/fake_transport_security.h',
+                              'src/core/tsi/ssl/session_cache/ssl_session.h',
+                              'src/core/tsi/ssl/session_cache/ssl_session_cache.h',
+                              'src/core/tsi/ssl_transport_security.h',
+                              'src/core/tsi/ssl_types.h',
+                              'src/core/tsi/transport_security_grpc.h',
+                              'src/core/ext/transport/chttp2/server/chttp2_server.h'
   end
 
-  s.subspec 'Tests' do |ss|
+  s.subspec 'Cronet-Tests' do |ss|
     ss.header_mappings_dir = '.'
 
-    ss.dependency "#{s.name}/Interface", version
-    ss.dependency "#{s.name}/Implementation", version
+    ss.dependency "#{s.name}/Cronet-Interface", version
+    ss.dependency "#{s.name}/Cronet-Implementation", version
 
     ss.source_files = 'test/core/util/test_config.cc',
                       'test/core/util/test_config.h',
@@ -1001,8 +2048,11 @@
                       'test/core/util/port_isolated_runtime_environment.cc',
                       'test/core/util/port_server_client.cc',
                       'test/core/util/slice_splitter.cc',
+                      'test/core/util/subprocess_posix.cc',
+                      'test/core/util/subprocess_windows.cc',
                       'test/core/util/tracer_util.cc',
                       'test/core/util/trickle_endpoint.cc',
+                      'test/core/util/cmdline.cc',
                       'test/core/end2end/data/ssl_test_data.h',
                       'test/core/security/oauth2_utils.h',
                       'test/core/end2end/cq_verifier.h',
@@ -1019,8 +2069,10 @@
                       'test/core/util/port.h',
                       'test/core/util/port_server_client.h',
                       'test/core/util/slice_splitter.h',
+                      'test/core/util/subprocess.h',
                       'test/core/util/tracer_util.h',
                       'test/core/util/trickle_endpoint.h',
+                      'test/core/util/cmdline.h',
                       'test/core/end2end/end2end_tests.cc',
                       'test/core/end2end/end2end_test_utils.cc',
                       'test/core/end2end/tests/authority_not_supported.cc',
@@ -1068,6 +2120,21 @@
                       'test/core/end2end/tests/request_with_flags.cc',
                       'test/core/end2end/tests/request_with_payload.cc',
                       'test/core/end2end/tests/resource_quota_server.cc',
+                      'test/core/end2end/tests/retry.cc',
+                      'test/core/end2end/tests/retry_cancellation.cc',
+                      'test/core/end2end/tests/retry_disabled.cc',
+                      'test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc',
+                      'test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc',
+                      'test/core/end2end/tests/retry_non_retriable_status.cc',
+                      'test/core/end2end/tests/retry_recv_initial_metadata.cc',
+                      'test/core/end2end/tests/retry_recv_message.cc',
+                      'test/core/end2end/tests/retry_server_pushback_delay.cc',
+                      'test/core/end2end/tests/retry_server_pushback_disabled.cc',
+                      'test/core/end2end/tests/retry_streaming.cc',
+                      'test/core/end2end/tests/retry_streaming_after_commit.cc',
+                      'test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc',
+                      'test/core/end2end/tests/retry_throttled.cc',
+                      'test/core/end2end/tests/retry_too_many_attempts.cc',
                       'test/core/end2end/tests/server_finishes_request.cc',
                       'test/core/end2end/tests/shutdown_finishes_calls.cc',
                       'test/core/end2end/tests/shutdown_finishes_tags.cc',
@@ -1089,6 +2156,6 @@
 
   # TODO (mxyan): Instead of this hack, add include path "third_party" to C core's include path?
   s.prepare_command = <<-END_OF_COMMAND
-    find src/core/ -type f -exec sed -E -i'.back' 's;#include "third_party/nanopb/(.*)";#include <nanopb/\\1>;g' {} \\\;
+    find src/core/ -type f ! -path '*.back*' -exec sed -E -i'.back' 's;#include "third_party/nanopb/(.*)";#include <nanopb/\\1>;g' {} \\\;
   END_OF_COMMAND
 end
diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec
index a0375bd..149687e 100644
--- a/gRPC-ProtoRPC.podspec
+++ b/gRPC-ProtoRPC.podspec
@@ -21,7 +21,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-ProtoRPC'
-  version = '1.10.0-dev'
+  version = '1.11.0-dev'
   s.version  = version
   s.summary  = 'RPC library for Protocol Buffers, based on gRPC'
   s.homepage = 'https://grpc.io'
diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec
index 280aafe..2497174 100644
--- a/gRPC-RxLibrary.podspec
+++ b/gRPC-RxLibrary.podspec
@@ -21,7 +21,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-RxLibrary'
-  version = '1.10.0-dev'
+  version = '1.11.0-dev'
   s.version  = version
   s.summary  = 'Reactive Extensions library for iOS/OSX.'
   s.homepage = 'https://grpc.io'
diff --git a/gRPC.podspec b/gRPC.podspec
index 930d991..68e06b5 100644
--- a/gRPC.podspec
+++ b/gRPC.podspec
@@ -20,7 +20,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC'
-  version = '1.10.0-dev'
+  version = '1.11.0-dev'
   s.version  = version
   s.summary  = 'gRPC client library for iOS/OSX'
   s.homepage = 'https://grpc.io'
diff --git a/grpc.def b/grpc.def
index be59ef0..d64629f 100644
--- a/grpc.def
+++ b/grpc.def
@@ -8,8 +8,6 @@
     grpc_compression_options_enable_algorithm
     grpc_compression_options_disable_algorithm
     grpc_compression_options_is_algorithm_enabled
-    grpc_compression_algorithm_parse_ruby
-    grpc_compression_algorithm_name_ruby
     grpc_metadata_array_init
     grpc_metadata_array_destroy
     grpc_call_details_init
@@ -47,6 +45,8 @@
     grpc_insecure_channel_create
     grpc_lame_client_channel_create
     grpc_channel_destroy
+    grpc_channel_get_trace
+    grpc_channel_get_uuid
     grpc_call_cancel
     grpc_call_cancel_with_status
     grpc_call_ref
@@ -85,6 +85,9 @@
     grpc_auth_context_add_property
     grpc_auth_context_add_cstring_property
     grpc_auth_context_set_peer_identity_property_name
+    grpc_ssl_session_cache_create_lru
+    grpc_ssl_session_cache_destroy
+    grpc_ssl_session_cache_create_channel_arg
     grpc_channel_credentials_release
     grpc_google_default_credentials_create
     grpc_set_ssl_roots_override_callback
@@ -178,27 +181,8 @@
     gpr_free_aligned
     gpr_set_allocation_functions
     gpr_get_allocation_functions
-    gpr_avl_create
-    gpr_avl_ref
-    gpr_avl_unref
-    gpr_avl_add
-    gpr_avl_remove
-    gpr_avl_get
-    gpr_avl_maybe_get
-    gpr_avl_is_empty
-    gpr_cmdline_create
-    gpr_cmdline_add_int
-    gpr_cmdline_add_flag
-    gpr_cmdline_add_string
-    gpr_cmdline_on_extra_arg
-    gpr_cmdline_set_survive_failure
-    gpr_cmdline_parse
-    gpr_cmdline_destroy
-    gpr_cmdline_usage_string
     gpr_cpu_num_cores
     gpr_cpu_current_cpu
-    gpr_join_host_port
-    gpr_split_host_port
     gpr_log_severity_string
     gpr_log
     gpr_log_message
@@ -208,11 +192,6 @@
     gpr_format_message
     gpr_strdup
     gpr_asprintf
-    gpr_subprocess_binary_extension
-    gpr_subprocess_create
-    gpr_subprocess_destroy
-    gpr_subprocess_join
-    gpr_subprocess_interrupt
     gpr_mu_init
     gpr_mu_destroy
     gpr_mu_lock
@@ -237,14 +216,7 @@
     gpr_stats_init
     gpr_stats_inc
     gpr_stats_read
-    gpr_thd_new
-    gpr_thd_options_default
-    gpr_thd_options_set_detached
-    gpr_thd_options_set_joinable
-    gpr_thd_options_is_detached
-    gpr_thd_options_is_joinable
     gpr_thd_currentid
-    gpr_thd_join
     gpr_time_0
     gpr_inf_future
     gpr_inf_past
diff --git a/grpc.gemspec b/grpc.gemspec
index 39174cc..920254a 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -44,32 +44,28 @@
 
   s.extensions = %w(src/ruby/ext/grpc/extconf.rb)
 
+  s.files += %w( third_party/address_sorting/address_sorting_internal.h )
+  s.files += %w( third_party/address_sorting/include/address_sorting/address_sorting.h )
+  s.files += %w( third_party/address_sorting/address_sorting.c )
+  s.files += %w( third_party/address_sorting/address_sorting_posix.c )
+  s.files += %w( third_party/address_sorting/address_sorting_windows.c )
   s.files += %w( include/grpc/support/alloc.h )
   s.files += %w( include/grpc/support/atm.h )
   s.files += %w( include/grpc/support/atm_gcc_atomic.h )
   s.files += %w( include/grpc/support/atm_gcc_sync.h )
   s.files += %w( include/grpc/support/atm_windows.h )
-  s.files += %w( include/grpc/support/avl.h )
-  s.files += %w( include/grpc/support/cmdline.h )
   s.files += %w( include/grpc/support/cpu.h )
-  s.files += %w( include/grpc/support/host_port.h )
   s.files += %w( include/grpc/support/log.h )
   s.files += %w( include/grpc/support/log_windows.h )
   s.files += %w( include/grpc/support/port_platform.h )
   s.files += %w( include/grpc/support/string_util.h )
-  s.files += %w( include/grpc/support/subprocess.h )
   s.files += %w( include/grpc/support/sync.h )
   s.files += %w( include/grpc/support/sync_custom.h )
   s.files += %w( include/grpc/support/sync_generic.h )
   s.files += %w( include/grpc/support/sync_posix.h )
   s.files += %w( include/grpc/support/sync_windows.h )
-  s.files += %w( include/grpc/support/thd.h )
+  s.files += %w( include/grpc/support/thd_id.h )
   s.files += %w( include/grpc/support/time.h )
-  s.files += %w( include/grpc/support/tls.h )
-  s.files += %w( include/grpc/support/tls_gcc.h )
-  s.files += %w( include/grpc/support/tls_msvc.h )
-  s.files += %w( include/grpc/support/tls_pthread.h )
-  s.files += %w( include/grpc/support/useful.h )
   s.files += %w( include/grpc/impl/codegen/atm.h )
   s.files += %w( include/grpc/impl/codegen/atm_gcc_atomic.h )
   s.files += %w( include/grpc/impl/codegen/atm_gcc_sync.h )
@@ -86,26 +82,30 @@
   s.files += %w( src/core/lib/gpr/arena.h )
   s.files += %w( src/core/lib/gpr/env.h )
   s.files += %w( src/core/lib/gpr/fork.h )
+  s.files += %w( src/core/lib/gpr/host_port.h )
   s.files += %w( src/core/lib/gpr/mpscq.h )
   s.files += %w( src/core/lib/gpr/murmur_hash.h )
   s.files += %w( src/core/lib/gpr/spinlock.h )
   s.files += %w( src/core/lib/gpr/string.h )
   s.files += %w( src/core/lib/gpr/string_windows.h )
-  s.files += %w( src/core/lib/gpr/thd_internal.h )
   s.files += %w( src/core/lib/gpr/time_precise.h )
+  s.files += %w( src/core/lib/gpr/tls.h )
+  s.files += %w( src/core/lib/gpr/tls_gcc.h )
+  s.files += %w( src/core/lib/gpr/tls_msvc.h )
+  s.files += %w( src/core/lib/gpr/tls_pthread.h )
   s.files += %w( src/core/lib/gpr/tmpfile.h )
+  s.files += %w( src/core/lib/gpr/useful.h )
   s.files += %w( src/core/lib/gprpp/abstract.h )
   s.files += %w( src/core/lib/gprpp/atomic.h )
   s.files += %w( src/core/lib/gprpp/atomic_with_atm.h )
   s.files += %w( src/core/lib/gprpp/atomic_with_std.h )
   s.files += %w( src/core/lib/gprpp/manual_constructor.h )
   s.files += %w( src/core/lib/gprpp/memory.h )
+  s.files += %w( src/core/lib/gprpp/thd.h )
   s.files += %w( src/core/lib/profiling/timers.h )
   s.files += %w( src/core/lib/gpr/alloc.cc )
   s.files += %w( src/core/lib/gpr/arena.cc )
   s.files += %w( src/core/lib/gpr/atm.cc )
-  s.files += %w( src/core/lib/gpr/avl.cc )
-  s.files += %w( src/core/lib/gpr/cmdline.cc )
   s.files += %w( src/core/lib/gpr/cpu_iphone.cc )
   s.files += %w( src/core/lib/gpr/cpu_linux.cc )
   s.files += %w( src/core/lib/gpr/cpu_posix.cc )
@@ -126,14 +126,9 @@
   s.files += %w( src/core/lib/gpr/string_posix.cc )
   s.files += %w( src/core/lib/gpr/string_util_windows.cc )
   s.files += %w( src/core/lib/gpr/string_windows.cc )
-  s.files += %w( src/core/lib/gpr/subprocess_posix.cc )
-  s.files += %w( src/core/lib/gpr/subprocess_windows.cc )
   s.files += %w( src/core/lib/gpr/sync.cc )
   s.files += %w( src/core/lib/gpr/sync_posix.cc )
   s.files += %w( src/core/lib/gpr/sync_windows.cc )
-  s.files += %w( src/core/lib/gpr/thd.cc )
-  s.files += %w( src/core/lib/gpr/thd_posix.cc )
-  s.files += %w( src/core/lib/gpr/thd_windows.cc )
   s.files += %w( src/core/lib/gpr/time.cc )
   s.files += %w( src/core/lib/gpr/time_posix.cc )
   s.files += %w( src/core/lib/gpr/time_precise.cc )
@@ -143,6 +138,8 @@
   s.files += %w( src/core/lib/gpr/tmpfile_posix.cc )
   s.files += %w( src/core/lib/gpr/tmpfile_windows.cc )
   s.files += %w( src/core/lib/gpr/wrap_memcpy.cc )
+  s.files += %w( src/core/lib/gprpp/thd_posix.cc )
+  s.files += %w( src/core/lib/gprpp/thd_windows.cc )
   s.files += %w( src/core/lib/profiling/basic_timers.cc )
   s.files += %w( src/core/lib/profiling/stap_timers.cc )
   s.files += %w( include/grpc/impl/codegen/byte_buffer.h )
@@ -170,7 +167,6 @@
   s.files += %w( include/grpc/byte_buffer.h )
   s.files += %w( include/grpc/byte_buffer_reader.h )
   s.files += %w( include/grpc/compression.h )
-  s.files += %w( include/grpc/compression_ruby.h )
   s.files += %w( include/grpc/fork.h )
   s.files += %w( include/grpc/grpc.h )
   s.files += %w( include/grpc/grpc_posix.h )
@@ -206,6 +202,7 @@
   s.files += %w( src/core/ext/filters/http/message_compress/message_compress_filter.h )
   s.files += %w( src/core/ext/filters/http/server/http_server_filter.h )
   s.files += %w( src/core/lib/security/context/security_context.h )
+  s.files += %w( src/core/lib/security/credentials/alts/alts_credentials.h )
   s.files += %w( src/core/lib/security/credentials/composite/composite_credentials.h )
   s.files += %w( src/core/lib/security/credentials/credentials.h )
   s.files += %w( src/core/lib/security/credentials/fake/fake_credentials.h )
@@ -217,22 +214,47 @@
   s.files += %w( src/core/lib/security/credentials/oauth2/oauth2_credentials.h )
   s.files += %w( src/core/lib/security/credentials/plugin/plugin_credentials.h )
   s.files += %w( src/core/lib/security/credentials/ssl/ssl_credentials.h )
+  s.files += %w( src/core/lib/security/security_connector/alts_security_connector.h )
+  s.files += %w( src/core/lib/security/security_connector/security_connector.h )
   s.files += %w( src/core/lib/security/transport/auth_filters.h )
-  s.files += %w( src/core/lib/security/transport/lb_targets_info.h )
   s.files += %w( src/core/lib/security/transport/secure_endpoint.h )
-  s.files += %w( src/core/lib/security/transport/security_connector.h )
   s.files += %w( src/core/lib/security/transport/security_handshaker.h )
+  s.files += %w( src/core/lib/security/transport/target_authority_table.h )
   s.files += %w( src/core/lib/security/transport/tsi_error.h )
   s.files += %w( src/core/lib/security/util/json_util.h )
-  s.files += %w( src/core/tsi/alts_transport_security.h )
-  s.files += %w( src/core/tsi/fake_transport_security.h )
-  s.files += %w( src/core/tsi/ssl_transport_security.h )
-  s.files += %w( src/core/tsi/ssl_types.h )
-  s.files += %w( src/core/tsi/transport_security_grpc.h )
+  s.files += %w( src/core/tsi/alts/crypt/gsec.h )
+  s.files += %w( src/core/tsi/alts/frame_protector/alts_counter.h )
+  s.files += %w( src/core/tsi/alts/frame_protector/alts_crypter.h )
+  s.files += %w( src/core/tsi/alts/frame_protector/alts_frame_protector.h )
+  s.files += %w( src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h )
+  s.files += %w( src/core/tsi/alts/frame_protector/frame_handler.h )
+  s.files += %w( src/core/tsi/alts/handshaker/alts_handshaker_client.h )
+  s.files += %w( src/core/tsi/alts/handshaker/alts_tsi_event.h )
+  s.files += %w( src/core/tsi/alts/handshaker/alts_tsi_handshaker.h )
+  s.files += %w( src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h )
+  s.files += %w( src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h )
+  s.files += %w( src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h )
+  s.files += %w( src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h )
+  s.files += %w( src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h )
+  s.files += %w( src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h )
+  s.files += %w( src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h )
+  s.files += %w( src/core/lib/security/credentials/alts/check_gcp_environment.h )
+  s.files += %w( src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h )
+  s.files += %w( src/core/tsi/alts/handshaker/alts_handshaker_service_api.h )
+  s.files += %w( src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h )
+  s.files += %w( src/core/tsi/alts/handshaker/alts_tsi_utils.h )
+  s.files += %w( src/core/tsi/alts/handshaker/transport_security_common_api.h )
+  s.files += %w( src/core/tsi/alts/handshaker/altscontext.pb.h )
+  s.files += %w( src/core/tsi/alts/handshaker/handshaker.pb.h )
+  s.files += %w( src/core/tsi/alts/handshaker/transport_security_common.pb.h )
+  s.files += %w( third_party/nanopb/pb.h )
+  s.files += %w( third_party/nanopb/pb_common.h )
+  s.files += %w( third_party/nanopb/pb_decode.h )
+  s.files += %w( third_party/nanopb/pb_encode.h )
   s.files += %w( src/core/tsi/transport_security.h )
   s.files += %w( src/core/tsi/transport_security_adapter.h )
   s.files += %w( src/core/tsi/transport_security_interface.h )
-  s.files += %w( src/core/ext/transport/chttp2/server/chttp2_server.h )
+  s.files += %w( src/core/ext/transport/chttp2/client/chttp2_connector.h )
   s.files += %w( src/core/ext/filters/client_channel/backup_poller.h )
   s.files += %w( src/core/ext/filters/client_channel/client_channel.h )
   s.files += %w( src/core/ext/filters/client_channel/client_channel_factory.h )
@@ -242,6 +264,7 @@
   s.files += %w( src/core/ext/filters/client_channel/lb_policy.h )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy_factory.h )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy_registry.h )
+  s.files += %w( src/core/ext/filters/client_channel/method_params.h )
   s.files += %w( src/core/ext/filters/client_channel/parse_address.h )
   s.files += %w( src/core/ext/filters/client_channel/proxy_mapper.h )
   s.files += %w( src/core/ext/filters/client_channel/proxy_mapper_registry.h )
@@ -253,17 +276,28 @@
   s.files += %w( src/core/ext/filters/client_channel/subchannel_index.h )
   s.files += %w( src/core/ext/filters/client_channel/uri_parser.h )
   s.files += %w( src/core/ext/filters/deadline/deadline_filter.h )
-  s.files += %w( src/core/ext/transport/chttp2/client/chttp2_connector.h )
+  s.files += %w( src/core/tsi/alts_transport_security.h )
+  s.files += %w( src/core/tsi/fake_transport_security.h )
+  s.files += %w( src/core/tsi/ssl/session_cache/ssl_session.h )
+  s.files += %w( src/core/tsi/ssl/session_cache/ssl_session_cache.h )
+  s.files += %w( src/core/tsi/ssl_transport_security.h )
+  s.files += %w( src/core/tsi/ssl_types.h )
+  s.files += %w( src/core/tsi/transport_security_grpc.h )
+  s.files += %w( src/core/ext/transport/chttp2/server/chttp2_server.h )
   s.files += %w( src/core/ext/transport/inproc/inproc_transport.h )
+  s.files += %w( src/core/lib/avl/avl.h )
   s.files += %w( src/core/lib/backoff/backoff.h )
   s.files += %w( src/core/lib/channel/channel_args.h )
   s.files += %w( src/core/lib/channel/channel_stack.h )
   s.files += %w( src/core/lib/channel/channel_stack_builder.h )
+  s.files += %w( src/core/lib/channel/channel_trace.h )
+  s.files += %w( src/core/lib/channel/channel_trace_registry.h )
   s.files += %w( src/core/lib/channel/connected_channel.h )
   s.files += %w( src/core/lib/channel/context.h )
   s.files += %w( src/core/lib/channel/handshaker.h )
   s.files += %w( src/core/lib/channel/handshaker_factory.h )
   s.files += %w( src/core/lib/channel/handshaker_registry.h )
+  s.files += %w( src/core/lib/channel/status_util.h )
   s.files += %w( src/core/lib/compression/algorithm_metadata.h )
   s.files += %w( src/core/lib/compression/compression_internal.h )
   s.files += %w( src/core/lib/compression/message_compress.h )
@@ -298,9 +332,9 @@
   s.files += %w( src/core/lib/iomgr/gethostname.h )
   s.files += %w( src/core/lib/iomgr/iocp_windows.h )
   s.files += %w( src/core/lib/iomgr/iomgr.h )
+  s.files += %w( src/core/lib/iomgr/iomgr_custom.h )
   s.files += %w( src/core/lib/iomgr/iomgr_internal.h )
   s.files += %w( src/core/lib/iomgr/iomgr_posix.h )
-  s.files += %w( src/core/lib/iomgr/iomgr_uv.h )
   s.files += %w( src/core/lib/iomgr/is_epollexclusive_available.h )
   s.files += %w( src/core/lib/iomgr/load_file.h )
   s.files += %w( src/core/lib/iomgr/lockfree_event.h )
@@ -308,14 +342,17 @@
   s.files += %w( src/core/lib/iomgr/network_status_tracker.h )
   s.files += %w( src/core/lib/iomgr/polling_entity.h )
   s.files += %w( src/core/lib/iomgr/pollset.h )
+  s.files += %w( src/core/lib/iomgr/pollset_custom.h )
   s.files += %w( src/core/lib/iomgr/pollset_set.h )
+  s.files += %w( src/core/lib/iomgr/pollset_set_custom.h )
   s.files += %w( src/core/lib/iomgr/pollset_set_windows.h )
-  s.files += %w( src/core/lib/iomgr/pollset_uv.h )
   s.files += %w( src/core/lib/iomgr/pollset_windows.h )
   s.files += %w( src/core/lib/iomgr/port.h )
   s.files += %w( src/core/lib/iomgr/resolve_address.h )
+  s.files += %w( src/core/lib/iomgr/resolve_address_custom.h )
   s.files += %w( src/core/lib/iomgr/resource_quota.h )
   s.files += %w( src/core/lib/iomgr/sockaddr.h )
+  s.files += %w( src/core/lib/iomgr/sockaddr_custom.h )
   s.files += %w( src/core/lib/iomgr/sockaddr_posix.h )
   s.files += %w( src/core/lib/iomgr/sockaddr_utils.h )
   s.files += %w( src/core/lib/iomgr/sockaddr_windows.h )
@@ -327,17 +364,16 @@
   s.files += %w( src/core/lib/iomgr/sys_epoll_wrapper.h )
   s.files += %w( src/core/lib/iomgr/tcp_client.h )
   s.files += %w( src/core/lib/iomgr/tcp_client_posix.h )
+  s.files += %w( src/core/lib/iomgr/tcp_custom.h )
   s.files += %w( src/core/lib/iomgr/tcp_posix.h )
   s.files += %w( src/core/lib/iomgr/tcp_server.h )
   s.files += %w( src/core/lib/iomgr/tcp_server_utils_posix.h )
-  s.files += %w( src/core/lib/iomgr/tcp_uv.h )
   s.files += %w( src/core/lib/iomgr/tcp_windows.h )
   s.files += %w( src/core/lib/iomgr/time_averaged_stats.h )
   s.files += %w( src/core/lib/iomgr/timer.h )
-  s.files += %w( src/core/lib/iomgr/timer_generic.h )
+  s.files += %w( src/core/lib/iomgr/timer_custom.h )
   s.files += %w( src/core/lib/iomgr/timer_heap.h )
   s.files += %w( src/core/lib/iomgr/timer_manager.h )
-  s.files += %w( src/core/lib/iomgr/timer_uv.h )
   s.files += %w( src/core/lib/iomgr/udp_server.h )
   s.files += %w( src/core/lib/iomgr/unix_sockets_posix.h )
   s.files += %w( src/core/lib/iomgr/wakeup_fd_cv.h )
@@ -352,6 +388,7 @@
   s.files += %w( src/core/lib/slice/slice_hash_table.h )
   s.files += %w( src/core/lib/slice/slice_internal.h )
   s.files += %w( src/core/lib/slice/slice_string_helpers.h )
+  s.files += %w( src/core/lib/slice/slice_weak_hash_table.h )
   s.files += %w( src/core/lib/surface/api_trace.h )
   s.files += %w( src/core/lib/surface/call.h )
   s.files += %w( src/core/lib/surface/call_test_only.h )
@@ -376,20 +413,16 @@
   s.files += %w( src/core/lib/transport/service_config.h )
   s.files += %w( src/core/lib/transport/static_metadata.h )
   s.files += %w( src/core/lib/transport/status_conversion.h )
+  s.files += %w( src/core/lib/transport/status_metadata.h )
   s.files += %w( src/core/lib/transport/timeout_encoding.h )
   s.files += %w( src/core/lib/transport/transport.h )
   s.files += %w( src/core/lib/transport/transport_impl.h )
   s.files += %w( src/core/lib/debug/trace.h )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h )
-  s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h )
-  s.files += %w( third_party/nanopb/pb.h )
-  s.files += %w( third_party/nanopb/pb_common.h )
-  s.files += %w( third_party/nanopb/pb_decode.h )
-  s.files += %w( third_party/nanopb/pb_encode.h )
   s.files += %w( src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/subchannel_list.h )
   s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h )
@@ -401,17 +434,20 @@
   s.files += %w( src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h )
   s.files += %w( src/core/ext/filters/workarounds/workaround_utils.h )
   s.files += %w( src/core/lib/surface/init.cc )
+  s.files += %w( src/core/lib/avl/avl.cc )
   s.files += %w( src/core/lib/backoff/backoff.cc )
   s.files += %w( src/core/lib/channel/channel_args.cc )
   s.files += %w( src/core/lib/channel/channel_stack.cc )
   s.files += %w( src/core/lib/channel/channel_stack_builder.cc )
+  s.files += %w( src/core/lib/channel/channel_trace.cc )
+  s.files += %w( src/core/lib/channel/channel_trace_registry.cc )
   s.files += %w( src/core/lib/channel/connected_channel.cc )
   s.files += %w( src/core/lib/channel/handshaker.cc )
   s.files += %w( src/core/lib/channel/handshaker_factory.cc )
   s.files += %w( src/core/lib/channel/handshaker_registry.cc )
+  s.files += %w( src/core/lib/channel/status_util.cc )
   s.files += %w( src/core/lib/compression/compression.cc )
   s.files += %w( src/core/lib/compression/compression_internal.cc )
-  s.files += %w( src/core/lib/compression/compression_ruby.cc )
   s.files += %w( src/core/lib/compression/message_compress.cc )
   s.files += %w( src/core/lib/compression/stream_compression.cc )
   s.files += %w( src/core/lib/compression/stream_compression_gzip.cc )
@@ -443,6 +479,8 @@
   s.files += %w( src/core/lib/iomgr/gethostname_sysconf.cc )
   s.files += %w( src/core/lib/iomgr/iocp_windows.cc )
   s.files += %w( src/core/lib/iomgr/iomgr.cc )
+  s.files += %w( src/core/lib/iomgr/iomgr_custom.cc )
+  s.files += %w( src/core/lib/iomgr/iomgr_internal.cc )
   s.files += %w( src/core/lib/iomgr/iomgr_posix.cc )
   s.files += %w( src/core/lib/iomgr/iomgr_uv.cc )
   s.files += %w( src/core/lib/iomgr/iomgr_windows.cc )
@@ -451,12 +489,16 @@
   s.files += %w( src/core/lib/iomgr/lockfree_event.cc )
   s.files += %w( src/core/lib/iomgr/network_status_tracker.cc )
   s.files += %w( src/core/lib/iomgr/polling_entity.cc )
-  s.files += %w( src/core/lib/iomgr/pollset_set_uv.cc )
+  s.files += %w( src/core/lib/iomgr/pollset.cc )
+  s.files += %w( src/core/lib/iomgr/pollset_custom.cc )
+  s.files += %w( src/core/lib/iomgr/pollset_set.cc )
+  s.files += %w( src/core/lib/iomgr/pollset_set_custom.cc )
   s.files += %w( src/core/lib/iomgr/pollset_set_windows.cc )
   s.files += %w( src/core/lib/iomgr/pollset_uv.cc )
   s.files += %w( src/core/lib/iomgr/pollset_windows.cc )
+  s.files += %w( src/core/lib/iomgr/resolve_address.cc )
+  s.files += %w( src/core/lib/iomgr/resolve_address_custom.cc )
   s.files += %w( src/core/lib/iomgr/resolve_address_posix.cc )
-  s.files += %w( src/core/lib/iomgr/resolve_address_uv.cc )
   s.files += %w( src/core/lib/iomgr/resolve_address_windows.cc )
   s.files += %w( src/core/lib/iomgr/resource_quota.cc )
   s.files += %w( src/core/lib/iomgr/sockaddr_utils.cc )
@@ -468,19 +510,24 @@
   s.files += %w( src/core/lib/iomgr/socket_utils_uv.cc )
   s.files += %w( src/core/lib/iomgr/socket_utils_windows.cc )
   s.files += %w( src/core/lib/iomgr/socket_windows.cc )
+  s.files += %w( src/core/lib/iomgr/tcp_client.cc )
+  s.files += %w( src/core/lib/iomgr/tcp_client_custom.cc )
   s.files += %w( src/core/lib/iomgr/tcp_client_posix.cc )
-  s.files += %w( src/core/lib/iomgr/tcp_client_uv.cc )
   s.files += %w( src/core/lib/iomgr/tcp_client_windows.cc )
+  s.files += %w( src/core/lib/iomgr/tcp_custom.cc )
   s.files += %w( src/core/lib/iomgr/tcp_posix.cc )
+  s.files += %w( src/core/lib/iomgr/tcp_server.cc )
+  s.files += %w( src/core/lib/iomgr/tcp_server_custom.cc )
   s.files += %w( src/core/lib/iomgr/tcp_server_posix.cc )
   s.files += %w( src/core/lib/iomgr/tcp_server_utils_posix_common.cc )
   s.files += %w( src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc )
   s.files += %w( src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc )
-  s.files += %w( src/core/lib/iomgr/tcp_server_uv.cc )
   s.files += %w( src/core/lib/iomgr/tcp_server_windows.cc )
   s.files += %w( src/core/lib/iomgr/tcp_uv.cc )
   s.files += %w( src/core/lib/iomgr/tcp_windows.cc )
   s.files += %w( src/core/lib/iomgr/time_averaged_stats.cc )
+  s.files += %w( src/core/lib/iomgr/timer.cc )
+  s.files += %w( src/core/lib/iomgr/timer_custom.cc )
   s.files += %w( src/core/lib/iomgr/timer_generic.cc )
   s.files += %w( src/core/lib/iomgr/timer_heap.cc )
   s.files += %w( src/core/lib/iomgr/timer_manager.cc )
@@ -501,7 +548,6 @@
   s.files += %w( src/core/lib/slice/percent_encoding.cc )
   s.files += %w( src/core/lib/slice/slice.cc )
   s.files += %w( src/core/lib/slice/slice_buffer.cc )
-  s.files += %w( src/core/lib/slice/slice_hash_table.cc )
   s.files += %w( src/core/lib/slice/slice_intern.cc )
   s.files += %w( src/core/lib/slice/slice_string_helpers.cc )
   s.files += %w( src/core/lib/surface/api_trace.cc )
@@ -532,6 +578,7 @@
   s.files += %w( src/core/lib/transport/service_config.cc )
   s.files += %w( src/core/lib/transport/static_metadata.cc )
   s.files += %w( src/core/lib/transport/status_conversion.cc )
+  s.files += %w( src/core/lib/transport/status_metadata.cc )
   s.files += %w( src/core/lib/transport/timeout_encoding.cc )
   s.files += %w( src/core/lib/transport/transport.cc )
   s.files += %w( src/core/lib/transport/transport_op_string.cc )
@@ -566,6 +613,7 @@
   s.files += %w( src/core/ext/filters/http/server/http_server_filter.cc )
   s.files += %w( src/core/lib/http/httpcli_security_connector.cc )
   s.files += %w( src/core/lib/security/context/security_context.cc )
+  s.files += %w( src/core/lib/security/credentials/alts/alts_credentials.cc )
   s.files += %w( src/core/lib/security/credentials/composite/composite_credentials.cc )
   s.files += %w( src/core/lib/security/credentials/credentials.cc )
   s.files += %w( src/core/lib/security/credentials/credentials_metadata.cc )
@@ -579,23 +627,55 @@
   s.files += %w( src/core/lib/security/credentials/oauth2/oauth2_credentials.cc )
   s.files += %w( src/core/lib/security/credentials/plugin/plugin_credentials.cc )
   s.files += %w( src/core/lib/security/credentials/ssl/ssl_credentials.cc )
+  s.files += %w( src/core/lib/security/security_connector/alts_security_connector.cc )
+  s.files += %w( src/core/lib/security/security_connector/security_connector.cc )
   s.files += %w( src/core/lib/security/transport/client_auth_filter.cc )
-  s.files += %w( src/core/lib/security/transport/lb_targets_info.cc )
   s.files += %w( src/core/lib/security/transport/secure_endpoint.cc )
-  s.files += %w( src/core/lib/security/transport/security_connector.cc )
   s.files += %w( src/core/lib/security/transport/security_handshaker.cc )
   s.files += %w( src/core/lib/security/transport/server_auth_filter.cc )
+  s.files += %w( src/core/lib/security/transport/target_authority_table.cc )
   s.files += %w( src/core/lib/security/transport/tsi_error.cc )
   s.files += %w( src/core/lib/security/util/json_util.cc )
   s.files += %w( src/core/lib/surface/init_secure.cc )
-  s.files += %w( src/core/tsi/alts_transport_security.cc )
-  s.files += %w( src/core/tsi/fake_transport_security.cc )
-  s.files += %w( src/core/tsi/ssl_transport_security.cc )
-  s.files += %w( src/core/tsi/transport_security_grpc.cc )
+  s.files += %w( src/core/tsi/alts/crypt/aes_gcm.cc )
+  s.files += %w( src/core/tsi/alts/crypt/gsec.cc )
+  s.files += %w( src/core/tsi/alts/frame_protector/alts_counter.cc )
+  s.files += %w( src/core/tsi/alts/frame_protector/alts_crypter.cc )
+  s.files += %w( src/core/tsi/alts/frame_protector/alts_frame_protector.cc )
+  s.files += %w( src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc )
+  s.files += %w( src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc )
+  s.files += %w( src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc )
+  s.files += %w( src/core/tsi/alts/frame_protector/frame_handler.cc )
+  s.files += %w( src/core/tsi/alts/handshaker/alts_handshaker_client.cc )
+  s.files += %w( src/core/tsi/alts/handshaker/alts_tsi_event.cc )
+  s.files += %w( src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc )
+  s.files += %w( src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc )
+  s.files += %w( src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc )
+  s.files += %w( src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc )
+  s.files += %w( src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc )
+  s.files += %w( src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc )
+  s.files += %w( src/core/lib/security/credentials/alts/check_gcp_environment.cc )
+  s.files += %w( src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc )
+  s.files += %w( src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc )
+  s.files += %w( src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc )
+  s.files += %w( src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc )
+  s.files += %w( src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc )
+  s.files += %w( src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc )
+  s.files += %w( src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc )
+  s.files += %w( src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc )
+  s.files += %w( src/core/tsi/alts/handshaker/alts_tsi_utils.cc )
+  s.files += %w( src/core/tsi/alts/handshaker/transport_security_common_api.cc )
+  s.files += %w( src/core/tsi/alts/handshaker/altscontext.pb.c )
+  s.files += %w( src/core/tsi/alts/handshaker/handshaker.pb.c )
+  s.files += %w( src/core/tsi/alts/handshaker/transport_security_common.pb.c )
+  s.files += %w( third_party/nanopb/pb_common.c )
+  s.files += %w( third_party/nanopb/pb_decode.c )
+  s.files += %w( third_party/nanopb/pb_encode.c )
   s.files += %w( src/core/tsi/transport_security.cc )
   s.files += %w( src/core/tsi/transport_security_adapter.cc )
-  s.files += %w( src/core/ext/transport/chttp2/server/chttp2_server.cc )
-  s.files += %w( src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc )
+  s.files += %w( src/core/ext/transport/chttp2/client/insecure/channel_create.cc )
+  s.files += %w( src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc )
+  s.files += %w( src/core/ext/transport/chttp2/client/chttp2_connector.cc )
   s.files += %w( src/core/ext/filters/client_channel/backup_poller.cc )
   s.files += %w( src/core/ext/filters/client_channel/channel_connectivity.cc )
   s.files += %w( src/core/ext/filters/client_channel/client_channel.cc )
@@ -607,22 +687,28 @@
   s.files += %w( src/core/ext/filters/client_channel/lb_policy.cc )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy_factory.cc )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy_registry.cc )
+  s.files += %w( src/core/ext/filters/client_channel/method_params.cc )
   s.files += %w( src/core/ext/filters/client_channel/parse_address.cc )
   s.files += %w( src/core/ext/filters/client_channel/proxy_mapper.cc )
   s.files += %w( src/core/ext/filters/client_channel/proxy_mapper_registry.cc )
   s.files += %w( src/core/ext/filters/client_channel/resolver.cc )
-  s.files += %w( src/core/ext/filters/client_channel/resolver_factory.cc )
   s.files += %w( src/core/ext/filters/client_channel/resolver_registry.cc )
   s.files += %w( src/core/ext/filters/client_channel/retry_throttle.cc )
   s.files += %w( src/core/ext/filters/client_channel/subchannel.cc )
   s.files += %w( src/core/ext/filters/client_channel/subchannel_index.cc )
   s.files += %w( src/core/ext/filters/client_channel/uri_parser.cc )
   s.files += %w( src/core/ext/filters/deadline/deadline_filter.cc )
-  s.files += %w( src/core/ext/transport/chttp2/client/chttp2_connector.cc )
+  s.files += %w( src/core/tsi/alts_transport_security.cc )
+  s.files += %w( src/core/tsi/fake_transport_security.cc )
+  s.files += %w( src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc )
+  s.files += %w( src/core/tsi/ssl/session_cache/ssl_session_cache.cc )
+  s.files += %w( src/core/tsi/ssl/session_cache/ssl_session_openssl.cc )
+  s.files += %w( src/core/tsi/ssl_transport_security.cc )
+  s.files += %w( src/core/tsi/transport_security_grpc.cc )
+  s.files += %w( src/core/ext/transport/chttp2/server/chttp2_server.cc )
+  s.files += %w( src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc )
   s.files += %w( src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc )
   s.files += %w( src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc )
-  s.files += %w( src/core/ext/transport/chttp2/client/insecure/channel_create.cc )
-  s.files += %w( src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc )
   s.files += %w( src/core/ext/transport/inproc/inproc_plugin.cc )
   s.files += %w( src/core/ext/transport/inproc/inproc_transport.cc )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc )
@@ -631,9 +717,6 @@
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c )
-  s.files += %w( third_party/nanopb/pb_common.c )
-  s.files += %w( third_party/nanopb/pb_decode.c )
-  s.files += %w( third_party/nanopb/pb_encode.c )
   s.files += %w( src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc )
@@ -658,23 +741,82 @@
   s.files += %w( third_party/boringssl/crypto/cipher_extra/internal.h )
   s.files += %w( third_party/boringssl/crypto/conf/conf_def.h )
   s.files += %w( third_party/boringssl/crypto/conf/internal.h )
-  s.files += %w( third_party/boringssl/crypto/curve25519/internal.h )
   s.files += %w( third_party/boringssl/crypto/err/internal.h )
   s.files += %w( third_party/boringssl/crypto/evp/internal.h )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/aes/aes.c )
   s.files += %w( third_party/boringssl/crypto/fipsmodule/aes/internal.h )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/aes/key_wrap.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/aes/mode_wrappers.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/bn/add.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/bn/asm/x86_64-gcc.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/bn/bn.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/bn/bytes.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/bn/cmp.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/bn/ctx.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/bn/div.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/bn/exponentiation.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/bn/gcd.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/bn/generic.c )
   s.files += %w( third_party/boringssl/crypto/fipsmodule/bn/internal.h )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/bn/jacobi.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/bn/montgomery.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/bn/montgomery_inv.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/bn/mul.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/bn/prime.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/bn/random.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/bn/rsaz_exp.c )
   s.files += %w( third_party/boringssl/crypto/fipsmodule/bn/rsaz_exp.h )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/bn/shift.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/bn/sqrt.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/cipher/aead.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/cipher/cipher.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/cipher/e_aes.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/cipher/e_des.c )
   s.files += %w( third_party/boringssl/crypto/fipsmodule/cipher/internal.h )
   s.files += %w( third_party/boringssl/crypto/fipsmodule/delocate.h )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/des/des.c )
   s.files += %w( third_party/boringssl/crypto/fipsmodule/des/internal.h )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/digest/digest.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/digest/digests.c )
   s.files += %w( third_party/boringssl/crypto/fipsmodule/digest/internal.h )
   s.files += %w( third_party/boringssl/crypto/fipsmodule/digest/md32_common.h )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/ec/ec.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/ec/ec_key.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/ec/ec_montgomery.c )
   s.files += %w( third_party/boringssl/crypto/fipsmodule/ec/internal.h )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/ec/oct.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/ec/p224-64.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/ec/p256-64.c )
   s.files += %w( third_party/boringssl/crypto/fipsmodule/ec/p256-x86_64-table.h )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/ec/p256-x86_64.c )
   s.files += %w( third_party/boringssl/crypto/fipsmodule/ec/p256-x86_64.h )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/ec/simple.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/ec/util-64.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/ec/wnaf.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/ecdsa/ecdsa.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/hmac/hmac.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/md4/md4.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/md5/md5.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/modes/cbc.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/modes/cfb.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/modes/ctr.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/modes/gcm.c )
   s.files += %w( third_party/boringssl/crypto/fipsmodule/modes/internal.h )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/modes/ofb.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/modes/polyval.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/rand/ctrdrbg.c )
   s.files += %w( third_party/boringssl/crypto/fipsmodule/rand/internal.h )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/rand/rand.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/rand/urandom.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/rsa/blinding.c )
   s.files += %w( third_party/boringssl/crypto/fipsmodule/rsa/internal.h )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/rsa/padding.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/rsa/rsa.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/rsa/rsa_impl.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/sha/sha1-altivec.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/sha/sha1.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/sha/sha256.c )
+  s.files += %w( third_party/boringssl/crypto/fipsmodule/sha/sha512.c )
   s.files += %w( third_party/boringssl/crypto/internal.h )
   s.files += %w( third_party/boringssl/crypto/obj/obj_dat.h )
   s.files += %w( third_party/boringssl/crypto/pkcs7/internal.h )
@@ -760,6 +902,7 @@
   s.files += %w( third_party/boringssl/include/openssl/x509_vfy.h )
   s.files += %w( third_party/boringssl/include/openssl/x509v3.h )
   s.files += %w( third_party/boringssl/ssl/internal.h )
+  s.files += %w( third_party/boringssl/third_party/fiat/internal.h )
   s.files += %w( src/boringssl/err_data.c )
   s.files += %w( third_party/boringssl/crypto/asn1/a_bitstr.c )
   s.files += %w( third_party/boringssl/crypto/asn1/a_bool.c )
@@ -829,7 +972,6 @@
   s.files += %w( third_party/boringssl/crypto/cpu-intel.c )
   s.files += %w( third_party/boringssl/crypto/cpu-ppc64le.c )
   s.files += %w( third_party/boringssl/crypto/crypto.c )
-  s.files += %w( third_party/boringssl/crypto/curve25519/curve25519.c )
   s.files += %w( third_party/boringssl/crypto/curve25519/spake25519.c )
   s.files += %w( third_party/boringssl/crypto/curve25519/x25519-x86_64.c )
   s.files += %w( third_party/boringssl/crypto/dh/check.c )
@@ -1015,6 +1157,7 @@
   s.files += %w( third_party/boringssl/ssl/tls13_server.cc )
   s.files += %w( third_party/boringssl/ssl/tls_method.cc )
   s.files += %w( third_party/boringssl/ssl/tls_record.cc )
+  s.files += %w( third_party/boringssl/third_party/fiat/curve25519.c )
   s.files += %w( third_party/zlib/crc32.h )
   s.files += %w( third_party/zlib/deflate.h )
   s.files += %w( third_party/zlib/gzguts.h )
diff --git a/grpc.gyp b/grpc.gyp
index 63f2eae..36b89f3 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -34,6 +34,7 @@
       'Release': {
         'cflags': [
           '-O2',
+          '-Wframe-larger-than=16384',
         ],
         'defines': [
           'NDEBUG',
@@ -64,11 +65,11 @@
     ],
     'cflags_c': [
       '-Werror',
-      '-std=c99'
+      '-std=c99',
     ],
     'cflags_cc': [
       '-Werror',
-      '-std=c++11'
+      '-std=c++11',
     ],
     'include_dirs': [
       '.',
@@ -148,7 +149,7 @@
             '-Wno-deprecated-declarations',
             '-stdlib=libc++',
             '-std=c++11',
-            '-Wno-error=deprecated-declarations'
+            '-Wno-error=deprecated-declarations',
           ],
         },
       }]
@@ -156,6 +157,28 @@
   },
   'targets': [
     {
+      'target_name': 'address_sorting',
+      'type': 'static_library',
+      'dependencies': [
+      ],
+      'sources': [
+        'third_party/address_sorting/address_sorting.c',
+        'third_party/address_sorting/address_sorting_posix.c',
+        'third_party/address_sorting/address_sorting_windows.c',
+      ],
+    },
+    {
+      'target_name': 'alts_test_util',
+      'type': 'static_library',
+      'dependencies': [
+        'grpc',
+      ],
+      'sources': [
+        'test/core/tsi/alts/crypt/gsec_test_util.cc',
+        'test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.cc',
+      ],
+    },
+    {
       'target_name': 'gpr',
       'type': 'static_library',
       'dependencies': [
@@ -164,8 +187,6 @@
         'src/core/lib/gpr/alloc.cc',
         'src/core/lib/gpr/arena.cc',
         'src/core/lib/gpr/atm.cc',
-        'src/core/lib/gpr/avl.cc',
-        'src/core/lib/gpr/cmdline.cc',
         'src/core/lib/gpr/cpu_iphone.cc',
         'src/core/lib/gpr/cpu_linux.cc',
         'src/core/lib/gpr/cpu_posix.cc',
@@ -186,14 +207,9 @@
         'src/core/lib/gpr/string_posix.cc',
         'src/core/lib/gpr/string_util_windows.cc',
         'src/core/lib/gpr/string_windows.cc',
-        'src/core/lib/gpr/subprocess_posix.cc',
-        'src/core/lib/gpr/subprocess_windows.cc',
         'src/core/lib/gpr/sync.cc',
         'src/core/lib/gpr/sync_posix.cc',
         'src/core/lib/gpr/sync_windows.cc',
-        'src/core/lib/gpr/thd.cc',
-        'src/core/lib/gpr/thd_posix.cc',
-        'src/core/lib/gpr/thd_windows.cc',
         'src/core/lib/gpr/time.cc',
         'src/core/lib/gpr/time_posix.cc',
         'src/core/lib/gpr/time_precise.cc',
@@ -203,6 +219,8 @@
         'src/core/lib/gpr/tmpfile_posix.cc',
         'src/core/lib/gpr/tmpfile_windows.cc',
         'src/core/lib/gpr/wrap_memcpy.cc',
+        'src/core/lib/gprpp/thd_posix.cc',
+        'src/core/lib/gprpp/thd_windows.cc',
         'src/core/lib/profiling/basic_timers.cc',
         'src/core/lib/profiling/stap_timers.cc',
       ],
@@ -225,17 +243,20 @@
       ],
       'sources': [
         'src/core/lib/surface/init.cc',
+        'src/core/lib/avl/avl.cc',
         'src/core/lib/backoff/backoff.cc',
         'src/core/lib/channel/channel_args.cc',
         'src/core/lib/channel/channel_stack.cc',
         'src/core/lib/channel/channel_stack_builder.cc',
+        'src/core/lib/channel/channel_trace.cc',
+        'src/core/lib/channel/channel_trace_registry.cc',
         'src/core/lib/channel/connected_channel.cc',
         'src/core/lib/channel/handshaker.cc',
         'src/core/lib/channel/handshaker_factory.cc',
         'src/core/lib/channel/handshaker_registry.cc',
+        'src/core/lib/channel/status_util.cc',
         'src/core/lib/compression/compression.cc',
         'src/core/lib/compression/compression_internal.cc',
-        'src/core/lib/compression/compression_ruby.cc',
         'src/core/lib/compression/message_compress.cc',
         'src/core/lib/compression/stream_compression.cc',
         'src/core/lib/compression/stream_compression_gzip.cc',
@@ -267,6 +288,8 @@
         'src/core/lib/iomgr/gethostname_sysconf.cc',
         'src/core/lib/iomgr/iocp_windows.cc',
         'src/core/lib/iomgr/iomgr.cc',
+        'src/core/lib/iomgr/iomgr_custom.cc',
+        'src/core/lib/iomgr/iomgr_internal.cc',
         'src/core/lib/iomgr/iomgr_posix.cc',
         'src/core/lib/iomgr/iomgr_uv.cc',
         'src/core/lib/iomgr/iomgr_windows.cc',
@@ -275,12 +298,16 @@
         'src/core/lib/iomgr/lockfree_event.cc',
         'src/core/lib/iomgr/network_status_tracker.cc',
         'src/core/lib/iomgr/polling_entity.cc',
-        'src/core/lib/iomgr/pollset_set_uv.cc',
+        'src/core/lib/iomgr/pollset.cc',
+        'src/core/lib/iomgr/pollset_custom.cc',
+        'src/core/lib/iomgr/pollset_set.cc',
+        'src/core/lib/iomgr/pollset_set_custom.cc',
         'src/core/lib/iomgr/pollset_set_windows.cc',
         'src/core/lib/iomgr/pollset_uv.cc',
         'src/core/lib/iomgr/pollset_windows.cc',
+        'src/core/lib/iomgr/resolve_address.cc',
+        'src/core/lib/iomgr/resolve_address_custom.cc',
         'src/core/lib/iomgr/resolve_address_posix.cc',
-        'src/core/lib/iomgr/resolve_address_uv.cc',
         'src/core/lib/iomgr/resolve_address_windows.cc',
         'src/core/lib/iomgr/resource_quota.cc',
         'src/core/lib/iomgr/sockaddr_utils.cc',
@@ -292,19 +319,24 @@
         'src/core/lib/iomgr/socket_utils_uv.cc',
         'src/core/lib/iomgr/socket_utils_windows.cc',
         'src/core/lib/iomgr/socket_windows.cc',
+        'src/core/lib/iomgr/tcp_client.cc',
+        'src/core/lib/iomgr/tcp_client_custom.cc',
         'src/core/lib/iomgr/tcp_client_posix.cc',
-        'src/core/lib/iomgr/tcp_client_uv.cc',
         'src/core/lib/iomgr/tcp_client_windows.cc',
+        'src/core/lib/iomgr/tcp_custom.cc',
         'src/core/lib/iomgr/tcp_posix.cc',
+        'src/core/lib/iomgr/tcp_server.cc',
+        'src/core/lib/iomgr/tcp_server_custom.cc',
         'src/core/lib/iomgr/tcp_server_posix.cc',
         'src/core/lib/iomgr/tcp_server_utils_posix_common.cc',
         'src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc',
         'src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc',
-        'src/core/lib/iomgr/tcp_server_uv.cc',
         'src/core/lib/iomgr/tcp_server_windows.cc',
         'src/core/lib/iomgr/tcp_uv.cc',
         'src/core/lib/iomgr/tcp_windows.cc',
         'src/core/lib/iomgr/time_averaged_stats.cc',
+        'src/core/lib/iomgr/timer.cc',
+        'src/core/lib/iomgr/timer_custom.cc',
         'src/core/lib/iomgr/timer_generic.cc',
         'src/core/lib/iomgr/timer_heap.cc',
         'src/core/lib/iomgr/timer_manager.cc',
@@ -325,7 +357,6 @@
         'src/core/lib/slice/percent_encoding.cc',
         'src/core/lib/slice/slice.cc',
         'src/core/lib/slice/slice_buffer.cc',
-        'src/core/lib/slice/slice_hash_table.cc',
         'src/core/lib/slice/slice_intern.cc',
         'src/core/lib/slice/slice_string_helpers.cc',
         'src/core/lib/surface/api_trace.cc',
@@ -356,6 +387,7 @@
         'src/core/lib/transport/service_config.cc',
         'src/core/lib/transport/static_metadata.cc',
         'src/core/lib/transport/status_conversion.cc',
+        'src/core/lib/transport/status_metadata.cc',
         'src/core/lib/transport/timeout_encoding.cc',
         'src/core/lib/transport/transport.cc',
         'src/core/lib/transport/transport_op_string.cc',
@@ -390,6 +422,7 @@
         'src/core/ext/filters/http/server/http_server_filter.cc',
         'src/core/lib/http/httpcli_security_connector.cc',
         'src/core/lib/security/context/security_context.cc',
+        'src/core/lib/security/credentials/alts/alts_credentials.cc',
         'src/core/lib/security/credentials/composite/composite_credentials.cc',
         'src/core/lib/security/credentials/credentials.cc',
         'src/core/lib/security/credentials/credentials_metadata.cc',
@@ -403,23 +436,55 @@
         'src/core/lib/security/credentials/oauth2/oauth2_credentials.cc',
         'src/core/lib/security/credentials/plugin/plugin_credentials.cc',
         'src/core/lib/security/credentials/ssl/ssl_credentials.cc',
+        'src/core/lib/security/security_connector/alts_security_connector.cc',
+        'src/core/lib/security/security_connector/security_connector.cc',
         'src/core/lib/security/transport/client_auth_filter.cc',
-        'src/core/lib/security/transport/lb_targets_info.cc',
         'src/core/lib/security/transport/secure_endpoint.cc',
-        'src/core/lib/security/transport/security_connector.cc',
         'src/core/lib/security/transport/security_handshaker.cc',
         'src/core/lib/security/transport/server_auth_filter.cc',
+        'src/core/lib/security/transport/target_authority_table.cc',
         'src/core/lib/security/transport/tsi_error.cc',
         'src/core/lib/security/util/json_util.cc',
         'src/core/lib/surface/init_secure.cc',
-        'src/core/tsi/alts_transport_security.cc',
-        'src/core/tsi/fake_transport_security.cc',
-        'src/core/tsi/ssl_transport_security.cc',
-        'src/core/tsi/transport_security_grpc.cc',
+        'src/core/tsi/alts/crypt/aes_gcm.cc',
+        'src/core/tsi/alts/crypt/gsec.cc',
+        'src/core/tsi/alts/frame_protector/alts_counter.cc',
+        'src/core/tsi/alts/frame_protector/alts_crypter.cc',
+        'src/core/tsi/alts/frame_protector/alts_frame_protector.cc',
+        'src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc',
+        'src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc',
+        'src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc',
+        'src/core/tsi/alts/frame_protector/frame_handler.cc',
+        'src/core/tsi/alts/handshaker/alts_handshaker_client.cc',
+        'src/core/tsi/alts/handshaker/alts_tsi_event.cc',
+        'src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc',
+        'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc',
+        'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc',
+        'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc',
+        'src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc',
+        'src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc',
+        'src/core/lib/security/credentials/alts/check_gcp_environment.cc',
+        'src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc',
+        'src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc',
+        'src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc',
+        'src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc',
+        'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc',
+        'src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc',
+        'src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc',
+        'src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc',
+        'src/core/tsi/alts/handshaker/alts_tsi_utils.cc',
+        'src/core/tsi/alts/handshaker/transport_security_common_api.cc',
+        'src/core/tsi/alts/handshaker/altscontext.pb.c',
+        'src/core/tsi/alts/handshaker/handshaker.pb.c',
+        'src/core/tsi/alts/handshaker/transport_security_common.pb.c',
+        'third_party/nanopb/pb_common.c',
+        'third_party/nanopb/pb_decode.c',
+        'third_party/nanopb/pb_encode.c',
         'src/core/tsi/transport_security.cc',
         'src/core/tsi/transport_security_adapter.cc',
-        'src/core/ext/transport/chttp2/server/chttp2_server.cc',
-        'src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc',
+        'src/core/ext/transport/chttp2/client/insecure/channel_create.cc',
+        'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc',
+        'src/core/ext/transport/chttp2/client/chttp2_connector.cc',
         'src/core/ext/filters/client_channel/backup_poller.cc',
         'src/core/ext/filters/client_channel/channel_connectivity.cc',
         'src/core/ext/filters/client_channel/client_channel.cc',
@@ -431,22 +496,28 @@
         'src/core/ext/filters/client_channel/lb_policy.cc',
         'src/core/ext/filters/client_channel/lb_policy_factory.cc',
         'src/core/ext/filters/client_channel/lb_policy_registry.cc',
+        'src/core/ext/filters/client_channel/method_params.cc',
         'src/core/ext/filters/client_channel/parse_address.cc',
         'src/core/ext/filters/client_channel/proxy_mapper.cc',
         'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
         'src/core/ext/filters/client_channel/resolver.cc',
-        'src/core/ext/filters/client_channel/resolver_factory.cc',
         'src/core/ext/filters/client_channel/resolver_registry.cc',
         'src/core/ext/filters/client_channel/retry_throttle.cc',
         'src/core/ext/filters/client_channel/subchannel.cc',
         'src/core/ext/filters/client_channel/subchannel_index.cc',
         'src/core/ext/filters/client_channel/uri_parser.cc',
         'src/core/ext/filters/deadline/deadline_filter.cc',
-        'src/core/ext/transport/chttp2/client/chttp2_connector.cc',
+        'src/core/tsi/alts_transport_security.cc',
+        'src/core/tsi/fake_transport_security.cc',
+        'src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc',
+        'src/core/tsi/ssl/session_cache/ssl_session_cache.cc',
+        'src/core/tsi/ssl/session_cache/ssl_session_openssl.cc',
+        'src/core/tsi/ssl_transport_security.cc',
+        'src/core/tsi/transport_security_grpc.cc',
+        'src/core/ext/transport/chttp2/server/chttp2_server.cc',
+        'src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc',
         'src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc',
         'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc',
-        'src/core/ext/transport/chttp2/client/insecure/channel_create.cc',
-        'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc',
         'src/core/ext/transport/inproc/inproc_plugin.cc',
         'src/core/ext/transport/inproc/inproc_transport.cc',
         'src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc',
@@ -455,9 +526,6 @@
         'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc',
         'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc',
         'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
-        'third_party/nanopb/pb_common.c',
-        'third_party/nanopb/pb_decode.c',
-        'third_party/nanopb/pb_encode.c',
         'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
         'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
         'src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc',
@@ -518,19 +586,25 @@
         'test/core/util/port_isolated_runtime_environment.cc',
         'test/core/util/port_server_client.cc',
         'test/core/util/slice_splitter.cc',
+        'test/core/util/subprocess_posix.cc',
+        'test/core/util/subprocess_windows.cc',
         'test/core/util/tracer_util.cc',
         'test/core/util/trickle_endpoint.cc',
+        'test/core/util/cmdline.cc',
+        'src/core/lib/avl/avl.cc',
         'src/core/lib/backoff/backoff.cc',
         'src/core/lib/channel/channel_args.cc',
         'src/core/lib/channel/channel_stack.cc',
         'src/core/lib/channel/channel_stack_builder.cc',
+        'src/core/lib/channel/channel_trace.cc',
+        'src/core/lib/channel/channel_trace_registry.cc',
         'src/core/lib/channel/connected_channel.cc',
         'src/core/lib/channel/handshaker.cc',
         'src/core/lib/channel/handshaker_factory.cc',
         'src/core/lib/channel/handshaker_registry.cc',
+        'src/core/lib/channel/status_util.cc',
         'src/core/lib/compression/compression.cc',
         'src/core/lib/compression/compression_internal.cc',
-        'src/core/lib/compression/compression_ruby.cc',
         'src/core/lib/compression/message_compress.cc',
         'src/core/lib/compression/stream_compression.cc',
         'src/core/lib/compression/stream_compression_gzip.cc',
@@ -562,6 +636,8 @@
         'src/core/lib/iomgr/gethostname_sysconf.cc',
         'src/core/lib/iomgr/iocp_windows.cc',
         'src/core/lib/iomgr/iomgr.cc',
+        'src/core/lib/iomgr/iomgr_custom.cc',
+        'src/core/lib/iomgr/iomgr_internal.cc',
         'src/core/lib/iomgr/iomgr_posix.cc',
         'src/core/lib/iomgr/iomgr_uv.cc',
         'src/core/lib/iomgr/iomgr_windows.cc',
@@ -570,12 +646,16 @@
         'src/core/lib/iomgr/lockfree_event.cc',
         'src/core/lib/iomgr/network_status_tracker.cc',
         'src/core/lib/iomgr/polling_entity.cc',
-        'src/core/lib/iomgr/pollset_set_uv.cc',
+        'src/core/lib/iomgr/pollset.cc',
+        'src/core/lib/iomgr/pollset_custom.cc',
+        'src/core/lib/iomgr/pollset_set.cc',
+        'src/core/lib/iomgr/pollset_set_custom.cc',
         'src/core/lib/iomgr/pollset_set_windows.cc',
         'src/core/lib/iomgr/pollset_uv.cc',
         'src/core/lib/iomgr/pollset_windows.cc',
+        'src/core/lib/iomgr/resolve_address.cc',
+        'src/core/lib/iomgr/resolve_address_custom.cc',
         'src/core/lib/iomgr/resolve_address_posix.cc',
-        'src/core/lib/iomgr/resolve_address_uv.cc',
         'src/core/lib/iomgr/resolve_address_windows.cc',
         'src/core/lib/iomgr/resource_quota.cc',
         'src/core/lib/iomgr/sockaddr_utils.cc',
@@ -587,19 +667,24 @@
         'src/core/lib/iomgr/socket_utils_uv.cc',
         'src/core/lib/iomgr/socket_utils_windows.cc',
         'src/core/lib/iomgr/socket_windows.cc',
+        'src/core/lib/iomgr/tcp_client.cc',
+        'src/core/lib/iomgr/tcp_client_custom.cc',
         'src/core/lib/iomgr/tcp_client_posix.cc',
-        'src/core/lib/iomgr/tcp_client_uv.cc',
         'src/core/lib/iomgr/tcp_client_windows.cc',
+        'src/core/lib/iomgr/tcp_custom.cc',
         'src/core/lib/iomgr/tcp_posix.cc',
+        'src/core/lib/iomgr/tcp_server.cc',
+        'src/core/lib/iomgr/tcp_server_custom.cc',
         'src/core/lib/iomgr/tcp_server_posix.cc',
         'src/core/lib/iomgr/tcp_server_utils_posix_common.cc',
         'src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc',
         'src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc',
-        'src/core/lib/iomgr/tcp_server_uv.cc',
         'src/core/lib/iomgr/tcp_server_windows.cc',
         'src/core/lib/iomgr/tcp_uv.cc',
         'src/core/lib/iomgr/tcp_windows.cc',
         'src/core/lib/iomgr/time_averaged_stats.cc',
+        'src/core/lib/iomgr/timer.cc',
+        'src/core/lib/iomgr/timer_custom.cc',
         'src/core/lib/iomgr/timer_generic.cc',
         'src/core/lib/iomgr/timer_heap.cc',
         'src/core/lib/iomgr/timer_manager.cc',
@@ -620,7 +705,6 @@
         'src/core/lib/slice/percent_encoding.cc',
         'src/core/lib/slice/slice.cc',
         'src/core/lib/slice/slice_buffer.cc',
-        'src/core/lib/slice/slice_hash_table.cc',
         'src/core/lib/slice/slice_intern.cc',
         'src/core/lib/slice/slice_string_helpers.cc',
         'src/core/lib/surface/api_trace.cc',
@@ -651,6 +735,7 @@
         'src/core/lib/transport/service_config.cc',
         'src/core/lib/transport/static_metadata.cc',
         'src/core/lib/transport/status_conversion.cc',
+        'src/core/lib/transport/status_metadata.cc',
         'src/core/lib/transport/timeout_encoding.cc',
         'src/core/lib/transport/transport.cc',
         'src/core/lib/transport/transport_op_string.cc',
@@ -666,11 +751,11 @@
         'src/core/ext/filters/client_channel/lb_policy.cc',
         'src/core/ext/filters/client_channel/lb_policy_factory.cc',
         'src/core/ext/filters/client_channel/lb_policy_registry.cc',
+        'src/core/ext/filters/client_channel/method_params.cc',
         'src/core/ext/filters/client_channel/parse_address.cc',
         'src/core/ext/filters/client_channel/proxy_mapper.cc',
         'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
         'src/core/ext/filters/client_channel/resolver.cc',
-        'src/core/ext/filters/client_channel/resolver_factory.cc',
         'src/core/ext/filters/client_channel/resolver_registry.cc',
         'src/core/ext/filters/client_channel/retry_throttle.cc',
         'src/core/ext/filters/client_channel/subchannel.cc',
@@ -731,19 +816,25 @@
         'test/core/util/port_isolated_runtime_environment.cc',
         'test/core/util/port_server_client.cc',
         'test/core/util/slice_splitter.cc',
+        'test/core/util/subprocess_posix.cc',
+        'test/core/util/subprocess_windows.cc',
         'test/core/util/tracer_util.cc',
         'test/core/util/trickle_endpoint.cc',
+        'test/core/util/cmdline.cc',
+        'src/core/lib/avl/avl.cc',
         'src/core/lib/backoff/backoff.cc',
         'src/core/lib/channel/channel_args.cc',
         'src/core/lib/channel/channel_stack.cc',
         'src/core/lib/channel/channel_stack_builder.cc',
+        'src/core/lib/channel/channel_trace.cc',
+        'src/core/lib/channel/channel_trace_registry.cc',
         'src/core/lib/channel/connected_channel.cc',
         'src/core/lib/channel/handshaker.cc',
         'src/core/lib/channel/handshaker_factory.cc',
         'src/core/lib/channel/handshaker_registry.cc',
+        'src/core/lib/channel/status_util.cc',
         'src/core/lib/compression/compression.cc',
         'src/core/lib/compression/compression_internal.cc',
-        'src/core/lib/compression/compression_ruby.cc',
         'src/core/lib/compression/message_compress.cc',
         'src/core/lib/compression/stream_compression.cc',
         'src/core/lib/compression/stream_compression_gzip.cc',
@@ -775,6 +866,8 @@
         'src/core/lib/iomgr/gethostname_sysconf.cc',
         'src/core/lib/iomgr/iocp_windows.cc',
         'src/core/lib/iomgr/iomgr.cc',
+        'src/core/lib/iomgr/iomgr_custom.cc',
+        'src/core/lib/iomgr/iomgr_internal.cc',
         'src/core/lib/iomgr/iomgr_posix.cc',
         'src/core/lib/iomgr/iomgr_uv.cc',
         'src/core/lib/iomgr/iomgr_windows.cc',
@@ -783,12 +876,16 @@
         'src/core/lib/iomgr/lockfree_event.cc',
         'src/core/lib/iomgr/network_status_tracker.cc',
         'src/core/lib/iomgr/polling_entity.cc',
-        'src/core/lib/iomgr/pollset_set_uv.cc',
+        'src/core/lib/iomgr/pollset.cc',
+        'src/core/lib/iomgr/pollset_custom.cc',
+        'src/core/lib/iomgr/pollset_set.cc',
+        'src/core/lib/iomgr/pollset_set_custom.cc',
         'src/core/lib/iomgr/pollset_set_windows.cc',
         'src/core/lib/iomgr/pollset_uv.cc',
         'src/core/lib/iomgr/pollset_windows.cc',
+        'src/core/lib/iomgr/resolve_address.cc',
+        'src/core/lib/iomgr/resolve_address_custom.cc',
         'src/core/lib/iomgr/resolve_address_posix.cc',
-        'src/core/lib/iomgr/resolve_address_uv.cc',
         'src/core/lib/iomgr/resolve_address_windows.cc',
         'src/core/lib/iomgr/resource_quota.cc',
         'src/core/lib/iomgr/sockaddr_utils.cc',
@@ -800,19 +897,24 @@
         'src/core/lib/iomgr/socket_utils_uv.cc',
         'src/core/lib/iomgr/socket_utils_windows.cc',
         'src/core/lib/iomgr/socket_windows.cc',
+        'src/core/lib/iomgr/tcp_client.cc',
+        'src/core/lib/iomgr/tcp_client_custom.cc',
         'src/core/lib/iomgr/tcp_client_posix.cc',
-        'src/core/lib/iomgr/tcp_client_uv.cc',
         'src/core/lib/iomgr/tcp_client_windows.cc',
+        'src/core/lib/iomgr/tcp_custom.cc',
         'src/core/lib/iomgr/tcp_posix.cc',
+        'src/core/lib/iomgr/tcp_server.cc',
+        'src/core/lib/iomgr/tcp_server_custom.cc',
         'src/core/lib/iomgr/tcp_server_posix.cc',
         'src/core/lib/iomgr/tcp_server_utils_posix_common.cc',
         'src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc',
         'src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc',
-        'src/core/lib/iomgr/tcp_server_uv.cc',
         'src/core/lib/iomgr/tcp_server_windows.cc',
         'src/core/lib/iomgr/tcp_uv.cc',
         'src/core/lib/iomgr/tcp_windows.cc',
         'src/core/lib/iomgr/time_averaged_stats.cc',
+        'src/core/lib/iomgr/timer.cc',
+        'src/core/lib/iomgr/timer_custom.cc',
         'src/core/lib/iomgr/timer_generic.cc',
         'src/core/lib/iomgr/timer_heap.cc',
         'src/core/lib/iomgr/timer_manager.cc',
@@ -833,7 +935,6 @@
         'src/core/lib/slice/percent_encoding.cc',
         'src/core/lib/slice/slice.cc',
         'src/core/lib/slice/slice_buffer.cc',
-        'src/core/lib/slice/slice_hash_table.cc',
         'src/core/lib/slice/slice_intern.cc',
         'src/core/lib/slice/slice_string_helpers.cc',
         'src/core/lib/surface/api_trace.cc',
@@ -864,6 +965,7 @@
         'src/core/lib/transport/service_config.cc',
         'src/core/lib/transport/static_metadata.cc',
         'src/core/lib/transport/status_conversion.cc',
+        'src/core/lib/transport/status_metadata.cc',
         'src/core/lib/transport/timeout_encoding.cc',
         'src/core/lib/transport/transport.cc',
         'src/core/lib/transport/transport_op_string.cc',
@@ -879,11 +981,11 @@
         'src/core/ext/filters/client_channel/lb_policy.cc',
         'src/core/ext/filters/client_channel/lb_policy_factory.cc',
         'src/core/ext/filters/client_channel/lb_policy_registry.cc',
+        'src/core/ext/filters/client_channel/method_params.cc',
         'src/core/ext/filters/client_channel/parse_address.cc',
         'src/core/ext/filters/client_channel/proxy_mapper.cc',
         'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
         'src/core/ext/filters/client_channel/resolver.cc',
-        'src/core/ext/filters/client_channel/resolver_factory.cc',
         'src/core/ext/filters/client_channel/resolver_registry.cc',
         'src/core/ext/filters/client_channel/retry_throttle.cc',
         'src/core/ext/filters/client_channel/subchannel.cc',
@@ -928,17 +1030,20 @@
       'sources': [
         'src/core/lib/surface/init.cc',
         'src/core/lib/surface/init_unsecure.cc',
+        'src/core/lib/avl/avl.cc',
         'src/core/lib/backoff/backoff.cc',
         'src/core/lib/channel/channel_args.cc',
         'src/core/lib/channel/channel_stack.cc',
         'src/core/lib/channel/channel_stack_builder.cc',
+        'src/core/lib/channel/channel_trace.cc',
+        'src/core/lib/channel/channel_trace_registry.cc',
         'src/core/lib/channel/connected_channel.cc',
         'src/core/lib/channel/handshaker.cc',
         'src/core/lib/channel/handshaker_factory.cc',
         'src/core/lib/channel/handshaker_registry.cc',
+        'src/core/lib/channel/status_util.cc',
         'src/core/lib/compression/compression.cc',
         'src/core/lib/compression/compression_internal.cc',
-        'src/core/lib/compression/compression_ruby.cc',
         'src/core/lib/compression/message_compress.cc',
         'src/core/lib/compression/stream_compression.cc',
         'src/core/lib/compression/stream_compression_gzip.cc',
@@ -970,6 +1075,8 @@
         'src/core/lib/iomgr/gethostname_sysconf.cc',
         'src/core/lib/iomgr/iocp_windows.cc',
         'src/core/lib/iomgr/iomgr.cc',
+        'src/core/lib/iomgr/iomgr_custom.cc',
+        'src/core/lib/iomgr/iomgr_internal.cc',
         'src/core/lib/iomgr/iomgr_posix.cc',
         'src/core/lib/iomgr/iomgr_uv.cc',
         'src/core/lib/iomgr/iomgr_windows.cc',
@@ -978,12 +1085,16 @@
         'src/core/lib/iomgr/lockfree_event.cc',
         'src/core/lib/iomgr/network_status_tracker.cc',
         'src/core/lib/iomgr/polling_entity.cc',
-        'src/core/lib/iomgr/pollset_set_uv.cc',
+        'src/core/lib/iomgr/pollset.cc',
+        'src/core/lib/iomgr/pollset_custom.cc',
+        'src/core/lib/iomgr/pollset_set.cc',
+        'src/core/lib/iomgr/pollset_set_custom.cc',
         'src/core/lib/iomgr/pollset_set_windows.cc',
         'src/core/lib/iomgr/pollset_uv.cc',
         'src/core/lib/iomgr/pollset_windows.cc',
+        'src/core/lib/iomgr/resolve_address.cc',
+        'src/core/lib/iomgr/resolve_address_custom.cc',
         'src/core/lib/iomgr/resolve_address_posix.cc',
-        'src/core/lib/iomgr/resolve_address_uv.cc',
         'src/core/lib/iomgr/resolve_address_windows.cc',
         'src/core/lib/iomgr/resource_quota.cc',
         'src/core/lib/iomgr/sockaddr_utils.cc',
@@ -995,19 +1106,24 @@
         'src/core/lib/iomgr/socket_utils_uv.cc',
         'src/core/lib/iomgr/socket_utils_windows.cc',
         'src/core/lib/iomgr/socket_windows.cc',
+        'src/core/lib/iomgr/tcp_client.cc',
+        'src/core/lib/iomgr/tcp_client_custom.cc',
         'src/core/lib/iomgr/tcp_client_posix.cc',
-        'src/core/lib/iomgr/tcp_client_uv.cc',
         'src/core/lib/iomgr/tcp_client_windows.cc',
+        'src/core/lib/iomgr/tcp_custom.cc',
         'src/core/lib/iomgr/tcp_posix.cc',
+        'src/core/lib/iomgr/tcp_server.cc',
+        'src/core/lib/iomgr/tcp_server_custom.cc',
         'src/core/lib/iomgr/tcp_server_posix.cc',
         'src/core/lib/iomgr/tcp_server_utils_posix_common.cc',
         'src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc',
         'src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc',
-        'src/core/lib/iomgr/tcp_server_uv.cc',
         'src/core/lib/iomgr/tcp_server_windows.cc',
         'src/core/lib/iomgr/tcp_uv.cc',
         'src/core/lib/iomgr/tcp_windows.cc',
         'src/core/lib/iomgr/time_averaged_stats.cc',
+        'src/core/lib/iomgr/timer.cc',
+        'src/core/lib/iomgr/timer_custom.cc',
         'src/core/lib/iomgr/timer_generic.cc',
         'src/core/lib/iomgr/timer_heap.cc',
         'src/core/lib/iomgr/timer_manager.cc',
@@ -1028,7 +1144,6 @@
         'src/core/lib/slice/percent_encoding.cc',
         'src/core/lib/slice/slice.cc',
         'src/core/lib/slice/slice_buffer.cc',
-        'src/core/lib/slice/slice_hash_table.cc',
         'src/core/lib/slice/slice_intern.cc',
         'src/core/lib/slice/slice_string_helpers.cc',
         'src/core/lib/surface/api_trace.cc',
@@ -1059,6 +1174,7 @@
         'src/core/lib/transport/service_config.cc',
         'src/core/lib/transport/static_metadata.cc',
         'src/core/lib/transport/status_conversion.cc',
+        'src/core/lib/transport/status_metadata.cc',
         'src/core/lib/transport/timeout_encoding.cc',
         'src/core/lib/transport/transport.cc',
         'src/core/lib/transport/transport_op_string.cc',
@@ -1107,11 +1223,11 @@
         'src/core/ext/filters/client_channel/lb_policy.cc',
         'src/core/ext/filters/client_channel/lb_policy_factory.cc',
         'src/core/ext/filters/client_channel/lb_policy_registry.cc',
+        'src/core/ext/filters/client_channel/method_params.cc',
         'src/core/ext/filters/client_channel/parse_address.cc',
         'src/core/ext/filters/client_channel/proxy_mapper.cc',
         'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
         'src/core/ext/filters/client_channel/resolver.cc',
-        'src/core/ext/filters/client_channel/resolver_factory.cc',
         'src/core/ext/filters/client_channel/resolver_registry.cc',
         'src/core/ext/filters/client_channel/retry_throttle.cc',
         'src/core/ext/filters/client_channel/subchannel.cc',
@@ -1294,12 +1410,14 @@
         'grpc',
       ],
       'sources': [
+        'src/proto/grpc/channelz/channelz.proto',
         'src/proto/grpc/health/v1/health.proto',
         'src/proto/grpc/testing/echo_messages.proto',
         'src/proto/grpc/testing/echo.proto',
         'src/proto/grpc/testing/duplicate/echo_duplicate.proto',
         'test/cpp/end2end/test_service_impl.cc',
         'test/cpp/util/byte_buffer_proto_helper.cc',
+        'test/cpp/util/channel_trace_proto_helper.cc',
         'test/cpp/util/create_test_channel.cc',
         'test/cpp/util/string_ref_helper.cc',
         'test/cpp/util/subprocess.cc',
@@ -1631,7 +1749,6 @@
         'third_party/boringssl/crypto/cpu-intel.c',
         'third_party/boringssl/crypto/cpu-ppc64le.c',
         'third_party/boringssl/crypto/crypto.c',
-        'third_party/boringssl/crypto/curve25519/curve25519.c',
         'third_party/boringssl/crypto/curve25519/spake25519.c',
         'third_party/boringssl/crypto/curve25519/x25519-x86_64.c',
         'third_party/boringssl/crypto/dh/check.c',
@@ -1817,6 +1934,7 @@
         'third_party/boringssl/ssl/tls13_server.cc',
         'third_party/boringssl/ssl/tls_method.cc',
         'third_party/boringssl/ssl/tls_record.cc',
+        'third_party/boringssl/third_party/fiat/curve25519.c',
       ],
     },
     {
@@ -1875,6 +1993,17 @@
       ],
     },
     {
+      'target_name': 'boringssl_buf_test_lib',
+      'type': 'static_library',
+      'dependencies': [
+        'boringssl_test_util',
+        'boringssl',
+      ],
+      'sources': [
+        'third_party/boringssl/crypto/buf/buf_test.cc',
+      ],
+    },
+    {
       'target_name': 'boringssl_bytestring_test_lib',
       'type': 'static_library',
       'dependencies': [
@@ -2484,6 +2613,21 @@
         'test/core/end2end/tests/request_with_flags.cc',
         'test/core/end2end/tests/request_with_payload.cc',
         'test/core/end2end/tests/resource_quota_server.cc',
+        'test/core/end2end/tests/retry.cc',
+        'test/core/end2end/tests/retry_cancellation.cc',
+        'test/core/end2end/tests/retry_disabled.cc',
+        'test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc',
+        'test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc',
+        'test/core/end2end/tests/retry_non_retriable_status.cc',
+        'test/core/end2end/tests/retry_recv_initial_metadata.cc',
+        'test/core/end2end/tests/retry_recv_message.cc',
+        'test/core/end2end/tests/retry_server_pushback_delay.cc',
+        'test/core/end2end/tests/retry_server_pushback_disabled.cc',
+        'test/core/end2end/tests/retry_streaming.cc',
+        'test/core/end2end/tests/retry_streaming_after_commit.cc',
+        'test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc',
+        'test/core/end2end/tests/retry_throttled.cc',
+        'test/core/end2end/tests/retry_too_many_attempts.cc',
         'test/core/end2end/tests/server_finishes_request.cc',
         'test/core/end2end/tests/shutdown_finishes_calls.cc',
         'test/core/end2end/tests/shutdown_finishes_tags.cc',
@@ -2557,6 +2701,21 @@
         'test/core/end2end/tests/request_with_flags.cc',
         'test/core/end2end/tests/request_with_payload.cc',
         'test/core/end2end/tests/resource_quota_server.cc',
+        'test/core/end2end/tests/retry.cc',
+        'test/core/end2end/tests/retry_cancellation.cc',
+        'test/core/end2end/tests/retry_disabled.cc',
+        'test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc',
+        'test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc',
+        'test/core/end2end/tests/retry_non_retriable_status.cc',
+        'test/core/end2end/tests/retry_recv_initial_metadata.cc',
+        'test/core/end2end/tests/retry_recv_message.cc',
+        'test/core/end2end/tests/retry_server_pushback_delay.cc',
+        'test/core/end2end/tests/retry_server_pushback_disabled.cc',
+        'test/core/end2end/tests/retry_streaming.cc',
+        'test/core/end2end/tests/retry_streaming_after_commit.cc',
+        'test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc',
+        'test/core/end2end/tests/retry_throttled.cc',
+        'test/core/end2end/tests/retry_too_many_attempts.cc',
         'test/core/end2end/tests/server_finishes_request.cc',
         'test/core/end2end/tests/shutdown_finishes_calls.cc',
         'test/core/end2end/tests/shutdown_finishes_tags.cc',
diff --git a/include/grpc++/alarm.h b/include/grpc++/alarm.h
index 37d4189..dce742e 100644
--- a/include/grpc++/alarm.h
+++ b/include/grpc++/alarm.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,72 +16,13 @@
  *
  */
 
-/// An Alarm posts the user provided tag to its associated completion queue upon
-/// expiry or cancellation.
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_ALARM_H
 #define GRPCXX_ALARM_H
 
-#include <grpc++/impl/codegen/completion_queue.h>
-#include <grpc++/impl/codegen/completion_queue_tag.h>
-#include <grpc++/impl/codegen/grpc_library.h>
-#include <grpc++/impl/codegen/time.h>
-#include <grpc++/impl/grpc_library.h>
-#include <grpc/grpc.h>
-
-namespace grpc {
-
-/// A thin wrapper around \a grpc_alarm (see / \a / src/core/surface/alarm.h).
-class Alarm : private GrpcLibraryCodegen {
- public:
-  /// Create an unset completion queue alarm
-  Alarm();
-
-  /// Destroy the given completion queue alarm, cancelling it in the process.
-  ~Alarm();
-
-  /// DEPRECATED: Create and set a completion queue alarm instance associated to
-  /// \a cq.
-  /// This form is deprecated because it is inherently racy.
-  /// \internal We rely on the presence of \a cq for grpc initialization. If \a
-  /// cq were ever to be removed, a reference to a static
-  /// internal::GrpcLibraryInitializer instance would need to be introduced
-  /// here. \endinternal.
-  template <typename T>
-  Alarm(CompletionQueue* cq, const T& deadline, void* tag) : Alarm() {
-    SetInternal(cq, TimePoint<T>(deadline).raw_time(), tag);
-  }
-
-  /// Trigger an alarm instance on completion queue \a cq at the specified time.
-  /// Once the alarm expires (at \a deadline) or it's cancelled (see \a Cancel),
-  /// an event with tag \a tag will be added to \a cq. If the alarm expired, the
-  /// event's success bit will be true, false otherwise (ie, upon cancellation).
-  template <typename T>
-  void Set(CompletionQueue* cq, const T& deadline, void* tag) {
-    SetInternal(cq, TimePoint<T>(deadline).raw_time(), tag);
-  }
-
-  /// Alarms aren't copyable.
-  Alarm(const Alarm&) = delete;
-  Alarm& operator=(const Alarm&) = delete;
-
-  /// Alarms are movable.
-  Alarm(Alarm&& rhs) : alarm_(rhs.alarm_) { rhs.alarm_ = nullptr; }
-  Alarm& operator=(Alarm&& rhs) {
-    alarm_ = rhs.alarm_;
-    rhs.alarm_ = nullptr;
-    return *this;
-  }
-
-  /// Cancel a completion queue alarm. Calling this function over an alarm that
-  /// has already fired has no effect.
-  void Cancel();
-
- private:
-  void SetInternal(CompletionQueue* cq, gpr_timespec deadline, void* tag);
-
-  internal::CompletionQueueTag* alarm_;
-};
-
-}  // namespace grpc
+#include <grpcpp/alarm.h>
 
 #endif  // GRPCXX_ALARM_H
diff --git a/include/grpc++/channel.h b/include/grpc++/channel.h
index e9fb5a5..b1154ce 100644
--- a/include/grpc++/channel.h
+++ b/include/grpc++/channel.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,63 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_CHANNEL_H
 #define GRPCXX_CHANNEL_H
 
-#include <memory>
-
-#include <grpc++/impl/call.h>
-#include <grpc++/impl/codegen/channel_interface.h>
-#include <grpc++/impl/codegen/config.h>
-#include <grpc++/impl/codegen/grpc_library.h>
-#include <grpc/grpc.h>
-
-struct grpc_channel;
-
-namespace grpc {
-/// Channels represent a connection to an endpoint. Created by \a CreateChannel.
-class Channel final : public ChannelInterface,
-                      public internal::CallHook,
-                      public std::enable_shared_from_this<Channel>,
-                      private GrpcLibraryCodegen {
- public:
-  ~Channel();
-
-  /// Get the current channel state. If the channel is in IDLE and
-  /// \a try_to_connect is set to true, try to connect.
-  grpc_connectivity_state GetState(bool try_to_connect) override;
-
-  /// Returns the LB policy name, or the empty string if not yet available.
-  grpc::string GetLoadBalancingPolicyName() const;
-
-  /// Returns the service config in JSON form, or the empty string if
-  /// not available.
-  grpc::string GetServiceConfigJSON() const;
-
- private:
-  template <class InputMessage, class OutputMessage>
-  friend class internal::BlockingUnaryCallImpl;
-  friend std::shared_ptr<Channel> CreateChannelInternal(
-      const grpc::string& host, grpc_channel* c_channel);
-  Channel(const grpc::string& host, grpc_channel* c_channel);
-
-  internal::Call CreateCall(const internal::RpcMethod& method,
-                            ClientContext* context,
-                            CompletionQueue* cq) override;
-  void PerformOpsOnCall(internal::CallOpSetInterface* ops,
-                        internal::Call* call) override;
-  void* RegisterMethod(const char* method) override;
-
-  void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
-                               gpr_timespec deadline, CompletionQueue* cq,
-                               void* tag) override;
-  bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
-                              gpr_timespec deadline) override;
-
-  const grpc::string host_;
-  grpc_channel* const c_channel_;  // owned
-};
-
-}  // namespace grpc
+#include <grpcpp/channel.h>
 
 #endif  // GRPCXX_CHANNEL_H
diff --git a/include/grpc++/client_context.h b/include/grpc++/client_context.h
index cf42a62..4b23644 100644
--- a/include/grpc++/client_context.h
+++ b/include/grpc++/client_context.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,24 +16,13 @@
  *
  */
 
-/// A ClientContext allows the person implementing a service client to:
-///
-/// - Add custom metadata key-value pairs that will propagated to the server
-/// side.
-/// - Control call settings such as compression and authentication.
-/// - Initial and trailing metadata coming from the server.
-/// - Get performance metrics (ie, census).
-///
-/// Context settings are only relevant to the call they are invoked with, that
-/// is to say, they aren't sticky. Some of these settings, such as the
-/// compression options, can be made persistant at channel construction time
-/// (see \a grpc::CreateCustomChannel).
-///
-/// \warning ClientContext instances should \em not be reused across rpcs.
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
 
 #ifndef GRPCXX_CLIENT_CONTEXT_H
 #define GRPCXX_CLIENT_CONTEXT_H
 
-#include <grpc++/impl/codegen/client_context.h>
+#include <grpcpp/client_context.h>
 
 #endif  // GRPCXX_CLIENT_CONTEXT_H
diff --git a/include/grpc++/completion_queue.h b/include/grpc++/completion_queue.h
index a71123e..98ef18f 100644
--- a/include/grpc++/completion_queue.h
+++ b/include/grpc++/completion_queue.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_COMPLETION_QUEUE_H
 #define GRPCXX_COMPLETION_QUEUE_H
 
-#include <grpc++/impl/codegen/completion_queue.h>
+#include <grpcpp/completion_queue.h>
 
 #endif  // GRPCXX_COMPLETION_QUEUE_H
diff --git a/include/grpc++/create_channel.h b/include/grpc++/create_channel.h
index 7ba1131..d95f3a9 100644
--- a/include/grpc++/create_channel.h
+++ b/include/grpc++/create_channel.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,43 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_CREATE_CHANNEL_H
 #define GRPCXX_CREATE_CHANNEL_H
 
-#include <memory>
-
-#include <grpc++/channel.h>
-#include <grpc++/security/credentials.h>
-#include <grpc++/support/channel_arguments.h>
-#include <grpc++/support/config.h>
-
-namespace grpc {
-
-/// Create a new \a Channel pointing to \a target.
-///
-/// \param target The URI of the endpoint to connect to.
-/// \param creds Credentials to use for the created channel. If it does not
-/// hold an object or is invalid, a lame channel (one on which all operations
-/// fail) is returned.
-std::shared_ptr<Channel> CreateChannel(
-    const grpc::string& target,
-    const std::shared_ptr<ChannelCredentials>& creds);
-
-/// Create a new \em custom \a Channel pointing to \a target.
-///
-/// \warning For advanced use and testing ONLY. Override default channel
-/// arguments only if necessary.
-///
-/// \param target The URI of the endpoint to connect to.
-/// \param creds Credentials to use for the created channel. If it does not
-/// hold an object or is invalid, a lame channel (one on which all operations
-/// fail) is returned.
-/// \param args Options for channel creation.
-std::shared_ptr<Channel> CreateCustomChannel(
-    const grpc::string& target,
-    const std::shared_ptr<ChannelCredentials>& creds,
-    const ChannelArguments& args);
-
-}  // namespace grpc
+#include <grpcpp/create_channel.h>
 
 #endif  // GRPCXX_CREATE_CHANNEL_H
diff --git a/include/grpc++/create_channel_posix.h b/include/grpc++/create_channel_posix.h
index 10f7e4a..8c8983b 100644
--- a/include/grpc++/create_channel_posix.h
+++ b/include/grpc++/create_channel_posix.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,37 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_CREATE_CHANNEL_POSIX_H
 #define GRPCXX_CREATE_CHANNEL_POSIX_H
 
-#include <memory>
-
-#include <grpc++/channel.h>
-#include <grpc++/support/channel_arguments.h>
-#include <grpc/support/port_platform.h>
-
-namespace grpc {
-
-#ifdef GPR_SUPPORT_CHANNELS_FROM_FD
-
-/// Create a new \a Channel communicating over the given file descriptor.
-///
-/// \param target The name of the target.
-/// \param fd The file descriptor representing a socket.
-std::shared_ptr<Channel> CreateInsecureChannelFromFd(const grpc::string& target,
-                                                     int fd);
-
-/// Create a new \a Channel communicating over given file descriptor with custom
-/// channel arguments.
-///
-/// \param target The name of the target.
-/// \param fd The file descriptor representing a socket.
-/// \param args Options for channel creation.
-std::shared_ptr<Channel> CreateCustomInsecureChannelFromFd(
-    const grpc::string& target, int fd, const ChannelArguments& args);
-
-#endif  // GPR_SUPPORT_CHANNELS_FROM_FD
-
-}  // namespace grpc
+#include <grpcpp/create_channel_posix.h>
 
 #endif  // GRPCXX_CREATE_CHANNEL_POSIX_H
diff --git a/include/grpc++/ext/health_check_service_server_builder_option.h b/include/grpc++/ext/health_check_service_server_builder_option.h
index 89af294..cb82fc0 100644
--- a/include/grpc++/ext/health_check_service_server_builder_option.h
+++ b/include/grpc++/ext/health_check_service_server_builder_option.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,32 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_EXT_HEALTH_CHECK_SERVICE_SERVER_BUILDER_OPTION_H
 #define GRPCXX_EXT_HEALTH_CHECK_SERVICE_SERVER_BUILDER_OPTION_H
 
-#include <memory>
-
-#include <grpc++/health_check_service_interface.h>
-#include <grpc++/impl/server_builder_option.h>
-#include <grpc++/support/config.h>
-
-namespace grpc {
-
-class HealthCheckServiceServerBuilderOption : public ServerBuilderOption {
- public:
-  /// The ownership of \a hc will be taken and transferred to the grpc server.
-  /// To explicitly disable default service, pass in a nullptr.
-  explicit HealthCheckServiceServerBuilderOption(
-      std::unique_ptr<HealthCheckServiceInterface> hc);
-  ~HealthCheckServiceServerBuilderOption() override {}
-  void UpdateArguments(ChannelArguments* args) override;
-  void UpdatePlugins(
-      std::vector<std::unique_ptr<ServerBuilderPlugin>>* plugins) override;
-
- private:
-  std::unique_ptr<HealthCheckServiceInterface> hc_;
-};
-
-}  // namespace grpc
+#include <grpcpp/ext/health_check_service_server_builder_option.h>
 
 #endif  // GRPCXX_EXT_HEALTH_CHECK_SERVICE_SERVER_BUILDER_OPTION_H
diff --git a/include/grpc++/ext/proto_server_reflection_plugin.h b/include/grpc++/ext/proto_server_reflection_plugin.h
index ee3fafd..02e21b9 100644
--- a/include/grpc++/ext/proto_server_reflection_plugin.h
+++ b/include/grpc++/ext/proto_server_reflection_plugin.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,39 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_EXT_PROTO_SERVER_REFLECTION_PLUGIN_H
 #define GRPCXX_EXT_PROTO_SERVER_REFLECTION_PLUGIN_H
 
-#include <grpc++/impl/server_builder_plugin.h>
-#include <grpc++/support/config.h>
-
-namespace grpc {
-class ServerInitializer;
-class ProtoServerReflection;
-}  // namespace grpc
-
-namespace grpc {
-namespace reflection {
-
-class ProtoServerReflectionPlugin : public ::grpc::ServerBuilderPlugin {
- public:
-  ProtoServerReflectionPlugin();
-  ::grpc::string name() override;
-  void InitServer(::grpc::ServerInitializer* si) override;
-  void Finish(::grpc::ServerInitializer* si) override;
-  void ChangeArguments(const ::grpc::string& name, void* value) override;
-  bool has_async_methods() const override;
-  bool has_sync_methods() const override;
-
- private:
-  std::shared_ptr<grpc::ProtoServerReflection> reflection_service_;
-};
-
-/// Add proto reflection plugin to \a ServerBuilder.
-/// This function should be called at the static initialization time.
-void InitProtoReflectionServerBuilderPlugin();
-
-}  // namespace reflection
-}  // namespace grpc
+#include <grpcpp/ext/proto_server_reflection_plugin.h>
 
 #endif  // GRPCXX_EXT_PROTO_SERVER_REFLECTION_PLUGIN_H
diff --git a/include/grpc++/generic/async_generic_service.h b/include/grpc++/generic/async_generic_service.h
index b1ea4f3..d3283fa 100644
--- a/include/grpc++/generic/async_generic_service.h
+++ b/include/grpc++/generic/async_generic_service.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,63 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_GENERIC_ASYNC_GENERIC_SERVICE_H
 #define GRPCXX_GENERIC_ASYNC_GENERIC_SERVICE_H
 
-#include <grpc++/support/async_stream.h>
-#include <grpc++/support/byte_buffer.h>
-
-struct grpc_server;
-
-namespace grpc {
-
-typedef ServerAsyncReaderWriter<ByteBuffer, ByteBuffer>
-    GenericServerAsyncReaderWriter;
-
-class GenericServerContext final : public ServerContext {
- public:
-  const grpc::string& method() const { return method_; }
-  const grpc::string& host() const { return host_; }
-
- private:
-  friend class Server;
-  friend class ServerInterface;
-
-  grpc::string method_;
-  grpc::string host_;
-};
-
-// A generic service at the server side accepts all RPC methods and hosts. It is
-// typically used in proxies. The generic service can be registered to a server
-// which also has other services.
-// Sample usage:
-//   ServerBuilder builder;
-//   auto cq = builder.AddCompletionQueue();
-//   AsyncGenericService generic_service;
-//   builder.RegisterAsyncGeneicService(&generic_service);
-//   auto server = builder.BuildAndStart();
-//
-//   // request a new call
-//   GenericServerContext context;
-//   GenericAsyncReaderWriter stream;
-//   generic_service.RequestCall(&context, &stream, cq.get(), cq.get(), tag);
-//
-// When tag is retrieved from cq->Next(), context.method() can be used to look
-// at the method and the RPC can be handled accordingly.
-class AsyncGenericService final {
- public:
-  AsyncGenericService() : server_(nullptr) {}
-
-  void RequestCall(GenericServerContext* ctx,
-                   GenericServerAsyncReaderWriter* reader_writer,
-                   CompletionQueue* call_cq,
-                   ServerCompletionQueue* notification_cq, void* tag);
-
- private:
-  friend class Server;
-  Server* server_;
-};
-
-}  // namespace grpc
+#include <grpcpp/generic/async_generic_service.h>
 
 #endif  // GRPCXX_GENERIC_ASYNC_GENERIC_SERVICE_H
diff --git a/include/grpc++/generic/generic_stub.h b/include/grpc++/generic/generic_stub.h
index d506431..502953b 100644
--- a/include/grpc++/generic/generic_stub.h
+++ b/include/grpc++/generic/generic_stub.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,55 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_GENERIC_GENERIC_STUB_H
 #define GRPCXX_GENERIC_GENERIC_STUB_H
 
-#include <grpc++/support/async_stream.h>
-#include <grpc++/support/async_unary_call.h>
-#include <grpc++/support/byte_buffer.h>
-
-namespace grpc {
-
-class CompletionQueue;
-typedef ClientAsyncReaderWriter<ByteBuffer, ByteBuffer>
-    GenericClientAsyncReaderWriter;
-typedef ClientAsyncResponseReader<ByteBuffer> GenericClientAsyncResponseReader;
-
-/// Generic stubs provide a type-unsafe interface to call gRPC methods
-/// by name.
-class GenericStub final {
- public:
-  explicit GenericStub(std::shared_ptr<ChannelInterface> channel)
-      : channel_(channel) {}
-
-  /// Begin a call to a named method \a method using \a context.
-  /// A tag \a tag will be delivered to \a cq when the call has been started
-  /// (i.e, initial metadata has been sent).
-  /// The return value only indicates whether or not registration of the call
-  /// succeeded (i.e. the call won't proceed if the return value is nullptr).
-  std::unique_ptr<GenericClientAsyncReaderWriter> Call(
-      ClientContext* context, const grpc::string& method, CompletionQueue* cq,
-      void* tag);
-
-  /// Setup a call to a named method \a method using \a context, but don't
-  /// start it. Let it be started explicitly with StartCall and a tag.
-  /// The return value only indicates whether or not registration of the call
-  /// succeeded (i.e. the call won't proceed if the return value is nullptr).
-  std::unique_ptr<GenericClientAsyncReaderWriter> PrepareCall(
-      ClientContext* context, const grpc::string& method, CompletionQueue* cq);
-
-  /// Setup a unary call to a named method \a method using \a context, and don't
-  /// start it. Let it be started explicitly with StartCall.
-  /// The return value only indicates whether or not registration of the call
-  /// succeeded (i.e. the call won't proceed if the return value is nullptr).
-  std::unique_ptr<GenericClientAsyncResponseReader> PrepareUnaryCall(
-      ClientContext* context, const grpc::string& method,
-      const ByteBuffer& request, CompletionQueue* cq);
-
- private:
-  std::shared_ptr<ChannelInterface> channel_;
-};
-
-}  // namespace grpc
+#include <grpcpp/generic/generic_stub.h>
 
 #endif  // GRPCXX_GENERIC_GENERIC_STUB_H
diff --git a/include/grpc++/grpc++.h b/include/grpc++/grpc++.h
index 31ed436..9f1d7b1 100644
--- a/include/grpc++/grpc++.h
+++ b/include/grpc++/grpc++.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,53 +16,13 @@
  *
  */
 
-/// \mainpage gRPC C++ API
-///
-/// The gRPC C++ API mainly consists of the following classes:
-/// <br>
-/// - grpc::Channel, which represents the connection to an endpoint. See [the
-/// gRPC Concepts page](https://grpc.io/docs/guides/concepts.html) for more
-/// details. Channels are created by the factory function grpc::CreateChannel.
-///
-/// - grpc::CompletionQueue, the producer-consumer queue used for all
-/// asynchronous communication with the gRPC runtime.
-///
-/// - grpc::ClientContext and grpc::ServerContext, where optional configuration
-/// for an RPC can be set, such as setting custom metadata to be conveyed to the
-/// peer, compression settings, authentication, etc.
-///
-/// - grpc::Server, representing a gRPC server, created by grpc::ServerBuilder.
-///
-/// Streaming calls are handled with the streaming classes in
-/// \ref sync_stream.h and
-/// \ref async_stream.h.
-///
-/// Refer to the
-/// [examples](https://github.com/grpc/grpc/blob/master/examples/cpp)
-/// for code putting these pieces into play.
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
 
 #ifndef GRPCXX_GRPCXX_H
 #define GRPCXX_GRPCXX_H
 
-// Pragma for http://include-what-you-use.org/ tool, tells that following
-// headers are not private for grpc++.h and are part of its interface.
-// IWYU pragma: begin_exports
-#include <grpc/grpc.h>
-
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/completion_queue.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/create_channel_posix.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
-#include <grpc++/server_posix.h>
-// IWYU pragma: end_exports
-
-namespace grpc {
-/// Return gRPC library version.
-grpc::string Version();
-}  // namespace grpc
+#include <grpcpp/grpcpp.h>
 
 #endif  // GRPCXX_GRPCXX_H
diff --git a/include/grpc++/health_check_service_interface.h b/include/grpc++/health_check_service_interface.h
index 7d4d36a..0cb0668 100644
--- a/include/grpc++/health_check_service_interface.h
+++ b/include/grpc++/health_check_service_interface.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,39 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_HEALTH_CHECK_SERVICE_INTERFACE_H
 #define GRPCXX_HEALTH_CHECK_SERVICE_INTERFACE_H
 
-#include <grpc++/support/config.h>
-
-namespace grpc {
-
-const char kHealthCheckServiceInterfaceArg[] =
-    "grpc.health_check_service_interface";
-
-/// The gRPC server uses this interface to expose the health checking service
-/// without depending on protobuf.
-class HealthCheckServiceInterface {
- public:
-  virtual ~HealthCheckServiceInterface() {}
-
-  /// Set or change the serving status of the given \a service_name.
-  virtual void SetServingStatus(const grpc::string& service_name,
-                                bool serving) = 0;
-  /// Apply to all registered service names.
-  virtual void SetServingStatus(bool serving) = 0;
-};
-
-/// Enable/disable the default health checking service. This applies to all C++
-/// servers created afterwards. For each server, user can override the default
-/// with a HealthCheckServiceServerBuilderOption.
-/// NOT thread safe.
-void EnableDefaultHealthCheckService(bool enable);
-
-/// Returns whether the default health checking service is enabled.
-/// NOT thread safe.
-bool DefaultHealthCheckServiceEnabled();
-
-}  // namespace grpc
+#include <grpcpp/health_check_service_interface.h>
 
 #endif  // GRPCXX_HEALTH_CHECK_SERVICE_INTERFACE_H
diff --git a/include/grpc++/impl/call.h b/include/grpc++/impl/call.h
index fceaa3b..b1da2b6 100644
--- a/include/grpc++/impl/call.h
+++ b/include/grpc++/impl/call.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CALL_H
 #define GRPCXX_IMPL_CALL_H
 
-#include <grpc++/impl/codegen/call.h>
+#include <grpcpp/impl/call.h>
 
 #endif  // GRPCXX_IMPL_CALL_H
diff --git a/include/grpc++/impl/channel_argument_option.h b/include/grpc++/impl/channel_argument_option.h
index f157ec1..3468378 100644
--- a/include/grpc++/impl/channel_argument_option.h
+++ b/include/grpc++/impl/channel_argument_option.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2017 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,22 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CHANNEL_ARGUMENT_OPTION_H
 #define GRPCXX_IMPL_CHANNEL_ARGUMENT_OPTION_H
 
-#include <map>
-#include <memory>
-
-#include <grpc++/impl/server_builder_option.h>
-#include <grpc++/support/channel_arguments.h>
-
-namespace grpc {
-
-std::unique_ptr<ServerBuilderOption> MakeChannelArgumentOption(
-    const grpc::string& name, const grpc::string& value);
-std::unique_ptr<ServerBuilderOption> MakeChannelArgumentOption(
-    const grpc::string& name, int value);
-
-}  // namespace grpc
+#include <grpcpp/impl/channel_argument_option.h>
 
 #endif  // GRPCXX_IMPL_CHANNEL_ARGUMENT_OPTION_H
diff --git a/include/grpc++/impl/client_unary_call.h b/include/grpc++/impl/client_unary_call.h
index d679727..75e6560 100644
--- a/include/grpc++/impl/client_unary_call.h
+++ b/include/grpc++/impl/client_unary_call.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CLIENT_UNARY_CALL_H
 #define GRPCXX_IMPL_CLIENT_UNARY_CALL_H
 
-#include <grpc++/impl/codegen/client_unary_call.h>
+#include <grpcpp/impl/client_unary_call.h>
 
 #endif  // GRPCXX_IMPL_CLIENT_UNARY_CALL_H
diff --git a/include/grpc++/impl/codegen/async_stream.h b/include/grpc++/impl/codegen/async_stream.h
index 4476033..a034470 100644
--- a/include/grpc++/impl/codegen/async_stream.h
+++ b/include/grpc++/impl/codegen/async_stream.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,1053 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_ASYNC_STREAM_H
 #define GRPCXX_IMPL_CODEGEN_ASYNC_STREAM_H
 
-#include <grpc++/impl/codegen/call.h>
-#include <grpc++/impl/codegen/channel_interface.h>
-#include <grpc++/impl/codegen/core_codegen_interface.h>
-#include <grpc++/impl/codegen/server_context.h>
-#include <grpc++/impl/codegen/service_type.h>
-#include <grpc++/impl/codegen/status.h>
-
-namespace grpc {
-
-class CompletionQueue;
-
-namespace internal {
-/// Common interface for all client side asynchronous streaming.
-class ClientAsyncStreamingInterface {
- public:
-  virtual ~ClientAsyncStreamingInterface() {}
-
-  /// Start the call that was set up by the constructor, but only if the
-  /// constructor was invoked through the "Prepare" API which doesn't actually
-  /// start the call
-  virtual void StartCall(void* tag) = 0;
-
-  /// Request notification of the reading of the initial metadata. Completion
-  /// will be notified by \a tag on the associated completion queue.
-  /// This call is optional, but if it is used, it cannot be used concurrently
-  /// with or after the \a AsyncReaderInterface::Read method.
-  ///
-  /// \param[in] tag Tag identifying this request.
-  virtual void ReadInitialMetadata(void* tag) = 0;
-
-  /// Indicate that the stream is to be finished and request notification for
-  /// when the call has been ended.
-  /// Should not be used concurrently with other operations.
-  ///
-  /// It is appropriate to call this method when both:
-  ///   * the client side has no more message to send
-  ///     (this can be declared implicitly by calling this method, or
-  ///     explicitly through an earlier call to the <i>WritesDone</i> method
-  ///     of the class in use, e.g. \a ClientAsyncWriterInterface::WritesDone or
-  ///     \a ClientAsyncReaderWriterInterface::WritesDone).
-  ///   * there are no more messages to be received from the server (this can
-  ///     be known implicitly by the calling code, or explicitly from an
-  ///     earlier call to \a AsyncReaderInterface::Read that yielded a failed
-  ///     result, e.g. cq->Next(&read_tag, &ok) filled in 'ok' with 'false').
-  ///
-  /// This function will return when either:
-  /// - all incoming messages have been read and the server has returned
-  ///   a status.
-  /// - the server has returned a non-OK status.
-  /// - the call failed for some reason and the library generated a
-  ///   status.
-  ///
-  /// Note that implementations of this method attempt to receive initial
-  /// metadata from the server if initial metadata hasn't yet been received.
-  ///
-  /// \param[in] tag Tag identifying this request.
-  /// \param[out] status To be updated with the operation status.
-  virtual void Finish(Status* status, void* tag) = 0;
-};
-
-/// An interface that yields a sequence of messages of type \a R.
-template <class R>
-class AsyncReaderInterface {
- public:
-  virtual ~AsyncReaderInterface() {}
-
-  /// Read a message of type \a R into \a msg. Completion will be notified by \a
-  /// tag on the associated completion queue.
-  /// This is thread-safe with respect to \a Write or \a WritesDone methods. It
-  /// should not be called concurrently with other streaming APIs
-  /// on the same stream. It is not meaningful to call it concurrently
-  /// with another \a AsyncReaderInterface::Read on the same stream since reads
-  /// on the same stream are delivered in order.
-  ///
-  /// \param[out] msg Where to eventually store the read message.
-  /// \param[in] tag The tag identifying the operation.
-  ///
-  /// Side effect: note that this method attempt to receive initial metadata for
-  /// a stream if it hasn't yet been received.
-  virtual void Read(R* msg, void* tag) = 0;
-};
-
-/// An interface that can be fed a sequence of messages of type \a W.
-template <class W>
-class AsyncWriterInterface {
- public:
-  virtual ~AsyncWriterInterface() {}
-
-  /// Request the writing of \a msg with identifying tag \a tag.
-  ///
-  /// Only one write may be outstanding at any given time. This means that
-  /// after calling Write, one must wait to receive \a tag from the completion
-  /// queue BEFORE calling Write again.
-  /// This is thread-safe with respect to \a AsyncReaderInterface::Read
-  ///
-  /// \param[in] msg The message to be written.
-  /// \param[in] tag The tag identifying the operation.
-  virtual void Write(const W& msg, void* tag) = 0;
-
-  /// Request the writing of \a msg using WriteOptions \a options with
-  /// identifying tag \a tag.
-  ///
-  /// Only one write may be outstanding at any given time. This means that
-  /// after calling Write, one must wait to receive \a tag from the completion
-  /// queue BEFORE calling Write again.
-  /// WriteOptions \a options is used to set the write options of this message.
-  /// This is thread-safe with respect to \a AsyncReaderInterface::Read
-  ///
-  /// \param[in] msg The message to be written.
-  /// \param[in] options The WriteOptions to be used to write this message.
-  /// \param[in] tag The tag identifying the operation.
-  virtual void Write(const W& msg, WriteOptions options, void* tag) = 0;
-
-  /// Request the writing of \a msg and coalesce it with the writing
-  /// of trailing metadata, using WriteOptions \a options with
-  /// identifying tag \a tag.
-  ///
-  /// For client, WriteLast is equivalent of performing Write and
-  /// WritesDone in a single step.
-  /// For server, WriteLast buffers the \a msg. The writing of \a msg is held
-  /// until Finish is called, where \a msg and trailing metadata are coalesced
-  /// and write is initiated. Note that WriteLast can only buffer \a msg up to
-  /// the flow control window size. If \a msg size is larger than the window
-  /// size, it will be sent on wire without buffering.
-  ///
-  /// \param[in] msg The message to be written.
-  /// \param[in] options The WriteOptions to be used to write this message.
-  /// \param[in] tag The tag identifying the operation.
-  void WriteLast(const W& msg, WriteOptions options, void* tag) {
-    Write(msg, options.set_last_message(), tag);
-  }
-};
-
-}  // namespace internal
-
-template <class R>
-class ClientAsyncReaderInterface
-    : public internal::ClientAsyncStreamingInterface,
-      public internal::AsyncReaderInterface<R> {};
-
-namespace internal {
-template <class R>
-class ClientAsyncReaderFactory {
- public:
-  /// Create a stream object.
-  /// Write the first request out if \a start is set.
-  /// \a tag will be notified on \a cq when the call has been started and
-  /// \a request has been written out. If \a start is not set, \a tag must be
-  /// nullptr and the actual call must be initiated by StartCall
-  /// Note that \a context will be used to fill in custom initial metadata
-  /// used to send to the server when starting the call.
-  template <class W>
-  static ClientAsyncReader<R>* Create(ChannelInterface* channel,
-                                      CompletionQueue* cq,
-                                      const ::grpc::internal::RpcMethod& method,
-                                      ClientContext* context, const W& request,
-                                      bool start, void* tag) {
-    ::grpc::internal::Call call = channel->CreateCall(method, context, cq);
-    return new (g_core_codegen_interface->grpc_call_arena_alloc(
-        call.call(), sizeof(ClientAsyncReader<R>)))
-        ClientAsyncReader<R>(call, context, request, start, tag);
-  }
-};
-}  // namespace internal
-
-/// Async client-side API for doing server-streaming RPCs,
-/// where the incoming message stream coming from the server has
-/// messages of type \a R.
-template <class R>
-class ClientAsyncReader final : public ClientAsyncReaderInterface<R> {
- public:
-  // always allocated against a call arena, no memory free required
-  static void operator delete(void* ptr, std::size_t size) {
-    assert(size == sizeof(ClientAsyncReader));
-  }
-
-  void StartCall(void* tag) override {
-    assert(!started_);
-    started_ = true;
-    StartCallInternal(tag);
-  }
-
-  /// See the \a ClientAsyncStreamingInterface.ReadInitialMetadata
-  /// method for semantics.
-  ///
-  /// Side effect:
-  ///   - upon receiving initial metadata from the server,
-  ///     the \a ClientContext associated with this call is updated, and the
-  ///     calling code can access the received metadata through the
-  ///     \a ClientContext.
-  void ReadInitialMetadata(void* tag) override {
-    assert(started_);
-    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
-
-    meta_ops_.set_output_tag(tag);
-    meta_ops_.RecvInitialMetadata(context_);
-    call_.PerformOps(&meta_ops_);
-  }
-
-  void Read(R* msg, void* tag) override {
-    assert(started_);
-    read_ops_.set_output_tag(tag);
-    if (!context_->initial_metadata_received_) {
-      read_ops_.RecvInitialMetadata(context_);
-    }
-    read_ops_.RecvMessage(msg);
-    call_.PerformOps(&read_ops_);
-  }
-
-  /// See the \a ClientAsyncStreamingInterface.Finish method for semantics.
-  ///
-  /// Side effect:
-  ///   - the \a ClientContext associated with this call is updated with
-  ///     possible initial and trailing metadata received from the server.
-  void Finish(Status* status, void* tag) override {
-    assert(started_);
-    finish_ops_.set_output_tag(tag);
-    if (!context_->initial_metadata_received_) {
-      finish_ops_.RecvInitialMetadata(context_);
-    }
-    finish_ops_.ClientRecvStatus(context_, status);
-    call_.PerformOps(&finish_ops_);
-  }
-
- private:
-  friend class internal::ClientAsyncReaderFactory<R>;
-  template <class W>
-  ClientAsyncReader(::grpc::internal::Call call, ClientContext* context,
-                    const W& request, bool start, void* tag)
-      : context_(context), call_(call), started_(start) {
-    // TODO(ctiller): don't assert
-    GPR_CODEGEN_ASSERT(init_ops_.SendMessage(request).ok());
-    init_ops_.ClientSendClose();
-    if (start) {
-      StartCallInternal(tag);
-    } else {
-      assert(tag == nullptr);
-    }
-  }
-
-  void StartCallInternal(void* tag) {
-    init_ops_.SendInitialMetadata(context_->send_initial_metadata_,
-                                  context_->initial_metadata_flags());
-    init_ops_.set_output_tag(tag);
-    call_.PerformOps(&init_ops_);
-  }
-
-  ClientContext* context_;
-  ::grpc::internal::Call call_;
-  bool started_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
-                              ::grpc::internal::CallOpSendMessage,
-                              ::grpc::internal::CallOpClientSendClose>
-      init_ops_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
-      meta_ops_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
-                              ::grpc::internal::CallOpRecvMessage<R>>
-      read_ops_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
-                              ::grpc::internal::CallOpClientRecvStatus>
-      finish_ops_;
-};
-
-/// Common interface for client side asynchronous writing.
-template <class W>
-class ClientAsyncWriterInterface
-    : public internal::ClientAsyncStreamingInterface,
-      public internal::AsyncWriterInterface<W> {
- public:
-  /// Signal the client is done with the writes (half-close the client stream).
-  /// Thread-safe with respect to \a AsyncReaderInterface::Read
-  ///
-  /// \param[in] tag The tag identifying the operation.
-  virtual void WritesDone(void* tag) = 0;
-};
-
-namespace internal {
-template <class W>
-class ClientAsyncWriterFactory {
- public:
-  /// Create a stream object.
-  /// Start the RPC if \a start is set
-  /// \a tag will be notified on \a cq when the call has been started (i.e.
-  /// intitial metadata sent) and \a request has been written out.
-  /// If \a start is not set, \a tag must be nullptr and the actual call
-  /// must be initiated by StartCall
-  /// Note that \a context will be used to fill in custom initial metadata
-  /// used to send to the server when starting the call.
-  /// \a response will be filled in with the single expected response
-  /// message from the server upon a successful call to the \a Finish
-  /// method of this instance.
-  template <class R>
-  static ClientAsyncWriter<W>* Create(ChannelInterface* channel,
-                                      CompletionQueue* cq,
-                                      const ::grpc::internal::RpcMethod& method,
-                                      ClientContext* context, R* response,
-                                      bool start, void* tag) {
-    ::grpc::internal::Call call = channel->CreateCall(method, context, cq);
-    return new (g_core_codegen_interface->grpc_call_arena_alloc(
-        call.call(), sizeof(ClientAsyncWriter<W>)))
-        ClientAsyncWriter<W>(call, context, response, start, tag);
-  }
-};
-}  // namespace internal
-
-/// Async API on the client side for doing client-streaming RPCs,
-/// where the outgoing message stream going to the server contains
-/// messages of type \a W.
-template <class W>
-class ClientAsyncWriter final : public ClientAsyncWriterInterface<W> {
- public:
-  // always allocated against a call arena, no memory free required
-  static void operator delete(void* ptr, std::size_t size) {
-    assert(size == sizeof(ClientAsyncWriter));
-  }
-
-  void StartCall(void* tag) override {
-    assert(!started_);
-    started_ = true;
-    StartCallInternal(tag);
-  }
-
-  /// See the \a ClientAsyncStreamingInterface.ReadInitialMetadata method for
-  /// semantics.
-  ///
-  /// Side effect:
-  ///   - upon receiving initial metadata from the server, the \a ClientContext
-  ///     associated with this call is updated, and the calling code can access
-  ///     the received metadata through the \a ClientContext.
-  void ReadInitialMetadata(void* tag) override {
-    assert(started_);
-    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
-
-    meta_ops_.set_output_tag(tag);
-    meta_ops_.RecvInitialMetadata(context_);
-    call_.PerformOps(&meta_ops_);
-  }
-
-  void Write(const W& msg, void* tag) override {
-    assert(started_);
-    write_ops_.set_output_tag(tag);
-    // TODO(ctiller): don't assert
-    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
-    call_.PerformOps(&write_ops_);
-  }
-
-  void Write(const W& msg, WriteOptions options, void* tag) override {
-    assert(started_);
-    write_ops_.set_output_tag(tag);
-    if (options.is_last_message()) {
-      options.set_buffer_hint();
-      write_ops_.ClientSendClose();
-    }
-    // TODO(ctiller): don't assert
-    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
-    call_.PerformOps(&write_ops_);
-  }
-
-  void WritesDone(void* tag) override {
-    assert(started_);
-    write_ops_.set_output_tag(tag);
-    write_ops_.ClientSendClose();
-    call_.PerformOps(&write_ops_);
-  }
-
-  /// See the \a ClientAsyncStreamingInterface.Finish method for semantics.
-  ///
-  /// Side effect:
-  ///   - the \a ClientContext associated with this call is updated with
-  ///     possible initial and trailing metadata received from the server.
-  ///   - attempts to fill in the \a response parameter passed to this class's
-  ///     constructor with the server's response message.
-  void Finish(Status* status, void* tag) override {
-    assert(started_);
-    finish_ops_.set_output_tag(tag);
-    if (!context_->initial_metadata_received_) {
-      finish_ops_.RecvInitialMetadata(context_);
-    }
-    finish_ops_.ClientRecvStatus(context_, status);
-    call_.PerformOps(&finish_ops_);
-  }
-
- private:
-  friend class internal::ClientAsyncWriterFactory<W>;
-  template <class R>
-  ClientAsyncWriter(::grpc::internal::Call call, ClientContext* context,
-                    R* response, bool start, void* tag)
-      : context_(context), call_(call), started_(start) {
-    finish_ops_.RecvMessage(response);
-    finish_ops_.AllowNoMessage();
-    if (start) {
-      StartCallInternal(tag);
-    } else {
-      assert(tag == nullptr);
-    }
-  }
-
-  void StartCallInternal(void* tag) {
-    write_ops_.SendInitialMetadata(context_->send_initial_metadata_,
-                                   context_->initial_metadata_flags());
-    // if corked bit is set in context, we just keep the initial metadata
-    // buffered up to coalesce with later message send. No op is performed.
-    if (!context_->initial_metadata_corked_) {
-      write_ops_.set_output_tag(tag);
-      call_.PerformOps(&write_ops_);
-    }
-  }
-
-  ClientContext* context_;
-  ::grpc::internal::Call call_;
-  bool started_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
-      meta_ops_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
-                              ::grpc::internal::CallOpSendMessage,
-                              ::grpc::internal::CallOpClientSendClose>
-      write_ops_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
-                              ::grpc::internal::CallOpGenericRecvMessage,
-                              ::grpc::internal::CallOpClientRecvStatus>
-      finish_ops_;
-};
-
-/// Async client-side interface for bi-directional streaming,
-/// where the client-to-server message stream has messages of type \a W,
-/// and the server-to-client message stream has messages of type \a R.
-template <class W, class R>
-class ClientAsyncReaderWriterInterface
-    : public internal::ClientAsyncStreamingInterface,
-      public internal::AsyncWriterInterface<W>,
-      public internal::AsyncReaderInterface<R> {
- public:
-  /// Signal the client is done with the writes (half-close the client stream).
-  /// Thread-safe with respect to \a AsyncReaderInterface::Read
-  ///
-  /// \param[in] tag The tag identifying the operation.
-  virtual void WritesDone(void* tag) = 0;
-};
-
-namespace internal {
-template <class W, class R>
-class ClientAsyncReaderWriterFactory {
- public:
-  /// Create a stream object.
-  /// Start the RPC request if \a start is set.
-  /// \a tag will be notified on \a cq when the call has been started (i.e.
-  /// intitial metadata sent). If \a start is not set, \a tag must be
-  /// nullptr and the actual call must be initiated by StartCall
-  /// Note that \a context will be used to fill in custom initial metadata
-  /// used to send to the server when starting the call.
-  static ClientAsyncReaderWriter<W, R>* Create(
-      ChannelInterface* channel, CompletionQueue* cq,
-      const ::grpc::internal::RpcMethod& method, ClientContext* context,
-      bool start, void* tag) {
-    ::grpc::internal::Call call = channel->CreateCall(method, context, cq);
-
-    return new (g_core_codegen_interface->grpc_call_arena_alloc(
-        call.call(), sizeof(ClientAsyncReaderWriter<W, R>)))
-        ClientAsyncReaderWriter<W, R>(call, context, start, tag);
-  }
-};
-}  // namespace internal
-
-/// Async client-side interface for bi-directional streaming,
-/// where the outgoing message stream going to the server
-/// has messages of type \a W,  and the incoming message stream coming
-/// from the server has messages of type \a R.
-template <class W, class R>
-class ClientAsyncReaderWriter final
-    : public ClientAsyncReaderWriterInterface<W, R> {
- public:
-  // always allocated against a call arena, no memory free required
-  static void operator delete(void* ptr, std::size_t size) {
-    assert(size == sizeof(ClientAsyncReaderWriter));
-  }
-
-  void StartCall(void* tag) override {
-    assert(!started_);
-    started_ = true;
-    StartCallInternal(tag);
-  }
-
-  /// See the \a ClientAsyncStreamingInterface.ReadInitialMetadata method
-  /// for semantics of this method.
-  ///
-  /// Side effect:
-  ///   - upon receiving initial metadata from the server, the \a ClientContext
-  ///     is updated with it, and then the receiving initial metadata can
-  ///     be accessed through this \a ClientContext.
-  void ReadInitialMetadata(void* tag) override {
-    assert(started_);
-    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
-
-    meta_ops_.set_output_tag(tag);
-    meta_ops_.RecvInitialMetadata(context_);
-    call_.PerformOps(&meta_ops_);
-  }
-
-  void Read(R* msg, void* tag) override {
-    assert(started_);
-    read_ops_.set_output_tag(tag);
-    if (!context_->initial_metadata_received_) {
-      read_ops_.RecvInitialMetadata(context_);
-    }
-    read_ops_.RecvMessage(msg);
-    call_.PerformOps(&read_ops_);
-  }
-
-  void Write(const W& msg, void* tag) override {
-    assert(started_);
-    write_ops_.set_output_tag(tag);
-    // TODO(ctiller): don't assert
-    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
-    call_.PerformOps(&write_ops_);
-  }
-
-  void Write(const W& msg, WriteOptions options, void* tag) override {
-    assert(started_);
-    write_ops_.set_output_tag(tag);
-    if (options.is_last_message()) {
-      options.set_buffer_hint();
-      write_ops_.ClientSendClose();
-    }
-    // TODO(ctiller): don't assert
-    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
-    call_.PerformOps(&write_ops_);
-  }
-
-  void WritesDone(void* tag) override {
-    assert(started_);
-    write_ops_.set_output_tag(tag);
-    write_ops_.ClientSendClose();
-    call_.PerformOps(&write_ops_);
-  }
-
-  /// See the \a ClientAsyncStreamingInterface.Finish method for semantics.
-  /// Side effect
-  ///   - the \a ClientContext associated with this call is updated with
-  ///     possible initial and trailing metadata sent from the server.
-  void Finish(Status* status, void* tag) override {
-    assert(started_);
-    finish_ops_.set_output_tag(tag);
-    if (!context_->initial_metadata_received_) {
-      finish_ops_.RecvInitialMetadata(context_);
-    }
-    finish_ops_.ClientRecvStatus(context_, status);
-    call_.PerformOps(&finish_ops_);
-  }
-
- private:
-  friend class internal::ClientAsyncReaderWriterFactory<W, R>;
-  ClientAsyncReaderWriter(::grpc::internal::Call call, ClientContext* context,
-                          bool start, void* tag)
-      : context_(context), call_(call), started_(start) {
-    if (start) {
-      StartCallInternal(tag);
-    } else {
-      assert(tag == nullptr);
-    }
-  }
-
-  void StartCallInternal(void* tag) {
-    write_ops_.SendInitialMetadata(context_->send_initial_metadata_,
-                                   context_->initial_metadata_flags());
-    // if corked bit is set in context, we just keep the initial metadata
-    // buffered up to coalesce with later message send. No op is performed.
-    if (!context_->initial_metadata_corked_) {
-      write_ops_.set_output_tag(tag);
-      call_.PerformOps(&write_ops_);
-    }
-  }
-
-  ClientContext* context_;
-  ::grpc::internal::Call call_;
-  bool started_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
-      meta_ops_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
-                              ::grpc::internal::CallOpRecvMessage<R>>
-      read_ops_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
-                              ::grpc::internal::CallOpSendMessage,
-                              ::grpc::internal::CallOpClientSendClose>
-      write_ops_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
-                              ::grpc::internal::CallOpClientRecvStatus>
-      finish_ops_;
-};
-
-template <class W, class R>
-class ServerAsyncReaderInterface
-    : public internal::ServerAsyncStreamingInterface,
-      public internal::AsyncReaderInterface<R> {
- public:
-  /// Indicate that the stream is to be finished with a certain status code
-  /// and also send out \a msg response to the client.
-  /// Request notification for when the server has sent the response and the
-  /// appropriate signals to the client to end the call.
-  /// Should not be used concurrently with other operations.
-  ///
-  /// It is appropriate to call this method when:
-  ///   * all messages from the client have been received (either known
-  ///     implictly, or explicitly because a previous
-  ///     \a AsyncReaderInterface::Read operation with a non-ok result,
-  ///     e.g., cq->Next(&read_tag, &ok) filled in 'ok' with 'false').
-  ///
-  /// This operation will end when the server has finished sending out initial
-  /// metadata (if not sent already), response message, and status, or if
-  /// some failure occurred when trying to do so.
-  ///
-  /// \param[in] tag Tag identifying this request.
-  /// \param[in] status To be sent to the client as the result of this call.
-  /// \param[in] msg To be sent to the client as the response for this call.
-  virtual void Finish(const W& msg, const Status& status, void* tag) = 0;
-
-  /// Indicate that the stream is to be finished with a certain
-  /// non-OK status code.
-  /// Request notification for when the server has sent the appropriate
-  /// signals to the client to end the call.
-  /// Should not be used concurrently with other operations.
-  ///
-  /// This call is meant to end the call with some error, and can be called at
-  /// any point that the server would like to "fail" the call (though note
-  /// this shouldn't be called concurrently with any other "sending" call, like
-  /// \a AsyncWriterInterface::Write).
-  ///
-  /// This operation will end when the server has finished sending out initial
-  /// metadata (if not sent already), and status, or if some failure occurred
-  /// when trying to do so.
-  ///
-  /// \param[in] tag Tag identifying this request.
-  /// \param[in] status To be sent to the client as the result of this call.
-  ///     - Note: \a status must have a non-OK code.
-  virtual void FinishWithError(const Status& status, void* tag) = 0;
-};
-
-/// Async server-side API for doing client-streaming RPCs,
-/// where the incoming message stream from the client has messages of type \a R,
-/// and the single response message sent from the server is type \a W.
-template <class W, class R>
-class ServerAsyncReader final : public ServerAsyncReaderInterface<W, R> {
- public:
-  explicit ServerAsyncReader(ServerContext* ctx)
-      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
-
-  /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics.
-  ///
-  /// Implicit input parameter:
-  ///   - The initial metadata that will be sent to the client from this op will
-  ///     be taken from the \a ServerContext associated with the call.
-  void SendInitialMetadata(void* tag) override {
-    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
-
-    meta_ops_.set_output_tag(tag);
-    meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
-                                  ctx_->initial_metadata_flags());
-    if (ctx_->compression_level_set()) {
-      meta_ops_.set_compression_level(ctx_->compression_level());
-    }
-    ctx_->sent_initial_metadata_ = true;
-    call_.PerformOps(&meta_ops_);
-  }
-
-  void Read(R* msg, void* tag) override {
-    read_ops_.set_output_tag(tag);
-    read_ops_.RecvMessage(msg);
-    call_.PerformOps(&read_ops_);
-  }
-
-  /// See the \a ServerAsyncReaderInterface.Read method for semantics
-  ///
-  /// Side effect:
-  ///   - also sends initial metadata if not alreay sent.
-  ///   - uses the \a ServerContext associated with this call to send possible
-  ///     initial and trailing metadata.
-  ///
-  /// Note: \a msg is not sent if \a status has a non-OK code.
-  void Finish(const W& msg, const Status& status, void* tag) override {
-    finish_ops_.set_output_tag(tag);
-    if (!ctx_->sent_initial_metadata_) {
-      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
-                                      ctx_->initial_metadata_flags());
-      if (ctx_->compression_level_set()) {
-        finish_ops_.set_compression_level(ctx_->compression_level());
-      }
-      ctx_->sent_initial_metadata_ = true;
-    }
-    // The response is dropped if the status is not OK.
-    if (status.ok()) {
-      finish_ops_.ServerSendStatus(ctx_->trailing_metadata_,
-                                   finish_ops_.SendMessage(msg));
-    } else {
-      finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
-    }
-    call_.PerformOps(&finish_ops_);
-  }
-
-  /// See the \a ServerAsyncReaderInterface.Read method for semantics
-  ///
-  /// Side effect:
-  ///   - also sends initial metadata if not alreay sent.
-  ///   - uses the \a ServerContext associated with this call to send possible
-  ///     initial and trailing metadata.
-  void FinishWithError(const Status& status, void* tag) override {
-    GPR_CODEGEN_ASSERT(!status.ok());
-    finish_ops_.set_output_tag(tag);
-    if (!ctx_->sent_initial_metadata_) {
-      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
-                                      ctx_->initial_metadata_flags());
-      if (ctx_->compression_level_set()) {
-        finish_ops_.set_compression_level(ctx_->compression_level());
-      }
-      ctx_->sent_initial_metadata_ = true;
-    }
-    finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
-    call_.PerformOps(&finish_ops_);
-  }
-
- private:
-  void BindCall(::grpc::internal::Call* call) override { call_ = *call; }
-
-  ::grpc::internal::Call call_;
-  ServerContext* ctx_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
-      meta_ops_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage<R>> read_ops_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
-                              ::grpc::internal::CallOpSendMessage,
-                              ::grpc::internal::CallOpServerSendStatus>
-      finish_ops_;
-};
-
-template <class W>
-class ServerAsyncWriterInterface
-    : public internal::ServerAsyncStreamingInterface,
-      public internal::AsyncWriterInterface<W> {
- public:
-  /// Indicate that the stream is to be finished with a certain status code.
-  /// Request notification for when the server has sent the appropriate
-  /// signals to the client to end the call.
-  /// Should not be used concurrently with other operations.
-  ///
-  /// It is appropriate to call this method when either:
-  ///   * all messages from the client have been received (either known
-  ///     implictly, or explicitly because a previous \a
-  ///     AsyncReaderInterface::Read operation with a non-ok
-  ///     result (e.g., cq->Next(&read_tag, &ok) filled in 'ok' with 'false'.
-  ///   * it is desired to end the call early with some non-OK status code.
-  ///
-  /// This operation will end when the server has finished sending out initial
-  /// metadata (if not sent already), response message, and status, or if
-  /// some failure occurred when trying to do so.
-  ///
-  /// \param[in] tag Tag identifying this request.
-  /// \param[in] status To be sent to the client as the result of this call.
-  virtual void Finish(const Status& status, void* tag) = 0;
-
-  /// Request the writing of \a msg and coalesce it with trailing metadata which
-  /// contains \a status, using WriteOptions options with
-  /// identifying tag \a tag.
-  ///
-  /// WriteAndFinish is equivalent of performing WriteLast and Finish
-  /// in a single step.
-  ///
-  /// \param[in] msg The message to be written.
-  /// \param[in] options The WriteOptions to be used to write this message.
-  /// \param[in] status The Status that server returns to client.
-  /// \param[in] tag The tag identifying the operation.
-  virtual void WriteAndFinish(const W& msg, WriteOptions options,
-                              const Status& status, void* tag) = 0;
-};
-
-/// Async server-side API for doing server streaming RPCs,
-/// where the outgoing message stream from the server has messages of type \a W.
-template <class W>
-class ServerAsyncWriter final : public ServerAsyncWriterInterface<W> {
- public:
-  explicit ServerAsyncWriter(ServerContext* ctx)
-      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
-
-  /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics.
-  ///
-  /// Implicit input parameter:
-  ///   - The initial metadata that will be sent to the client from this op will
-  ///     be taken from the \a ServerContext associated with the call.
-  ///
-  /// \param[in] tag Tag identifying this request.
-  void SendInitialMetadata(void* tag) override {
-    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
-
-    meta_ops_.set_output_tag(tag);
-    meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
-                                  ctx_->initial_metadata_flags());
-    if (ctx_->compression_level_set()) {
-      meta_ops_.set_compression_level(ctx_->compression_level());
-    }
-    ctx_->sent_initial_metadata_ = true;
-    call_.PerformOps(&meta_ops_);
-  }
-
-  void Write(const W& msg, void* tag) override {
-    write_ops_.set_output_tag(tag);
-    EnsureInitialMetadataSent(&write_ops_);
-    // TODO(ctiller): don't assert
-    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
-    call_.PerformOps(&write_ops_);
-  }
-
-  void Write(const W& msg, WriteOptions options, void* tag) override {
-    write_ops_.set_output_tag(tag);
-    if (options.is_last_message()) {
-      options.set_buffer_hint();
-    }
-
-    EnsureInitialMetadataSent(&write_ops_);
-    // TODO(ctiller): don't assert
-    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
-    call_.PerformOps(&write_ops_);
-  }
-
-  /// See the \a ServerAsyncWriterInterface.WriteAndFinish method for semantics.
-  ///
-  /// Implicit input parameter:
-  ///   - the \a ServerContext associated with this call is used
-  ///     for sending trailing (and initial) metadata to the client.
-  ///
-  /// Note: \a status must have an OK code.
-  void WriteAndFinish(const W& msg, WriteOptions options, const Status& status,
-                      void* tag) override {
-    write_ops_.set_output_tag(tag);
-    EnsureInitialMetadataSent(&write_ops_);
-    options.set_buffer_hint();
-    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
-    write_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
-    call_.PerformOps(&write_ops_);
-  }
-
-  /// See the \a ServerAsyncWriterInterface.Finish method for semantics.
-  ///
-  /// Implicit input parameter:
-  ///   - the \a ServerContext associated with this call is used for sending
-  ///     trailing (and initial if not already sent) metadata to the client.
-  ///
-  /// Note: there are no restrictions are the code of
-  /// \a status,it may be non-OK
-  void Finish(const Status& status, void* tag) override {
-    finish_ops_.set_output_tag(tag);
-    EnsureInitialMetadataSent(&finish_ops_);
-    finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
-    call_.PerformOps(&finish_ops_);
-  }
-
- private:
-  void BindCall(::grpc::internal::Call* call) override { call_ = *call; }
-
-  template <class T>
-  void EnsureInitialMetadataSent(T* ops) {
-    if (!ctx_->sent_initial_metadata_) {
-      ops->SendInitialMetadata(ctx_->initial_metadata_,
-                               ctx_->initial_metadata_flags());
-      if (ctx_->compression_level_set()) {
-        ops->set_compression_level(ctx_->compression_level());
-      }
-      ctx_->sent_initial_metadata_ = true;
-    }
-  }
-
-  ::grpc::internal::Call call_;
-  ServerContext* ctx_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
-      meta_ops_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
-                              ::grpc::internal::CallOpSendMessage,
-                              ::grpc::internal::CallOpServerSendStatus>
-      write_ops_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
-                              ::grpc::internal::CallOpServerSendStatus>
-      finish_ops_;
-};
-
-/// Server-side interface for asynchronous bi-directional streaming.
-template <class W, class R>
-class ServerAsyncReaderWriterInterface
-    : public internal::ServerAsyncStreamingInterface,
-      public internal::AsyncWriterInterface<W>,
-      public internal::AsyncReaderInterface<R> {
- public:
-  /// Indicate that the stream is to be finished with a certain status code.
-  /// Request notification for when the server has sent the appropriate
-  /// signals to the client to end the call.
-  /// Should not be used concurrently with other operations.
-  ///
-  /// It is appropriate to call this method when either:
-  ///   * all messages from the client have been received (either known
-  ///     implictly, or explicitly because a previous \a
-  ///     AsyncReaderInterface::Read operation
-  ///     with a non-ok result (e.g., cq->Next(&read_tag, &ok) filled in 'ok'
-  ///     with 'false'.
-  ///   * it is desired to end the call early with some non-OK status code.
-  ///
-  /// This operation will end when the server has finished sending out initial
-  /// metadata (if not sent already), response message, and status, or if some
-  /// failure occurred when trying to do so.
-  ///
-  /// \param[in] tag Tag identifying this request.
-  /// \param[in] status To be sent to the client as the result of this call.
-  virtual void Finish(const Status& status, void* tag) = 0;
-
-  /// Request the writing of \a msg and coalesce it with trailing metadata which
-  /// contains \a status, using WriteOptions options with
-  /// identifying tag \a tag.
-  ///
-  /// WriteAndFinish is equivalent of performing WriteLast and Finish in a
-  /// single step.
-  ///
-  /// \param[in] msg The message to be written.
-  /// \param[in] options The WriteOptions to be used to write this message.
-  /// \param[in] status The Status that server returns to client.
-  /// \param[in] tag The tag identifying the operation.
-  virtual void WriteAndFinish(const W& msg, WriteOptions options,
-                              const Status& status, void* tag) = 0;
-};
-
-/// Async server-side API for doing bidirectional streaming RPCs,
-/// where the incoming message stream coming from the client has messages of
-/// type \a R, and the outgoing message stream coming from the server has
-/// messages of type \a W.
-template <class W, class R>
-class ServerAsyncReaderWriter final
-    : public ServerAsyncReaderWriterInterface<W, R> {
- public:
-  explicit ServerAsyncReaderWriter(ServerContext* ctx)
-      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
-
-  /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics.
-  ///
-  /// Implicit input parameter:
-  ///   - The initial metadata that will be sent to the client from this op will
-  ///     be taken from the \a ServerContext associated with the call.
-  ///
-  /// \param[in] tag Tag identifying this request.
-  void SendInitialMetadata(void* tag) override {
-    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
-
-    meta_ops_.set_output_tag(tag);
-    meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
-                                  ctx_->initial_metadata_flags());
-    if (ctx_->compression_level_set()) {
-      meta_ops_.set_compression_level(ctx_->compression_level());
-    }
-    ctx_->sent_initial_metadata_ = true;
-    call_.PerformOps(&meta_ops_);
-  }
-
-  void Read(R* msg, void* tag) override {
-    read_ops_.set_output_tag(tag);
-    read_ops_.RecvMessage(msg);
-    call_.PerformOps(&read_ops_);
-  }
-
-  void Write(const W& msg, void* tag) override {
-    write_ops_.set_output_tag(tag);
-    EnsureInitialMetadataSent(&write_ops_);
-    // TODO(ctiller): don't assert
-    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
-    call_.PerformOps(&write_ops_);
-  }
-
-  void Write(const W& msg, WriteOptions options, void* tag) override {
-    write_ops_.set_output_tag(tag);
-    if (options.is_last_message()) {
-      options.set_buffer_hint();
-    }
-    EnsureInitialMetadataSent(&write_ops_);
-    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
-    call_.PerformOps(&write_ops_);
-  }
-
-  /// See the \a ServerAsyncReaderWriterInterface.WriteAndFinish
-  /// method for semantics.
-  ///
-  /// Implicit input parameter:
-  ///   - the \a ServerContext associated with this call is used
-  ///     for sending trailing (and initial) metadata to the client.
-  ///
-  /// Note: \a status must have an OK code.
-  void WriteAndFinish(const W& msg, WriteOptions options, const Status& status,
-                      void* tag) override {
-    write_ops_.set_output_tag(tag);
-    EnsureInitialMetadataSent(&write_ops_);
-    options.set_buffer_hint();
-    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
-    write_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
-    call_.PerformOps(&write_ops_);
-  }
-
-  /// See the \a ServerAsyncReaderWriterInterface.Finish method for semantics.
-  ///
-  /// Implicit input parameter:
-  ///   - the \a ServerContext associated with this call is used for sending
-  ///     trailing (and initial if not already sent) metadata to the client.
-  ///
-  /// Note: there are no restrictions are the code of \a status,
-  /// it may be non-OK
-  void Finish(const Status& status, void* tag) override {
-    finish_ops_.set_output_tag(tag);
-    EnsureInitialMetadataSent(&finish_ops_);
-
-    finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
-    call_.PerformOps(&finish_ops_);
-  }
-
- private:
-  friend class ::grpc::Server;
-
-  void BindCall(::grpc::internal::Call* call) override { call_ = *call; }
-
-  template <class T>
-  void EnsureInitialMetadataSent(T* ops) {
-    if (!ctx_->sent_initial_metadata_) {
-      ops->SendInitialMetadata(ctx_->initial_metadata_,
-                               ctx_->initial_metadata_flags());
-      if (ctx_->compression_level_set()) {
-        ops->set_compression_level(ctx_->compression_level());
-      }
-      ctx_->sent_initial_metadata_ = true;
-    }
-  }
-
-  ::grpc::internal::Call call_;
-  ServerContext* ctx_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
-      meta_ops_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage<R>> read_ops_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
-                              ::grpc::internal::CallOpSendMessage,
-                              ::grpc::internal::CallOpServerSendStatus>
-      write_ops_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
-                              ::grpc::internal::CallOpServerSendStatus>
-      finish_ops_;
-};
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/async_stream.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_ASYNC_STREAM_H
diff --git a/include/grpc++/impl/codegen/async_unary_call.h b/include/grpc++/impl/codegen/async_unary_call.h
index fb57300..2b08920 100644
--- a/include/grpc++/impl/codegen/async_unary_call.h
+++ b/include/grpc++/impl/codegen/async_unary_call.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,294 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_ASYNC_UNARY_CALL_H
 #define GRPCXX_IMPL_CODEGEN_ASYNC_UNARY_CALL_H
 
-#include <assert.h>
-#include <grpc++/impl/codegen/call.h>
-#include <grpc++/impl/codegen/channel_interface.h>
-#include <grpc++/impl/codegen/client_context.h>
-#include <grpc++/impl/codegen/server_context.h>
-#include <grpc++/impl/codegen/service_type.h>
-#include <grpc++/impl/codegen/status.h>
-
-namespace grpc {
-
-class CompletionQueue;
-extern CoreCodegenInterface* g_core_codegen_interface;
-
-/// An interface relevant for async client side unary RPCs (which send
-/// one request message to a server and receive one response message).
-template <class R>
-class ClientAsyncResponseReaderInterface {
- public:
-  virtual ~ClientAsyncResponseReaderInterface() {}
-
-  /// Start the call that was set up by the constructor, but only if the
-  /// constructor was invoked through the "Prepare" API which doesn't actually
-  /// start the call
-  virtual void StartCall() = 0;
-
-  /// Request notification of the reading of initial metadata. Completion
-  /// will be notified by \a tag on the associated completion queue.
-  /// This call is optional, but if it is used, it cannot be used concurrently
-  /// with or after the \a Finish method.
-  ///
-  /// \param[in] tag Tag identifying this request.
-  virtual void ReadInitialMetadata(void* tag) = 0;
-
-  /// Request to receive the server's response \a msg and final \a status for
-  /// the call, and to notify \a tag on this call's completion queue when
-  /// finished.
-  ///
-  /// This function will return when either:
-  /// - when the server's response message and status have been received.
-  /// - when the server has returned a non-OK status (no message expected in
-  ///   this case).
-  /// - when the call failed for some reason and the library generated a
-  ///   non-OK status.
-  ///
-  /// \param[in] tag Tag identifying this request.
-  /// \param[out] status To be updated with the operation status.
-  /// \param[out] msg To be filled in with the server's response message.
-  virtual void Finish(R* msg, Status* status, void* tag) = 0;
-};
-
-namespace internal {
-template <class R>
-class ClientAsyncResponseReaderFactory {
- public:
-  /// Start a call and write the request out if \a start is set.
-  /// \a tag will be notified on \a cq when the call has been started (i.e.
-  /// intitial metadata sent) and \a request has been written out.
-  /// If \a start is not set, the actual call must be initiated by StartCall
-  /// Note that \a context will be used to fill in custom initial metadata
-  /// used to send to the server when starting the call.
-  template <class W>
-  static ClientAsyncResponseReader<R>* Create(
-      ChannelInterface* channel, CompletionQueue* cq,
-      const ::grpc::internal::RpcMethod& method, ClientContext* context,
-      const W& request, bool start) {
-    ::grpc::internal::Call call = channel->CreateCall(method, context, cq);
-    return new (g_core_codegen_interface->grpc_call_arena_alloc(
-        call.call(), sizeof(ClientAsyncResponseReader<R>)))
-        ClientAsyncResponseReader<R>(call, context, request, start);
-  }
-};
-}  // namespace internal
-
-/// Async API for client-side unary RPCs, where the message response
-/// received from the server is of type \a R.
-template <class R>
-class ClientAsyncResponseReader final
-    : public ClientAsyncResponseReaderInterface<R> {
- public:
-  // always allocated against a call arena, no memory free required
-  static void operator delete(void* ptr, std::size_t size) {
-    assert(size == sizeof(ClientAsyncResponseReader));
-  }
-
-  // This operator should never be called as the memory should be freed as part
-  // of the arena destruction. It only exists to provide a matching operator
-  // delete to the operator new so that some compilers will not complain (see
-  // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
-  // there are no tests catching the compiler warning.
-  static void operator delete(void*, void*) { assert(0); }
-
-  void StartCall() override {
-    assert(!started_);
-    started_ = true;
-    StartCallInternal();
-  }
-
-  /// See \a ClientAsyncResponseReaderInterface::ReadInitialMetadata for
-  /// semantics.
-  ///
-  /// Side effect:
-  ///   - the \a ClientContext associated with this call is updated with
-  ///     possible initial and trailing metadata sent from the server.
-  void ReadInitialMetadata(void* tag) override {
-    assert(started_);
-    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
-
-    meta_buf.set_output_tag(tag);
-    meta_buf.RecvInitialMetadata(context_);
-    call_.PerformOps(&meta_buf);
-  }
-
-  /// See \a ClientAysncResponseReaderInterface::Finish for semantics.
-  ///
-  /// Side effect:
-  ///   - the \a ClientContext associated with this call is updated with
-  ///     possible initial and trailing metadata sent from the server.
-  void Finish(R* msg, Status* status, void* tag) override {
-    assert(started_);
-    finish_buf.set_output_tag(tag);
-    if (!context_->initial_metadata_received_) {
-      finish_buf.RecvInitialMetadata(context_);
-    }
-    finish_buf.RecvMessage(msg);
-    finish_buf.AllowNoMessage();
-    finish_buf.ClientRecvStatus(context_, status);
-    call_.PerformOps(&finish_buf);
-  }
-
- private:
-  friend class internal::ClientAsyncResponseReaderFactory<R>;
-  ClientContext* const context_;
-  ::grpc::internal::Call call_;
-  bool started_;
-
-  template <class W>
-  ClientAsyncResponseReader(::grpc::internal::Call call, ClientContext* context,
-                            const W& request, bool start)
-      : context_(context), call_(call), started_(start) {
-    // Bind the metadata at time of StartCallInternal but set up the rest here
-    // TODO(ctiller): don't assert
-    GPR_CODEGEN_ASSERT(init_buf.SendMessage(request).ok());
-    init_buf.ClientSendClose();
-    if (start) StartCallInternal();
-  }
-
-  void StartCallInternal() {
-    init_buf.SendInitialMetadata(context_->send_initial_metadata_,
-                                 context_->initial_metadata_flags());
-    call_.PerformOps(&init_buf);
-  }
-
-  // disable operator new
-  static void* operator new(std::size_t size);
-  static void* operator new(std::size_t size, void* p) { return p; }
-
-  ::grpc::internal::SneakyCallOpSet<::grpc::internal::CallOpSendInitialMetadata,
-                                    ::grpc::internal::CallOpSendMessage,
-                                    ::grpc::internal::CallOpClientSendClose>
-      init_buf;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
-      meta_buf;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
-                              ::grpc::internal::CallOpRecvMessage<R>,
-                              ::grpc::internal::CallOpClientRecvStatus>
-      finish_buf;
-};
-
-/// Async server-side API for handling unary calls, where the single
-/// response message sent to the client is of type \a W.
-template <class W>
-class ServerAsyncResponseWriter final
-    : public internal::ServerAsyncStreamingInterface {
- public:
-  explicit ServerAsyncResponseWriter(ServerContext* ctx)
-      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
-
-  /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics.
-  ///
-  /// Side effect:
-  ///   The initial metadata that will be sent to the client from this op will
-  ///   be taken from the \a ServerContext associated with the call.
-  ///
-  /// \param[in] tag Tag identifying this request.
-  void SendInitialMetadata(void* tag) override {
-    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
-
-    meta_buf_.set_output_tag(tag);
-    meta_buf_.SendInitialMetadata(ctx_->initial_metadata_,
-                                  ctx_->initial_metadata_flags());
-    if (ctx_->compression_level_set()) {
-      meta_buf_.set_compression_level(ctx_->compression_level());
-    }
-    ctx_->sent_initial_metadata_ = true;
-    call_.PerformOps(&meta_buf_);
-  }
-
-  /// Indicate that the stream is to be finished and request notification
-  /// when the server has sent the appropriate signals to the client to
-  /// end the call. Should not be used concurrently with other operations.
-  ///
-  /// \param[in] tag Tag identifying this request.
-  /// \param[in] status To be sent to the client as the result of the call.
-  /// \param[in] msg Message to be sent to the client.
-  ///
-  /// Side effect:
-  ///   - also sends initial metadata if not already sent (using the
-  ///     \a ServerContext associated with this call).
-  ///
-  /// Note: if \a status has a non-OK code, then \a msg will not be sent,
-  /// and the client will receive only the status with possible trailing
-  /// metadata.
-  void Finish(const W& msg, const Status& status, void* tag) {
-    finish_buf_.set_output_tag(tag);
-    if (!ctx_->sent_initial_metadata_) {
-      finish_buf_.SendInitialMetadata(ctx_->initial_metadata_,
-                                      ctx_->initial_metadata_flags());
-      if (ctx_->compression_level_set()) {
-        finish_buf_.set_compression_level(ctx_->compression_level());
-      }
-      ctx_->sent_initial_metadata_ = true;
-    }
-    // The response is dropped if the status is not OK.
-    if (status.ok()) {
-      finish_buf_.ServerSendStatus(ctx_->trailing_metadata_,
-                                   finish_buf_.SendMessage(msg));
-    } else {
-      finish_buf_.ServerSendStatus(ctx_->trailing_metadata_, status);
-    }
-    call_.PerformOps(&finish_buf_);
-  }
-
-  /// Indicate that the stream is to be finished with a non-OK status,
-  /// and request notification for when the server has finished sending the
-  /// appropriate signals to the client to end the call.
-  /// Should not be used concurrently with other operations.
-  ///
-  /// \param[in] tag Tag identifying this request.
-  /// \param[in] status To be sent to the client as the result of the call.
-  ///   - Note: \a status must have a non-OK code.
-  ///
-  /// Side effect:
-  ///   - also sends initial metadata if not already sent (using the
-  ///     \a ServerContext associated with this call).
-  void FinishWithError(const Status& status, void* tag) {
-    GPR_CODEGEN_ASSERT(!status.ok());
-    finish_buf_.set_output_tag(tag);
-    if (!ctx_->sent_initial_metadata_) {
-      finish_buf_.SendInitialMetadata(ctx_->initial_metadata_,
-                                      ctx_->initial_metadata_flags());
-      if (ctx_->compression_level_set()) {
-        finish_buf_.set_compression_level(ctx_->compression_level());
-      }
-      ctx_->sent_initial_metadata_ = true;
-    }
-    finish_buf_.ServerSendStatus(ctx_->trailing_metadata_, status);
-    call_.PerformOps(&finish_buf_);
-  }
-
- private:
-  void BindCall(::grpc::internal::Call* call) override { call_ = *call; }
-
-  ::grpc::internal::Call call_;
-  ServerContext* ctx_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
-      meta_buf_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
-                              ::grpc::internal::CallOpSendMessage,
-                              ::grpc::internal::CallOpServerSendStatus>
-      finish_buf_;
-};
-
-}  // namespace grpc
-
-namespace std {
-template <class R>
-class default_delete<grpc::ClientAsyncResponseReader<R>> {
- public:
-  void operator()(void* p) {}
-};
-template <class R>
-class default_delete<grpc::ClientAsyncResponseReaderInterface<R>> {
- public:
-  void operator()(void* p) {}
-};
-}  // namespace std
+#include <grpcpp/impl/codegen/async_unary_call.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_ASYNC_UNARY_CALL_H
diff --git a/include/grpc++/impl/codegen/byte_buffer.h b/include/grpc++/impl/codegen/byte_buffer.h
index fe73ce7..b754fa2 100644
--- a/include/grpc++/impl/codegen/byte_buffer.h
+++ b/include/grpc++/impl/codegen/byte_buffer.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2017 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,142 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_BYTE_BUFFER_H
 #define GRPCXX_IMPL_CODEGEN_BYTE_BUFFER_H
 
-#include <grpc/impl/codegen/byte_buffer.h>
-
-#include <grpc++/impl/codegen/config.h>
-#include <grpc++/impl/codegen/core_codegen_interface.h>
-#include <grpc++/impl/codegen/serialization_traits.h>
-#include <grpc++/impl/codegen/slice.h>
-#include <grpc++/impl/codegen/status.h>
-
-#include <vector>
-
-namespace grpc {
-
-namespace internal {
-class CallOpSendMessage;
-template <class R>
-class CallOpRecvMessage;
-class CallOpGenericRecvMessage;
-class MethodHandler;
-template <class ServiceType, class RequestType, class ResponseType>
-class RpcMethodHandler;
-template <class ServiceType, class RequestType, class ResponseType>
-class ServerStreamingHandler;
-template <class R>
-class DeserializeFuncType;
-}  // namespace internal
-/// A sequence of bytes.
-class ByteBuffer final {
- public:
-  /// Constuct an empty buffer.
-  ByteBuffer() : buffer_(nullptr) {}
-
-  /// Construct buffer from \a slices, of which there are \a nslices.
-  ByteBuffer(const Slice* slices, size_t nslices);
-
-  /// Constuct a byte buffer by referencing elements of existing buffer
-  /// \a buf. Wrapper of core function grpc_byte_buffer_copy
-  ByteBuffer(const ByteBuffer& buf);
-
-  ~ByteBuffer() {
-    if (buffer_) {
-      g_core_codegen_interface->grpc_byte_buffer_destroy(buffer_);
-    }
-  }
-
-  ByteBuffer& operator=(const ByteBuffer&);
-
-  /// Dump (read) the buffer contents into \a slices.
-  Status Dump(std::vector<Slice>* slices) const;
-
-  /// Remove all data.
-  void Clear() {
-    if (buffer_) {
-      g_core_codegen_interface->grpc_byte_buffer_destroy(buffer_);
-      buffer_ = nullptr;
-    }
-  }
-
-  /// Make a duplicate copy of the internals of this byte
-  /// buffer so that we have our own owned version of it.
-  /// bbuf.Duplicate(); is equivalent to bbuf=bbuf; but is actually readable
-  void Duplicate() {
-    buffer_ = g_core_codegen_interface->grpc_byte_buffer_copy(buffer_);
-  }
-
-  /// Forget underlying byte buffer without destroying
-  /// Use this only for un-owned byte buffers
-  void Release() { buffer_ = nullptr; }
-
-  /// Buffer size in bytes.
-  size_t Length() const;
-
-  /// Swap the state of *this and *other.
-  void Swap(ByteBuffer* other);
-
-  /// Is this ByteBuffer valid?
-  bool Valid() const { return (buffer_ != nullptr); }
-
- private:
-  friend class SerializationTraits<ByteBuffer, void>;
-  friend class internal::CallOpSendMessage;
-  template <class R>
-  friend class internal::CallOpRecvMessage;
-  friend class internal::CallOpGenericRecvMessage;
-  friend class internal::MethodHandler;
-  template <class ServiceType, class RequestType, class ResponseType>
-  friend class internal::RpcMethodHandler;
-  template <class ServiceType, class RequestType, class ResponseType>
-  friend class internal::ServerStreamingHandler;
-  template <class R>
-  friend class internal::DeserializeFuncType;
-
-  grpc_byte_buffer* buffer_;
-
-  // takes ownership
-  void set_buffer(grpc_byte_buffer* buf) {
-    if (buffer_) {
-      Clear();
-    }
-    buffer_ = buf;
-  }
-
-  grpc_byte_buffer* c_buffer() { return buffer_; }
-  grpc_byte_buffer** c_buffer_ptr() { return &buffer_; }
-
-  class ByteBufferPointer {
-   public:
-    ByteBufferPointer(const ByteBuffer* b)
-        : bbuf_(const_cast<ByteBuffer*>(b)) {}
-    operator ByteBuffer*() { return bbuf_; }
-    operator grpc_byte_buffer*() { return bbuf_->buffer_; }
-    operator grpc_byte_buffer**() { return &bbuf_->buffer_; }
-
-   private:
-    ByteBuffer* bbuf_;
-  };
-  ByteBufferPointer bbuf_ptr() const { return ByteBufferPointer(this); }
-};
-
-template <>
-class SerializationTraits<ByteBuffer, void> {
- public:
-  static Status Deserialize(ByteBuffer* byte_buffer, ByteBuffer* dest) {
-    dest->set_buffer(byte_buffer->buffer_);
-    return Status::OK;
-  }
-  static Status Serialize(const ByteBuffer& source, ByteBuffer* buffer,
-                          bool* own_buffer) {
-    *buffer = source;
-    *own_buffer = true;
-    return Status::OK;
-  }
-};
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/byte_buffer.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_BYTE_BUFFER_H
diff --git a/include/grpc++/impl/codegen/call.h b/include/grpc++/impl/codegen/call.h
index c04526c..dadab54 100644
--- a/include/grpc++/impl/codegen/call.h
+++ b/include/grpc++/impl/codegen/call.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,694 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_CALL_H
 #define GRPCXX_IMPL_CODEGEN_CALL_H
 
-#include <assert.h>
-#include <cstring>
-#include <functional>
-#include <map>
-#include <memory>
-
-#include <grpc++/impl/codegen/byte_buffer.h>
-#include <grpc++/impl/codegen/call_hook.h>
-#include <grpc++/impl/codegen/client_context.h>
-#include <grpc++/impl/codegen/completion_queue_tag.h>
-#include <grpc++/impl/codegen/config.h>
-#include <grpc++/impl/codegen/core_codegen_interface.h>
-#include <grpc++/impl/codegen/serialization_traits.h>
-#include <grpc++/impl/codegen/slice.h>
-#include <grpc++/impl/codegen/status.h>
-#include <grpc++/impl/codegen/string_ref.h>
-
-#include <grpc/impl/codegen/atm.h>
-#include <grpc/impl/codegen/compression_types.h>
-#include <grpc/impl/codegen/grpc_types.h>
-
-namespace grpc {
-
-class ByteBuffer;
-class CompletionQueue;
-extern CoreCodegenInterface* g_core_codegen_interface;
-
-namespace internal {
-class Call;
-class CallHook;
-
-const char kBinaryErrorDetailsKey[] = "grpc-status-details-bin";
-
-// TODO(yangg) if the map is changed before we send, the pointers will be a
-// mess. Make sure it does not happen.
-inline grpc_metadata* FillMetadataArray(
-    const std::multimap<grpc::string, grpc::string>& metadata,
-    size_t* metadata_count, const grpc::string& optional_error_details) {
-  *metadata_count = metadata.size() + (optional_error_details.empty() ? 0 : 1);
-  if (*metadata_count == 0) {
-    return nullptr;
-  }
-  grpc_metadata* metadata_array =
-      (grpc_metadata*)(g_core_codegen_interface->gpr_malloc(
-          (*metadata_count) * sizeof(grpc_metadata)));
-  size_t i = 0;
-  for (auto iter = metadata.cbegin(); iter != metadata.cend(); ++iter, ++i) {
-    metadata_array[i].key = SliceReferencingString(iter->first);
-    metadata_array[i].value = SliceReferencingString(iter->second);
-  }
-  if (!optional_error_details.empty()) {
-    metadata_array[i].key =
-        g_core_codegen_interface->grpc_slice_from_static_buffer(
-            kBinaryErrorDetailsKey, sizeof(kBinaryErrorDetailsKey) - 1);
-    metadata_array[i].value = SliceReferencingString(optional_error_details);
-  }
-  return metadata_array;
-}
-}  // namespace internal
-
-/// Per-message write options.
-class WriteOptions {
- public:
-  WriteOptions() : flags_(0), last_message_(false) {}
-  WriteOptions(const WriteOptions& other)
-      : flags_(other.flags_), last_message_(other.last_message_) {}
-
-  /// Clear all flags.
-  inline void Clear() { flags_ = 0; }
-
-  /// Returns raw flags bitset.
-  inline uint32_t flags() const { return flags_; }
-
-  /// Sets flag for the disabling of compression for the next message write.
-  ///
-  /// \sa GRPC_WRITE_NO_COMPRESS
-  inline WriteOptions& set_no_compression() {
-    SetBit(GRPC_WRITE_NO_COMPRESS);
-    return *this;
-  }
-
-  /// Clears flag for the disabling of compression for the next message write.
-  ///
-  /// \sa GRPC_WRITE_NO_COMPRESS
-  inline WriteOptions& clear_no_compression() {
-    ClearBit(GRPC_WRITE_NO_COMPRESS);
-    return *this;
-  }
-
-  /// Get value for the flag indicating whether compression for the next
-  /// message write is forcefully disabled.
-  ///
-  /// \sa GRPC_WRITE_NO_COMPRESS
-  inline bool get_no_compression() const {
-    return GetBit(GRPC_WRITE_NO_COMPRESS);
-  }
-
-  /// Sets flag indicating that the write may be buffered and need not go out on
-  /// the wire immediately.
-  ///
-  /// \sa GRPC_WRITE_BUFFER_HINT
-  inline WriteOptions& set_buffer_hint() {
-    SetBit(GRPC_WRITE_BUFFER_HINT);
-    return *this;
-  }
-
-  /// Clears flag indicating that the write may be buffered and need not go out
-  /// on the wire immediately.
-  ///
-  /// \sa GRPC_WRITE_BUFFER_HINT
-  inline WriteOptions& clear_buffer_hint() {
-    ClearBit(GRPC_WRITE_BUFFER_HINT);
-    return *this;
-  }
-
-  /// Get value for the flag indicating that the write may be buffered and need
-  /// not go out on the wire immediately.
-  ///
-  /// \sa GRPC_WRITE_BUFFER_HINT
-  inline bool get_buffer_hint() const { return GetBit(GRPC_WRITE_BUFFER_HINT); }
-
-  /// corked bit: aliases set_buffer_hint currently, with the intent that
-  /// set_buffer_hint will be removed in the future
-  inline WriteOptions& set_corked() {
-    SetBit(GRPC_WRITE_BUFFER_HINT);
-    return *this;
-  }
-
-  inline WriteOptions& clear_corked() {
-    ClearBit(GRPC_WRITE_BUFFER_HINT);
-    return *this;
-  }
-
-  inline bool is_corked() const { return GetBit(GRPC_WRITE_BUFFER_HINT); }
-
-  /// last-message bit: indicates this is the last message in a stream
-  /// client-side:  makes Write the equivalent of performing Write, WritesDone
-  /// in a single step
-  /// server-side:  hold the Write until the service handler returns (sync api)
-  /// or until Finish is called (async api)
-  inline WriteOptions& set_last_message() {
-    last_message_ = true;
-    return *this;
-  }
-
-  /// Clears flag indicating that this is the last message in a stream,
-  /// disabling coalescing.
-  inline WriteOptions& clear_last_message() {
-    last_message_ = false;
-    return *this;
-  }
-
-  /// Guarantee that all bytes have been written to the wire before completing
-  /// this write (usually writes are completed when they pass flow control)
-  inline WriteOptions& set_write_through() {
-    SetBit(GRPC_WRITE_THROUGH);
-    return *this;
-  }
-
-  inline bool is_write_through() const { return GetBit(GRPC_WRITE_THROUGH); }
-
-  /// Get value for the flag indicating that this is the last message, and
-  /// should be coalesced with trailing metadata.
-  ///
-  /// \sa GRPC_WRITE_LAST_MESSAGE
-  bool is_last_message() const { return last_message_; }
-
-  WriteOptions& operator=(const WriteOptions& rhs) {
-    flags_ = rhs.flags_;
-    return *this;
-  }
-
- private:
-  void SetBit(const uint32_t mask) { flags_ |= mask; }
-
-  void ClearBit(const uint32_t mask) { flags_ &= ~mask; }
-
-  bool GetBit(const uint32_t mask) const { return (flags_ & mask) != 0; }
-
-  uint32_t flags_;
-  bool last_message_;
-};
-
-namespace internal {
-/// Default argument for CallOpSet. I is unused by the class, but can be
-/// used for generating multiple names for the same thing.
-template <int I>
-class CallNoOp {
- protected:
-  void AddOp(grpc_op* ops, size_t* nops) {}
-  void FinishOp(bool* status) {}
-};
-
-class CallOpSendInitialMetadata {
- public:
-  CallOpSendInitialMetadata() : send_(false) {
-    maybe_compression_level_.is_set = false;
-  }
-
-  void SendInitialMetadata(
-      const std::multimap<grpc::string, grpc::string>& metadata,
-      uint32_t flags) {
-    maybe_compression_level_.is_set = false;
-    send_ = true;
-    flags_ = flags;
-    initial_metadata_ =
-        FillMetadataArray(metadata, &initial_metadata_count_, "");
-  }
-
-  void set_compression_level(grpc_compression_level level) {
-    maybe_compression_level_.is_set = true;
-    maybe_compression_level_.level = level;
-  }
-
- protected:
-  void AddOp(grpc_op* ops, size_t* nops) {
-    if (!send_) return;
-    grpc_op* op = &ops[(*nops)++];
-    op->op = GRPC_OP_SEND_INITIAL_METADATA;
-    op->flags = flags_;
-    op->reserved = NULL;
-    op->data.send_initial_metadata.count = initial_metadata_count_;
-    op->data.send_initial_metadata.metadata = initial_metadata_;
-    op->data.send_initial_metadata.maybe_compression_level.is_set =
-        maybe_compression_level_.is_set;
-    if (maybe_compression_level_.is_set) {
-      op->data.send_initial_metadata.maybe_compression_level.level =
-          maybe_compression_level_.level;
-    }
-  }
-  void FinishOp(bool* status) {
-    if (!send_) return;
-    g_core_codegen_interface->gpr_free(initial_metadata_);
-    send_ = false;
-  }
-
-  bool send_;
-  uint32_t flags_;
-  size_t initial_metadata_count_;
-  grpc_metadata* initial_metadata_;
-  struct {
-    bool is_set;
-    grpc_compression_level level;
-  } maybe_compression_level_;
-};
-
-class CallOpSendMessage {
- public:
-  CallOpSendMessage() : send_buf_() {}
-
-  /// Send \a message using \a options for the write. The \a options are cleared
-  /// after use.
-  template <class M>
-  Status SendMessage(const M& message,
-                     WriteOptions options) GRPC_MUST_USE_RESULT;
-
-  template <class M>
-  Status SendMessage(const M& message) GRPC_MUST_USE_RESULT;
-
- protected:
-  void AddOp(grpc_op* ops, size_t* nops) {
-    if (!send_buf_.Valid()) return;
-    grpc_op* op = &ops[(*nops)++];
-    op->op = GRPC_OP_SEND_MESSAGE;
-    op->flags = write_options_.flags();
-    op->reserved = NULL;
-    op->data.send_message.send_message = send_buf_.c_buffer();
-    // Flags are per-message: clear them after use.
-    write_options_.Clear();
-  }
-  void FinishOp(bool* status) { send_buf_.Clear(); }
-
- private:
-  ByteBuffer send_buf_;
-  WriteOptions write_options_;
-};
-
-template <class M>
-Status CallOpSendMessage::SendMessage(const M& message, WriteOptions options) {
-  write_options_ = options;
-  bool own_buf;
-  // TODO(vjpai): Remove the void below when possible
-  // The void in the template parameter below should not be needed
-  // (since it should be implicit) but is needed due to an observed
-  // difference in behavior between clang and gcc for certain internal users
-  Status result = SerializationTraits<M, void>::Serialize(
-      message, send_buf_.bbuf_ptr(), &own_buf);
-  if (!own_buf) {
-    send_buf_.Duplicate();
-  }
-  return result;
-}
-
-template <class M>
-Status CallOpSendMessage::SendMessage(const M& message) {
-  return SendMessage(message, WriteOptions());
-}
-
-template <class R>
-class CallOpRecvMessage {
- public:
-  CallOpRecvMessage()
-      : got_message(false),
-        message_(nullptr),
-        allow_not_getting_message_(false) {}
-
-  void RecvMessage(R* message) { message_ = message; }
-
-  // Do not change status if no message is received.
-  void AllowNoMessage() { allow_not_getting_message_ = true; }
-
-  bool got_message;
-
- protected:
-  void AddOp(grpc_op* ops, size_t* nops) {
-    if (message_ == nullptr) return;
-    grpc_op* op = &ops[(*nops)++];
-    op->op = GRPC_OP_RECV_MESSAGE;
-    op->flags = 0;
-    op->reserved = NULL;
-    op->data.recv_message.recv_message = recv_buf_.c_buffer_ptr();
-  }
-
-  void FinishOp(bool* status) {
-    if (message_ == nullptr) return;
-    if (recv_buf_.Valid()) {
-      if (*status) {
-        got_message = *status =
-            SerializationTraits<R>::Deserialize(recv_buf_.bbuf_ptr(), message_)
-                .ok();
-        recv_buf_.Release();
-      } else {
-        got_message = false;
-        recv_buf_.Clear();
-      }
-    } else {
-      got_message = false;
-      if (!allow_not_getting_message_) {
-        *status = false;
-      }
-    }
-    message_ = nullptr;
-  }
-
- private:
-  R* message_;
-  ByteBuffer recv_buf_;
-  bool allow_not_getting_message_;
-};
-
-class DeserializeFunc {
- public:
-  virtual Status Deserialize(ByteBuffer* buf) = 0;
-  virtual ~DeserializeFunc() {}
-};
-
-template <class R>
-class DeserializeFuncType final : public DeserializeFunc {
- public:
-  DeserializeFuncType(R* message) : message_(message) {}
-  Status Deserialize(ByteBuffer* buf) override {
-    return SerializationTraits<R>::Deserialize(buf->bbuf_ptr(), message_);
-  }
-
-  ~DeserializeFuncType() override {}
-
- private:
-  R* message_;  // Not a managed pointer because management is external to this
-};
-
-class CallOpGenericRecvMessage {
- public:
-  CallOpGenericRecvMessage()
-      : got_message(false), allow_not_getting_message_(false) {}
-
-  template <class R>
-  void RecvMessage(R* message) {
-    // Use an explicit base class pointer to avoid resolution error in the
-    // following unique_ptr::reset for some old implementations.
-    DeserializeFunc* func = new DeserializeFuncType<R>(message);
-    deserialize_.reset(func);
-  }
-
-  // Do not change status if no message is received.
-  void AllowNoMessage() { allow_not_getting_message_ = true; }
-
-  bool got_message;
-
- protected:
-  void AddOp(grpc_op* ops, size_t* nops) {
-    if (!deserialize_) return;
-    grpc_op* op = &ops[(*nops)++];
-    op->op = GRPC_OP_RECV_MESSAGE;
-    op->flags = 0;
-    op->reserved = NULL;
-    op->data.recv_message.recv_message = recv_buf_.c_buffer_ptr();
-  }
-
-  void FinishOp(bool* status) {
-    if (!deserialize_) return;
-    if (recv_buf_.Valid()) {
-      if (*status) {
-        got_message = true;
-        *status = deserialize_->Deserialize(&recv_buf_).ok();
-        recv_buf_.Release();
-      } else {
-        got_message = false;
-        recv_buf_.Clear();
-      }
-    } else {
-      got_message = false;
-      if (!allow_not_getting_message_) {
-        *status = false;
-      }
-    }
-    deserialize_.reset();
-  }
-
- private:
-  std::unique_ptr<DeserializeFunc> deserialize_;
-  ByteBuffer recv_buf_;
-  bool allow_not_getting_message_;
-};
-
-class CallOpClientSendClose {
- public:
-  CallOpClientSendClose() : send_(false) {}
-
-  void ClientSendClose() { send_ = true; }
-
- protected:
-  void AddOp(grpc_op* ops, size_t* nops) {
-    if (!send_) return;
-    grpc_op* op = &ops[(*nops)++];
-    op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
-    op->flags = 0;
-    op->reserved = NULL;
-  }
-  void FinishOp(bool* status) { send_ = false; }
-
- private:
-  bool send_;
-};
-
-class CallOpServerSendStatus {
- public:
-  CallOpServerSendStatus() : send_status_available_(false) {}
-
-  void ServerSendStatus(
-      const std::multimap<grpc::string, grpc::string>& trailing_metadata,
-      const Status& status) {
-    send_error_details_ = status.error_details();
-    trailing_metadata_ = FillMetadataArray(
-        trailing_metadata, &trailing_metadata_count_, send_error_details_);
-    send_status_available_ = true;
-    send_status_code_ = static_cast<grpc_status_code>(status.error_code());
-    send_error_message_ = status.error_message();
-  }
-
- protected:
-  void AddOp(grpc_op* ops, size_t* nops) {
-    if (!send_status_available_) return;
-    grpc_op* op = &ops[(*nops)++];
-    op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
-    op->data.send_status_from_server.trailing_metadata_count =
-        trailing_metadata_count_;
-    op->data.send_status_from_server.trailing_metadata = trailing_metadata_;
-    op->data.send_status_from_server.status = send_status_code_;
-    error_message_slice_ = SliceReferencingString(send_error_message_);
-    op->data.send_status_from_server.status_details =
-        send_error_message_.empty() ? nullptr : &error_message_slice_;
-    op->flags = 0;
-    op->reserved = NULL;
-  }
-
-  void FinishOp(bool* status) {
-    if (!send_status_available_) return;
-    g_core_codegen_interface->gpr_free(trailing_metadata_);
-    send_status_available_ = false;
-  }
-
- private:
-  bool send_status_available_;
-  grpc_status_code send_status_code_;
-  grpc::string send_error_details_;
-  grpc::string send_error_message_;
-  size_t trailing_metadata_count_;
-  grpc_metadata* trailing_metadata_;
-  grpc_slice error_message_slice_;
-};
-
-class CallOpRecvInitialMetadata {
- public:
-  CallOpRecvInitialMetadata() : metadata_map_(nullptr) {}
-
-  void RecvInitialMetadata(ClientContext* context) {
-    context->initial_metadata_received_ = true;
-    metadata_map_ = &context->recv_initial_metadata_;
-  }
-
- protected:
-  void AddOp(grpc_op* ops, size_t* nops) {
-    if (metadata_map_ == nullptr) return;
-    grpc_op* op = &ops[(*nops)++];
-    op->op = GRPC_OP_RECV_INITIAL_METADATA;
-    op->data.recv_initial_metadata.recv_initial_metadata = metadata_map_->arr();
-    op->flags = 0;
-    op->reserved = NULL;
-  }
-
-  void FinishOp(bool* status) {
-    if (metadata_map_ == nullptr) return;
-    metadata_map_->FillMap();
-    metadata_map_ = nullptr;
-  }
-
- private:
-  MetadataMap* metadata_map_;
-};
-
-class CallOpClientRecvStatus {
- public:
-  CallOpClientRecvStatus()
-      : recv_status_(nullptr), debug_error_string_(nullptr) {}
-
-  void ClientRecvStatus(ClientContext* context, Status* status) {
-    client_context_ = context;
-    metadata_map_ = &client_context_->trailing_metadata_;
-    recv_status_ = status;
-    error_message_ = g_core_codegen_interface->grpc_empty_slice();
-  }
-
- protected:
-  void AddOp(grpc_op* ops, size_t* nops) {
-    if (recv_status_ == nullptr) return;
-    grpc_op* op = &ops[(*nops)++];
-    op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
-    op->data.recv_status_on_client.trailing_metadata = metadata_map_->arr();
-    op->data.recv_status_on_client.status = &status_code_;
-    op->data.recv_status_on_client.status_details = &error_message_;
-    op->data.recv_status_on_client.error_string = &debug_error_string_;
-    op->flags = 0;
-    op->reserved = NULL;
-  }
-
-  void FinishOp(bool* status) {
-    if (recv_status_ == nullptr) return;
-    metadata_map_->FillMap();
-    grpc::string binary_error_details;
-    auto iter = metadata_map_->map()->find(kBinaryErrorDetailsKey);
-    if (iter != metadata_map_->map()->end()) {
-      binary_error_details =
-          grpc::string(iter->second.begin(), iter->second.length());
-    }
-    *recv_status_ = Status(static_cast<StatusCode>(status_code_),
-                           grpc::string(GRPC_SLICE_START_PTR(error_message_),
-                                        GRPC_SLICE_END_PTR(error_message_)),
-                           binary_error_details);
-    client_context_->set_debug_error_string(
-        debug_error_string_ != nullptr ? debug_error_string_ : "");
-    g_core_codegen_interface->grpc_slice_unref(error_message_);
-    if (debug_error_string_ != nullptr) {
-      g_core_codegen_interface->gpr_free((void*)debug_error_string_);
-    }
-    recv_status_ = nullptr;
-  }
-
- private:
-  ClientContext* client_context_;
-  MetadataMap* metadata_map_;
-  Status* recv_status_;
-  const char* debug_error_string_;
-  grpc_status_code status_code_;
-  grpc_slice error_message_;
-};
-
-/// An abstract collection of call ops, used to generate the
-/// grpc_call_op structure to pass down to the lower layers,
-/// and as it is-a CompletionQueueTag, also massages the final
-/// completion into the correct form for consumption in the C++
-/// API.
-class CallOpSetInterface : public CompletionQueueTag {
- public:
-  /// Fills in grpc_op, starting from ops[*nops] and moving
-  /// upwards.
-  virtual void FillOps(grpc_call* call, grpc_op* ops, size_t* nops) = 0;
-};
-
-/// Primary implementation of CallOpSetInterface.
-/// Since we cannot use variadic templates, we declare slots up to
-/// the maximum count of ops we'll need in a set. We leverage the
-/// empty base class optimization to slim this class (especially
-/// when there are many unused slots used). To avoid duplicate base classes,
-/// the template parmeter for CallNoOp is varied by argument position.
-template <class Op1 = CallNoOp<1>, class Op2 = CallNoOp<2>,
-          class Op3 = CallNoOp<3>, class Op4 = CallNoOp<4>,
-          class Op5 = CallNoOp<5>, class Op6 = CallNoOp<6>>
-class CallOpSet : public CallOpSetInterface,
-                  public Op1,
-                  public Op2,
-                  public Op3,
-                  public Op4,
-                  public Op5,
-                  public Op6 {
- public:
-  CallOpSet() : return_tag_(this), call_(nullptr) {}
-  void FillOps(grpc_call* call, grpc_op* ops, size_t* nops) override {
-    this->Op1::AddOp(ops, nops);
-    this->Op2::AddOp(ops, nops);
-    this->Op3::AddOp(ops, nops);
-    this->Op4::AddOp(ops, nops);
-    this->Op5::AddOp(ops, nops);
-    this->Op6::AddOp(ops, nops);
-    g_core_codegen_interface->grpc_call_ref(call);
-    call_ = call;
-  }
-
-  bool FinalizeResult(void** tag, bool* status) override {
-    this->Op1::FinishOp(status);
-    this->Op2::FinishOp(status);
-    this->Op3::FinishOp(status);
-    this->Op4::FinishOp(status);
-    this->Op5::FinishOp(status);
-    this->Op6::FinishOp(status);
-    *tag = return_tag_;
-
-    g_core_codegen_interface->grpc_call_unref(call_);
-    return true;
-  }
-
-  void set_output_tag(void* return_tag) { return_tag_ = return_tag; }
-
- private:
-  void* return_tag_;
-  grpc_call* call_;
-};
-
-/// A CallOpSet that does not post completions to the completion queue.
-///
-/// Allows hiding some completions that the C core must generate from
-/// C++ users.
-template <class Op1 = CallNoOp<1>, class Op2 = CallNoOp<2>,
-          class Op3 = CallNoOp<3>, class Op4 = CallNoOp<4>,
-          class Op5 = CallNoOp<5>, class Op6 = CallNoOp<6>>
-class SneakyCallOpSet : public CallOpSet<Op1, Op2, Op3, Op4, Op5, Op6> {
- public:
-  bool FinalizeResult(void** tag, bool* status) override {
-    typedef CallOpSet<Op1, Op2, Op3, Op4, Op5, Op6> Base;
-    return Base::FinalizeResult(tag, status) && false;
-  }
-};
-
-/// Straightforward wrapping of the C call object
-class Call final {
- public:
-  /** call is owned by the caller */
-  Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq)
-      : call_hook_(call_hook),
-        cq_(cq),
-        call_(call),
-        max_receive_message_size_(-1) {}
-
-  Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq,
-       int max_receive_message_size)
-      : call_hook_(call_hook),
-        cq_(cq),
-        call_(call),
-        max_receive_message_size_(max_receive_message_size) {}
-
-  void PerformOps(CallOpSetInterface* ops) {
-    call_hook_->PerformOpsOnCall(ops, this);
-  }
-
-  grpc_call* call() const { return call_; }
-  CompletionQueue* cq() const { return cq_; }
-
-  int max_receive_message_size() const { return max_receive_message_size_; }
-
- private:
-  CallHook* call_hook_;
-  CompletionQueue* cq_;
-  grpc_call* call_;
-  int max_receive_message_size_;
-};
-}  // namespace internal
-}  // namespace grpc
+#include <grpcpp/impl/codegen/call.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_CALL_H
diff --git a/include/grpc++/impl/codegen/call_hook.h b/include/grpc++/impl/codegen/call_hook.h
index 44e9de2..cf5ed57 100644
--- a/include/grpc++/impl/codegen/call_hook.h
+++ b/include/grpc++/impl/codegen/call_hook.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,24 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_CALL_HOOK_H
 #define GRPCXX_IMPL_CODEGEN_CALL_HOOK_H
 
-namespace grpc {
-
-namespace internal {
-class CallOpSetInterface;
-class Call;
-
-/// This is an interface that Channel and Server implement to allow them to hook
-/// performing ops.
-class CallHook {
- public:
-  virtual ~CallHook() {}
-  virtual void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) = 0;
-};
-}  // namespace internal
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/call_hook.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_CALL_HOOK_H
diff --git a/include/grpc++/impl/codegen/channel_interface.h b/include/grpc++/impl/codegen/channel_interface.h
index 769f853..c6e782e 100644
--- a/include/grpc++/impl/codegen/channel_interface.h
+++ b/include/grpc++/impl/codegen/channel_interface.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,106 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_CHANNEL_INTERFACE_H
 #define GRPCXX_IMPL_CODEGEN_CHANNEL_INTERFACE_H
 
-#include <grpc++/impl/codegen/status.h>
-#include <grpc++/impl/codegen/time.h>
-#include <grpc/impl/codegen/connectivity_state.h>
-
-namespace grpc {
-class ChannelInterface;
-class ClientContext;
-class CompletionQueue;
-
-template <class R>
-class ClientReader;
-template <class W>
-class ClientWriter;
-template <class W, class R>
-class ClientReaderWriter;
-
-namespace internal {
-class Call;
-class CallOpSetInterface;
-class RpcMethod;
-template <class InputMessage, class OutputMessage>
-class BlockingUnaryCallImpl;
-template <class R>
-class ClientAsyncReaderFactory;
-template <class W>
-class ClientAsyncWriterFactory;
-template <class W, class R>
-class ClientAsyncReaderWriterFactory;
-template <class R>
-class ClientAsyncResponseReaderFactory;
-}  // namespace internal
-
-/// Codegen interface for \a grpc::Channel.
-class ChannelInterface {
- public:
-  virtual ~ChannelInterface() {}
-  /// Get the current channel state. If the channel is in IDLE and
-  /// \a try_to_connect is set to true, try to connect.
-  virtual grpc_connectivity_state GetState(bool try_to_connect) = 0;
-
-  /// Return the \a tag on \a cq when the channel state is changed or \a
-  /// deadline expires. \a GetState needs to called to get the current state.
-  template <typename T>
-  void NotifyOnStateChange(grpc_connectivity_state last_observed, T deadline,
-                           CompletionQueue* cq, void* tag) {
-    TimePoint<T> deadline_tp(deadline);
-    NotifyOnStateChangeImpl(last_observed, deadline_tp.raw_time(), cq, tag);
-  }
-
-  /// Blocking wait for channel state change or \a deadline expiration.
-  /// \a GetState needs to called to get the current state.
-  template <typename T>
-  bool WaitForStateChange(grpc_connectivity_state last_observed, T deadline) {
-    TimePoint<T> deadline_tp(deadline);
-    return WaitForStateChangeImpl(last_observed, deadline_tp.raw_time());
-  }
-
-  /// Wait for this channel to be connected
-  template <typename T>
-  bool WaitForConnected(T deadline) {
-    grpc_connectivity_state state;
-    while ((state = GetState(true)) != GRPC_CHANNEL_READY) {
-      if (!WaitForStateChange(state, deadline)) return false;
-    }
-    return true;
-  }
-
- private:
-  template <class R>
-  friend class ::grpc::ClientReader;
-  template <class W>
-  friend class ::grpc::ClientWriter;
-  template <class W, class R>
-  friend class ::grpc::ClientReaderWriter;
-  template <class R>
-  friend class ::grpc::internal::ClientAsyncReaderFactory;
-  template <class W>
-  friend class ::grpc::internal::ClientAsyncWriterFactory;
-  template <class W, class R>
-  friend class ::grpc::internal::ClientAsyncReaderWriterFactory;
-  template <class R>
-  friend class ::grpc::internal::ClientAsyncResponseReaderFactory;
-  template <class InputMessage, class OutputMessage>
-  friend class ::grpc::internal::BlockingUnaryCallImpl;
-  friend class ::grpc::internal::RpcMethod;
-  virtual internal::Call CreateCall(const internal::RpcMethod& method,
-                                    ClientContext* context,
-                                    CompletionQueue* cq) = 0;
-  virtual void PerformOpsOnCall(internal::CallOpSetInterface* ops,
-                                internal::Call* call) = 0;
-  virtual void* RegisterMethod(const char* method) = 0;
-  virtual void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
-                                       gpr_timespec deadline,
-                                       CompletionQueue* cq, void* tag) = 0;
-  virtual bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
-                                      gpr_timespec deadline) = 0;
-};
-}  // namespace grpc
+#include <grpcpp/impl/codegen/channel_interface.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_CHANNEL_INTERFACE_H
diff --git a/include/grpc++/impl/codegen/client_context.h b/include/grpc++/impl/codegen/client_context.h
index 61d97ce..107532c 100644
--- a/include/grpc++/impl/codegen/client_context.h
+++ b/include/grpc++/impl/codegen/client_context.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,418 +16,13 @@
  *
  */
 
-/// A ClientContext allows the person implementing a service client to:
-///
-/// - Add custom metadata key-value pairs that will propagated to the server
-/// side.
-/// - Control call settings such as compression and authentication.
-/// - Initial and trailing metadata coming from the server.
-/// - Get performance metrics (ie, census).
-///
-/// Context settings are only relevant to the call they are invoked with, that
-/// is to say, they aren't sticky. Some of these settings, such as the
-/// compression options, can be made persistent at channel construction time
-/// (see \a grpc::CreateCustomChannel).
-///
-/// \warning ClientContext instances should \em not be reused across rpcs.
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
 
 #ifndef GRPCXX_IMPL_CODEGEN_CLIENT_CONTEXT_H
 #define GRPCXX_IMPL_CODEGEN_CLIENT_CONTEXT_H
 
-#include <map>
-#include <memory>
-#include <mutex>
-#include <string>
-
-#include <grpc++/impl/codegen/config.h>
-#include <grpc++/impl/codegen/core_codegen_interface.h>
-#include <grpc++/impl/codegen/create_auth_context.h>
-#include <grpc++/impl/codegen/metadata_map.h>
-#include <grpc++/impl/codegen/security/auth_context.h>
-#include <grpc++/impl/codegen/slice.h>
-#include <grpc++/impl/codegen/status.h>
-#include <grpc++/impl/codegen/string_ref.h>
-#include <grpc++/impl/codegen/time.h>
-#include <grpc/impl/codegen/compression_types.h>
-#include <grpc/impl/codegen/propagation_bits.h>
-
-struct census_context;
-struct grpc_call;
-
-namespace grpc {
-
-class Channel;
-class ChannelInterface;
-class CompletionQueue;
-class CallCredentials;
-class ClientContext;
-
-namespace internal {
-class RpcMethod;
-class CallOpClientRecvStatus;
-class CallOpRecvInitialMetadata;
-template <class InputMessage, class OutputMessage>
-class BlockingUnaryCallImpl;
-}  // namespace internal
-
-template <class R>
-class ClientReader;
-template <class W>
-class ClientWriter;
-template <class W, class R>
-class ClientReaderWriter;
-template <class R>
-class ClientAsyncReader;
-template <class W>
-class ClientAsyncWriter;
-template <class W, class R>
-class ClientAsyncReaderWriter;
-template <class R>
-class ClientAsyncResponseReader;
-class ServerContext;
-
-/// Options for \a ClientContext::FromServerContext specifying which traits from
-/// the \a ServerContext to propagate (copy) from it into a new \a
-/// ClientContext.
-///
-/// \see ClientContext::FromServerContext
-class PropagationOptions {
- public:
-  PropagationOptions() : propagate_(GRPC_PROPAGATE_DEFAULTS) {}
-
-  PropagationOptions& enable_deadline_propagation() {
-    propagate_ |= GRPC_PROPAGATE_DEADLINE;
-    return *this;
-  }
-
-  PropagationOptions& disable_deadline_propagation() {
-    propagate_ &= ~GRPC_PROPAGATE_DEADLINE;
-    return *this;
-  }
-
-  PropagationOptions& enable_census_stats_propagation() {
-    propagate_ |= GRPC_PROPAGATE_CENSUS_STATS_CONTEXT;
-    return *this;
-  }
-
-  PropagationOptions& disable_census_stats_propagation() {
-    propagate_ &= ~GRPC_PROPAGATE_CENSUS_STATS_CONTEXT;
-    return *this;
-  }
-
-  PropagationOptions& enable_census_tracing_propagation() {
-    propagate_ |= GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT;
-    return *this;
-  }
-
-  PropagationOptions& disable_census_tracing_propagation() {
-    propagate_ &= ~GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT;
-    return *this;
-  }
-
-  PropagationOptions& enable_cancellation_propagation() {
-    propagate_ |= GRPC_PROPAGATE_CANCELLATION;
-    return *this;
-  }
-
-  PropagationOptions& disable_cancellation_propagation() {
-    propagate_ &= ~GRPC_PROPAGATE_CANCELLATION;
-    return *this;
-  }
-
-  uint32_t c_bitmask() const { return propagate_; }
-
- private:
-  uint32_t propagate_;
-};
-
-namespace testing {
-class InteropClientContextInspector;
-}  // namespace testing
-
-/// A ClientContext allows the person implementing a service client to:
-///
-/// - Add custom metadata key-value pairs that will propagated to the server
-///   side.
-/// - Control call settings such as compression and authentication.
-/// - Initial and trailing metadata coming from the server.
-/// - Get performance metrics (ie, census).
-///
-/// Context settings are only relevant to the call they are invoked with, that
-/// is to say, they aren't sticky. Some of these settings, such as the
-/// compression options, can be made persistent at channel construction time
-/// (see \a grpc::CreateCustomChannel).
-///
-/// \warning ClientContext instances should \em not be reused across rpcs.
-class ClientContext {
- public:
-  ClientContext();
-  ~ClientContext();
-
-  /// Create a new \a ClientContext as a child of an incoming server call,
-  /// according to \a options (\see PropagationOptions).
-  ///
-  /// \param server_context The source server context to use as the basis for
-  /// constructing the client context.
-  /// \param options The options controlling what to copy from the \a
-  /// server_context.
-  ///
-  /// \return A newly constructed \a ClientContext instance based on \a
-  /// server_context, with traits propagated (copied) according to \a options.
-  static std::unique_ptr<ClientContext> FromServerContext(
-      const ServerContext& server_context,
-      PropagationOptions options = PropagationOptions());
-
-  /// Add the (\a meta_key, \a meta_value) pair to the metadata associated with
-  /// a client call. These are made available at the server side by the \a
-  /// grpc::ServerContext::client_metadata() method.
-  ///
-  /// \warning This method should only be called before invoking the rpc.
-  ///
-  /// \param meta_key The metadata key. If \a meta_value is binary data, it must
-  /// end in "-bin".
-  /// \param meta_value The metadata value. If its value is binary, the key name
-  /// must end in "-bin".
-  void AddMetadata(const grpc::string& meta_key,
-                   const grpc::string& meta_value);
-
-  /// Return a collection of initial metadata key-value pairs. Note that keys
-  /// may happen more than once (ie, a \a std::multimap is returned).
-  ///
-  /// \warning This method should only be called after initial metadata has been
-  /// received. For streaming calls, see \a
-  /// ClientReaderInterface::WaitForInitialMetadata().
-  ///
-  /// \return A multimap of initial metadata key-value pairs from the server.
-  const std::multimap<grpc::string_ref, grpc::string_ref>&
-  GetServerInitialMetadata() const {
-    GPR_CODEGEN_ASSERT(initial_metadata_received_);
-    return *recv_initial_metadata_.map();
-  }
-
-  /// Return a collection of trailing metadata key-value pairs. Note that keys
-  /// may happen more than once (ie, a \a std::multimap is returned).
-  ///
-  /// \warning This method is only callable once the stream has finished.
-  ///
-  /// \return A multimap of metadata trailing key-value pairs from the server.
-  const std::multimap<grpc::string_ref, grpc::string_ref>&
-  GetServerTrailingMetadata() const {
-    // TODO(yangg) check finished
-    return *trailing_metadata_.map();
-  }
-
-  /// Set the deadline for the client call.
-  ///
-  /// \warning This method should only be called before invoking the rpc.
-  ///
-  /// \param deadline the deadline for the client call. Units are determined by
-  /// the type used.
-  template <typename T>
-  void set_deadline(const T& deadline) {
-    TimePoint<T> deadline_tp(deadline);
-    deadline_ = deadline_tp.raw_time();
-  }
-
-  /// EXPERIMENTAL: Indicate that this request is idempotent.
-  /// By default, RPCs are assumed to <i>not</i> be idempotent.
-  ///
-  /// If true, the gRPC library assumes that it's safe to initiate
-  /// this RPC multiple times.
-  void set_idempotent(bool idempotent) { idempotent_ = idempotent; }
-
-  /// EXPERIMENTAL: Set this request to be cacheable.
-  /// If set, grpc is free to use the HTTP GET verb for sending the request,
-  /// with the possibility of receiving a cached response.
-  void set_cacheable(bool cacheable) { cacheable_ = cacheable; }
-
-  /// EXPERIMENTAL: Trigger wait-for-ready or not on this request.
-  /// See https://github.com/grpc/grpc/blob/master/doc/wait-for-ready.md.
-  /// If set, if an RPC is made when a channel's connectivity state is
-  /// TRANSIENT_FAILURE or CONNECTING, the call will not "fail fast",
-  /// and the channel will wait until the channel is READY before making the
-  /// call.
-  void set_wait_for_ready(bool wait_for_ready) {
-    wait_for_ready_ = wait_for_ready;
-    wait_for_ready_explicitly_set_ = true;
-  }
-
-  /// DEPRECATED: Use set_wait_for_ready() instead.
-  void set_fail_fast(bool fail_fast) { set_wait_for_ready(!fail_fast); }
-
-  /// Return the deadline for the client call.
-  std::chrono::system_clock::time_point deadline() const {
-    return Timespec2Timepoint(deadline_);
-  }
-
-  /// Return a \a gpr_timespec representation of the client call's deadline.
-  gpr_timespec raw_deadline() const { return deadline_; }
-
-  /// Set the per call authority header (see
-  /// https://tools.ietf.org/html/rfc7540#section-8.1.2.3).
-  void set_authority(const grpc::string& authority) { authority_ = authority; }
-
-  /// Return the authentication context for this client call.
-  ///
-  /// \see grpc::AuthContext.
-  std::shared_ptr<const AuthContext> auth_context() const {
-    if (auth_context_.get() == nullptr) {
-      auth_context_ = CreateAuthContext(call_);
-    }
-    return auth_context_;
-  }
-
-  /// Set credentials for the client call.
-  ///
-  /// A credentials object encapsulates all the state needed by a client to
-  /// authenticate with a server and make various assertions, e.g., about the
-  /// client’s identity, role, or whether it is authorized to make a particular
-  /// call.
-  ///
-  /// \see  https://grpc.io/docs/guides/auth.html
-  void set_credentials(const std::shared_ptr<CallCredentials>& creds) {
-    creds_ = creds;
-  }
-
-  /// Return the compression algorithm to be used by the client call.
-  grpc_compression_algorithm compression_algorithm() const {
-    return compression_algorithm_;
-  }
-
-  /// Set \a algorithm to be the compression algorithm used for the client call.
-  ///
-  /// \param algorithm The compression algorithm used for the client call.
-  void set_compression_algorithm(grpc_compression_algorithm algorithm);
-
-  /// Flag whether the initial metadata should be \a corked
-  ///
-  /// If \a corked is true, then the initial metadata will be coalesced with the
-  /// write of first message in the stream.
-  ///
-  /// \param corked The flag indicating whether the initial metadata is to be
-  /// corked or not.
-  void set_initial_metadata_corked(bool corked) {
-    initial_metadata_corked_ = corked;
-  }
-
-  /// Return the peer uri in a string.
-  ///
-  /// \warning This value is never authenticated or subject to any security
-  /// related code. It must not be used for any authentication related
-  /// functionality. Instead, use auth_context.
-  ///
-  /// \return The call's peer URI.
-  grpc::string peer() const;
-
-  /// Get and set census context.
-  void set_census_context(struct census_context* ccp) { census_context_ = ccp; }
-  struct census_context* census_context() const {
-    return census_context_;
-  }
-
-  /// Send a best-effort out-of-band cancel on the call associated with
-  /// this client context.  The call could be in any stage; e.g., if it is
-  /// already finished, it may still return success.
-  ///
-  /// There is no guarantee the call will be cancelled.
-  void TryCancel();
-
-  /// Global Callbacks
-  ///
-  /// Can be set exactly once per application to install hooks whenever
-  /// a client context is constructed and destructed.
-  class GlobalCallbacks {
-   public:
-    virtual ~GlobalCallbacks() {}
-    virtual void DefaultConstructor(ClientContext* context) = 0;
-    virtual void Destructor(ClientContext* context) = 0;
-  };
-  static void SetGlobalCallbacks(GlobalCallbacks* callbacks);
-
-  /// Should be used for framework-level extensions only.
-  /// Applications never need to call this method.
-  grpc_call* c_call() { return call_; }
-
-  /// EXPERIMENTAL debugging API
-  ///
-  /// if status is not ok() for an RPC, this will return a detailed string
-  /// of the gRPC Core error that led to the failure. It should not be relied
-  /// upon for anything other than gaining more debug data in failure cases.
-  grpc::string debug_error_string() const { return debug_error_string_; }
-
- private:
-  // Disallow copy and assign.
-  ClientContext(const ClientContext&);
-  ClientContext& operator=(const ClientContext&);
-
-  friend class ::grpc::testing::InteropClientContextInspector;
-  friend class ::grpc::internal::CallOpClientRecvStatus;
-  friend class ::grpc::internal::CallOpRecvInitialMetadata;
-  friend class Channel;
-  template <class R>
-  friend class ::grpc::ClientReader;
-  template <class W>
-  friend class ::grpc::ClientWriter;
-  template <class W, class R>
-  friend class ::grpc::ClientReaderWriter;
-  template <class R>
-  friend class ::grpc::ClientAsyncReader;
-  template <class W>
-  friend class ::grpc::ClientAsyncWriter;
-  template <class W, class R>
-  friend class ::grpc::ClientAsyncReaderWriter;
-  template <class R>
-  friend class ::grpc::ClientAsyncResponseReader;
-  template <class InputMessage, class OutputMessage>
-  friend class ::grpc::internal::BlockingUnaryCallImpl;
-
-  // Used by friend class CallOpClientRecvStatus
-  void set_debug_error_string(const grpc::string& debug_error_string) {
-    debug_error_string_ = debug_error_string;
-  }
-
-  grpc_call* call() const { return call_; }
-  void set_call(grpc_call* call, const std::shared_ptr<Channel>& channel);
-
-  uint32_t initial_metadata_flags() const {
-    return (idempotent_ ? GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST : 0) |
-           (wait_for_ready_ ? GRPC_INITIAL_METADATA_WAIT_FOR_READY : 0) |
-           (cacheable_ ? GRPC_INITIAL_METADATA_CACHEABLE_REQUEST : 0) |
-           (wait_for_ready_explicitly_set_
-                ? GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET
-                : 0) |
-           (initial_metadata_corked_ ? GRPC_INITIAL_METADATA_CORKED : 0);
-  }
-
-  grpc::string authority() { return authority_; }
-
-  bool initial_metadata_received_;
-  bool wait_for_ready_;
-  bool wait_for_ready_explicitly_set_;
-  bool idempotent_;
-  bool cacheable_;
-  std::shared_ptr<Channel> channel_;
-  std::mutex mu_;
-  grpc_call* call_;
-  bool call_canceled_;
-  gpr_timespec deadline_;
-  grpc::string authority_;
-  std::shared_ptr<CallCredentials> creds_;
-  mutable std::shared_ptr<const AuthContext> auth_context_;
-  struct census_context* census_context_;
-  std::multimap<grpc::string, grpc::string> send_initial_metadata_;
-  internal::MetadataMap recv_initial_metadata_;
-  internal::MetadataMap trailing_metadata_;
-
-  grpc_call* propagate_from_call_;
-  PropagationOptions propagation_options_;
-
-  grpc_compression_algorithm compression_algorithm_;
-  bool initial_metadata_corked_;
-
-  grpc::string debug_error_string_;
-};
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/client_context.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_CLIENT_CONTEXT_H
diff --git a/include/grpc++/impl/codegen/client_unary_call.h b/include/grpc++/impl/codegen/client_unary_call.h
index 543e54b..f7dff1f 100644
--- a/include/grpc++/impl/codegen/client_unary_call.h
+++ b/include/grpc++/impl/codegen/client_unary_call.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,75 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_CLIENT_UNARY_CALL_H
 #define GRPCXX_IMPL_CODEGEN_CLIENT_UNARY_CALL_H
 
-#include <grpc++/impl/codegen/call.h>
-#include <grpc++/impl/codegen/channel_interface.h>
-#include <grpc++/impl/codegen/config.h>
-#include <grpc++/impl/codegen/core_codegen_interface.h>
-#include <grpc++/impl/codegen/status.h>
-
-namespace grpc {
-
-class Channel;
-class ClientContext;
-class CompletionQueue;
-
-namespace internal {
-class RpcMethod;
-/// Wrapper that performs a blocking unary call
-template <class InputMessage, class OutputMessage>
-Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method,
-                         ClientContext* context, const InputMessage& request,
-                         OutputMessage* result) {
-  return BlockingUnaryCallImpl<InputMessage, OutputMessage>(
-             channel, method, context, request, result)
-      .status();
-}
-
-template <class InputMessage, class OutputMessage>
-class BlockingUnaryCallImpl {
- public:
-  BlockingUnaryCallImpl(ChannelInterface* channel, const RpcMethod& method,
-                        ClientContext* context, const InputMessage& request,
-                        OutputMessage* result) {
-    CompletionQueue cq(grpc_completion_queue_attributes{
-        GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK,
-        GRPC_CQ_DEFAULT_POLLING});  // Pluckable completion queue
-    Call call(channel->CreateCall(method, context, &cq));
-    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
-              CallOpRecvInitialMetadata, CallOpRecvMessage<OutputMessage>,
-              CallOpClientSendClose, CallOpClientRecvStatus>
-        ops;
-    status_ = ops.SendMessage(request);
-    if (!status_.ok()) {
-      return;
-    }
-    ops.SendInitialMetadata(context->send_initial_metadata_,
-                            context->initial_metadata_flags());
-    ops.RecvInitialMetadata(context);
-    ops.RecvMessage(result);
-    ops.AllowNoMessage();
-    ops.ClientSendClose();
-    ops.ClientRecvStatus(context, &status_);
-    call.PerformOps(&ops);
-    if (cq.Pluck(&ops)) {
-      if (!ops.got_message && status_.ok()) {
-        status_ = Status(StatusCode::UNIMPLEMENTED,
-                         "No message returned for unary request");
-      }
-    } else {
-      GPR_CODEGEN_ASSERT(!status_.ok());
-    }
-  }
-  Status status() { return status_; }
-
- private:
-  Status status_;
-};
-
-}  // namespace internal
-}  // namespace grpc
+#include <grpcpp/impl/codegen/client_unary_call.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_CLIENT_UNARY_CALL_H
diff --git a/include/grpc++/impl/codegen/completion_queue.h b/include/grpc++/impl/codegen/completion_queue.h
index b8a7862..1075495 100644
--- a/include/grpc++/impl/codegen/completion_queue.h
+++ b/include/grpc++/impl/codegen/completion_queue.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015-2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,325 +16,13 @@
  *
  */
 
-/// A completion queue implements a concurrent producer-consumer queue, with
-/// two main API-exposed methods: \a Next and \a AsyncNext. These
-/// methods are the essential component of the gRPC C++ asynchronous API.
-/// There is also a \a Shutdown method to indicate that a given completion queue
-/// will no longer have regular events. This must be called before the
-/// completion queue is destroyed.
-/// All completion queue APIs are thread-safe and may be used concurrently with
-/// any other completion queue API invocation; it is acceptable to have
-/// multiple threads calling \a Next or \a AsyncNext on the same or different
-/// completion queues, or to call these methods concurrently with a \a Shutdown
-/// elsewhere.
-/// \remark{All other API calls on completion queue should be completed before
-/// a completion queue destructor is called.}
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_COMPLETION_QUEUE_H
 #define GRPCXX_IMPL_CODEGEN_COMPLETION_QUEUE_H
 
-#include <grpc++/impl/codegen/completion_queue_tag.h>
-#include <grpc++/impl/codegen/core_codegen_interface.h>
-#include <grpc++/impl/codegen/grpc_library.h>
-#include <grpc++/impl/codegen/status.h>
-#include <grpc++/impl/codegen/time.h>
-#include <grpc/impl/codegen/atm.h>
-
-struct grpc_completion_queue;
-
-namespace grpc {
-
-template <class R>
-class ClientReader;
-template <class W>
-class ClientWriter;
-template <class W, class R>
-class ClientReaderWriter;
-template <class R>
-class ServerReader;
-template <class W>
-class ServerWriter;
-namespace internal {
-template <class W, class R>
-class ServerReaderWriterBody;
-}  // namespace internal
-
-class Channel;
-class ChannelInterface;
-class ClientContext;
-class CompletionQueue;
-class Server;
-class ServerBuilder;
-class ServerContext;
-class ServerInterface;
-
-namespace internal {
-class CompletionQueueTag;
-class RpcMethod;
-template <class ServiceType, class RequestType, class ResponseType>
-class RpcMethodHandler;
-template <class ServiceType, class RequestType, class ResponseType>
-class ClientStreamingHandler;
-template <class ServiceType, class RequestType, class ResponseType>
-class ServerStreamingHandler;
-template <class ServiceType, class RequestType, class ResponseType>
-class BidiStreamingHandler;
-class UnknownMethodHandler;
-template <class Streamer, bool WriteNeeded>
-class TemplatedBidiStreamingHandler;
-template <class InputMessage, class OutputMessage>
-class BlockingUnaryCallImpl;
-}  // namespace internal
-
-extern CoreCodegenInterface* g_core_codegen_interface;
-
-/// A thin wrapper around \ref grpc_completion_queue (see \ref
-/// src/core/lib/surface/completion_queue.h).
-/// See \ref doc/cpp/perf_notes.md for notes on best practices for high
-/// performance servers.
-class CompletionQueue : private GrpcLibraryCodegen {
- public:
-  /// Default constructor. Implicitly creates a \a grpc_completion_queue
-  /// instance.
-  CompletionQueue()
-      : CompletionQueue(grpc_completion_queue_attributes{
-            GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, GRPC_CQ_DEFAULT_POLLING}) {}
-
-  /// Wrap \a take, taking ownership of the instance.
-  ///
-  /// \param take The completion queue instance to wrap. Ownership is taken.
-  explicit CompletionQueue(grpc_completion_queue* take);
-
-  /// Destructor. Destroys the owned wrapped completion queue / instance.
-  ~CompletionQueue() {
-    g_core_codegen_interface->grpc_completion_queue_destroy(cq_);
-  }
-
-  /// Tri-state return for AsyncNext: SHUTDOWN, GOT_EVENT, TIMEOUT.
-  enum NextStatus {
-    SHUTDOWN,   ///< The completion queue has been shutdown.
-    GOT_EVENT,  ///< Got a new event; \a tag will be filled in with its
-                ///< associated value; \a ok indicating its success.
-    TIMEOUT     ///< deadline was reached.
-  };
-
-  /// EXPERIMENTAL
-  /// First executes \a F, then reads from the queue, blocking up to
-  /// \a deadline (or the queue's shutdown).
-  /// Both \a tag and \a ok are updated upon success (if an event is available
-  /// within the \a deadline).  A \a tag points to an arbitrary location usually
-  /// employed to uniquely identify an event.
-  ///
-  /// \param F[in] Function to execute before calling AsyncNext on this queue.
-  /// \param tag[out] Upon sucess, updated to point to the event's tag.
-  /// \param ok[out] Upon sucess, true if read a regular event, false otherwise.
-  /// \param deadline[in] How long to block in wait for an event.
-  ///
-  /// \return The type of event read.
-  template <typename T, typename F>
-  NextStatus DoThenAsyncNext(F&& f, void** tag, bool* ok, const T& deadline) {
-    CompletionQueueTLSCache cache = CompletionQueueTLSCache(this);
-    f();
-    if (cache.Flush(tag, ok)) {
-      return GOT_EVENT;
-    } else {
-      return AsyncNext(tag, ok, deadline);
-    }
-  }
-
-  /// Read from the queue, blocking up to \a deadline (or the queue's shutdown).
-  /// Both \a tag and \a ok are updated upon success (if an event is available
-  /// within the \a deadline).  A \a tag points to an arbitrary location usually
-  /// employed to uniquely identify an event.
-  ///
-  /// \param tag[out] Upon sucess, updated to point to the event's tag.
-  /// \param ok[out] Upon sucess, true if read a regular event, false otherwise.
-  /// \param deadline[in] How long to block in wait for an event.
-  ///
-  /// \return The type of event read.
-  template <typename T>
-  NextStatus AsyncNext(void** tag, bool* ok, const T& deadline) {
-    TimePoint<T> deadline_tp(deadline);
-    return AsyncNextInternal(tag, ok, deadline_tp.raw_time());
-  }
-
-  /// Read from the queue, blocking until an event is available or the queue is
-  /// shutting down.
-  ///
-  /// \param tag[out] Updated to point to the read event's tag.
-  /// \param ok[out] true if read a regular event, false otherwise.
-  ///
-  /// \return true if read a regular event, false if the queue is shutting down.
-  bool Next(void** tag, bool* ok) {
-    return (AsyncNextInternal(tag, ok,
-                              g_core_codegen_interface->gpr_inf_future(
-                                  GPR_CLOCK_REALTIME)) != SHUTDOWN);
-  }
-
-  /// Request the shutdown of the queue.
-  ///
-  /// \warning This method must be called at some point if this completion queue
-  /// is accessed with Next or AsyncNext. Once invoked, \a Next
-  /// will start to return false and \a AsyncNext will return \a
-  /// NextStatus::SHUTDOWN. Only once either one of these methods does that
-  /// (that is, once the queue has been \em drained) can an instance of this
-  /// class be destroyed. Also note that applications must ensure that
-  /// no work is enqueued on this completion queue after this method is called.
-  void Shutdown();
-
-  /// Returns a \em raw pointer to the underlying \a grpc_completion_queue
-  /// instance.
-  ///
-  /// \warning Remember that the returned instance is owned. No transfer of
-  /// owership is performed.
-  grpc_completion_queue* cq() { return cq_; }
-
- protected:
-  /// Private constructor of CompletionQueue only visible to friend classes
-  CompletionQueue(const grpc_completion_queue_attributes& attributes) {
-    cq_ = g_core_codegen_interface->grpc_completion_queue_create(
-        g_core_codegen_interface->grpc_completion_queue_factory_lookup(
-            &attributes),
-        &attributes, NULL);
-    InitialAvalanching();  // reserve this for the future shutdown
-  }
-
- private:
-  // Friend synchronous wrappers so that they can access Pluck(), which is
-  // a semi-private API geared towards the synchronous implementation.
-  template <class R>
-  friend class ::grpc::ClientReader;
-  template <class W>
-  friend class ::grpc::ClientWriter;
-  template <class W, class R>
-  friend class ::grpc::ClientReaderWriter;
-  template <class R>
-  friend class ::grpc::ServerReader;
-  template <class W>
-  friend class ::grpc::ServerWriter;
-  template <class W, class R>
-  friend class ::grpc::internal::ServerReaderWriterBody;
-  template <class ServiceType, class RequestType, class ResponseType>
-  friend class ::grpc::internal::RpcMethodHandler;
-  template <class ServiceType, class RequestType, class ResponseType>
-  friend class ::grpc::internal::ClientStreamingHandler;
-  template <class ServiceType, class RequestType, class ResponseType>
-  friend class ::grpc::internal::ServerStreamingHandler;
-  template <class Streamer, bool WriteNeeded>
-  friend class ::grpc::internal::TemplatedBidiStreamingHandler;
-  friend class ::grpc::internal::UnknownMethodHandler;
-  friend class ::grpc::Server;
-  friend class ::grpc::ServerContext;
-  friend class ::grpc::ServerInterface;
-  template <class InputMessage, class OutputMessage>
-  friend class ::grpc::internal::BlockingUnaryCallImpl;
-
-  /// EXPERIMENTAL
-  /// Creates a Thread Local cache to store the first event
-  /// On this completion queue queued from this thread.  Once
-  /// initialized, it must be flushed on the same thread.
-  class CompletionQueueTLSCache {
-   public:
-    CompletionQueueTLSCache(CompletionQueue* cq);
-    ~CompletionQueueTLSCache();
-    bool Flush(void** tag, bool* ok);
-
-   private:
-    CompletionQueue* cq_;
-    bool flushed_;
-  };
-
-  NextStatus AsyncNextInternal(void** tag, bool* ok, gpr_timespec deadline);
-
-  /// Wraps \a grpc_completion_queue_pluck.
-  /// \warning Must not be mixed with calls to \a Next.
-  bool Pluck(internal::CompletionQueueTag* tag) {
-    auto deadline =
-        g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_REALTIME);
-    auto ev = g_core_codegen_interface->grpc_completion_queue_pluck(
-        cq_, tag, deadline, nullptr);
-    bool ok = ev.success != 0;
-    void* ignored = tag;
-    GPR_CODEGEN_ASSERT(tag->FinalizeResult(&ignored, &ok));
-    GPR_CODEGEN_ASSERT(ignored == tag);
-    // Ignore mutations by FinalizeResult: Pluck returns the C API status
-    return ev.success != 0;
-  }
-
-  /// Performs a single polling pluck on \a tag.
-  /// \warning Must not be mixed with calls to \a Next.
-  ///
-  /// TODO: sreek - This calls tag->FinalizeResult() even if the cq_ is already
-  /// shutdown. This is most likely a bug and if it is a bug, then change this
-  /// implementation to simple call the other TryPluck function with a zero
-  /// timeout. i.e:
-  ///      TryPluck(tag, gpr_time_0(GPR_CLOCK_REALTIME))
-  void TryPluck(internal::CompletionQueueTag* tag) {
-    auto deadline = g_core_codegen_interface->gpr_time_0(GPR_CLOCK_REALTIME);
-    auto ev = g_core_codegen_interface->grpc_completion_queue_pluck(
-        cq_, tag, deadline, nullptr);
-    if (ev.type == GRPC_QUEUE_TIMEOUT) return;
-    bool ok = ev.success != 0;
-    void* ignored = tag;
-    // the tag must be swallowed if using TryPluck
-    GPR_CODEGEN_ASSERT(!tag->FinalizeResult(&ignored, &ok));
-  }
-
-  /// Performs a single polling pluck on \a tag. Calls tag->FinalizeResult if
-  /// the pluck() was successful and returned the tag.
-  ///
-  /// This exects tag->FinalizeResult (if called) to return 'false' i.e expects
-  /// that the tag is internal not something that is returned to the user.
-  void TryPluck(internal::CompletionQueueTag* tag, gpr_timespec deadline) {
-    auto ev = g_core_codegen_interface->grpc_completion_queue_pluck(
-        cq_, tag, deadline, nullptr);
-    if (ev.type == GRPC_QUEUE_TIMEOUT || ev.type == GRPC_QUEUE_SHUTDOWN) {
-      return;
-    }
-
-    bool ok = ev.success != 0;
-    void* ignored = tag;
-    GPR_CODEGEN_ASSERT(!tag->FinalizeResult(&ignored, &ok));
-  }
-
-  /// Manage state of avalanching operations : completion queue tags that
-  /// trigger other completion queue operations. The underlying core completion
-  /// queue should not really shutdown until all avalanching operations have
-  /// been finalized. Note that we maintain the requirement that an avalanche
-  /// registration must take place before CQ shutdown (which must be maintained
-  /// elsehwere)
-  void InitialAvalanching() {
-    gpr_atm_rel_store(&avalanches_in_flight_, static_cast<gpr_atm>(1));
-  }
-  void RegisterAvalanching() {
-    gpr_atm_no_barrier_fetch_add(&avalanches_in_flight_,
-                                 static_cast<gpr_atm>(1));
-  }
-  void CompleteAvalanching();
-
-  grpc_completion_queue* cq_;  // owned
-
-  gpr_atm avalanches_in_flight_;
-};
-
-/// A specific type of completion queue used by the processing of notifications
-/// by servers. Instantiated by \a ServerBuilder.
-class ServerCompletionQueue : public CompletionQueue {
- public:
-  bool IsFrequentlyPolled() { return polling_type_ != GRPC_CQ_NON_LISTENING; }
-
- private:
-  grpc_cq_polling_type polling_type_;
-  friend class ServerBuilder;
-  /// \param is_frequently_polled Informs the GRPC library about whether the
-  /// server completion queue would be actively polled (by calling Next() or
-  /// AsyncNext()). By default all server completion queues are assumed to be
-  /// frequently polled.
-  ServerCompletionQueue(grpc_cq_polling_type polling_type)
-      : CompletionQueue(grpc_completion_queue_attributes{
-            GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, polling_type}),
-        polling_type_(polling_type) {}
-};
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/completion_queue.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_COMPLETION_QUEUE_H
diff --git a/include/grpc++/impl/codegen/completion_queue_tag.h b/include/grpc++/impl/codegen/completion_queue_tag.h
index cb16bcf..994fa2a 100644
--- a/include/grpc++/impl/codegen/completion_queue_tag.h
+++ b/include/grpc++/impl/codegen/completion_queue_tag.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,24 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_COMPLETION_QUEUE_TAG_H
 #define GRPCXX_IMPL_CODEGEN_COMPLETION_QUEUE_TAG_H
 
-namespace grpc {
-
-namespace internal {
-/// An interface allowing implementors to process and filter event tags.
-class CompletionQueueTag {
- public:
-  virtual ~CompletionQueueTag() {}
-  /// Called prior to returning from Next(), return value is the status of the
-  /// operation (return status is the default thing to do). If this function
-  /// returns false, the tag is dropped and not returned from the completion
-  /// queue
-  virtual bool FinalizeResult(void** tag, bool* status) = 0;
-};
-}  // namespace internal
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/completion_queue_tag.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_COMPLETION_QUEUE_TAG_H
diff --git a/include/grpc++/impl/codegen/config.h b/include/grpc++/impl/codegen/config.h
index b5ac9a7..237bf38 100644
--- a/include/grpc++/impl/codegen/config.h
+++ b/include/grpc++/impl/codegen/config.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,26 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_CONFIG_H
 #define GRPCXX_IMPL_CODEGEN_CONFIG_H
 
-#ifndef GRPC_CUSTOM_STRING
-#include <string>
-#define GRPC_CUSTOM_STRING std::string
-#endif
-
-/// The following macros are deprecated and appear only for users
-/// with PB files generated using gRPC 1.0.x plugins. They should
-/// not be used in new code
-#define GRPC_OVERRIDE override  // deprecated
-#define GRPC_FINAL final        // deprecated
-
-namespace grpc {
-
-typedef GRPC_CUSTOM_STRING string;
-
-using std::to_string;
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/config.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_CONFIG_H
diff --git a/include/grpc++/impl/codegen/config_protobuf.h b/include/grpc++/impl/codegen/config_protobuf.h
index 7387fa2..debd74a 100644
--- a/include/grpc++/impl/codegen/config_protobuf.h
+++ b/include/grpc++/impl/codegen/config_protobuf.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,80 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_CONFIG_PROTOBUF_H
 #define GRPCXX_IMPL_CODEGEN_CONFIG_PROTOBUF_H
 
-#define GRPC_OPEN_SOURCE_PROTO
-
-#ifndef GRPC_CUSTOM_PROTOBUF_INT64
-#include <google/protobuf/stubs/common.h>
-#define GRPC_CUSTOM_PROTOBUF_INT64 ::google::protobuf::int64
-#endif
-
-#ifndef GRPC_CUSTOM_MESSAGE
-#ifdef GRPC_USE_PROTO_LITE
-#include <google/protobuf/message_lite.h>
-#define GRPC_CUSTOM_MESSAGE ::google::protobuf::MessageLite
-#else
-#include <google/protobuf/message.h>
-#define GRPC_CUSTOM_MESSAGE ::google::protobuf::Message
-#endif
-#endif
-
-#ifndef GRPC_CUSTOM_DESCRIPTOR
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/descriptor.pb.h>
-#define GRPC_CUSTOM_DESCRIPTOR ::google::protobuf::Descriptor
-#define GRPC_CUSTOM_DESCRIPTORPOOL ::google::protobuf::DescriptorPool
-#define GRPC_CUSTOM_FIELDDESCRIPTOR ::google::protobuf::FieldDescriptor
-#define GRPC_CUSTOM_FILEDESCRIPTOR ::google::protobuf::FileDescriptor
-#define GRPC_CUSTOM_FILEDESCRIPTORPROTO ::google::protobuf::FileDescriptorProto
-#define GRPC_CUSTOM_METHODDESCRIPTOR ::google::protobuf::MethodDescriptor
-#define GRPC_CUSTOM_SERVICEDESCRIPTOR ::google::protobuf::ServiceDescriptor
-#define GRPC_CUSTOM_SOURCELOCATION ::google::protobuf::SourceLocation
-#endif
-
-#ifndef GRPC_CUSTOM_DESCRIPTORDATABASE
-#include <google/protobuf/descriptor_database.h>
-#define GRPC_CUSTOM_DESCRIPTORDATABASE ::google::protobuf::DescriptorDatabase
-#define GRPC_CUSTOM_SIMPLEDESCRIPTORDATABASE \
-  ::google::protobuf::SimpleDescriptorDatabase
-#endif
-
-#ifndef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/io/zero_copy_stream.h>
-#define GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM \
-  ::google::protobuf::io::ZeroCopyOutputStream
-#define GRPC_CUSTOM_ZEROCOPYINPUTSTREAM \
-  ::google::protobuf::io::ZeroCopyInputStream
-#define GRPC_CUSTOM_CODEDINPUTSTREAM ::google::protobuf::io::CodedInputStream
-#endif
-
-namespace grpc {
-namespace protobuf {
-
-typedef GRPC_CUSTOM_MESSAGE Message;
-typedef GRPC_CUSTOM_PROTOBUF_INT64 int64;
-
-typedef GRPC_CUSTOM_DESCRIPTOR Descriptor;
-typedef GRPC_CUSTOM_DESCRIPTORPOOL DescriptorPool;
-typedef GRPC_CUSTOM_DESCRIPTORDATABASE DescriptorDatabase;
-typedef GRPC_CUSTOM_FIELDDESCRIPTOR FieldDescriptor;
-typedef GRPC_CUSTOM_FILEDESCRIPTOR FileDescriptor;
-typedef GRPC_CUSTOM_FILEDESCRIPTORPROTO FileDescriptorProto;
-typedef GRPC_CUSTOM_METHODDESCRIPTOR MethodDescriptor;
-typedef GRPC_CUSTOM_SERVICEDESCRIPTOR ServiceDescriptor;
-typedef GRPC_CUSTOM_SIMPLEDESCRIPTORDATABASE SimpleDescriptorDatabase;
-typedef GRPC_CUSTOM_SOURCELOCATION SourceLocation;
-
-namespace io {
-typedef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM ZeroCopyOutputStream;
-typedef GRPC_CUSTOM_ZEROCOPYINPUTSTREAM ZeroCopyInputStream;
-typedef GRPC_CUSTOM_CODEDINPUTSTREAM CodedInputStream;
-}  // namespace io
-
-}  // namespace protobuf
-}  // namespace grpc
+#include <grpcpp/impl/codegen/config_protobuf.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_CONFIG_PROTOBUF_H
diff --git a/include/grpc++/impl/codegen/core_codegen.h b/include/grpc++/impl/codegen/core_codegen.h
index d7c57be..ee600a9 100644
--- a/include/grpc++/impl/codegen/core_codegen.h
+++ b/include/grpc++/impl/codegen/core_codegen.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,102 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_CORE_CODEGEN_H
 #define GRPCXX_IMPL_CODEGEN_CORE_CODEGEN_H
 
-// This file should be compiled as part of grpc++.
-
-#include <grpc++/impl/codegen/core_codegen_interface.h>
-#include <grpc/byte_buffer.h>
-#include <grpc/grpc.h>
-#include <grpc/impl/codegen/grpc_types.h>
-
-namespace grpc {
-
-/// Implementation of the core codegen interface.
-class CoreCodegen final : public CoreCodegenInterface {
- private:
-  virtual const grpc_completion_queue_factory*
-  grpc_completion_queue_factory_lookup(
-      const grpc_completion_queue_attributes* attributes) override;
-  virtual grpc_completion_queue* grpc_completion_queue_create(
-      const grpc_completion_queue_factory* factory,
-      const grpc_completion_queue_attributes* attributes,
-      void* reserved) override;
-  grpc_completion_queue* grpc_completion_queue_create_for_next(
-      void* reserved) override;
-  grpc_completion_queue* grpc_completion_queue_create_for_pluck(
-      void* reserved) override;
-  void grpc_completion_queue_destroy(grpc_completion_queue* cq) override;
-  grpc_event grpc_completion_queue_pluck(grpc_completion_queue* cq, void* tag,
-                                         gpr_timespec deadline,
-                                         void* reserved) override;
-
-  void* gpr_malloc(size_t size) override;
-  void gpr_free(void* p) override;
-
-  void grpc_init() override;
-  void grpc_shutdown() override;
-
-  void gpr_mu_init(gpr_mu* mu) override;
-  void gpr_mu_destroy(gpr_mu* mu) override;
-  void gpr_mu_lock(gpr_mu* mu) override;
-  void gpr_mu_unlock(gpr_mu* mu) override;
-  void gpr_cv_init(gpr_cv* cv) override;
-  void gpr_cv_destroy(gpr_cv* cv) override;
-  int gpr_cv_wait(gpr_cv* cv, gpr_mu* mu, gpr_timespec abs_deadline) override;
-  void gpr_cv_signal(gpr_cv* cv) override;
-  void gpr_cv_broadcast(gpr_cv* cv) override;
-
-  grpc_call_error grpc_call_cancel_with_status(grpc_call* call,
-                                               grpc_status_code status,
-                                               const char* description,
-                                               void* reserved) override;
-  void grpc_call_ref(grpc_call* call) override;
-  void grpc_call_unref(grpc_call* call) override;
-  virtual void* grpc_call_arena_alloc(grpc_call* call, size_t length) override;
-
-  grpc_byte_buffer* grpc_byte_buffer_copy(grpc_byte_buffer* bb) override;
-  void grpc_byte_buffer_destroy(grpc_byte_buffer* bb) override;
-
-  int grpc_byte_buffer_reader_init(grpc_byte_buffer_reader* reader,
-                                   grpc_byte_buffer* buffer) override;
-  void grpc_byte_buffer_reader_destroy(
-      grpc_byte_buffer_reader* reader) override;
-  int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader* reader,
-                                   grpc_slice* slice) override;
-
-  grpc_byte_buffer* grpc_raw_byte_buffer_create(grpc_slice* slice,
-                                                size_t nslices) override;
-  grpc_slice grpc_slice_new_with_user_data(void* p, size_t len,
-                                           void (*destroy)(void*),
-                                           void* user_data) override;
-  grpc_slice grpc_empty_slice() override;
-  grpc_slice grpc_slice_malloc(size_t length) override;
-  void grpc_slice_unref(grpc_slice slice) override;
-  grpc_slice grpc_slice_ref(grpc_slice slice) override;
-  grpc_slice grpc_slice_split_tail(grpc_slice* s, size_t split) override;
-  grpc_slice grpc_slice_split_head(grpc_slice* s, size_t split) override;
-  grpc_slice grpc_slice_sub(grpc_slice s, size_t begin, size_t end) override;
-  void grpc_slice_buffer_add(grpc_slice_buffer* sb, grpc_slice slice) override;
-  void grpc_slice_buffer_pop(grpc_slice_buffer* sb) override;
-  grpc_slice grpc_slice_from_static_buffer(const void* buffer,
-                                           size_t length) override;
-  grpc_slice grpc_slice_from_copied_buffer(const void* buffer,
-                                           size_t length) override;
-  void grpc_metadata_array_init(grpc_metadata_array* array) override;
-  void grpc_metadata_array_destroy(grpc_metadata_array* array) override;
-
-  gpr_timespec gpr_inf_future(gpr_clock_type type) override;
-  gpr_timespec gpr_time_0(gpr_clock_type type) override;
-
-  virtual const Status& ok() override;
-  virtual const Status& cancelled() override;
-
-  void assert_fail(const char* failed_assertion, const char* file,
-                   int line) override;
-};
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/core_codegen.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_CORE_CODEGEN_H
diff --git a/include/grpc++/impl/codegen/core_codegen_interface.h b/include/grpc++/impl/codegen/core_codegen_interface.h
index d7ad7a4..03b3f67 100644
--- a/include/grpc++/impl/codegen/core_codegen_interface.h
+++ b/include/grpc++/impl/codegen/core_codegen_interface.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,125 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H
 #define GRPCXX_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H
 
-#include <grpc++/impl/codegen/config.h>
-#include <grpc++/impl/codegen/status.h>
-#include <grpc/impl/codegen/byte_buffer_reader.h>
-#include <grpc/impl/codegen/grpc_types.h>
-#include <grpc/impl/codegen/sync.h>
-
-namespace grpc {
-
-/// Interface between the codegen library and the minimal subset of core
-/// features required by the generated code.
-///
-/// All undocumented methods are simply forwarding the call to their namesakes.
-/// Please refer to their corresponding documentation for details.
-///
-/// \warning This interface should be considered internal and private.
-class CoreCodegenInterface {
- public:
-  /// Upon a failed assertion, log the error.
-  virtual void assert_fail(const char* failed_assertion, const char* file,
-                           int line) = 0;
-
-  virtual const grpc_completion_queue_factory*
-  grpc_completion_queue_factory_lookup(
-      const grpc_completion_queue_attributes* attributes) = 0;
-  virtual grpc_completion_queue* grpc_completion_queue_create(
-      const grpc_completion_queue_factory* factory,
-      const grpc_completion_queue_attributes* attributes, void* reserved) = 0;
-  virtual grpc_completion_queue* grpc_completion_queue_create_for_next(
-      void* reserved) = 0;
-  virtual grpc_completion_queue* grpc_completion_queue_create_for_pluck(
-      void* reserved) = 0;
-  virtual void grpc_completion_queue_destroy(grpc_completion_queue* cq) = 0;
-  virtual grpc_event grpc_completion_queue_pluck(grpc_completion_queue* cq,
-                                                 void* tag,
-                                                 gpr_timespec deadline,
-                                                 void* reserved) = 0;
-
-  virtual void* gpr_malloc(size_t size) = 0;
-  virtual void gpr_free(void* p) = 0;
-
-  // These are only to be used to fix edge cases involving grpc_init and
-  // grpc_shutdown. Calling grpc_init from the codegen interface before
-  // the real grpc_init is called will cause a crash, so if you use this
-  // function, ensure that it is not the first call to grpc_init.
-  virtual void grpc_init() = 0;
-  virtual void grpc_shutdown() = 0;
-
-  virtual void gpr_mu_init(gpr_mu* mu) = 0;
-  virtual void gpr_mu_destroy(gpr_mu* mu) = 0;
-  virtual void gpr_mu_lock(gpr_mu* mu) = 0;
-  virtual void gpr_mu_unlock(gpr_mu* mu) = 0;
-  virtual void gpr_cv_init(gpr_cv* cv) = 0;
-  virtual void gpr_cv_destroy(gpr_cv* cv) = 0;
-  virtual int gpr_cv_wait(gpr_cv* cv, gpr_mu* mu,
-                          gpr_timespec abs_deadline) = 0;
-  virtual void gpr_cv_signal(gpr_cv* cv) = 0;
-  virtual void gpr_cv_broadcast(gpr_cv* cv) = 0;
-
-  virtual grpc_byte_buffer* grpc_byte_buffer_copy(grpc_byte_buffer* bb) = 0;
-  virtual void grpc_byte_buffer_destroy(grpc_byte_buffer* bb) = 0;
-
-  virtual int grpc_byte_buffer_reader_init(grpc_byte_buffer_reader* reader,
-                                           grpc_byte_buffer* buffer)
-      GRPC_MUST_USE_RESULT = 0;
-  virtual void grpc_byte_buffer_reader_destroy(
-      grpc_byte_buffer_reader* reader) = 0;
-  virtual int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader* reader,
-                                           grpc_slice* slice) = 0;
-
-  virtual grpc_byte_buffer* grpc_raw_byte_buffer_create(grpc_slice* slice,
-                                                        size_t nslices) = 0;
-  virtual grpc_slice grpc_slice_new_with_user_data(void* p, size_t len,
-                                                   void (*destroy)(void*),
-                                                   void* user_data) = 0;
-  virtual grpc_call_error grpc_call_cancel_with_status(grpc_call* call,
-                                                       grpc_status_code status,
-                                                       const char* description,
-                                                       void* reserved) = 0;
-  virtual void grpc_call_ref(grpc_call* call) = 0;
-  virtual void grpc_call_unref(grpc_call* call) = 0;
-  virtual void* grpc_call_arena_alloc(grpc_call* call, size_t length) = 0;
-  virtual grpc_slice grpc_empty_slice() = 0;
-  virtual grpc_slice grpc_slice_malloc(size_t length) = 0;
-  virtual void grpc_slice_unref(grpc_slice slice) = 0;
-  virtual grpc_slice grpc_slice_ref(grpc_slice slice) = 0;
-  virtual grpc_slice grpc_slice_split_tail(grpc_slice* s, size_t split) = 0;
-  virtual grpc_slice grpc_slice_split_head(grpc_slice* s, size_t split) = 0;
-  virtual grpc_slice grpc_slice_sub(grpc_slice s, size_t begin, size_t end) = 0;
-  virtual void grpc_slice_buffer_add(grpc_slice_buffer* sb,
-                                     grpc_slice slice) = 0;
-  virtual void grpc_slice_buffer_pop(grpc_slice_buffer* sb) = 0;
-  virtual grpc_slice grpc_slice_from_static_buffer(const void* buffer,
-                                                   size_t length) = 0;
-  virtual grpc_slice grpc_slice_from_copied_buffer(const void* buffer,
-                                                   size_t length) = 0;
-
-  virtual void grpc_metadata_array_init(grpc_metadata_array* array) = 0;
-  virtual void grpc_metadata_array_destroy(grpc_metadata_array* array) = 0;
-
-  virtual const Status& ok() = 0;
-  virtual const Status& cancelled() = 0;
-
-  virtual gpr_timespec gpr_inf_future(gpr_clock_type type) = 0;
-  virtual gpr_timespec gpr_time_0(gpr_clock_type type) = 0;
-};
-
-extern CoreCodegenInterface* g_core_codegen_interface;
-
-/// Codegen specific version of \a GPR_ASSERT.
-#define GPR_CODEGEN_ASSERT(x)                                              \
-  do {                                                                     \
-    if (!(x)) {                                                            \
-      grpc::g_core_codegen_interface->assert_fail(#x, __FILE__, __LINE__); \
-    }                                                                      \
-  } while (0)
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H
diff --git a/include/grpc++/impl/codegen/create_auth_context.h b/include/grpc++/impl/codegen/create_auth_context.h
index afa6302..ef89229 100644
--- a/include/grpc++/impl/codegen/create_auth_context.h
+++ b/include/grpc++/impl/codegen/create_auth_context.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,18 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_CREATE_AUTH_CONTEXT_H
 #define GRPCXX_IMPL_CODEGEN_CREATE_AUTH_CONTEXT_H
 
-#include <memory>
-
-#include <grpc++/impl/codegen/security/auth_context.h>
-#include <grpc/impl/codegen/grpc_types.h>
-
-namespace grpc {
-
-std::shared_ptr<const AuthContext> CreateAuthContext(grpc_call* call);
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/create_auth_context.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_CREATE_AUTH_CONTEXT_H
diff --git a/include/grpc++/impl/codegen/grpc_library.h b/include/grpc++/impl/codegen/grpc_library.h
index 6036ad7..33c3e25 100644
--- a/include/grpc++/impl/codegen/grpc_library.h
+++ b/include/grpc++/impl/codegen/grpc_library.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,48 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_GRPC_LIBRARY_H
 #define GRPCXX_IMPL_CODEGEN_GRPC_LIBRARY_H
 
-#include <grpc++/impl/codegen/core_codegen_interface.h>
-
-namespace grpc {
-
-class GrpcLibraryInterface {
- public:
-  virtual void init() = 0;
-  virtual void shutdown() = 0;
-};
-
-/// Initialized by \a grpc::GrpcLibraryInitializer from
-/// <grpc++/impl/grpc_library.h>
-extern GrpcLibraryInterface* g_glip;
-
-/// Classes that require gRPC to be initialized should inherit from this class.
-class GrpcLibraryCodegen {
- public:
-  GrpcLibraryCodegen(bool call_grpc_init = true) : grpc_init_called_(false) {
-    if (call_grpc_init) {
-      GPR_CODEGEN_ASSERT(g_glip &&
-                         "gRPC library not initialized. See "
-                         "grpc::internal::GrpcLibraryInitializer.");
-      g_glip->init();
-      grpc_init_called_ = true;
-    }
-  }
-  virtual ~GrpcLibraryCodegen() {
-    if (grpc_init_called_) {
-      GPR_CODEGEN_ASSERT(g_glip &&
-                         "gRPC library not initialized. See "
-                         "grpc::internal::GrpcLibraryInitializer.");
-      g_glip->shutdown();
-    }
-  }
-
- private:
-  bool grpc_init_called_;
-};
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/grpc_library.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_GRPC_LIBRARY_H
diff --git a/include/grpc++/impl/codegen/metadata_map.h b/include/grpc++/impl/codegen/metadata_map.h
index 8dc7211..41c5ad3 100644
--- a/include/grpc++/impl/codegen/metadata_map.h
+++ b/include/grpc++/impl/codegen/metadata_map.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,43 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_METADATA_MAP_H
 #define GRPCXX_IMPL_CODEGEN_METADATA_MAP_H
 
-#include <grpc++/impl/codegen/slice.h>
-
-namespace grpc {
-
-namespace internal {
-class MetadataMap {
- public:
-  MetadataMap() { memset(&arr_, 0, sizeof(arr_)); }
-
-  ~MetadataMap() {
-    g_core_codegen_interface->grpc_metadata_array_destroy(&arr_);
-  }
-
-  void FillMap() {
-    for (size_t i = 0; i < arr_.count; i++) {
-      // TODO(yangg) handle duplicates?
-      map_.insert(std::pair<grpc::string_ref, grpc::string_ref>(
-          StringRefFromSlice(&arr_.metadata[i].key),
-          StringRefFromSlice(&arr_.metadata[i].value)));
-    }
-  }
-
-  std::multimap<grpc::string_ref, grpc::string_ref>* map() { return &map_; }
-  const std::multimap<grpc::string_ref, grpc::string_ref>* map() const {
-    return &map_;
-  }
-  grpc_metadata_array* arr() { return &arr_; }
-
- private:
-  grpc_metadata_array arr_;
-  std::multimap<grpc::string_ref, grpc::string_ref> map_;
-};
-}  // namespace internal
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/metadata_map.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_METADATA_MAP_H
diff --git a/include/grpc++/impl/codegen/method_handler_impl.h b/include/grpc++/impl/codegen/method_handler_impl.h
index daf090f..0bdb620 100644
--- a/include/grpc++/impl/codegen/method_handler_impl.h
+++ b/include/grpc++/impl/codegen/method_handler_impl.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,287 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_METHOD_HANDLER_IMPL_H
 #define GRPCXX_IMPL_CODEGEN_METHOD_HANDLER_IMPL_H
 
-#include <grpc++/impl/codegen/byte_buffer.h>
-#include <grpc++/impl/codegen/core_codegen_interface.h>
-#include <grpc++/impl/codegen/rpc_service_method.h>
-#include <grpc++/impl/codegen/sync_stream.h>
-
-namespace grpc {
-
-namespace internal {
-
-// Invoke the method handler, fill in the status, and
-// return whether or not we finished safely (without an exception).
-// Note that exception handling is 0-cost in most compiler/library
-// implementations (except when an exception is actually thrown),
-// so this process doesn't require additional overhead in the common case.
-// Additionally, we don't need to return if we caught an exception or not;
-// the handling is the same in either case.
-template <class Callable>
-Status CatchingFunctionHandler(Callable&& handler) {
-#if GRPC_ALLOW_EXCEPTIONS
-  try {
-    return handler();
-  } catch (...) {
-    return Status(StatusCode::UNKNOWN, "Unexpected error in RPC handling");
-  }
-#else   // GRPC_ALLOW_EXCEPTIONS
-  return handler();
-#endif  // GRPC_ALLOW_EXCEPTIONS
-}
-
-/// A wrapper class of an application provided rpc method handler.
-template <class ServiceType, class RequestType, class ResponseType>
-class RpcMethodHandler : public MethodHandler {
- public:
-  RpcMethodHandler(std::function<Status(ServiceType*, ServerContext*,
-                                        const RequestType*, ResponseType*)>
-                       func,
-                   ServiceType* service)
-      : func_(func), service_(service) {}
-
-  void RunHandler(const HandlerParameter& param) final {
-    RequestType req;
-    Status status = SerializationTraits<RequestType>::Deserialize(
-        param.request.bbuf_ptr(), &req);
-    ResponseType rsp;
-    if (status.ok()) {
-      status = CatchingFunctionHandler([this, &param, &req, &rsp] {
-        return func_(service_, param.server_context, &req, &rsp);
-      });
-    }
-
-    GPR_CODEGEN_ASSERT(!param.server_context->sent_initial_metadata_);
-    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
-              CallOpServerSendStatus>
-        ops;
-    ops.SendInitialMetadata(param.server_context->initial_metadata_,
-                            param.server_context->initial_metadata_flags());
-    if (param.server_context->compression_level_set()) {
-      ops.set_compression_level(param.server_context->compression_level());
-    }
-    if (status.ok()) {
-      status = ops.SendMessage(rsp);
-    }
-    ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
-    param.call->PerformOps(&ops);
-    param.call->cq()->Pluck(&ops);
-  }
-
- private:
-  /// Application provided rpc handler function.
-  std::function<Status(ServiceType*, ServerContext*, const RequestType*,
-                       ResponseType*)>
-      func_;
-  // The class the above handler function lives in.
-  ServiceType* service_;
-};
-
-/// A wrapper class of an application provided client streaming handler.
-template <class ServiceType, class RequestType, class ResponseType>
-class ClientStreamingHandler : public MethodHandler {
- public:
-  ClientStreamingHandler(
-      std::function<Status(ServiceType*, ServerContext*,
-                           ServerReader<RequestType>*, ResponseType*)>
-          func,
-      ServiceType* service)
-      : func_(func), service_(service) {}
-
-  void RunHandler(const HandlerParameter& param) final {
-    ServerReader<RequestType> reader(param.call, param.server_context);
-    ResponseType rsp;
-    Status status = CatchingFunctionHandler([this, &param, &reader, &rsp] {
-      return func_(service_, param.server_context, &reader, &rsp);
-    });
-
-    GPR_CODEGEN_ASSERT(!param.server_context->sent_initial_metadata_);
-    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
-              CallOpServerSendStatus>
-        ops;
-    ops.SendInitialMetadata(param.server_context->initial_metadata_,
-                            param.server_context->initial_metadata_flags());
-    if (param.server_context->compression_level_set()) {
-      ops.set_compression_level(param.server_context->compression_level());
-    }
-    if (status.ok()) {
-      status = ops.SendMessage(rsp);
-    }
-    ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
-    param.call->PerformOps(&ops);
-    param.call->cq()->Pluck(&ops);
-  }
-
- private:
-  std::function<Status(ServiceType*, ServerContext*, ServerReader<RequestType>*,
-                       ResponseType*)>
-      func_;
-  ServiceType* service_;
-};
-
-/// A wrapper class of an application provided server streaming handler.
-template <class ServiceType, class RequestType, class ResponseType>
-class ServerStreamingHandler : public MethodHandler {
- public:
-  ServerStreamingHandler(
-      std::function<Status(ServiceType*, ServerContext*, const RequestType*,
-                           ServerWriter<ResponseType>*)>
-          func,
-      ServiceType* service)
-      : func_(func), service_(service) {}
-
-  void RunHandler(const HandlerParameter& param) final {
-    RequestType req;
-    Status status = SerializationTraits<RequestType>::Deserialize(
-        param.request.bbuf_ptr(), &req);
-
-    if (status.ok()) {
-      ServerWriter<ResponseType> writer(param.call, param.server_context);
-      status = CatchingFunctionHandler([this, &param, &req, &writer] {
-        return func_(service_, param.server_context, &req, &writer);
-      });
-    }
-
-    CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> ops;
-    if (!param.server_context->sent_initial_metadata_) {
-      ops.SendInitialMetadata(param.server_context->initial_metadata_,
-                              param.server_context->initial_metadata_flags());
-      if (param.server_context->compression_level_set()) {
-        ops.set_compression_level(param.server_context->compression_level());
-      }
-    }
-    ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
-    param.call->PerformOps(&ops);
-    if (param.server_context->has_pending_ops_) {
-      param.call->cq()->Pluck(&param.server_context->pending_ops_);
-    }
-    param.call->cq()->Pluck(&ops);
-  }
-
- private:
-  std::function<Status(ServiceType*, ServerContext*, const RequestType*,
-                       ServerWriter<ResponseType>*)>
-      func_;
-  ServiceType* service_;
-};
-
-/// A wrapper class of an application provided bidi-streaming handler.
-/// This also applies to server-streamed implementation of a unary method
-/// with the additional requirement that such methods must have done a
-/// write for status to be ok
-/// Since this is used by more than 1 class, the service is not passed in.
-/// Instead, it is expected to be an implicitly-captured argument of func
-/// (through bind or something along those lines)
-template <class Streamer, bool WriteNeeded>
-class TemplatedBidiStreamingHandler : public MethodHandler {
- public:
-  TemplatedBidiStreamingHandler(
-      std::function<Status(ServerContext*, Streamer*)> func)
-      : func_(func), write_needed_(WriteNeeded) {}
-
-  void RunHandler(const HandlerParameter& param) final {
-    Streamer stream(param.call, param.server_context);
-    Status status = CatchingFunctionHandler([this, &param, &stream] {
-      return func_(param.server_context, &stream);
-    });
-
-    CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> ops;
-    if (!param.server_context->sent_initial_metadata_) {
-      ops.SendInitialMetadata(param.server_context->initial_metadata_,
-                              param.server_context->initial_metadata_flags());
-      if (param.server_context->compression_level_set()) {
-        ops.set_compression_level(param.server_context->compression_level());
-      }
-      if (write_needed_ && status.ok()) {
-        // If we needed a write but never did one, we need to mark the
-        // status as a fail
-        status = Status(StatusCode::INTERNAL,
-                        "Service did not provide response message");
-      }
-    }
-    ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
-    param.call->PerformOps(&ops);
-    if (param.server_context->has_pending_ops_) {
-      param.call->cq()->Pluck(&param.server_context->pending_ops_);
-    }
-    param.call->cq()->Pluck(&ops);
-  }
-
- private:
-  std::function<Status(ServerContext*, Streamer*)> func_;
-  const bool write_needed_;
-};
-
-template <class ServiceType, class RequestType, class ResponseType>
-class BidiStreamingHandler
-    : public TemplatedBidiStreamingHandler<
-          ServerReaderWriter<ResponseType, RequestType>, false> {
- public:
-  BidiStreamingHandler(
-      std::function<Status(ServiceType*, ServerContext*,
-                           ServerReaderWriter<ResponseType, RequestType>*)>
-          func,
-      ServiceType* service)
-      : TemplatedBidiStreamingHandler<
-            ServerReaderWriter<ResponseType, RequestType>, false>(std::bind(
-            func, service, std::placeholders::_1, std::placeholders::_2)) {}
-};
-
-template <class RequestType, class ResponseType>
-class StreamedUnaryHandler
-    : public TemplatedBidiStreamingHandler<
-          ServerUnaryStreamer<RequestType, ResponseType>, true> {
- public:
-  explicit StreamedUnaryHandler(
-      std::function<Status(ServerContext*,
-                           ServerUnaryStreamer<RequestType, ResponseType>*)>
-          func)
-      : TemplatedBidiStreamingHandler<
-            ServerUnaryStreamer<RequestType, ResponseType>, true>(func) {}
-};
-
-template <class RequestType, class ResponseType>
-class SplitServerStreamingHandler
-    : public TemplatedBidiStreamingHandler<
-          ServerSplitStreamer<RequestType, ResponseType>, false> {
- public:
-  explicit SplitServerStreamingHandler(
-      std::function<Status(ServerContext*,
-                           ServerSplitStreamer<RequestType, ResponseType>*)>
-          func)
-      : TemplatedBidiStreamingHandler<
-            ServerSplitStreamer<RequestType, ResponseType>, false>(func) {}
-};
-
-/// Handle unknown method by returning UNIMPLEMENTED error.
-class UnknownMethodHandler : public MethodHandler {
- public:
-  template <class T>
-  static void FillOps(ServerContext* context, T* ops) {
-    Status status(StatusCode::UNIMPLEMENTED, "");
-    if (!context->sent_initial_metadata_) {
-      ops->SendInitialMetadata(context->initial_metadata_,
-                               context->initial_metadata_flags());
-      if (context->compression_level_set()) {
-        ops->set_compression_level(context->compression_level());
-      }
-      context->sent_initial_metadata_ = true;
-    }
-    ops->ServerSendStatus(context->trailing_metadata_, status);
-  }
-
-  void RunHandler(const HandlerParameter& param) final {
-    CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> ops;
-    FillOps(param.server_context, &ops);
-    param.call->PerformOps(&ops);
-    param.call->cq()->Pluck(&ops);
-  }
-};
-
-}  // namespace internal
-}  // namespace grpc
+#include <grpcpp/impl/codegen/method_handler_impl.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_METHOD_HANDLER_IMPL_H
diff --git a/include/grpc++/impl/codegen/proto_utils.h b/include/grpc++/impl/codegen/proto_utils.h
index b763603..1f47884 100644
--- a/include/grpc++/impl/codegen/proto_utils.h
+++ b/include/grpc++/impl/codegen/proto_utils.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,249 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_PROTO_UTILS_H
 #define GRPCXX_IMPL_CODEGEN_PROTO_UTILS_H
 
-#include <type_traits>
-
-#include <grpc++/impl/codegen/config_protobuf.h>
-#include <grpc++/impl/codegen/core_codegen_interface.h>
-#include <grpc++/impl/codegen/serialization_traits.h>
-#include <grpc++/impl/codegen/status.h>
-#include <grpc/impl/codegen/byte_buffer_reader.h>
-#include <grpc/impl/codegen/grpc_types.h>
-#include <grpc/impl/codegen/slice.h>
-
-namespace grpc {
-
-extern CoreCodegenInterface* g_core_codegen_interface;
-
-namespace internal {
-
-class GrpcBufferWriterPeer;
-
-const int kGrpcBufferWriterMaxBufferLength = 1024 * 1024;
-
-class GrpcBufferWriter : public ::grpc::protobuf::io::ZeroCopyOutputStream {
- public:
-  GrpcBufferWriter(grpc_byte_buffer** bp, int block_size, int total_size)
-      : block_size_(block_size),
-        total_size_(total_size),
-        byte_count_(0),
-        have_backup_(false) {
-    *bp = g_core_codegen_interface->grpc_raw_byte_buffer_create(NULL, 0);
-    slice_buffer_ = &(*bp)->data.raw.slice_buffer;
-  }
-
-  ~GrpcBufferWriter() override {
-    if (have_backup_) {
-      g_core_codegen_interface->grpc_slice_unref(backup_slice_);
-    }
-  }
-
-  bool Next(void** data, int* size) override {
-    // Protobuf should not ask for more memory than total_size_.
-    GPR_CODEGEN_ASSERT(byte_count_ < total_size_);
-    if (have_backup_) {
-      slice_ = backup_slice_;
-      have_backup_ = false;
-    } else {
-      // When less than a whole block is needed, only allocate that much.
-      // But make sure the allocated slice is not inlined.
-      size_t remain = total_size_ - byte_count_ > block_size_
-                          ? block_size_
-                          : total_size_ - byte_count_;
-      slice_ = g_core_codegen_interface->grpc_slice_malloc(
-          remain > GRPC_SLICE_INLINED_SIZE ? remain
-                                           : GRPC_SLICE_INLINED_SIZE + 1);
-    }
-    *data = GRPC_SLICE_START_PTR(slice_);
-    // On win x64, int is only 32bit
-    GPR_CODEGEN_ASSERT(GRPC_SLICE_LENGTH(slice_) <= INT_MAX);
-    byte_count_ += * size = (int)GRPC_SLICE_LENGTH(slice_);
-    g_core_codegen_interface->grpc_slice_buffer_add(slice_buffer_, slice_);
-    return true;
-  }
-
-  void BackUp(int count) override {
-    g_core_codegen_interface->grpc_slice_buffer_pop(slice_buffer_);
-    if ((size_t)count == GRPC_SLICE_LENGTH(slice_)) {
-      backup_slice_ = slice_;
-    } else {
-      backup_slice_ = g_core_codegen_interface->grpc_slice_split_tail(
-          &slice_, GRPC_SLICE_LENGTH(slice_) - count);
-      g_core_codegen_interface->grpc_slice_buffer_add(slice_buffer_, slice_);
-    }
-    // It's dangerous to keep an inlined grpc_slice as the backup slice, since
-    // on a following Next() call, a reference will be returned to this slice
-    // via GRPC_SLICE_START_PTR, which will not be an adddress held by
-    // slice_buffer_.
-    have_backup_ = backup_slice_.refcount != NULL;
-    byte_count_ -= count;
-  }
-
-  grpc::protobuf::int64 ByteCount() const override { return byte_count_; }
-
- protected:
-  friend class GrpcBufferWriterPeer;
-  const int block_size_;
-  const int total_size_;
-  int64_t byte_count_;
-  grpc_slice_buffer* slice_buffer_;
-  bool have_backup_;
-  grpc_slice backup_slice_;
-  grpc_slice slice_;
-};
-
-class GrpcBufferReader : public ::grpc::protobuf::io::ZeroCopyInputStream {
- public:
-  explicit GrpcBufferReader(grpc_byte_buffer* buffer)
-      : byte_count_(0), backup_count_(0), status_() {
-    if (!g_core_codegen_interface->grpc_byte_buffer_reader_init(&reader_,
-                                                                buffer)) {
-      status_ = Status(StatusCode::INTERNAL,
-                       "Couldn't initialize byte buffer reader");
-    }
-  }
-  ~GrpcBufferReader() override {
-    g_core_codegen_interface->grpc_byte_buffer_reader_destroy(&reader_);
-  }
-
-  bool Next(const void** data, int* size) override {
-    if (!status_.ok()) {
-      return false;
-    }
-    if (backup_count_ > 0) {
-      *data = GRPC_SLICE_START_PTR(slice_) + GRPC_SLICE_LENGTH(slice_) -
-              backup_count_;
-      GPR_CODEGEN_ASSERT(backup_count_ <= INT_MAX);
-      *size = (int)backup_count_;
-      backup_count_ = 0;
-      return true;
-    }
-    if (!g_core_codegen_interface->grpc_byte_buffer_reader_next(&reader_,
-                                                                &slice_)) {
-      return false;
-    }
-    g_core_codegen_interface->grpc_slice_unref(slice_);
-    *data = GRPC_SLICE_START_PTR(slice_);
-    // On win x64, int is only 32bit
-    GPR_CODEGEN_ASSERT(GRPC_SLICE_LENGTH(slice_) <= INT_MAX);
-    byte_count_ += * size = (int)GRPC_SLICE_LENGTH(slice_);
-    return true;
-  }
-
-  Status status() const { return status_; }
-
-  void BackUp(int count) override { backup_count_ = count; }
-
-  bool Skip(int count) override {
-    const void* data;
-    int size;
-    while (Next(&data, &size)) {
-      if (size >= count) {
-        BackUp(size - count);
-        return true;
-      }
-      // size < count;
-      count -= size;
-    }
-    // error or we have too large count;
-    return false;
-  }
-
-  grpc::protobuf::int64 ByteCount() const override {
-    return byte_count_ - backup_count_;
-  }
-
- protected:
-  int64_t byte_count_;
-  int64_t backup_count_;
-  grpc_byte_buffer_reader reader_;
-  grpc_slice slice_;
-  Status status_;
-};
-
-// BufferWriter must be a subclass of io::ZeroCopyOutputStream.
-template <class BufferWriter, class T>
-Status GenericSerialize(const grpc::protobuf::Message& msg,
-                        grpc_byte_buffer** bp, bool* own_buffer) {
-  static_assert(
-      std::is_base_of<protobuf::io::ZeroCopyOutputStream, BufferWriter>::value,
-      "BufferWriter must be a subclass of io::ZeroCopyOutputStream");
-  *own_buffer = true;
-  int byte_size = msg.ByteSize();
-  if ((size_t)byte_size <= GRPC_SLICE_INLINED_SIZE) {
-    grpc_slice slice = g_core_codegen_interface->grpc_slice_malloc(byte_size);
-    GPR_CODEGEN_ASSERT(
-        GRPC_SLICE_END_PTR(slice) ==
-        msg.SerializeWithCachedSizesToArray(GRPC_SLICE_START_PTR(slice)));
-    *bp = g_core_codegen_interface->grpc_raw_byte_buffer_create(&slice, 1);
-    g_core_codegen_interface->grpc_slice_unref(slice);
-
-    return g_core_codegen_interface->ok();
-  }
-  BufferWriter writer(bp, kGrpcBufferWriterMaxBufferLength, byte_size);
-  return msg.SerializeToZeroCopyStream(&writer)
-             ? g_core_codegen_interface->ok()
-             : Status(StatusCode::INTERNAL, "Failed to serialize message");
-}
-
-// BufferReader must be a subclass of io::ZeroCopyInputStream.
-template <class BufferReader, class T>
-Status GenericDeserialize(grpc_byte_buffer* buffer,
-                          grpc::protobuf::Message* msg) {
-  static_assert(
-      std::is_base_of<protobuf::io::ZeroCopyInputStream, BufferReader>::value,
-      "BufferReader must be a subclass of io::ZeroCopyInputStream");
-  if (buffer == nullptr) {
-    return Status(StatusCode::INTERNAL, "No payload");
-  }
-  Status result = g_core_codegen_interface->ok();
-  {
-    BufferReader reader(buffer);
-    if (!reader.status().ok()) {
-      return reader.status();
-    }
-    ::grpc::protobuf::io::CodedInputStream decoder(&reader);
-    decoder.SetTotalBytesLimit(INT_MAX, INT_MAX);
-    if (!msg->ParseFromCodedStream(&decoder)) {
-      result = Status(StatusCode::INTERNAL, msg->InitializationErrorString());
-    }
-    if (!decoder.ConsumedEntireMessage()) {
-      result = Status(StatusCode::INTERNAL, "Did not read entire message");
-    }
-  }
-  g_core_codegen_interface->grpc_byte_buffer_destroy(buffer);
-  return result;
-}
-
-}  // namespace internal
-
-// this is needed so the following class does not conflict with protobuf
-// serializers that utilize internal-only tools.
-#ifdef GRPC_OPEN_SOURCE_PROTO
-// This class provides a protobuf serializer. It translates between protobuf
-// objects and grpc_byte_buffers. More information about SerializationTraits can
-// be found in include/grpc++/impl/codegen/serialization_traits.h.
-template <class T>
-class SerializationTraits<T, typename std::enable_if<std::is_base_of<
-                                 grpc::protobuf::Message, T>::value>::type> {
- public:
-  static Status Serialize(const grpc::protobuf::Message& msg,
-                          grpc_byte_buffer** bp, bool* own_buffer) {
-    return internal::GenericSerialize<internal::GrpcBufferWriter, T>(
-        msg, bp, own_buffer);
-  }
-
-  static Status Deserialize(grpc_byte_buffer* buffer,
-                            grpc::protobuf::Message* msg) {
-    return internal::GenericDeserialize<internal::GrpcBufferReader, T>(buffer,
-                                                                       msg);
-  }
-};
-#endif
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/proto_utils.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_PROTO_UTILS_H
diff --git a/include/grpc++/impl/codegen/rpc_method.h b/include/grpc++/impl/codegen/rpc_method.h
index 54e5236..2906c74 100644
--- a/include/grpc++/impl/codegen/rpc_method.h
+++ b/include/grpc++/impl/codegen/rpc_method.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,46 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_RPC_METHOD_H
 #define GRPCXX_IMPL_CODEGEN_RPC_METHOD_H
 
-#include <memory>
-
-#include <grpc++/impl/codegen/channel_interface.h>
-
-namespace grpc {
-namespace internal {
-/// Descriptor of an RPC method
-class RpcMethod {
- public:
-  enum RpcType {
-    NORMAL_RPC = 0,
-    CLIENT_STREAMING,  // request streaming
-    SERVER_STREAMING,  // response streaming
-    BIDI_STREAMING
-  };
-
-  RpcMethod(const char* name, RpcType type)
-      : name_(name), method_type_(type), channel_tag_(NULL) {}
-
-  RpcMethod(const char* name, RpcType type,
-            const std::shared_ptr<ChannelInterface>& channel)
-      : name_(name),
-        method_type_(type),
-        channel_tag_(channel->RegisterMethod(name)) {}
-
-  const char* name() const { return name_; }
-  RpcType method_type() const { return method_type_; }
-  void SetMethodType(RpcType type) { method_type_ = type; }
-  void* channel_tag() const { return channel_tag_; }
-
- private:
-  const char* const name_;
-  RpcType method_type_;
-  void* const channel_tag_;
-};
-
-}  // namespace internal
-}  // namespace grpc
+#include <grpcpp/impl/codegen/rpc_method.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_RPC_METHOD_H
diff --git a/include/grpc++/impl/codegen/rpc_service_method.h b/include/grpc++/impl/codegen/rpc_service_method.h
index 5ba11e8..999c0d5 100644
--- a/include/grpc++/impl/codegen/rpc_service_method.h
+++ b/include/grpc++/impl/codegen/rpc_service_method.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,63 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_RPC_SERVICE_METHOD_H
 #define GRPCXX_IMPL_CODEGEN_RPC_SERVICE_METHOD_H
 
-#include <climits>
-#include <functional>
-#include <map>
-#include <memory>
-#include <vector>
-
-#include <grpc++/impl/codegen/byte_buffer.h>
-#include <grpc++/impl/codegen/config.h>
-#include <grpc++/impl/codegen/rpc_method.h>
-#include <grpc++/impl/codegen/status.h>
-
-namespace grpc {
-class ServerContext;
-
-namespace internal {
-/// Base class for running an RPC handler.
-class MethodHandler {
- public:
-  virtual ~MethodHandler() {}
-  struct HandlerParameter {
-    HandlerParameter(Call* c, ServerContext* context, grpc_byte_buffer* req)
-        : call(c), server_context(context) {
-      request.set_buffer(req);
-    }
-    ~HandlerParameter() { request.Release(); }
-    Call* call;
-    ServerContext* server_context;
-    // Handler required to destroy these contents
-    ByteBuffer request;
-  };
-  virtual void RunHandler(const HandlerParameter& param) = 0;
-};
-
-/// Server side rpc method class
-class RpcServiceMethod : public RpcMethod {
- public:
-  /// Takes ownership of the handler
-  RpcServiceMethod(const char* name, RpcMethod::RpcType type,
-                   MethodHandler* handler)
-      : RpcMethod(name, type), server_tag_(nullptr), handler_(handler) {}
-
-  void set_server_tag(void* tag) { server_tag_ = tag; }
-  void* server_tag() const { return server_tag_; }
-  /// if MethodHandler is nullptr, then this is an async method
-  MethodHandler* handler() const { return handler_.get(); }
-  void ResetHandler() { handler_.reset(); }
-  void SetHandler(MethodHandler* handler) { handler_.reset(handler); }
-
- private:
-  void* server_tag_;
-  std::unique_ptr<MethodHandler> handler_;
-};
-}  // namespace internal
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/rpc_service_method.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_RPC_SERVICE_METHOD_H
diff --git a/include/grpc++/impl/codegen/security/auth_context.h b/include/grpc++/impl/codegen/security/auth_context.h
index 337da91..b466373 100644
--- a/include/grpc++/impl/codegen/security/auth_context.h
+++ b/include/grpc++/impl/codegen/security/auth_context.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,80 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_SECURITY_AUTH_CONTEXT_H
 #define GRPCXX_IMPL_CODEGEN_SECURITY_AUTH_CONTEXT_H
 
-#include <iterator>
-#include <vector>
-
-#include <grpc++/impl/codegen/config.h>
-#include <grpc++/impl/codegen/string_ref.h>
-
-struct grpc_auth_context;
-struct grpc_auth_property;
-struct grpc_auth_property_iterator;
-
-namespace grpc {
-class SecureAuthContext;
-
-typedef std::pair<grpc::string_ref, grpc::string_ref> AuthProperty;
-
-class AuthPropertyIterator
-    : public std::iterator<std::input_iterator_tag, const AuthProperty> {
- public:
-  ~AuthPropertyIterator();
-  AuthPropertyIterator& operator++();
-  AuthPropertyIterator operator++(int);
-  bool operator==(const AuthPropertyIterator& rhs) const;
-  bool operator!=(const AuthPropertyIterator& rhs) const;
-  const AuthProperty operator*();
-
- protected:
-  AuthPropertyIterator();
-  AuthPropertyIterator(const grpc_auth_property* property,
-                       const grpc_auth_property_iterator* iter);
-
- private:
-  friend class SecureAuthContext;
-  const grpc_auth_property* property_;
-  // The following items form a grpc_auth_property_iterator.
-  const grpc_auth_context* ctx_;
-  size_t index_;
-  const char* name_;
-};
-
-/// Class encapsulating the Authentication Information.
-///
-/// It includes the secure identity of the peer, the type of secure transport
-/// used as well as any other properties required by the authorization layer.
-class AuthContext {
- public:
-  virtual ~AuthContext() {}
-
-  /// Returns true if the peer is authenticated.
-  virtual bool IsPeerAuthenticated() const = 0;
-
-  /// A peer identity.
-  ///
-  /// It is, in general, comprised of one or more properties (in which case they
-  /// have the same name).
-  virtual std::vector<grpc::string_ref> GetPeerIdentity() const = 0;
-  virtual grpc::string GetPeerIdentityPropertyName() const = 0;
-
-  /// Returns all the property values with the given name.
-  virtual std::vector<grpc::string_ref> FindPropertyValues(
-      const grpc::string& name) const = 0;
-
-  /// Iteration over all the properties.
-  virtual AuthPropertyIterator begin() const = 0;
-  virtual AuthPropertyIterator end() const = 0;
-
-  /// Mutation functions: should only be used by an AuthMetadataProcessor.
-  virtual void AddProperty(const grpc::string& key,
-                           const grpc::string_ref& value) = 0;
-  virtual bool SetPeerIdentityPropertyName(const grpc::string& name) = 0;
-};
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/security/auth_context.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_SECURITY_AUTH_CONTEXT_H
diff --git a/include/grpc++/impl/codegen/serialization_traits.h b/include/grpc++/impl/codegen/serialization_traits.h
index 4d91739..480575d 100644
--- a/include/grpc++/impl/codegen/serialization_traits.h
+++ b/include/grpc++/impl/codegen/serialization_traits.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,47 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_SERIALIZATION_TRAITS_H
 #define GRPCXX_IMPL_CODEGEN_SERIALIZATION_TRAITS_H
 
-namespace grpc {
-
-/// Defines how to serialize and deserialize some type.
-///
-/// Used for hooking different message serialization API's into GRPC.
-/// Each SerializationTraits<Message> implementation must provide the
-/// following functions:
-/// 1.  static Status Serialize(const Message& msg,
-///                             ByteBuffer* buffer,
-///                             bool* own_buffer);
-///     OR
-///     static Status Serialize(const Message& msg,
-///                             grpc_byte_buffer** buffer,
-///                             bool* own_buffer);
-///     The former is preferred; the latter is deprecated
-///
-/// 2.  static Status Deserialize(ByteBuffer* buffer,
-///                               Message* msg);
-///     OR
-///     static Status Deserialize(grpc_byte_buffer* buffer,
-///                               Message* msg);
-///     The former is preferred; the latter is deprecated
-///
-/// Serialize is required to convert message to a ByteBuffer, and
-/// return that byte buffer through *buffer. *own_buffer should
-/// be set to true if the caller owns said byte buffer, or false if
-/// ownership is retained elsewhere.
-///
-/// Deserialize is required to convert buffer into the message stored at
-/// msg. max_receive_message_size is passed in as a bound on the maximum
-/// number of message bytes Deserialize should accept.
-///
-/// Both functions return a Status, allowing them to explain what went
-/// wrong if required.
-template <class Message,
-          class UnusedButHereForPartialTemplateSpecialization = void>
-class SerializationTraits;
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/serialization_traits.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_SERIALIZATION_TRAITS_H
diff --git a/include/grpc++/impl/codegen/server_context.h b/include/grpc++/impl/codegen/server_context.h
index a2d6967..1c3342d 100644
--- a/include/grpc++/impl/codegen/server_context.h
+++ b/include/grpc++/impl/codegen/server_context.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,287 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_SERVER_CONTEXT_H
 #define GRPCXX_IMPL_CODEGEN_SERVER_CONTEXT_H
 
-#include <map>
-#include <memory>
-#include <vector>
-
-#include <grpc/impl/codegen/compression_types.h>
-
-#include <grpc++/impl/codegen/call.h>
-#include <grpc++/impl/codegen/completion_queue_tag.h>
-#include <grpc++/impl/codegen/config.h>
-#include <grpc++/impl/codegen/create_auth_context.h>
-#include <grpc++/impl/codegen/metadata_map.h>
-#include <grpc++/impl/codegen/security/auth_context.h>
-#include <grpc++/impl/codegen/string_ref.h>
-#include <grpc++/impl/codegen/time.h>
-
-struct grpc_metadata;
-struct grpc_call;
-struct census_context;
-
-namespace grpc {
-class ClientContext;
-template <class W, class R>
-class ServerAsyncReader;
-template <class W>
-class ServerAsyncWriter;
-template <class W>
-class ServerAsyncResponseWriter;
-template <class W, class R>
-class ServerAsyncReaderWriter;
-template <class R>
-class ServerReader;
-template <class W>
-class ServerWriter;
-namespace internal {
-template <class W, class R>
-class ServerReaderWriterBody;
-template <class ServiceType, class RequestType, class ResponseType>
-class RpcMethodHandler;
-template <class ServiceType, class RequestType, class ResponseType>
-class ClientStreamingHandler;
-template <class ServiceType, class RequestType, class ResponseType>
-class ServerStreamingHandler;
-template <class ServiceType, class RequestType, class ResponseType>
-class BidiStreamingHandler;
-class UnknownMethodHandler;
-template <class Streamer, bool WriteNeeded>
-class TemplatedBidiStreamingHandler;
-class Call;
-}  // namespace internal
-
-class CompletionQueue;
-class Server;
-class ServerInterface;
-
-namespace testing {
-class InteropServerContextInspector;
-class ServerContextTestSpouse;
-}  // namespace testing
-
-/// A ServerContext allows the person implementing a service handler to:
-///
-/// - Add custom initial and trailing metadata key-value pairs that will
-///   propagated to the client side.
-/// - Control call settings such as compression and authentication.
-/// - Access metadata coming from the client.
-/// - Get performance metrics (ie, census).
-///
-/// Context settings are only relevant to the call handler they are supplied to,
-/// that is to say, they aren't sticky across multiple calls. Some of these
-/// settings, such as the compression options, can be made persistant at server
-/// construction time by specifying the approriate \a ChannelArguments
-/// to a \a grpc::ServerBuilder, via \a ServerBuilder::AddChannelArgument.
-///
-/// \warning ServerContext instances should \em not be reused across rpcs.
-class ServerContext {
- public:
-  ServerContext();  // for async calls
-  ~ServerContext();
-
-  /// Return the deadline for the server call.
-  std::chrono::system_clock::time_point deadline() const {
-    return Timespec2Timepoint(deadline_);
-  }
-
-  /// Return a \a gpr_timespec representation of the server call's deadline.
-  gpr_timespec raw_deadline() const { return deadline_; }
-
-  /// Add the (\a meta_key, \a meta_value) pair to the initial metadata
-  /// associated with a server call. These are made available at the client side
-  /// by the \a grpc::ClientContext::GetServerInitialMetadata() method.
-  ///
-  /// \warning This method should only be called before sending initial metadata
-  /// to the client (which can happen explicitly, or implicitly when sending a
-  /// a response message or status to the client).
-  ///
-  /// \param meta_key The metadata key. If \a meta_value is binary data, it must
-  /// end in "-bin".
-  /// \param meta_value The metadata value. If its value is binary, the key name
-  /// must end in "-bin".
-  void AddInitialMetadata(const grpc::string& key, const grpc::string& value);
-
-  /// Add the (\a meta_key, \a meta_value) pair to the initial metadata
-  /// associated with a server call. These are made available at the client
-  /// side by the \a grpc::ClientContext::GetServerTrailingMetadata() method.
-  ///
-  /// \warning This method should only be called before sending trailing
-  /// metadata to the client (which happens when the call is finished and a
-  /// status is sent to the client).
-  ///
-  /// \param meta_key The metadata key. If \a meta_value is binary data,
-  /// it must end in "-bin".
-  /// \param meta_value The metadata value. If its value is binary, the key name
-  /// must end in "-bin".
-  void AddTrailingMetadata(const grpc::string& key, const grpc::string& value);
-
-  /// IsCancelled is always safe to call when using sync API.
-  /// When using async API, it is only safe to call IsCancelled after
-  /// the AsyncNotifyWhenDone tag has been delivered.
-  bool IsCancelled() const;
-
-  /// Cancel the Call from the server. This is a best-effort API and
-  /// depending on when it is called, the RPC may still appear successful to
-  /// the client.
-  /// For example, if TryCancel() is called on a separate thread, it might race
-  /// with the server handler which might return success to the client before
-  /// TryCancel() was even started by the thread.
-  ///
-  /// It is the caller's responsibility to prevent such races and ensure that if
-  /// TryCancel() is called, the serverhandler must return Status::CANCELLED.
-  /// The only exception is that if the serverhandler is already returning an
-  /// error status code, it is ok to not return Status::CANCELLED even if
-  /// TryCancel() was called.
-  void TryCancel() const;
-
-  /// Return a collection of initial metadata key-value pairs sent from the
-  /// client. Note that keys may happen more than
-  /// once (ie, a \a std::multimap is returned).
-  ///
-  /// It is safe to use this method after initial metadata has been received,
-  /// Calls always begin with the client sending initial metadata, so this is
-  /// safe to access as soon as the call has begun on the server side.
-  ///
-  /// \return A multimap of initial metadata key-value pairs from the server.
-  const std::multimap<grpc::string_ref, grpc::string_ref>& client_metadata()
-      const {
-    return *client_metadata_.map();
-  }
-
-  /// Return the compression algorithm to be used by the server call.
-  grpc_compression_level compression_level() const {
-    return compression_level_;
-  }
-
-  /// Set \a algorithm to be the compression algorithm used for the server call.
-  ///
-  /// \param algorithm The compression algorithm used for the server call.
-  void set_compression_level(grpc_compression_level level) {
-    compression_level_set_ = true;
-    compression_level_ = level;
-  }
-
-  /// Return a bool indicating whether the compression level for this call
-  /// has been set (either implicitly or through a previous call to
-  /// \a set_compression_level.
-  bool compression_level_set() const { return compression_level_set_; }
-
-  /// Return the compression algorithm to be used by the server call.
-  grpc_compression_algorithm compression_algorithm() const {
-    return compression_algorithm_;
-  }
-  /// Set \a algorithm to be the compression algorithm used for the server call.
-  ///
-  /// \param algorithm The compression algorithm used for the server call.
-  void set_compression_algorithm(grpc_compression_algorithm algorithm);
-
-  /// Set the load reporting costs in \a cost_data for the call.
-  void SetLoadReportingCosts(const std::vector<grpc::string>& cost_data);
-
-  /// Return the authentication context for this server call.
-  ///
-  /// \see grpc::AuthContext.
-  std::shared_ptr<const AuthContext> auth_context() const {
-    if (auth_context_.get() == nullptr) {
-      auth_context_ = CreateAuthContext(call_);
-    }
-    return auth_context_;
-  }
-
-  /// Return the peer uri in a string.
-  /// WARNING: this value is never authenticated or subject to any security
-  /// related code. It must not be used for any authentication related
-  /// functionality. Instead, use auth_context.
-  grpc::string peer() const;
-
-  /// Get the census context associated with this server call.
-  const struct census_context* census_context() const;
-
-  /// Async only. Has to be called before the rpc starts.
-  /// Returns the tag in completion queue when the rpc finishes.
-  /// IsCancelled() can then be called to check whether the rpc was cancelled.
-  void AsyncNotifyWhenDone(void* tag) {
-    has_notify_when_done_tag_ = true;
-    async_notify_when_done_tag_ = tag;
-  }
-
-  /// Should be used for framework-level extensions only.
-  /// Applications never need to call this method.
-  grpc_call* c_call() { return call_; }
-
- private:
-  friend class ::grpc::testing::InteropServerContextInspector;
-  friend class ::grpc::testing::ServerContextTestSpouse;
-  friend class ::grpc::ServerInterface;
-  friend class ::grpc::Server;
-  template <class W, class R>
-  friend class ::grpc::ServerAsyncReader;
-  template <class W>
-  friend class ::grpc::ServerAsyncWriter;
-  template <class W>
-  friend class ::grpc::ServerAsyncResponseWriter;
-  template <class W, class R>
-  friend class ::grpc::ServerAsyncReaderWriter;
-  template <class R>
-  friend class ::grpc::ServerReader;
-  template <class W>
-  friend class ::grpc::ServerWriter;
-  template <class W, class R>
-  friend class ::grpc::internal::ServerReaderWriterBody;
-  template <class ServiceType, class RequestType, class ResponseType>
-  friend class ::grpc::internal::RpcMethodHandler;
-  template <class ServiceType, class RequestType, class ResponseType>
-  friend class ::grpc::internal::ClientStreamingHandler;
-  template <class ServiceType, class RequestType, class ResponseType>
-  friend class ::grpc::internal::ServerStreamingHandler;
-  template <class Streamer, bool WriteNeeded>
-  friend class ::grpc::internal::TemplatedBidiStreamingHandler;
-  friend class ::grpc::internal::UnknownMethodHandler;
-  friend class ::grpc::ClientContext;
-
-  /// Prevent copying.
-  ServerContext(const ServerContext&);
-  ServerContext& operator=(const ServerContext&);
-
-  class CompletionOp;
-
-  void BeginCompletionOp(internal::Call* call);
-  /// Return the tag queued by BeginCompletionOp()
-  internal::CompletionQueueTag* GetCompletionOpTag();
-
-  ServerContext(gpr_timespec deadline, grpc_metadata_array* arr);
-
-  void set_call(grpc_call* call) { call_ = call; }
-
-  uint32_t initial_metadata_flags() const { return 0; }
-
-  CompletionOp* completion_op_;
-  bool has_notify_when_done_tag_;
-  void* async_notify_when_done_tag_;
-
-  gpr_timespec deadline_;
-  grpc_call* call_;
-  CompletionQueue* cq_;
-  bool sent_initial_metadata_;
-  mutable std::shared_ptr<const AuthContext> auth_context_;
-  internal::MetadataMap client_metadata_;
-  std::multimap<grpc::string, grpc::string> initial_metadata_;
-  std::multimap<grpc::string, grpc::string> trailing_metadata_;
-
-  bool compression_level_set_;
-  grpc_compression_level compression_level_;
-  grpc_compression_algorithm compression_algorithm_;
-
-  internal::CallOpSet<internal::CallOpSendInitialMetadata,
-                      internal::CallOpSendMessage>
-      pending_ops_;
-  bool has_pending_ops_;
-};
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/server_context.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_SERVER_CONTEXT_H
diff --git a/include/grpc++/impl/codegen/server_interface.h b/include/grpc++/impl/codegen/server_interface.h
index 3bcf4c8..ceea44c 100644
--- a/include/grpc++/impl/codegen/server_interface.h
+++ b/include/grpc++/impl/codegen/server_interface.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,259 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_SERVER_INTERFACE_H
 #define GRPCXX_IMPL_CODEGEN_SERVER_INTERFACE_H
 
-#include <grpc++/impl/codegen/call_hook.h>
-#include <grpc++/impl/codegen/completion_queue_tag.h>
-#include <grpc++/impl/codegen/core_codegen_interface.h>
-#include <grpc++/impl/codegen/rpc_service_method.h>
-#include <grpc/impl/codegen/grpc_types.h>
-
-namespace grpc {
-
-class AsyncGenericService;
-class Channel;
-class GenericServerContext;
-class ServerCompletionQueue;
-class ServerContext;
-class ServerCredentials;
-class Service;
-
-extern CoreCodegenInterface* g_core_codegen_interface;
-
-/// Models a gRPC server.
-///
-/// Servers are configured and started via \a grpc::ServerBuilder.
-namespace internal {
-class ServerAsyncStreamingInterface;
-}  // namespace internal
-
-class ServerInterface : public internal::CallHook {
- public:
-  virtual ~ServerInterface() {}
-
-  /// Shutdown the server, blocking until all rpc processing finishes.
-  /// Forcefully terminate pending calls after \a deadline expires.
-  ///
-  /// All completion queue associated with the server (for example, for async
-  /// serving) must be shutdown *after* this method has returned:
-  /// See \a ServerBuilder::AddCompletionQueue for details.
-  ///
-  /// \param deadline How long to wait until pending rpcs are forcefully
-  /// terminated.
-  template <class T>
-  void Shutdown(const T& deadline) {
-    ShutdownInternal(TimePoint<T>(deadline).raw_time());
-  }
-
-  /// Shutdown the server, waiting for all rpc processing to finish.
-  ///
-  /// All completion queue associated with the server (for example, for async
-  /// serving) must be shutdown *after* this method has returned:
-  /// See \a ServerBuilder::AddCompletionQueue for details.
-  void Shutdown() {
-    ShutdownInternal(
-        g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_MONOTONIC));
-  }
-
-  /// Block waiting for all work to complete.
-  ///
-  /// \warning The server must be either shutting down or some other thread must
-  /// call \a Shutdown for this function to ever return.
-  virtual void Wait() = 0;
-
- protected:
-  friend class ::grpc::Service;
-
-  /// Register a service. This call does not take ownership of the service.
-  /// The service must exist for the lifetime of the Server instance.
-  virtual bool RegisterService(const grpc::string* host, Service* service) = 0;
-
-  /// Register a generic service. This call does not take ownership of the
-  /// service. The service must exist for the lifetime of the Server instance.
-  virtual void RegisterAsyncGenericService(AsyncGenericService* service) = 0;
-
-  /// Tries to bind \a server to the given \a addr.
-  ///
-  /// It can be invoked multiple times.
-  ///
-  /// \param addr The address to try to bind to the server (eg, localhost:1234,
-  /// 192.168.1.1:31416, [::1]:27182, etc.).
-  /// \params creds The credentials associated with the server.
-  ///
-  /// \return bound port number on sucess, 0 on failure.
-  ///
-  /// \warning It's an error to call this method on an already started server.
-  virtual int AddListeningPort(const grpc::string& addr,
-                               ServerCredentials* creds) = 0;
-
-  /// Start the server.
-  ///
-  /// \param cqs Completion queues for handling asynchronous services. The
-  /// caller is required to keep all completion queues live until the server is
-  /// destroyed.
-  /// \param num_cqs How many completion queues does \a cqs hold.
-  virtual void Start(ServerCompletionQueue** cqs, size_t num_cqs) = 0;
-
-  virtual void ShutdownInternal(gpr_timespec deadline) = 0;
-
-  virtual int max_receive_message_size() const = 0;
-
-  virtual grpc_server* server() = 0;
-
-  virtual void PerformOpsOnCall(internal::CallOpSetInterface* ops,
-                                internal::Call* call) = 0;
-
-  class BaseAsyncRequest : public internal::CompletionQueueTag {
-   public:
-    BaseAsyncRequest(ServerInterface* server, ServerContext* context,
-                     internal::ServerAsyncStreamingInterface* stream,
-                     CompletionQueue* call_cq, void* tag,
-                     bool delete_on_finalize);
-    virtual ~BaseAsyncRequest();
-
-    bool FinalizeResult(void** tag, bool* status) override;
-
-   protected:
-    ServerInterface* const server_;
-    ServerContext* const context_;
-    internal::ServerAsyncStreamingInterface* const stream_;
-    CompletionQueue* const call_cq_;
-    void* const tag_;
-    const bool delete_on_finalize_;
-    grpc_call* call_;
-  };
-
-  class RegisteredAsyncRequest : public BaseAsyncRequest {
-   public:
-    RegisteredAsyncRequest(ServerInterface* server, ServerContext* context,
-                           internal::ServerAsyncStreamingInterface* stream,
-                           CompletionQueue* call_cq, void* tag);
-
-    // uses BaseAsyncRequest::FinalizeResult
-
-   protected:
-    void IssueRequest(void* registered_method, grpc_byte_buffer** payload,
-                      ServerCompletionQueue* notification_cq);
-  };
-
-  class NoPayloadAsyncRequest final : public RegisteredAsyncRequest {
-   public:
-    NoPayloadAsyncRequest(void* registered_method, ServerInterface* server,
-                          ServerContext* context,
-                          internal::ServerAsyncStreamingInterface* stream,
-                          CompletionQueue* call_cq,
-                          ServerCompletionQueue* notification_cq, void* tag)
-        : RegisteredAsyncRequest(server, context, stream, call_cq, tag) {
-      IssueRequest(registered_method, nullptr, notification_cq);
-    }
-
-    // uses RegisteredAsyncRequest::FinalizeResult
-  };
-
-  template <class Message>
-  class PayloadAsyncRequest final : public RegisteredAsyncRequest {
-   public:
-    PayloadAsyncRequest(void* registered_method, ServerInterface* server,
-                        ServerContext* context,
-                        internal::ServerAsyncStreamingInterface* stream,
-                        CompletionQueue* call_cq,
-                        ServerCompletionQueue* notification_cq, void* tag,
-                        Message* request)
-        : RegisteredAsyncRequest(server, context, stream, call_cq, tag),
-          registered_method_(registered_method),
-          server_(server),
-          context_(context),
-          stream_(stream),
-          call_cq_(call_cq),
-          notification_cq_(notification_cq),
-          tag_(tag),
-          request_(request) {
-      IssueRequest(registered_method, &payload_, notification_cq);
-    }
-
-    bool FinalizeResult(void** tag, bool* status) override {
-      if (*status) {
-        if (payload_ == nullptr ||
-            !SerializationTraits<Message>::Deserialize(payload_, request_)
-                 .ok()) {
-          // If deserialization fails, we cancel the call and instantiate
-          // a new instance of ourselves to request another call.  We then
-          // return false, which prevents the call from being returned to
-          // the application.
-          g_core_codegen_interface->grpc_call_cancel_with_status(
-              call_, GRPC_STATUS_INTERNAL, "Unable to parse request", nullptr);
-          g_core_codegen_interface->grpc_call_unref(call_);
-          new PayloadAsyncRequest(registered_method_, server_, context_,
-                                  stream_, call_cq_, notification_cq_, tag_,
-                                  request_);
-          delete this;
-          return false;
-        }
-      }
-      return RegisteredAsyncRequest::FinalizeResult(tag, status);
-    }
-
-   private:
-    void* const registered_method_;
-    ServerInterface* const server_;
-    ServerContext* const context_;
-    internal::ServerAsyncStreamingInterface* const stream_;
-    CompletionQueue* const call_cq_;
-    ServerCompletionQueue* const notification_cq_;
-    void* const tag_;
-    Message* const request_;
-    grpc_byte_buffer* payload_;
-  };
-
-  class GenericAsyncRequest : public BaseAsyncRequest {
-   public:
-    GenericAsyncRequest(ServerInterface* server, GenericServerContext* context,
-                        internal::ServerAsyncStreamingInterface* stream,
-                        CompletionQueue* call_cq,
-                        ServerCompletionQueue* notification_cq, void* tag,
-                        bool delete_on_finalize);
-
-    bool FinalizeResult(void** tag, bool* status) override;
-
-   private:
-    grpc_call_details call_details_;
-  };
-
-  template <class Message>
-  void RequestAsyncCall(internal::RpcServiceMethod* method,
-                        ServerContext* context,
-                        internal::ServerAsyncStreamingInterface* stream,
-                        CompletionQueue* call_cq,
-                        ServerCompletionQueue* notification_cq, void* tag,
-                        Message* message) {
-    GPR_CODEGEN_ASSERT(method);
-    new PayloadAsyncRequest<Message>(method->server_tag(), this, context,
-                                     stream, call_cq, notification_cq, tag,
-                                     message);
-  }
-
-  void RequestAsyncCall(internal::RpcServiceMethod* method,
-                        ServerContext* context,
-                        internal::ServerAsyncStreamingInterface* stream,
-                        CompletionQueue* call_cq,
-                        ServerCompletionQueue* notification_cq, void* tag) {
-    GPR_CODEGEN_ASSERT(method);
-    new NoPayloadAsyncRequest(method->server_tag(), this, context, stream,
-                              call_cq, notification_cq, tag);
-  }
-
-  void RequestAsyncGenericCall(GenericServerContext* context,
-                               internal::ServerAsyncStreamingInterface* stream,
-                               CompletionQueue* call_cq,
-                               ServerCompletionQueue* notification_cq,
-                               void* tag) {
-    new GenericAsyncRequest(this, context, stream, call_cq, notification_cq,
-                            tag, true);
-  }
-};
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/server_interface.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_SERVER_INTERFACE_H
diff --git a/include/grpc++/impl/codegen/service_type.h b/include/grpc++/impl/codegen/service_type.h
index 71c3d99..be02b75 100644
--- a/include/grpc++/impl/codegen/service_type.h
+++ b/include/grpc++/impl/codegen/service_type.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,148 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_SERVICE_TYPE_H
 #define GRPCXX_IMPL_CODEGEN_SERVICE_TYPE_H
 
-#include <grpc++/impl/codegen/config.h>
-#include <grpc++/impl/codegen/core_codegen_interface.h>
-#include <grpc++/impl/codegen/rpc_service_method.h>
-#include <grpc++/impl/codegen/serialization_traits.h>
-#include <grpc++/impl/codegen/server_interface.h>
-#include <grpc++/impl/codegen/status.h>
-
-namespace grpc {
-
-class CompletionQueue;
-class Server;
-class ServerInterface;
-class ServerCompletionQueue;
-class ServerContext;
-
-namespace internal {
-class Call;
-class ServerAsyncStreamingInterface {
- public:
-  virtual ~ServerAsyncStreamingInterface() {}
-
-  /// Request notification of the sending of initial metadata to the client.
-  /// Completion will be notified by \a tag on the associated completion
-  /// queue. This call is optional, but if it is used, it cannot be used
-  /// concurrently with or after the \a Finish method.
-  ///
-  /// \param[in] tag Tag identifying this request.
-  virtual void SendInitialMetadata(void* tag) = 0;
-
- private:
-  friend class ::grpc::ServerInterface;
-  virtual void BindCall(Call* call) = 0;
-};
-}  // namespace internal
-
-/// Desriptor of an RPC service and its various RPC methods
-class Service {
- public:
-  Service() : server_(nullptr) {}
-  virtual ~Service() {}
-
-  bool has_async_methods() const {
-    for (auto it = methods_.begin(); it != methods_.end(); ++it) {
-      if (*it && (*it)->handler() == nullptr) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  bool has_synchronous_methods() const {
-    for (auto it = methods_.begin(); it != methods_.end(); ++it) {
-      if (*it && (*it)->handler() != nullptr) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  bool has_generic_methods() const {
-    for (auto it = methods_.begin(); it != methods_.end(); ++it) {
-      if (it->get() == nullptr) {
-        return true;
-      }
-    }
-    return false;
-  }
-
- protected:
-  template <class Message>
-  void RequestAsyncUnary(int index, ServerContext* context, Message* request,
-                         internal::ServerAsyncStreamingInterface* stream,
-                         CompletionQueue* call_cq,
-                         ServerCompletionQueue* notification_cq, void* tag) {
-    server_->RequestAsyncCall(methods_[index].get(), context, stream, call_cq,
-                              notification_cq, tag, request);
-  }
-  void RequestAsyncClientStreaming(
-      int index, ServerContext* context,
-      internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
-      ServerCompletionQueue* notification_cq, void* tag) {
-    server_->RequestAsyncCall(methods_[index].get(), context, stream, call_cq,
-                              notification_cq, tag);
-  }
-  template <class Message>
-  void RequestAsyncServerStreaming(
-      int index, ServerContext* context, Message* request,
-      internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
-      ServerCompletionQueue* notification_cq, void* tag) {
-    server_->RequestAsyncCall(methods_[index].get(), context, stream, call_cq,
-                              notification_cq, tag, request);
-  }
-  void RequestAsyncBidiStreaming(
-      int index, ServerContext* context,
-      internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
-      ServerCompletionQueue* notification_cq, void* tag) {
-    server_->RequestAsyncCall(methods_[index].get(), context, stream, call_cq,
-                              notification_cq, tag);
-  }
-
-  void AddMethod(internal::RpcServiceMethod* method) {
-    methods_.emplace_back(method);
-  }
-
-  void MarkMethodAsync(int index) {
-    GPR_CODEGEN_ASSERT(
-        methods_[index].get() != nullptr &&
-        "Cannot mark the method as 'async' because it has already been "
-        "marked as 'generic'.");
-    methods_[index]->ResetHandler();
-  }
-
-  void MarkMethodGeneric(int index) {
-    GPR_CODEGEN_ASSERT(
-        methods_[index]->handler() != nullptr &&
-        "Cannot mark the method as 'generic' because it has already been "
-        "marked as 'async'.");
-    methods_[index].reset();
-  }
-
-  void MarkMethodStreamed(int index, internal::MethodHandler* streamed_method) {
-    GPR_CODEGEN_ASSERT(methods_[index] && methods_[index]->handler() &&
-                       "Cannot mark an async or generic method Streamed");
-    methods_[index]->SetHandler(streamed_method);
-
-    // From the server's point of view, streamed unary is a special
-    // case of BIDI_STREAMING that has 1 read and 1 write, in that order,
-    // and split server-side streaming is BIDI_STREAMING with 1 read and
-    // any number of writes, in that order.
-    methods_[index]->SetMethodType(internal::RpcMethod::BIDI_STREAMING);
-  }
-
- private:
-  friend class Server;
-  friend class ServerInterface;
-  ServerInterface* server_;
-  std::vector<std::unique_ptr<internal::RpcServiceMethod>> methods_;
-};
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/service_type.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_SERVICE_TYPE_H
diff --git a/include/grpc++/impl/codegen/slice.h b/include/grpc++/impl/codegen/slice.h
index c185bf4..6714bad 100644
--- a/include/grpc++/impl/codegen/slice.h
+++ b/include/grpc++/impl/codegen/slice.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,113 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_SLICE_H
 #define GRPCXX_IMPL_CODEGEN_SLICE_H
 
-#include <grpc++/impl/codegen/config.h>
-#include <grpc++/impl/codegen/core_codegen_interface.h>
-#include <grpc++/impl/codegen/string_ref.h>
-
-#include <grpc/impl/codegen/slice.h>
-
-namespace grpc {
-
-/// A wrapper around \a grpc_slice.
-///
-/// A slice represents a contiguous reference counted array of bytes.
-/// It is cheap to take references to a slice, and it is cheap to create a
-/// slice pointing to a subset of another slice.
-class Slice final {
- public:
-  /// Construct an empty slice.
-  Slice();
-  /// Destructor - drops one reference.
-  ~Slice();
-
-  enum AddRef { ADD_REF };
-  /// Construct a slice from \a slice, adding a reference.
-  Slice(grpc_slice slice, AddRef);
-
-  enum StealRef { STEAL_REF };
-  /// Construct a slice from \a slice, stealing a reference.
-  Slice(grpc_slice slice, StealRef);
-
-  /// Allocate a slice of specified size
-  Slice(size_t len);
-
-  /// Construct a slice from a copied buffer
-  Slice(const void* buf, size_t len);
-
-  /// Construct a slice from a copied string
-  Slice(const grpc::string& str);
-
-  enum StaticSlice { STATIC_SLICE };
-
-  /// Construct a slice from a static buffer
-  Slice(const void* buf, size_t len, StaticSlice);
-
-  /// Copy constructor, adds a reference.
-  Slice(const Slice& other);
-
-  /// Assignment, reference count is unchanged.
-  Slice& operator=(Slice other) {
-    std::swap(slice_, other.slice_);
-    return *this;
-  }
-
-  /// Create a slice pointing at some data. Calls malloc to allocate a refcount
-  /// for the object, and arranges that destroy will be called with the
-  /// user data pointer passed in at destruction. Can be the same as buf or
-  /// different (e.g., if data is part of a larger structure that must be
-  /// destroyed when the data is no longer needed)
-  Slice(void* buf, size_t len, void (*destroy)(void*), void* user_data);
-
-  /// Specialization of above for common case where buf == user_data
-  Slice(void* buf, size_t len, void (*destroy)(void*))
-      : Slice(buf, len, destroy, buf) {}
-
-  /// Similar to the above but has a destroy that also takes slice length
-  Slice(void* buf, size_t len, void (*destroy)(void*, size_t));
-
-  /// Byte size.
-  size_t size() const { return GRPC_SLICE_LENGTH(slice_); }
-
-  /// Raw pointer to the beginning (first element) of the slice.
-  const uint8_t* begin() const { return GRPC_SLICE_START_PTR(slice_); }
-
-  /// Raw pointer to the end (one byte \em past the last element) of the slice.
-  const uint8_t* end() const { return GRPC_SLICE_END_PTR(slice_); }
-
-  /// Raw C slice. Caller needs to call grpc_slice_unref when done.
-  grpc_slice c_slice() const;
-
- private:
-  friend class ByteBuffer;
-
-  grpc_slice slice_;
-};
-
-inline grpc::string_ref StringRefFromSlice(const grpc_slice* slice) {
-  return grpc::string_ref(
-      reinterpret_cast<const char*>(GRPC_SLICE_START_PTR(*slice)),
-      GRPC_SLICE_LENGTH(*slice));
-}
-
-inline grpc::string StringFromCopiedSlice(grpc_slice slice) {
-  return grpc::string(reinterpret_cast<char*>(GRPC_SLICE_START_PTR(slice)),
-                      GRPC_SLICE_LENGTH(slice));
-}
-
-inline grpc_slice SliceReferencingString(const grpc::string& str) {
-  return g_core_codegen_interface->grpc_slice_from_static_buffer(str.data(),
-                                                                 str.length());
-}
-
-inline grpc_slice SliceFromCopiedString(const grpc::string& str) {
-  return g_core_codegen_interface->grpc_slice_from_copied_buffer(str.data(),
-                                                                 str.length());
-}
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/slice.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_SLICE_H
diff --git a/include/grpc++/impl/codegen/status.h b/include/grpc++/impl/codegen/status.h
index 6f013cf..6cf9459 100644
--- a/include/grpc++/impl/codegen/status.h
+++ b/include/grpc++/impl/codegen/status.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,64 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_STATUS_H
 #define GRPCXX_IMPL_CODEGEN_STATUS_H
 
-#include <grpc++/impl/codegen/config.h>
-#include <grpc++/impl/codegen/status_code_enum.h>
-
-namespace grpc {
-
-/// Did it work? If it didn't, why?
-///
-/// See \a grpc::StatusCode for details on the available code and their meaning.
-class Status {
- public:
-  /// Construct an OK instance.
-  Status() : code_(StatusCode::OK) {}
-
-  /// Construct an instance with associated \a code and \a error_message.
-  /// It is an error to construct an OK status with non-empty \a error_message.
-  Status(StatusCode code, const grpc::string& error_message)
-      : code_(code), error_message_(error_message) {}
-
-  /// Construct an instance with \a code,  \a error_message and
-  /// \a error_details. It is an error to construct an OK status with non-empty
-  /// \a error_message and/or \a error_details.
-  Status(StatusCode code, const grpc::string& error_message,
-         const grpc::string& error_details)
-      : code_(code),
-        error_message_(error_message),
-        binary_error_details_(error_details) {}
-
-  // Pre-defined special status objects.
-  /// An OK pre-defined instance.
-  static const Status& OK;
-  /// A CANCELLED pre-defined instance.
-  static const Status& CANCELLED;
-
-  /// Return the instance's error code.
-  StatusCode error_code() const { return code_; }
-  /// Return the instance's error message.
-  grpc::string error_message() const { return error_message_; }
-  /// Return the (binary) error details.
-  // Usually it contains a serialized google.rpc.Status proto.
-  grpc::string error_details() const { return binary_error_details_; }
-
-  /// Is the status OK?
-  bool ok() const { return code_ == StatusCode::OK; }
-
-  // Ignores any errors. This method does nothing except potentially suppress
-  // complaints from any tools that are checking that errors are not dropped on
-  // the floor.
-  void IgnoreError() const {}
-
- private:
-  StatusCode code_;
-  grpc::string error_message_;
-  grpc::string binary_error_details_;
-};
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/status.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_STATUS_H
diff --git a/include/grpc++/impl/codegen/status_code_enum.h b/include/grpc++/impl/codegen/status_code_enum.h
index 68da185..7503eae 100644
--- a/include/grpc++/impl/codegen/status_code_enum.h
+++ b/include/grpc++/impl/codegen/status_code_enum.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,127 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_STATUS_CODE_ENUM_H
 #define GRPCXX_IMPL_CODEGEN_STATUS_CODE_ENUM_H
 
-namespace grpc {
-
-enum StatusCode {
-  /// Not an error; returned on success.
-  OK = 0,
-
-  /// The operation was cancelled (typically by the caller).
-  CANCELLED = 1,
-
-  /// Unknown error. An example of where this error may be returned is if a
-  /// Status value received from another address space belongs to an error-space
-  /// that is not known in this address space. Also errors raised by APIs that
-  /// do not return enough error information may be converted to this error.
-  UNKNOWN = 2,
-
-  /// Client specified an invalid argument. Note that this differs from
-  /// FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments that are
-  /// problematic regardless of the state of the system (e.g., a malformed file
-  /// name).
-  INVALID_ARGUMENT = 3,
-
-  /// Deadline expired before operation could complete. For operations that
-  /// change the state of the system, this error may be returned even if the
-  /// operation has completed successfully. For example, a successful response
-  /// from a server could have been delayed long enough for the deadline to
-  /// expire.
-  DEADLINE_EXCEEDED = 4,
-
-  /// Some requested entity (e.g., file or directory) was not found.
-  NOT_FOUND = 5,
-
-  /// Some entity that we attempted to create (e.g., file or directory) already
-  /// exists.
-  ALREADY_EXISTS = 6,
-
-  /// The caller does not have permission to execute the specified operation.
-  /// PERMISSION_DENIED must not be used for rejections caused by exhausting
-  /// some resource (use RESOURCE_EXHAUSTED instead for those errors).
-  /// PERMISSION_DENIED must not be used if the caller can not be identified
-  /// (use UNAUTHENTICATED instead for those errors).
-  PERMISSION_DENIED = 7,
-
-  /// The request does not have valid authentication credentials for the
-  /// operation.
-  UNAUTHENTICATED = 16,
-
-  /// Some resource has been exhausted, perhaps a per-user quota, or perhaps the
-  /// entire file system is out of space.
-  RESOURCE_EXHAUSTED = 8,
-
-  /// Operation was rejected because the system is not in a state required for
-  /// the operation's execution. For example, directory to be deleted may be
-  /// non-empty, an rmdir operation is applied to a non-directory, etc.
-  ///
-  /// A litmus test that may help a service implementor in deciding
-  /// between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:
-  ///  (a) Use UNAVAILABLE if the client can retry just the failing call.
-  ///  (b) Use ABORTED if the client should retry at a higher-level
-  ///      (e.g., restarting a read-modify-write sequence).
-  ///  (c) Use FAILED_PRECONDITION if the client should not retry until
-  ///      the system state has been explicitly fixed. E.g., if an "rmdir"
-  ///      fails because the directory is non-empty, FAILED_PRECONDITION
-  ///      should be returned since the client should not retry unless
-  ///      they have first fixed up the directory by deleting files from it.
-  ///  (d) Use FAILED_PRECONDITION if the client performs conditional
-  ///      REST Get/Update/Delete on a resource and the resource on the
-  ///      server does not match the condition. E.g., conflicting
-  ///      read-modify-write on the same resource.
-  FAILED_PRECONDITION = 9,
-
-  /// The operation was aborted, typically due to a concurrency issue like
-  /// sequencer check failures, transaction aborts, etc.
-  ///
-  /// See litmus test above for deciding between FAILED_PRECONDITION, ABORTED,
-  /// and UNAVAILABLE.
-  ABORTED = 10,
-
-  /// Operation was attempted past the valid range. E.g., seeking or reading
-  /// past end of file.
-  ///
-  /// Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed
-  /// if the system state changes. For example, a 32-bit file system will
-  /// generate INVALID_ARGUMENT if asked to read at an offset that is not in the
-  /// range [0,2^32-1], but it will generate OUT_OF_RANGE if asked to read from
-  /// an offset past the current file size.
-  ///
-  /// There is a fair bit of overlap between FAILED_PRECONDITION and
-  /// OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific error)
-  /// when it applies so that callers who are iterating through a space can
-  /// easily look for an OUT_OF_RANGE error to detect when they are done.
-  OUT_OF_RANGE = 11,
-
-  /// Operation is not implemented or not supported/enabled in this service.
-  UNIMPLEMENTED = 12,
-
-  /// Internal errors. Means some invariants expected by underlying System has
-  /// been broken. If you see one of these errors, Something is very broken.
-  INTERNAL = 13,
-
-  /// The service is currently unavailable. This is a most likely a transient
-  /// condition and may be corrected by retrying with a backoff.
-  ///
-  /// \warning Although data MIGHT not have been transmitted when this
-  /// status occurs, there is NOT A GUARANTEE that the server has not seen
-  /// anything. So in general it is unsafe to retry on this status code
-  /// if the call is non-idempotent.
-  ///
-  /// See litmus test above for deciding between FAILED_PRECONDITION, ABORTED,
-  /// and UNAVAILABLE.
-  UNAVAILABLE = 14,
-
-  /// Unrecoverable data loss or corruption.
-  DATA_LOSS = 15,
-
-  /// Force users to include a default branch:
-  DO_NOT_USE = -1
-};
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/status_code_enum.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_STATUS_CODE_ENUM_H
diff --git a/include/grpc++/impl/codegen/string_ref.h b/include/grpc++/impl/codegen/string_ref.h
index dbe3f19..66e250e 100644
--- a/include/grpc++/impl/codegen/string_ref.h
+++ b/include/grpc++/impl/codegen/string_ref.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,131 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_STRING_REF_H
 #define GRPCXX_IMPL_CODEGEN_STRING_REF_H
 
-#include <string.h>
-
-#include <algorithm>
-#include <iosfwd>
-#include <iostream>
-#include <iterator>
-
-#include <grpc++/impl/codegen/config.h>
-
-namespace grpc {
-
-/// This class is a non owning reference to a string.
-///
-/// It should be a strict subset of the upcoming std::string_ref.
-///
-/// \see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html
-///
-/// The constexpr is dropped or replaced with const for legacy compiler
-/// compatibility.
-class string_ref {
- public:
-  /// types
-  typedef const char* const_iterator;
-  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
-
-  /// constants
-  const static size_t npos;
-
-  /// construct/copy.
-  string_ref() : data_(nullptr), length_(0) {}
-  string_ref(const string_ref& other)
-      : data_(other.data_), length_(other.length_) {}
-  string_ref& operator=(const string_ref& rhs) {
-    data_ = rhs.data_;
-    length_ = rhs.length_;
-    return *this;
-  }
-
-  string_ref(const char* s) : data_(s), length_(strlen(s)) {}
-  string_ref(const char* s, size_t l) : data_(s), length_(l) {}
-  string_ref(const grpc::string& s) : data_(s.data()), length_(s.length()) {}
-
-  /// iterators
-  const_iterator begin() const { return data_; }
-  const_iterator end() const { return data_ + length_; }
-  const_iterator cbegin() const { return data_; }
-  const_iterator cend() const { return data_ + length_; }
-  const_reverse_iterator rbegin() const {
-    return const_reverse_iterator(end());
-  }
-  const_reverse_iterator rend() const {
-    return const_reverse_iterator(begin());
-  }
-  const_reverse_iterator crbegin() const {
-    return const_reverse_iterator(end());
-  }
-  const_reverse_iterator crend() const {
-    return const_reverse_iterator(begin());
-  }
-
-  /// capacity
-  size_t size() const { return length_; }
-  size_t length() const { return length_; }
-  size_t max_size() const { return length_; }
-  bool empty() const { return length_ == 0; }
-
-  /// element access
-  const char* data() const { return data_; }
-
-  /// string operations
-  int compare(string_ref x) const {
-    size_t min_size = length_ < x.length_ ? length_ : x.length_;
-    int r = memcmp(data_, x.data_, min_size);
-    if (r < 0) return -1;
-    if (r > 0) return 1;
-    if (length_ < x.length_) return -1;
-    if (length_ > x.length_) return 1;
-    return 0;
-  }
-
-  bool starts_with(string_ref x) const {
-    return length_ >= x.length_ && (memcmp(data_, x.data_, x.length_) == 0);
-  }
-
-  bool ends_with(string_ref x) const {
-    return length_ >= x.length_ &&
-           (memcmp(data_ + (length_ - x.length_), x.data_, x.length_) == 0);
-  }
-
-  size_t find(string_ref s) const {
-    auto it = std::search(cbegin(), cend(), s.cbegin(), s.cend());
-    return it == cend() ? npos : std::distance(cbegin(), it);
-  }
-
-  size_t find(char c) const {
-    auto it = std::find(cbegin(), cend(), c);
-    return it == cend() ? npos : std::distance(cbegin(), it);
-  }
-
-  string_ref substr(size_t pos, size_t n = npos) const {
-    if (pos > length_) pos = length_;
-    if (n > (length_ - pos)) n = length_ - pos;
-    return string_ref(data_ + pos, n);
-  }
-
- private:
-  const char* data_;
-  size_t length_;
-};
-
-/// Comparison operators
-inline bool operator==(string_ref x, string_ref y) { return x.compare(y) == 0; }
-inline bool operator!=(string_ref x, string_ref y) { return x.compare(y) != 0; }
-inline bool operator<(string_ref x, string_ref y) { return x.compare(y) < 0; }
-inline bool operator<=(string_ref x, string_ref y) { return x.compare(y) <= 0; }
-inline bool operator>(string_ref x, string_ref y) { return x.compare(y) > 0; }
-inline bool operator>=(string_ref x, string_ref y) { return x.compare(y) >= 0; }
-
-inline std::ostream& operator<<(std::ostream& out, const string_ref& string) {
-  return out << grpc::string(string.begin(), string.end());
-}
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/string_ref.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_STRING_REF_H
diff --git a/include/grpc++/impl/codegen/stub_options.h b/include/grpc++/impl/codegen/stub_options.h
index 380d052..07cb441 100644
--- a/include/grpc++/impl/codegen/stub_options.h
+++ b/include/grpc++/impl/codegen/stub_options.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,14 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_STUB_OPTIONS_H
 #define GRPCXX_IMPL_CODEGEN_STUB_OPTIONS_H
 
-namespace grpc {
-
-/// Useful interface for generated stubs
-class StubOptions {};
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/stub_options.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_STUB_OPTIONS_H
diff --git a/include/grpc++/impl/codegen/sync_stream.h b/include/grpc++/impl/codegen/sync_stream.h
index a6dd26f..1e6ba27 100644
--- a/include/grpc++/impl/codegen/sync_stream.h
+++ b/include/grpc++/impl/codegen/sync_stream.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,919 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_SYNC_STREAM_H
 #define GRPCXX_IMPL_CODEGEN_SYNC_STREAM_H
 
-#include <grpc++/impl/codegen/call.h>
-#include <grpc++/impl/codegen/channel_interface.h>
-#include <grpc++/impl/codegen/client_context.h>
-#include <grpc++/impl/codegen/completion_queue.h>
-#include <grpc++/impl/codegen/core_codegen_interface.h>
-#include <grpc++/impl/codegen/server_context.h>
-#include <grpc++/impl/codegen/service_type.h>
-#include <grpc++/impl/codegen/status.h>
-
-namespace grpc {
-
-namespace internal {
-/// Common interface for all synchronous client side streaming.
-class ClientStreamingInterface {
- public:
-  virtual ~ClientStreamingInterface() {}
-
-  /// Block waiting until the stream finishes and a final status of the call is
-  /// available.
-  ///
-  /// It is appropriate to call this method when both:
-  ///   * the calling code (client-side) has no more message to send
-  ///     (this can be declared implicitly by calling this method, or
-  ///     explicitly through an earlier call to <i>WritesDone</i> method of the
-  ///     class in use, e.g. \a ClientWriterInterface::WritesDone or
-  ///     \a ClientReaderWriterInterface::WritesDone).
-  ///   * there are no more messages to be received from the server (which can
-  ///     be known implicitly, or explicitly from an earlier call to \a
-  ///     ReaderInterface::Read that returned "false").
-  ///
-  /// This function will return either:
-  /// - when all incoming messages have been read and the server has
-  ///   returned status.
-  /// - when the server has returned a non-OK status.
-  /// - OR when the call failed for some reason and the library generated a
-  ///   status.
-  ///
-  /// Return values:
-  ///   - \a Status contains the status code, message and details for the call
-  ///   - the \a ClientContext associated with this call is updated with
-  ///     possible trailing metadata sent from the server.
-  virtual Status Finish() = 0;
-};
-
-/// Common interface for all synchronous server side streaming.
-class ServerStreamingInterface {
- public:
-  virtual ~ServerStreamingInterface() {}
-
-  /// Block to send initial metadata to client.
-  /// This call is optional, but if it is used, it cannot be used concurrently
-  /// with or after the \a Finish method.
-  ///
-  /// The initial metadata that will be sent to the client will be
-  /// taken from the \a ServerContext associated with the call.
-  virtual void SendInitialMetadata() = 0;
-};
-
-/// An interface that yields a sequence of messages of type \a R.
-template <class R>
-class ReaderInterface {
- public:
-  virtual ~ReaderInterface() {}
-
-  /// Get an upper bound on the next message size available for reading on this
-  /// stream.
-  virtual bool NextMessageSize(uint32_t* sz) = 0;
-
-  /// Block to read a message and parse to \a msg. Returns \a true on success.
-  /// This is thread-safe with respect to \a Write or \WritesDone methods on
-  /// the same stream. It should not be called concurrently with another \a
-  /// Read on the same stream as the order of delivery will not be defined.
-  ///
-  /// \param[out] msg The read message.
-  ///
-  /// \return \a false when there will be no more incoming messages, either
-  /// because the other side has called \a WritesDone() or the stream has failed
-  /// (or been cancelled).
-  virtual bool Read(R* msg) = 0;
-};
-
-/// An interface that can be fed a sequence of messages of type \a W.
-template <class W>
-class WriterInterface {
- public:
-  virtual ~WriterInterface() {}
-
-  /// Block to write \a msg to the stream with WriteOptions \a options.
-  /// This is thread-safe with respect to \a ReaderInterface::Read
-  ///
-  /// \param msg The message to be written to the stream.
-  /// \param options The WriteOptions affecting the write operation.
-  ///
-  /// \return \a true on success, \a false when the stream has been closed.
-  virtual bool Write(const W& msg, WriteOptions options) = 0;
-
-  /// Block to write \a msg to the stream with default write options.
-  /// This is thread-safe with respect to \a ReaderInterface::Read
-  ///
-  /// \param msg The message to be written to the stream.
-  ///
-  /// \return \a true on success, \a false when the stream has been closed.
-  inline bool Write(const W& msg) { return Write(msg, WriteOptions()); }
-
-  /// Write \a msg and coalesce it with the writing of trailing metadata, using
-  /// WriteOptions \a options.
-  ///
-  /// For client, WriteLast is equivalent of performing Write and WritesDone in
-  /// a single step. \a msg and trailing metadata are coalesced and sent on wire
-  /// by calling this function. For server, WriteLast buffers the \a msg.
-  /// The writing of \a msg is held until the service handler returns,
-  /// where \a msg and trailing metadata are coalesced and sent on wire.
-  /// Note that WriteLast can only buffer \a msg up to the flow control window
-  /// size. If \a msg size is larger than the window size, it will be sent on
-  /// wire without buffering.
-  ///
-  /// \param[in] msg The message to be written to the stream.
-  /// \param[in] options The WriteOptions to be used to write this message.
-  void WriteLast(const W& msg, WriteOptions options) {
-    Write(msg, options.set_last_message());
-  }
-};
-
-}  // namespace internal
-
-/// Client-side interface for streaming reads of message of type \a R.
-template <class R>
-class ClientReaderInterface : public internal::ClientStreamingInterface,
-                              public internal::ReaderInterface<R> {
- public:
-  /// Block to wait for initial metadata from server. The received metadata
-  /// can only be accessed after this call returns. Should only be called before
-  /// the first read. Calling this method is optional, and if it is not called
-  /// the metadata will be available in ClientContext after the first read.
-  virtual void WaitForInitialMetadata() = 0;
-};
-
-namespace internal {
-template <class R>
-class ClientReaderFactory {
- public:
-  template <class W>
-  static ClientReader<R>* Create(ChannelInterface* channel,
-                                 const ::grpc::internal::RpcMethod& method,
-                                 ClientContext* context, const W& request) {
-    return new ClientReader<R>(channel, method, context, request);
-  }
-};
-}  // namespace internal
-
-/// Synchronous (blocking) client-side API for doing server-streaming RPCs,
-/// where the stream of messages coming from the server has messages
-/// of type \a R.
-template <class R>
-class ClientReader final : public ClientReaderInterface<R> {
- public:
-  /// See the \a ClientStreamingInterface.WaitForInitialMetadata method for
-  /// semantics.
-  ///
-  //  Side effect:
-  ///   Once complete, the initial metadata read from
-  ///   the server will be accessable through the \a ClientContext used to
-  ///   construct this object.
-  void WaitForInitialMetadata() override {
-    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
-
-    ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
-        ops;
-    ops.RecvInitialMetadata(context_);
-    call_.PerformOps(&ops);
-    cq_.Pluck(&ops);  /// status ignored
-  }
-
-  bool NextMessageSize(uint32_t* sz) override {
-    *sz = call_.max_receive_message_size();
-    return true;
-  }
-
-  /// See the \a ReaderInterface.Read method for semantics.
-  /// Side effect:
-  ///   This also receives initial metadata from the server, if not
-  ///   already received (if initial metadata is received, it can be then
-  ///   accessed through the \a ClientContext associated with this call).
-  bool Read(R* msg) override {
-    ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
-                                ::grpc::internal::CallOpRecvMessage<R>>
-        ops;
-    if (!context_->initial_metadata_received_) {
-      ops.RecvInitialMetadata(context_);
-    }
-    ops.RecvMessage(msg);
-    call_.PerformOps(&ops);
-    return cq_.Pluck(&ops) && ops.got_message;
-  }
-
-  /// See the \a ClientStreamingInterface.Finish method for semantics.
-  ///
-  /// Side effect:
-  ///   The \a ClientContext associated with this call is updated with
-  ///   possible metadata received from the server.
-  Status Finish() override {
-    ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientRecvStatus> ops;
-    Status status;
-    ops.ClientRecvStatus(context_, &status);
-    call_.PerformOps(&ops);
-    GPR_CODEGEN_ASSERT(cq_.Pluck(&ops));
-    return status;
-  }
-
- private:
-  friend class internal::ClientReaderFactory<R>;
-  ClientContext* context_;
-  CompletionQueue cq_;
-  ::grpc::internal::Call call_;
-
-  /// Block to create a stream and write the initial metadata and \a request
-  /// out. Note that \a context will be used to fill in custom initial
-  /// metadata used to send to the server when starting the call.
-  template <class W>
-  ClientReader(::grpc::ChannelInterface* channel,
-               const ::grpc::internal::RpcMethod& method,
-               ClientContext* context, const W& request)
-      : context_(context),
-        cq_(grpc_completion_queue_attributes{
-            GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK,
-            GRPC_CQ_DEFAULT_POLLING}),  // Pluckable cq
-        call_(channel->CreateCall(method, context, &cq_)) {
-    ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
-                                ::grpc::internal::CallOpSendMessage,
-                                ::grpc::internal::CallOpClientSendClose>
-        ops;
-    ops.SendInitialMetadata(context->send_initial_metadata_,
-                            context->initial_metadata_flags());
-    // TODO(ctiller): don't assert
-    GPR_CODEGEN_ASSERT(ops.SendMessage(request).ok());
-    ops.ClientSendClose();
-    call_.PerformOps(&ops);
-    cq_.Pluck(&ops);
-  }
-};
-
-/// Client-side interface for streaming writes of message type \a W.
-template <class W>
-class ClientWriterInterface : public internal::ClientStreamingInterface,
-                              public internal::WriterInterface<W> {
- public:
-  /// Half close writing from the client. (signal that the stream of messages
-  /// coming from the client is complete).
-  /// Blocks until currently-pending writes are completed.
-  /// Thread safe with respect to \a ReaderInterface::Read operations only
-  ///
-  /// \return Whether the writes were successful.
-  virtual bool WritesDone() = 0;
-};
-
-namespace internal {
-template <class W>
-class ClientWriterFactory {
- public:
-  template <class R>
-  static ClientWriter<W>* Create(::grpc::ChannelInterface* channel,
-                                 const ::grpc::internal::RpcMethod& method,
-                                 ClientContext* context, R* response) {
-    return new ClientWriter<W>(channel, method, context, response);
-  }
-};
-}  // namespace internal
-
-/// Synchronous (blocking) client-side API for doing client-streaming RPCs,
-/// where the outgoing message stream coming from the client has messages of
-/// type \a W.
-template <class W>
-class ClientWriter : public ClientWriterInterface<W> {
- public:
-  /// See the \a ClientStreamingInterface.WaitForInitialMetadata method for
-  /// semantics.
-  ///
-  //  Side effect:
-  ///   Once complete, the initial metadata read from the server will be
-  ///   accessable through the \a ClientContext used to construct this object.
-  void WaitForInitialMetadata() {
-    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
-
-    ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
-        ops;
-    ops.RecvInitialMetadata(context_);
-    call_.PerformOps(&ops);
-    cq_.Pluck(&ops);  // status ignored
-  }
-
-  /// See the WriterInterface.Write(const W& msg, WriteOptions options) method
-  /// for semantics.
-  ///
-  /// Side effect:
-  ///   Also sends initial metadata if not already sent (using the
-  ///   \a ClientContext associated with this call).
-  using ::grpc::internal::WriterInterface<W>::Write;
-  bool Write(const W& msg, WriteOptions options) override {
-    ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
-                                ::grpc::internal::CallOpSendMessage,
-                                ::grpc::internal::CallOpClientSendClose>
-        ops;
-
-    if (options.is_last_message()) {
-      options.set_buffer_hint();
-      ops.ClientSendClose();
-    }
-    if (context_->initial_metadata_corked_) {
-      ops.SendInitialMetadata(context_->send_initial_metadata_,
-                              context_->initial_metadata_flags());
-      context_->set_initial_metadata_corked(false);
-    }
-    if (!ops.SendMessage(msg, options).ok()) {
-      return false;
-    }
-
-    call_.PerformOps(&ops);
-    return cq_.Pluck(&ops);
-  }
-
-  bool WritesDone() override {
-    ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops;
-    ops.ClientSendClose();
-    call_.PerformOps(&ops);
-    return cq_.Pluck(&ops);
-  }
-
-  /// See the ClientStreamingInterface.Finish method for semantics.
-  /// Side effects:
-  ///   - Also receives initial metadata if not already received.
-  ///   - Attempts to fill in the \a response parameter passed
-  ///     to the constructor of this instance with the response
-  ///     message from the server.
-  Status Finish() override {
-    Status status;
-    if (!context_->initial_metadata_received_) {
-      finish_ops_.RecvInitialMetadata(context_);
-    }
-    finish_ops_.ClientRecvStatus(context_, &status);
-    call_.PerformOps(&finish_ops_);
-    GPR_CODEGEN_ASSERT(cq_.Pluck(&finish_ops_));
-    return status;
-  }
-
- private:
-  friend class internal::ClientWriterFactory<W>;
-
-  /// Block to create a stream (i.e. send request headers and other initial
-  /// metadata to the server). Note that \a context will be used to fill
-  /// in custom initial metadata. \a response will be filled in with the
-  /// single expected response message from the server upon a successful
-  /// call to the \a Finish method of this instance.
-  template <class R>
-  ClientWriter(ChannelInterface* channel,
-               const ::grpc::internal::RpcMethod& method,
-               ClientContext* context, R* response)
-      : context_(context),
-        cq_(grpc_completion_queue_attributes{
-            GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK,
-            GRPC_CQ_DEFAULT_POLLING}),  // Pluckable cq
-        call_(channel->CreateCall(method, context, &cq_)) {
-    finish_ops_.RecvMessage(response);
-    finish_ops_.AllowNoMessage();
-
-    if (!context_->initial_metadata_corked_) {
-      ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
-          ops;
-      ops.SendInitialMetadata(context->send_initial_metadata_,
-                              context->initial_metadata_flags());
-      call_.PerformOps(&ops);
-      cq_.Pluck(&ops);
-    }
-  }
-
-  ClientContext* context_;
-  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
-                              ::grpc::internal::CallOpGenericRecvMessage,
-                              ::grpc::internal::CallOpClientRecvStatus>
-      finish_ops_;
-  CompletionQueue cq_;
-  ::grpc::internal::Call call_;
-};
-
-/// Client-side interface for bi-directional streaming with
-/// client-to-server stream messages of type \a W and
-/// server-to-client stream messages of type \a R.
-template <class W, class R>
-class ClientReaderWriterInterface : public internal::ClientStreamingInterface,
-                                    public internal::WriterInterface<W>,
-                                    public internal::ReaderInterface<R> {
- public:
-  /// Block to wait for initial metadata from server. The received metadata
-  /// can only be accessed after this call returns. Should only be called before
-  /// the first read. Calling this method is optional, and if it is not called
-  /// the metadata will be available in ClientContext after the first read.
-  virtual void WaitForInitialMetadata() = 0;
-
-  /// Half close writing from the client. (signal that the stream of messages
-  /// coming from the clinet is complete).
-  /// Blocks until currently-pending writes are completed.
-  /// Thread-safe with respect to \a ReaderInterface::Read
-  ///
-  /// \return Whether the writes were successful.
-  virtual bool WritesDone() = 0;
-};
-
-namespace internal {
-template <class W, class R>
-class ClientReaderWriterFactory {
- public:
-  static ClientReaderWriter<W, R>* Create(
-      ::grpc::ChannelInterface* channel,
-      const ::grpc::internal::RpcMethod& method, ClientContext* context) {
-    return new ClientReaderWriter<W, R>(channel, method, context);
-  }
-};
-}  // namespace internal
-
-/// Synchronous (blocking) client-side API for bi-directional streaming RPCs,
-/// where the outgoing message stream coming from the client has messages of
-/// type \a W, and the incoming messages stream coming from the server has
-/// messages of type \a R.
-template <class W, class R>
-class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> {
- public:
-  /// Block waiting to read initial metadata from the server.
-  /// This call is optional, but if it is used, it cannot be used concurrently
-  /// with or after the \a Finish method.
-  ///
-  /// Once complete, the initial metadata read from the server will be
-  /// accessable through the \a ClientContext used to construct this object.
-  void WaitForInitialMetadata() override {
-    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
-
-    ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
-        ops;
-    ops.RecvInitialMetadata(context_);
-    call_.PerformOps(&ops);
-    cq_.Pluck(&ops);  // status ignored
-  }
-
-  bool NextMessageSize(uint32_t* sz) override {
-    *sz = call_.max_receive_message_size();
-    return true;
-  }
-
-  /// See the \a ReaderInterface.Read method for semantics.
-  /// Side effect:
-  ///   Also receives initial metadata if not already received (updates the \a
-  ///   ClientContext associated with this call in that case).
-  bool Read(R* msg) override {
-    ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
-                                ::grpc::internal::CallOpRecvMessage<R>>
-        ops;
-    if (!context_->initial_metadata_received_) {
-      ops.RecvInitialMetadata(context_);
-    }
-    ops.RecvMessage(msg);
-    call_.PerformOps(&ops);
-    return cq_.Pluck(&ops) && ops.got_message;
-  }
-
-  /// See the \a WriterInterface.Write method for semantics.
-  ///
-  /// Side effect:
-  ///   Also sends initial metadata if not already sent (using the
-  ///   \a ClientContext associated with this call to fill in values).
-  using ::grpc::internal::WriterInterface<W>::Write;
-  bool Write(const W& msg, WriteOptions options) override {
-    ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
-                                ::grpc::internal::CallOpSendMessage,
-                                ::grpc::internal::CallOpClientSendClose>
-        ops;
-
-    if (options.is_last_message()) {
-      options.set_buffer_hint();
-      ops.ClientSendClose();
-    }
-    if (context_->initial_metadata_corked_) {
-      ops.SendInitialMetadata(context_->send_initial_metadata_,
-                              context_->initial_metadata_flags());
-      context_->set_initial_metadata_corked(false);
-    }
-    if (!ops.SendMessage(msg, options).ok()) {
-      return false;
-    }
-
-    call_.PerformOps(&ops);
-    return cq_.Pluck(&ops);
-  }
-
-  bool WritesDone() override {
-    ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops;
-    ops.ClientSendClose();
-    call_.PerformOps(&ops);
-    return cq_.Pluck(&ops);
-  }
-
-  /// See the ClientStreamingInterface.Finish method for semantics.
-  ///
-  /// Side effect:
-  ///   - the \a ClientContext associated with this call is updated with
-  ///     possible trailing metadata sent from the server.
-  Status Finish() override {
-    ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
-                                ::grpc::internal::CallOpClientRecvStatus>
-        ops;
-    if (!context_->initial_metadata_received_) {
-      ops.RecvInitialMetadata(context_);
-    }
-    Status status;
-    ops.ClientRecvStatus(context_, &status);
-    call_.PerformOps(&ops);
-    GPR_CODEGEN_ASSERT(cq_.Pluck(&ops));
-    return status;
-  }
-
- private:
-  friend class internal::ClientReaderWriterFactory<W, R>;
-
-  ClientContext* context_;
-  CompletionQueue cq_;
-  ::grpc::internal::Call call_;
-
-  /// Block to create a stream and write the initial metadata and \a request
-  /// out. Note that \a context will be used to fill in custom initial metadata
-  /// used to send to the server when starting the call.
-  ClientReaderWriter(::grpc::ChannelInterface* channel,
-                     const ::grpc::internal::RpcMethod& method,
-                     ClientContext* context)
-      : context_(context),
-        cq_(grpc_completion_queue_attributes{
-            GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK,
-            GRPC_CQ_DEFAULT_POLLING}),  // Pluckable cq
-        call_(channel->CreateCall(method, context, &cq_)) {
-    if (!context_->initial_metadata_corked_) {
-      ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
-          ops;
-      ops.SendInitialMetadata(context->send_initial_metadata_,
-                              context->initial_metadata_flags());
-      call_.PerformOps(&ops);
-      cq_.Pluck(&ops);
-    }
-  }
-};
-
-/// Server-side interface for streaming reads of message of type \a R.
-template <class R>
-class ServerReaderInterface : public internal::ServerStreamingInterface,
-                              public internal::ReaderInterface<R> {};
-
-/// Synchronous (blocking) server-side API for doing client-streaming RPCs,
-/// where the incoming message stream coming from the client has messages of
-/// type \a R.
-template <class R>
-class ServerReader final : public ServerReaderInterface<R> {
- public:
-  /// See the \a ServerStreamingInterface.SendInitialMetadata method
-  /// for semantics. Note that initial metadata will be affected by the
-  /// \a ServerContext associated with this call.
-  void SendInitialMetadata() override {
-    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
-
-    internal::CallOpSet<internal::CallOpSendInitialMetadata> ops;
-    ops.SendInitialMetadata(ctx_->initial_metadata_,
-                            ctx_->initial_metadata_flags());
-    if (ctx_->compression_level_set()) {
-      ops.set_compression_level(ctx_->compression_level());
-    }
-    ctx_->sent_initial_metadata_ = true;
-    call_->PerformOps(&ops);
-    call_->cq()->Pluck(&ops);
-  }
-
-  bool NextMessageSize(uint32_t* sz) override {
-    *sz = call_->max_receive_message_size();
-    return true;
-  }
-
-  bool Read(R* msg) override {
-    internal::CallOpSet<internal::CallOpRecvMessage<R>> ops;
-    ops.RecvMessage(msg);
-    call_->PerformOps(&ops);
-    return call_->cq()->Pluck(&ops) && ops.got_message;
-  }
-
- private:
-  internal::Call* const call_;
-  ServerContext* const ctx_;
-
-  template <class ServiceType, class RequestType, class ResponseType>
-  friend class internal::ClientStreamingHandler;
-
-  ServerReader(internal::Call* call, ServerContext* ctx)
-      : call_(call), ctx_(ctx) {}
-};
-
-/// Server-side interface for streaming writes of message of type \a W.
-template <class W>
-class ServerWriterInterface : public internal::ServerStreamingInterface,
-                              public internal::WriterInterface<W> {};
-
-/// Synchronous (blocking) server-side API for doing for doing a
-/// server-streaming RPCs, where the outgoing message stream coming from the
-/// server has messages of type \a W.
-template <class W>
-class ServerWriter final : public ServerWriterInterface<W> {
- public:
-  /// See the \a ServerStreamingInterface.SendInitialMetadata method
-  /// for semantics.
-  /// Note that initial metadata will be affected by the
-  /// \a ServerContext associated with this call.
-  void SendInitialMetadata() override {
-    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
-
-    internal::CallOpSet<internal::CallOpSendInitialMetadata> ops;
-    ops.SendInitialMetadata(ctx_->initial_metadata_,
-                            ctx_->initial_metadata_flags());
-    if (ctx_->compression_level_set()) {
-      ops.set_compression_level(ctx_->compression_level());
-    }
-    ctx_->sent_initial_metadata_ = true;
-    call_->PerformOps(&ops);
-    call_->cq()->Pluck(&ops);
-  }
-
-  /// See the \a WriterInterface.Write method for semantics.
-  ///
-  /// Side effect:
-  ///   Also sends initial metadata if not already sent (using the
-  ///   \a ClientContext associated with this call to fill in values).
-  using internal::WriterInterface<W>::Write;
-  bool Write(const W& msg, WriteOptions options) override {
-    if (options.is_last_message()) {
-      options.set_buffer_hint();
-    }
-
-    if (!ctx_->pending_ops_.SendMessage(msg, options).ok()) {
-      return false;
-    }
-    if (!ctx_->sent_initial_metadata_) {
-      ctx_->pending_ops_.SendInitialMetadata(ctx_->initial_metadata_,
-                                             ctx_->initial_metadata_flags());
-      if (ctx_->compression_level_set()) {
-        ctx_->pending_ops_.set_compression_level(ctx_->compression_level());
-      }
-      ctx_->sent_initial_metadata_ = true;
-    }
-    call_->PerformOps(&ctx_->pending_ops_);
-    // if this is the last message we defer the pluck until AFTER we start
-    // the trailing md op. This prevents hangs. See
-    // https://github.com/grpc/grpc/issues/11546
-    if (options.is_last_message()) {
-      ctx_->has_pending_ops_ = true;
-      return true;
-    }
-    ctx_->has_pending_ops_ = false;
-    return call_->cq()->Pluck(&ctx_->pending_ops_);
-  }
-
- private:
-  internal::Call* const call_;
-  ServerContext* const ctx_;
-
-  template <class ServiceType, class RequestType, class ResponseType>
-  friend class internal::ServerStreamingHandler;
-
-  ServerWriter(internal::Call* call, ServerContext* ctx)
-      : call_(call), ctx_(ctx) {}
-};
-
-/// Server-side interface for bi-directional streaming.
-template <class W, class R>
-class ServerReaderWriterInterface : public internal::ServerStreamingInterface,
-                                    public internal::WriterInterface<W>,
-                                    public internal::ReaderInterface<R> {};
-
-/// Actual implementation of bi-directional streaming
-namespace internal {
-template <class W, class R>
-class ServerReaderWriterBody final {
- public:
-  ServerReaderWriterBody(Call* call, ServerContext* ctx)
-      : call_(call), ctx_(ctx) {}
-
-  void SendInitialMetadata() {
-    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
-
-    CallOpSet<CallOpSendInitialMetadata> ops;
-    ops.SendInitialMetadata(ctx_->initial_metadata_,
-                            ctx_->initial_metadata_flags());
-    if (ctx_->compression_level_set()) {
-      ops.set_compression_level(ctx_->compression_level());
-    }
-    ctx_->sent_initial_metadata_ = true;
-    call_->PerformOps(&ops);
-    call_->cq()->Pluck(&ops);
-  }
-
-  bool NextMessageSize(uint32_t* sz) {
-    *sz = call_->max_receive_message_size();
-    return true;
-  }
-
-  bool Read(R* msg) {
-    CallOpSet<CallOpRecvMessage<R>> ops;
-    ops.RecvMessage(msg);
-    call_->PerformOps(&ops);
-    return call_->cq()->Pluck(&ops) && ops.got_message;
-  }
-
-  bool Write(const W& msg, WriteOptions options) {
-    if (options.is_last_message()) {
-      options.set_buffer_hint();
-    }
-    if (!ctx_->pending_ops_.SendMessage(msg, options).ok()) {
-      return false;
-    }
-    if (!ctx_->sent_initial_metadata_) {
-      ctx_->pending_ops_.SendInitialMetadata(ctx_->initial_metadata_,
-                                             ctx_->initial_metadata_flags());
-      if (ctx_->compression_level_set()) {
-        ctx_->pending_ops_.set_compression_level(ctx_->compression_level());
-      }
-      ctx_->sent_initial_metadata_ = true;
-    }
-    call_->PerformOps(&ctx_->pending_ops_);
-    // if this is the last message we defer the pluck until AFTER we start
-    // the trailing md op. This prevents hangs. See
-    // https://github.com/grpc/grpc/issues/11546
-    if (options.is_last_message()) {
-      ctx_->has_pending_ops_ = true;
-      return true;
-    }
-    ctx_->has_pending_ops_ = false;
-    return call_->cq()->Pluck(&ctx_->pending_ops_);
-  }
-
- private:
-  Call* const call_;
-  ServerContext* const ctx_;
-};
-
-}  // namespace internal
-
-/// Synchronous (blocking) server-side API for a bidirectional
-/// streaming call, where the incoming message stream coming from the client has
-/// messages of type \a R, and the outgoing message streaming coming from
-/// the server has messages of type \a W.
-template <class W, class R>
-class ServerReaderWriter final : public ServerReaderWriterInterface<W, R> {
- public:
-  /// See the \a ServerStreamingInterface.SendInitialMetadata method
-  /// for semantics. Note that initial metadata will be affected by the
-  /// \a ServerContext associated with this call.
-  void SendInitialMetadata() override { body_.SendInitialMetadata(); }
-
-  bool NextMessageSize(uint32_t* sz) override {
-    return body_.NextMessageSize(sz);
-  }
-
-  bool Read(R* msg) override { return body_.Read(msg); }
-
-  /// See the \a WriterInterface.Write(const W& msg, WriteOptions options)
-  /// method for semantics.
-  /// Side effect:
-  ///   Also sends initial metadata if not already sent (using the \a
-  ///   ServerContext associated with this call).
-  using internal::WriterInterface<W>::Write;
-  bool Write(const W& msg, WriteOptions options) override {
-    return body_.Write(msg, options);
-  }
-
- private:
-  internal::ServerReaderWriterBody<W, R> body_;
-
-  friend class internal::TemplatedBidiStreamingHandler<ServerReaderWriter<W, R>,
-                                                       false>;
-  ServerReaderWriter(internal::Call* call, ServerContext* ctx)
-      : body_(call, ctx) {}
-};
-
-/// A class to represent a flow-controlled unary call. This is something
-/// of a hybrid between conventional unary and streaming. This is invoked
-/// through a unary call on the client side, but the server responds to it
-/// as though it were a single-ping-pong streaming call. The server can use
-/// the \a NextMessageSize method to determine an upper-bound on the size of
-/// the message. A key difference relative to streaming: ServerUnaryStreamer
-/// must have exactly 1 Read and exactly 1 Write, in that order, to function
-/// correctly. Otherwise, the RPC is in error.
-template <class RequestType, class ResponseType>
-class ServerUnaryStreamer final
-    : public ServerReaderWriterInterface<ResponseType, RequestType> {
- public:
-  /// Block to send initial metadata to client.
-  /// Implicit input parameter:
-  ///    - the \a ServerContext associated with this call will be used for
-  ///      sending initial metadata.
-  void SendInitialMetadata() override { body_.SendInitialMetadata(); }
-
-  /// Get an upper bound on the request message size from the client.
-  bool NextMessageSize(uint32_t* sz) override {
-    return body_.NextMessageSize(sz);
-  }
-
-  /// Read a message of type \a R into \a msg. Completion will be notified by \a
-  /// tag on the associated completion queue.
-  /// This is thread-safe with respect to \a Write or \a WritesDone methods. It
-  /// should not be called concurrently with other streaming APIs
-  /// on the same stream. It is not meaningful to call it concurrently
-  /// with another \a ReaderInterface::Read on the same stream since reads on
-  /// the same stream are delivered in order.
-  ///
-  /// \param[out] msg Where to eventually store the read message.
-  /// \param[in] tag The tag identifying the operation.
-  bool Read(RequestType* request) override {
-    if (read_done_) {
-      return false;
-    }
-    read_done_ = true;
-    return body_.Read(request);
-  }
-
-  /// Block to write \a msg to the stream with WriteOptions \a options.
-  /// This is thread-safe with respect to \a ReaderInterface::Read
-  ///
-  /// \param msg The message to be written to the stream.
-  /// \param options The WriteOptions affecting the write operation.
-  ///
-  /// \return \a true on success, \a false when the stream has been closed.
-  using internal::WriterInterface<ResponseType>::Write;
-  bool Write(const ResponseType& response, WriteOptions options) override {
-    if (write_done_ || !read_done_) {
-      return false;
-    }
-    write_done_ = true;
-    return body_.Write(response, options);
-  }
-
- private:
-  internal::ServerReaderWriterBody<ResponseType, RequestType> body_;
-  bool read_done_;
-  bool write_done_;
-
-  friend class internal::TemplatedBidiStreamingHandler<
-      ServerUnaryStreamer<RequestType, ResponseType>, true>;
-  ServerUnaryStreamer(internal::Call* call, ServerContext* ctx)
-      : body_(call, ctx), read_done_(false), write_done_(false) {}
-};
-
-/// A class to represent a flow-controlled server-side streaming call.
-/// This is something of a hybrid between server-side and bidi streaming.
-/// This is invoked through a server-side streaming call on the client side,
-/// but the server responds to it as though it were a bidi streaming call that
-/// must first have exactly 1 Read and then any number of Writes.
-template <class RequestType, class ResponseType>
-class ServerSplitStreamer final
-    : public ServerReaderWriterInterface<ResponseType, RequestType> {
- public:
-  /// Block to send initial metadata to client.
-  /// Implicit input parameter:
-  ///    - the \a ServerContext associated with this call will be used for
-  ///      sending initial metadata.
-  void SendInitialMetadata() override { body_.SendInitialMetadata(); }
-
-  /// Get an upper bound on the request message size from the client.
-  bool NextMessageSize(uint32_t* sz) override {
-    return body_.NextMessageSize(sz);
-  }
-
-  /// Read a message of type \a R into \a msg. Completion will be notified by \a
-  /// tag on the associated completion queue.
-  /// This is thread-safe with respect to \a Write or \a WritesDone methods. It
-  /// should not be called concurrently with other streaming APIs
-  /// on the same stream. It is not meaningful to call it concurrently
-  /// with another \a ReaderInterface::Read on the same stream since reads on
-  /// the same stream are delivered in order.
-  ///
-  /// \param[out] msg Where to eventually store the read message.
-  /// \param[in] tag The tag identifying the operation.
-  bool Read(RequestType* request) override {
-    if (read_done_) {
-      return false;
-    }
-    read_done_ = true;
-    return body_.Read(request);
-  }
-
-  /// Block to write \a msg to the stream with WriteOptions \a options.
-  /// This is thread-safe with respect to \a ReaderInterface::Read
-  ///
-  /// \param msg The message to be written to the stream.
-  /// \param options The WriteOptions affecting the write operation.
-  ///
-  /// \return \a true on success, \a false when the stream has been closed.
-  using internal::WriterInterface<ResponseType>::Write;
-  bool Write(const ResponseType& response, WriteOptions options) override {
-    return read_done_ && body_.Write(response, options);
-  }
-
- private:
-  internal::ServerReaderWriterBody<ResponseType, RequestType> body_;
-  bool read_done_;
-
-  friend class internal::TemplatedBidiStreamingHandler<
-      ServerSplitStreamer<RequestType, ResponseType>, false>;
-  ServerSplitStreamer(internal::Call* call, ServerContext* ctx)
-      : body_(call, ctx), read_done_(false) {}
-};
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/sync_stream.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_SYNC_STREAM_H
diff --git a/include/grpc++/impl/codegen/time.h b/include/grpc++/impl/codegen/time.h
index d464d6e..f9b70f8 100644
--- a/include/grpc++/impl/codegen/time.h
+++ b/include/grpc++/impl/codegen/time.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,74 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_CODEGEN_TIME_H
 #define GRPCXX_IMPL_CODEGEN_TIME_H
 
-#include <chrono>
-
-#include <grpc++/impl/codegen/config.h>
-#include <grpc/impl/codegen/grpc_types.h>
-
-namespace grpc {
-
-/** If you are trying to use CompletionQueue::AsyncNext with a time class that
-    isn't either gpr_timespec or std::chrono::system_clock::time_point, you
-    will most likely be looking at this comment as your compiler will have
-    fired an error below. In order to fix this issue, you have two potential
-    solutions:
-
-      1. Use gpr_timespec or std::chrono::system_clock::time_point instead
-      2. Specialize the TimePoint class with whichever time class that you
-         want to use here. See below for two examples of how to do this.
- */
-template <typename T>
-class TimePoint {
- public:
-  TimePoint(const T& time) { you_need_a_specialization_of_TimePoint(); }
-  gpr_timespec raw_time() {
-    gpr_timespec t;
-    return t;
-  }
-
- private:
-  void you_need_a_specialization_of_TimePoint();
-};
-
-template <>
-class TimePoint<gpr_timespec> {
- public:
-  TimePoint(const gpr_timespec& time) : time_(time) {}
-  gpr_timespec raw_time() { return time_; }
-
- private:
-  gpr_timespec time_;
-};
-
-}  // namespace grpc
-
-namespace grpc {
-
-// from and to should be absolute time.
-void Timepoint2Timespec(const std::chrono::system_clock::time_point& from,
-                        gpr_timespec* to);
-void TimepointHR2Timespec(
-    const std::chrono::high_resolution_clock::time_point& from,
-    gpr_timespec* to);
-
-std::chrono::system_clock::time_point Timespec2Timepoint(gpr_timespec t);
-
-template <>
-class TimePoint<std::chrono::system_clock::time_point> {
- public:
-  TimePoint(const std::chrono::system_clock::time_point& time) {
-    Timepoint2Timespec(time, &time_);
-  }
-  gpr_timespec raw_time() const { return time_; }
-
- private:
-  gpr_timespec time_;
-};
-
-}  // namespace grpc
+#include <grpcpp/impl/codegen/time.h>
 
 #endif  // GRPCXX_IMPL_CODEGEN_TIME_H
diff --git a/include/grpc++/impl/grpc_library.h b/include/grpc++/impl/grpc_library.h
index 55c867d..f34a281 100644
--- a/include/grpc++/impl/grpc_library.h
+++ b/include/grpc++/impl/grpc_library.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,46 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_GRPC_LIBRARY_H
 #define GRPCXX_IMPL_GRPC_LIBRARY_H
 
-#include <iostream>
-
-#include <grpc++/impl/codegen/config.h>
-#include <grpc++/impl/codegen/core_codegen.h>
-#include <grpc++/impl/codegen/grpc_library.h>
-#include <grpc/grpc.h>
-
-namespace grpc {
-
-namespace internal {
-class GrpcLibrary final : public GrpcLibraryInterface {
- public:
-  void init() override { grpc_init(); }
-  void shutdown() override { grpc_shutdown(); }
-};
-
-static GrpcLibrary g_gli;
-static CoreCodegen g_core_codegen;
-
-/// Instantiating this class ensures the proper initialization of gRPC.
-class GrpcLibraryInitializer final {
- public:
-  GrpcLibraryInitializer() {
-    if (grpc::g_glip == nullptr) {
-      grpc::g_glip = &g_gli;
-    }
-    if (grpc::g_core_codegen_interface == nullptr) {
-      grpc::g_core_codegen_interface = &g_core_codegen;
-    }
-  }
-
-  /// A no-op method to force the linker to reference this class, which will
-  /// take care of initializing and shutting down the gRPC runtime.
-  int summon() { return 0; }
-};
-
-}  // namespace internal
-}  // namespace grpc
+#include <grpcpp/impl/grpc_library.h>
 
 #endif  // GRPCXX_IMPL_GRPC_LIBRARY_H
diff --git a/include/grpc++/impl/method_handler_impl.h b/include/grpc++/impl/method_handler_impl.h
index 0b1ab02..3840f48 100644
--- a/include/grpc++/impl/method_handler_impl.h
+++ b/include/grpc++/impl/method_handler_impl.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_METHOD_HANDLER_IMPL_H
 #define GRPCXX_IMPL_METHOD_HANDLER_IMPL_H
 
-#include <grpc++/impl/codegen/method_handler_impl.h>
+#include <grpcpp/impl/method_handler_impl.h>
 
 #endif  // GRPCXX_IMPL_METHOD_HANDLER_IMPL_H
diff --git a/include/grpc++/impl/rpc_method.h b/include/grpc++/impl/rpc_method.h
index 51e95bb..7cba7c4 100644
--- a/include/grpc++/impl/rpc_method.h
+++ b/include/grpc++/impl/rpc_method.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_RPC_METHOD_H
 #define GRPCXX_IMPL_RPC_METHOD_H
 
-#include <grpc++/impl/codegen/rpc_method.h>
+#include <grpcpp/impl/rpc_method.h>
 
 #endif  // GRPCXX_IMPL_RPC_METHOD_H
diff --git a/include/grpc++/impl/rpc_service_method.h b/include/grpc++/impl/rpc_service_method.h
index efde374..2c75087 100644
--- a/include/grpc++/impl/rpc_service_method.h
+++ b/include/grpc++/impl/rpc_service_method.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_RPC_SERVICE_METHOD_H
 #define GRPCXX_IMPL_RPC_SERVICE_METHOD_H
 
-#include <grpc++/impl/codegen/rpc_service_method.h>
+#include <grpcpp/impl/rpc_service_method.h>
 
 #endif  // GRPCXX_IMPL_RPC_SERVICE_METHOD_H
diff --git a/include/grpc++/impl/serialization_traits.h b/include/grpc++/impl/serialization_traits.h
index 91e894c..33b3a0b 100644
--- a/include/grpc++/impl/serialization_traits.h
+++ b/include/grpc++/impl/serialization_traits.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_SERIALIZATION_TRAITS_H
 #define GRPCXX_IMPL_SERIALIZATION_TRAITS_H
 
-#include <grpc++/impl/codegen/serialization_traits.h>
+#include <grpcpp/impl/serialization_traits.h>
 
 #endif  // GRPCXX_IMPL_SERIALIZATION_TRAITS_H
diff --git a/include/grpc++/impl/server_builder_option.h b/include/grpc++/impl/server_builder_option.h
index ab04a1c..833f8db 100644
--- a/include/grpc++/impl/server_builder_option.h
+++ b/include/grpc++/impl/server_builder_option.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,28 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_SERVER_BUILDER_OPTION_H
 #define GRPCXX_IMPL_SERVER_BUILDER_OPTION_H
 
-#include <map>
-#include <memory>
-
-#include <grpc++/impl/server_builder_plugin.h>
-#include <grpc++/support/channel_arguments.h>
-
-namespace grpc {
-
-/// Interface to pass an option to a \a ServerBuilder.
-class ServerBuilderOption {
- public:
-  virtual ~ServerBuilderOption() {}
-  /// Alter the \a ChannelArguments used to create the gRPC server.
-  virtual void UpdateArguments(ChannelArguments* args) = 0;
-  /// Alter the ServerBuilderPlugin map that will be added into ServerBuilder.
-  virtual void UpdatePlugins(
-      std::vector<std::unique_ptr<ServerBuilderPlugin>>* plugins) = 0;
-};
-
-}  // namespace grpc
+#include <grpcpp/impl/server_builder_option.h>
 
 #endif  // GRPCXX_IMPL_SERVER_BUILDER_OPTION_H
diff --git a/include/grpc++/impl/server_builder_plugin.h b/include/grpc++/impl/server_builder_plugin.h
index e15cd7b..844d32c 100644
--- a/include/grpc++/impl/server_builder_plugin.h
+++ b/include/grpc++/impl/server_builder_plugin.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,50 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_SERVER_BUILDER_PLUGIN_H
 #define GRPCXX_IMPL_SERVER_BUILDER_PLUGIN_H
 
-#include <memory>
-
-#include <grpc++/support/config.h>
-
-namespace grpc {
-
-class ServerBuilder;
-class ServerInitializer;
-class ChannelArguments;
-
-/// This interface is meant for internal usage only. Implementations of this
-/// interface should add themselves to a \a ServerBuilder instance through the
-/// \a InternalAddPluginFactory method.
-class ServerBuilderPlugin {
- public:
-  virtual ~ServerBuilderPlugin() {}
-  virtual grpc::string name() = 0;
-
-  /// UpdateServerBuilder will be called at the beginning of
-  /// \a ServerBuilder::BuildAndStart().
-  virtual void UpdateServerBuilder(ServerBuilder* builder) {}
-
-  /// InitServer will be called in ServerBuilder::BuildAndStart(), after the
-  /// Server instance is created.
-  virtual void InitServer(ServerInitializer* si) = 0;
-
-  /// Finish will be called at the end of ServerBuilder::BuildAndStart().
-  virtual void Finish(ServerInitializer* si) = 0;
-
-  /// ChangeArguments is an interface that can be used in
-  /// ServerBuilderOption::UpdatePlugins
-  virtual void ChangeArguments(const grpc::string& name, void* value) = 0;
-
-  /// UpdateChannelArguments will be called in ServerBuilder::BuildAndStart(),
-  /// before the Server instance is created.
-  virtual void UpdateChannelArguments(ChannelArguments* args) {}
-
-  virtual bool has_sync_methods() const { return false; }
-  virtual bool has_async_methods() const { return false; }
-};
-
-}  // namespace grpc
+#include <grpcpp/impl/server_builder_plugin.h>
 
 #endif  // GRPCXX_IMPL_SERVER_BUILDER_PLUGIN_H
diff --git a/include/grpc++/impl/server_initializer.h b/include/grpc++/impl/server_initializer.h
index 873c46f..6a1669c 100644
--- a/include/grpc++/impl/server_initializer.h
+++ b/include/grpc++/impl/server_initializer.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,40 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_SERVER_INITIALIZER_H
 #define GRPCXX_IMPL_SERVER_INITIALIZER_H
 
-#include <memory>
-#include <vector>
-
-#include <grpc++/server.h>
-
-namespace grpc {
-
-class Server;
-class Service;
-
-class ServerInitializer {
- public:
-  ServerInitializer(Server* server) : server_(server) {}
-
-  bool RegisterService(std::shared_ptr<Service> service) {
-    if (!server_->RegisterService(nullptr, service.get())) {
-      return false;
-    }
-    default_services_.push_back(service);
-    return true;
-  }
-
-  const std::vector<grpc::string>* GetServiceList() {
-    return &server_->services_;
-  }
-
- private:
-  Server* server_;
-  std::vector<std::shared_ptr<Service> > default_services_;
-};
-
-}  // namespace grpc
+#include <grpcpp/impl/server_initializer.h>
 
 #endif  // GRPCXX_IMPL_SERVER_INITIALIZER_H
diff --git a/include/grpc++/impl/service_type.h b/include/grpc++/impl/service_type.h
index 6a9e90a..8642216 100644
--- a/include/grpc++/impl/service_type.h
+++ b/include/grpc++/impl/service_type.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_SERVICE_TYPE_H
 #define GRPCXX_IMPL_SERVICE_TYPE_H
 
-#include <grpc++/impl/codegen/service_type.h>
+#include <grpcpp/impl/service_type.h>
 
 #endif  // GRPCXX_IMPL_SERVICE_TYPE_H
diff --git a/include/grpc++/impl/sync_cxx11.h b/include/grpc++/impl/sync_cxx11.h
index 64d467f..8bcfb2c 100644
--- a/include/grpc++/impl/sync_cxx11.h
+++ b/include/grpc++/impl/sync_cxx11.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_SYNC_CXX11_H
 #define GRPCXX_IMPL_SYNC_CXX11_H
 
-#include <grpc++/impl/codegen/sync_cxx11.h>
+#include <grpcpp/impl/sync_cxx11.h>
 
 #endif  // GRPCXX_IMPL_SYNC_CXX11_H
diff --git a/include/grpc++/impl/sync_no_cxx11.h b/include/grpc++/impl/sync_no_cxx11.h
index cc0177e..5264567 100644
--- a/include/grpc++/impl/sync_no_cxx11.h
+++ b/include/grpc++/impl/sync_no_cxx11.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_IMPL_SYNC_NO_CXX11_H
 #define GRPCXX_IMPL_SYNC_NO_CXX11_H
 
-#include <grpc++/impl/codegen/sync_no_cxx11.h>
+#include <grpcpp/impl/sync_no_cxx11.h>
 
 #endif  // GRPCXX_IMPL_SYNC_NO_CXX11_H
diff --git a/include/grpc++/resource_quota.h b/include/grpc++/resource_quota.h
index ef214db..aad1b56 100644
--- a/include/grpc++/resource_quota.h
+++ b/include/grpc++/resource_quota.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,43 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_RESOURCE_QUOTA_H
 #define GRPCXX_RESOURCE_QUOTA_H
 
-struct grpc_resource_quota;
-
-#include <grpc++/impl/codegen/config.h>
-#include <grpc++/impl/codegen/grpc_library.h>
-
-namespace grpc {
-
-/// ResourceQuota represents a bound on memory usage by the gRPC library.
-/// A ResourceQuota can be attached to a server (via \a ServerBuilder),
-/// or a client channel (via \a ChannelArguments).
-/// gRPC will attempt to keep memory used by all attached entities
-/// below the ResourceQuota bound.
-class ResourceQuota final : private GrpcLibraryCodegen {
- public:
-  /// \param name - a unique name for this ResourceQuota.
-  explicit ResourceQuota(const grpc::string& name);
-  ResourceQuota();
-  ~ResourceQuota();
-
-  /// Resize this \a ResourceQuota to a new size. If \a new_size is smaller
-  /// than the current size of the pool, memory usage will be monotonically
-  /// decreased until it falls under \a new_size.
-  /// No time bound is given for this to occur however.
-  ResourceQuota& Resize(size_t new_size);
-
-  grpc_resource_quota* c_resource_quota() const { return impl_; }
-
- private:
-  ResourceQuota(const ResourceQuota& rhs);
-  ResourceQuota& operator=(const ResourceQuota& rhs);
-
-  grpc_resource_quota* const impl_;
-};
-
-}  // namespace grpc
+#include <grpcpp/resource_quota.h>
 
 #endif  // GRPCXX_RESOURCE_QUOTA_H
diff --git a/include/grpc++/security/auth_context.h b/include/grpc++/security/auth_context.h
index 71f5d6e..9fe59d4 100644
--- a/include/grpc++/security/auth_context.h
+++ b/include/grpc++/security/auth_context.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_SECURITY_AUTH_CONTEXT_H
 #define GRPCXX_SECURITY_AUTH_CONTEXT_H
 
-#include <grpc++/impl/codegen/security/auth_context.h>
+#include <grpcpp/security/auth_context.h>
 
 #endif  // GRPCXX_SECURITY_AUTH_CONTEXT_H
diff --git a/include/grpc++/security/auth_metadata_processor.h b/include/grpc++/security/auth_metadata_processor.h
index a49e30f..d045313 100644
--- a/include/grpc++/security/auth_metadata_processor.h
+++ b/include/grpc++/security/auth_metadata_processor.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,46 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_SECURITY_AUTH_METADATA_PROCESSOR_H
 #define GRPCXX_SECURITY_AUTH_METADATA_PROCESSOR_H
 
-#include <map>
-
-#include <grpc++/security/auth_context.h>
-#include <grpc++/support/status.h>
-#include <grpc++/support/string_ref.h>
-
-namespace grpc {
-
-/// Interface allowing custom server-side authorization based on credentials
-/// encoded in metadata.  Objects of this type can be passed to
-/// \a ServerCredentials::SetAuthMetadataProcessor().
-class AuthMetadataProcessor {
- public:
-  typedef std::multimap<grpc::string_ref, grpc::string_ref> InputMetadata;
-  typedef std::multimap<grpc::string, grpc::string> OutputMetadata;
-
-  virtual ~AuthMetadataProcessor() {}
-
-  /// If this method returns true, the \a Process function will be scheduled in
-  /// a different thread from the one processing the call.
-  virtual bool IsBlocking() const { return true; }
-
-  /// context is read/write: it contains the properties of the channel peer and
-  /// it is the job of the Process method to augment it with properties derived
-  /// from the passed-in auth_metadata.
-  /// consumed_auth_metadata needs to be filled with metadata that has been
-  /// consumed by the processor and will be removed from the call.
-  /// response_metadata is the metadata that will be sent as part of the
-  /// response.
-  /// If the return value is not Status::OK, the rpc call will be aborted with
-  /// the error code and error message sent back to the client.
-  virtual Status Process(const InputMetadata& auth_metadata,
-                         AuthContext* context,
-                         OutputMetadata* consumed_auth_metadata,
-                         OutputMetadata* response_metadata) = 0;
-};
-
-}  // namespace grpc
+#include <grpcpp/security/auth_metadata_processor.h>
 
 #endif  // GRPCXX_SECURITY_AUTH_METADATA_PROCESSOR_H
diff --git a/include/grpc++/security/credentials.h b/include/grpc++/security/credentials.h
index 92330d4..9404418 100644
--- a/include/grpc++/security/credentials.h
+++ b/include/grpc++/security/credentials.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,209 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_SECURITY_CREDENTIALS_H
 #define GRPCXX_SECURITY_CREDENTIALS_H
 
-#include <map>
-#include <memory>
-
-#include <grpc++/impl/codegen/grpc_library.h>
-#include <grpc++/security/auth_context.h>
-#include <grpc++/support/status.h>
-#include <grpc++/support/string_ref.h>
-
-struct grpc_call;
-
-namespace grpc {
-class ChannelArguments;
-class Channel;
-class SecureChannelCredentials;
-class CallCredentials;
-class SecureCallCredentials;
-
-/// A channel credentials object encapsulates all the state needed by a client
-/// to authenticate with a server for a given channel.
-/// It can make various assertions, e.g., about the client’s identity, role
-/// for all the calls on that channel.
-///
-/// \see https://grpc.io/docs/guides/auth.html
-class ChannelCredentials : private GrpcLibraryCodegen {
- public:
-  ChannelCredentials();
-  ~ChannelCredentials();
-
- protected:
-  friend std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
-      const std::shared_ptr<ChannelCredentials>& channel_creds,
-      const std::shared_ptr<CallCredentials>& call_creds);
-
-  virtual SecureChannelCredentials* AsSecureCredentials() = 0;
-
- private:
-  friend std::shared_ptr<Channel> CreateCustomChannel(
-      const grpc::string& target,
-      const std::shared_ptr<ChannelCredentials>& creds,
-      const ChannelArguments& args);
-
-  virtual std::shared_ptr<Channel> CreateChannel(
-      const grpc::string& target, const ChannelArguments& args) = 0;
-};
-
-/// A call credentials object encapsulates the state needed by a client to
-/// authenticate with a server for a given call on a channel.
-///
-/// \see https://grpc.io/docs/guides/auth.html
-class CallCredentials : private GrpcLibraryCodegen {
- public:
-  CallCredentials();
-  ~CallCredentials();
-
-  /// Apply this instance's credentials to \a call.
-  virtual bool ApplyToCall(grpc_call* call) = 0;
-
- protected:
-  friend std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
-      const std::shared_ptr<ChannelCredentials>& channel_creds,
-      const std::shared_ptr<CallCredentials>& call_creds);
-
-  friend std::shared_ptr<CallCredentials> CompositeCallCredentials(
-      const std::shared_ptr<CallCredentials>& creds1,
-      const std::shared_ptr<CallCredentials>& creds2);
-
-  virtual SecureCallCredentials* AsSecureCredentials() = 0;
-};
-
-/// Options used to build SslCredentials.
-struct SslCredentialsOptions {
-  /// The buffer containing the PEM encoding of the server root certificates. If
-  /// this parameter is empty, the default roots will be used.  The default
-  /// roots can be overridden using the \a GRPC_DEFAULT_SSL_ROOTS_FILE_PATH
-  /// environment variable pointing to a file on the file system containing the
-  /// roots.
-  grpc::string pem_root_certs;
-
-  /// The buffer containing the PEM encoding of the client's private key. This
-  /// parameter can be empty if the client does not have a private key.
-  grpc::string pem_private_key;
-
-  /// The buffer containing the PEM encoding of the client's certificate chain.
-  /// This parameter can be empty if the client does not have a certificate
-  /// chain.
-  grpc::string pem_cert_chain;
-};
-
-// Factories for building different types of Credentials The functions may
-// return empty shared_ptr when credentials cannot be created. If a
-// Credentials pointer is returned, it can still be invalid when used to create
-// a channel. A lame channel will be created then and all rpcs will fail on it.
-
-/// Builds credentials with reasonable defaults.
-///
-/// \warning Only use these credentials when connecting to a Google endpoint.
-/// Using these credentials to connect to any other service may result in this
-/// service being able to impersonate your client for requests to Google
-/// services.
-std::shared_ptr<ChannelCredentials> GoogleDefaultCredentials();
-
-/// Builds SSL Credentials given SSL specific options
-std::shared_ptr<ChannelCredentials> SslCredentials(
-    const SslCredentialsOptions& options);
-
-/// Builds credentials for use when running in GCE
-///
-/// \warning Only use these credentials when connecting to a Google endpoint.
-/// Using these credentials to connect to any other service may result in this
-/// service being able to impersonate your client for requests to Google
-/// services.
-std::shared_ptr<CallCredentials> GoogleComputeEngineCredentials();
-
-/// Constant for maximum auth token lifetime.
-constexpr long kMaxAuthTokenLifetimeSecs = 3600;
-
-/// Builds Service Account JWT Access credentials.
-/// json_key is the JSON key string containing the client's private key.
-/// token_lifetime_seconds is the lifetime in seconds of each Json Web Token
-/// (JWT) created with this credentials. It should not exceed
-/// \a kMaxAuthTokenLifetimeSecs or will be cropped to this value.
-std::shared_ptr<CallCredentials> ServiceAccountJWTAccessCredentials(
-    const grpc::string& json_key,
-    long token_lifetime_seconds = kMaxAuthTokenLifetimeSecs);
-
-/// Builds refresh token credentials.
-/// json_refresh_token is the JSON string containing the refresh token along
-/// with a client_id and client_secret.
-///
-/// \warning Only use these credentials when connecting to a Google endpoint.
-/// Using these credentials to connect to any other service may result in this
-/// service being able to impersonate your client for requests to Google
-/// services.
-std::shared_ptr<CallCredentials> GoogleRefreshTokenCredentials(
-    const grpc::string& json_refresh_token);
-
-/// Builds access token credentials.
-/// access_token is an oauth2 access token that was fetched using an out of band
-/// mechanism.
-///
-/// \warning Only use these credentials when connecting to a Google endpoint.
-/// Using these credentials to connect to any other service may result in this
-/// service being able to impersonate your client for requests to Google
-/// services.
-std::shared_ptr<CallCredentials> AccessTokenCredentials(
-    const grpc::string& access_token);
-
-/// Builds IAM credentials.
-///
-/// \warning Only use these credentials when connecting to a Google endpoint.
-/// Using these credentials to connect to any other service may result in this
-/// service being able to impersonate your client for requests to Google
-/// services.
-std::shared_ptr<CallCredentials> GoogleIAMCredentials(
-    const grpc::string& authorization_token,
-    const grpc::string& authority_selector);
-
-/// Combines a channel credentials and a call credentials into a composite
-/// channel credentials.
-std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
-    const std::shared_ptr<ChannelCredentials>& channel_creds,
-    const std::shared_ptr<CallCredentials>& call_creds);
-
-/// Combines two call credentials objects into a composite call credentials.
-std::shared_ptr<CallCredentials> CompositeCallCredentials(
-    const std::shared_ptr<CallCredentials>& creds1,
-    const std::shared_ptr<CallCredentials>& creds2);
-
-/// Credentials for an unencrypted, unauthenticated channel
-std::shared_ptr<ChannelCredentials> InsecureChannelCredentials();
-
-/// Credentials for a channel using Cronet.
-std::shared_ptr<ChannelCredentials> CronetChannelCredentials(void* engine);
-
-/// User defined metadata credentials.
-class MetadataCredentialsPlugin {
- public:
-  virtual ~MetadataCredentialsPlugin() {}
-
-  /// If this method returns true, the Process function will be scheduled in
-  /// a different thread from the one processing the call.
-  virtual bool IsBlocking() const { return true; }
-
-  /// Type of credentials this plugin is implementing.
-  virtual const char* GetType() const { return ""; }
-
-  /// Gets the auth metatada produced by this plugin.
-  /// The fully qualified method name is:
-  /// service_url + "/" + method_name.
-  /// The channel_auth_context contains (among other things), the identity of
-  /// the server.
-  virtual Status GetMetadata(
-      grpc::string_ref service_url, grpc::string_ref method_name,
-      const AuthContext& channel_auth_context,
-      std::multimap<grpc::string, grpc::string>* metadata) = 0;
-};
-
-std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
-    std::unique_ptr<MetadataCredentialsPlugin> plugin);
-
-}  // namespace grpc
+#include <grpcpp/security/credentials.h>
 
 #endif  // GRPCXX_SECURITY_CREDENTIALS_H
diff --git a/include/grpc++/security/server_credentials.h b/include/grpc++/security/server_credentials.h
index 74a61b5..c6d1c4f 100644
--- a/include/grpc++/security/server_credentials.h
+++ b/include/grpc++/security/server_credentials.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,76 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_SECURITY_SERVER_CREDENTIALS_H
 #define GRPCXX_SECURITY_SERVER_CREDENTIALS_H
 
-#include <memory>
-#include <vector>
-
-#include <grpc++/security/auth_metadata_processor.h>
-#include <grpc++/support/config.h>
-#include <grpc/grpc_security_constants.h>
-
-struct grpc_server;
-
-namespace grpc {
-class Server;
-
-/// Wrapper around \a grpc_server_credentials, a way to authenticate a server.
-class ServerCredentials {
- public:
-  virtual ~ServerCredentials();
-
-  /// This method is not thread-safe and has to be called before the server is
-  /// started. The last call to this function wins.
-  virtual void SetAuthMetadataProcessor(
-      const std::shared_ptr<AuthMetadataProcessor>& processor) = 0;
-
- private:
-  friend class ::grpc::Server;
-
-  /// Tries to bind \a server to the given \a addr (eg, localhost:1234,
-  /// 192.168.1.1:31416, [::1]:27182, etc.)
-  ///
-  /// \return bound port number on sucess, 0 on failure.
-  // TODO(dgq): the "port" part seems to be a misnomer.
-  virtual int AddPortToServer(const grpc::string& addr,
-                              grpc_server* server) = 0;
-};
-
-/// Options to create ServerCredentials with SSL
-struct SslServerCredentialsOptions {
-  /// \warning Deprecated
-  SslServerCredentialsOptions()
-      : force_client_auth(false),
-        client_certificate_request(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE) {}
-  SslServerCredentialsOptions(
-      grpc_ssl_client_certificate_request_type request_type)
-      : force_client_auth(false), client_certificate_request(request_type) {}
-
-  struct PemKeyCertPair {
-    grpc::string private_key;
-    grpc::string cert_chain;
-  };
-  grpc::string pem_root_certs;
-  std::vector<PemKeyCertPair> pem_key_cert_pairs;
-  /// \warning Deprecated
-  bool force_client_auth;
-
-  /// If both \a force_client_auth and \a client_certificate_request
-  /// fields are set, \a force_client_auth takes effect, i.e.
-  /// \a REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
-  /// will be enforced.
-  grpc_ssl_client_certificate_request_type client_certificate_request;
-};
-
-/// Builds SSL ServerCredentials given SSL specific options
-std::shared_ptr<ServerCredentials> SslServerCredentials(
-    const SslServerCredentialsOptions& options);
-
-/// Builds insecure server credentials.
-std::shared_ptr<ServerCredentials> InsecureServerCredentials();
-
-}  // namespace grpc
+#include <grpcpp/security/server_credentials.h>
 
 #endif  // GRPCXX_SECURITY_SERVER_CREDENTIALS_H
diff --git a/include/grpc++/server.h b/include/grpc++/server.h
index 01c4a60..086c24c 100644
--- a/include/grpc++/server.h
+++ b/include/grpc++/server.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,212 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_SERVER_H
 #define GRPCXX_SERVER_H
 
-#include <condition_variable>
-#include <list>
-#include <memory>
-#include <mutex>
-#include <vector>
-
-#include <grpc++/completion_queue.h>
-#include <grpc++/impl/call.h>
-#include <grpc++/impl/codegen/grpc_library.h>
-#include <grpc++/impl/codegen/server_interface.h>
-#include <grpc++/impl/rpc_service_method.h>
-#include <grpc++/security/server_credentials.h>
-#include <grpc++/support/channel_arguments.h>
-#include <grpc++/support/config.h>
-#include <grpc++/support/status.h>
-#include <grpc/compression.h>
-
-struct grpc_server;
-
-namespace grpc {
-
-class AsyncGenericService;
-class HealthCheckServiceInterface;
-class ServerContext;
-class ServerInitializer;
-
-/// Represents a gRPC server.
-///
-/// Use a \a grpc::ServerBuilder to create, configure, and start
-/// \a Server instances.
-class Server final : public ServerInterface, private GrpcLibraryCodegen {
- public:
-  ~Server();
-
-  /// Block until the server shuts down.
-  ///
-  /// \warning The server must be either shutting down or some other thread must
-  /// call \a Shutdown for this function to ever return.
-  void Wait() override;
-
-  /// Global callbacks are a set of hooks that are called when server
-  /// events occur.  \a SetGlobalCallbacks method is used to register
-  /// the hooks with gRPC.  Note that
-  /// the \a GlobalCallbacks instance will be shared among all
-  /// \a Server instances in an application and can be set exactly
-  /// once per application.
-  class GlobalCallbacks {
-   public:
-    virtual ~GlobalCallbacks() {}
-    /// Called before server is created.
-    virtual void UpdateArguments(ChannelArguments* args) {}
-    /// Called before application callback for each synchronous server request
-    virtual void PreSynchronousRequest(ServerContext* context) = 0;
-    /// Called after application callback for each synchronous server request
-    virtual void PostSynchronousRequest(ServerContext* context) = 0;
-    /// Called before server is started.
-    virtual void PreServerStart(Server* server) {}
-    /// Called after a server port is added.
-    virtual void AddPort(Server* server, const grpc::string& addr,
-                         ServerCredentials* creds, int port) {}
-  };
-  /// Set the global callback object. Can only be called once per application.
-  /// Does not take ownership of callbacks, and expects the pointed to object
-  /// to be alive until all server objects in the process have been destroyed.
-  /// The same \a GlobalCallbacks object will be used throughout the
-  /// application and is shared among all \a Server objects.
-  static void SetGlobalCallbacks(GlobalCallbacks* callbacks);
-
-  // Returns a \em raw pointer to the underlying \a grpc_server instance.
-  grpc_server* c_server();
-
-  /// Returns the health check service.
-  HealthCheckServiceInterface* GetHealthCheckService() const {
-    return health_check_service_.get();
-  }
-
-  /// Establish a channel for in-process communication
-  std::shared_ptr<Channel> InProcessChannel(const ChannelArguments& args);
-
- private:
-  friend class AsyncGenericService;
-  friend class ServerBuilder;
-  friend class ServerInitializer;
-
-  class SyncRequest;
-  class AsyncRequest;
-  class ShutdownRequest;
-
-  /// SyncRequestThreadManager is an implementation of ThreadManager. This class
-  /// is responsible for polling for incoming RPCs and calling the RPC handlers.
-  /// This is only used in case of a Sync server (i.e a server exposing a sync
-  /// interface)
-  class SyncRequestThreadManager;
-
-  class UnimplementedAsyncRequestContext;
-  class UnimplementedAsyncRequest;
-  class UnimplementedAsyncResponse;
-
-  /// Server constructors. To be used by \a ServerBuilder only.
-  ///
-  /// \param max_message_size Maximum message length that the channel can
-  /// receive.
-  ///
-  /// \param args The channel args
-  ///
-  /// \param sync_server_cqs The completion queues to use if the server is a
-  /// synchronous server (or a hybrid server). The server polls for new RPCs on
-  /// these queues
-  ///
-  /// \param min_pollers The minimum number of polling threads per server
-  /// completion queue (in param sync_server_cqs) to use for listening to
-  /// incoming requests (used only in case of sync server)
-  ///
-  /// \param max_pollers The maximum number of polling threads per server
-  /// completion queue (in param sync_server_cqs) to use for listening to
-  /// incoming requests (used only in case of sync server)
-  ///
-  /// \param sync_cq_timeout_msec The timeout to use when calling AsyncNext() on
-  /// server completion queues passed via sync_server_cqs param.
-  Server(int max_message_size, ChannelArguments* args,
-         std::shared_ptr<std::vector<std::unique_ptr<ServerCompletionQueue>>>
-             sync_server_cqs,
-         int min_pollers, int max_pollers, int sync_cq_timeout_msec);
-
-  /// Register a service. This call does not take ownership of the service.
-  /// The service must exist for the lifetime of the Server instance.
-  bool RegisterService(const grpc::string* host, Service* service) override;
-
-  /// Register a generic service. This call does not take ownership of the
-  /// service. The service must exist for the lifetime of the Server instance.
-  void RegisterAsyncGenericService(AsyncGenericService* service) override;
-
-  /// Try binding the server to the given \a addr endpoint
-  /// (port, and optionally including IP address to bind to).
-  ///
-  /// It can be invoked multiple times. Should be used before
-  /// starting the server.
-  ///
-  /// \param addr The address to try to bind to the server (eg, localhost:1234,
-  /// 192.168.1.1:31416, [::1]:27182, etc.).
-  /// \param creds The credentials associated with the server.
-  ///
-  /// \return bound port number on success, 0 on failure.
-  ///
-  /// \warning It is an error to call this method on an already started server.
-  int AddListeningPort(const grpc::string& addr,
-                       ServerCredentials* creds) override;
-
-  /// Start the server.
-  ///
-  /// \param cqs Completion queues for handling asynchronous services. The
-  /// caller is required to keep all completion queues live until the server is
-  /// destroyed.
-  /// \param num_cqs How many completion queues does \a cqs hold.
-  void Start(ServerCompletionQueue** cqs, size_t num_cqs) override;
-
-  void PerformOpsOnCall(internal::CallOpSetInterface* ops,
-                        internal::Call* call) override;
-
-  void ShutdownInternal(gpr_timespec deadline) override;
-
-  int max_receive_message_size() const override {
-    return max_receive_message_size_;
-  };
-
-  grpc_server* server() override { return server_; };
-
-  ServerInitializer* initializer();
-
-  const int max_receive_message_size_;
-
-  /// The following completion queues are ONLY used in case of Sync API
-  /// i.e. if the server has any services with sync methods. The server uses
-  /// these completion queues to poll for new RPCs
-  std::shared_ptr<std::vector<std::unique_ptr<ServerCompletionQueue>>>
-      sync_server_cqs_;
-
-  /// List of \a ThreadManager instances (one for each cq in
-  /// the \a sync_server_cqs)
-  std::vector<std::unique_ptr<SyncRequestThreadManager>> sync_req_mgrs_;
-
-  // Sever status
-  std::mutex mu_;
-  bool started_;
-  bool shutdown_;
-  bool shutdown_notified_;  // Was notify called on the shutdown_cv_
-
-  std::condition_variable shutdown_cv_;
-
-  std::shared_ptr<GlobalCallbacks> global_callbacks_;
-
-  std::vector<grpc::string> services_;
-  bool has_generic_service_;
-
-  // Pointer to the wrapped grpc_server.
-  grpc_server* server_;
-
-  std::unique_ptr<ServerInitializer> server_initializer_;
-
-  std::unique_ptr<HealthCheckServiceInterface> health_check_service_;
-  bool health_check_service_disabled_;
-};
-
-}  // namespace grpc
+#include <grpcpp/server.h>
 
 #endif  // GRPCXX_SERVER_H
diff --git a/include/grpc++/server_builder.h b/include/grpc++/server_builder.h
index e2bae4b..2c6dab4 100644
--- a/include/grpc++/server_builder.h
+++ b/include/grpc++/server_builder.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015-2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,264 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_SERVER_BUILDER_H
 #define GRPCXX_SERVER_BUILDER_H
 
-#include <climits>
-#include <map>
-#include <memory>
-#include <vector>
-
-#include <grpc++/impl/channel_argument_option.h>
-#include <grpc++/impl/server_builder_option.h>
-#include <grpc++/impl/server_builder_plugin.h>
-#include <grpc++/support/config.h>
-#include <grpc/compression.h>
-#include <grpc/support/cpu.h>
-#include <grpc/support/useful.h>
-#include <grpc/support/workaround_list.h>
-
-struct grpc_resource_quota;
-
-namespace grpc {
-
-class AsyncGenericService;
-class ResourceQuota;
-class CompletionQueue;
-class Server;
-class ServerCompletionQueue;
-class ServerCredentials;
-class Service;
-
-namespace testing {
-class ServerBuilderPluginTest;
-}  // namespace testing
-
-/// A builder class for the creation and startup of \a grpc::Server instances.
-class ServerBuilder {
- public:
-  ServerBuilder();
-  ~ServerBuilder();
-
-  //////////////////////////////////////////////////////////////////////////////
-  // Primary API's
-
-  /// Return a running server which is ready for processing calls.
-  /// Before calling, one typically needs to ensure that:
-  ///  1. a service is registered - so that the server knows what to serve
-  ///     (via RegisterService, or RegisterAsyncGenericService)
-  ///  2. a listening port has been added - so the server knows where to receive
-  ///     traffic (via AddListeningPort)
-  ///  3. [for async api only] completion queues have been added via
-  ///     AddCompletionQueue
-  std::unique_ptr<Server> BuildAndStart();
-
-  /// Register a service. This call does not take ownership of the service.
-  /// The service must exist for the lifetime of the \a Server instance returned
-  /// by \a BuildAndStart().
-  /// Matches requests with any :authority
-  ServerBuilder& RegisterService(Service* service);
-
-  /// Enlists an endpoint \a addr (port with an optional IP address) to
-  /// bind the \a grpc::Server object to be created to.
-  ///
-  /// It can be invoked multiple times.
-  ///
-  /// \param addr_uri The address to try to bind to the server in URI form. If
-  /// the scheme name is omitted, "dns:///" is assumed. To bind to any address,
-  /// please use IPv6 any, i.e., [::]:<port>, which also accepts IPv4
-  /// connections.  Valid values include dns:///localhost:1234, /
-  /// 192.168.1.1:31416, dns:///[::1]:27182, etc.).
-  /// \param creds The credentials associated with the server.
-  /// \param selected_port[out] If not `nullptr`, gets populated with the port
-  /// number bound to the \a grpc::Server for the corresponding endpoint after
-  /// it is successfully bound, 0 otherwise.
-  ///
-  ServerBuilder& AddListeningPort(const grpc::string& addr_uri,
-                                  std::shared_ptr<ServerCredentials> creds,
-                                  int* selected_port = nullptr);
-
-  /// Add a completion queue for handling asynchronous services.
-  ///
-  /// Best performance is typically obtained by using one thread per polling
-  /// completion queue.
-  ///
-  /// Caller is required to shutdown the server prior to shutting down the
-  /// returned completion queue. Caller is also required to drain the
-  /// completion queue after shutting it down. A typical usage scenario:
-  ///
-  /// // While building the server:
-  /// ServerBuilder builder;
-  /// ...
-  /// cq_ = builder.AddCompletionQueue();
-  /// server_ = builder.BuildAndStart();
-  ///
-  /// // While shutting down the server;
-  /// server_->Shutdown();
-  /// cq_->Shutdown();  // Always *after* the associated server's Shutdown()!
-  /// // Drain the cq_ that was created
-  /// void* ignored_tag;
-  /// bool ignored_ok;
-  /// while (cq_->Next(&ignored_tag, &ignored_ok)) { }
-  ///
-  /// \param is_frequently_polled This is an optional parameter to inform gRPC
-  /// library about whether this completion queue would be frequently polled
-  /// (i.e. by calling \a Next() or \a AsyncNext()). The default value is
-  /// 'true' and is the recommended setting. Setting this to 'false' (i.e.
-  /// not polling the completion queue frequently) will have a significantly
-  /// negative performance impact and hence should not be used in production
-  /// use cases.
-  std::unique_ptr<ServerCompletionQueue> AddCompletionQueue(
-      bool is_frequently_polled = true);
-
-  //////////////////////////////////////////////////////////////////////////////
-  // Less commonly used RegisterService variants
-
-  /// Register a service. This call does not take ownership of the service.
-  /// The service must exist for the lifetime of the \a Server instance returned
-  /// by \a BuildAndStart().
-  /// Only matches requests with :authority \a host
-  ServerBuilder& RegisterService(const grpc::string& host, Service* service);
-
-  /// Register a generic service.
-  /// Matches requests with any :authority
-  /// This is mostly useful for writing generic gRPC Proxies where the exact
-  /// serialization format is unknown
-  ServerBuilder& RegisterAsyncGenericService(AsyncGenericService* service);
-
-  //////////////////////////////////////////////////////////////////////////////
-  // Fine control knobs
-
-  /// Set max receive message size in bytes.
-  ServerBuilder& SetMaxReceiveMessageSize(int max_receive_message_size) {
-    max_receive_message_size_ = max_receive_message_size;
-    return *this;
-  }
-
-  /// Set max send message size in bytes.
-  ServerBuilder& SetMaxSendMessageSize(int max_send_message_size) {
-    max_send_message_size_ = max_send_message_size;
-    return *this;
-  }
-
-  /// \deprecated For backward compatibility.
-  ServerBuilder& SetMaxMessageSize(int max_message_size) {
-    return SetMaxReceiveMessageSize(max_message_size);
-  }
-
-  /// Set the support status for compression algorithms. All algorithms are
-  /// enabled by default.
-  ///
-  /// Incoming calls compressed with an unsupported algorithm will fail with
-  /// \a GRPC_STATUS_UNIMPLEMENTED.
-  ServerBuilder& SetCompressionAlgorithmSupportStatus(
-      grpc_compression_algorithm algorithm, bool enabled);
-
-  /// The default compression level to use for all channel calls in the
-  /// absence of a call-specific level.
-  ServerBuilder& SetDefaultCompressionLevel(grpc_compression_level level);
-
-  /// The default compression algorithm to use for all channel calls in the
-  /// absence of a call-specific level. Note that it overrides any compression
-  /// level set by \a SetDefaultCompressionLevel.
-  ServerBuilder& SetDefaultCompressionAlgorithm(
-      grpc_compression_algorithm algorithm);
-
-  /// Set the attached buffer pool for this server
-  ServerBuilder& SetResourceQuota(const ResourceQuota& resource_quota);
-
-  ServerBuilder& SetOption(std::unique_ptr<ServerBuilderOption> option);
-
-  /// Options for synchronous servers.
-  enum SyncServerOption {
-    NUM_CQS,         ///< Number of completion queues.
-    MIN_POLLERS,     ///< Minimum number of polling threads.
-    MAX_POLLERS,     ///< Maximum number of polling threads.
-    CQ_TIMEOUT_MSEC  ///< Completion queue timeout in milliseconds.
-  };
-
-  /// Only useful if this is a Synchronous server.
-  ServerBuilder& SetSyncServerOption(SyncServerOption option, int value);
-
-  /// Add a channel argument (an escape hatch to tuning core library parameters
-  /// directly)
-  template <class T>
-  ServerBuilder& AddChannelArgument(const grpc::string& arg, const T& value) {
-    return SetOption(MakeChannelArgumentOption(arg, value));
-  }
-
-  /// For internal use only: Register a ServerBuilderPlugin factory function.
-  static void InternalAddPluginFactory(
-      std::unique_ptr<ServerBuilderPlugin> (*CreatePlugin)());
-
-  /// Enable a server workaround. Do not use unless you know what the workaround
-  /// does. For explanation and detailed descriptions of workarounds, see
-  /// doc/workarounds.md.
-  ServerBuilder& EnableWorkaround(grpc_workaround_list id);
-
- private:
-  friend class ::grpc::testing::ServerBuilderPluginTest;
-
-  struct Port {
-    grpc::string addr;
-    std::shared_ptr<ServerCredentials> creds;
-    int* selected_port;
-  };
-
-  struct SyncServerSettings {
-    SyncServerSettings()
-        : num_cqs(1), min_pollers(1), max_pollers(2), cq_timeout_msec(10000) {}
-
-    /// Number of server completion queues to create to listen to incoming RPCs.
-    int num_cqs;
-
-    /// Minimum number of threads per completion queue that should be listening
-    /// to incoming RPCs.
-    int min_pollers;
-
-    /// Maximum number of threads per completion queue that can be listening to
-    /// incoming RPCs.
-    int max_pollers;
-
-    /// The timeout for server completion queue's AsyncNext call.
-    int cq_timeout_msec;
-  };
-
-  typedef std::unique_ptr<grpc::string> HostString;
-  struct NamedService {
-    explicit NamedService(Service* s) : service(s) {}
-    NamedService(const grpc::string& h, Service* s)
-        : host(new grpc::string(h)), service(s) {}
-    HostString host;
-    Service* service;
-  };
-
-  int max_receive_message_size_;
-  int max_send_message_size_;
-  std::vector<std::unique_ptr<ServerBuilderOption>> options_;
-  std::vector<std::unique_ptr<NamedService>> services_;
-  std::vector<Port> ports_;
-
-  SyncServerSettings sync_server_settings_;
-
-  /// List of completion queues added via \a AddCompletionQueue method.
-  std::vector<ServerCompletionQueue*> cqs_;
-
-  std::shared_ptr<ServerCredentials> creds_;
-  std::vector<std::unique_ptr<ServerBuilderPlugin>> plugins_;
-  grpc_resource_quota* resource_quota_;
-  AsyncGenericService* generic_service_;
-  struct {
-    bool is_set;
-    grpc_compression_level level;
-  } maybe_default_compression_level_;
-  struct {
-    bool is_set;
-    grpc_compression_algorithm algorithm;
-  } maybe_default_compression_algorithm_;
-  uint32_t enabled_compression_algorithms_bitset_;
-};
-
-}  // namespace grpc
+#include <grpcpp/server_builder.h>
 
 #endif  // GRPCXX_SERVER_BUILDER_H
diff --git a/include/grpc++/server_context.h b/include/grpc++/server_context.h
index f9b98e1..672ccdc 100644
--- a/include/grpc++/server_context.h
+++ b/include/grpc++/server_context.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_SERVER_CONTEXT_H
 #define GRPCXX_SERVER_CONTEXT_H
 
-#include <grpc++/impl/codegen/server_context.h>
+#include <grpcpp/server_context.h>
 
 #endif  // GRPCXX_SERVER_CONTEXT_H
diff --git a/include/grpc++/server_posix.h b/include/grpc++/server_posix.h
index 6cafcff..d2866d9 100644
--- a/include/grpc++/server_posix.h
+++ b/include/grpc++/server_posix.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,27 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_SERVER_POSIX_H
 #define GRPCXX_SERVER_POSIX_H
 
-#include <memory>
-
-#include <grpc++/server.h>
-#include <grpc/support/port_platform.h>
-
-namespace grpc {
-
-#ifdef GPR_SUPPORT_CHANNELS_FROM_FD
-
-/// Add a new client to a \a Server communicating over the given
-/// file descriptor.
-///
-/// \param server The server to add the client to.
-/// \param fd The file descriptor representing a socket.
-void AddInsecureChannelFromFd(Server* server, int fd);
-
-#endif  // GPR_SUPPORT_CHANNELS_FROM_FD
-
-}  // namespace grpc
+#include <grpcpp/server_posix.h>
 
 #endif  // GRPCXX_SERVER_POSIX_H
diff --git a/include/grpc++/support/async_stream.h b/include/grpc++/support/async_stream.h
index f2cab84..9bb2b72 100644
--- a/include/grpc++/support/async_stream.h
+++ b/include/grpc++/support/async_stream.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_SUPPORT_ASYNC_STREAM_H
 #define GRPCXX_SUPPORT_ASYNC_STREAM_H
 
-#include <grpc++/impl/codegen/async_stream.h>
+#include <grpcpp/support/async_stream.h>
 
 #endif  // GRPCXX_SUPPORT_ASYNC_STREAM_H
diff --git a/include/grpc++/support/async_unary_call.h b/include/grpc++/support/async_unary_call.h
index 4947c44..56fbf31 100644
--- a/include/grpc++/support/async_unary_call.h
+++ b/include/grpc++/support/async_unary_call.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_SUPPORT_ASYNC_UNARY_CALL_H
 #define GRPCXX_SUPPORT_ASYNC_UNARY_CALL_H
 
-#include <grpc++/impl/codegen/async_unary_call.h>
+#include <grpcpp/support/async_unary_call.h>
 
 #endif  // GRPCXX_SUPPORT_ASYNC_UNARY_CALL_H
diff --git a/include/grpc++/support/byte_buffer.h b/include/grpc++/support/byte_buffer.h
index 81fa3b0..ec607ee 100644
--- a/include/grpc++/support/byte_buffer.h
+++ b/include/grpc++/support/byte_buffer.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,16 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_SUPPORT_BYTE_BUFFER_H
 #define GRPCXX_SUPPORT_BYTE_BUFFER_H
 
-#include <grpc++/impl/codegen/byte_buffer.h>
-#include <grpc++/impl/serialization_traits.h>
-#include <grpc++/support/config.h>
-#include <grpc++/support/slice.h>
-#include <grpc++/support/status.h>
-#include <grpc/byte_buffer.h>
-#include <grpc/grpc.h>
-#include <grpc/support/log.h>
+#include <grpcpp/support/byte_buffer.h>
 
 #endif  // GRPCXX_SUPPORT_BYTE_BUFFER_H
diff --git a/include/grpc++/support/channel_arguments.h b/include/grpc++/support/channel_arguments.h
index c9879d8..6d5300c 100644
--- a/include/grpc++/support/channel_arguments.h
+++ b/include/grpc++/support/channel_arguments.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,127 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_SUPPORT_CHANNEL_ARGUMENTS_H
 #define GRPCXX_SUPPORT_CHANNEL_ARGUMENTS_H
 
-#include <list>
-#include <vector>
-
-#include <grpc++/support/config.h>
-#include <grpc/compression.h>
-#include <grpc/grpc.h>
-
-namespace grpc {
-namespace testing {
-class ChannelArgumentsTest;
-}  // namespace testing
-
-class ResourceQuota;
-
-/// Options for channel creation. The user can use generic setters to pass
-/// key value pairs down to C channel creation code. For gRPC related options,
-/// concrete setters are provided.
-class ChannelArguments {
- public:
-  ChannelArguments();
-  ~ChannelArguments();
-
-  ChannelArguments(const ChannelArguments& other);
-  ChannelArguments& operator=(ChannelArguments other) {
-    Swap(other);
-    return *this;
-  }
-
-  void Swap(ChannelArguments& other);
-
-  /// Dump arguments in this instance to \a channel_args. Does not take
-  /// ownership of \a channel_args.
-  ///
-  /// Note that the underlying arguments are shared. Changes made to either \a
-  /// channel_args or this instance would be reflected on both.
-  void SetChannelArgs(grpc_channel_args* channel_args) const;
-
-  // gRPC specific channel argument setters
-  /// Set target name override for SSL host name checking. This option is for
-  /// testing only and should never be used in production.
-  void SetSslTargetNameOverride(const grpc::string& name);
-  // TODO(yangg) add flow control options
-  /// Set the compression algorithm for the channel.
-  void SetCompressionAlgorithm(grpc_compression_algorithm algorithm);
-
-  /// Set the grpclb fallback timeout (in ms) for the channel. If this amount
-  /// of time has passed but we have not gotten any non-empty \a serverlist from
-  /// the balancer, we will fall back to use the backend address(es) returned by
-  /// the resolver.
-  void SetGrpclbFallbackTimeout(int fallback_timeout);
-
-  /// Set the socket mutator for the channel.
-  void SetSocketMutator(grpc_socket_mutator* mutator);
-
-  /// Set the string to prepend to the user agent.
-  void SetUserAgentPrefix(const grpc::string& user_agent_prefix);
-
-  /// Set the buffer pool to be attached to the constructed channel.
-  void SetResourceQuota(const ResourceQuota& resource_quota);
-
-  /// Set the max receive and send message sizes.
-  void SetMaxReceiveMessageSize(int size);
-  void SetMaxSendMessageSize(int size);
-
-  /// Set LB policy name.
-  /// Note that if the name resolver returns only balancer addresses, the
-  /// grpclb LB policy will be used, regardless of what is specified here.
-  void SetLoadBalancingPolicyName(const grpc::string& lb_policy_name);
-
-  /// Set service config in JSON form.
-  /// Primarily meant for use in unit tests.
-  void SetServiceConfigJSON(const grpc::string& service_config_json);
-
-  // Generic channel argument setters. Only for advanced use cases.
-  /// Set an integer argument \a value under \a key.
-  void SetInt(const grpc::string& key, int value);
-
-  // Generic channel argument setter. Only for advanced use cases.
-  /// Set a pointer argument \a value under \a key. Owership is not transferred.
-  void SetPointer(const grpc::string& key, void* value);
-
-  void SetPointerWithVtable(const grpc::string& key, void* value,
-                            const grpc_arg_pointer_vtable* vtable);
-
-  /// Set a textual argument \a value under \a key.
-  void SetString(const grpc::string& key, const grpc::string& value);
-
-  /// Return (by value) a C \a grpc_channel_args structure which points to
-  /// arguments owned by this \a ChannelArguments instance
-  grpc_channel_args c_channel_args() const {
-    grpc_channel_args out;
-    out.num_args = args_.size();
-    out.args = args_.empty() ? NULL : const_cast<grpc_arg*>(&args_[0]);
-    return out;
-  }
-
- private:
-  friend class SecureChannelCredentials;
-  friend class testing::ChannelArgumentsTest;
-
-  /// Default pointer argument operations.
-  struct PointerVtableMembers {
-    static void* Copy(void* in) { return in; }
-    static void Destroy(void* in) {}
-    static int Compare(void* a, void* b) {
-      if (a < b) return -1;
-      if (a > b) return 1;
-      return 0;
-    }
-  };
-
-  // Returns empty string when it is not set.
-  grpc::string GetSslTargetNameOverride() const;
-
-  std::vector<grpc_arg> args_;
-  std::list<grpc::string> strings_;
-};
-
-}  // namespace grpc
+#include <grpcpp/support/channel_arguments.h>
 
 #endif  // GRPCXX_SUPPORT_CHANNEL_ARGUMENTS_H
diff --git a/include/grpc++/support/config.h b/include/grpc++/support/config.h
index b65af31..f8eee50 100644
--- a/include/grpc++/support/config.h
+++ b/include/grpc++/support/config.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_SUPPORT_CONFIG_H
 #define GRPCXX_SUPPORT_CONFIG_H
 
-#include <grpc++/impl/codegen/config.h>
+#include <grpcpp/support/config.h>
 
 #endif  // GRPCXX_SUPPORT_CONFIG_H
diff --git a/include/grpc++/support/error_details.h b/include/grpc++/support/error_details.h
index 8925fa8..7ace308 100644
--- a/include/grpc++/support/error_details.h
+++ b/include/grpc++/support/error_details.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2017 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,31 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_SUPPORT_ERROR_DETAILS_H
 #define GRPCXX_SUPPORT_ERROR_DETAILS_H
 
-#include <grpc++/support/status.h>
-
-namespace google {
-namespace rpc {
-class Status;
-}  // namespace rpc
-}  // namespace google
-
-namespace grpc {
-
-/// Map a \a grpc::Status to a \a google::rpc::Status.
-/// The given \a to object will be cleared.
-/// On success, returns status with OK.
-/// Returns status with \a INVALID_ARGUMENT, if failed to deserialize.
-/// Returns status with \a FAILED_PRECONDITION, if \a to is nullptr.
-Status ExtractErrorDetails(const Status& from, ::google::rpc::Status* to);
-
-/// Map \a google::rpc::Status to a \a grpc::Status.
-/// Returns OK on success.
-/// Returns status with \a FAILED_PRECONDITION if \a to is nullptr.
-Status SetErrorDetails(const ::google::rpc::Status& from, Status* to);
-
-}  // namespace grpc
+#include <grpcpp/support/error_details.h>
 
 #endif  // GRPCXX_SUPPORT_ERROR_DETAILS_H
diff --git a/include/grpc++/support/slice.h b/include/grpc++/support/slice.h
index 10db10d..b02b1a9 100644
--- a/include/grpc++/support/slice.h
+++ b/include/grpc++/support/slice.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,11 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_SUPPORT_SLICE_H
 #define GRPCXX_SUPPORT_SLICE_H
 
-#include <grpc++/impl/codegen/slice.h>
-#include <grpc++/support/config.h>
-#include <grpc/slice.h>
+#include <grpcpp/support/slice.h>
 
 #endif  // GRPCXX_SUPPORT_SLICE_H
diff --git a/include/grpc++/support/status.h b/include/grpc++/support/status.h
index 1fa910a..e58a18b 100644
--- a/include/grpc++/support/status.h
+++ b/include/grpc++/support/status.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_SUPPORT_STATUS_H
 #define GRPCXX_SUPPORT_STATUS_H
 
-#include <grpc++/impl/codegen/status.h>
+#include <grpcpp/support/status.h>
 
 #endif  // GRPCXX_SUPPORT_STATUS_H
diff --git a/include/grpc++/support/status_code_enum.h b/include/grpc++/support/status_code_enum.h
index d320c0c..c278add 100644
--- a/include/grpc++/support/status_code_enum.h
+++ b/include/grpc++/support/status_code_enum.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_SUPPORT_STATUS_CODE_ENUM_H
 #define GRPCXX_SUPPORT_STATUS_CODE_ENUM_H
 
-#include <grpc++/impl/codegen/status_code_enum.h>
+#include <grpcpp/support/status_code_enum.h>
 
 #endif  // GRPCXX_SUPPORT_STATUS_CODE_ENUM_H
diff --git a/include/grpc++/support/string_ref.h b/include/grpc++/support/string_ref.h
index 873be63..49de6da 100644
--- a/include/grpc++/support/string_ref.h
+++ b/include/grpc++/support/string_ref.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_SUPPORT_STRING_REF_H
 #define GRPCXX_SUPPORT_STRING_REF_H
 
-#include <grpc++/impl/codegen/string_ref.h>
+#include <grpcpp/support/string_ref.h>
 
 #endif  // GRPCXX_SUPPORT_STRING_REF_H
diff --git a/include/grpc++/support/stub_options.h b/include/grpc++/support/stub_options.h
index 87843cf..a712ce8 100644
--- a/include/grpc++/support/stub_options.h
+++ b/include/grpc++/support/stub_options.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_SUPPORT_STUB_OPTIONS_H
 #define GRPCXX_SUPPORT_STUB_OPTIONS_H
 
-#include <grpc++/impl/codegen/stub_options.h>
+#include <grpcpp/support/stub_options.h>
 
 #endif  // GRPCXX_SUPPORT_STUB_OPTIONS_H
diff --git a/include/grpc++/support/sync_stream.h b/include/grpc++/support/sync_stream.h
index 6a6e0c7..c118df9 100644
--- a/include/grpc++/support/sync_stream.h
+++ b/include/grpc++/support/sync_stream.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_SUPPORT_SYNC_STREAM_H
 #define GRPCXX_SUPPORT_SYNC_STREAM_H
 
-#include <grpc++/impl/codegen/sync_stream.h>
+#include <grpcpp/support/sync_stream.h>
 
 #endif  // GRPCXX_SUPPORT_SYNC_STREAM_H
diff --git a/include/grpc++/support/time.h b/include/grpc++/support/time.h
index e47a593..d356b91 100644
--- a/include/grpc++/support/time.h
+++ b/include/grpc++/support/time.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_SUPPORT_TIME_H
 #define GRPCXX_SUPPORT_TIME_H
 
-#include <grpc++/impl/codegen/time.h>
+#include <grpcpp/support/time.h>
 
 #endif  // GRPCXX_SUPPORT_TIME_H
diff --git a/include/grpc++/test/mock_stream.h b/include/grpc++/test/mock_stream.h
index f8f7824..a29345b 100644
--- a/include/grpc++/test/mock_stream.h
+++ b/include/grpc++/test/mock_stream.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2017 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,133 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_TEST_MOCK_STREAM_H
 #define GRPCXX_TEST_MOCK_STREAM_H
 
-#include <stdint.h>
-
-#include <gmock/gmock.h>
-#include <grpc++/impl/codegen/call.h>
-#include <grpc++/support/async_stream.h>
-#include <grpc++/support/async_unary_call.h>
-#include <grpc++/support/sync_stream.h>
-
-namespace grpc {
-namespace testing {
-
-template <class R>
-class MockClientReader : public ClientReaderInterface<R> {
- public:
-  MockClientReader() = default;
-
-  /// ClientStreamingInterface
-  MOCK_METHOD0_T(Finish, Status());
-
-  /// ReaderInterface
-  MOCK_METHOD1_T(NextMessageSize, bool(uint32_t*));
-  MOCK_METHOD1_T(Read, bool(R*));
-
-  /// ClientReaderInterface
-  MOCK_METHOD0_T(WaitForInitialMetadata, void());
-};
-
-template <class W>
-class MockClientWriter : public ClientWriterInterface<W> {
- public:
-  MockClientWriter() = default;
-
-  /// ClientStreamingInterface
-  MOCK_METHOD0_T(Finish, Status());
-
-  /// WriterInterface
-  MOCK_METHOD2_T(Write, bool(const W&, const WriteOptions));
-
-  /// ClientWriterInterface
-  MOCK_METHOD0_T(WritesDone, bool());
-};
-
-template <class W, class R>
-class MockClientReaderWriter : public ClientReaderWriterInterface<W, R> {
- public:
-  MockClientReaderWriter() = default;
-
-  /// ClientStreamingInterface
-  MOCK_METHOD0_T(Finish, Status());
-
-  /// ReaderInterface
-  MOCK_METHOD1_T(NextMessageSize, bool(uint32_t*));
-  MOCK_METHOD1_T(Read, bool(R*));
-
-  /// WriterInterface
-  MOCK_METHOD2_T(Write, bool(const W&, const WriteOptions));
-
-  /// ClientReaderWriterInterface
-  MOCK_METHOD0_T(WaitForInitialMetadata, void());
-  MOCK_METHOD0_T(WritesDone, bool());
-};
-
-/// TODO: We do not support mocking an async RPC for now.
-
-template <class R>
-class MockClientAsyncResponseReader
-    : public ClientAsyncResponseReaderInterface<R> {
- public:
-  MockClientAsyncResponseReader() = default;
-
-  MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
-  MOCK_METHOD3_T(Finish, void(R*, Status*, void*));
-};
-
-template <class R>
-class MockClientAsyncReader : public ClientAsyncReaderInterface<R> {
- public:
-  MockClientAsyncReader() = default;
-
-  /// ClientAsyncStreamingInterface
-  MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
-  MOCK_METHOD2_T(Finish, void(Status*, void*));
-
-  /// AsyncReaderInterface
-  MOCK_METHOD2_T(Read, void(R*, void*));
-};
-
-template <class W>
-class MockClientAsyncWriter : public ClientAsyncWriterInterface<W> {
- public:
-  MockClientAsyncWriter() = default;
-
-  /// ClientAsyncStreamingInterface
-  MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
-  MOCK_METHOD2_T(Finish, void(Status*, void*));
-
-  /// AsyncWriterInterface
-  MOCK_METHOD2_T(Write, void(const W&, void*));
-
-  /// ClientAsyncWriterInterface
-  MOCK_METHOD1_T(WritesDone, void(void*));
-};
-
-template <class W, class R>
-class MockClientAsyncReaderWriter
-    : public ClientAsyncReaderWriterInterface<W, R> {
- public:
-  MockClientAsyncReaderWriter() = default;
-
-  /// ClientAsyncStreamingInterface
-  MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
-  MOCK_METHOD2_T(Finish, void(Status*, void*));
-
-  /// AsyncWriterInterface
-  MOCK_METHOD2_T(Write, void(const W&, void*));
-
-  /// AsyncReaderInterface
-  MOCK_METHOD2_T(Read, void(R*, void*));
-
-  /// ClientAsyncReaderWriterInterface
-  MOCK_METHOD1_T(WritesDone, void(void*));
-};
-
-}  // namespace testing
-}  // namespace grpc
+#include <grpcpp/test/mock_stream.h>
 
 #endif  // GRPCXX_TEST_MOCK_STREAM_H
diff --git a/include/grpc++/test/server_context_test_spouse.h b/include/grpc++/test/server_context_test_spouse.h
index b1a7f87..48a4838 100644
--- a/include/grpc++/test/server_context_test_spouse.h
+++ b/include/grpc++/test/server_context_test_spouse.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,50 +16,13 @@
  *
  */
 
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
 #ifndef GRPCXX_TEST_SERVER_CONTEXT_TEST_SPOUSE_H
 #define GRPCXX_TEST_SERVER_CONTEXT_TEST_SPOUSE_H
 
-#include <map>
-
-#include <grpc++/server_context.h>
-
-namespace grpc {
-namespace testing {
-
-/// A test-only class to access private members and methods of ServerContext.
-class ServerContextTestSpouse {
- public:
-  explicit ServerContextTestSpouse(ServerContext* ctx) : ctx_(ctx) {}
-
-  /// Inject client metadata to the ServerContext for the test. The test spouse
-  /// must be alive when \a ServerContext::client_metadata is called.
-  void AddClientMetadata(const grpc::string& key, const grpc::string& value) {
-    client_metadata_storage_.insert(
-        std::pair<grpc::string, grpc::string>(key, value));
-    ctx_->client_metadata_.map()->clear();
-    for (auto iter = client_metadata_storage_.begin();
-         iter != client_metadata_storage_.end(); ++iter) {
-      ctx_->client_metadata_.map()->insert(
-          std::pair<grpc::string_ref, grpc::string_ref>(
-              iter->first.c_str(),
-              grpc::string_ref(iter->second.data(), iter->second.size())));
-    }
-  }
-
-  std::multimap<grpc::string, grpc::string> GetInitialMetadata() const {
-    return ctx_->initial_metadata_;
-  }
-
-  std::multimap<grpc::string, grpc::string> GetTrailingMetadata() const {
-    return ctx_->trailing_metadata_;
-  }
-
- private:
-  ServerContext* ctx_;  // not owned
-  std::multimap<grpc::string, grpc::string> client_metadata_storage_;
-};
-
-}  // namespace testing
-}  // namespace grpc
+#include <grpcpp/test/server_context_test_spouse.h>
 
 #endif  // GRPCXX_TEST_SERVER_CONTEXT_TEST_SPOUSE_H
diff --git a/include/grpc/byte_buffer.h b/include/grpc/byte_buffer.h
index 7669582..ee740f4 100644
--- a/include/grpc/byte_buffer.h
+++ b/include/grpc/byte_buffer.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_BYTE_BUFFER_H
 #define GRPC_BYTE_BUFFER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/byte_buffer.h>
 #include <grpc/slice_buffer.h>
 
diff --git a/include/grpc/byte_buffer_reader.h b/include/grpc/byte_buffer_reader.h
index 6bd0784..15e06ca 100644
--- a/include/grpc/byte_buffer_reader.h
+++ b/include/grpc/byte_buffer_reader.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_BYTE_BUFFER_READER_H
 #define GRPC_BYTE_BUFFER_READER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/byte_buffer_reader.h>
 
 #endif /* GRPC_BYTE_BUFFER_READER_H */
diff --git a/include/grpc/census.h b/include/grpc/census.h
index 2258af8..4894f1c 100644
--- a/include/grpc/census.h
+++ b/include/grpc/census.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CENSUS_H
 #define GRPC_CENSUS_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 
 #ifdef __cplusplus
diff --git a/include/grpc/compression_ruby.h b/include/grpc/compression_ruby.h
deleted file mode 100644
index b063b2b..0000000
--- a/include/grpc/compression_ruby.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *
- * Copyright 2017 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 GRPC_COMPRESSION_RUBY_H
-#define GRPC_COMPRESSION_RUBY_H
-
-#include <grpc/impl/codegen/port_platform.h>
-
-#include <grpc/impl/codegen/compression_types.h>
-#include <grpc/slice.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** Parses the \a slice as a grpc_compression_algorithm instance and updating \a
- * algorithm following algorithm names compatible with Ruby. Returns 1 upon
- * success, 0 otherwise. */
-GRPCAPI int grpc_compression_algorithm_parse_ruby(
-    grpc_slice value, grpc_compression_algorithm* algorithm);
-
-/** Updates \a name with the encoding name corresponding to a valid \a
- * algorithm. The \a name follows names compatible with Ruby. Note that \a name
- * is statically allocated and must *not* be freed. Returns 1 upon success, 0
- * otherwise. */
-GRPCAPI int grpc_compression_algorithm_name_ruby(
-    grpc_compression_algorithm algorithm, const char** name);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_COMPRESSION_RUBY_H */
diff --git a/include/grpc/fork.h b/include/grpc/fork.h
index ca45e11..26f9df9 100644
--- a/include/grpc/fork.h
+++ b/include/grpc/fork.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_FORK_H
 #define GRPC_FORK_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/fork.h>
 
 #endif /* GRPC_FORK_H */
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index 47d749c..dd8a5d7 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_GRPC_H
 #define GRPC_GRPC_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/status.h>
 
 #include <grpc/byte_buffer.h>
@@ -269,9 +271,11 @@
 
 /** Create a client channel to 'target'. Additional channel level configuration
     MAY be provided by grpc_channel_args, though the expectation is that most
-    clients will want to simply pass NULL. See grpc_channel_args definition for
-    more on this. The data in 'args' need only live through the invocation of
-    this function. */
+    clients will want to simply pass NULL. The user data in 'args' need only
+    live through the invocation of this function. However, if any args of the
+    'pointer' type are passed, then the referenced vtable must be maintained
+    by the caller until grpc_channel_destroy terminates. See grpc_channel_args
+    definition for more on this. */
 GRPCAPI grpc_channel* grpc_insecure_channel_create(
     const char* target, const grpc_channel_args* args, void* reserved);
 
@@ -282,6 +286,14 @@
 /** Close and destroy a grpc channel */
 GRPCAPI void grpc_channel_destroy(grpc_channel* channel);
 
+/** Returns the JSON formatted channel trace for this channel. The caller
+    owns the returned string and is responsible for freeing it. */
+GRPCAPI char* grpc_channel_get_trace(grpc_channel* channel);
+
+/** Returns the channel uuid, which can be used to look up its trace at a
+    later time. */
+GRPCAPI intptr_t grpc_channel_get_uuid(grpc_channel* channel);
+
 /** Error handling for grpc_call
    Most grpc_call functions return a grpc_error. If the error is not GRPC_OK
    then the operation failed due to some unsatisfied precondition.
@@ -364,8 +376,11 @@
 
 /** Create a server. Additional configuration for each incoming channel can
     be specified with args. If no additional configuration is needed, args can
-    be NULL. See grpc_channel_args for more. The data in 'args' need only live
-    through the invocation of this function. */
+    be NULL. The user data in 'args' need only live through the invocation of
+    this function. However, if any args of the 'pointer' type are passed, then
+    the referenced vtable must be maintained by the caller until
+    grpc_server_destroy terminates. See grpc_channel_args definition for more
+    on this. */
 GRPCAPI grpc_server* grpc_server_create(const grpc_channel_args* args,
                                         void* reserved);
 
diff --git a/include/grpc/grpc_cronet.h b/include/grpc/grpc_cronet.h
index 127d5d0..289cfcd 100644
--- a/include/grpc/grpc_cronet.h
+++ b/include/grpc/grpc_cronet.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_GRPC_CRONET_H
 #define GRPC_GRPC_CRONET_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 
 #ifdef __cplusplus
diff --git a/include/grpc/grpc_posix.h b/include/grpc/grpc_posix.h
index fa7ebce..5f1ada5 100644
--- a/include/grpc/grpc_posix.h
+++ b/include/grpc/grpc_posix.h
@@ -19,9 +19,10 @@
 #ifndef GRPC_GRPC_POSIX_H
 #define GRPC_GRPC_POSIX_H
 
-#include <grpc/impl/codegen/grpc_types.h>
 #include <grpc/support/port_platform.h>
 
+#include <grpc/impl/codegen/grpc_types.h>
+
 #include <stddef.h>
 
 #ifdef __cplusplus
diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h
index bae07ac..7c069b3 100644
--- a/include/grpc/grpc_security.h
+++ b/include/grpc/grpc_security.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_GRPC_SECURITY_H
 #define GRPC_GRPC_SECURITY_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 #include <grpc/grpc_security_constants.h>
 #include <grpc/status.h>
@@ -98,6 +100,25 @@
 GRPCAPI int grpc_auth_context_set_peer_identity_property_name(
     grpc_auth_context* ctx, const char* name);
 
+/** --- SSL Session Cache. ---
+
+    A SSL session cache object represents a way to cache client sessions
+    between connections. Only ticket-based resumption is supported. */
+
+typedef struct grpc_ssl_session_cache grpc_ssl_session_cache;
+
+/** Create LRU cache for client-side SSL sessions with the given capacity.
+    If capacity is < 1, a default capacity is used instead. */
+GRPCAPI grpc_ssl_session_cache* grpc_ssl_session_cache_create_lru(
+    size_t capacity);
+
+/** Destroy SSL session cache. */
+GRPCAPI void grpc_ssl_session_cache_destroy(grpc_ssl_session_cache* cache);
+
+/** Create a channel arg with the given cache object. */
+GRPCAPI grpc_arg
+grpc_ssl_session_cache_create_channel_arg(grpc_ssl_session_cache* cache);
+
 /** --- grpc_channel_credentials object. ---
 
    A channel credentials object represents a way to authenticate a client on a
@@ -300,7 +321,13 @@
 
 /** --- Secure channel creation. --- */
 
-/** Creates a secure channel using the passed-in credentials. */
+/** Creates a secure channel using the passed-in credentials. Additional
+    channel level configuration MAY be provided by grpc_channel_args, though
+    the expectation is that most clients will want to simply pass NULL. The
+    user data in 'args' need only live through the invocation of this function.
+    However, if any args of the 'pointer' type are passed, then the referenced
+    vtable must be maintained by the caller until grpc_channel_destroy
+    terminates. See grpc_channel_args definition for more on this. */
 GRPCAPI grpc_channel* grpc_secure_channel_create(
     grpc_channel_credentials* creds, const char* target,
     const grpc_channel_args* args, void* reserved);
diff --git a/include/grpc/grpc_security_constants.h b/include/grpc/grpc_security_constants.h
index 60e167e..92580ea 100644
--- a/include/grpc/grpc_security_constants.h
+++ b/include/grpc/grpc_security_constants.h
@@ -29,6 +29,7 @@
 #define GRPC_X509_CN_PROPERTY_NAME "x509_common_name"
 #define GRPC_X509_SAN_PROPERTY_NAME "x509_subject_alternative_name"
 #define GRPC_X509_PEM_CERT_PROPERTY_NAME "x509_pem_cert"
+#define GRPC_SSL_SESSION_REUSED_PROPERTY "ssl_session_reused"
 
 /** Environment variable that points to the default SSL roots file. This file
    must be a PEM encoded file with all the roots such as the one that can be
diff --git a/include/grpc/impl/codegen/byte_buffer.h b/include/grpc/impl/codegen/byte_buffer.h
index f8dfbd1..774655e 100644
--- a/include/grpc/impl/codegen/byte_buffer.h
+++ b/include/grpc/impl/codegen/byte_buffer.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_IMPL_CODEGEN_BYTE_BUFFER_H
 #define GRPC_IMPL_CODEGEN_BYTE_BUFFER_H
 
+#include <grpc/impl/codegen/port_platform.h>
+
 #include <grpc/impl/codegen/grpc_types.h>
 
 #ifdef __cplusplus
diff --git a/include/grpc/impl/codegen/compression_types.h b/include/grpc/impl/codegen/compression_types.h
index ddc667f..e35d892 100644
--- a/include/grpc/impl/codegen/compression_types.h
+++ b/include/grpc/impl/codegen/compression_types.h
@@ -55,8 +55,9 @@
 /** The various compression algorithms supported by gRPC */
 typedef enum {
   GRPC_COMPRESS_NONE = 0,
-  GRPC_COMPRESS_MESSAGE_DEFLATE,
-  GRPC_COMPRESS_MESSAGE_GZIP,
+  GRPC_COMPRESS_DEFLATE,
+  GRPC_COMPRESS_GZIP,
+  /* EXPERIMENTAL: Stream compression is currently experimental. */
   GRPC_COMPRESS_STREAM_GZIP,
   /* TODO(ctiller): snappy */
   GRPC_COMPRESS_ALGORITHMS_COUNT
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index d64b23f..03aaa9f 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -119,9 +119,14 @@
     These configuration options are modelled as key-value pairs as defined
     by grpc_arg; keys are strings to allow easy backwards-compatible extension
     by arbitrary parties. All evaluation is performed at channel creation
-    time (i.e. the values in this structure need only live through the
+    time (i.e. the keys and values in this structure need only live through the
     creation invocation).
 
+    However, if one of the args has grpc_arg_type==GRPC_ARG_POINTER, then the
+    grpc_arg_pointer_vtable must live until the channel args are done being
+    used by core (i.e. when the object for use with which they were passed
+    is destroyed).
+
     See the description of the \ref grpc_arg_keys "available args" for more
     details. */
 typedef struct {
@@ -253,6 +258,10 @@
     secure channel is an SSL channel). If this parameter is specified and the
     underlying is not an SSL channel, it will just be ignored. */
 #define GRPC_SSL_TARGET_NAME_OVERRIDE_ARG "grpc.ssl_target_name_override"
+/** If non-zero, a pointer to a session cache (a pointer of type
+    grpc_ssl_session_cache*). (use grpc_ssl_session_cache_arg_vtable() to fetch
+    an appropriate pointer arg vtable) */
+#define GRPC_SSL_SESSION_CACHE_ARG "grpc.ssl_session_cache"
 /** Maximum metadata size, in bytes. Note this limit applies to the max sum of
     all metadata key-value entries in a batch of headers. */
 #define GRPC_ARG_MAX_METADATA_SIZE "grpc.max_metadata_size"
@@ -276,6 +285,10 @@
 #define GRPC_ARG_SOCKET_MUTATOR "grpc.socket_mutator"
 /** The grpc_socket_factory instance to create and bind sockets. A pointer. */
 #define GRPC_ARG_SOCKET_FACTORY "grpc.socket_factory"
+/** The maximum number of trace events to keep in the tracer for each channel or
+ * subchannel. The default is 10. If set to 0, channel tracing is disabled. */
+#define GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE \
+  "grpc.max_channel_trace_events_per_node"
 /** If non-zero, Cronet transport will coalesce packets to fewer frames
  * when possible. */
 #define GRPC_ARG_USE_CRONET_PACKET_COALESCING \
@@ -296,7 +309,7 @@
 #define GRPC_ARG_GRPCLB_CALL_TIMEOUT_MS "grpc.grpclb_call_timeout_ms"
 /* Timeout in milliseconds to wait for the serverlist from the grpclb load
    balancer before using fallback backend addresses from the resolver.
-   If 0, fallback will never be used. */
+   If 0, fallback will never be used. Default value is 10000. */
 #define GRPC_ARG_GRPCLB_FALLBACK_TIMEOUT_MS "grpc.grpclb_fallback_timeout_ms"
 /** If non-zero, grpc server's cronet compression workaround will be enabled */
 #define GRPC_ARG_WORKAROUND_CRONET_COMPRESSION \
@@ -309,6 +322,17 @@
     Defaults to "blend". In the current implementation "blend" is equivalent to
     "latency". */
 #define GRPC_ARG_OPTIMIZATION_TARGET "grpc.optimization_target"
+/** If set to zero, disables retry behavior. Otherwise, transparent retries
+    are enabled for all RPCs, and configurable retries are enabled when they
+    are configured via the service config. For details, see:
+      https://github.com/grpc/proposal/blob/master/A6-client-retries.md
+ */
+#define GRPC_ARG_ENABLE_RETRIES "grpc.enable_retries"
+/** Per-RPC retry buffer size, in bytes. Default is 256 KiB. */
+#define GRPC_ARG_PER_RPC_RETRY_BUFFER_SIZE "grpc.per_rpc_retry_buffer_size"
+/** Channel arg that carries the bridged objective c object for custom metrics
+ * logging filter. */
+#define GRPC_ARG_MOBILE_LOG_CONFIG "grpc.mobile_log_config"
 /** \} */
 
 /** Result of a grpc call. If the caller satisfies the prerequisites of a
@@ -546,6 +570,8 @@
     } recv_initial_metadata;
     /** ownership of the byte buffer is moved to the caller; the caller must
         call grpc_byte_buffer_destroy on this value, or reuse it in a future op.
+        The returned byte buffer will be NULL if trailing metadata was
+        received instead of a message.
        */
     struct grpc_op_recv_message {
       struct grpc_byte_buffer** recv_message;
diff --git a/include/grpc/impl/codegen/slice.h b/include/grpc/impl/codegen/slice.h
index a3cd1f1..90dbfd3 100644
--- a/include/grpc/impl/codegen/slice.h
+++ b/include/grpc/impl/codegen/slice.h
@@ -95,7 +95,7 @@
 
 /** Represents an expandable array of slices, to be interpreted as a
    single item. */
-typedef struct {
+typedef struct grpc_slice_buffer {
   /** This is for internal use only. External users (i.e any code outside grpc
    * core) MUST NOT use this field */
   grpc_slice* base_slices;
diff --git a/include/grpc/impl/codegen/sync.h b/include/grpc/impl/codegen/sync.h
index 6cdb0c5..3df68c6 100644
--- a/include/grpc/impl/codegen/sync.h
+++ b/include/grpc/impl/codegen/sync.h
@@ -43,6 +43,7 @@
 
 /* Platform-specific type declarations of gpr_mu and gpr_cv.   */
 #include <grpc/impl/codegen/port_platform.h>
+
 #include <grpc/impl/codegen/sync_generic.h>
 
 #if defined(GPR_POSIX_SYNC)
diff --git a/include/grpc/impl/codegen/sync_custom.h b/include/grpc/impl/codegen/sync_custom.h
index 0840ad2..69b1bf6 100644
--- a/include/grpc/impl/codegen/sync_custom.h
+++ b/include/grpc/impl/codegen/sync_custom.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_IMPL_CODEGEN_SYNC_CUSTOM_H
 #define GRPC_IMPL_CODEGEN_SYNC_CUSTOM_H
 
+#include <grpc/impl/codegen/port_platform.h>
+
 #include <grpc/impl/codegen/sync_generic.h>
 
 /* Users defining GPR_CUSTOM_SYNC need to define the following macros. */
diff --git a/include/grpc/impl/codegen/sync_generic.h b/include/grpc/impl/codegen/sync_generic.h
index 83f905e..d64db58 100644
--- a/include/grpc/impl/codegen/sync_generic.h
+++ b/include/grpc/impl/codegen/sync_generic.h
@@ -20,6 +20,8 @@
 #define GRPC_IMPL_CODEGEN_SYNC_GENERIC_H
 /* Generic type defintions for gpr_sync. */
 
+#include <grpc/impl/codegen/port_platform.h>
+
 #include <grpc/impl/codegen/atm.h>
 
 /* gpr_event */
diff --git a/include/grpc/impl/codegen/sync_posix.h b/include/grpc/impl/codegen/sync_posix.h
index 6a3aed9..d927046 100644
--- a/include/grpc/impl/codegen/sync_posix.h
+++ b/include/grpc/impl/codegen/sync_posix.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_IMPL_CODEGEN_SYNC_POSIX_H
 #define GRPC_IMPL_CODEGEN_SYNC_POSIX_H
 
+#include <grpc/impl/codegen/port_platform.h>
+
 #include <grpc/impl/codegen/sync_generic.h>
 
 #include <pthread.h>
diff --git a/include/grpc/impl/codegen/sync_windows.h b/include/grpc/impl/codegen/sync_windows.h
index 39b1276..ba5d5ae 100644
--- a/include/grpc/impl/codegen/sync_windows.h
+++ b/include/grpc/impl/codegen/sync_windows.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_IMPL_CODEGEN_SYNC_WINDOWS_H
 #define GRPC_IMPL_CODEGEN_SYNC_WINDOWS_H
 
+#include <grpc/impl/codegen/port_platform.h>
+
 #include <grpc/impl/codegen/sync_generic.h>
 
 typedef struct {
diff --git a/include/grpc/module.modulemap b/include/grpc/module.modulemap
index d23072f..e0d5404 100644
--- a/include/grpc/module.modulemap
+++ b/include/grpc/module.modulemap
@@ -4,21 +4,15 @@
 
   header "support/alloc.h"
   header "support/atm.h"
-  header "support/avl.h"
-  header "support/cmdline.h"
   header "support/cpu.h"
-  header "support/host_port.h"
   header "support/log.h"
   header "support/log_windows.h"
   header "support/port_platform.h"
   header "support/string_util.h"
-  header "support/subprocess.h"
   header "support/sync.h"
   header "support/sync_generic.h"
-  header "support/thd.h"
+  header "support/thd_id.h"
   header "support/time.h"
-  header "support/tls.h"
-  header "support/useful.h"
   header "impl/codegen/atm.h"
   header "impl/codegen/fork.h"
   header "impl/codegen/gpr_slice.h"
@@ -45,7 +39,6 @@
   header "byte_buffer.h"
   header "byte_buffer_reader.h"
   header "compression.h"
-  header "compression_ruby.h"
   header "fork.h"
   header "grpc.h"
   header "grpc_posix.h"
@@ -63,9 +56,6 @@
   textual header "support/sync_custom.h"
   textual header "support/sync_posix.h"
   textual header "support/sync_windows.h"
-  textual header "support/tls_gcc.h"
-  textual header "support/tls_msvc.h"
-  textual header "support/tls_pthread.h"
   textual header "impl/codegen/atm_gcc_atomic.h"
   textual header "impl/codegen/atm_gcc_sync.h"
   textual header "impl/codegen/atm_windows.h"
diff --git a/include/grpc/slice.h b/include/grpc/slice.h
index 10b6a62..ce48292 100644
--- a/include/grpc/slice.h
+++ b/include/grpc/slice.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_SLICE_H
 #define GRPC_SLICE_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/slice.h>
 #include <grpc/support/sync.h>
 
diff --git a/include/grpc/slice_buffer.h b/include/grpc/slice_buffer.h
index 30833d0..3260019 100644
--- a/include/grpc/slice_buffer.h
+++ b/include/grpc/slice_buffer.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_SLICE_BUFFER_H
 #define GRPC_SLICE_BUFFER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice.h>
 
 #ifdef __cplusplus
diff --git a/include/grpc/status.h b/include/grpc/status.h
index 9d8f50b..ecb9668 100644
--- a/include/grpc/status.h
+++ b/include/grpc/status.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_STATUS_H
 #define GRPC_STATUS_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/status.h>
 
 #endif /* GRPC_STATUS_H */
diff --git a/include/grpc/support/alloc.h b/include/grpc/support/alloc.h
index 577d4f0..8bd940b 100644
--- a/include/grpc/support/alloc.h
+++ b/include/grpc/support/alloc.h
@@ -19,9 +19,9 @@
 #ifndef GRPC_SUPPORT_ALLOC_H
 #define GRPC_SUPPORT_ALLOC_H
 
-#include <stddef.h>
+#include <grpc/support/port_platform.h>
 
-#include <grpc/impl/codegen/port_platform.h>
+#include <stddef.h>
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/include/grpc/support/atm.h b/include/grpc/support/atm.h
index b3afa52..073b0a6 100644
--- a/include/grpc/support/atm.h
+++ b/include/grpc/support/atm.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_SUPPORT_ATM_H
 #define GRPC_SUPPORT_ATM_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/atm.h>
 
 #endif /* GRPC_SUPPORT_ATM_H */
diff --git a/include/grpc/support/atm_gcc_atomic.h b/include/grpc/support/atm_gcc_atomic.h
index e7b5ec4..ae603db 100644
--- a/include/grpc/support/atm_gcc_atomic.h
+++ b/include/grpc/support/atm_gcc_atomic.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_SUPPORT_ATM_GCC_ATOMIC_H
 #define GRPC_SUPPORT_ATM_GCC_ATOMIC_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/atm_gcc_atomic.h>
 
 #endif /* GRPC_SUPPORT_ATM_GCC_ATOMIC_H */
diff --git a/include/grpc/support/atm_gcc_sync.h b/include/grpc/support/atm_gcc_sync.h
index 7284897..6f51fdb 100644
--- a/include/grpc/support/atm_gcc_sync.h
+++ b/include/grpc/support/atm_gcc_sync.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_SUPPORT_ATM_GCC_SYNC_H
 #define GRPC_SUPPORT_ATM_GCC_SYNC_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/atm_gcc_sync.h>
 
 #endif /* GRPC_SUPPORT_ATM_GCC_SYNC_H */
diff --git a/include/grpc/support/atm_windows.h b/include/grpc/support/atm_windows.h
index 554c59a..36955e4 100644
--- a/include/grpc/support/atm_windows.h
+++ b/include/grpc/support/atm_windows.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_SUPPORT_ATM_WINDOWS_H
 #define GRPC_SUPPORT_ATM_WINDOWS_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/atm_windows.h>
 
 #endif /* GRPC_SUPPORT_ATM_WINDOWS_H */
diff --git a/include/grpc/support/log.h b/include/grpc/support/log.h
index a8371cb..2236703 100644
--- a/include/grpc/support/log.h
+++ b/include/grpc/support/log.h
@@ -19,12 +19,11 @@
 #ifndef GRPC_SUPPORT_LOG_H
 #define GRPC_SUPPORT_LOG_H
 
-#include <inttypes.h>
+#include <grpc/impl/codegen/port_platform.h>
+
 #include <stdarg.h>
 #include <stdlib.h> /* for abort() */
 
-#include <grpc/impl/codegen/port_platform.h>
-
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/include/grpc/support/sync.h b/include/grpc/support/sync.h
index 7519267..91d1fa7 100644
--- a/include/grpc/support/sync.h
+++ b/include/grpc/support/sync.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_SUPPORT_SYNC_H
 #define GRPC_SUPPORT_SYNC_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/gpr_types.h> /* for gpr_timespec */
 #include <grpc/impl/codegen/sync.h>
 
diff --git a/include/grpc/support/sync_custom.h b/include/grpc/support/sync_custom.h
index b575f5e..27cf0e0 100644
--- a/include/grpc/support/sync_custom.h
+++ b/include/grpc/support/sync_custom.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_SUPPORT_SYNC_CUSTOM_H
 #define GRPC_SUPPORT_SYNC_CUSTOM_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/sync_custom.h>
 
 #endif /* GRPC_SUPPORT_SYNC_CUSTOM_H */
diff --git a/include/grpc/support/sync_generic.h b/include/grpc/support/sync_generic.h
index 970b7a5..93028c4 100644
--- a/include/grpc/support/sync_generic.h
+++ b/include/grpc/support/sync_generic.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_SUPPORT_SYNC_GENERIC_H
 #define GRPC_SUPPORT_SYNC_GENERIC_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/sync_generic.h>
 
 #endif /* GRPC_SUPPORT_SYNC_GENERIC_H */
diff --git a/include/grpc/support/sync_posix.h b/include/grpc/support/sync_posix.h
index 482a600..3dce7ee 100644
--- a/include/grpc/support/sync_posix.h
+++ b/include/grpc/support/sync_posix.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_SUPPORT_SYNC_POSIX_H
 #define GRPC_SUPPORT_SYNC_POSIX_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/sync_posix.h>
 
 #endif /* GRPC_SUPPORT_SYNC_POSIX_H */
diff --git a/include/grpc/support/sync_windows.h b/include/grpc/support/sync_windows.h
index 90ce8b7..a493c86 100644
--- a/include/grpc/support/sync_windows.h
+++ b/include/grpc/support/sync_windows.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_SUPPORT_SYNC_WINDOWS_H
 #define GRPC_SUPPORT_SYNC_WINDOWS_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/sync_windows.h>
 
 #endif /* GRPC_SUPPORT_SYNC_WINDOWS_H */
diff --git a/include/grpc/support/thd.h b/include/grpc/support/thd.h
deleted file mode 100644
index e9444e8..0000000
--- a/include/grpc/support/thd.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 GRPC_SUPPORT_THD_H
-#define GRPC_SUPPORT_THD_H
-/** Thread interface for GPR.
-
-   Types
-        gpr_thd_id        a thread identifier.
-                          (Currently no calls take a thread identifier.
-                          It exists for future extensibility.)
-        gpr_thd_options   options used when creating a thread
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef uintptr_t gpr_thd_id;
-
-/** Thread creation options. */
-typedef struct {
-  int flags; /** Opaque field. Get and set with accessors below. */
-} gpr_thd_options;
-
-/** Create a new thread running (*thd_body)(arg) and place its thread identifier
-   in *t, and return true.  If there are insufficient resources, return false.
-   thd_name is the name of the thread for identification purposes on platforms
-   that support thread naming.
-   If options==NULL, default options are used.
-   The thread is immediately runnable, and exits when (*thd_body)() returns.  */
-GPRAPI int gpr_thd_new(gpr_thd_id* t, const char* thd_name,
-                       void (*thd_body)(void* arg), void* arg,
-                       const gpr_thd_options* options);
-
-/** Return a gpr_thd_options struct with all fields set to defaults. */
-GPRAPI gpr_thd_options gpr_thd_options_default(void);
-
-/** Set the thread to become detached on startup - this is the default. */
-GPRAPI void gpr_thd_options_set_detached(gpr_thd_options* options);
-
-/** Set the thread to become joinable - mutually exclusive with detached. */
-GPRAPI void gpr_thd_options_set_joinable(gpr_thd_options* options);
-
-/** Returns non-zero if the option detached is set. */
-GPRAPI int gpr_thd_options_is_detached(const gpr_thd_options* options);
-
-/** Returns non-zero if the option joinable is set. */
-GPRAPI int gpr_thd_options_is_joinable(const gpr_thd_options* options);
-
-/** Returns the identifier of the current thread. */
-GPRAPI gpr_thd_id gpr_thd_currentid(void);
-
-/** Blocks until the specified thread properly terminates.
-   Calling this on a detached thread has unpredictable results. */
-GPRAPI void gpr_thd_join(gpr_thd_id t);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_SUPPORT_THD_H */
diff --git a/include/grpc/support/thd_id.h b/include/grpc/support/thd_id.h
new file mode 100644
index 0000000..e9b2b7e
--- /dev/null
+++ b/include/grpc/support/thd_id.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_SUPPORT_THD_ID_H
+#define GRPC_SUPPORT_THD_ID_H
+/** Thread ID interface for GPR.
+
+   Used by some wrapped languages for logging purposes.
+
+   Types
+        gpr_thd_id        a unique opaque identifier for a thread.
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef uintptr_t gpr_thd_id;
+
+/** Returns the identifier of the current thread. */
+GPRAPI gpr_thd_id gpr_thd_currentid(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_SUPPORT_THD_ID_H */
diff --git a/include/grpc/support/time.h b/include/grpc/support/time.h
index 62d354a..550ffc2 100644
--- a/include/grpc/support/time.h
+++ b/include/grpc/support/time.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_SUPPORT_TIME_H
 #define GRPC_SUPPORT_TIME_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/gpr_types.h>
 
 #include <stddef.h>
diff --git a/include/grpcpp/alarm.h b/include/grpcpp/alarm.h
new file mode 100644
index 0000000..f484610
--- /dev/null
+++ b/include/grpcpp/alarm.h
@@ -0,0 +1,87 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 Alarm posts the user provided tag to its associated completion queue upon
+/// expiry or cancellation.
+#ifndef GRPCPP_ALARM_H
+#define GRPCPP_ALARM_H
+
+#include <grpc/grpc.h>
+#include <grpcpp/impl/codegen/completion_queue.h>
+#include <grpcpp/impl/codegen/completion_queue_tag.h>
+#include <grpcpp/impl/codegen/grpc_library.h>
+#include <grpcpp/impl/codegen/time.h>
+#include <grpcpp/impl/grpc_library.h>
+
+namespace grpc {
+
+/// A thin wrapper around \a grpc_alarm (see / \a / src/core/surface/alarm.h).
+class Alarm : private GrpcLibraryCodegen {
+ public:
+  /// Create an unset completion queue alarm
+  Alarm();
+
+  /// Destroy the given completion queue alarm, cancelling it in the process.
+  ~Alarm();
+
+  /// DEPRECATED: Create and set a completion queue alarm instance associated to
+  /// \a cq.
+  /// This form is deprecated because it is inherently racy.
+  /// \internal We rely on the presence of \a cq for grpc initialization. If \a
+  /// cq were ever to be removed, a reference to a static
+  /// internal::GrpcLibraryInitializer instance would need to be introduced
+  /// here. \endinternal.
+  template <typename T>
+  Alarm(CompletionQueue* cq, const T& deadline, void* tag) : Alarm() {
+    SetInternal(cq, TimePoint<T>(deadline).raw_time(), tag);
+  }
+
+  /// Trigger an alarm instance on completion queue \a cq at the specified time.
+  /// Once the alarm expires (at \a deadline) or it's cancelled (see \a Cancel),
+  /// an event with tag \a tag will be added to \a cq. If the alarm expired, the
+  /// event's success bit will be true, false otherwise (ie, upon cancellation).
+  template <typename T>
+  void Set(CompletionQueue* cq, const T& deadline, void* tag) {
+    SetInternal(cq, TimePoint<T>(deadline).raw_time(), tag);
+  }
+
+  /// Alarms aren't copyable.
+  Alarm(const Alarm&) = delete;
+  Alarm& operator=(const Alarm&) = delete;
+
+  /// Alarms are movable.
+  Alarm(Alarm&& rhs) : alarm_(rhs.alarm_) { rhs.alarm_ = nullptr; }
+  Alarm& operator=(Alarm&& rhs) {
+    alarm_ = rhs.alarm_;
+    rhs.alarm_ = nullptr;
+    return *this;
+  }
+
+  /// Cancel a completion queue alarm. Calling this function over an alarm that
+  /// has already fired has no effect.
+  void Cancel();
+
+ private:
+  void SetInternal(CompletionQueue* cq, gpr_timespec deadline, void* tag);
+
+  internal::CompletionQueueTag* alarm_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_ALARM_H
diff --git a/include/grpcpp/channel.h b/include/grpcpp/channel.h
new file mode 100644
index 0000000..4b45d53
--- /dev/null
+++ b/include/grpcpp/channel.h
@@ -0,0 +1,78 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_CHANNEL_H
+#define GRPCPP_CHANNEL_H
+
+#include <memory>
+
+#include <grpc/grpc.h>
+#include <grpcpp/impl/call.h>
+#include <grpcpp/impl/codegen/channel_interface.h>
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/grpc_library.h>
+
+struct grpc_channel;
+
+namespace grpc {
+/// Channels represent a connection to an endpoint. Created by \a CreateChannel.
+class Channel final : public ChannelInterface,
+                      public internal::CallHook,
+                      public std::enable_shared_from_this<Channel>,
+                      private GrpcLibraryCodegen {
+ public:
+  ~Channel();
+
+  /// Get the current channel state. If the channel is in IDLE and
+  /// \a try_to_connect is set to true, try to connect.
+  grpc_connectivity_state GetState(bool try_to_connect) override;
+
+  /// Returns the LB policy name, or the empty string if not yet available.
+  grpc::string GetLoadBalancingPolicyName() const;
+
+  /// Returns the service config in JSON form, or the empty string if
+  /// not available.
+  grpc::string GetServiceConfigJSON() const;
+
+ private:
+  template <class InputMessage, class OutputMessage>
+  friend class internal::BlockingUnaryCallImpl;
+  friend std::shared_ptr<Channel> CreateChannelInternal(
+      const grpc::string& host, grpc_channel* c_channel);
+  Channel(const grpc::string& host, grpc_channel* c_channel);
+
+  internal::Call CreateCall(const internal::RpcMethod& method,
+                            ClientContext* context,
+                            CompletionQueue* cq) override;
+  void PerformOpsOnCall(internal::CallOpSetInterface* ops,
+                        internal::Call* call) override;
+  void* RegisterMethod(const char* method) override;
+
+  void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
+                               gpr_timespec deadline, CompletionQueue* cq,
+                               void* tag) override;
+  bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
+                              gpr_timespec deadline) override;
+
+  const grpc::string host_;
+  grpc_channel* const c_channel_;  // owned
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_CHANNEL_H
diff --git a/include/grpcpp/client_context.h b/include/grpcpp/client_context.h
new file mode 100644
index 0000000..8c12577
--- /dev/null
+++ b/include/grpcpp/client_context.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 ClientContext allows the person implementing a service client to:
+///
+/// - Add custom metadata key-value pairs that will propagated to the server
+/// side.
+/// - Control call settings such as compression and authentication.
+/// - Initial and trailing metadata coming from the server.
+/// - Get performance metrics (ie, census).
+///
+/// Context settings are only relevant to the call they are invoked with, that
+/// is to say, they aren't sticky. Some of these settings, such as the
+/// compression options, can be made persistant at channel construction time
+/// (see \a grpc::CreateCustomChannel).
+///
+/// \warning ClientContext instances should \em not be reused across rpcs.
+
+#ifndef GRPCPP_CLIENT_CONTEXT_H
+#define GRPCPP_CLIENT_CONTEXT_H
+
+#include <grpcpp/impl/codegen/client_context.h>
+
+#endif  // GRPCPP_CLIENT_CONTEXT_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/completion_queue.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/completion_queue.h
index 692c00c..123b277 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/completion_queue.h
@@ -16,15 +16,9 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_COMPLETION_QUEUE_H
+#define GRPCPP_COMPLETION_QUEUE_H
 
-#include <grpc/support/time.h>
+#include <grpcpp/impl/codegen/completion_queue.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_COMPLETION_QUEUE_H
diff --git a/include/grpcpp/create_channel.h b/include/grpcpp/create_channel.h
new file mode 100644
index 0000000..7a505a7
--- /dev/null
+++ b/include/grpcpp/create_channel.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_CREATE_CHANNEL_H
+#define GRPCPP_CREATE_CHANNEL_H
+
+#include <memory>
+
+#include <grpcpp/channel.h>
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/support/channel_arguments.h>
+#include <grpcpp/support/config.h>
+
+namespace grpc {
+
+/// Create a new \a Channel pointing to \a target.
+///
+/// \param target The URI of the endpoint to connect to.
+/// \param creds Credentials to use for the created channel. If it does not
+/// hold an object or is invalid, a lame channel (one on which all operations
+/// fail) is returned.
+std::shared_ptr<Channel> CreateChannel(
+    const grpc::string& target,
+    const std::shared_ptr<ChannelCredentials>& creds);
+
+/// Create a new \em custom \a Channel pointing to \a target.
+///
+/// \warning For advanced use and testing ONLY. Override default channel
+/// arguments only if necessary.
+///
+/// \param target The URI of the endpoint to connect to.
+/// \param creds Credentials to use for the created channel. If it does not
+/// hold an object or is invalid, a lame channel (one on which all operations
+/// fail) is returned.
+/// \param args Options for channel creation.
+std::shared_ptr<Channel> CreateCustomChannel(
+    const grpc::string& target,
+    const std::shared_ptr<ChannelCredentials>& creds,
+    const ChannelArguments& args);
+
+}  // namespace grpc
+
+#endif  // GRPCPP_CREATE_CHANNEL_H
diff --git a/include/grpcpp/create_channel_posix.h b/include/grpcpp/create_channel_posix.h
new file mode 100644
index 0000000..9bf5acc
--- /dev/null
+++ b/include/grpcpp/create_channel_posix.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_CREATE_CHANNEL_POSIX_H
+#define GRPCPP_CREATE_CHANNEL_POSIX_H
+
+#include <memory>
+
+#include <grpc/support/port_platform.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/support/channel_arguments.h>
+
+namespace grpc {
+
+#ifdef GPR_SUPPORT_CHANNELS_FROM_FD
+
+/// Create a new \a Channel communicating over the given file descriptor.
+///
+/// \param target The name of the target.
+/// \param fd The file descriptor representing a socket.
+std::shared_ptr<Channel> CreateInsecureChannelFromFd(const grpc::string& target,
+                                                     int fd);
+
+/// Create a new \a Channel communicating over given file descriptor with custom
+/// channel arguments.
+///
+/// \param target The name of the target.
+/// \param fd The file descriptor representing a socket.
+/// \param args Options for channel creation.
+std::shared_ptr<Channel> CreateCustomInsecureChannelFromFd(
+    const grpc::string& target, int fd, const ChannelArguments& args);
+
+#endif  // GPR_SUPPORT_CHANNELS_FROM_FD
+
+}  // namespace grpc
+
+#endif  // GRPCPP_CREATE_CHANNEL_POSIX_H
diff --git a/include/grpcpp/ext/health_check_service_server_builder_option.h b/include/grpcpp/ext/health_check_service_server_builder_option.h
new file mode 100644
index 0000000..dd43b05
--- /dev/null
+++ b/include/grpcpp/ext/health_check_service_server_builder_option.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_EXT_HEALTH_CHECK_SERVICE_SERVER_BUILDER_OPTION_H
+#define GRPCPP_EXT_HEALTH_CHECK_SERVICE_SERVER_BUILDER_OPTION_H
+
+#include <memory>
+
+#include <grpcpp/health_check_service_interface.h>
+#include <grpcpp/impl/server_builder_option.h>
+#include <grpcpp/support/config.h>
+
+namespace grpc {
+
+class HealthCheckServiceServerBuilderOption : public ServerBuilderOption {
+ public:
+  /// The ownership of \a hc will be taken and transferred to the grpc server.
+  /// To explicitly disable default service, pass in a nullptr.
+  explicit HealthCheckServiceServerBuilderOption(
+      std::unique_ptr<HealthCheckServiceInterface> hc);
+  ~HealthCheckServiceServerBuilderOption() override {}
+  void UpdateArguments(ChannelArguments* args) override;
+  void UpdatePlugins(
+      std::vector<std::unique_ptr<ServerBuilderPlugin>>* plugins) override;
+
+ private:
+  std::unique_ptr<HealthCheckServiceInterface> hc_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_EXT_HEALTH_CHECK_SERVICE_SERVER_BUILDER_OPTION_H
diff --git a/include/grpcpp/ext/proto_server_reflection_plugin.h b/include/grpcpp/ext/proto_server_reflection_plugin.h
new file mode 100644
index 0000000..1cfdc1b
--- /dev/null
+++ b/include/grpcpp/ext/proto_server_reflection_plugin.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_EXT_PROTO_SERVER_REFLECTION_PLUGIN_H
+#define GRPCPP_EXT_PROTO_SERVER_REFLECTION_PLUGIN_H
+
+#include <grpcpp/impl/server_builder_plugin.h>
+#include <grpcpp/support/config.h>
+
+namespace grpc {
+class ServerInitializer;
+class ProtoServerReflection;
+}  // namespace grpc
+
+namespace grpc {
+namespace reflection {
+
+class ProtoServerReflectionPlugin : public ::grpc::ServerBuilderPlugin {
+ public:
+  ProtoServerReflectionPlugin();
+  ::grpc::string name() override;
+  void InitServer(::grpc::ServerInitializer* si) override;
+  void Finish(::grpc::ServerInitializer* si) override;
+  void ChangeArguments(const ::grpc::string& name, void* value) override;
+  bool has_async_methods() const override;
+  bool has_sync_methods() const override;
+
+ private:
+  std::shared_ptr<grpc::ProtoServerReflection> reflection_service_;
+};
+
+/// Add proto reflection plugin to \a ServerBuilder.
+/// This function should be called at the static initialization time.
+void InitProtoReflectionServerBuilderPlugin();
+
+}  // namespace reflection
+}  // namespace grpc
+
+#endif  // GRPCPP_EXT_PROTO_SERVER_REFLECTION_PLUGIN_H
diff --git a/include/grpcpp/generic/async_generic_service.h b/include/grpcpp/generic/async_generic_service.h
new file mode 100644
index 0000000..7eaa541
--- /dev/null
+++ b/include/grpcpp/generic/async_generic_service.h
@@ -0,0 +1,78 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_GENERIC_ASYNC_GENERIC_SERVICE_H
+#define GRPCPP_GENERIC_ASYNC_GENERIC_SERVICE_H
+
+#include <grpcpp/support/async_stream.h>
+#include <grpcpp/support/byte_buffer.h>
+
+struct grpc_server;
+
+namespace grpc {
+
+typedef ServerAsyncReaderWriter<ByteBuffer, ByteBuffer>
+    GenericServerAsyncReaderWriter;
+
+class GenericServerContext final : public ServerContext {
+ public:
+  const grpc::string& method() const { return method_; }
+  const grpc::string& host() const { return host_; }
+
+ private:
+  friend class Server;
+  friend class ServerInterface;
+
+  grpc::string method_;
+  grpc::string host_;
+};
+
+// A generic service at the server side accepts all RPC methods and hosts. It is
+// typically used in proxies. The generic service can be registered to a server
+// which also has other services.
+// Sample usage:
+//   ServerBuilder builder;
+//   auto cq = builder.AddCompletionQueue();
+//   AsyncGenericService generic_service;
+//   builder.RegisterAsyncGeneicService(&generic_service);
+//   auto server = builder.BuildAndStart();
+//
+//   // request a new call
+//   GenericServerContext context;
+//   GenericAsyncReaderWriter stream;
+//   generic_service.RequestCall(&context, &stream, cq.get(), cq.get(), tag);
+//
+// When tag is retrieved from cq->Next(), context.method() can be used to look
+// at the method and the RPC can be handled accordingly.
+class AsyncGenericService final {
+ public:
+  AsyncGenericService() : server_(nullptr) {}
+
+  void RequestCall(GenericServerContext* ctx,
+                   GenericServerAsyncReaderWriter* reader_writer,
+                   CompletionQueue* call_cq,
+                   ServerCompletionQueue* notification_cq, void* tag);
+
+ private:
+  friend class Server;
+  Server* server_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_GENERIC_ASYNC_GENERIC_SERVICE_H
diff --git a/include/grpcpp/generic/generic_stub.h b/include/grpcpp/generic/generic_stub.h
new file mode 100644
index 0000000..92405a4
--- /dev/null
+++ b/include/grpcpp/generic/generic_stub.h
@@ -0,0 +1,71 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_GENERIC_GENERIC_STUB_H
+#define GRPCPP_GENERIC_GENERIC_STUB_H
+
+#include <grpcpp/support/async_stream.h>
+#include <grpcpp/support/async_unary_call.h>
+#include <grpcpp/support/byte_buffer.h>
+
+namespace grpc {
+
+class CompletionQueue;
+typedef ClientAsyncReaderWriter<ByteBuffer, ByteBuffer>
+    GenericClientAsyncReaderWriter;
+typedef ClientAsyncResponseReader<ByteBuffer> GenericClientAsyncResponseReader;
+
+/// Generic stubs provide a type-unsafe interface to call gRPC methods
+/// by name.
+class GenericStub final {
+ public:
+  explicit GenericStub(std::shared_ptr<ChannelInterface> channel)
+      : channel_(channel) {}
+
+  /// Setup a call to a named method \a method using \a context, but don't
+  /// start it. Let it be started explicitly with StartCall and a tag.
+  /// The return value only indicates whether or not registration of the call
+  /// succeeded (i.e. the call won't proceed if the return value is nullptr).
+  std::unique_ptr<GenericClientAsyncReaderWriter> PrepareCall(
+      ClientContext* context, const grpc::string& method, CompletionQueue* cq);
+
+  /// Setup a unary call to a named method \a method using \a context, and don't
+  /// start it. Let it be started explicitly with StartCall.
+  /// The return value only indicates whether or not registration of the call
+  /// succeeded (i.e. the call won't proceed if the return value is nullptr).
+  std::unique_ptr<GenericClientAsyncResponseReader> PrepareUnaryCall(
+      ClientContext* context, const grpc::string& method,
+      const ByteBuffer& request, CompletionQueue* cq);
+
+  /// DEPRECATED for multi-threaded use
+  /// Begin a call to a named method \a method using \a context.
+  /// A tag \a tag will be delivered to \a cq when the call has been started
+  /// (i.e, initial metadata has been sent).
+  /// The return value only indicates whether or not registration of the call
+  /// succeeded (i.e. the call won't proceed if the return value is nullptr).
+  std::unique_ptr<GenericClientAsyncReaderWriter> Call(
+      ClientContext* context, const grpc::string& method, CompletionQueue* cq,
+      void* tag);
+
+ private:
+  std::shared_ptr<ChannelInterface> channel_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_GENERIC_GENERIC_STUB_H
diff --git a/include/grpcpp/grpcpp.h b/include/grpcpp/grpcpp.h
new file mode 100644
index 0000000..aa8a242
--- /dev/null
+++ b/include/grpcpp/grpcpp.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/// \mainpage gRPC C++ API
+///
+/// The gRPC C++ API mainly consists of the following classes:
+/// <br>
+/// - grpc::Channel, which represents the connection to an endpoint. See [the
+/// gRPC Concepts page](https://grpc.io/docs/guides/concepts.html) for more
+/// details. Channels are created by the factory function grpc::CreateChannel.
+///
+/// - grpc::CompletionQueue, the producer-consumer queue used for all
+/// asynchronous communication with the gRPC runtime.
+///
+/// - grpc::ClientContext and grpc::ServerContext, where optional configuration
+/// for an RPC can be set, such as setting custom metadata to be conveyed to the
+/// peer, compression settings, authentication, etc.
+///
+/// - grpc::Server, representing a gRPC server, created by grpc::ServerBuilder.
+///
+/// Streaming calls are handled with the streaming classes in
+/// \ref sync_stream.h and
+/// \ref async_stream.h.
+///
+/// Refer to the
+/// [examples](https://github.com/grpc/grpc/blob/master/examples/cpp)
+/// for code putting these pieces into play.
+
+#ifndef GRPCPP_GRPCPP_H
+#define GRPCPP_GRPCPP_H
+
+// Pragma for http://include-what-you-use.org/ tool, tells that following
+// headers are not private for grpcpp.h and are part of its interface.
+// IWYU pragma: begin_exports
+#include <grpc/grpc.h>
+
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/completion_queue.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/create_channel_posix.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
+#include <grpcpp/server_posix.h>
+// IWYU pragma: end_exports
+
+namespace grpc {
+/// Return gRPC library version.
+grpc::string Version();
+}  // namespace grpc
+
+#endif  // GRPCPP_GRPCPP_H
diff --git a/include/grpcpp/health_check_service_interface.h b/include/grpcpp/health_check_service_interface.h
new file mode 100644
index 0000000..b45a699
--- /dev/null
+++ b/include/grpcpp/health_check_service_interface.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_HEALTH_CHECK_SERVICE_INTERFACE_H
+#define GRPCPP_HEALTH_CHECK_SERVICE_INTERFACE_H
+
+#include <grpcpp/support/config.h>
+
+namespace grpc {
+
+const char kHealthCheckServiceInterfaceArg[] =
+    "grpc.health_check_service_interface";
+
+/// The gRPC server uses this interface to expose the health checking service
+/// without depending on protobuf.
+class HealthCheckServiceInterface {
+ public:
+  virtual ~HealthCheckServiceInterface() {}
+
+  /// Set or change the serving status of the given \a service_name.
+  virtual void SetServingStatus(const grpc::string& service_name,
+                                bool serving) = 0;
+  /// Apply to all registered service names.
+  virtual void SetServingStatus(bool serving) = 0;
+};
+
+/// Enable/disable the default health checking service. This applies to all C++
+/// servers created afterwards. For each server, user can override the default
+/// with a HealthCheckServiceServerBuilderOption.
+/// NOT thread safe.
+void EnableDefaultHealthCheckService(bool enable);
+
+/// Returns whether the default health checking service is enabled.
+/// NOT thread safe.
+bool DefaultHealthCheckServiceEnabled();
+
+}  // namespace grpc
+
+#endif  // GRPCPP_HEALTH_CHECK_SERVICE_INTERFACE_H
diff --git a/include/grpc++/impl/README.md b/include/grpcpp/impl/README.md
similarity index 100%
rename from include/grpc++/impl/README.md
rename to include/grpcpp/impl/README.md
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/impl/call.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/impl/call.h
index 692c00c..a6b1312 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/impl/call.h
@@ -16,15 +16,9 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_IMPL_CALL_H
+#define GRPCPP_IMPL_CALL_H
 
-#include <grpc/support/time.h>
+#include <grpcpp/impl/codegen/call.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_IMPL_CALL_H
diff --git a/include/grpcpp/impl/channel_argument_option.h b/include/grpcpp/impl/channel_argument_option.h
new file mode 100644
index 0000000..0c48824
--- /dev/null
+++ b/include/grpcpp/impl/channel_argument_option.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CHANNEL_ARGUMENT_OPTION_H
+#define GRPCPP_IMPL_CHANNEL_ARGUMENT_OPTION_H
+
+#include <map>
+#include <memory>
+
+#include <grpcpp/impl/server_builder_option.h>
+#include <grpcpp/support/channel_arguments.h>
+
+namespace grpc {
+
+std::unique_ptr<ServerBuilderOption> MakeChannelArgumentOption(
+    const grpc::string& name, const grpc::string& value);
+std::unique_ptr<ServerBuilderOption> MakeChannelArgumentOption(
+    const grpc::string& name, int value);
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CHANNEL_ARGUMENT_OPTION_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/impl/client_unary_call.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/impl/client_unary_call.h
index 692c00c..378482c 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/impl/client_unary_call.h
@@ -16,15 +16,9 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_IMPL_CLIENT_UNARY_CALL_H
+#define GRPCPP_IMPL_CLIENT_UNARY_CALL_H
 
-#include <grpc/support/time.h>
+#include <grpcpp/impl/codegen/client_unary_call.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_IMPL_CLIENT_UNARY_CALL_H
diff --git a/include/grpcpp/impl/codegen/async_stream.h b/include/grpcpp/impl/codegen/async_stream.h
new file mode 100644
index 0000000..b213459
--- /dev/null
+++ b/include/grpcpp/impl/codegen/async_stream.h
@@ -0,0 +1,1068 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_ASYNC_STREAM_H
+#define GRPCPP_IMPL_CODEGEN_ASYNC_STREAM_H
+
+#include <grpcpp/impl/codegen/call.h>
+#include <grpcpp/impl/codegen/channel_interface.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/server_context.h>
+#include <grpcpp/impl/codegen/service_type.h>
+#include <grpcpp/impl/codegen/status.h>
+
+namespace grpc {
+
+class CompletionQueue;
+
+namespace internal {
+/// Common interface for all client side asynchronous streaming.
+class ClientAsyncStreamingInterface {
+ public:
+  virtual ~ClientAsyncStreamingInterface() {}
+
+  /// Start the call that was set up by the constructor, but only if the
+  /// constructor was invoked through the "Prepare" API which doesn't actually
+  /// start the call
+  virtual void StartCall(void* tag) = 0;
+
+  /// Request notification of the reading of the initial metadata. Completion
+  /// will be notified by \a tag on the associated completion queue.
+  /// This call is optional, but if it is used, it cannot be used concurrently
+  /// with or after the \a AsyncReaderInterface::Read method.
+  ///
+  /// \param[in] tag Tag identifying this request.
+  virtual void ReadInitialMetadata(void* tag) = 0;
+
+  /// Indicate that the stream is to be finished and request notification for
+  /// when the call has been ended.
+  /// Should not be used concurrently with other operations.
+  ///
+  /// It is appropriate to call this method when both:
+  ///   * the client side has no more message to send
+  ///     (this can be declared implicitly by calling this method, or
+  ///     explicitly through an earlier call to the <i>WritesDone</i> method
+  ///     of the class in use, e.g. \a ClientAsyncWriterInterface::WritesDone or
+  ///     \a ClientAsyncReaderWriterInterface::WritesDone).
+  ///   * there are no more messages to be received from the server (this can
+  ///     be known implicitly by the calling code, or explicitly from an
+  ///     earlier call to \a AsyncReaderInterface::Read that yielded a failed
+  ///     result, e.g. cq->Next(&read_tag, &ok) filled in 'ok' with 'false').
+  ///
+  /// This function will return when either:
+  /// - all incoming messages have been read and the server has returned
+  ///   a status.
+  /// - the server has returned a non-OK status.
+  /// - the call failed for some reason and the library generated a
+  ///   status.
+  ///
+  /// Note that implementations of this method attempt to receive initial
+  /// metadata from the server if initial metadata hasn't yet been received.
+  ///
+  /// \param[in] tag Tag identifying this request.
+  /// \param[out] status To be updated with the operation status.
+  virtual void Finish(Status* status, void* tag) = 0;
+};
+
+/// An interface that yields a sequence of messages of type \a R.
+template <class R>
+class AsyncReaderInterface {
+ public:
+  virtual ~AsyncReaderInterface() {}
+
+  /// Read a message of type \a R into \a msg. Completion will be notified by \a
+  /// tag on the associated completion queue.
+  /// This is thread-safe with respect to \a Write or \a WritesDone methods. It
+  /// should not be called concurrently with other streaming APIs
+  /// on the same stream. It is not meaningful to call it concurrently
+  /// with another \a AsyncReaderInterface::Read on the same stream since reads
+  /// on the same stream are delivered in order.
+  ///
+  /// \param[out] msg Where to eventually store the read message.
+  /// \param[in] tag The tag identifying the operation.
+  ///
+  /// Side effect: note that this method attempt to receive initial metadata for
+  /// a stream if it hasn't yet been received.
+  virtual void Read(R* msg, void* tag) = 0;
+};
+
+/// An interface that can be fed a sequence of messages of type \a W.
+template <class W>
+class AsyncWriterInterface {
+ public:
+  virtual ~AsyncWriterInterface() {}
+
+  /// Request the writing of \a msg with identifying tag \a tag.
+  ///
+  /// Only one write may be outstanding at any given time. This means that
+  /// after calling Write, one must wait to receive \a tag from the completion
+  /// queue BEFORE calling Write again.
+  /// This is thread-safe with respect to \a AsyncReaderInterface::Read
+  ///
+  /// \param[in] msg The message to be written.
+  /// \param[in] tag The tag identifying the operation.
+  virtual void Write(const W& msg, void* tag) = 0;
+
+  /// Request the writing of \a msg using WriteOptions \a options with
+  /// identifying tag \a tag.
+  ///
+  /// Only one write may be outstanding at any given time. This means that
+  /// after calling Write, one must wait to receive \a tag from the completion
+  /// queue BEFORE calling Write again.
+  /// WriteOptions \a options is used to set the write options of this message.
+  /// This is thread-safe with respect to \a AsyncReaderInterface::Read
+  ///
+  /// \param[in] msg The message to be written.
+  /// \param[in] options The WriteOptions to be used to write this message.
+  /// \param[in] tag The tag identifying the operation.
+  virtual void Write(const W& msg, WriteOptions options, void* tag) = 0;
+
+  /// Request the writing of \a msg and coalesce it with the writing
+  /// of trailing metadata, using WriteOptions \a options with
+  /// identifying tag \a tag.
+  ///
+  /// For client, WriteLast is equivalent of performing Write and
+  /// WritesDone in a single step.
+  /// For server, WriteLast buffers the \a msg. The writing of \a msg is held
+  /// until Finish is called, where \a msg and trailing metadata are coalesced
+  /// and write is initiated. Note that WriteLast can only buffer \a msg up to
+  /// the flow control window size. If \a msg size is larger than the window
+  /// size, it will be sent on wire without buffering.
+  ///
+  /// \param[in] msg The message to be written.
+  /// \param[in] options The WriteOptions to be used to write this message.
+  /// \param[in] tag The tag identifying the operation.
+  void WriteLast(const W& msg, WriteOptions options, void* tag) {
+    Write(msg, options.set_last_message(), tag);
+  }
+};
+
+}  // namespace internal
+
+template <class R>
+class ClientAsyncReaderInterface
+    : public internal::ClientAsyncStreamingInterface,
+      public internal::AsyncReaderInterface<R> {};
+
+namespace internal {
+template <class R>
+class ClientAsyncReaderFactory {
+ public:
+  /// Create a stream object.
+  /// Write the first request out if \a start is set.
+  /// \a tag will be notified on \a cq when the call has been started and
+  /// \a request has been written out. If \a start is not set, \a tag must be
+  /// nullptr and the actual call must be initiated by StartCall
+  /// Note that \a context will be used to fill in custom initial metadata
+  /// used to send to the server when starting the call.
+  template <class W>
+  static ClientAsyncReader<R>* Create(ChannelInterface* channel,
+                                      CompletionQueue* cq,
+                                      const ::grpc::internal::RpcMethod& method,
+                                      ClientContext* context, const W& request,
+                                      bool start, void* tag) {
+    ::grpc::internal::Call call = channel->CreateCall(method, context, cq);
+    return new (g_core_codegen_interface->grpc_call_arena_alloc(
+        call.call(), sizeof(ClientAsyncReader<R>)))
+        ClientAsyncReader<R>(call, context, request, start, tag);
+  }
+};
+}  // namespace internal
+
+/// Async client-side API for doing server-streaming RPCs,
+/// where the incoming message stream coming from the server has
+/// messages of type \a R.
+template <class R>
+class ClientAsyncReader final : public ClientAsyncReaderInterface<R> {
+ public:
+  // always allocated against a call arena, no memory free required
+  static void operator delete(void* ptr, std::size_t size) {
+    assert(size == sizeof(ClientAsyncReader));
+  }
+
+  void StartCall(void* tag) override {
+    assert(!started_);
+    started_ = true;
+    StartCallInternal(tag);
+  }
+
+  /// See the \a ClientAsyncStreamingInterface.ReadInitialMetadata
+  /// method for semantics.
+  ///
+  /// Side effect:
+  ///   - upon receiving initial metadata from the server,
+  ///     the \a ClientContext associated with this call is updated, and the
+  ///     calling code can access the received metadata through the
+  ///     \a ClientContext.
+  void ReadInitialMetadata(void* tag) override {
+    assert(started_);
+    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
+
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.RecvInitialMetadata(context_);
+    call_.PerformOps(&meta_ops_);
+  }
+
+  void Read(R* msg, void* tag) override {
+    assert(started_);
+    read_ops_.set_output_tag(tag);
+    if (!context_->initial_metadata_received_) {
+      read_ops_.RecvInitialMetadata(context_);
+    }
+    read_ops_.RecvMessage(msg);
+    call_.PerformOps(&read_ops_);
+  }
+
+  /// See the \a ClientAsyncStreamingInterface.Finish method for semantics.
+  ///
+  /// Side effect:
+  ///   - the \a ClientContext associated with this call is updated with
+  ///     possible initial and trailing metadata received from the server.
+  void Finish(Status* status, void* tag) override {
+    assert(started_);
+    finish_ops_.set_output_tag(tag);
+    if (!context_->initial_metadata_received_) {
+      finish_ops_.RecvInitialMetadata(context_);
+    }
+    finish_ops_.ClientRecvStatus(context_, status);
+    call_.PerformOps(&finish_ops_);
+  }
+
+ private:
+  friend class internal::ClientAsyncReaderFactory<R>;
+  template <class W>
+  ClientAsyncReader(::grpc::internal::Call call, ClientContext* context,
+                    const W& request, bool start, void* tag)
+      : context_(context), call_(call), started_(start) {
+    // TODO(ctiller): don't assert
+    GPR_CODEGEN_ASSERT(init_ops_.SendMessage(request).ok());
+    init_ops_.ClientSendClose();
+    if (start) {
+      StartCallInternal(tag);
+    } else {
+      assert(tag == nullptr);
+    }
+  }
+
+  void StartCallInternal(void* tag) {
+    init_ops_.SendInitialMetadata(context_->send_initial_metadata_,
+                                  context_->initial_metadata_flags());
+    init_ops_.set_output_tag(tag);
+    call_.PerformOps(&init_ops_);
+  }
+
+  ClientContext* context_;
+  ::grpc::internal::Call call_;
+  bool started_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
+                              ::grpc::internal::CallOpSendMessage,
+                              ::grpc::internal::CallOpClientSendClose>
+      init_ops_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
+      meta_ops_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
+                              ::grpc::internal::CallOpRecvMessage<R>>
+      read_ops_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
+                              ::grpc::internal::CallOpClientRecvStatus>
+      finish_ops_;
+};
+
+/// Common interface for client side asynchronous writing.
+template <class W>
+class ClientAsyncWriterInterface
+    : public internal::ClientAsyncStreamingInterface,
+      public internal::AsyncWriterInterface<W> {
+ public:
+  /// Signal the client is done with the writes (half-close the client stream).
+  /// Thread-safe with respect to \a AsyncReaderInterface::Read
+  ///
+  /// \param[in] tag The tag identifying the operation.
+  virtual void WritesDone(void* tag) = 0;
+};
+
+namespace internal {
+template <class W>
+class ClientAsyncWriterFactory {
+ public:
+  /// Create a stream object.
+  /// Start the RPC if \a start is set
+  /// \a tag will be notified on \a cq when the call has been started (i.e.
+  /// intitial metadata sent) and \a request has been written out.
+  /// If \a start is not set, \a tag must be nullptr and the actual call
+  /// must be initiated by StartCall
+  /// Note that \a context will be used to fill in custom initial metadata
+  /// used to send to the server when starting the call.
+  /// \a response will be filled in with the single expected response
+  /// message from the server upon a successful call to the \a Finish
+  /// method of this instance.
+  template <class R>
+  static ClientAsyncWriter<W>* Create(ChannelInterface* channel,
+                                      CompletionQueue* cq,
+                                      const ::grpc::internal::RpcMethod& method,
+                                      ClientContext* context, R* response,
+                                      bool start, void* tag) {
+    ::grpc::internal::Call call = channel->CreateCall(method, context, cq);
+    return new (g_core_codegen_interface->grpc_call_arena_alloc(
+        call.call(), sizeof(ClientAsyncWriter<W>)))
+        ClientAsyncWriter<W>(call, context, response, start, tag);
+  }
+};
+}  // namespace internal
+
+/// Async API on the client side for doing client-streaming RPCs,
+/// where the outgoing message stream going to the server contains
+/// messages of type \a W.
+template <class W>
+class ClientAsyncWriter final : public ClientAsyncWriterInterface<W> {
+ public:
+  // always allocated against a call arena, no memory free required
+  static void operator delete(void* ptr, std::size_t size) {
+    assert(size == sizeof(ClientAsyncWriter));
+  }
+
+  void StartCall(void* tag) override {
+    assert(!started_);
+    started_ = true;
+    StartCallInternal(tag);
+  }
+
+  /// See the \a ClientAsyncStreamingInterface.ReadInitialMetadata method for
+  /// semantics.
+  ///
+  /// Side effect:
+  ///   - upon receiving initial metadata from the server, the \a ClientContext
+  ///     associated with this call is updated, and the calling code can access
+  ///     the received metadata through the \a ClientContext.
+  void ReadInitialMetadata(void* tag) override {
+    assert(started_);
+    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
+
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.RecvInitialMetadata(context_);
+    call_.PerformOps(&meta_ops_);
+  }
+
+  void Write(const W& msg, void* tag) override {
+    assert(started_);
+    write_ops_.set_output_tag(tag);
+    // TODO(ctiller): don't assert
+    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
+    call_.PerformOps(&write_ops_);
+  }
+
+  void Write(const W& msg, WriteOptions options, void* tag) override {
+    assert(started_);
+    write_ops_.set_output_tag(tag);
+    if (options.is_last_message()) {
+      options.set_buffer_hint();
+      write_ops_.ClientSendClose();
+    }
+    // TODO(ctiller): don't assert
+    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
+    call_.PerformOps(&write_ops_);
+  }
+
+  void WritesDone(void* tag) override {
+    assert(started_);
+    write_ops_.set_output_tag(tag);
+    write_ops_.ClientSendClose();
+    call_.PerformOps(&write_ops_);
+  }
+
+  /// See the \a ClientAsyncStreamingInterface.Finish method for semantics.
+  ///
+  /// Side effect:
+  ///   - the \a ClientContext associated with this call is updated with
+  ///     possible initial and trailing metadata received from the server.
+  ///   - attempts to fill in the \a response parameter passed to this class's
+  ///     constructor with the server's response message.
+  void Finish(Status* status, void* tag) override {
+    assert(started_);
+    finish_ops_.set_output_tag(tag);
+    if (!context_->initial_metadata_received_) {
+      finish_ops_.RecvInitialMetadata(context_);
+    }
+    finish_ops_.ClientRecvStatus(context_, status);
+    call_.PerformOps(&finish_ops_);
+  }
+
+ private:
+  friend class internal::ClientAsyncWriterFactory<W>;
+  template <class R>
+  ClientAsyncWriter(::grpc::internal::Call call, ClientContext* context,
+                    R* response, bool start, void* tag)
+      : context_(context), call_(call), started_(start) {
+    finish_ops_.RecvMessage(response);
+    finish_ops_.AllowNoMessage();
+    if (start) {
+      StartCallInternal(tag);
+    } else {
+      assert(tag == nullptr);
+    }
+  }
+
+  void StartCallInternal(void* tag) {
+    write_ops_.SendInitialMetadata(context_->send_initial_metadata_,
+                                   context_->initial_metadata_flags());
+    // if corked bit is set in context, we just keep the initial metadata
+    // buffered up to coalesce with later message send. No op is performed.
+    if (!context_->initial_metadata_corked_) {
+      write_ops_.set_output_tag(tag);
+      call_.PerformOps(&write_ops_);
+    }
+  }
+
+  ClientContext* context_;
+  ::grpc::internal::Call call_;
+  bool started_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
+      meta_ops_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
+                              ::grpc::internal::CallOpSendMessage,
+                              ::grpc::internal::CallOpClientSendClose>
+      write_ops_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
+                              ::grpc::internal::CallOpGenericRecvMessage,
+                              ::grpc::internal::CallOpClientRecvStatus>
+      finish_ops_;
+};
+
+/// Async client-side interface for bi-directional streaming,
+/// where the client-to-server message stream has messages of type \a W,
+/// and the server-to-client message stream has messages of type \a R.
+template <class W, class R>
+class ClientAsyncReaderWriterInterface
+    : public internal::ClientAsyncStreamingInterface,
+      public internal::AsyncWriterInterface<W>,
+      public internal::AsyncReaderInterface<R> {
+ public:
+  /// Signal the client is done with the writes (half-close the client stream).
+  /// Thread-safe with respect to \a AsyncReaderInterface::Read
+  ///
+  /// \param[in] tag The tag identifying the operation.
+  virtual void WritesDone(void* tag) = 0;
+};
+
+namespace internal {
+template <class W, class R>
+class ClientAsyncReaderWriterFactory {
+ public:
+  /// Create a stream object.
+  /// Start the RPC request if \a start is set.
+  /// \a tag will be notified on \a cq when the call has been started (i.e.
+  /// intitial metadata sent). If \a start is not set, \a tag must be
+  /// nullptr and the actual call must be initiated by StartCall
+  /// Note that \a context will be used to fill in custom initial metadata
+  /// used to send to the server when starting the call.
+  static ClientAsyncReaderWriter<W, R>* Create(
+      ChannelInterface* channel, CompletionQueue* cq,
+      const ::grpc::internal::RpcMethod& method, ClientContext* context,
+      bool start, void* tag) {
+    ::grpc::internal::Call call = channel->CreateCall(method, context, cq);
+
+    return new (g_core_codegen_interface->grpc_call_arena_alloc(
+        call.call(), sizeof(ClientAsyncReaderWriter<W, R>)))
+        ClientAsyncReaderWriter<W, R>(call, context, start, tag);
+  }
+};
+}  // namespace internal
+
+/// Async client-side interface for bi-directional streaming,
+/// where the outgoing message stream going to the server
+/// has messages of type \a W,  and the incoming message stream coming
+/// from the server has messages of type \a R.
+template <class W, class R>
+class ClientAsyncReaderWriter final
+    : public ClientAsyncReaderWriterInterface<W, R> {
+ public:
+  // always allocated against a call arena, no memory free required
+  static void operator delete(void* ptr, std::size_t size) {
+    assert(size == sizeof(ClientAsyncReaderWriter));
+  }
+
+  void StartCall(void* tag) override {
+    assert(!started_);
+    started_ = true;
+    StartCallInternal(tag);
+  }
+
+  /// See the \a ClientAsyncStreamingInterface.ReadInitialMetadata method
+  /// for semantics of this method.
+  ///
+  /// Side effect:
+  ///   - upon receiving initial metadata from the server, the \a ClientContext
+  ///     is updated with it, and then the receiving initial metadata can
+  ///     be accessed through this \a ClientContext.
+  void ReadInitialMetadata(void* tag) override {
+    assert(started_);
+    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
+
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.RecvInitialMetadata(context_);
+    call_.PerformOps(&meta_ops_);
+  }
+
+  void Read(R* msg, void* tag) override {
+    assert(started_);
+    read_ops_.set_output_tag(tag);
+    if (!context_->initial_metadata_received_) {
+      read_ops_.RecvInitialMetadata(context_);
+    }
+    read_ops_.RecvMessage(msg);
+    call_.PerformOps(&read_ops_);
+  }
+
+  void Write(const W& msg, void* tag) override {
+    assert(started_);
+    write_ops_.set_output_tag(tag);
+    // TODO(ctiller): don't assert
+    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
+    call_.PerformOps(&write_ops_);
+  }
+
+  void Write(const W& msg, WriteOptions options, void* tag) override {
+    assert(started_);
+    write_ops_.set_output_tag(tag);
+    if (options.is_last_message()) {
+      options.set_buffer_hint();
+      write_ops_.ClientSendClose();
+    }
+    // TODO(ctiller): don't assert
+    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
+    call_.PerformOps(&write_ops_);
+  }
+
+  void WritesDone(void* tag) override {
+    assert(started_);
+    write_ops_.set_output_tag(tag);
+    write_ops_.ClientSendClose();
+    call_.PerformOps(&write_ops_);
+  }
+
+  /// See the \a ClientAsyncStreamingInterface.Finish method for semantics.
+  /// Side effect
+  ///   - the \a ClientContext associated with this call is updated with
+  ///     possible initial and trailing metadata sent from the server.
+  void Finish(Status* status, void* tag) override {
+    assert(started_);
+    finish_ops_.set_output_tag(tag);
+    if (!context_->initial_metadata_received_) {
+      finish_ops_.RecvInitialMetadata(context_);
+    }
+    finish_ops_.ClientRecvStatus(context_, status);
+    call_.PerformOps(&finish_ops_);
+  }
+
+ private:
+  friend class internal::ClientAsyncReaderWriterFactory<W, R>;
+  ClientAsyncReaderWriter(::grpc::internal::Call call, ClientContext* context,
+                          bool start, void* tag)
+      : context_(context), call_(call), started_(start) {
+    if (start) {
+      StartCallInternal(tag);
+    } else {
+      assert(tag == nullptr);
+    }
+  }
+
+  void StartCallInternal(void* tag) {
+    write_ops_.SendInitialMetadata(context_->send_initial_metadata_,
+                                   context_->initial_metadata_flags());
+    // if corked bit is set in context, we just keep the initial metadata
+    // buffered up to coalesce with later message send. No op is performed.
+    if (!context_->initial_metadata_corked_) {
+      write_ops_.set_output_tag(tag);
+      call_.PerformOps(&write_ops_);
+    }
+  }
+
+  ClientContext* context_;
+  ::grpc::internal::Call call_;
+  bool started_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
+      meta_ops_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
+                              ::grpc::internal::CallOpRecvMessage<R>>
+      read_ops_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
+                              ::grpc::internal::CallOpSendMessage,
+                              ::grpc::internal::CallOpClientSendClose>
+      write_ops_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
+                              ::grpc::internal::CallOpClientRecvStatus>
+      finish_ops_;
+};
+
+template <class W, class R>
+class ServerAsyncReaderInterface
+    : public internal::ServerAsyncStreamingInterface,
+      public internal::AsyncReaderInterface<R> {
+ public:
+  /// Indicate that the stream is to be finished with a certain status code
+  /// and also send out \a msg response to the client.
+  /// Request notification for when the server has sent the response and the
+  /// appropriate signals to the client to end the call.
+  /// Should not be used concurrently with other operations.
+  ///
+  /// It is appropriate to call this method when:
+  ///   * all messages from the client have been received (either known
+  ///     implictly, or explicitly because a previous
+  ///     \a AsyncReaderInterface::Read operation with a non-ok result,
+  ///     e.g., cq->Next(&read_tag, &ok) filled in 'ok' with 'false').
+  ///
+  /// This operation will end when the server has finished sending out initial
+  /// metadata (if not sent already), response message, and status, or if
+  /// some failure occurred when trying to do so.
+  ///
+  /// \param[in] tag Tag identifying this request.
+  /// \param[in] status To be sent to the client as the result of this call.
+  /// \param[in] msg To be sent to the client as the response for this call.
+  virtual void Finish(const W& msg, const Status& status, void* tag) = 0;
+
+  /// Indicate that the stream is to be finished with a certain
+  /// non-OK status code.
+  /// Request notification for when the server has sent the appropriate
+  /// signals to the client to end the call.
+  /// Should not be used concurrently with other operations.
+  ///
+  /// This call is meant to end the call with some error, and can be called at
+  /// any point that the server would like to "fail" the call (though note
+  /// this shouldn't be called concurrently with any other "sending" call, like
+  /// \a AsyncWriterInterface::Write).
+  ///
+  /// This operation will end when the server has finished sending out initial
+  /// metadata (if not sent already), and status, or if some failure occurred
+  /// when trying to do so.
+  ///
+  /// \param[in] tag Tag identifying this request.
+  /// \param[in] status To be sent to the client as the result of this call.
+  ///     - Note: \a status must have a non-OK code.
+  virtual void FinishWithError(const Status& status, void* tag) = 0;
+};
+
+/// Async server-side API for doing client-streaming RPCs,
+/// where the incoming message stream from the client has messages of type \a R,
+/// and the single response message sent from the server is type \a W.
+template <class W, class R>
+class ServerAsyncReader final : public ServerAsyncReaderInterface<W, R> {
+ public:
+  explicit ServerAsyncReader(ServerContext* ctx)
+      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
+
+  /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics.
+  ///
+  /// Implicit input parameter:
+  ///   - The initial metadata that will be sent to the client from this op will
+  ///     be taken from the \a ServerContext associated with the call.
+  void SendInitialMetadata(void* tag) override {
+    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
+
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
+                                  ctx_->initial_metadata_flags());
+    if (ctx_->compression_level_set()) {
+      meta_ops_.set_compression_level(ctx_->compression_level());
+    }
+    ctx_->sent_initial_metadata_ = true;
+    call_.PerformOps(&meta_ops_);
+  }
+
+  void Read(R* msg, void* tag) override {
+    read_ops_.set_output_tag(tag);
+    read_ops_.RecvMessage(msg);
+    call_.PerformOps(&read_ops_);
+  }
+
+  /// See the \a ServerAsyncReaderInterface.Read method for semantics
+  ///
+  /// Side effect:
+  ///   - also sends initial metadata if not alreay sent.
+  ///   - uses the \a ServerContext associated with this call to send possible
+  ///     initial and trailing metadata.
+  ///
+  /// Note: \a msg is not sent if \a status has a non-OK code.
+  void Finish(const W& msg, const Status& status, void* tag) override {
+    finish_ops_.set_output_tag(tag);
+    if (!ctx_->sent_initial_metadata_) {
+      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
+                                      ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        finish_ops_.set_compression_level(ctx_->compression_level());
+      }
+      ctx_->sent_initial_metadata_ = true;
+    }
+    // The response is dropped if the status is not OK.
+    if (status.ok()) {
+      finish_ops_.ServerSendStatus(ctx_->trailing_metadata_,
+                                   finish_ops_.SendMessage(msg));
+    } else {
+      finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+    }
+    call_.PerformOps(&finish_ops_);
+  }
+
+  /// See the \a ServerAsyncReaderInterface.Read method for semantics
+  ///
+  /// Side effect:
+  ///   - also sends initial metadata if not alreay sent.
+  ///   - uses the \a ServerContext associated with this call to send possible
+  ///     initial and trailing metadata.
+  void FinishWithError(const Status& status, void* tag) override {
+    GPR_CODEGEN_ASSERT(!status.ok());
+    finish_ops_.set_output_tag(tag);
+    if (!ctx_->sent_initial_metadata_) {
+      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
+                                      ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        finish_ops_.set_compression_level(ctx_->compression_level());
+      }
+      ctx_->sent_initial_metadata_ = true;
+    }
+    finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+    call_.PerformOps(&finish_ops_);
+  }
+
+ private:
+  void BindCall(::grpc::internal::Call* call) override { call_ = *call; }
+
+  ::grpc::internal::Call call_;
+  ServerContext* ctx_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
+      meta_ops_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage<R>> read_ops_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
+                              ::grpc::internal::CallOpSendMessage,
+                              ::grpc::internal::CallOpServerSendStatus>
+      finish_ops_;
+};
+
+template <class W>
+class ServerAsyncWriterInterface
+    : public internal::ServerAsyncStreamingInterface,
+      public internal::AsyncWriterInterface<W> {
+ public:
+  /// Indicate that the stream is to be finished with a certain status code.
+  /// Request notification for when the server has sent the appropriate
+  /// signals to the client to end the call.
+  /// Should not be used concurrently with other operations.
+  ///
+  /// It is appropriate to call this method when either:
+  ///   * all messages from the client have been received (either known
+  ///     implictly, or explicitly because a previous \a
+  ///     AsyncReaderInterface::Read operation with a non-ok
+  ///     result (e.g., cq->Next(&read_tag, &ok) filled in 'ok' with 'false'.
+  ///   * it is desired to end the call early with some non-OK status code.
+  ///
+  /// This operation will end when the server has finished sending out initial
+  /// metadata (if not sent already), response message, and status, or if
+  /// some failure occurred when trying to do so.
+  ///
+  /// \param[in] tag Tag identifying this request.
+  /// \param[in] status To be sent to the client as the result of this call.
+  virtual void Finish(const Status& status, void* tag) = 0;
+
+  /// Request the writing of \a msg and coalesce it with trailing metadata which
+  /// contains \a status, using WriteOptions options with
+  /// identifying tag \a tag.
+  ///
+  /// WriteAndFinish is equivalent of performing WriteLast and Finish
+  /// in a single step.
+  ///
+  /// \param[in] msg The message to be written.
+  /// \param[in] options The WriteOptions to be used to write this message.
+  /// \param[in] status The Status that server returns to client.
+  /// \param[in] tag The tag identifying the operation.
+  virtual void WriteAndFinish(const W& msg, WriteOptions options,
+                              const Status& status, void* tag) = 0;
+};
+
+/// Async server-side API for doing server streaming RPCs,
+/// where the outgoing message stream from the server has messages of type \a W.
+template <class W>
+class ServerAsyncWriter final : public ServerAsyncWriterInterface<W> {
+ public:
+  explicit ServerAsyncWriter(ServerContext* ctx)
+      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
+
+  /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics.
+  ///
+  /// Implicit input parameter:
+  ///   - The initial metadata that will be sent to the client from this op will
+  ///     be taken from the \a ServerContext associated with the call.
+  ///
+  /// \param[in] tag Tag identifying this request.
+  void SendInitialMetadata(void* tag) override {
+    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
+
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
+                                  ctx_->initial_metadata_flags());
+    if (ctx_->compression_level_set()) {
+      meta_ops_.set_compression_level(ctx_->compression_level());
+    }
+    ctx_->sent_initial_metadata_ = true;
+    call_.PerformOps(&meta_ops_);
+  }
+
+  void Write(const W& msg, void* tag) override {
+    write_ops_.set_output_tag(tag);
+    EnsureInitialMetadataSent(&write_ops_);
+    // TODO(ctiller): don't assert
+    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
+    call_.PerformOps(&write_ops_);
+  }
+
+  void Write(const W& msg, WriteOptions options, void* tag) override {
+    write_ops_.set_output_tag(tag);
+    if (options.is_last_message()) {
+      options.set_buffer_hint();
+    }
+
+    EnsureInitialMetadataSent(&write_ops_);
+    // TODO(ctiller): don't assert
+    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
+    call_.PerformOps(&write_ops_);
+  }
+
+  /// See the \a ServerAsyncWriterInterface.WriteAndFinish method for semantics.
+  ///
+  /// Implicit input parameter:
+  ///   - the \a ServerContext associated with this call is used
+  ///     for sending trailing (and initial) metadata to the client.
+  ///
+  /// Note: \a status must have an OK code.
+  void WriteAndFinish(const W& msg, WriteOptions options, const Status& status,
+                      void* tag) override {
+    write_ops_.set_output_tag(tag);
+    EnsureInitialMetadataSent(&write_ops_);
+    options.set_buffer_hint();
+    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
+    write_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+    call_.PerformOps(&write_ops_);
+  }
+
+  /// See the \a ServerAsyncWriterInterface.Finish method for semantics.
+  ///
+  /// Implicit input parameter:
+  ///   - the \a ServerContext associated with this call is used for sending
+  ///     trailing (and initial if not already sent) metadata to the client.
+  ///
+  /// Note: there are no restrictions are the code of
+  /// \a status,it may be non-OK
+  void Finish(const Status& status, void* tag) override {
+    finish_ops_.set_output_tag(tag);
+    EnsureInitialMetadataSent(&finish_ops_);
+    finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+    call_.PerformOps(&finish_ops_);
+  }
+
+ private:
+  void BindCall(::grpc::internal::Call* call) override { call_ = *call; }
+
+  template <class T>
+  void EnsureInitialMetadataSent(T* ops) {
+    if (!ctx_->sent_initial_metadata_) {
+      ops->SendInitialMetadata(ctx_->initial_metadata_,
+                               ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        ops->set_compression_level(ctx_->compression_level());
+      }
+      ctx_->sent_initial_metadata_ = true;
+    }
+  }
+
+  ::grpc::internal::Call call_;
+  ServerContext* ctx_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
+      meta_ops_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
+                              ::grpc::internal::CallOpSendMessage,
+                              ::grpc::internal::CallOpServerSendStatus>
+      write_ops_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
+                              ::grpc::internal::CallOpServerSendStatus>
+      finish_ops_;
+};
+
+/// Server-side interface for asynchronous bi-directional streaming.
+template <class W, class R>
+class ServerAsyncReaderWriterInterface
+    : public internal::ServerAsyncStreamingInterface,
+      public internal::AsyncWriterInterface<W>,
+      public internal::AsyncReaderInterface<R> {
+ public:
+  /// Indicate that the stream is to be finished with a certain status code.
+  /// Request notification for when the server has sent the appropriate
+  /// signals to the client to end the call.
+  /// Should not be used concurrently with other operations.
+  ///
+  /// It is appropriate to call this method when either:
+  ///   * all messages from the client have been received (either known
+  ///     implictly, or explicitly because a previous \a
+  ///     AsyncReaderInterface::Read operation
+  ///     with a non-ok result (e.g., cq->Next(&read_tag, &ok) filled in 'ok'
+  ///     with 'false'.
+  ///   * it is desired to end the call early with some non-OK status code.
+  ///
+  /// This operation will end when the server has finished sending out initial
+  /// metadata (if not sent already), response message, and status, or if some
+  /// failure occurred when trying to do so.
+  ///
+  /// \param[in] tag Tag identifying this request.
+  /// \param[in] status To be sent to the client as the result of this call.
+  virtual void Finish(const Status& status, void* tag) = 0;
+
+  /// Request the writing of \a msg and coalesce it with trailing metadata which
+  /// contains \a status, using WriteOptions options with
+  /// identifying tag \a tag.
+  ///
+  /// WriteAndFinish is equivalent of performing WriteLast and Finish in a
+  /// single step.
+  ///
+  /// \param[in] msg The message to be written.
+  /// \param[in] options The WriteOptions to be used to write this message.
+  /// \param[in] status The Status that server returns to client.
+  /// \param[in] tag The tag identifying the operation.
+  virtual void WriteAndFinish(const W& msg, WriteOptions options,
+                              const Status& status, void* tag) = 0;
+};
+
+/// Async server-side API for doing bidirectional streaming RPCs,
+/// where the incoming message stream coming from the client has messages of
+/// type \a R, and the outgoing message stream coming from the server has
+/// messages of type \a W.
+template <class W, class R>
+class ServerAsyncReaderWriter final
+    : public ServerAsyncReaderWriterInterface<W, R> {
+ public:
+  explicit ServerAsyncReaderWriter(ServerContext* ctx)
+      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
+
+  /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics.
+  ///
+  /// Implicit input parameter:
+  ///   - The initial metadata that will be sent to the client from this op will
+  ///     be taken from the \a ServerContext associated with the call.
+  ///
+  /// \param[in] tag Tag identifying this request.
+  void SendInitialMetadata(void* tag) override {
+    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
+
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
+                                  ctx_->initial_metadata_flags());
+    if (ctx_->compression_level_set()) {
+      meta_ops_.set_compression_level(ctx_->compression_level());
+    }
+    ctx_->sent_initial_metadata_ = true;
+    call_.PerformOps(&meta_ops_);
+  }
+
+  void Read(R* msg, void* tag) override {
+    read_ops_.set_output_tag(tag);
+    read_ops_.RecvMessage(msg);
+    call_.PerformOps(&read_ops_);
+  }
+
+  void Write(const W& msg, void* tag) override {
+    write_ops_.set_output_tag(tag);
+    EnsureInitialMetadataSent(&write_ops_);
+    // TODO(ctiller): don't assert
+    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
+    call_.PerformOps(&write_ops_);
+  }
+
+  void Write(const W& msg, WriteOptions options, void* tag) override {
+    write_ops_.set_output_tag(tag);
+    if (options.is_last_message()) {
+      options.set_buffer_hint();
+    }
+    EnsureInitialMetadataSent(&write_ops_);
+    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
+    call_.PerformOps(&write_ops_);
+  }
+
+  /// See the \a ServerAsyncReaderWriterInterface.WriteAndFinish
+  /// method for semantics.
+  ///
+  /// Implicit input parameter:
+  ///   - the \a ServerContext associated with this call is used
+  ///     for sending trailing (and initial) metadata to the client.
+  ///
+  /// Note: \a status must have an OK code.
+  void WriteAndFinish(const W& msg, WriteOptions options, const Status& status,
+                      void* tag) override {
+    write_ops_.set_output_tag(tag);
+    EnsureInitialMetadataSent(&write_ops_);
+    options.set_buffer_hint();
+    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok());
+    write_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+    call_.PerformOps(&write_ops_);
+  }
+
+  /// See the \a ServerAsyncReaderWriterInterface.Finish method for semantics.
+  ///
+  /// Implicit input parameter:
+  ///   - the \a ServerContext associated with this call is used for sending
+  ///     trailing (and initial if not already sent) metadata to the client.
+  ///
+  /// Note: there are no restrictions are the code of \a status,
+  /// it may be non-OK
+  void Finish(const Status& status, void* tag) override {
+    finish_ops_.set_output_tag(tag);
+    EnsureInitialMetadataSent(&finish_ops_);
+
+    finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+    call_.PerformOps(&finish_ops_);
+  }
+
+ private:
+  friend class ::grpc::Server;
+
+  void BindCall(::grpc::internal::Call* call) override { call_ = *call; }
+
+  template <class T>
+  void EnsureInitialMetadataSent(T* ops) {
+    if (!ctx_->sent_initial_metadata_) {
+      ops->SendInitialMetadata(ctx_->initial_metadata_,
+                               ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        ops->set_compression_level(ctx_->compression_level());
+      }
+      ctx_->sent_initial_metadata_ = true;
+    }
+  }
+
+  ::grpc::internal::Call call_;
+  ServerContext* ctx_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
+      meta_ops_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage<R>> read_ops_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
+                              ::grpc::internal::CallOpSendMessage,
+                              ::grpc::internal::CallOpServerSendStatus>
+      write_ops_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
+                              ::grpc::internal::CallOpServerSendStatus>
+      finish_ops_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_ASYNC_STREAM_H
diff --git a/include/grpcpp/impl/codegen/async_unary_call.h b/include/grpcpp/impl/codegen/async_unary_call.h
new file mode 100644
index 0000000..60ff8e2
--- /dev/null
+++ b/include/grpcpp/impl/codegen/async_unary_call.h
@@ -0,0 +1,316 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_H
+#define GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_H
+
+#include <assert.h>
+#include <grpcpp/impl/codegen/call.h>
+#include <grpcpp/impl/codegen/channel_interface.h>
+#include <grpcpp/impl/codegen/client_context.h>
+#include <grpcpp/impl/codegen/server_context.h>
+#include <grpcpp/impl/codegen/service_type.h>
+#include <grpcpp/impl/codegen/status.h>
+
+namespace grpc {
+
+class CompletionQueue;
+extern CoreCodegenInterface* g_core_codegen_interface;
+
+/// An interface relevant for async client side unary RPCs (which send
+/// one request message to a server and receive one response message).
+template <class R>
+class ClientAsyncResponseReaderInterface {
+ public:
+  virtual ~ClientAsyncResponseReaderInterface() {}
+
+  /// Start the call that was set up by the constructor, but only if the
+  /// constructor was invoked through the "Prepare" API which doesn't actually
+  /// start the call
+  virtual void StartCall() = 0;
+
+  /// Request notification of the reading of initial metadata. Completion
+  /// will be notified by \a tag on the associated completion queue.
+  /// This call is optional, but if it is used, it cannot be used concurrently
+  /// with or after the \a Finish method.
+  ///
+  /// \param[in] tag Tag identifying this request.
+  virtual void ReadInitialMetadata(void* tag) = 0;
+
+  /// Request to receive the server's response \a msg and final \a status for
+  /// the call, and to notify \a tag on this call's completion queue when
+  /// finished.
+  ///
+  /// This function will return when either:
+  /// - when the server's response message and status have been received.
+  /// - when the server has returned a non-OK status (no message expected in
+  ///   this case).
+  /// - when the call failed for some reason and the library generated a
+  ///   non-OK status.
+  ///
+  /// \param[in] tag Tag identifying this request.
+  /// \param[out] status To be updated with the operation status.
+  /// \param[out] msg To be filled in with the server's response message.
+  virtual void Finish(R* msg, Status* status, void* tag) = 0;
+};
+
+namespace internal {
+template <class R>
+class ClientAsyncResponseReaderFactory {
+ public:
+  /// Start a call and write the request out if \a start is set.
+  /// \a tag will be notified on \a cq when the call has been started (i.e.
+  /// intitial metadata sent) and \a request has been written out.
+  /// If \a start is not set, the actual call must be initiated by StartCall
+  /// Note that \a context will be used to fill in custom initial metadata
+  /// used to send to the server when starting the call.
+  template <class W>
+  static ClientAsyncResponseReader<R>* Create(
+      ChannelInterface* channel, CompletionQueue* cq,
+      const ::grpc::internal::RpcMethod& method, ClientContext* context,
+      const W& request, bool start) {
+    ::grpc::internal::Call call = channel->CreateCall(method, context, cq);
+    return new (g_core_codegen_interface->grpc_call_arena_alloc(
+        call.call(), sizeof(ClientAsyncResponseReader<R>)))
+        ClientAsyncResponseReader<R>(call, context, request, start);
+  }
+};
+}  // namespace internal
+
+/// Async API for client-side unary RPCs, where the message response
+/// received from the server is of type \a R.
+template <class R>
+class ClientAsyncResponseReader final
+    : public ClientAsyncResponseReaderInterface<R> {
+ public:
+  // always allocated against a call arena, no memory free required
+  static void operator delete(void* ptr, std::size_t size) {
+    assert(size == sizeof(ClientAsyncResponseReader));
+  }
+
+  // This operator should never be called as the memory should be freed as part
+  // of the arena destruction. It only exists to provide a matching operator
+  // delete to the operator new so that some compilers will not complain (see
+  // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
+  // there are no tests catching the compiler warning.
+  static void operator delete(void*, void*) { assert(0); }
+
+  void StartCall() override {
+    assert(!started_);
+    started_ = true;
+    StartCallInternal();
+  }
+
+  /// See \a ClientAsyncResponseReaderInterface::ReadInitialMetadata for
+  /// semantics.
+  ///
+  /// Side effect:
+  ///   - the \a ClientContext associated with this call is updated with
+  ///     possible initial and trailing metadata sent from the server.
+  void ReadInitialMetadata(void* tag) override {
+    assert(started_);
+    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
+
+    single_buf.set_output_tag(tag);
+    single_buf.RecvInitialMetadata(context_);
+    call_.PerformOps(&single_buf);
+    initial_metadata_read_ = true;
+  }
+
+  /// See \a ClientAysncResponseReaderInterface::Finish for semantics.
+  ///
+  /// Side effect:
+  ///   - the \a ClientContext associated with this call is updated with
+  ///     possible initial and trailing metadata sent from the server.
+  void Finish(R* msg, Status* status, void* tag) override {
+    assert(started_);
+    if (initial_metadata_read_) {
+      finish_buf.set_output_tag(tag);
+      finish_buf.RecvMessage(msg);
+      finish_buf.AllowNoMessage();
+      finish_buf.ClientRecvStatus(context_, status);
+      call_.PerformOps(&finish_buf);
+    } else {
+      single_buf.set_output_tag(tag);
+      single_buf.RecvInitialMetadata(context_);
+      single_buf.RecvMessage(msg);
+      single_buf.AllowNoMessage();
+      single_buf.ClientRecvStatus(context_, status);
+      call_.PerformOps(&single_buf);
+    }
+  }
+
+ private:
+  friend class internal::ClientAsyncResponseReaderFactory<R>;
+  ClientContext* const context_;
+  ::grpc::internal::Call call_;
+  bool started_;
+  bool initial_metadata_read_ = false;
+
+  template <class W>
+  ClientAsyncResponseReader(::grpc::internal::Call call, ClientContext* context,
+                            const W& request, bool start)
+      : context_(context), call_(call), started_(start) {
+    // Bind the metadata at time of StartCallInternal but set up the rest here
+    // TODO(ctiller): don't assert
+    GPR_CODEGEN_ASSERT(single_buf.SendMessage(request).ok());
+    single_buf.ClientSendClose();
+    if (start) StartCallInternal();
+  }
+
+  void StartCallInternal() {
+    single_buf.SendInitialMetadata(context_->send_initial_metadata_,
+                                   context_->initial_metadata_flags());
+  }
+
+  // disable operator new
+  static void* operator new(std::size_t size);
+  static void* operator new(std::size_t size, void* p) { return p; }
+
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
+                              ::grpc::internal::CallOpSendMessage,
+                              ::grpc::internal::CallOpClientSendClose,
+                              ::grpc::internal::CallOpRecvInitialMetadata,
+                              ::grpc::internal::CallOpRecvMessage<R>,
+                              ::grpc::internal::CallOpClientRecvStatus>
+      single_buf;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage<R>,
+                              ::grpc::internal::CallOpClientRecvStatus>
+      finish_buf;
+};
+
+/// Async server-side API for handling unary calls, where the single
+/// response message sent to the client is of type \a W.
+template <class W>
+class ServerAsyncResponseWriter final
+    : public internal::ServerAsyncStreamingInterface {
+ public:
+  explicit ServerAsyncResponseWriter(ServerContext* ctx)
+      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
+
+  /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics.
+  ///
+  /// Side effect:
+  ///   The initial metadata that will be sent to the client from this op will
+  ///   be taken from the \a ServerContext associated with the call.
+  ///
+  /// \param[in] tag Tag identifying this request.
+  void SendInitialMetadata(void* tag) override {
+    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
+
+    meta_buf_.set_output_tag(tag);
+    meta_buf_.SendInitialMetadata(ctx_->initial_metadata_,
+                                  ctx_->initial_metadata_flags());
+    if (ctx_->compression_level_set()) {
+      meta_buf_.set_compression_level(ctx_->compression_level());
+    }
+    ctx_->sent_initial_metadata_ = true;
+    call_.PerformOps(&meta_buf_);
+  }
+
+  /// Indicate that the stream is to be finished and request notification
+  /// when the server has sent the appropriate signals to the client to
+  /// end the call. Should not be used concurrently with other operations.
+  ///
+  /// \param[in] tag Tag identifying this request.
+  /// \param[in] status To be sent to the client as the result of the call.
+  /// \param[in] msg Message to be sent to the client.
+  ///
+  /// Side effect:
+  ///   - also sends initial metadata if not already sent (using the
+  ///     \a ServerContext associated with this call).
+  ///
+  /// Note: if \a status has a non-OK code, then \a msg will not be sent,
+  /// and the client will receive only the status with possible trailing
+  /// metadata.
+  void Finish(const W& msg, const Status& status, void* tag) {
+    finish_buf_.set_output_tag(tag);
+    if (!ctx_->sent_initial_metadata_) {
+      finish_buf_.SendInitialMetadata(ctx_->initial_metadata_,
+                                      ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        finish_buf_.set_compression_level(ctx_->compression_level());
+      }
+      ctx_->sent_initial_metadata_ = true;
+    }
+    // The response is dropped if the status is not OK.
+    if (status.ok()) {
+      finish_buf_.ServerSendStatus(ctx_->trailing_metadata_,
+                                   finish_buf_.SendMessage(msg));
+    } else {
+      finish_buf_.ServerSendStatus(ctx_->trailing_metadata_, status);
+    }
+    call_.PerformOps(&finish_buf_);
+  }
+
+  /// Indicate that the stream is to be finished with a non-OK status,
+  /// and request notification for when the server has finished sending the
+  /// appropriate signals to the client to end the call.
+  /// Should not be used concurrently with other operations.
+  ///
+  /// \param[in] tag Tag identifying this request.
+  /// \param[in] status To be sent to the client as the result of the call.
+  ///   - Note: \a status must have a non-OK code.
+  ///
+  /// Side effect:
+  ///   - also sends initial metadata if not already sent (using the
+  ///     \a ServerContext associated with this call).
+  void FinishWithError(const Status& status, void* tag) {
+    GPR_CODEGEN_ASSERT(!status.ok());
+    finish_buf_.set_output_tag(tag);
+    if (!ctx_->sent_initial_metadata_) {
+      finish_buf_.SendInitialMetadata(ctx_->initial_metadata_,
+                                      ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        finish_buf_.set_compression_level(ctx_->compression_level());
+      }
+      ctx_->sent_initial_metadata_ = true;
+    }
+    finish_buf_.ServerSendStatus(ctx_->trailing_metadata_, status);
+    call_.PerformOps(&finish_buf_);
+  }
+
+ private:
+  void BindCall(::grpc::internal::Call* call) override { call_ = *call; }
+
+  ::grpc::internal::Call call_;
+  ServerContext* ctx_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
+      meta_buf_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
+                              ::grpc::internal::CallOpSendMessage,
+                              ::grpc::internal::CallOpServerSendStatus>
+      finish_buf_;
+};
+
+}  // namespace grpc
+
+namespace std {
+template <class R>
+class default_delete<grpc::ClientAsyncResponseReader<R>> {
+ public:
+  void operator()(void* p) {}
+};
+template <class R>
+class default_delete<grpc::ClientAsyncResponseReaderInterface<R>> {
+ public:
+  void operator()(void* p) {}
+};
+}  // namespace std
+
+#endif  // GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_H
diff --git a/include/grpcpp/impl/codegen/byte_buffer.h b/include/grpcpp/impl/codegen/byte_buffer.h
new file mode 100644
index 0000000..8d6a169
--- /dev/null
+++ b/include/grpcpp/impl/codegen/byte_buffer.h
@@ -0,0 +1,157 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_BYTE_BUFFER_H
+#define GRPCPP_IMPL_CODEGEN_BYTE_BUFFER_H
+
+#include <grpc/impl/codegen/byte_buffer.h>
+
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/serialization_traits.h>
+#include <grpcpp/impl/codegen/slice.h>
+#include <grpcpp/impl/codegen/status.h>
+
+#include <vector>
+
+namespace grpc {
+
+namespace internal {
+class CallOpSendMessage;
+template <class R>
+class CallOpRecvMessage;
+class CallOpGenericRecvMessage;
+class MethodHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class RpcMethodHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class ServerStreamingHandler;
+template <class R>
+class DeserializeFuncType;
+}  // namespace internal
+/// A sequence of bytes.
+class ByteBuffer final {
+ public:
+  /// Constuct an empty buffer.
+  ByteBuffer() : buffer_(nullptr) {}
+
+  /// Construct buffer from \a slices, of which there are \a nslices.
+  ByteBuffer(const Slice* slices, size_t nslices);
+
+  /// Constuct a byte buffer by referencing elements of existing buffer
+  /// \a buf. Wrapper of core function grpc_byte_buffer_copy
+  ByteBuffer(const ByteBuffer& buf);
+
+  ~ByteBuffer() {
+    if (buffer_) {
+      g_core_codegen_interface->grpc_byte_buffer_destroy(buffer_);
+    }
+  }
+
+  ByteBuffer& operator=(const ByteBuffer&);
+
+  /// Dump (read) the buffer contents into \a slices.
+  Status Dump(std::vector<Slice>* slices) const;
+
+  /// Remove all data.
+  void Clear() {
+    if (buffer_) {
+      g_core_codegen_interface->grpc_byte_buffer_destroy(buffer_);
+      buffer_ = nullptr;
+    }
+  }
+
+  /// Make a duplicate copy of the internals of this byte
+  /// buffer so that we have our own owned version of it.
+  /// bbuf.Duplicate(); is equivalent to bbuf=bbuf; but is actually readable
+  void Duplicate() {
+    buffer_ = g_core_codegen_interface->grpc_byte_buffer_copy(buffer_);
+  }
+
+  /// Forget underlying byte buffer without destroying
+  /// Use this only for un-owned byte buffers
+  void Release() { buffer_ = nullptr; }
+
+  /// Buffer size in bytes.
+  size_t Length() const;
+
+  /// Swap the state of *this and *other.
+  void Swap(ByteBuffer* other);
+
+  /// Is this ByteBuffer valid?
+  bool Valid() const { return (buffer_ != nullptr); }
+
+ private:
+  friend class SerializationTraits<ByteBuffer, void>;
+  friend class internal::CallOpSendMessage;
+  template <class R>
+  friend class internal::CallOpRecvMessage;
+  friend class internal::CallOpGenericRecvMessage;
+  friend class internal::MethodHandler;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class internal::RpcMethodHandler;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class internal::ServerStreamingHandler;
+  template <class R>
+  friend class internal::DeserializeFuncType;
+
+  grpc_byte_buffer* buffer_;
+
+  // takes ownership
+  void set_buffer(grpc_byte_buffer* buf) {
+    if (buffer_) {
+      Clear();
+    }
+    buffer_ = buf;
+  }
+
+  grpc_byte_buffer* c_buffer() { return buffer_; }
+  grpc_byte_buffer** c_buffer_ptr() { return &buffer_; }
+
+  class ByteBufferPointer {
+   public:
+    ByteBufferPointer(const ByteBuffer* b)
+        : bbuf_(const_cast<ByteBuffer*>(b)) {}
+    operator ByteBuffer*() { return bbuf_; }
+    operator grpc_byte_buffer*() { return bbuf_->buffer_; }
+    operator grpc_byte_buffer**() { return &bbuf_->buffer_; }
+
+   private:
+    ByteBuffer* bbuf_;
+  };
+  ByteBufferPointer bbuf_ptr() const { return ByteBufferPointer(this); }
+};
+
+template <>
+class SerializationTraits<ByteBuffer, void> {
+ public:
+  static Status Deserialize(ByteBuffer* byte_buffer, ByteBuffer* dest) {
+    dest->set_buffer(byte_buffer->buffer_);
+    return Status::OK;
+  }
+  static Status Serialize(const ByteBuffer& source, ByteBuffer* buffer,
+                          bool* own_buffer) {
+    *buffer = source;
+    *own_buffer = true;
+    return Status::OK;
+  }
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_BYTE_BUFFER_H
diff --git a/include/grpcpp/impl/codegen/call.h b/include/grpcpp/impl/codegen/call.h
new file mode 100644
index 0000000..28cc4a9
--- /dev/null
+++ b/include/grpcpp/impl/codegen/call.h
@@ -0,0 +1,694 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_CALL_H
+#define GRPCPP_IMPL_CODEGEN_CALL_H
+
+#include <assert.h>
+#include <cstring>
+#include <functional>
+#include <map>
+#include <memory>
+
+#include <grpcpp/impl/codegen/byte_buffer.h>
+#include <grpcpp/impl/codegen/call_hook.h>
+#include <grpcpp/impl/codegen/client_context.h>
+#include <grpcpp/impl/codegen/completion_queue_tag.h>
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/serialization_traits.h>
+#include <grpcpp/impl/codegen/slice.h>
+#include <grpcpp/impl/codegen/status.h>
+#include <grpcpp/impl/codegen/string_ref.h>
+
+#include <grpc/impl/codegen/atm.h>
+#include <grpc/impl/codegen/compression_types.h>
+#include <grpc/impl/codegen/grpc_types.h>
+
+namespace grpc {
+
+class ByteBuffer;
+class CompletionQueue;
+extern CoreCodegenInterface* g_core_codegen_interface;
+
+namespace internal {
+class Call;
+class CallHook;
+
+const char kBinaryErrorDetailsKey[] = "grpc-status-details-bin";
+
+// TODO(yangg) if the map is changed before we send, the pointers will be a
+// mess. Make sure it does not happen.
+inline grpc_metadata* FillMetadataArray(
+    const std::multimap<grpc::string, grpc::string>& metadata,
+    size_t* metadata_count, const grpc::string& optional_error_details) {
+  *metadata_count = metadata.size() + (optional_error_details.empty() ? 0 : 1);
+  if (*metadata_count == 0) {
+    return nullptr;
+  }
+  grpc_metadata* metadata_array =
+      (grpc_metadata*)(g_core_codegen_interface->gpr_malloc(
+          (*metadata_count) * sizeof(grpc_metadata)));
+  size_t i = 0;
+  for (auto iter = metadata.cbegin(); iter != metadata.cend(); ++iter, ++i) {
+    metadata_array[i].key = SliceReferencingString(iter->first);
+    metadata_array[i].value = SliceReferencingString(iter->second);
+  }
+  if (!optional_error_details.empty()) {
+    metadata_array[i].key =
+        g_core_codegen_interface->grpc_slice_from_static_buffer(
+            kBinaryErrorDetailsKey, sizeof(kBinaryErrorDetailsKey) - 1);
+    metadata_array[i].value = SliceReferencingString(optional_error_details);
+  }
+  return metadata_array;
+}
+}  // namespace internal
+
+/// Per-message write options.
+class WriteOptions {
+ public:
+  WriteOptions() : flags_(0), last_message_(false) {}
+  WriteOptions(const WriteOptions& other)
+      : flags_(other.flags_), last_message_(other.last_message_) {}
+
+  /// Clear all flags.
+  inline void Clear() { flags_ = 0; }
+
+  /// Returns raw flags bitset.
+  inline uint32_t flags() const { return flags_; }
+
+  /// Sets flag for the disabling of compression for the next message write.
+  ///
+  /// \sa GRPC_WRITE_NO_COMPRESS
+  inline WriteOptions& set_no_compression() {
+    SetBit(GRPC_WRITE_NO_COMPRESS);
+    return *this;
+  }
+
+  /// Clears flag for the disabling of compression for the next message write.
+  ///
+  /// \sa GRPC_WRITE_NO_COMPRESS
+  inline WriteOptions& clear_no_compression() {
+    ClearBit(GRPC_WRITE_NO_COMPRESS);
+    return *this;
+  }
+
+  /// Get value for the flag indicating whether compression for the next
+  /// message write is forcefully disabled.
+  ///
+  /// \sa GRPC_WRITE_NO_COMPRESS
+  inline bool get_no_compression() const {
+    return GetBit(GRPC_WRITE_NO_COMPRESS);
+  }
+
+  /// Sets flag indicating that the write may be buffered and need not go out on
+  /// the wire immediately.
+  ///
+  /// \sa GRPC_WRITE_BUFFER_HINT
+  inline WriteOptions& set_buffer_hint() {
+    SetBit(GRPC_WRITE_BUFFER_HINT);
+    return *this;
+  }
+
+  /// Clears flag indicating that the write may be buffered and need not go out
+  /// on the wire immediately.
+  ///
+  /// \sa GRPC_WRITE_BUFFER_HINT
+  inline WriteOptions& clear_buffer_hint() {
+    ClearBit(GRPC_WRITE_BUFFER_HINT);
+    return *this;
+  }
+
+  /// Get value for the flag indicating that the write may be buffered and need
+  /// not go out on the wire immediately.
+  ///
+  /// \sa GRPC_WRITE_BUFFER_HINT
+  inline bool get_buffer_hint() const { return GetBit(GRPC_WRITE_BUFFER_HINT); }
+
+  /// corked bit: aliases set_buffer_hint currently, with the intent that
+  /// set_buffer_hint will be removed in the future
+  inline WriteOptions& set_corked() {
+    SetBit(GRPC_WRITE_BUFFER_HINT);
+    return *this;
+  }
+
+  inline WriteOptions& clear_corked() {
+    ClearBit(GRPC_WRITE_BUFFER_HINT);
+    return *this;
+  }
+
+  inline bool is_corked() const { return GetBit(GRPC_WRITE_BUFFER_HINT); }
+
+  /// last-message bit: indicates this is the last message in a stream
+  /// client-side:  makes Write the equivalent of performing Write, WritesDone
+  /// in a single step
+  /// server-side:  hold the Write until the service handler returns (sync api)
+  /// or until Finish is called (async api)
+  inline WriteOptions& set_last_message() {
+    last_message_ = true;
+    return *this;
+  }
+
+  /// Clears flag indicating that this is the last message in a stream,
+  /// disabling coalescing.
+  inline WriteOptions& clear_last_message() {
+    last_message_ = false;
+    return *this;
+  }
+
+  /// Guarantee that all bytes have been written to the wire before completing
+  /// this write (usually writes are completed when they pass flow control)
+  inline WriteOptions& set_write_through() {
+    SetBit(GRPC_WRITE_THROUGH);
+    return *this;
+  }
+
+  inline bool is_write_through() const { return GetBit(GRPC_WRITE_THROUGH); }
+
+  /// Get value for the flag indicating that this is the last message, and
+  /// should be coalesced with trailing metadata.
+  ///
+  /// \sa GRPC_WRITE_LAST_MESSAGE
+  bool is_last_message() const { return last_message_; }
+
+  WriteOptions& operator=(const WriteOptions& rhs) {
+    flags_ = rhs.flags_;
+    return *this;
+  }
+
+ private:
+  void SetBit(const uint32_t mask) { flags_ |= mask; }
+
+  void ClearBit(const uint32_t mask) { flags_ &= ~mask; }
+
+  bool GetBit(const uint32_t mask) const { return (flags_ & mask) != 0; }
+
+  uint32_t flags_;
+  bool last_message_;
+};
+
+namespace internal {
+/// Default argument for CallOpSet. I is unused by the class, but can be
+/// used for generating multiple names for the same thing.
+template <int I>
+class CallNoOp {
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {}
+  void FinishOp(bool* status) {}
+};
+
+class CallOpSendInitialMetadata {
+ public:
+  CallOpSendInitialMetadata() : send_(false) {
+    maybe_compression_level_.is_set = false;
+  }
+
+  void SendInitialMetadata(
+      const std::multimap<grpc::string, grpc::string>& metadata,
+      uint32_t flags) {
+    maybe_compression_level_.is_set = false;
+    send_ = true;
+    flags_ = flags;
+    initial_metadata_ =
+        FillMetadataArray(metadata, &initial_metadata_count_, "");
+  }
+
+  void set_compression_level(grpc_compression_level level) {
+    maybe_compression_level_.is_set = true;
+    maybe_compression_level_.level = level;
+  }
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (!send_) return;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_SEND_INITIAL_METADATA;
+    op->flags = flags_;
+    op->reserved = NULL;
+    op->data.send_initial_metadata.count = initial_metadata_count_;
+    op->data.send_initial_metadata.metadata = initial_metadata_;
+    op->data.send_initial_metadata.maybe_compression_level.is_set =
+        maybe_compression_level_.is_set;
+    if (maybe_compression_level_.is_set) {
+      op->data.send_initial_metadata.maybe_compression_level.level =
+          maybe_compression_level_.level;
+    }
+  }
+  void FinishOp(bool* status) {
+    if (!send_) return;
+    g_core_codegen_interface->gpr_free(initial_metadata_);
+    send_ = false;
+  }
+
+  bool send_;
+  uint32_t flags_;
+  size_t initial_metadata_count_;
+  grpc_metadata* initial_metadata_;
+  struct {
+    bool is_set;
+    grpc_compression_level level;
+  } maybe_compression_level_;
+};
+
+class CallOpSendMessage {
+ public:
+  CallOpSendMessage() : send_buf_() {}
+
+  /// Send \a message using \a options for the write. The \a options are cleared
+  /// after use.
+  template <class M>
+  Status SendMessage(const M& message,
+                     WriteOptions options) GRPC_MUST_USE_RESULT;
+
+  template <class M>
+  Status SendMessage(const M& message) GRPC_MUST_USE_RESULT;
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (!send_buf_.Valid()) return;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_SEND_MESSAGE;
+    op->flags = write_options_.flags();
+    op->reserved = NULL;
+    op->data.send_message.send_message = send_buf_.c_buffer();
+    // Flags are per-message: clear them after use.
+    write_options_.Clear();
+  }
+  void FinishOp(bool* status) { send_buf_.Clear(); }
+
+ private:
+  ByteBuffer send_buf_;
+  WriteOptions write_options_;
+};
+
+template <class M>
+Status CallOpSendMessage::SendMessage(const M& message, WriteOptions options) {
+  write_options_ = options;
+  bool own_buf;
+  // TODO(vjpai): Remove the void below when possible
+  // The void in the template parameter below should not be needed
+  // (since it should be implicit) but is needed due to an observed
+  // difference in behavior between clang and gcc for certain internal users
+  Status result = SerializationTraits<M, void>::Serialize(
+      message, send_buf_.bbuf_ptr(), &own_buf);
+  if (!own_buf) {
+    send_buf_.Duplicate();
+  }
+  return result;
+}
+
+template <class M>
+Status CallOpSendMessage::SendMessage(const M& message) {
+  return SendMessage(message, WriteOptions());
+}
+
+template <class R>
+class CallOpRecvMessage {
+ public:
+  CallOpRecvMessage()
+      : got_message(false),
+        message_(nullptr),
+        allow_not_getting_message_(false) {}
+
+  void RecvMessage(R* message) { message_ = message; }
+
+  // Do not change status if no message is received.
+  void AllowNoMessage() { allow_not_getting_message_ = true; }
+
+  bool got_message;
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (message_ == nullptr) return;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_RECV_MESSAGE;
+    op->flags = 0;
+    op->reserved = NULL;
+    op->data.recv_message.recv_message = recv_buf_.c_buffer_ptr();
+  }
+
+  void FinishOp(bool* status) {
+    if (message_ == nullptr) return;
+    if (recv_buf_.Valid()) {
+      if (*status) {
+        got_message = *status =
+            SerializationTraits<R>::Deserialize(recv_buf_.bbuf_ptr(), message_)
+                .ok();
+        recv_buf_.Release();
+      } else {
+        got_message = false;
+        recv_buf_.Clear();
+      }
+    } else {
+      got_message = false;
+      if (!allow_not_getting_message_) {
+        *status = false;
+      }
+    }
+    message_ = nullptr;
+  }
+
+ private:
+  R* message_;
+  ByteBuffer recv_buf_;
+  bool allow_not_getting_message_;
+};
+
+class DeserializeFunc {
+ public:
+  virtual Status Deserialize(ByteBuffer* buf) = 0;
+  virtual ~DeserializeFunc() {}
+};
+
+template <class R>
+class DeserializeFuncType final : public DeserializeFunc {
+ public:
+  DeserializeFuncType(R* message) : message_(message) {}
+  Status Deserialize(ByteBuffer* buf) override {
+    return SerializationTraits<R>::Deserialize(buf->bbuf_ptr(), message_);
+  }
+
+  ~DeserializeFuncType() override {}
+
+ private:
+  R* message_;  // Not a managed pointer because management is external to this
+};
+
+class CallOpGenericRecvMessage {
+ public:
+  CallOpGenericRecvMessage()
+      : got_message(false), allow_not_getting_message_(false) {}
+
+  template <class R>
+  void RecvMessage(R* message) {
+    // Use an explicit base class pointer to avoid resolution error in the
+    // following unique_ptr::reset for some old implementations.
+    DeserializeFunc* func = new DeserializeFuncType<R>(message);
+    deserialize_.reset(func);
+  }
+
+  // Do not change status if no message is received.
+  void AllowNoMessage() { allow_not_getting_message_ = true; }
+
+  bool got_message;
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (!deserialize_) return;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_RECV_MESSAGE;
+    op->flags = 0;
+    op->reserved = NULL;
+    op->data.recv_message.recv_message = recv_buf_.c_buffer_ptr();
+  }
+
+  void FinishOp(bool* status) {
+    if (!deserialize_) return;
+    if (recv_buf_.Valid()) {
+      if (*status) {
+        got_message = true;
+        *status = deserialize_->Deserialize(&recv_buf_).ok();
+        recv_buf_.Release();
+      } else {
+        got_message = false;
+        recv_buf_.Clear();
+      }
+    } else {
+      got_message = false;
+      if (!allow_not_getting_message_) {
+        *status = false;
+      }
+    }
+    deserialize_.reset();
+  }
+
+ private:
+  std::unique_ptr<DeserializeFunc> deserialize_;
+  ByteBuffer recv_buf_;
+  bool allow_not_getting_message_;
+};
+
+class CallOpClientSendClose {
+ public:
+  CallOpClientSendClose() : send_(false) {}
+
+  void ClientSendClose() { send_ = true; }
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (!send_) return;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+    op->flags = 0;
+    op->reserved = NULL;
+  }
+  void FinishOp(bool* status) { send_ = false; }
+
+ private:
+  bool send_;
+};
+
+class CallOpServerSendStatus {
+ public:
+  CallOpServerSendStatus() : send_status_available_(false) {}
+
+  void ServerSendStatus(
+      const std::multimap<grpc::string, grpc::string>& trailing_metadata,
+      const Status& status) {
+    send_error_details_ = status.error_details();
+    trailing_metadata_ = FillMetadataArray(
+        trailing_metadata, &trailing_metadata_count_, send_error_details_);
+    send_status_available_ = true;
+    send_status_code_ = static_cast<grpc_status_code>(status.error_code());
+    send_error_message_ = status.error_message();
+  }
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (!send_status_available_) return;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+    op->data.send_status_from_server.trailing_metadata_count =
+        trailing_metadata_count_;
+    op->data.send_status_from_server.trailing_metadata = trailing_metadata_;
+    op->data.send_status_from_server.status = send_status_code_;
+    error_message_slice_ = SliceReferencingString(send_error_message_);
+    op->data.send_status_from_server.status_details =
+        send_error_message_.empty() ? nullptr : &error_message_slice_;
+    op->flags = 0;
+    op->reserved = NULL;
+  }
+
+  void FinishOp(bool* status) {
+    if (!send_status_available_) return;
+    g_core_codegen_interface->gpr_free(trailing_metadata_);
+    send_status_available_ = false;
+  }
+
+ private:
+  bool send_status_available_;
+  grpc_status_code send_status_code_;
+  grpc::string send_error_details_;
+  grpc::string send_error_message_;
+  size_t trailing_metadata_count_;
+  grpc_metadata* trailing_metadata_;
+  grpc_slice error_message_slice_;
+};
+
+class CallOpRecvInitialMetadata {
+ public:
+  CallOpRecvInitialMetadata() : metadata_map_(nullptr) {}
+
+  void RecvInitialMetadata(ClientContext* context) {
+    context->initial_metadata_received_ = true;
+    metadata_map_ = &context->recv_initial_metadata_;
+  }
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (metadata_map_ == nullptr) return;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_RECV_INITIAL_METADATA;
+    op->data.recv_initial_metadata.recv_initial_metadata = metadata_map_->arr();
+    op->flags = 0;
+    op->reserved = NULL;
+  }
+
+  void FinishOp(bool* status) {
+    if (metadata_map_ == nullptr) return;
+    metadata_map_->FillMap();
+    metadata_map_ = nullptr;
+  }
+
+ private:
+  MetadataMap* metadata_map_;
+};
+
+class CallOpClientRecvStatus {
+ public:
+  CallOpClientRecvStatus()
+      : recv_status_(nullptr), debug_error_string_(nullptr) {}
+
+  void ClientRecvStatus(ClientContext* context, Status* status) {
+    client_context_ = context;
+    metadata_map_ = &client_context_->trailing_metadata_;
+    recv_status_ = status;
+    error_message_ = g_core_codegen_interface->grpc_empty_slice();
+  }
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (recv_status_ == nullptr) return;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+    op->data.recv_status_on_client.trailing_metadata = metadata_map_->arr();
+    op->data.recv_status_on_client.status = &status_code_;
+    op->data.recv_status_on_client.status_details = &error_message_;
+    op->data.recv_status_on_client.error_string = &debug_error_string_;
+    op->flags = 0;
+    op->reserved = NULL;
+  }
+
+  void FinishOp(bool* status) {
+    if (recv_status_ == nullptr) return;
+    metadata_map_->FillMap();
+    grpc::string binary_error_details;
+    auto iter = metadata_map_->map()->find(kBinaryErrorDetailsKey);
+    if (iter != metadata_map_->map()->end()) {
+      binary_error_details =
+          grpc::string(iter->second.begin(), iter->second.length());
+    }
+    *recv_status_ = Status(static_cast<StatusCode>(status_code_),
+                           grpc::string(GRPC_SLICE_START_PTR(error_message_),
+                                        GRPC_SLICE_END_PTR(error_message_)),
+                           binary_error_details);
+    client_context_->set_debug_error_string(
+        debug_error_string_ != nullptr ? debug_error_string_ : "");
+    g_core_codegen_interface->grpc_slice_unref(error_message_);
+    if (debug_error_string_ != nullptr) {
+      g_core_codegen_interface->gpr_free((void*)debug_error_string_);
+    }
+    recv_status_ = nullptr;
+  }
+
+ private:
+  ClientContext* client_context_;
+  MetadataMap* metadata_map_;
+  Status* recv_status_;
+  const char* debug_error_string_;
+  grpc_status_code status_code_;
+  grpc_slice error_message_;
+};
+
+/// An abstract collection of call ops, used to generate the
+/// grpc_call_op structure to pass down to the lower layers,
+/// and as it is-a CompletionQueueTag, also massages the final
+/// completion into the correct form for consumption in the C++
+/// API.
+class CallOpSetInterface : public CompletionQueueTag {
+ public:
+  /// Fills in grpc_op, starting from ops[*nops] and moving
+  /// upwards.
+  virtual void FillOps(grpc_call* call, grpc_op* ops, size_t* nops) = 0;
+};
+
+/// Primary implementation of CallOpSetInterface.
+/// Since we cannot use variadic templates, we declare slots up to
+/// the maximum count of ops we'll need in a set. We leverage the
+/// empty base class optimization to slim this class (especially
+/// when there are many unused slots used). To avoid duplicate base classes,
+/// the template parmeter for CallNoOp is varied by argument position.
+template <class Op1 = CallNoOp<1>, class Op2 = CallNoOp<2>,
+          class Op3 = CallNoOp<3>, class Op4 = CallNoOp<4>,
+          class Op5 = CallNoOp<5>, class Op6 = CallNoOp<6>>
+class CallOpSet : public CallOpSetInterface,
+                  public Op1,
+                  public Op2,
+                  public Op3,
+                  public Op4,
+                  public Op5,
+                  public Op6 {
+ public:
+  CallOpSet() : return_tag_(this), call_(nullptr) {}
+  void FillOps(grpc_call* call, grpc_op* ops, size_t* nops) override {
+    this->Op1::AddOp(ops, nops);
+    this->Op2::AddOp(ops, nops);
+    this->Op3::AddOp(ops, nops);
+    this->Op4::AddOp(ops, nops);
+    this->Op5::AddOp(ops, nops);
+    this->Op6::AddOp(ops, nops);
+    g_core_codegen_interface->grpc_call_ref(call);
+    call_ = call;
+  }
+
+  bool FinalizeResult(void** tag, bool* status) override {
+    this->Op1::FinishOp(status);
+    this->Op2::FinishOp(status);
+    this->Op3::FinishOp(status);
+    this->Op4::FinishOp(status);
+    this->Op5::FinishOp(status);
+    this->Op6::FinishOp(status);
+    *tag = return_tag_;
+
+    g_core_codegen_interface->grpc_call_unref(call_);
+    return true;
+  }
+
+  void set_output_tag(void* return_tag) { return_tag_ = return_tag; }
+
+ private:
+  void* return_tag_;
+  grpc_call* call_;
+};
+
+/// Straightforward wrapping of the C call object
+class Call final {
+ public:
+  /** call is owned by the caller */
+  Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq)
+      : call_hook_(call_hook),
+        cq_(cq),
+        call_(call),
+        max_receive_message_size_(-1) {}
+
+  Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq,
+       int max_receive_message_size)
+      : call_hook_(call_hook),
+        cq_(cq),
+        call_(call),
+        max_receive_message_size_(max_receive_message_size) {}
+
+  void PerformOps(CallOpSetInterface* ops) {
+    call_hook_->PerformOpsOnCall(ops, this);
+  }
+
+  grpc_call* call() const { return call_; }
+  CompletionQueue* cq() const { return cq_; }
+
+  int max_receive_message_size() const { return max_receive_message_size_; }
+
+ private:
+  CallHook* call_hook_;
+  CompletionQueue* cq_;
+  grpc_call* call_;
+  int max_receive_message_size_;
+};
+}  // namespace internal
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_CALL_H
diff --git a/include/grpcpp/impl/codegen/call_hook.h b/include/grpcpp/impl/codegen/call_hook.h
new file mode 100644
index 0000000..4f7d370
--- /dev/null
+++ b/include/grpcpp/impl/codegen/call_hook.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_CALL_HOOK_H
+#define GRPCPP_IMPL_CODEGEN_CALL_HOOK_H
+
+namespace grpc {
+
+namespace internal {
+class CallOpSetInterface;
+class Call;
+
+/// This is an interface that Channel and Server implement to allow them to hook
+/// performing ops.
+class CallHook {
+ public:
+  virtual ~CallHook() {}
+  virtual void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) = 0;
+};
+}  // namespace internal
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_CALL_HOOK_H
diff --git a/include/grpcpp/impl/codegen/channel_interface.h b/include/grpcpp/impl/codegen/channel_interface.h
new file mode 100644
index 0000000..ec1c6c2
--- /dev/null
+++ b/include/grpcpp/impl/codegen/channel_interface.h
@@ -0,0 +1,121 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_CHANNEL_INTERFACE_H
+#define GRPCPP_IMPL_CODEGEN_CHANNEL_INTERFACE_H
+
+#include <grpc/impl/codegen/connectivity_state.h>
+#include <grpcpp/impl/codegen/status.h>
+#include <grpcpp/impl/codegen/time.h>
+
+namespace grpc {
+class ChannelInterface;
+class ClientContext;
+class CompletionQueue;
+
+template <class R>
+class ClientReader;
+template <class W>
+class ClientWriter;
+template <class W, class R>
+class ClientReaderWriter;
+
+namespace internal {
+class Call;
+class CallOpSetInterface;
+class RpcMethod;
+template <class InputMessage, class OutputMessage>
+class BlockingUnaryCallImpl;
+template <class R>
+class ClientAsyncReaderFactory;
+template <class W>
+class ClientAsyncWriterFactory;
+template <class W, class R>
+class ClientAsyncReaderWriterFactory;
+template <class R>
+class ClientAsyncResponseReaderFactory;
+}  // namespace internal
+
+/// Codegen interface for \a grpc::Channel.
+class ChannelInterface {
+ public:
+  virtual ~ChannelInterface() {}
+  /// Get the current channel state. If the channel is in IDLE and
+  /// \a try_to_connect is set to true, try to connect.
+  virtual grpc_connectivity_state GetState(bool try_to_connect) = 0;
+
+  /// Return the \a tag on \a cq when the channel state is changed or \a
+  /// deadline expires. \a GetState needs to called to get the current state.
+  template <typename T>
+  void NotifyOnStateChange(grpc_connectivity_state last_observed, T deadline,
+                           CompletionQueue* cq, void* tag) {
+    TimePoint<T> deadline_tp(deadline);
+    NotifyOnStateChangeImpl(last_observed, deadline_tp.raw_time(), cq, tag);
+  }
+
+  /// Blocking wait for channel state change or \a deadline expiration.
+  /// \a GetState needs to called to get the current state.
+  template <typename T>
+  bool WaitForStateChange(grpc_connectivity_state last_observed, T deadline) {
+    TimePoint<T> deadline_tp(deadline);
+    return WaitForStateChangeImpl(last_observed, deadline_tp.raw_time());
+  }
+
+  /// Wait for this channel to be connected
+  template <typename T>
+  bool WaitForConnected(T deadline) {
+    grpc_connectivity_state state;
+    while ((state = GetState(true)) != GRPC_CHANNEL_READY) {
+      if (!WaitForStateChange(state, deadline)) return false;
+    }
+    return true;
+  }
+
+ private:
+  template <class R>
+  friend class ::grpc::ClientReader;
+  template <class W>
+  friend class ::grpc::ClientWriter;
+  template <class W, class R>
+  friend class ::grpc::ClientReaderWriter;
+  template <class R>
+  friend class ::grpc::internal::ClientAsyncReaderFactory;
+  template <class W>
+  friend class ::grpc::internal::ClientAsyncWriterFactory;
+  template <class W, class R>
+  friend class ::grpc::internal::ClientAsyncReaderWriterFactory;
+  template <class R>
+  friend class ::grpc::internal::ClientAsyncResponseReaderFactory;
+  template <class InputMessage, class OutputMessage>
+  friend class ::grpc::internal::BlockingUnaryCallImpl;
+  friend class ::grpc::internal::RpcMethod;
+  virtual internal::Call CreateCall(const internal::RpcMethod& method,
+                                    ClientContext* context,
+                                    CompletionQueue* cq) = 0;
+  virtual void PerformOpsOnCall(internal::CallOpSetInterface* ops,
+                                internal::Call* call) = 0;
+  virtual void* RegisterMethod(const char* method) = 0;
+  virtual void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
+                                       gpr_timespec deadline,
+                                       CompletionQueue* cq, void* tag) = 0;
+  virtual bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
+                                      gpr_timespec deadline) = 0;
+};
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_CHANNEL_INTERFACE_H
diff --git a/include/grpcpp/impl/codegen/client_context.h b/include/grpcpp/impl/codegen/client_context.h
new file mode 100644
index 0000000..9dda4c7
--- /dev/null
+++ b/include/grpcpp/impl/codegen/client_context.h
@@ -0,0 +1,442 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 ClientContext allows the person implementing a service client to:
+///
+/// - Add custom metadata key-value pairs that will propagated to the server
+/// side.
+/// - Control call settings such as compression and authentication.
+/// - Initial and trailing metadata coming from the server.
+/// - Get performance metrics (ie, census).
+///
+/// Context settings are only relevant to the call they are invoked with, that
+/// is to say, they aren't sticky. Some of these settings, such as the
+/// compression options, can be made persistent at channel construction time
+/// (see \a grpc::CreateCustomChannel).
+///
+/// \warning ClientContext instances should \em not be reused across rpcs.
+
+#ifndef GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_H
+#define GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_H
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <string>
+
+#include <grpc/impl/codegen/compression_types.h>
+#include <grpc/impl/codegen/propagation_bits.h>
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/create_auth_context.h>
+#include <grpcpp/impl/codegen/metadata_map.h>
+#include <grpcpp/impl/codegen/security/auth_context.h>
+#include <grpcpp/impl/codegen/slice.h>
+#include <grpcpp/impl/codegen/status.h>
+#include <grpcpp/impl/codegen/string_ref.h>
+#include <grpcpp/impl/codegen/time.h>
+
+struct census_context;
+struct grpc_call;
+
+namespace grpc {
+
+class Channel;
+class ChannelInterface;
+class CompletionQueue;
+class CallCredentials;
+class ClientContext;
+
+namespace internal {
+class RpcMethod;
+class CallOpClientRecvStatus;
+class CallOpRecvInitialMetadata;
+template <class InputMessage, class OutputMessage>
+class BlockingUnaryCallImpl;
+}  // namespace internal
+
+template <class R>
+class ClientReader;
+template <class W>
+class ClientWriter;
+template <class W, class R>
+class ClientReaderWriter;
+template <class R>
+class ClientAsyncReader;
+template <class W>
+class ClientAsyncWriter;
+template <class W, class R>
+class ClientAsyncReaderWriter;
+template <class R>
+class ClientAsyncResponseReader;
+class ServerContext;
+
+/// Options for \a ClientContext::FromServerContext specifying which traits from
+/// the \a ServerContext to propagate (copy) from it into a new \a
+/// ClientContext.
+///
+/// \see ClientContext::FromServerContext
+class PropagationOptions {
+ public:
+  PropagationOptions() : propagate_(GRPC_PROPAGATE_DEFAULTS) {}
+
+  PropagationOptions& enable_deadline_propagation() {
+    propagate_ |= GRPC_PROPAGATE_DEADLINE;
+    return *this;
+  }
+
+  PropagationOptions& disable_deadline_propagation() {
+    propagate_ &= ~GRPC_PROPAGATE_DEADLINE;
+    return *this;
+  }
+
+  PropagationOptions& enable_census_stats_propagation() {
+    propagate_ |= GRPC_PROPAGATE_CENSUS_STATS_CONTEXT;
+    return *this;
+  }
+
+  PropagationOptions& disable_census_stats_propagation() {
+    propagate_ &= ~GRPC_PROPAGATE_CENSUS_STATS_CONTEXT;
+    return *this;
+  }
+
+  PropagationOptions& enable_census_tracing_propagation() {
+    propagate_ |= GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT;
+    return *this;
+  }
+
+  PropagationOptions& disable_census_tracing_propagation() {
+    propagate_ &= ~GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT;
+    return *this;
+  }
+
+  PropagationOptions& enable_cancellation_propagation() {
+    propagate_ |= GRPC_PROPAGATE_CANCELLATION;
+    return *this;
+  }
+
+  PropagationOptions& disable_cancellation_propagation() {
+    propagate_ &= ~GRPC_PROPAGATE_CANCELLATION;
+    return *this;
+  }
+
+  uint32_t c_bitmask() const { return propagate_; }
+
+ private:
+  uint32_t propagate_;
+};
+
+namespace testing {
+class InteropClientContextInspector;
+}  // namespace testing
+
+/// A ClientContext allows the person implementing a service client to:
+///
+/// - Add custom metadata key-value pairs that will propagated to the server
+///   side.
+/// - Control call settings such as compression and authentication.
+/// - Initial and trailing metadata coming from the server.
+/// - Get performance metrics (ie, census).
+///
+/// Context settings are only relevant to the call they are invoked with, that
+/// is to say, they aren't sticky. Some of these settings, such as the
+/// compression options, can be made persistent at channel construction time
+/// (see \a grpc::CreateCustomChannel).
+///
+/// \warning ClientContext instances should \em not be reused across rpcs.
+class ClientContext {
+ public:
+  ClientContext();
+  ~ClientContext();
+
+  /// Create a new \a ClientContext as a child of an incoming server call,
+  /// according to \a options (\see PropagationOptions).
+  ///
+  /// \param server_context The source server context to use as the basis for
+  /// constructing the client context.
+  /// \param options The options controlling what to copy from the \a
+  /// server_context.
+  ///
+  /// \return A newly constructed \a ClientContext instance based on \a
+  /// server_context, with traits propagated (copied) according to \a options.
+  static std::unique_ptr<ClientContext> FromServerContext(
+      const ServerContext& server_context,
+      PropagationOptions options = PropagationOptions());
+
+  /// Add the (\a meta_key, \a meta_value) pair to the metadata associated with
+  /// a client call. These are made available at the server side by the \a
+  /// grpc::ServerContext::client_metadata() method.
+  ///
+  /// \warning This method should only be called before invoking the rpc.
+  ///
+  /// \param meta_key The metadata key. If \a meta_value is binary data, it must
+  /// end in "-bin".
+  /// \param meta_value The metadata value. If its value is binary, the key name
+  /// must end in "-bin".
+  void AddMetadata(const grpc::string& meta_key,
+                   const grpc::string& meta_value);
+
+  /// Return a collection of initial metadata key-value pairs. Note that keys
+  /// may happen more than once (ie, a \a std::multimap is returned).
+  ///
+  /// \warning This method should only be called after initial metadata has been
+  /// received. For streaming calls, see \a
+  /// ClientReaderInterface::WaitForInitialMetadata().
+  ///
+  /// \return A multimap of initial metadata key-value pairs from the server.
+  const std::multimap<grpc::string_ref, grpc::string_ref>&
+  GetServerInitialMetadata() const {
+    GPR_CODEGEN_ASSERT(initial_metadata_received_);
+    return *recv_initial_metadata_.map();
+  }
+
+  /// Return a collection of trailing metadata key-value pairs. Note that keys
+  /// may happen more than once (ie, a \a std::multimap is returned).
+  ///
+  /// \warning This method is only callable once the stream has finished.
+  ///
+  /// \return A multimap of metadata trailing key-value pairs from the server.
+  const std::multimap<grpc::string_ref, grpc::string_ref>&
+  GetServerTrailingMetadata() const {
+    // TODO(yangg) check finished
+    return *trailing_metadata_.map();
+  }
+
+  /// Set the deadline for the client call.
+  ///
+  /// \warning This method should only be called before invoking the rpc.
+  ///
+  /// \param deadline the deadline for the client call. Units are determined by
+  /// the type used.
+  template <typename T>
+  void set_deadline(const T& deadline) {
+    TimePoint<T> deadline_tp(deadline);
+    deadline_ = deadline_tp.raw_time();
+  }
+
+  /// EXPERIMENTAL: Indicate that this request is idempotent.
+  /// By default, RPCs are assumed to <i>not</i> be idempotent.
+  ///
+  /// If true, the gRPC library assumes that it's safe to initiate
+  /// this RPC multiple times.
+  void set_idempotent(bool idempotent) { idempotent_ = idempotent; }
+
+  /// EXPERIMENTAL: Set this request to be cacheable.
+  /// If set, grpc is free to use the HTTP GET verb for sending the request,
+  /// with the possibility of receiving a cached response.
+  void set_cacheable(bool cacheable) { cacheable_ = cacheable; }
+
+  /// EXPERIMENTAL: Trigger wait-for-ready or not on this request.
+  /// See https://github.com/grpc/grpc/blob/master/doc/wait-for-ready.md.
+  /// If set, if an RPC is made when a channel's connectivity state is
+  /// TRANSIENT_FAILURE or CONNECTING, the call will not "fail fast",
+  /// and the channel will wait until the channel is READY before making the
+  /// call.
+  void set_wait_for_ready(bool wait_for_ready) {
+    wait_for_ready_ = wait_for_ready;
+    wait_for_ready_explicitly_set_ = true;
+  }
+
+  /// DEPRECATED: Use set_wait_for_ready() instead.
+  void set_fail_fast(bool fail_fast) { set_wait_for_ready(!fail_fast); }
+
+  /// Return the deadline for the client call.
+  std::chrono::system_clock::time_point deadline() const {
+    return Timespec2Timepoint(deadline_);
+  }
+
+  /// Return a \a gpr_timespec representation of the client call's deadline.
+  gpr_timespec raw_deadline() const { return deadline_; }
+
+  /// Set the per call authority header (see
+  /// https://tools.ietf.org/html/rfc7540#section-8.1.2.3).
+  void set_authority(const grpc::string& authority) { authority_ = authority; }
+
+  /// Return the authentication context for this client call.
+  ///
+  /// \see grpc::AuthContext.
+  std::shared_ptr<const AuthContext> auth_context() const {
+    if (auth_context_.get() == nullptr) {
+      auth_context_ = CreateAuthContext(call_);
+    }
+    return auth_context_;
+  }
+
+  /// Set credentials for the client call.
+  ///
+  /// A credentials object encapsulates all the state needed by a client to
+  /// authenticate with a server and make various assertions, e.g., about the
+  /// client’s identity, role, or whether it is authorized to make a particular
+  /// call.
+  ///
+  /// \see  https://grpc.io/docs/guides/auth.html
+  void set_credentials(const std::shared_ptr<CallCredentials>& creds) {
+    creds_ = creds;
+  }
+
+  /// Return the compression algorithm the client call will request be used.
+  /// Note that the gRPC runtime may decide to ignore this request, for example,
+  /// due to resource constraints.
+  grpc_compression_algorithm compression_algorithm() const {
+    return compression_algorithm_;
+  }
+
+  /// Set \a algorithm to be the compression algorithm used for the client call.
+  ///
+  /// \param algorithm The compression algorithm used for the client call.
+  void set_compression_algorithm(grpc_compression_algorithm algorithm);
+
+  /// Flag whether the initial metadata should be \a corked
+  ///
+  /// If \a corked is true, then the initial metadata will be coalesced with the
+  /// write of first message in the stream. As a result, any tag set for the
+  /// initial metadata operation (starting a client-streaming or bidi-streaming
+  /// RPC) will not actually be sent to the completion queue or delivered
+  /// via Next.
+  ///
+  /// \param corked The flag indicating whether the initial metadata is to be
+  /// corked or not.
+  void set_initial_metadata_corked(bool corked) {
+    initial_metadata_corked_ = corked;
+  }
+
+  /// Return the peer uri in a string.
+  ///
+  /// \warning This value is never authenticated or subject to any security
+  /// related code. It must not be used for any authentication related
+  /// functionality. Instead, use auth_context.
+  ///
+  /// \return The call's peer URI.
+  grpc::string peer() const;
+
+  /// Get and set census context.
+  void set_census_context(struct census_context* ccp) { census_context_ = ccp; }
+  struct census_context* census_context() const {
+    return census_context_;
+  }
+
+  /// Send a best-effort out-of-band cancel on the call associated with
+  /// this client context.  The call could be in any stage; e.g., if it is
+  /// already finished, it may still return success.
+  ///
+  /// There is no guarantee the call will be cancelled.
+  ///
+  /// Note that TryCancel() does not change any of the tags that are pending
+  /// on the completion queue. All pending tags will still be delivered
+  /// (though their ok result may reflect the effect of cancellation).
+  void TryCancel();
+
+  /// Global Callbacks
+  ///
+  /// Can be set exactly once per application to install hooks whenever
+  /// a client context is constructed and destructed.
+  class GlobalCallbacks {
+   public:
+    virtual ~GlobalCallbacks() {}
+    virtual void DefaultConstructor(ClientContext* context) = 0;
+    virtual void Destructor(ClientContext* context) = 0;
+  };
+  static void SetGlobalCallbacks(GlobalCallbacks* callbacks);
+
+  /// Should be used for framework-level extensions only.
+  /// Applications never need to call this method.
+  grpc_call* c_call() { return call_; }
+
+  /// EXPERIMENTAL debugging API
+  ///
+  /// if status is not ok() for an RPC, this will return a detailed string
+  /// of the gRPC Core error that led to the failure. It should not be relied
+  /// upon for anything other than gaining more debug data in failure cases.
+  grpc::string debug_error_string() const { return debug_error_string_; }
+
+ private:
+  // Disallow copy and assign.
+  ClientContext(const ClientContext&);
+  ClientContext& operator=(const ClientContext&);
+
+  friend class ::grpc::testing::InteropClientContextInspector;
+  friend class ::grpc::internal::CallOpClientRecvStatus;
+  friend class ::grpc::internal::CallOpRecvInitialMetadata;
+  friend class Channel;
+  template <class R>
+  friend class ::grpc::ClientReader;
+  template <class W>
+  friend class ::grpc::ClientWriter;
+  template <class W, class R>
+  friend class ::grpc::ClientReaderWriter;
+  template <class R>
+  friend class ::grpc::ClientAsyncReader;
+  template <class W>
+  friend class ::grpc::ClientAsyncWriter;
+  template <class W, class R>
+  friend class ::grpc::ClientAsyncReaderWriter;
+  template <class R>
+  friend class ::grpc::ClientAsyncResponseReader;
+  template <class InputMessage, class OutputMessage>
+  friend class ::grpc::internal::BlockingUnaryCallImpl;
+
+  // Used by friend class CallOpClientRecvStatus
+  void set_debug_error_string(const grpc::string& debug_error_string) {
+    debug_error_string_ = debug_error_string;
+  }
+
+  grpc_call* call() const { return call_; }
+  void set_call(grpc_call* call, const std::shared_ptr<Channel>& channel);
+
+  uint32_t initial_metadata_flags() const {
+    return (idempotent_ ? GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST : 0) |
+           (wait_for_ready_ ? GRPC_INITIAL_METADATA_WAIT_FOR_READY : 0) |
+           (cacheable_ ? GRPC_INITIAL_METADATA_CACHEABLE_REQUEST : 0) |
+           (wait_for_ready_explicitly_set_
+                ? GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET
+                : 0) |
+           (initial_metadata_corked_ ? GRPC_INITIAL_METADATA_CORKED : 0);
+  }
+
+  grpc::string authority() { return authority_; }
+
+  bool initial_metadata_received_;
+  bool wait_for_ready_;
+  bool wait_for_ready_explicitly_set_;
+  bool idempotent_;
+  bool cacheable_;
+  std::shared_ptr<Channel> channel_;
+  std::mutex mu_;
+  grpc_call* call_;
+  bool call_canceled_;
+  gpr_timespec deadline_;
+  grpc::string authority_;
+  std::shared_ptr<CallCredentials> creds_;
+  mutable std::shared_ptr<const AuthContext> auth_context_;
+  struct census_context* census_context_;
+  std::multimap<grpc::string, grpc::string> send_initial_metadata_;
+  internal::MetadataMap recv_initial_metadata_;
+  internal::MetadataMap trailing_metadata_;
+
+  grpc_call* propagate_from_call_;
+  PropagationOptions propagation_options_;
+
+  grpc_compression_algorithm compression_algorithm_;
+  bool initial_metadata_corked_;
+
+  grpc::string debug_error_string_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_H
diff --git a/include/grpcpp/impl/codegen/client_unary_call.h b/include/grpcpp/impl/codegen/client_unary_call.h
new file mode 100644
index 0000000..a37a81b
--- /dev/null
+++ b/include/grpcpp/impl/codegen/client_unary_call.h
@@ -0,0 +1,90 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_CLIENT_UNARY_CALL_H
+#define GRPCPP_IMPL_CODEGEN_CLIENT_UNARY_CALL_H
+
+#include <grpcpp/impl/codegen/call.h>
+#include <grpcpp/impl/codegen/channel_interface.h>
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/status.h>
+
+namespace grpc {
+
+class Channel;
+class ClientContext;
+class CompletionQueue;
+
+namespace internal {
+class RpcMethod;
+/// Wrapper that performs a blocking unary call
+template <class InputMessage, class OutputMessage>
+Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method,
+                         ClientContext* context, const InputMessage& request,
+                         OutputMessage* result) {
+  return BlockingUnaryCallImpl<InputMessage, OutputMessage>(
+             channel, method, context, request, result)
+      .status();
+}
+
+template <class InputMessage, class OutputMessage>
+class BlockingUnaryCallImpl {
+ public:
+  BlockingUnaryCallImpl(ChannelInterface* channel, const RpcMethod& method,
+                        ClientContext* context, const InputMessage& request,
+                        OutputMessage* result) {
+    CompletionQueue cq(grpc_completion_queue_attributes{
+        GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK,
+        GRPC_CQ_DEFAULT_POLLING});  // Pluckable completion queue
+    Call call(channel->CreateCall(method, context, &cq));
+    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+              CallOpRecvInitialMetadata, CallOpRecvMessage<OutputMessage>,
+              CallOpClientSendClose, CallOpClientRecvStatus>
+        ops;
+    status_ = ops.SendMessage(request);
+    if (!status_.ok()) {
+      return;
+    }
+    ops.SendInitialMetadata(context->send_initial_metadata_,
+                            context->initial_metadata_flags());
+    ops.RecvInitialMetadata(context);
+    ops.RecvMessage(result);
+    ops.AllowNoMessage();
+    ops.ClientSendClose();
+    ops.ClientRecvStatus(context, &status_);
+    call.PerformOps(&ops);
+    if (cq.Pluck(&ops)) {
+      if (!ops.got_message && status_.ok()) {
+        status_ = Status(StatusCode::UNIMPLEMENTED,
+                         "No message returned for unary request");
+      }
+    } else {
+      GPR_CODEGEN_ASSERT(!status_.ok());
+    }
+  }
+  Status status() { return status_; }
+
+ private:
+  Status status_;
+};
+
+}  // namespace internal
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_CLIENT_UNARY_CALL_H
diff --git a/include/grpcpp/impl/codegen/completion_queue.h b/include/grpcpp/impl/codegen/completion_queue.h
new file mode 100644
index 0000000..9713333
--- /dev/null
+++ b/include/grpcpp/impl/codegen/completion_queue.h
@@ -0,0 +1,388 @@
+/*
+ *
+ * Copyright 2015-2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 completion queue implements a concurrent producer-consumer queue, with
+/// two main API-exposed methods: \a Next and \a AsyncNext. These
+/// methods are the essential component of the gRPC C++ asynchronous API.
+/// There is also a \a Shutdown method to indicate that a given completion queue
+/// will no longer have regular events. This must be called before the
+/// completion queue is destroyed.
+/// All completion queue APIs are thread-safe and may be used concurrently with
+/// any other completion queue API invocation; it is acceptable to have
+/// multiple threads calling \a Next or \a AsyncNext on the same or different
+/// completion queues, or to call these methods concurrently with a \a Shutdown
+/// elsewhere.
+/// \remark{All other API calls on completion queue should be completed before
+/// a completion queue destructor is called.}
+#ifndef GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_H
+#define GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_H
+
+#include <grpc/impl/codegen/atm.h>
+#include <grpcpp/impl/codegen/completion_queue_tag.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/grpc_library.h>
+#include <grpcpp/impl/codegen/status.h>
+#include <grpcpp/impl/codegen/time.h>
+
+struct grpc_completion_queue;
+
+namespace grpc {
+
+template <class R>
+class ClientReader;
+template <class W>
+class ClientWriter;
+template <class W, class R>
+class ClientReaderWriter;
+template <class R>
+class ServerReader;
+template <class W>
+class ServerWriter;
+namespace internal {
+template <class W, class R>
+class ServerReaderWriterBody;
+}  // namespace internal
+
+class Channel;
+class ChannelInterface;
+class ClientContext;
+class CompletionQueue;
+class Server;
+class ServerBuilder;
+class ServerContext;
+class ServerInterface;
+
+namespace internal {
+class CompletionQueueTag;
+class RpcMethod;
+template <class ServiceType, class RequestType, class ResponseType>
+class RpcMethodHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class ClientStreamingHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class ServerStreamingHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class BidiStreamingHandler;
+class UnknownMethodHandler;
+template <class Streamer, bool WriteNeeded>
+class TemplatedBidiStreamingHandler;
+template <class InputMessage, class OutputMessage>
+class BlockingUnaryCallImpl;
+}  // namespace internal
+
+extern CoreCodegenInterface* g_core_codegen_interface;
+
+/// A thin wrapper around \ref grpc_completion_queue (see \ref
+/// src/core/lib/surface/completion_queue.h).
+/// See \ref doc/cpp/perf_notes.md for notes on best practices for high
+/// performance servers.
+class CompletionQueue : private GrpcLibraryCodegen {
+ public:
+  /// Default constructor. Implicitly creates a \a grpc_completion_queue
+  /// instance.
+  CompletionQueue()
+      : CompletionQueue(grpc_completion_queue_attributes{
+            GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, GRPC_CQ_DEFAULT_POLLING}) {}
+
+  /// Wrap \a take, taking ownership of the instance.
+  ///
+  /// \param take The completion queue instance to wrap. Ownership is taken.
+  explicit CompletionQueue(grpc_completion_queue* take);
+
+  /// Destructor. Destroys the owned wrapped completion queue / instance.
+  ~CompletionQueue() {
+    g_core_codegen_interface->grpc_completion_queue_destroy(cq_);
+  }
+
+  /// Tri-state return for AsyncNext: SHUTDOWN, GOT_EVENT, TIMEOUT.
+  enum NextStatus {
+    SHUTDOWN,   ///< The completion queue has been shutdown and fully-drained
+    GOT_EVENT,  ///< Got a new event; \a tag will be filled in with its
+                ///< associated value; \a ok indicating its success.
+    TIMEOUT     ///< deadline was reached.
+  };
+
+  /// Read from the queue, blocking until an event is available or the queue is
+  /// shutting down.
+  ///
+  /// \param tag[out] Updated to point to the read event's tag.
+  /// \param ok[out] true if read a successful event, false otherwise.
+  ///
+  /// Note that each tag sent to the completion queue (through RPC operations
+  /// or alarms) will be delivered out of the completion queue by a call to
+  /// Next (or a related method), regardless of whether the operation succeeded
+  /// or not. Success here means that this operation completed in the normal
+  /// valid manner.
+  ///
+  /// Server-side RPC request: \a ok indicates that the RPC has indeed
+  /// been started. If it is false, the server has been Shutdown
+  /// before this particular call got matched to an incoming RPC.
+  ///
+  /// Client-side StartCall/RPC invocation: \a ok indicates that the RPC is
+  /// going to go to the wire. If it is false, it not going to the wire. This
+  /// would happen if the channel is either permanently broken or
+  /// transiently broken but with the fail-fast option. (Note that async unary
+  /// RPCs don't post a CQ tag at this point, nor do client-streaming
+  /// or bidi-streaming RPCs that have the initial metadata corked option set.)
+  ///
+  /// Client-side Write, Client-side WritesDone, Server-side Write,
+  /// Server-side Finish, Server-side SendInitialMetadata (which is
+  /// typically included in Write or Finish when not done explicitly):
+  /// \a ok means that the data/metadata/status/etc is going to go to the
+  /// wire. If it is false, it not going to the wire because the call
+  /// is already dead (i.e., canceled, deadline expired, other side
+  /// dropped the channel, etc).
+  ///
+  /// Client-side Read, Server-side Read, Client-side
+  /// RecvInitialMetadata (which is typically included in Read if not
+  /// done explicitly): \a ok indicates whether there is a valid message
+  /// that got read. If not, you know that there are certainly no more
+  /// messages that can ever be read from this stream. For the client-side
+  /// operations, this only happens because the call is dead. For the
+  /// server-sider operation, though, this could happen because the client
+  /// has done a WritesDone already.
+  ///
+  /// Client-side Finish: \a ok should always be true
+  ///
+  /// Server-side AsyncNotifyWhenDone: \a ok should always be true
+  ///
+  /// Alarm: \a ok is true if it expired, false if it was canceled
+  ///
+  /// \return true if got an event, false if the queue is fully drained and
+  ///         shut down.
+  bool Next(void** tag, bool* ok) {
+    return (AsyncNextInternal(tag, ok,
+                              g_core_codegen_interface->gpr_inf_future(
+                                  GPR_CLOCK_REALTIME)) != SHUTDOWN);
+  }
+
+  /// Read from the queue, blocking up to \a deadline (or the queue's shutdown).
+  /// Both \a tag and \a ok are updated upon success (if an event is available
+  /// within the \a deadline).  A \a tag points to an arbitrary location usually
+  /// employed to uniquely identify an event.
+  ///
+  /// \param tag[out] Upon sucess, updated to point to the event's tag.
+  /// \param ok[out] Upon sucess, true if a successful event, false otherwise
+  ///        See documentation for CompletionQueue::Next for explanation of ok
+  /// \param deadline[in] How long to block in wait for an event.
+  ///
+  /// \return The type of event read.
+  template <typename T>
+  NextStatus AsyncNext(void** tag, bool* ok, const T& deadline) {
+    TimePoint<T> deadline_tp(deadline);
+    return AsyncNextInternal(tag, ok, deadline_tp.raw_time());
+  }
+
+  /// EXPERIMENTAL
+  /// First executes \a F, then reads from the queue, blocking up to
+  /// \a deadline (or the queue's shutdown).
+  /// Both \a tag and \a ok are updated upon success (if an event is available
+  /// within the \a deadline).  A \a tag points to an arbitrary location usually
+  /// employed to uniquely identify an event.
+  ///
+  /// \param F[in] Function to execute before calling AsyncNext on this queue.
+  /// \param tag[out] Upon sucess, updated to point to the event's tag.
+  /// \param ok[out] Upon sucess, true if read a regular event, false otherwise.
+  /// \param deadline[in] How long to block in wait for an event.
+  ///
+  /// \return The type of event read.
+  template <typename T, typename F>
+  NextStatus DoThenAsyncNext(F&& f, void** tag, bool* ok, const T& deadline) {
+    CompletionQueueTLSCache cache = CompletionQueueTLSCache(this);
+    f();
+    if (cache.Flush(tag, ok)) {
+      return GOT_EVENT;
+    } else {
+      return AsyncNext(tag, ok, deadline);
+    }
+  }
+
+  /// Request the shutdown of the queue.
+  ///
+  /// \warning This method must be called at some point if this completion queue
+  /// is accessed with Next or AsyncNext. \a Next will not return false
+  /// until this method has been called and all pending tags have been drained.
+  /// (Likewise for \a AsyncNext returning \a NextStatus::SHUTDOWN .)
+  /// Only once either one of these methods does that (that is, once the queue
+  /// has been \em drained) can an instance of this class be destroyed.
+  /// Also note that applications must ensure that no work is enqueued on this
+  /// completion queue after this method is called.
+  void Shutdown();
+
+  /// Returns a \em raw pointer to the underlying \a grpc_completion_queue
+  /// instance.
+  ///
+  /// \warning Remember that the returned instance is owned. No transfer of
+  /// owership is performed.
+  grpc_completion_queue* cq() { return cq_; }
+
+ protected:
+  /// Private constructor of CompletionQueue only visible to friend classes
+  CompletionQueue(const grpc_completion_queue_attributes& attributes) {
+    cq_ = g_core_codegen_interface->grpc_completion_queue_create(
+        g_core_codegen_interface->grpc_completion_queue_factory_lookup(
+            &attributes),
+        &attributes, NULL);
+    InitialAvalanching();  // reserve this for the future shutdown
+  }
+
+ private:
+  // Friend synchronous wrappers so that they can access Pluck(), which is
+  // a semi-private API geared towards the synchronous implementation.
+  template <class R>
+  friend class ::grpc::ClientReader;
+  template <class W>
+  friend class ::grpc::ClientWriter;
+  template <class W, class R>
+  friend class ::grpc::ClientReaderWriter;
+  template <class R>
+  friend class ::grpc::ServerReader;
+  template <class W>
+  friend class ::grpc::ServerWriter;
+  template <class W, class R>
+  friend class ::grpc::internal::ServerReaderWriterBody;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class ::grpc::internal::RpcMethodHandler;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class ::grpc::internal::ClientStreamingHandler;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class ::grpc::internal::ServerStreamingHandler;
+  template <class Streamer, bool WriteNeeded>
+  friend class ::grpc::internal::TemplatedBidiStreamingHandler;
+  friend class ::grpc::internal::UnknownMethodHandler;
+  friend class ::grpc::Server;
+  friend class ::grpc::ServerContext;
+  friend class ::grpc::ServerInterface;
+  template <class InputMessage, class OutputMessage>
+  friend class ::grpc::internal::BlockingUnaryCallImpl;
+
+  /// EXPERIMENTAL
+  /// Creates a Thread Local cache to store the first event
+  /// On this completion queue queued from this thread.  Once
+  /// initialized, it must be flushed on the same thread.
+  class CompletionQueueTLSCache {
+   public:
+    CompletionQueueTLSCache(CompletionQueue* cq);
+    ~CompletionQueueTLSCache();
+    bool Flush(void** tag, bool* ok);
+
+   private:
+    CompletionQueue* cq_;
+    bool flushed_;
+  };
+
+  NextStatus AsyncNextInternal(void** tag, bool* ok, gpr_timespec deadline);
+
+  /// Wraps \a grpc_completion_queue_pluck.
+  /// \warning Must not be mixed with calls to \a Next.
+  bool Pluck(internal::CompletionQueueTag* tag) {
+    auto deadline =
+        g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_REALTIME);
+    auto ev = g_core_codegen_interface->grpc_completion_queue_pluck(
+        cq_, tag, deadline, nullptr);
+    bool ok = ev.success != 0;
+    void* ignored = tag;
+    GPR_CODEGEN_ASSERT(tag->FinalizeResult(&ignored, &ok));
+    GPR_CODEGEN_ASSERT(ignored == tag);
+    // Ignore mutations by FinalizeResult: Pluck returns the C API status
+    return ev.success != 0;
+  }
+
+  /// Performs a single polling pluck on \a tag.
+  /// \warning Must not be mixed with calls to \a Next.
+  ///
+  /// TODO: sreek - This calls tag->FinalizeResult() even if the cq_ is already
+  /// shutdown. This is most likely a bug and if it is a bug, then change this
+  /// implementation to simple call the other TryPluck function with a zero
+  /// timeout. i.e:
+  ///      TryPluck(tag, gpr_time_0(GPR_CLOCK_REALTIME))
+  void TryPluck(internal::CompletionQueueTag* tag) {
+    auto deadline = g_core_codegen_interface->gpr_time_0(GPR_CLOCK_REALTIME);
+    auto ev = g_core_codegen_interface->grpc_completion_queue_pluck(
+        cq_, tag, deadline, nullptr);
+    if (ev.type == GRPC_QUEUE_TIMEOUT) return;
+    bool ok = ev.success != 0;
+    void* ignored = tag;
+    // the tag must be swallowed if using TryPluck
+    GPR_CODEGEN_ASSERT(!tag->FinalizeResult(&ignored, &ok));
+  }
+
+  /// Performs a single polling pluck on \a tag. Calls tag->FinalizeResult if
+  /// the pluck() was successful and returned the tag.
+  ///
+  /// This exects tag->FinalizeResult (if called) to return 'false' i.e expects
+  /// that the tag is internal not something that is returned to the user.
+  void TryPluck(internal::CompletionQueueTag* tag, gpr_timespec deadline) {
+    auto ev = g_core_codegen_interface->grpc_completion_queue_pluck(
+        cq_, tag, deadline, nullptr);
+    if (ev.type == GRPC_QUEUE_TIMEOUT || ev.type == GRPC_QUEUE_SHUTDOWN) {
+      return;
+    }
+
+    bool ok = ev.success != 0;
+    void* ignored = tag;
+    GPR_CODEGEN_ASSERT(!tag->FinalizeResult(&ignored, &ok));
+  }
+
+  /// Manage state of avalanching operations : completion queue tags that
+  /// trigger other completion queue operations. The underlying core completion
+  /// queue should not really shutdown until all avalanching operations have
+  /// been finalized. Note that we maintain the requirement that an avalanche
+  /// registration must take place before CQ shutdown (which must be maintained
+  /// elsehwere)
+  void InitialAvalanching() {
+    gpr_atm_rel_store(&avalanches_in_flight_, static_cast<gpr_atm>(1));
+  }
+  void RegisterAvalanching() {
+    gpr_atm_no_barrier_fetch_add(&avalanches_in_flight_,
+                                 static_cast<gpr_atm>(1));
+  }
+  void CompleteAvalanching();
+
+  grpc_completion_queue* cq_;  // owned
+
+  gpr_atm avalanches_in_flight_;
+};
+
+/// A specific type of completion queue used by the processing of notifications
+/// by servers. Instantiated by \a ServerBuilder.
+class ServerCompletionQueue : public CompletionQueue {
+ public:
+  bool IsFrequentlyPolled() { return polling_type_ != GRPC_CQ_NON_LISTENING; }
+
+ protected:
+  /// Default constructor
+  ServerCompletionQueue() {}
+
+ private:
+  /// \param is_frequently_polled Informs the GRPC library about whether the
+  /// server completion queue would be actively polled (by calling Next() or
+  /// AsyncNext()). By default all server completion queues are assumed to be
+  /// frequently polled.
+  ServerCompletionQueue(grpc_cq_polling_type polling_type)
+      : CompletionQueue(grpc_completion_queue_attributes{
+            GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, polling_type}),
+        polling_type_(polling_type) {}
+
+  grpc_cq_polling_type polling_type_;
+  friend class ServerBuilder;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_H
diff --git a/include/grpcpp/impl/codegen/completion_queue_tag.h b/include/grpcpp/impl/codegen/completion_queue_tag.h
new file mode 100644
index 0000000..ffb642c
--- /dev/null
+++ b/include/grpcpp/impl/codegen/completion_queue_tag.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_TAG_H
+#define GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_TAG_H
+
+namespace grpc {
+
+namespace internal {
+/// An interface allowing implementors to process and filter event tags.
+class CompletionQueueTag {
+ public:
+  virtual ~CompletionQueueTag() {}
+  /// Called prior to returning from Next(), return value is the status of the
+  /// operation (return status is the default thing to do). If this function
+  /// returns false, the tag is dropped and not returned from the completion
+  /// queue
+  virtual bool FinalizeResult(void** tag, bool* status) = 0;
+};
+}  // namespace internal
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_TAG_H
diff --git a/include/grpcpp/impl/codegen/config.h b/include/grpcpp/impl/codegen/config.h
new file mode 100644
index 0000000..37f0fd1
--- /dev/null
+++ b/include/grpcpp/impl/codegen/config.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_CONFIG_H
+#define GRPCPP_IMPL_CODEGEN_CONFIG_H
+
+#ifndef GRPC_CUSTOM_STRING
+#include <string>
+#define GRPC_CUSTOM_STRING std::string
+#endif
+
+/// The following macros are deprecated and appear only for users
+/// with PB files generated using gRPC 1.0.x plugins. They should
+/// not be used in new code
+#define GRPC_OVERRIDE override  // deprecated
+#define GRPC_FINAL final        // deprecated
+
+namespace grpc {
+
+typedef GRPC_CUSTOM_STRING string;
+
+using std::to_string;
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_CONFIG_H
diff --git a/include/grpcpp/impl/codegen/config_protobuf.h b/include/grpcpp/impl/codegen/config_protobuf.h
new file mode 100644
index 0000000..94e593d
--- /dev/null
+++ b/include/grpcpp/impl/codegen/config_protobuf.h
@@ -0,0 +1,95 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_CONFIG_PROTOBUF_H
+#define GRPCPP_IMPL_CODEGEN_CONFIG_PROTOBUF_H
+
+#define GRPC_OPEN_SOURCE_PROTO
+
+#ifndef GRPC_CUSTOM_PROTOBUF_INT64
+#include <google/protobuf/stubs/common.h>
+#define GRPC_CUSTOM_PROTOBUF_INT64 ::google::protobuf::int64
+#endif
+
+#ifndef GRPC_CUSTOM_MESSAGE
+#ifdef GRPC_USE_PROTO_LITE
+#include <google/protobuf/message_lite.h>
+#define GRPC_CUSTOM_MESSAGE ::google::protobuf::MessageLite
+#else
+#include <google/protobuf/message.h>
+#define GRPC_CUSTOM_MESSAGE ::google::protobuf::Message
+#endif
+#endif
+
+#ifndef GRPC_CUSTOM_DESCRIPTOR
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#define GRPC_CUSTOM_DESCRIPTOR ::google::protobuf::Descriptor
+#define GRPC_CUSTOM_DESCRIPTORPOOL ::google::protobuf::DescriptorPool
+#define GRPC_CUSTOM_FIELDDESCRIPTOR ::google::protobuf::FieldDescriptor
+#define GRPC_CUSTOM_FILEDESCRIPTOR ::google::protobuf::FileDescriptor
+#define GRPC_CUSTOM_FILEDESCRIPTORPROTO ::google::protobuf::FileDescriptorProto
+#define GRPC_CUSTOM_METHODDESCRIPTOR ::google::protobuf::MethodDescriptor
+#define GRPC_CUSTOM_SERVICEDESCRIPTOR ::google::protobuf::ServiceDescriptor
+#define GRPC_CUSTOM_SOURCELOCATION ::google::protobuf::SourceLocation
+#endif
+
+#ifndef GRPC_CUSTOM_DESCRIPTORDATABASE
+#include <google/protobuf/descriptor_database.h>
+#define GRPC_CUSTOM_DESCRIPTORDATABASE ::google::protobuf::DescriptorDatabase
+#define GRPC_CUSTOM_SIMPLEDESCRIPTORDATABASE \
+  ::google::protobuf::SimpleDescriptorDatabase
+#endif
+
+#ifndef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#define GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM \
+  ::google::protobuf::io::ZeroCopyOutputStream
+#define GRPC_CUSTOM_ZEROCOPYINPUTSTREAM \
+  ::google::protobuf::io::ZeroCopyInputStream
+#define GRPC_CUSTOM_CODEDINPUTSTREAM ::google::protobuf::io::CodedInputStream
+#endif
+
+namespace grpc {
+namespace protobuf {
+
+typedef GRPC_CUSTOM_MESSAGE Message;
+typedef GRPC_CUSTOM_PROTOBUF_INT64 int64;
+
+typedef GRPC_CUSTOM_DESCRIPTOR Descriptor;
+typedef GRPC_CUSTOM_DESCRIPTORPOOL DescriptorPool;
+typedef GRPC_CUSTOM_DESCRIPTORDATABASE DescriptorDatabase;
+typedef GRPC_CUSTOM_FIELDDESCRIPTOR FieldDescriptor;
+typedef GRPC_CUSTOM_FILEDESCRIPTOR FileDescriptor;
+typedef GRPC_CUSTOM_FILEDESCRIPTORPROTO FileDescriptorProto;
+typedef GRPC_CUSTOM_METHODDESCRIPTOR MethodDescriptor;
+typedef GRPC_CUSTOM_SERVICEDESCRIPTOR ServiceDescriptor;
+typedef GRPC_CUSTOM_SIMPLEDESCRIPTORDATABASE SimpleDescriptorDatabase;
+typedef GRPC_CUSTOM_SOURCELOCATION SourceLocation;
+
+namespace io {
+typedef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM ZeroCopyOutputStream;
+typedef GRPC_CUSTOM_ZEROCOPYINPUTSTREAM ZeroCopyInputStream;
+typedef GRPC_CUSTOM_CODEDINPUTSTREAM CodedInputStream;
+}  // namespace io
+
+}  // namespace protobuf
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_CONFIG_PROTOBUF_H
diff --git a/include/grpcpp/impl/codegen/core_codegen.h b/include/grpcpp/impl/codegen/core_codegen.h
new file mode 100644
index 0000000..0ca4ad5
--- /dev/null
+++ b/include/grpcpp/impl/codegen/core_codegen.h
@@ -0,0 +1,117 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_CORE_CODEGEN_H
+#define GRPCPP_IMPL_CODEGEN_CORE_CODEGEN_H
+
+// This file should be compiled as part of grpcpp.
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+
+namespace grpc {
+
+/// Implementation of the core codegen interface.
+class CoreCodegen final : public CoreCodegenInterface {
+ private:
+  virtual const grpc_completion_queue_factory*
+  grpc_completion_queue_factory_lookup(
+      const grpc_completion_queue_attributes* attributes) override;
+  virtual grpc_completion_queue* grpc_completion_queue_create(
+      const grpc_completion_queue_factory* factory,
+      const grpc_completion_queue_attributes* attributes,
+      void* reserved) override;
+  grpc_completion_queue* grpc_completion_queue_create_for_next(
+      void* reserved) override;
+  grpc_completion_queue* grpc_completion_queue_create_for_pluck(
+      void* reserved) override;
+  void grpc_completion_queue_destroy(grpc_completion_queue* cq) override;
+  grpc_event grpc_completion_queue_pluck(grpc_completion_queue* cq, void* tag,
+                                         gpr_timespec deadline,
+                                         void* reserved) override;
+
+  void* gpr_malloc(size_t size) override;
+  void gpr_free(void* p) override;
+
+  void grpc_init() override;
+  void grpc_shutdown() override;
+
+  void gpr_mu_init(gpr_mu* mu) override;
+  void gpr_mu_destroy(gpr_mu* mu) override;
+  void gpr_mu_lock(gpr_mu* mu) override;
+  void gpr_mu_unlock(gpr_mu* mu) override;
+  void gpr_cv_init(gpr_cv* cv) override;
+  void gpr_cv_destroy(gpr_cv* cv) override;
+  int gpr_cv_wait(gpr_cv* cv, gpr_mu* mu, gpr_timespec abs_deadline) override;
+  void gpr_cv_signal(gpr_cv* cv) override;
+  void gpr_cv_broadcast(gpr_cv* cv) override;
+
+  grpc_call_error grpc_call_cancel_with_status(grpc_call* call,
+                                               grpc_status_code status,
+                                               const char* description,
+                                               void* reserved) override;
+  void grpc_call_ref(grpc_call* call) override;
+  void grpc_call_unref(grpc_call* call) override;
+  virtual void* grpc_call_arena_alloc(grpc_call* call, size_t length) override;
+
+  grpc_byte_buffer* grpc_byte_buffer_copy(grpc_byte_buffer* bb) override;
+  void grpc_byte_buffer_destroy(grpc_byte_buffer* bb) override;
+
+  int grpc_byte_buffer_reader_init(grpc_byte_buffer_reader* reader,
+                                   grpc_byte_buffer* buffer) override;
+  void grpc_byte_buffer_reader_destroy(
+      grpc_byte_buffer_reader* reader) override;
+  int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader* reader,
+                                   grpc_slice* slice) override;
+
+  grpc_byte_buffer* grpc_raw_byte_buffer_create(grpc_slice* slice,
+                                                size_t nslices) override;
+  grpc_slice grpc_slice_new_with_user_data(void* p, size_t len,
+                                           void (*destroy)(void*),
+                                           void* user_data) override;
+  grpc_slice grpc_empty_slice() override;
+  grpc_slice grpc_slice_malloc(size_t length) override;
+  void grpc_slice_unref(grpc_slice slice) override;
+  grpc_slice grpc_slice_ref(grpc_slice slice) override;
+  grpc_slice grpc_slice_split_tail(grpc_slice* s, size_t split) override;
+  grpc_slice grpc_slice_split_head(grpc_slice* s, size_t split) override;
+  grpc_slice grpc_slice_sub(grpc_slice s, size_t begin, size_t end) override;
+  void grpc_slice_buffer_add(grpc_slice_buffer* sb, grpc_slice slice) override;
+  void grpc_slice_buffer_pop(grpc_slice_buffer* sb) override;
+  grpc_slice grpc_slice_from_static_buffer(const void* buffer,
+                                           size_t length) override;
+  grpc_slice grpc_slice_from_copied_buffer(const void* buffer,
+                                           size_t length) override;
+  void grpc_metadata_array_init(grpc_metadata_array* array) override;
+  void grpc_metadata_array_destroy(grpc_metadata_array* array) override;
+
+  gpr_timespec gpr_inf_future(gpr_clock_type type) override;
+  gpr_timespec gpr_time_0(gpr_clock_type type) override;
+
+  virtual const Status& ok() override;
+  virtual const Status& cancelled() override;
+
+  void assert_fail(const char* failed_assertion, const char* file,
+                   int line) override;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_CORE_CODEGEN_H
diff --git a/include/grpcpp/impl/codegen/core_codegen_interface.h b/include/grpcpp/impl/codegen/core_codegen_interface.h
new file mode 100644
index 0000000..d72f579
--- /dev/null
+++ b/include/grpcpp/impl/codegen/core_codegen_interface.h
@@ -0,0 +1,142 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H
+#define GRPCPP_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H
+
+#include <grpc/impl/codegen/byte_buffer_reader.h>
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpc/impl/codegen/sync.h>
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/status.h>
+
+namespace grpc {
+
+/// Interface between the codegen library and the minimal subset of core
+/// features required by the generated code.
+///
+/// All undocumented methods are simply forwarding the call to their namesakes.
+/// Please refer to their corresponding documentation for details.
+///
+/// \warning This interface should be considered internal and private.
+class CoreCodegenInterface {
+ public:
+  virtual ~CoreCodegenInterface() = default;
+
+  /// Upon a failed assertion, log the error.
+  virtual void assert_fail(const char* failed_assertion, const char* file,
+                           int line) = 0;
+
+  virtual const grpc_completion_queue_factory*
+  grpc_completion_queue_factory_lookup(
+      const grpc_completion_queue_attributes* attributes) = 0;
+  virtual grpc_completion_queue* grpc_completion_queue_create(
+      const grpc_completion_queue_factory* factory,
+      const grpc_completion_queue_attributes* attributes, void* reserved) = 0;
+  virtual grpc_completion_queue* grpc_completion_queue_create_for_next(
+      void* reserved) = 0;
+  virtual grpc_completion_queue* grpc_completion_queue_create_for_pluck(
+      void* reserved) = 0;
+  virtual void grpc_completion_queue_destroy(grpc_completion_queue* cq) = 0;
+  virtual grpc_event grpc_completion_queue_pluck(grpc_completion_queue* cq,
+                                                 void* tag,
+                                                 gpr_timespec deadline,
+                                                 void* reserved) = 0;
+
+  virtual void* gpr_malloc(size_t size) = 0;
+  virtual void gpr_free(void* p) = 0;
+
+  // These are only to be used to fix edge cases involving grpc_init and
+  // grpc_shutdown. Calling grpc_init from the codegen interface before
+  // the real grpc_init is called will cause a crash, so if you use this
+  // function, ensure that it is not the first call to grpc_init.
+  virtual void grpc_init() = 0;
+  virtual void grpc_shutdown() = 0;
+
+  virtual void gpr_mu_init(gpr_mu* mu) = 0;
+  virtual void gpr_mu_destroy(gpr_mu* mu) = 0;
+  virtual void gpr_mu_lock(gpr_mu* mu) = 0;
+  virtual void gpr_mu_unlock(gpr_mu* mu) = 0;
+  virtual void gpr_cv_init(gpr_cv* cv) = 0;
+  virtual void gpr_cv_destroy(gpr_cv* cv) = 0;
+  virtual int gpr_cv_wait(gpr_cv* cv, gpr_mu* mu,
+                          gpr_timespec abs_deadline) = 0;
+  virtual void gpr_cv_signal(gpr_cv* cv) = 0;
+  virtual void gpr_cv_broadcast(gpr_cv* cv) = 0;
+
+  virtual grpc_byte_buffer* grpc_byte_buffer_copy(grpc_byte_buffer* bb) = 0;
+  virtual void grpc_byte_buffer_destroy(grpc_byte_buffer* bb) = 0;
+
+  virtual int grpc_byte_buffer_reader_init(grpc_byte_buffer_reader* reader,
+                                           grpc_byte_buffer* buffer)
+      GRPC_MUST_USE_RESULT = 0;
+  virtual void grpc_byte_buffer_reader_destroy(
+      grpc_byte_buffer_reader* reader) = 0;
+  virtual int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader* reader,
+                                           grpc_slice* slice) = 0;
+
+  virtual grpc_byte_buffer* grpc_raw_byte_buffer_create(grpc_slice* slice,
+                                                        size_t nslices) = 0;
+  virtual grpc_slice grpc_slice_new_with_user_data(void* p, size_t len,
+                                                   void (*destroy)(void*),
+                                                   void* user_data) = 0;
+  virtual grpc_call_error grpc_call_cancel_with_status(grpc_call* call,
+                                                       grpc_status_code status,
+                                                       const char* description,
+                                                       void* reserved) = 0;
+  virtual void grpc_call_ref(grpc_call* call) = 0;
+  virtual void grpc_call_unref(grpc_call* call) = 0;
+  virtual void* grpc_call_arena_alloc(grpc_call* call, size_t length) = 0;
+  virtual grpc_slice grpc_empty_slice() = 0;
+  virtual grpc_slice grpc_slice_malloc(size_t length) = 0;
+  virtual void grpc_slice_unref(grpc_slice slice) = 0;
+  virtual grpc_slice grpc_slice_ref(grpc_slice slice) = 0;
+  virtual grpc_slice grpc_slice_split_tail(grpc_slice* s, size_t split) = 0;
+  virtual grpc_slice grpc_slice_split_head(grpc_slice* s, size_t split) = 0;
+  virtual grpc_slice grpc_slice_sub(grpc_slice s, size_t begin, size_t end) = 0;
+  virtual void grpc_slice_buffer_add(grpc_slice_buffer* sb,
+                                     grpc_slice slice) = 0;
+  virtual void grpc_slice_buffer_pop(grpc_slice_buffer* sb) = 0;
+  virtual grpc_slice grpc_slice_from_static_buffer(const void* buffer,
+                                                   size_t length) = 0;
+  virtual grpc_slice grpc_slice_from_copied_buffer(const void* buffer,
+                                                   size_t length) = 0;
+
+  virtual void grpc_metadata_array_init(grpc_metadata_array* array) = 0;
+  virtual void grpc_metadata_array_destroy(grpc_metadata_array* array) = 0;
+
+  virtual const Status& ok() = 0;
+  virtual const Status& cancelled() = 0;
+
+  virtual gpr_timespec gpr_inf_future(gpr_clock_type type) = 0;
+  virtual gpr_timespec gpr_time_0(gpr_clock_type type) = 0;
+};
+
+extern CoreCodegenInterface* g_core_codegen_interface;
+
+/// Codegen specific version of \a GPR_ASSERT.
+#define GPR_CODEGEN_ASSERT(x)                                              \
+  do {                                                                     \
+    if (!(x)) {                                                            \
+      grpc::g_core_codegen_interface->assert_fail(#x, __FILE__, __LINE__); \
+    }                                                                      \
+  } while (0)
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/impl/codegen/create_auth_context.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/impl/codegen/create_auth_context.h
index 692c00c..cb6095c 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/impl/codegen/create_auth_context.h
@@ -16,15 +16,18 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_IMPL_CODEGEN_CREATE_AUTH_CONTEXT_H
+#define GRPCPP_IMPL_CODEGEN_CREATE_AUTH_CONTEXT_H
 
-#include <grpc/support/time.h>
+#include <memory>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpcpp/impl/codegen/security/auth_context.h>
 
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
+namespace grpc {
 
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+std::shared_ptr<const AuthContext> CreateAuthContext(grpc_call* call);
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_CREATE_AUTH_CONTEXT_H
diff --git a/include/grpcpp/impl/codegen/grpc_library.h b/include/grpcpp/impl/codegen/grpc_library.h
new file mode 100644
index 0000000..17c904d
--- /dev/null
+++ b/include/grpcpp/impl/codegen/grpc_library.h
@@ -0,0 +1,64 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_GRPC_LIBRARY_H
+#define GRPCPP_IMPL_CODEGEN_GRPC_LIBRARY_H
+
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+
+namespace grpc {
+
+class GrpcLibraryInterface {
+ public:
+  virtual ~GrpcLibraryInterface() = default;
+  virtual void init() = 0;
+  virtual void shutdown() = 0;
+};
+
+/// Initialized by \a grpc::GrpcLibraryInitializer from
+/// <grpcpp/impl/grpc_library.h>
+extern GrpcLibraryInterface* g_glip;
+
+/// Classes that require gRPC to be initialized should inherit from this class.
+class GrpcLibraryCodegen {
+ public:
+  GrpcLibraryCodegen(bool call_grpc_init = true) : grpc_init_called_(false) {
+    if (call_grpc_init) {
+      GPR_CODEGEN_ASSERT(g_glip &&
+                         "gRPC library not initialized. See "
+                         "grpc::internal::GrpcLibraryInitializer.");
+      g_glip->init();
+      grpc_init_called_ = true;
+    }
+  }
+  virtual ~GrpcLibraryCodegen() {
+    if (grpc_init_called_) {
+      GPR_CODEGEN_ASSERT(g_glip &&
+                         "gRPC library not initialized. See "
+                         "grpc::internal::GrpcLibraryInitializer.");
+      g_glip->shutdown();
+    }
+  }
+
+ private:
+  bool grpc_init_called_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_GRPC_LIBRARY_H
diff --git a/include/grpcpp/impl/codegen/metadata_map.h b/include/grpcpp/impl/codegen/metadata_map.h
new file mode 100644
index 0000000..0866539
--- /dev/null
+++ b/include/grpcpp/impl/codegen/metadata_map.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_METADATA_MAP_H
+#define GRPCPP_IMPL_CODEGEN_METADATA_MAP_H
+
+#include <grpcpp/impl/codegen/slice.h>
+
+namespace grpc {
+
+namespace internal {
+class MetadataMap {
+ public:
+  MetadataMap() { memset(&arr_, 0, sizeof(arr_)); }
+
+  ~MetadataMap() {
+    g_core_codegen_interface->grpc_metadata_array_destroy(&arr_);
+  }
+
+  void FillMap() {
+    for (size_t i = 0; i < arr_.count; i++) {
+      // TODO(yangg) handle duplicates?
+      map_.insert(std::pair<grpc::string_ref, grpc::string_ref>(
+          StringRefFromSlice(&arr_.metadata[i].key),
+          StringRefFromSlice(&arr_.metadata[i].value)));
+    }
+  }
+
+  std::multimap<grpc::string_ref, grpc::string_ref>* map() { return &map_; }
+  const std::multimap<grpc::string_ref, grpc::string_ref>* map() const {
+    return &map_;
+  }
+  grpc_metadata_array* arr() { return &arr_; }
+
+ private:
+  grpc_metadata_array arr_;
+  std::multimap<grpc::string_ref, grpc::string_ref> map_;
+};
+}  // namespace internal
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_METADATA_MAP_H
diff --git a/include/grpcpp/impl/codegen/method_handler_impl.h b/include/grpcpp/impl/codegen/method_handler_impl.h
new file mode 100644
index 0000000..27552d7
--- /dev/null
+++ b/include/grpcpp/impl/codegen/method_handler_impl.h
@@ -0,0 +1,302 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_METHOD_HANDLER_IMPL_H
+#define GRPCPP_IMPL_CODEGEN_METHOD_HANDLER_IMPL_H
+
+#include <grpcpp/impl/codegen/byte_buffer.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/rpc_service_method.h>
+#include <grpcpp/impl/codegen/sync_stream.h>
+
+namespace grpc {
+
+namespace internal {
+
+// Invoke the method handler, fill in the status, and
+// return whether or not we finished safely (without an exception).
+// Note that exception handling is 0-cost in most compiler/library
+// implementations (except when an exception is actually thrown),
+// so this process doesn't require additional overhead in the common case.
+// Additionally, we don't need to return if we caught an exception or not;
+// the handling is the same in either case.
+template <class Callable>
+Status CatchingFunctionHandler(Callable&& handler) {
+#if GRPC_ALLOW_EXCEPTIONS
+  try {
+    return handler();
+  } catch (...) {
+    return Status(StatusCode::UNKNOWN, "Unexpected error in RPC handling");
+  }
+#else   // GRPC_ALLOW_EXCEPTIONS
+  return handler();
+#endif  // GRPC_ALLOW_EXCEPTIONS
+}
+
+/// A wrapper class of an application provided rpc method handler.
+template <class ServiceType, class RequestType, class ResponseType>
+class RpcMethodHandler : public MethodHandler {
+ public:
+  RpcMethodHandler(std::function<Status(ServiceType*, ServerContext*,
+                                        const RequestType*, ResponseType*)>
+                       func,
+                   ServiceType* service)
+      : func_(func), service_(service) {}
+
+  void RunHandler(const HandlerParameter& param) final {
+    RequestType req;
+    Status status = SerializationTraits<RequestType>::Deserialize(
+        param.request.bbuf_ptr(), &req);
+    ResponseType rsp;
+    if (status.ok()) {
+      status = CatchingFunctionHandler([this, &param, &req, &rsp] {
+        return func_(service_, param.server_context, &req, &rsp);
+      });
+    }
+
+    GPR_CODEGEN_ASSERT(!param.server_context->sent_initial_metadata_);
+    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+              CallOpServerSendStatus>
+        ops;
+    ops.SendInitialMetadata(param.server_context->initial_metadata_,
+                            param.server_context->initial_metadata_flags());
+    if (param.server_context->compression_level_set()) {
+      ops.set_compression_level(param.server_context->compression_level());
+    }
+    if (status.ok()) {
+      status = ops.SendMessage(rsp);
+    }
+    ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
+    param.call->PerformOps(&ops);
+    param.call->cq()->Pluck(&ops);
+  }
+
+ private:
+  /// Application provided rpc handler function.
+  std::function<Status(ServiceType*, ServerContext*, const RequestType*,
+                       ResponseType*)>
+      func_;
+  // The class the above handler function lives in.
+  ServiceType* service_;
+};
+
+/// A wrapper class of an application provided client streaming handler.
+template <class ServiceType, class RequestType, class ResponseType>
+class ClientStreamingHandler : public MethodHandler {
+ public:
+  ClientStreamingHandler(
+      std::function<Status(ServiceType*, ServerContext*,
+                           ServerReader<RequestType>*, ResponseType*)>
+          func,
+      ServiceType* service)
+      : func_(func), service_(service) {}
+
+  void RunHandler(const HandlerParameter& param) final {
+    ServerReader<RequestType> reader(param.call, param.server_context);
+    ResponseType rsp;
+    Status status = CatchingFunctionHandler([this, &param, &reader, &rsp] {
+      return func_(service_, param.server_context, &reader, &rsp);
+    });
+
+    GPR_CODEGEN_ASSERT(!param.server_context->sent_initial_metadata_);
+    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+              CallOpServerSendStatus>
+        ops;
+    ops.SendInitialMetadata(param.server_context->initial_metadata_,
+                            param.server_context->initial_metadata_flags());
+    if (param.server_context->compression_level_set()) {
+      ops.set_compression_level(param.server_context->compression_level());
+    }
+    if (status.ok()) {
+      status = ops.SendMessage(rsp);
+    }
+    ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
+    param.call->PerformOps(&ops);
+    param.call->cq()->Pluck(&ops);
+  }
+
+ private:
+  std::function<Status(ServiceType*, ServerContext*, ServerReader<RequestType>*,
+                       ResponseType*)>
+      func_;
+  ServiceType* service_;
+};
+
+/// A wrapper class of an application provided server streaming handler.
+template <class ServiceType, class RequestType, class ResponseType>
+class ServerStreamingHandler : public MethodHandler {
+ public:
+  ServerStreamingHandler(
+      std::function<Status(ServiceType*, ServerContext*, const RequestType*,
+                           ServerWriter<ResponseType>*)>
+          func,
+      ServiceType* service)
+      : func_(func), service_(service) {}
+
+  void RunHandler(const HandlerParameter& param) final {
+    RequestType req;
+    Status status = SerializationTraits<RequestType>::Deserialize(
+        param.request.bbuf_ptr(), &req);
+
+    if (status.ok()) {
+      ServerWriter<ResponseType> writer(param.call, param.server_context);
+      status = CatchingFunctionHandler([this, &param, &req, &writer] {
+        return func_(service_, param.server_context, &req, &writer);
+      });
+    }
+
+    CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> ops;
+    if (!param.server_context->sent_initial_metadata_) {
+      ops.SendInitialMetadata(param.server_context->initial_metadata_,
+                              param.server_context->initial_metadata_flags());
+      if (param.server_context->compression_level_set()) {
+        ops.set_compression_level(param.server_context->compression_level());
+      }
+    }
+    ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
+    param.call->PerformOps(&ops);
+    if (param.server_context->has_pending_ops_) {
+      param.call->cq()->Pluck(&param.server_context->pending_ops_);
+    }
+    param.call->cq()->Pluck(&ops);
+  }
+
+ private:
+  std::function<Status(ServiceType*, ServerContext*, const RequestType*,
+                       ServerWriter<ResponseType>*)>
+      func_;
+  ServiceType* service_;
+};
+
+/// A wrapper class of an application provided bidi-streaming handler.
+/// This also applies to server-streamed implementation of a unary method
+/// with the additional requirement that such methods must have done a
+/// write for status to be ok
+/// Since this is used by more than 1 class, the service is not passed in.
+/// Instead, it is expected to be an implicitly-captured argument of func
+/// (through bind or something along those lines)
+template <class Streamer, bool WriteNeeded>
+class TemplatedBidiStreamingHandler : public MethodHandler {
+ public:
+  TemplatedBidiStreamingHandler(
+      std::function<Status(ServerContext*, Streamer*)> func)
+      : func_(func), write_needed_(WriteNeeded) {}
+
+  void RunHandler(const HandlerParameter& param) final {
+    Streamer stream(param.call, param.server_context);
+    Status status = CatchingFunctionHandler([this, &param, &stream] {
+      return func_(param.server_context, &stream);
+    });
+
+    CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> ops;
+    if (!param.server_context->sent_initial_metadata_) {
+      ops.SendInitialMetadata(param.server_context->initial_metadata_,
+                              param.server_context->initial_metadata_flags());
+      if (param.server_context->compression_level_set()) {
+        ops.set_compression_level(param.server_context->compression_level());
+      }
+      if (write_needed_ && status.ok()) {
+        // If we needed a write but never did one, we need to mark the
+        // status as a fail
+        status = Status(StatusCode::INTERNAL,
+                        "Service did not provide response message");
+      }
+    }
+    ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
+    param.call->PerformOps(&ops);
+    if (param.server_context->has_pending_ops_) {
+      param.call->cq()->Pluck(&param.server_context->pending_ops_);
+    }
+    param.call->cq()->Pluck(&ops);
+  }
+
+ private:
+  std::function<Status(ServerContext*, Streamer*)> func_;
+  const bool write_needed_;
+};
+
+template <class ServiceType, class RequestType, class ResponseType>
+class BidiStreamingHandler
+    : public TemplatedBidiStreamingHandler<
+          ServerReaderWriter<ResponseType, RequestType>, false> {
+ public:
+  BidiStreamingHandler(
+      std::function<Status(ServiceType*, ServerContext*,
+                           ServerReaderWriter<ResponseType, RequestType>*)>
+          func,
+      ServiceType* service)
+      : TemplatedBidiStreamingHandler<
+            ServerReaderWriter<ResponseType, RequestType>, false>(std::bind(
+            func, service, std::placeholders::_1, std::placeholders::_2)) {}
+};
+
+template <class RequestType, class ResponseType>
+class StreamedUnaryHandler
+    : public TemplatedBidiStreamingHandler<
+          ServerUnaryStreamer<RequestType, ResponseType>, true> {
+ public:
+  explicit StreamedUnaryHandler(
+      std::function<Status(ServerContext*,
+                           ServerUnaryStreamer<RequestType, ResponseType>*)>
+          func)
+      : TemplatedBidiStreamingHandler<
+            ServerUnaryStreamer<RequestType, ResponseType>, true>(func) {}
+};
+
+template <class RequestType, class ResponseType>
+class SplitServerStreamingHandler
+    : public TemplatedBidiStreamingHandler<
+          ServerSplitStreamer<RequestType, ResponseType>, false> {
+ public:
+  explicit SplitServerStreamingHandler(
+      std::function<Status(ServerContext*,
+                           ServerSplitStreamer<RequestType, ResponseType>*)>
+          func)
+      : TemplatedBidiStreamingHandler<
+            ServerSplitStreamer<RequestType, ResponseType>, false>(func) {}
+};
+
+/// Handle unknown method by returning UNIMPLEMENTED error.
+class UnknownMethodHandler : public MethodHandler {
+ public:
+  template <class T>
+  static void FillOps(ServerContext* context, T* ops) {
+    Status status(StatusCode::UNIMPLEMENTED, "");
+    if (!context->sent_initial_metadata_) {
+      ops->SendInitialMetadata(context->initial_metadata_,
+                               context->initial_metadata_flags());
+      if (context->compression_level_set()) {
+        ops->set_compression_level(context->compression_level());
+      }
+      context->sent_initial_metadata_ = true;
+    }
+    ops->ServerSendStatus(context->trailing_metadata_, status);
+  }
+
+  void RunHandler(const HandlerParameter& param) final {
+    CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> ops;
+    FillOps(param.server_context, &ops);
+    param.call->PerformOps(&ops);
+    param.call->cq()->Pluck(&ops);
+  }
+};
+
+}  // namespace internal
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_METHOD_HANDLER_IMPL_H
diff --git a/include/grpcpp/impl/codegen/proto_utils.h b/include/grpcpp/impl/codegen/proto_utils.h
new file mode 100644
index 0000000..81438ee
--- /dev/null
+++ b/include/grpcpp/impl/codegen/proto_utils.h
@@ -0,0 +1,268 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_PROTO_UTILS_H
+#define GRPCPP_IMPL_CODEGEN_PROTO_UTILS_H
+
+#include <type_traits>
+
+#include <grpc/impl/codegen/byte_buffer_reader.h>
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpc/impl/codegen/slice.h>
+#include <grpcpp/impl/codegen/config_protobuf.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/serialization_traits.h>
+#include <grpcpp/impl/codegen/status.h>
+
+namespace grpc {
+
+extern CoreCodegenInterface* g_core_codegen_interface;
+
+namespace internal {
+
+class GrpcBufferWriterPeer;
+
+const int kGrpcBufferWriterMaxBufferLength = 1024 * 1024;
+
+class GrpcBufferWriter : public ::grpc::protobuf::io::ZeroCopyOutputStream {
+ public:
+  GrpcBufferWriter(grpc_byte_buffer** bp, int block_size, int total_size)
+      : block_size_(block_size),
+        total_size_(total_size),
+        byte_count_(0),
+        have_backup_(false) {
+    *bp = g_core_codegen_interface->grpc_raw_byte_buffer_create(NULL, 0);
+    slice_buffer_ = &(*bp)->data.raw.slice_buffer;
+  }
+
+  ~GrpcBufferWriter() override {
+    if (have_backup_) {
+      g_core_codegen_interface->grpc_slice_unref(backup_slice_);
+    }
+  }
+
+  bool Next(void** data, int* size) override {
+    // Protobuf should not ask for more memory than total_size_.
+    GPR_CODEGEN_ASSERT(byte_count_ < total_size_);
+    size_t remain = total_size_ - byte_count_;
+    if (have_backup_) {
+      slice_ = backup_slice_;
+      have_backup_ = false;
+      if (GRPC_SLICE_LENGTH(slice_) > remain) {
+        GRPC_SLICE_SET_LENGTH(slice_, remain);
+      }
+    } else {
+      // When less than a whole block is needed, only allocate that much.
+      // But make sure the allocated slice is not inlined.
+      size_t allocate_length =
+          remain > static_cast<size_t>(block_size_) ? block_size_ : remain;
+      slice_ = g_core_codegen_interface->grpc_slice_malloc(
+          allocate_length > GRPC_SLICE_INLINED_SIZE
+              ? allocate_length
+              : GRPC_SLICE_INLINED_SIZE + 1);
+    }
+    *data = GRPC_SLICE_START_PTR(slice_);
+    // On win x64, int is only 32bit
+    GPR_CODEGEN_ASSERT(GRPC_SLICE_LENGTH(slice_) <= INT_MAX);
+    byte_count_ += * size = (int)GRPC_SLICE_LENGTH(slice_);
+    g_core_codegen_interface->grpc_slice_buffer_add(slice_buffer_, slice_);
+    return true;
+  }
+
+  void BackUp(int count) override {
+    g_core_codegen_interface->grpc_slice_buffer_pop(slice_buffer_);
+    if ((size_t)count == GRPC_SLICE_LENGTH(slice_)) {
+      backup_slice_ = slice_;
+    } else {
+      backup_slice_ = g_core_codegen_interface->grpc_slice_split_tail(
+          &slice_, GRPC_SLICE_LENGTH(slice_) - count);
+      g_core_codegen_interface->grpc_slice_buffer_add(slice_buffer_, slice_);
+    }
+    // It's dangerous to keep an inlined grpc_slice as the backup slice, since
+    // on a following Next() call, a reference will be returned to this slice
+    // via GRPC_SLICE_START_PTR, which will not be an adddress held by
+    // slice_buffer_.
+    have_backup_ = backup_slice_.refcount != NULL;
+    byte_count_ -= count;
+  }
+
+  grpc::protobuf::int64 ByteCount() const override { return byte_count_; }
+
+ protected:
+  friend class GrpcBufferWriterPeer;
+  const int block_size_;
+  const int total_size_;
+  int64_t byte_count_;
+  grpc_slice_buffer* slice_buffer_;
+  bool have_backup_;
+  grpc_slice backup_slice_;
+  grpc_slice slice_;
+};
+
+class GrpcBufferReader : public ::grpc::protobuf::io::ZeroCopyInputStream {
+ public:
+  explicit GrpcBufferReader(grpc_byte_buffer* buffer)
+      : byte_count_(0), backup_count_(0), status_() {
+    if (!g_core_codegen_interface->grpc_byte_buffer_reader_init(&reader_,
+                                                                buffer)) {
+      status_ = Status(StatusCode::INTERNAL,
+                       "Couldn't initialize byte buffer reader");
+    }
+  }
+  ~GrpcBufferReader() override {
+    g_core_codegen_interface->grpc_byte_buffer_reader_destroy(&reader_);
+  }
+
+  bool Next(const void** data, int* size) override {
+    if (!status_.ok()) {
+      return false;
+    }
+    if (backup_count_ > 0) {
+      *data = GRPC_SLICE_START_PTR(slice_) + GRPC_SLICE_LENGTH(slice_) -
+              backup_count_;
+      GPR_CODEGEN_ASSERT(backup_count_ <= INT_MAX);
+      *size = (int)backup_count_;
+      backup_count_ = 0;
+      return true;
+    }
+    if (!g_core_codegen_interface->grpc_byte_buffer_reader_next(&reader_,
+                                                                &slice_)) {
+      return false;
+    }
+    g_core_codegen_interface->grpc_slice_unref(slice_);
+    *data = GRPC_SLICE_START_PTR(slice_);
+    // On win x64, int is only 32bit
+    GPR_CODEGEN_ASSERT(GRPC_SLICE_LENGTH(slice_) <= INT_MAX);
+    byte_count_ += * size = (int)GRPC_SLICE_LENGTH(slice_);
+    return true;
+  }
+
+  Status status() const { return status_; }
+
+  void BackUp(int count) override { backup_count_ = count; }
+
+  bool Skip(int count) override {
+    const void* data;
+    int size;
+    while (Next(&data, &size)) {
+      if (size >= count) {
+        BackUp(size - count);
+        return true;
+      }
+      // size < count;
+      count -= size;
+    }
+    // error or we have too large count;
+    return false;
+  }
+
+  grpc::protobuf::int64 ByteCount() const override {
+    return byte_count_ - backup_count_;
+  }
+
+ protected:
+  int64_t byte_count_;
+  int64_t backup_count_;
+  grpc_byte_buffer_reader reader_;
+  grpc_slice slice_;
+  Status status_;
+};
+
+// BufferWriter must be a subclass of io::ZeroCopyOutputStream.
+template <class BufferWriter, class T>
+Status GenericSerialize(const grpc::protobuf::Message& msg,
+                        grpc_byte_buffer** bp, bool* own_buffer) {
+  static_assert(
+      std::is_base_of<protobuf::io::ZeroCopyOutputStream, BufferWriter>::value,
+      "BufferWriter must be a subclass of io::ZeroCopyOutputStream");
+  *own_buffer = true;
+  int byte_size = msg.ByteSize();
+  if ((size_t)byte_size <= GRPC_SLICE_INLINED_SIZE) {
+    grpc_slice slice = g_core_codegen_interface->grpc_slice_malloc(byte_size);
+    GPR_CODEGEN_ASSERT(
+        GRPC_SLICE_END_PTR(slice) ==
+        msg.SerializeWithCachedSizesToArray(GRPC_SLICE_START_PTR(slice)));
+    *bp = g_core_codegen_interface->grpc_raw_byte_buffer_create(&slice, 1);
+    g_core_codegen_interface->grpc_slice_unref(slice);
+
+    return g_core_codegen_interface->ok();
+  }
+  BufferWriter writer(bp, kGrpcBufferWriterMaxBufferLength, byte_size);
+  return msg.SerializeToZeroCopyStream(&writer)
+             ? g_core_codegen_interface->ok()
+             : Status(StatusCode::INTERNAL, "Failed to serialize message");
+}
+
+// BufferReader must be a subclass of io::ZeroCopyInputStream.
+template <class BufferReader, class T>
+Status GenericDeserialize(grpc_byte_buffer* buffer,
+                          grpc::protobuf::Message* msg) {
+  static_assert(
+      std::is_base_of<protobuf::io::ZeroCopyInputStream, BufferReader>::value,
+      "BufferReader must be a subclass of io::ZeroCopyInputStream");
+  if (buffer == nullptr) {
+    return Status(StatusCode::INTERNAL, "No payload");
+  }
+  Status result = g_core_codegen_interface->ok();
+  {
+    BufferReader reader(buffer);
+    if (!reader.status().ok()) {
+      return reader.status();
+    }
+    ::grpc::protobuf::io::CodedInputStream decoder(&reader);
+    decoder.SetTotalBytesLimit(INT_MAX, INT_MAX);
+    if (!msg->ParseFromCodedStream(&decoder)) {
+      result = Status(StatusCode::INTERNAL, msg->InitializationErrorString());
+    }
+    if (!decoder.ConsumedEntireMessage()) {
+      result = Status(StatusCode::INTERNAL, "Did not read entire message");
+    }
+  }
+  g_core_codegen_interface->grpc_byte_buffer_destroy(buffer);
+  return result;
+}
+
+}  // namespace internal
+
+// this is needed so the following class does not conflict with protobuf
+// serializers that utilize internal-only tools.
+#ifdef GRPC_OPEN_SOURCE_PROTO
+// This class provides a protobuf serializer. It translates between protobuf
+// objects and grpc_byte_buffers. More information about SerializationTraits can
+// be found in include/grpcpp/impl/codegen/serialization_traits.h.
+template <class T>
+class SerializationTraits<T, typename std::enable_if<std::is_base_of<
+                                 grpc::protobuf::Message, T>::value>::type> {
+ public:
+  static Status Serialize(const grpc::protobuf::Message& msg,
+                          grpc_byte_buffer** bp, bool* own_buffer) {
+    return internal::GenericSerialize<internal::GrpcBufferWriter, T>(
+        msg, bp, own_buffer);
+  }
+
+  static Status Deserialize(grpc_byte_buffer* buffer,
+                            grpc::protobuf::Message* msg) {
+    return internal::GenericDeserialize<internal::GrpcBufferReader, T>(buffer,
+                                                                       msg);
+  }
+};
+#endif
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_PROTO_UTILS_H
diff --git a/include/grpcpp/impl/codegen/rpc_method.h b/include/grpcpp/impl/codegen/rpc_method.h
new file mode 100644
index 0000000..9dcde95
--- /dev/null
+++ b/include/grpcpp/impl/codegen/rpc_method.h
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_RPC_METHOD_H
+#define GRPCPP_IMPL_CODEGEN_RPC_METHOD_H
+
+#include <memory>
+
+#include <grpcpp/impl/codegen/channel_interface.h>
+
+namespace grpc {
+namespace internal {
+/// Descriptor of an RPC method
+class RpcMethod {
+ public:
+  enum RpcType {
+    NORMAL_RPC = 0,
+    CLIENT_STREAMING,  // request streaming
+    SERVER_STREAMING,  // response streaming
+    BIDI_STREAMING
+  };
+
+  RpcMethod(const char* name, RpcType type)
+      : name_(name), method_type_(type), channel_tag_(NULL) {}
+
+  RpcMethod(const char* name, RpcType type,
+            const std::shared_ptr<ChannelInterface>& channel)
+      : name_(name),
+        method_type_(type),
+        channel_tag_(channel->RegisterMethod(name)) {}
+
+  const char* name() const { return name_; }
+  RpcType method_type() const { return method_type_; }
+  void SetMethodType(RpcType type) { method_type_ = type; }
+  void* channel_tag() const { return channel_tag_; }
+
+ private:
+  const char* const name_;
+  RpcType method_type_;
+  void* const channel_tag_;
+};
+
+}  // namespace internal
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_RPC_METHOD_H
diff --git a/include/grpcpp/impl/codegen/rpc_service_method.h b/include/grpcpp/impl/codegen/rpc_service_method.h
new file mode 100644
index 0000000..dd85405
--- /dev/null
+++ b/include/grpcpp/impl/codegen/rpc_service_method.h
@@ -0,0 +1,78 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_RPC_SERVICE_METHOD_H
+#define GRPCPP_IMPL_CODEGEN_RPC_SERVICE_METHOD_H
+
+#include <climits>
+#include <functional>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include <grpcpp/impl/codegen/byte_buffer.h>
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/rpc_method.h>
+#include <grpcpp/impl/codegen/status.h>
+
+namespace grpc {
+class ServerContext;
+
+namespace internal {
+/// Base class for running an RPC handler.
+class MethodHandler {
+ public:
+  virtual ~MethodHandler() {}
+  struct HandlerParameter {
+    HandlerParameter(Call* c, ServerContext* context, grpc_byte_buffer* req)
+        : call(c), server_context(context) {
+      request.set_buffer(req);
+    }
+    ~HandlerParameter() { request.Release(); }
+    Call* call;
+    ServerContext* server_context;
+    // Handler required to destroy these contents
+    ByteBuffer request;
+  };
+  virtual void RunHandler(const HandlerParameter& param) = 0;
+};
+
+/// Server side rpc method class
+class RpcServiceMethod : public RpcMethod {
+ public:
+  /// Takes ownership of the handler
+  RpcServiceMethod(const char* name, RpcMethod::RpcType type,
+                   MethodHandler* handler)
+      : RpcMethod(name, type), server_tag_(nullptr), handler_(handler) {}
+
+  void set_server_tag(void* tag) { server_tag_ = tag; }
+  void* server_tag() const { return server_tag_; }
+  /// if MethodHandler is nullptr, then this is an async method
+  MethodHandler* handler() const { return handler_.get(); }
+  void ResetHandler() { handler_.reset(); }
+  void SetHandler(MethodHandler* handler) { handler_.reset(handler); }
+
+ private:
+  void* server_tag_;
+  std::unique_ptr<MethodHandler> handler_;
+};
+}  // namespace internal
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_RPC_SERVICE_METHOD_H
diff --git a/include/grpcpp/impl/codegen/security/auth_context.h b/include/grpcpp/impl/codegen/security/auth_context.h
new file mode 100644
index 0000000..0e30f7c
--- /dev/null
+++ b/include/grpcpp/impl/codegen/security/auth_context.h
@@ -0,0 +1,95 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_SECURITY_AUTH_CONTEXT_H
+#define GRPCPP_IMPL_CODEGEN_SECURITY_AUTH_CONTEXT_H
+
+#include <iterator>
+#include <vector>
+
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/string_ref.h>
+
+struct grpc_auth_context;
+struct grpc_auth_property;
+struct grpc_auth_property_iterator;
+
+namespace grpc {
+class SecureAuthContext;
+
+typedef std::pair<grpc::string_ref, grpc::string_ref> AuthProperty;
+
+class AuthPropertyIterator
+    : public std::iterator<std::input_iterator_tag, const AuthProperty> {
+ public:
+  ~AuthPropertyIterator();
+  AuthPropertyIterator& operator++();
+  AuthPropertyIterator operator++(int);
+  bool operator==(const AuthPropertyIterator& rhs) const;
+  bool operator!=(const AuthPropertyIterator& rhs) const;
+  const AuthProperty operator*();
+
+ protected:
+  AuthPropertyIterator();
+  AuthPropertyIterator(const grpc_auth_property* property,
+                       const grpc_auth_property_iterator* iter);
+
+ private:
+  friend class SecureAuthContext;
+  const grpc_auth_property* property_;
+  // The following items form a grpc_auth_property_iterator.
+  const grpc_auth_context* ctx_;
+  size_t index_;
+  const char* name_;
+};
+
+/// Class encapsulating the Authentication Information.
+///
+/// It includes the secure identity of the peer, the type of secure transport
+/// used as well as any other properties required by the authorization layer.
+class AuthContext {
+ public:
+  virtual ~AuthContext() {}
+
+  /// Returns true if the peer is authenticated.
+  virtual bool IsPeerAuthenticated() const = 0;
+
+  /// A peer identity.
+  ///
+  /// It is, in general, comprised of one or more properties (in which case they
+  /// have the same name).
+  virtual std::vector<grpc::string_ref> GetPeerIdentity() const = 0;
+  virtual grpc::string GetPeerIdentityPropertyName() const = 0;
+
+  /// Returns all the property values with the given name.
+  virtual std::vector<grpc::string_ref> FindPropertyValues(
+      const grpc::string& name) const = 0;
+
+  /// Iteration over all the properties.
+  virtual AuthPropertyIterator begin() const = 0;
+  virtual AuthPropertyIterator end() const = 0;
+
+  /// Mutation functions: should only be used by an AuthMetadataProcessor.
+  virtual void AddProperty(const grpc::string& key,
+                           const grpc::string_ref& value) = 0;
+  virtual bool SetPeerIdentityPropertyName(const grpc::string& name) = 0;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_SECURITY_AUTH_CONTEXT_H
diff --git a/include/grpcpp/impl/codegen/serialization_traits.h b/include/grpcpp/impl/codegen/serialization_traits.h
new file mode 100644
index 0000000..8f79223
--- /dev/null
+++ b/include/grpcpp/impl/codegen/serialization_traits.h
@@ -0,0 +1,62 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_SERIALIZATION_TRAITS_H
+#define GRPCPP_IMPL_CODEGEN_SERIALIZATION_TRAITS_H
+
+namespace grpc {
+
+/// Defines how to serialize and deserialize some type.
+///
+/// Used for hooking different message serialization API's into GRPC.
+/// Each SerializationTraits<Message> implementation must provide the
+/// following functions:
+/// 1.  static Status Serialize(const Message& msg,
+///                             ByteBuffer* buffer,
+///                             bool* own_buffer);
+///     OR
+///     static Status Serialize(const Message& msg,
+///                             grpc_byte_buffer** buffer,
+///                             bool* own_buffer);
+///     The former is preferred; the latter is deprecated
+///
+/// 2.  static Status Deserialize(ByteBuffer* buffer,
+///                               Message* msg);
+///     OR
+///     static Status Deserialize(grpc_byte_buffer* buffer,
+///                               Message* msg);
+///     The former is preferred; the latter is deprecated
+///
+/// Serialize is required to convert message to a ByteBuffer, and
+/// return that byte buffer through *buffer. *own_buffer should
+/// be set to true if the caller owns said byte buffer, or false if
+/// ownership is retained elsewhere.
+///
+/// Deserialize is required to convert buffer into the message stored at
+/// msg. max_receive_message_size is passed in as a bound on the maximum
+/// number of message bytes Deserialize should accept.
+///
+/// Both functions return a Status, allowing them to explain what went
+/// wrong if required.
+template <class Message,
+          class UnusedButHereForPartialTemplateSpecialization = void>
+class SerializationTraits;
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_SERIALIZATION_TRAITS_H
diff --git a/include/grpcpp/impl/codegen/server_context.h b/include/grpcpp/impl/codegen/server_context.h
new file mode 100644
index 0000000..bb357d6
--- /dev/null
+++ b/include/grpcpp/impl/codegen/server_context.h
@@ -0,0 +1,309 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_H
+#define GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_H
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include <grpc/impl/codegen/compression_types.h>
+
+#include <grpcpp/impl/codegen/call.h>
+#include <grpcpp/impl/codegen/completion_queue_tag.h>
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/create_auth_context.h>
+#include <grpcpp/impl/codegen/metadata_map.h>
+#include <grpcpp/impl/codegen/security/auth_context.h>
+#include <grpcpp/impl/codegen/string_ref.h>
+#include <grpcpp/impl/codegen/time.h>
+
+struct grpc_metadata;
+struct grpc_call;
+struct census_context;
+
+namespace grpc {
+class ClientContext;
+template <class W, class R>
+class ServerAsyncReader;
+template <class W>
+class ServerAsyncWriter;
+template <class W>
+class ServerAsyncResponseWriter;
+template <class W, class R>
+class ServerAsyncReaderWriter;
+template <class R>
+class ServerReader;
+template <class W>
+class ServerWriter;
+namespace internal {
+template <class W, class R>
+class ServerReaderWriterBody;
+template <class ServiceType, class RequestType, class ResponseType>
+class RpcMethodHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class ClientStreamingHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class ServerStreamingHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class BidiStreamingHandler;
+class UnknownMethodHandler;
+template <class Streamer, bool WriteNeeded>
+class TemplatedBidiStreamingHandler;
+class Call;
+}  // namespace internal
+
+class CompletionQueue;
+class Server;
+class ServerInterface;
+
+namespace testing {
+class InteropServerContextInspector;
+class ServerContextTestSpouse;
+}  // namespace testing
+
+/// A ServerContext allows the person implementing a service handler to:
+///
+/// - Add custom initial and trailing metadata key-value pairs that will
+///   propagated to the client side.
+/// - Control call settings such as compression and authentication.
+/// - Access metadata coming from the client.
+/// - Get performance metrics (ie, census).
+///
+/// Context settings are only relevant to the call handler they are supplied to,
+/// that is to say, they aren't sticky across multiple calls. Some of these
+/// settings, such as the compression options, can be made persistant at server
+/// construction time by specifying the approriate \a ChannelArguments
+/// to a \a grpc::ServerBuilder, via \a ServerBuilder::AddChannelArgument.
+///
+/// \warning ServerContext instances should \em not be reused across rpcs.
+class ServerContext {
+ public:
+  ServerContext();  // for async calls
+  ~ServerContext();
+
+  /// Return the deadline for the server call.
+  std::chrono::system_clock::time_point deadline() const {
+    return Timespec2Timepoint(deadline_);
+  }
+
+  /// Return a \a gpr_timespec representation of the server call's deadline.
+  gpr_timespec raw_deadline() const { return deadline_; }
+
+  /// Add the (\a meta_key, \a meta_value) pair to the initial metadata
+  /// associated with a server call. These are made available at the client side
+  /// by the \a grpc::ClientContext::GetServerInitialMetadata() method.
+  ///
+  /// \warning This method should only be called before sending initial metadata
+  /// to the client (which can happen explicitly, or implicitly when sending a
+  /// a response message or status to the client).
+  ///
+  /// \param meta_key The metadata key. If \a meta_value is binary data, it must
+  /// end in "-bin".
+  /// \param meta_value The metadata value. If its value is binary, the key name
+  /// must end in "-bin".
+  void AddInitialMetadata(const grpc::string& key, const grpc::string& value);
+
+  /// Add the (\a meta_key, \a meta_value) pair to the initial metadata
+  /// associated with a server call. These are made available at the client
+  /// side by the \a grpc::ClientContext::GetServerTrailingMetadata() method.
+  ///
+  /// \warning This method should only be called before sending trailing
+  /// metadata to the client (which happens when the call is finished and a
+  /// status is sent to the client).
+  ///
+  /// \param meta_key The metadata key. If \a meta_value is binary data,
+  /// it must end in "-bin".
+  /// \param meta_value The metadata value. If its value is binary, the key name
+  /// must end in "-bin".
+  void AddTrailingMetadata(const grpc::string& key, const grpc::string& value);
+
+  /// IsCancelled is always safe to call when using sync API.
+  /// When using async API, it is only safe to call IsCancelled after
+  /// the AsyncNotifyWhenDone tag has been delivered.
+  bool IsCancelled() const;
+
+  /// Cancel the Call from the server. This is a best-effort API and
+  /// depending on when it is called, the RPC may still appear successful to
+  /// the client.
+  /// For example, if TryCancel() is called on a separate thread, it might race
+  /// with the server handler which might return success to the client before
+  /// TryCancel() was even started by the thread.
+  ///
+  /// It is the caller's responsibility to prevent such races and ensure that if
+  /// TryCancel() is called, the serverhandler must return Status::CANCELLED.
+  /// The only exception is that if the serverhandler is already returning an
+  /// error status code, it is ok to not return Status::CANCELLED even if
+  /// TryCancel() was called.
+  ///
+  /// Note that TryCancel() does not change any of the tags that are pending
+  /// on the completion queue. All pending tags will still be delivered
+  /// (though their ok result may reflect the effect of cancellation).
+  void TryCancel() const;
+
+  /// Return a collection of initial metadata key-value pairs sent from the
+  /// client. Note that keys may happen more than
+  /// once (ie, a \a std::multimap is returned).
+  ///
+  /// It is safe to use this method after initial metadata has been received,
+  /// Calls always begin with the client sending initial metadata, so this is
+  /// safe to access as soon as the call has begun on the server side.
+  ///
+  /// \return A multimap of initial metadata key-value pairs from the server.
+  const std::multimap<grpc::string_ref, grpc::string_ref>& client_metadata()
+      const {
+    return *client_metadata_.map();
+  }
+
+  /// Return the compression algorithm to be used by the server call.
+  grpc_compression_level compression_level() const {
+    return compression_level_;
+  }
+
+  /// Set \a algorithm to be the compression algorithm used for the server call.
+  ///
+  /// \param algorithm The compression algorithm used for the server call.
+  void set_compression_level(grpc_compression_level level) {
+    compression_level_set_ = true;
+    compression_level_ = level;
+  }
+
+  /// Return a bool indicating whether the compression level for this call
+  /// has been set (either implicitly or through a previous call to
+  /// \a set_compression_level.
+  bool compression_level_set() const { return compression_level_set_; }
+
+  /// Return the compression algorithm the server call will request be used.
+  /// Note that the gRPC runtime may decide to ignore this request, for example,
+  /// due to resource constraints, or if the server is aware the client doesn't
+  /// support the requested algorithm.
+  grpc_compression_algorithm compression_algorithm() const {
+    return compression_algorithm_;
+  }
+  /// Set \a algorithm to be the compression algorithm used for the server call.
+  ///
+  /// \param algorithm The compression algorithm used for the server call.
+  void set_compression_algorithm(grpc_compression_algorithm algorithm);
+
+  /// Set the load reporting costs in \a cost_data for the call.
+  void SetLoadReportingCosts(const std::vector<grpc::string>& cost_data);
+
+  /// Return the authentication context for this server call.
+  ///
+  /// \see grpc::AuthContext.
+  std::shared_ptr<const AuthContext> auth_context() const {
+    if (auth_context_.get() == nullptr) {
+      auth_context_ = CreateAuthContext(call_);
+    }
+    return auth_context_;
+  }
+
+  /// Return the peer uri in a string.
+  /// WARNING: this value is never authenticated or subject to any security
+  /// related code. It must not be used for any authentication related
+  /// functionality. Instead, use auth_context.
+  grpc::string peer() const;
+
+  /// Get the census context associated with this server call.
+  const struct census_context* census_context() const;
+
+  /// Async only. Has to be called before the rpc starts.
+  /// Returns the tag in completion queue when the rpc finishes.
+  /// IsCancelled() can then be called to check whether the rpc was cancelled.
+  void AsyncNotifyWhenDone(void* tag) {
+    has_notify_when_done_tag_ = true;
+    async_notify_when_done_tag_ = tag;
+  }
+
+  /// Should be used for framework-level extensions only.
+  /// Applications never need to call this method.
+  grpc_call* c_call() { return call_; }
+
+ private:
+  friend class ::grpc::testing::InteropServerContextInspector;
+  friend class ::grpc::testing::ServerContextTestSpouse;
+  friend class ::grpc::ServerInterface;
+  friend class ::grpc::Server;
+  template <class W, class R>
+  friend class ::grpc::ServerAsyncReader;
+  template <class W>
+  friend class ::grpc::ServerAsyncWriter;
+  template <class W>
+  friend class ::grpc::ServerAsyncResponseWriter;
+  template <class W, class R>
+  friend class ::grpc::ServerAsyncReaderWriter;
+  template <class R>
+  friend class ::grpc::ServerReader;
+  template <class W>
+  friend class ::grpc::ServerWriter;
+  template <class W, class R>
+  friend class ::grpc::internal::ServerReaderWriterBody;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class ::grpc::internal::RpcMethodHandler;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class ::grpc::internal::ClientStreamingHandler;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class ::grpc::internal::ServerStreamingHandler;
+  template <class Streamer, bool WriteNeeded>
+  friend class ::grpc::internal::TemplatedBidiStreamingHandler;
+  friend class ::grpc::internal::UnknownMethodHandler;
+  friend class ::grpc::ClientContext;
+
+  /// Prevent copying.
+  ServerContext(const ServerContext&);
+  ServerContext& operator=(const ServerContext&);
+
+  class CompletionOp;
+
+  void BeginCompletionOp(internal::Call* call);
+  /// Return the tag queued by BeginCompletionOp()
+  internal::CompletionQueueTag* GetCompletionOpTag();
+
+  ServerContext(gpr_timespec deadline, grpc_metadata_array* arr);
+
+  void set_call(grpc_call* call) { call_ = call; }
+
+  uint32_t initial_metadata_flags() const { return 0; }
+
+  CompletionOp* completion_op_;
+  bool has_notify_when_done_tag_;
+  void* async_notify_when_done_tag_;
+
+  gpr_timespec deadline_;
+  grpc_call* call_;
+  CompletionQueue* cq_;
+  bool sent_initial_metadata_;
+  mutable std::shared_ptr<const AuthContext> auth_context_;
+  internal::MetadataMap client_metadata_;
+  std::multimap<grpc::string, grpc::string> initial_metadata_;
+  std::multimap<grpc::string, grpc::string> trailing_metadata_;
+
+  bool compression_level_set_;
+  grpc_compression_level compression_level_;
+  grpc_compression_algorithm compression_algorithm_;
+
+  internal::CallOpSet<internal::CallOpSendInitialMetadata,
+                      internal::CallOpSendMessage>
+      pending_ops_;
+  bool has_pending_ops_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_H
diff --git a/include/grpcpp/impl/codegen/server_interface.h b/include/grpcpp/impl/codegen/server_interface.h
new file mode 100644
index 0000000..4700763
--- /dev/null
+++ b/include/grpcpp/impl/codegen/server_interface.h
@@ -0,0 +1,274 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_SERVER_INTERFACE_H
+#define GRPCPP_IMPL_CODEGEN_SERVER_INTERFACE_H
+
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpcpp/impl/codegen/call_hook.h>
+#include <grpcpp/impl/codegen/completion_queue_tag.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/rpc_service_method.h>
+
+namespace grpc {
+
+class AsyncGenericService;
+class Channel;
+class GenericServerContext;
+class ServerCompletionQueue;
+class ServerContext;
+class ServerCredentials;
+class Service;
+
+extern CoreCodegenInterface* g_core_codegen_interface;
+
+/// Models a gRPC server.
+///
+/// Servers are configured and started via \a grpc::ServerBuilder.
+namespace internal {
+class ServerAsyncStreamingInterface;
+}  // namespace internal
+
+class ServerInterface : public internal::CallHook {
+ public:
+  virtual ~ServerInterface() {}
+
+  /// Shutdown the server, blocking until all rpc processing finishes.
+  /// Forcefully terminate pending calls after \a deadline expires.
+  ///
+  /// All completion queue associated with the server (for example, for async
+  /// serving) must be shutdown *after* this method has returned:
+  /// See \a ServerBuilder::AddCompletionQueue for details.
+  ///
+  /// \param deadline How long to wait until pending rpcs are forcefully
+  /// terminated.
+  template <class T>
+  void Shutdown(const T& deadline) {
+    ShutdownInternal(TimePoint<T>(deadline).raw_time());
+  }
+
+  /// Shutdown the server, waiting for all rpc processing to finish.
+  ///
+  /// All completion queue associated with the server (for example, for async
+  /// serving) must be shutdown *after* this method has returned:
+  /// See \a ServerBuilder::AddCompletionQueue for details.
+  void Shutdown() {
+    ShutdownInternal(
+        g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_MONOTONIC));
+  }
+
+  /// Block waiting for all work to complete.
+  ///
+  /// \warning The server must be either shutting down or some other thread must
+  /// call \a Shutdown for this function to ever return.
+  virtual void Wait() = 0;
+
+ protected:
+  friend class ::grpc::Service;
+
+  /// Register a service. This call does not take ownership of the service.
+  /// The service must exist for the lifetime of the Server instance.
+  virtual bool RegisterService(const grpc::string* host, Service* service) = 0;
+
+  /// Register a generic service. This call does not take ownership of the
+  /// service. The service must exist for the lifetime of the Server instance.
+  virtual void RegisterAsyncGenericService(AsyncGenericService* service) = 0;
+
+  /// Tries to bind \a server to the given \a addr.
+  ///
+  /// It can be invoked multiple times.
+  ///
+  /// \param addr The address to try to bind to the server (eg, localhost:1234,
+  /// 192.168.1.1:31416, [::1]:27182, etc.).
+  /// \params creds The credentials associated with the server.
+  ///
+  /// \return bound port number on sucess, 0 on failure.
+  ///
+  /// \warning It's an error to call this method on an already started server.
+  virtual int AddListeningPort(const grpc::string& addr,
+                               ServerCredentials* creds) = 0;
+
+  /// Start the server.
+  ///
+  /// \param cqs Completion queues for handling asynchronous services. The
+  /// caller is required to keep all completion queues live until the server is
+  /// destroyed.
+  /// \param num_cqs How many completion queues does \a cqs hold.
+  virtual void Start(ServerCompletionQueue** cqs, size_t num_cqs) = 0;
+
+  virtual void ShutdownInternal(gpr_timespec deadline) = 0;
+
+  virtual int max_receive_message_size() const = 0;
+
+  virtual grpc_server* server() = 0;
+
+  virtual void PerformOpsOnCall(internal::CallOpSetInterface* ops,
+                                internal::Call* call) = 0;
+
+  class BaseAsyncRequest : public internal::CompletionQueueTag {
+   public:
+    BaseAsyncRequest(ServerInterface* server, ServerContext* context,
+                     internal::ServerAsyncStreamingInterface* stream,
+                     CompletionQueue* call_cq, void* tag,
+                     bool delete_on_finalize);
+    virtual ~BaseAsyncRequest();
+
+    bool FinalizeResult(void** tag, bool* status) override;
+
+   protected:
+    ServerInterface* const server_;
+    ServerContext* const context_;
+    internal::ServerAsyncStreamingInterface* const stream_;
+    CompletionQueue* const call_cq_;
+    void* const tag_;
+    const bool delete_on_finalize_;
+    grpc_call* call_;
+  };
+
+  class RegisteredAsyncRequest : public BaseAsyncRequest {
+   public:
+    RegisteredAsyncRequest(ServerInterface* server, ServerContext* context,
+                           internal::ServerAsyncStreamingInterface* stream,
+                           CompletionQueue* call_cq, void* tag);
+
+    // uses BaseAsyncRequest::FinalizeResult
+
+   protected:
+    void IssueRequest(void* registered_method, grpc_byte_buffer** payload,
+                      ServerCompletionQueue* notification_cq);
+  };
+
+  class NoPayloadAsyncRequest final : public RegisteredAsyncRequest {
+   public:
+    NoPayloadAsyncRequest(void* registered_method, ServerInterface* server,
+                          ServerContext* context,
+                          internal::ServerAsyncStreamingInterface* stream,
+                          CompletionQueue* call_cq,
+                          ServerCompletionQueue* notification_cq, void* tag)
+        : RegisteredAsyncRequest(server, context, stream, call_cq, tag) {
+      IssueRequest(registered_method, nullptr, notification_cq);
+    }
+
+    // uses RegisteredAsyncRequest::FinalizeResult
+  };
+
+  template <class Message>
+  class PayloadAsyncRequest final : public RegisteredAsyncRequest {
+   public:
+    PayloadAsyncRequest(void* registered_method, ServerInterface* server,
+                        ServerContext* context,
+                        internal::ServerAsyncStreamingInterface* stream,
+                        CompletionQueue* call_cq,
+                        ServerCompletionQueue* notification_cq, void* tag,
+                        Message* request)
+        : RegisteredAsyncRequest(server, context, stream, call_cq, tag),
+          registered_method_(registered_method),
+          server_(server),
+          context_(context),
+          stream_(stream),
+          call_cq_(call_cq),
+          notification_cq_(notification_cq),
+          tag_(tag),
+          request_(request) {
+      IssueRequest(registered_method, &payload_, notification_cq);
+    }
+
+    bool FinalizeResult(void** tag, bool* status) override {
+      if (*status) {
+        if (payload_ == nullptr ||
+            !SerializationTraits<Message>::Deserialize(payload_, request_)
+                 .ok()) {
+          // If deserialization fails, we cancel the call and instantiate
+          // a new instance of ourselves to request another call.  We then
+          // return false, which prevents the call from being returned to
+          // the application.
+          g_core_codegen_interface->grpc_call_cancel_with_status(
+              call_, GRPC_STATUS_INTERNAL, "Unable to parse request", nullptr);
+          g_core_codegen_interface->grpc_call_unref(call_);
+          new PayloadAsyncRequest(registered_method_, server_, context_,
+                                  stream_, call_cq_, notification_cq_, tag_,
+                                  request_);
+          delete this;
+          return false;
+        }
+      }
+      return RegisteredAsyncRequest::FinalizeResult(tag, status);
+    }
+
+   private:
+    void* const registered_method_;
+    ServerInterface* const server_;
+    ServerContext* const context_;
+    internal::ServerAsyncStreamingInterface* const stream_;
+    CompletionQueue* const call_cq_;
+    ServerCompletionQueue* const notification_cq_;
+    void* const tag_;
+    Message* const request_;
+    grpc_byte_buffer* payload_;
+  };
+
+  class GenericAsyncRequest : public BaseAsyncRequest {
+   public:
+    GenericAsyncRequest(ServerInterface* server, GenericServerContext* context,
+                        internal::ServerAsyncStreamingInterface* stream,
+                        CompletionQueue* call_cq,
+                        ServerCompletionQueue* notification_cq, void* tag,
+                        bool delete_on_finalize);
+
+    bool FinalizeResult(void** tag, bool* status) override;
+
+   private:
+    grpc_call_details call_details_;
+  };
+
+  template <class Message>
+  void RequestAsyncCall(internal::RpcServiceMethod* method,
+                        ServerContext* context,
+                        internal::ServerAsyncStreamingInterface* stream,
+                        CompletionQueue* call_cq,
+                        ServerCompletionQueue* notification_cq, void* tag,
+                        Message* message) {
+    GPR_CODEGEN_ASSERT(method);
+    new PayloadAsyncRequest<Message>(method->server_tag(), this, context,
+                                     stream, call_cq, notification_cq, tag,
+                                     message);
+  }
+
+  void RequestAsyncCall(internal::RpcServiceMethod* method,
+                        ServerContext* context,
+                        internal::ServerAsyncStreamingInterface* stream,
+                        CompletionQueue* call_cq,
+                        ServerCompletionQueue* notification_cq, void* tag) {
+    GPR_CODEGEN_ASSERT(method);
+    new NoPayloadAsyncRequest(method->server_tag(), this, context, stream,
+                              call_cq, notification_cq, tag);
+  }
+
+  void RequestAsyncGenericCall(GenericServerContext* context,
+                               internal::ServerAsyncStreamingInterface* stream,
+                               CompletionQueue* call_cq,
+                               ServerCompletionQueue* notification_cq,
+                               void* tag) {
+    new GenericAsyncRequest(this, context, stream, call_cq, notification_cq,
+                            tag, true);
+  }
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_SERVER_INTERFACE_H
diff --git a/include/grpcpp/impl/codegen/service_type.h b/include/grpcpp/impl/codegen/service_type.h
new file mode 100644
index 0000000..a576f66
--- /dev/null
+++ b/include/grpcpp/impl/codegen/service_type.h
@@ -0,0 +1,163 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_SERVICE_TYPE_H
+#define GRPCPP_IMPL_CODEGEN_SERVICE_TYPE_H
+
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/rpc_service_method.h>
+#include <grpcpp/impl/codegen/serialization_traits.h>
+#include <grpcpp/impl/codegen/server_interface.h>
+#include <grpcpp/impl/codegen/status.h>
+
+namespace grpc {
+
+class CompletionQueue;
+class Server;
+class ServerInterface;
+class ServerCompletionQueue;
+class ServerContext;
+
+namespace internal {
+class Call;
+class ServerAsyncStreamingInterface {
+ public:
+  virtual ~ServerAsyncStreamingInterface() {}
+
+  /// Request notification of the sending of initial metadata to the client.
+  /// Completion will be notified by \a tag on the associated completion
+  /// queue. This call is optional, but if it is used, it cannot be used
+  /// concurrently with or after the \a Finish method.
+  ///
+  /// \param[in] tag Tag identifying this request.
+  virtual void SendInitialMetadata(void* tag) = 0;
+
+ private:
+  friend class ::grpc::ServerInterface;
+  virtual void BindCall(Call* call) = 0;
+};
+}  // namespace internal
+
+/// Desriptor of an RPC service and its various RPC methods
+class Service {
+ public:
+  Service() : server_(nullptr) {}
+  virtual ~Service() {}
+
+  bool has_async_methods() const {
+    for (auto it = methods_.begin(); it != methods_.end(); ++it) {
+      if (*it && (*it)->handler() == nullptr) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  bool has_synchronous_methods() const {
+    for (auto it = methods_.begin(); it != methods_.end(); ++it) {
+      if (*it && (*it)->handler() != nullptr) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  bool has_generic_methods() const {
+    for (auto it = methods_.begin(); it != methods_.end(); ++it) {
+      if (it->get() == nullptr) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+ protected:
+  template <class Message>
+  void RequestAsyncUnary(int index, ServerContext* context, Message* request,
+                         internal::ServerAsyncStreamingInterface* stream,
+                         CompletionQueue* call_cq,
+                         ServerCompletionQueue* notification_cq, void* tag) {
+    server_->RequestAsyncCall(methods_[index].get(), context, stream, call_cq,
+                              notification_cq, tag, request);
+  }
+  void RequestAsyncClientStreaming(
+      int index, ServerContext* context,
+      internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
+      ServerCompletionQueue* notification_cq, void* tag) {
+    server_->RequestAsyncCall(methods_[index].get(), context, stream, call_cq,
+                              notification_cq, tag);
+  }
+  template <class Message>
+  void RequestAsyncServerStreaming(
+      int index, ServerContext* context, Message* request,
+      internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
+      ServerCompletionQueue* notification_cq, void* tag) {
+    server_->RequestAsyncCall(methods_[index].get(), context, stream, call_cq,
+                              notification_cq, tag, request);
+  }
+  void RequestAsyncBidiStreaming(
+      int index, ServerContext* context,
+      internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
+      ServerCompletionQueue* notification_cq, void* tag) {
+    server_->RequestAsyncCall(methods_[index].get(), context, stream, call_cq,
+                              notification_cq, tag);
+  }
+
+  void AddMethod(internal::RpcServiceMethod* method) {
+    methods_.emplace_back(method);
+  }
+
+  void MarkMethodAsync(int index) {
+    GPR_CODEGEN_ASSERT(
+        methods_[index].get() != nullptr &&
+        "Cannot mark the method as 'async' because it has already been "
+        "marked as 'generic'.");
+    methods_[index]->ResetHandler();
+  }
+
+  void MarkMethodGeneric(int index) {
+    GPR_CODEGEN_ASSERT(
+        methods_[index]->handler() != nullptr &&
+        "Cannot mark the method as 'generic' because it has already been "
+        "marked as 'async'.");
+    methods_[index].reset();
+  }
+
+  void MarkMethodStreamed(int index, internal::MethodHandler* streamed_method) {
+    GPR_CODEGEN_ASSERT(methods_[index] && methods_[index]->handler() &&
+                       "Cannot mark an async or generic method Streamed");
+    methods_[index]->SetHandler(streamed_method);
+
+    // From the server's point of view, streamed unary is a special
+    // case of BIDI_STREAMING that has 1 read and 1 write, in that order,
+    // and split server-side streaming is BIDI_STREAMING with 1 read and
+    // any number of writes, in that order.
+    methods_[index]->SetMethodType(internal::RpcMethod::BIDI_STREAMING);
+  }
+
+ private:
+  friend class Server;
+  friend class ServerInterface;
+  ServerInterface* server_;
+  std::vector<std::unique_ptr<internal::RpcServiceMethod>> methods_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_SERVICE_TYPE_H
diff --git a/include/grpcpp/impl/codegen/slice.h b/include/grpcpp/impl/codegen/slice.h
new file mode 100644
index 0000000..fcccd4b
--- /dev/null
+++ b/include/grpcpp/impl/codegen/slice.h
@@ -0,0 +1,128 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_SLICE_H
+#define GRPCPP_IMPL_CODEGEN_SLICE_H
+
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/string_ref.h>
+
+#include <grpc/impl/codegen/slice.h>
+
+namespace grpc {
+
+/// A wrapper around \a grpc_slice.
+///
+/// A slice represents a contiguous reference counted array of bytes.
+/// It is cheap to take references to a slice, and it is cheap to create a
+/// slice pointing to a subset of another slice.
+class Slice final {
+ public:
+  /// Construct an empty slice.
+  Slice();
+  /// Destructor - drops one reference.
+  ~Slice();
+
+  enum AddRef { ADD_REF };
+  /// Construct a slice from \a slice, adding a reference.
+  Slice(grpc_slice slice, AddRef);
+
+  enum StealRef { STEAL_REF };
+  /// Construct a slice from \a slice, stealing a reference.
+  Slice(grpc_slice slice, StealRef);
+
+  /// Allocate a slice of specified size
+  Slice(size_t len);
+
+  /// Construct a slice from a copied buffer
+  Slice(const void* buf, size_t len);
+
+  /// Construct a slice from a copied string
+  Slice(const grpc::string& str);
+
+  enum StaticSlice { STATIC_SLICE };
+
+  /// Construct a slice from a static buffer
+  Slice(const void* buf, size_t len, StaticSlice);
+
+  /// Copy constructor, adds a reference.
+  Slice(const Slice& other);
+
+  /// Assignment, reference count is unchanged.
+  Slice& operator=(Slice other) {
+    std::swap(slice_, other.slice_);
+    return *this;
+  }
+
+  /// Create a slice pointing at some data. Calls malloc to allocate a refcount
+  /// for the object, and arranges that destroy will be called with the
+  /// user data pointer passed in at destruction. Can be the same as buf or
+  /// different (e.g., if data is part of a larger structure that must be
+  /// destroyed when the data is no longer needed)
+  Slice(void* buf, size_t len, void (*destroy)(void*), void* user_data);
+
+  /// Specialization of above for common case where buf == user_data
+  Slice(void* buf, size_t len, void (*destroy)(void*))
+      : Slice(buf, len, destroy, buf) {}
+
+  /// Similar to the above but has a destroy that also takes slice length
+  Slice(void* buf, size_t len, void (*destroy)(void*, size_t));
+
+  /// Byte size.
+  size_t size() const { return GRPC_SLICE_LENGTH(slice_); }
+
+  /// Raw pointer to the beginning (first element) of the slice.
+  const uint8_t* begin() const { return GRPC_SLICE_START_PTR(slice_); }
+
+  /// Raw pointer to the end (one byte \em past the last element) of the slice.
+  const uint8_t* end() const { return GRPC_SLICE_END_PTR(slice_); }
+
+  /// Raw C slice. Caller needs to call grpc_slice_unref when done.
+  grpc_slice c_slice() const;
+
+ private:
+  friend class ByteBuffer;
+
+  grpc_slice slice_;
+};
+
+inline grpc::string_ref StringRefFromSlice(const grpc_slice* slice) {
+  return grpc::string_ref(
+      reinterpret_cast<const char*>(GRPC_SLICE_START_PTR(*slice)),
+      GRPC_SLICE_LENGTH(*slice));
+}
+
+inline grpc::string StringFromCopiedSlice(grpc_slice slice) {
+  return grpc::string(reinterpret_cast<char*>(GRPC_SLICE_START_PTR(slice)),
+                      GRPC_SLICE_LENGTH(slice));
+}
+
+inline grpc_slice SliceReferencingString(const grpc::string& str) {
+  return g_core_codegen_interface->grpc_slice_from_static_buffer(str.data(),
+                                                                 str.length());
+}
+
+inline grpc_slice SliceFromCopiedString(const grpc::string& str) {
+  return g_core_codegen_interface->grpc_slice_from_copied_buffer(str.data(),
+                                                                 str.length());
+}
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_SLICE_H
diff --git a/include/grpcpp/impl/codegen/status.h b/include/grpcpp/impl/codegen/status.h
new file mode 100644
index 0000000..e625a76
--- /dev/null
+++ b/include/grpcpp/impl/codegen/status.h
@@ -0,0 +1,133 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_STATUS_H
+#define GRPCPP_IMPL_CODEGEN_STATUS_H
+
+#include <grpc/impl/codegen/status.h>
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/status_code_enum.h>
+
+namespace grpc {
+
+/// Did it work? If it didn't, why?
+///
+/// See \a grpc::StatusCode for details on the available code and their meaning.
+class Status {
+ public:
+  /// Construct an OK instance.
+  Status() : code_(StatusCode::OK) {
+    // Static assertions to make sure that the C++ API value correctly
+    // maps to the core surface API value
+    static_assert(StatusCode::OK == static_cast<StatusCode>(GRPC_STATUS_OK),
+                  "Mismatched status code");
+    static_assert(
+        StatusCode::CANCELLED == static_cast<StatusCode>(GRPC_STATUS_CANCELLED),
+        "Mismatched status code");
+    static_assert(
+        StatusCode::UNKNOWN == static_cast<StatusCode>(GRPC_STATUS_UNKNOWN),
+        "Mismatched status code");
+    static_assert(StatusCode::INVALID_ARGUMENT ==
+                      static_cast<StatusCode>(GRPC_STATUS_INVALID_ARGUMENT),
+                  "Mismatched status code");
+    static_assert(StatusCode::DEADLINE_EXCEEDED ==
+                      static_cast<StatusCode>(GRPC_STATUS_DEADLINE_EXCEEDED),
+                  "Mismatched status code");
+    static_assert(
+        StatusCode::NOT_FOUND == static_cast<StatusCode>(GRPC_STATUS_NOT_FOUND),
+        "Mismatched status code");
+    static_assert(StatusCode::ALREADY_EXISTS ==
+                      static_cast<StatusCode>(GRPC_STATUS_ALREADY_EXISTS),
+                  "Mismatched status code");
+    static_assert(StatusCode::PERMISSION_DENIED ==
+                      static_cast<StatusCode>(GRPC_STATUS_PERMISSION_DENIED),
+                  "Mismatched status code");
+    static_assert(StatusCode::UNAUTHENTICATED ==
+                      static_cast<StatusCode>(GRPC_STATUS_UNAUTHENTICATED),
+                  "Mismatched status code");
+    static_assert(StatusCode::RESOURCE_EXHAUSTED ==
+                      static_cast<StatusCode>(GRPC_STATUS_RESOURCE_EXHAUSTED),
+                  "Mismatched status code");
+    static_assert(StatusCode::FAILED_PRECONDITION ==
+                      static_cast<StatusCode>(GRPC_STATUS_FAILED_PRECONDITION),
+                  "Mismatched status code");
+    static_assert(
+        StatusCode::ABORTED == static_cast<StatusCode>(GRPC_STATUS_ABORTED),
+        "Mismatched status code");
+    static_assert(StatusCode::OUT_OF_RANGE ==
+                      static_cast<StatusCode>(GRPC_STATUS_OUT_OF_RANGE),
+                  "Mismatched status code");
+    static_assert(StatusCode::UNIMPLEMENTED ==
+                      static_cast<StatusCode>(GRPC_STATUS_UNIMPLEMENTED),
+                  "Mismatched status code");
+    static_assert(
+        StatusCode::INTERNAL == static_cast<StatusCode>(GRPC_STATUS_INTERNAL),
+        "Mismatched status code");
+    static_assert(StatusCode::UNAVAILABLE ==
+                      static_cast<StatusCode>(GRPC_STATUS_UNAVAILABLE),
+                  "Mismatched status code");
+    static_assert(
+        StatusCode::DATA_LOSS == static_cast<StatusCode>(GRPC_STATUS_DATA_LOSS),
+        "Mismatched status code");
+  }
+
+  /// Construct an instance with associated \a code and \a error_message.
+  /// It is an error to construct an OK status with non-empty \a error_message.
+  Status(StatusCode code, const grpc::string& error_message)
+      : code_(code), error_message_(error_message) {}
+
+  /// Construct an instance with \a code,  \a error_message and
+  /// \a error_details. It is an error to construct an OK status with non-empty
+  /// \a error_message and/or \a error_details.
+  Status(StatusCode code, const grpc::string& error_message,
+         const grpc::string& error_details)
+      : code_(code),
+        error_message_(error_message),
+        binary_error_details_(error_details) {}
+
+  // Pre-defined special status objects.
+  /// An OK pre-defined instance.
+  static const Status& OK;
+  /// A CANCELLED pre-defined instance.
+  static const Status& CANCELLED;
+
+  /// Return the instance's error code.
+  StatusCode error_code() const { return code_; }
+  /// Return the instance's error message.
+  grpc::string error_message() const { return error_message_; }
+  /// Return the (binary) error details.
+  // Usually it contains a serialized google.rpc.Status proto.
+  grpc::string error_details() const { return binary_error_details_; }
+
+  /// Is the status OK?
+  bool ok() const { return code_ == StatusCode::OK; }
+
+  // Ignores any errors. This method does nothing except potentially suppress
+  // complaints from any tools that are checking that errors are not dropped on
+  // the floor.
+  void IgnoreError() const {}
+
+ private:
+  StatusCode code_;
+  grpc::string error_message_;
+  grpc::string binary_error_details_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_STATUS_H
diff --git a/include/grpcpp/impl/codegen/status_code_enum.h b/include/grpcpp/impl/codegen/status_code_enum.h
new file mode 100644
index 0000000..09943f1
--- /dev/null
+++ b/include/grpcpp/impl/codegen/status_code_enum.h
@@ -0,0 +1,142 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_STATUS_CODE_ENUM_H
+#define GRPCPP_IMPL_CODEGEN_STATUS_CODE_ENUM_H
+
+namespace grpc {
+
+enum StatusCode {
+  /// Not an error; returned on success.
+  OK = 0,
+
+  /// The operation was cancelled (typically by the caller).
+  CANCELLED = 1,
+
+  /// Unknown error. An example of where this error may be returned is if a
+  /// Status value received from another address space belongs to an error-space
+  /// that is not known in this address space. Also errors raised by APIs that
+  /// do not return enough error information may be converted to this error.
+  UNKNOWN = 2,
+
+  /// Client specified an invalid argument. Note that this differs from
+  /// FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments that are
+  /// problematic regardless of the state of the system (e.g., a malformed file
+  /// name).
+  INVALID_ARGUMENT = 3,
+
+  /// Deadline expired before operation could complete. For operations that
+  /// change the state of the system, this error may be returned even if the
+  /// operation has completed successfully. For example, a successful response
+  /// from a server could have been delayed long enough for the deadline to
+  /// expire.
+  DEADLINE_EXCEEDED = 4,
+
+  /// Some requested entity (e.g., file or directory) was not found.
+  NOT_FOUND = 5,
+
+  /// Some entity that we attempted to create (e.g., file or directory) already
+  /// exists.
+  ALREADY_EXISTS = 6,
+
+  /// The caller does not have permission to execute the specified operation.
+  /// PERMISSION_DENIED must not be used for rejections caused by exhausting
+  /// some resource (use RESOURCE_EXHAUSTED instead for those errors).
+  /// PERMISSION_DENIED must not be used if the caller can not be identified
+  /// (use UNAUTHENTICATED instead for those errors).
+  PERMISSION_DENIED = 7,
+
+  /// The request does not have valid authentication credentials for the
+  /// operation.
+  UNAUTHENTICATED = 16,
+
+  /// Some resource has been exhausted, perhaps a per-user quota, or perhaps the
+  /// entire file system is out of space.
+  RESOURCE_EXHAUSTED = 8,
+
+  /// Operation was rejected because the system is not in a state required for
+  /// the operation's execution. For example, directory to be deleted may be
+  /// non-empty, an rmdir operation is applied to a non-directory, etc.
+  ///
+  /// A litmus test that may help a service implementor in deciding
+  /// between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:
+  ///  (a) Use UNAVAILABLE if the client can retry just the failing call.
+  ///  (b) Use ABORTED if the client should retry at a higher-level
+  ///      (e.g., restarting a read-modify-write sequence).
+  ///  (c) Use FAILED_PRECONDITION if the client should not retry until
+  ///      the system state has been explicitly fixed. E.g., if an "rmdir"
+  ///      fails because the directory is non-empty, FAILED_PRECONDITION
+  ///      should be returned since the client should not retry unless
+  ///      they have first fixed up the directory by deleting files from it.
+  ///  (d) Use FAILED_PRECONDITION if the client performs conditional
+  ///      REST Get/Update/Delete on a resource and the resource on the
+  ///      server does not match the condition. E.g., conflicting
+  ///      read-modify-write on the same resource.
+  FAILED_PRECONDITION = 9,
+
+  /// The operation was aborted, typically due to a concurrency issue like
+  /// sequencer check failures, transaction aborts, etc.
+  ///
+  /// See litmus test above for deciding between FAILED_PRECONDITION, ABORTED,
+  /// and UNAVAILABLE.
+  ABORTED = 10,
+
+  /// Operation was attempted past the valid range. E.g., seeking or reading
+  /// past end of file.
+  ///
+  /// Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed
+  /// if the system state changes. For example, a 32-bit file system will
+  /// generate INVALID_ARGUMENT if asked to read at an offset that is not in the
+  /// range [0,2^32-1], but it will generate OUT_OF_RANGE if asked to read from
+  /// an offset past the current file size.
+  ///
+  /// There is a fair bit of overlap between FAILED_PRECONDITION and
+  /// OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific error)
+  /// when it applies so that callers who are iterating through a space can
+  /// easily look for an OUT_OF_RANGE error to detect when they are done.
+  OUT_OF_RANGE = 11,
+
+  /// Operation is not implemented or not supported/enabled in this service.
+  UNIMPLEMENTED = 12,
+
+  /// Internal errors. Means some invariants expected by underlying System has
+  /// been broken. If you see one of these errors, Something is very broken.
+  INTERNAL = 13,
+
+  /// The service is currently unavailable. This is a most likely a transient
+  /// condition and may be corrected by retrying with a backoff.
+  ///
+  /// \warning Although data MIGHT not have been transmitted when this
+  /// status occurs, there is NOT A GUARANTEE that the server has not seen
+  /// anything. So in general it is unsafe to retry on this status code
+  /// if the call is non-idempotent.
+  ///
+  /// See litmus test above for deciding between FAILED_PRECONDITION, ABORTED,
+  /// and UNAVAILABLE.
+  UNAVAILABLE = 14,
+
+  /// Unrecoverable data loss or corruption.
+  DATA_LOSS = 15,
+
+  /// Force users to include a default branch:
+  DO_NOT_USE = -1
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_STATUS_CODE_ENUM_H
diff --git a/include/grpcpp/impl/codegen/string_ref.h b/include/grpcpp/impl/codegen/string_ref.h
new file mode 100644
index 0000000..5d55fc4
--- /dev/null
+++ b/include/grpcpp/impl/codegen/string_ref.h
@@ -0,0 +1,146 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_STRING_REF_H
+#define GRPCPP_IMPL_CODEGEN_STRING_REF_H
+
+#include <string.h>
+
+#include <algorithm>
+#include <iosfwd>
+#include <iostream>
+#include <iterator>
+
+#include <grpcpp/impl/codegen/config.h>
+
+namespace grpc {
+
+/// This class is a non owning reference to a string.
+///
+/// It should be a strict subset of the upcoming std::string_ref.
+///
+/// \see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html
+///
+/// The constexpr is dropped or replaced with const for legacy compiler
+/// compatibility.
+class string_ref {
+ public:
+  /// types
+  typedef const char* const_iterator;
+  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+  /// constants
+  const static size_t npos;
+
+  /// construct/copy.
+  string_ref() : data_(nullptr), length_(0) {}
+  string_ref(const string_ref& other)
+      : data_(other.data_), length_(other.length_) {}
+  string_ref& operator=(const string_ref& rhs) {
+    data_ = rhs.data_;
+    length_ = rhs.length_;
+    return *this;
+  }
+
+  string_ref(const char* s) : data_(s), length_(strlen(s)) {}
+  string_ref(const char* s, size_t l) : data_(s), length_(l) {}
+  string_ref(const grpc::string& s) : data_(s.data()), length_(s.length()) {}
+
+  /// iterators
+  const_iterator begin() const { return data_; }
+  const_iterator end() const { return data_ + length_; }
+  const_iterator cbegin() const { return data_; }
+  const_iterator cend() const { return data_ + length_; }
+  const_reverse_iterator rbegin() const {
+    return const_reverse_iterator(end());
+  }
+  const_reverse_iterator rend() const {
+    return const_reverse_iterator(begin());
+  }
+  const_reverse_iterator crbegin() const {
+    return const_reverse_iterator(end());
+  }
+  const_reverse_iterator crend() const {
+    return const_reverse_iterator(begin());
+  }
+
+  /// capacity
+  size_t size() const { return length_; }
+  size_t length() const { return length_; }
+  size_t max_size() const { return length_; }
+  bool empty() const { return length_ == 0; }
+
+  /// element access
+  const char* data() const { return data_; }
+
+  /// string operations
+  int compare(string_ref x) const {
+    size_t min_size = length_ < x.length_ ? length_ : x.length_;
+    int r = memcmp(data_, x.data_, min_size);
+    if (r < 0) return -1;
+    if (r > 0) return 1;
+    if (length_ < x.length_) return -1;
+    if (length_ > x.length_) return 1;
+    return 0;
+  }
+
+  bool starts_with(string_ref x) const {
+    return length_ >= x.length_ && (memcmp(data_, x.data_, x.length_) == 0);
+  }
+
+  bool ends_with(string_ref x) const {
+    return length_ >= x.length_ &&
+           (memcmp(data_ + (length_ - x.length_), x.data_, x.length_) == 0);
+  }
+
+  size_t find(string_ref s) const {
+    auto it = std::search(cbegin(), cend(), s.cbegin(), s.cend());
+    return it == cend() ? npos : std::distance(cbegin(), it);
+  }
+
+  size_t find(char c) const {
+    auto it = std::find(cbegin(), cend(), c);
+    return it == cend() ? npos : std::distance(cbegin(), it);
+  }
+
+  string_ref substr(size_t pos, size_t n = npos) const {
+    if (pos > length_) pos = length_;
+    if (n > (length_ - pos)) n = length_ - pos;
+    return string_ref(data_ + pos, n);
+  }
+
+ private:
+  const char* data_;
+  size_t length_;
+};
+
+/// Comparison operators
+inline bool operator==(string_ref x, string_ref y) { return x.compare(y) == 0; }
+inline bool operator!=(string_ref x, string_ref y) { return x.compare(y) != 0; }
+inline bool operator<(string_ref x, string_ref y) { return x.compare(y) < 0; }
+inline bool operator<=(string_ref x, string_ref y) { return x.compare(y) <= 0; }
+inline bool operator>(string_ref x, string_ref y) { return x.compare(y) > 0; }
+inline bool operator>=(string_ref x, string_ref y) { return x.compare(y) >= 0; }
+
+inline std::ostream& operator<<(std::ostream& out, const string_ref& string) {
+  return out << grpc::string(string.begin(), string.end());
+}
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_STRING_REF_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/impl/codegen/stub_options.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/impl/codegen/stub_options.h
index 692c00c..a56695a 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/impl/codegen/stub_options.h
@@ -16,15 +16,14 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_IMPL_CODEGEN_STUB_OPTIONS_H
+#define GRPCPP_IMPL_CODEGEN_STUB_OPTIONS_H
 
-#include <grpc/support/time.h>
+namespace grpc {
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
+/// Useful interface for generated stubs
+class StubOptions {};
 
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
+}  // namespace grpc
 
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_IMPL_CODEGEN_STUB_OPTIONS_H
diff --git a/include/grpcpp/impl/codegen/sync_stream.h b/include/grpcpp/impl/codegen/sync_stream.h
new file mode 100644
index 0000000..7152eaf
--- /dev/null
+++ b/include/grpcpp/impl/codegen/sync_stream.h
@@ -0,0 +1,934 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_SYNC_STREAM_H
+#define GRPCPP_IMPL_CODEGEN_SYNC_STREAM_H
+
+#include <grpcpp/impl/codegen/call.h>
+#include <grpcpp/impl/codegen/channel_interface.h>
+#include <grpcpp/impl/codegen/client_context.h>
+#include <grpcpp/impl/codegen/completion_queue.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/server_context.h>
+#include <grpcpp/impl/codegen/service_type.h>
+#include <grpcpp/impl/codegen/status.h>
+
+namespace grpc {
+
+namespace internal {
+/// Common interface for all synchronous client side streaming.
+class ClientStreamingInterface {
+ public:
+  virtual ~ClientStreamingInterface() {}
+
+  /// Block waiting until the stream finishes and a final status of the call is
+  /// available.
+  ///
+  /// It is appropriate to call this method when both:
+  ///   * the calling code (client-side) has no more message to send
+  ///     (this can be declared implicitly by calling this method, or
+  ///     explicitly through an earlier call to <i>WritesDone</i> method of the
+  ///     class in use, e.g. \a ClientWriterInterface::WritesDone or
+  ///     \a ClientReaderWriterInterface::WritesDone).
+  ///   * there are no more messages to be received from the server (which can
+  ///     be known implicitly, or explicitly from an earlier call to \a
+  ///     ReaderInterface::Read that returned "false").
+  ///
+  /// This function will return either:
+  /// - when all incoming messages have been read and the server has
+  ///   returned status.
+  /// - when the server has returned a non-OK status.
+  /// - OR when the call failed for some reason and the library generated a
+  ///   status.
+  ///
+  /// Return values:
+  ///   - \a Status contains the status code, message and details for the call
+  ///   - the \a ClientContext associated with this call is updated with
+  ///     possible trailing metadata sent from the server.
+  virtual Status Finish() = 0;
+};
+
+/// Common interface for all synchronous server side streaming.
+class ServerStreamingInterface {
+ public:
+  virtual ~ServerStreamingInterface() {}
+
+  /// Block to send initial metadata to client.
+  /// This call is optional, but if it is used, it cannot be used concurrently
+  /// with or after the \a Finish method.
+  ///
+  /// The initial metadata that will be sent to the client will be
+  /// taken from the \a ServerContext associated with the call.
+  virtual void SendInitialMetadata() = 0;
+};
+
+/// An interface that yields a sequence of messages of type \a R.
+template <class R>
+class ReaderInterface {
+ public:
+  virtual ~ReaderInterface() {}
+
+  /// Get an upper bound on the next message size available for reading on this
+  /// stream.
+  virtual bool NextMessageSize(uint32_t* sz) = 0;
+
+  /// Block to read a message and parse to \a msg. Returns \a true on success.
+  /// This is thread-safe with respect to \a Write or \WritesDone methods on
+  /// the same stream. It should not be called concurrently with another \a
+  /// Read on the same stream as the order of delivery will not be defined.
+  ///
+  /// \param[out] msg The read message.
+  ///
+  /// \return \a false when there will be no more incoming messages, either
+  /// because the other side has called \a WritesDone() or the stream has failed
+  /// (or been cancelled).
+  virtual bool Read(R* msg) = 0;
+};
+
+/// An interface that can be fed a sequence of messages of type \a W.
+template <class W>
+class WriterInterface {
+ public:
+  virtual ~WriterInterface() {}
+
+  /// Block to write \a msg to the stream with WriteOptions \a options.
+  /// This is thread-safe with respect to \a ReaderInterface::Read
+  ///
+  /// \param msg The message to be written to the stream.
+  /// \param options The WriteOptions affecting the write operation.
+  ///
+  /// \return \a true on success, \a false when the stream has been closed.
+  virtual bool Write(const W& msg, WriteOptions options) = 0;
+
+  /// Block to write \a msg to the stream with default write options.
+  /// This is thread-safe with respect to \a ReaderInterface::Read
+  ///
+  /// \param msg The message to be written to the stream.
+  ///
+  /// \return \a true on success, \a false when the stream has been closed.
+  inline bool Write(const W& msg) { return Write(msg, WriteOptions()); }
+
+  /// Write \a msg and coalesce it with the writing of trailing metadata, using
+  /// WriteOptions \a options.
+  ///
+  /// For client, WriteLast is equivalent of performing Write and WritesDone in
+  /// a single step. \a msg and trailing metadata are coalesced and sent on wire
+  /// by calling this function. For server, WriteLast buffers the \a msg.
+  /// The writing of \a msg is held until the service handler returns,
+  /// where \a msg and trailing metadata are coalesced and sent on wire.
+  /// Note that WriteLast can only buffer \a msg up to the flow control window
+  /// size. If \a msg size is larger than the window size, it will be sent on
+  /// wire without buffering.
+  ///
+  /// \param[in] msg The message to be written to the stream.
+  /// \param[in] options The WriteOptions to be used to write this message.
+  void WriteLast(const W& msg, WriteOptions options) {
+    Write(msg, options.set_last_message());
+  }
+};
+
+}  // namespace internal
+
+/// Client-side interface for streaming reads of message of type \a R.
+template <class R>
+class ClientReaderInterface : public internal::ClientStreamingInterface,
+                              public internal::ReaderInterface<R> {
+ public:
+  /// Block to wait for initial metadata from server. The received metadata
+  /// can only be accessed after this call returns. Should only be called before
+  /// the first read. Calling this method is optional, and if it is not called
+  /// the metadata will be available in ClientContext after the first read.
+  virtual void WaitForInitialMetadata() = 0;
+};
+
+namespace internal {
+template <class R>
+class ClientReaderFactory {
+ public:
+  template <class W>
+  static ClientReader<R>* Create(ChannelInterface* channel,
+                                 const ::grpc::internal::RpcMethod& method,
+                                 ClientContext* context, const W& request) {
+    return new ClientReader<R>(channel, method, context, request);
+  }
+};
+}  // namespace internal
+
+/// Synchronous (blocking) client-side API for doing server-streaming RPCs,
+/// where the stream of messages coming from the server has messages
+/// of type \a R.
+template <class R>
+class ClientReader final : public ClientReaderInterface<R> {
+ public:
+  /// See the \a ClientStreamingInterface.WaitForInitialMetadata method for
+  /// semantics.
+  ///
+  //  Side effect:
+  ///   Once complete, the initial metadata read from
+  ///   the server will be accessable through the \a ClientContext used to
+  ///   construct this object.
+  void WaitForInitialMetadata() override {
+    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
+
+    ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
+        ops;
+    ops.RecvInitialMetadata(context_);
+    call_.PerformOps(&ops);
+    cq_.Pluck(&ops);  /// status ignored
+  }
+
+  bool NextMessageSize(uint32_t* sz) override {
+    *sz = call_.max_receive_message_size();
+    return true;
+  }
+
+  /// See the \a ReaderInterface.Read method for semantics.
+  /// Side effect:
+  ///   This also receives initial metadata from the server, if not
+  ///   already received (if initial metadata is received, it can be then
+  ///   accessed through the \a ClientContext associated with this call).
+  bool Read(R* msg) override {
+    ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
+                                ::grpc::internal::CallOpRecvMessage<R>>
+        ops;
+    if (!context_->initial_metadata_received_) {
+      ops.RecvInitialMetadata(context_);
+    }
+    ops.RecvMessage(msg);
+    call_.PerformOps(&ops);
+    return cq_.Pluck(&ops) && ops.got_message;
+  }
+
+  /// See the \a ClientStreamingInterface.Finish method for semantics.
+  ///
+  /// Side effect:
+  ///   The \a ClientContext associated with this call is updated with
+  ///   possible metadata received from the server.
+  Status Finish() override {
+    ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientRecvStatus> ops;
+    Status status;
+    ops.ClientRecvStatus(context_, &status);
+    call_.PerformOps(&ops);
+    GPR_CODEGEN_ASSERT(cq_.Pluck(&ops));
+    return status;
+  }
+
+ private:
+  friend class internal::ClientReaderFactory<R>;
+  ClientContext* context_;
+  CompletionQueue cq_;
+  ::grpc::internal::Call call_;
+
+  /// Block to create a stream and write the initial metadata and \a request
+  /// out. Note that \a context will be used to fill in custom initial
+  /// metadata used to send to the server when starting the call.
+  template <class W>
+  ClientReader(::grpc::ChannelInterface* channel,
+               const ::grpc::internal::RpcMethod& method,
+               ClientContext* context, const W& request)
+      : context_(context),
+        cq_(grpc_completion_queue_attributes{
+            GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK,
+            GRPC_CQ_DEFAULT_POLLING}),  // Pluckable cq
+        call_(channel->CreateCall(method, context, &cq_)) {
+    ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
+                                ::grpc::internal::CallOpSendMessage,
+                                ::grpc::internal::CallOpClientSendClose>
+        ops;
+    ops.SendInitialMetadata(context->send_initial_metadata_,
+                            context->initial_metadata_flags());
+    // TODO(ctiller): don't assert
+    GPR_CODEGEN_ASSERT(ops.SendMessage(request).ok());
+    ops.ClientSendClose();
+    call_.PerformOps(&ops);
+    cq_.Pluck(&ops);
+  }
+};
+
+/// Client-side interface for streaming writes of message type \a W.
+template <class W>
+class ClientWriterInterface : public internal::ClientStreamingInterface,
+                              public internal::WriterInterface<W> {
+ public:
+  /// Half close writing from the client. (signal that the stream of messages
+  /// coming from the client is complete).
+  /// Blocks until currently-pending writes are completed.
+  /// Thread safe with respect to \a ReaderInterface::Read operations only
+  ///
+  /// \return Whether the writes were successful.
+  virtual bool WritesDone() = 0;
+};
+
+namespace internal {
+template <class W>
+class ClientWriterFactory {
+ public:
+  template <class R>
+  static ClientWriter<W>* Create(::grpc::ChannelInterface* channel,
+                                 const ::grpc::internal::RpcMethod& method,
+                                 ClientContext* context, R* response) {
+    return new ClientWriter<W>(channel, method, context, response);
+  }
+};
+}  // namespace internal
+
+/// Synchronous (blocking) client-side API for doing client-streaming RPCs,
+/// where the outgoing message stream coming from the client has messages of
+/// type \a W.
+template <class W>
+class ClientWriter : public ClientWriterInterface<W> {
+ public:
+  /// See the \a ClientStreamingInterface.WaitForInitialMetadata method for
+  /// semantics.
+  ///
+  //  Side effect:
+  ///   Once complete, the initial metadata read from the server will be
+  ///   accessable through the \a ClientContext used to construct this object.
+  void WaitForInitialMetadata() {
+    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
+
+    ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
+        ops;
+    ops.RecvInitialMetadata(context_);
+    call_.PerformOps(&ops);
+    cq_.Pluck(&ops);  // status ignored
+  }
+
+  /// See the WriterInterface.Write(const W& msg, WriteOptions options) method
+  /// for semantics.
+  ///
+  /// Side effect:
+  ///   Also sends initial metadata if not already sent (using the
+  ///   \a ClientContext associated with this call).
+  using ::grpc::internal::WriterInterface<W>::Write;
+  bool Write(const W& msg, WriteOptions options) override {
+    ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
+                                ::grpc::internal::CallOpSendMessage,
+                                ::grpc::internal::CallOpClientSendClose>
+        ops;
+
+    if (options.is_last_message()) {
+      options.set_buffer_hint();
+      ops.ClientSendClose();
+    }
+    if (context_->initial_metadata_corked_) {
+      ops.SendInitialMetadata(context_->send_initial_metadata_,
+                              context_->initial_metadata_flags());
+      context_->set_initial_metadata_corked(false);
+    }
+    if (!ops.SendMessage(msg, options).ok()) {
+      return false;
+    }
+
+    call_.PerformOps(&ops);
+    return cq_.Pluck(&ops);
+  }
+
+  bool WritesDone() override {
+    ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops;
+    ops.ClientSendClose();
+    call_.PerformOps(&ops);
+    return cq_.Pluck(&ops);
+  }
+
+  /// See the ClientStreamingInterface.Finish method for semantics.
+  /// Side effects:
+  ///   - Also receives initial metadata if not already received.
+  ///   - Attempts to fill in the \a response parameter passed
+  ///     to the constructor of this instance with the response
+  ///     message from the server.
+  Status Finish() override {
+    Status status;
+    if (!context_->initial_metadata_received_) {
+      finish_ops_.RecvInitialMetadata(context_);
+    }
+    finish_ops_.ClientRecvStatus(context_, &status);
+    call_.PerformOps(&finish_ops_);
+    GPR_CODEGEN_ASSERT(cq_.Pluck(&finish_ops_));
+    return status;
+  }
+
+ private:
+  friend class internal::ClientWriterFactory<W>;
+
+  /// Block to create a stream (i.e. send request headers and other initial
+  /// metadata to the server). Note that \a context will be used to fill
+  /// in custom initial metadata. \a response will be filled in with the
+  /// single expected response message from the server upon a successful
+  /// call to the \a Finish method of this instance.
+  template <class R>
+  ClientWriter(ChannelInterface* channel,
+               const ::grpc::internal::RpcMethod& method,
+               ClientContext* context, R* response)
+      : context_(context),
+        cq_(grpc_completion_queue_attributes{
+            GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK,
+            GRPC_CQ_DEFAULT_POLLING}),  // Pluckable cq
+        call_(channel->CreateCall(method, context, &cq_)) {
+    finish_ops_.RecvMessage(response);
+    finish_ops_.AllowNoMessage();
+
+    if (!context_->initial_metadata_corked_) {
+      ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
+          ops;
+      ops.SendInitialMetadata(context->send_initial_metadata_,
+                              context->initial_metadata_flags());
+      call_.PerformOps(&ops);
+      cq_.Pluck(&ops);
+    }
+  }
+
+  ClientContext* context_;
+  ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
+                              ::grpc::internal::CallOpGenericRecvMessage,
+                              ::grpc::internal::CallOpClientRecvStatus>
+      finish_ops_;
+  CompletionQueue cq_;
+  ::grpc::internal::Call call_;
+};
+
+/// Client-side interface for bi-directional streaming with
+/// client-to-server stream messages of type \a W and
+/// server-to-client stream messages of type \a R.
+template <class W, class R>
+class ClientReaderWriterInterface : public internal::ClientStreamingInterface,
+                                    public internal::WriterInterface<W>,
+                                    public internal::ReaderInterface<R> {
+ public:
+  /// Block to wait for initial metadata from server. The received metadata
+  /// can only be accessed after this call returns. Should only be called before
+  /// the first read. Calling this method is optional, and if it is not called
+  /// the metadata will be available in ClientContext after the first read.
+  virtual void WaitForInitialMetadata() = 0;
+
+  /// Half close writing from the client. (signal that the stream of messages
+  /// coming from the clinet is complete).
+  /// Blocks until currently-pending writes are completed.
+  /// Thread-safe with respect to \a ReaderInterface::Read
+  ///
+  /// \return Whether the writes were successful.
+  virtual bool WritesDone() = 0;
+};
+
+namespace internal {
+template <class W, class R>
+class ClientReaderWriterFactory {
+ public:
+  static ClientReaderWriter<W, R>* Create(
+      ::grpc::ChannelInterface* channel,
+      const ::grpc::internal::RpcMethod& method, ClientContext* context) {
+    return new ClientReaderWriter<W, R>(channel, method, context);
+  }
+};
+}  // namespace internal
+
+/// Synchronous (blocking) client-side API for bi-directional streaming RPCs,
+/// where the outgoing message stream coming from the client has messages of
+/// type \a W, and the incoming messages stream coming from the server has
+/// messages of type \a R.
+template <class W, class R>
+class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> {
+ public:
+  /// Block waiting to read initial metadata from the server.
+  /// This call is optional, but if it is used, it cannot be used concurrently
+  /// with or after the \a Finish method.
+  ///
+  /// Once complete, the initial metadata read from the server will be
+  /// accessable through the \a ClientContext used to construct this object.
+  void WaitForInitialMetadata() override {
+    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
+
+    ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata>
+        ops;
+    ops.RecvInitialMetadata(context_);
+    call_.PerformOps(&ops);
+    cq_.Pluck(&ops);  // status ignored
+  }
+
+  bool NextMessageSize(uint32_t* sz) override {
+    *sz = call_.max_receive_message_size();
+    return true;
+  }
+
+  /// See the \a ReaderInterface.Read method for semantics.
+  /// Side effect:
+  ///   Also receives initial metadata if not already received (updates the \a
+  ///   ClientContext associated with this call in that case).
+  bool Read(R* msg) override {
+    ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
+                                ::grpc::internal::CallOpRecvMessage<R>>
+        ops;
+    if (!context_->initial_metadata_received_) {
+      ops.RecvInitialMetadata(context_);
+    }
+    ops.RecvMessage(msg);
+    call_.PerformOps(&ops);
+    return cq_.Pluck(&ops) && ops.got_message;
+  }
+
+  /// See the \a WriterInterface.Write method for semantics.
+  ///
+  /// Side effect:
+  ///   Also sends initial metadata if not already sent (using the
+  ///   \a ClientContext associated with this call to fill in values).
+  using ::grpc::internal::WriterInterface<W>::Write;
+  bool Write(const W& msg, WriteOptions options) override {
+    ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
+                                ::grpc::internal::CallOpSendMessage,
+                                ::grpc::internal::CallOpClientSendClose>
+        ops;
+
+    if (options.is_last_message()) {
+      options.set_buffer_hint();
+      ops.ClientSendClose();
+    }
+    if (context_->initial_metadata_corked_) {
+      ops.SendInitialMetadata(context_->send_initial_metadata_,
+                              context_->initial_metadata_flags());
+      context_->set_initial_metadata_corked(false);
+    }
+    if (!ops.SendMessage(msg, options).ok()) {
+      return false;
+    }
+
+    call_.PerformOps(&ops);
+    return cq_.Pluck(&ops);
+  }
+
+  bool WritesDone() override {
+    ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops;
+    ops.ClientSendClose();
+    call_.PerformOps(&ops);
+    return cq_.Pluck(&ops);
+  }
+
+  /// See the ClientStreamingInterface.Finish method for semantics.
+  ///
+  /// Side effect:
+  ///   - the \a ClientContext associated with this call is updated with
+  ///     possible trailing metadata sent from the server.
+  Status Finish() override {
+    ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata,
+                                ::grpc::internal::CallOpClientRecvStatus>
+        ops;
+    if (!context_->initial_metadata_received_) {
+      ops.RecvInitialMetadata(context_);
+    }
+    Status status;
+    ops.ClientRecvStatus(context_, &status);
+    call_.PerformOps(&ops);
+    GPR_CODEGEN_ASSERT(cq_.Pluck(&ops));
+    return status;
+  }
+
+ private:
+  friend class internal::ClientReaderWriterFactory<W, R>;
+
+  ClientContext* context_;
+  CompletionQueue cq_;
+  ::grpc::internal::Call call_;
+
+  /// Block to create a stream and write the initial metadata and \a request
+  /// out. Note that \a context will be used to fill in custom initial metadata
+  /// used to send to the server when starting the call.
+  ClientReaderWriter(::grpc::ChannelInterface* channel,
+                     const ::grpc::internal::RpcMethod& method,
+                     ClientContext* context)
+      : context_(context),
+        cq_(grpc_completion_queue_attributes{
+            GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK,
+            GRPC_CQ_DEFAULT_POLLING}),  // Pluckable cq
+        call_(channel->CreateCall(method, context, &cq_)) {
+    if (!context_->initial_metadata_corked_) {
+      ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata>
+          ops;
+      ops.SendInitialMetadata(context->send_initial_metadata_,
+                              context->initial_metadata_flags());
+      call_.PerformOps(&ops);
+      cq_.Pluck(&ops);
+    }
+  }
+};
+
+/// Server-side interface for streaming reads of message of type \a R.
+template <class R>
+class ServerReaderInterface : public internal::ServerStreamingInterface,
+                              public internal::ReaderInterface<R> {};
+
+/// Synchronous (blocking) server-side API for doing client-streaming RPCs,
+/// where the incoming message stream coming from the client has messages of
+/// type \a R.
+template <class R>
+class ServerReader final : public ServerReaderInterface<R> {
+ public:
+  /// See the \a ServerStreamingInterface.SendInitialMetadata method
+  /// for semantics. Note that initial metadata will be affected by the
+  /// \a ServerContext associated with this call.
+  void SendInitialMetadata() override {
+    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
+
+    internal::CallOpSet<internal::CallOpSendInitialMetadata> ops;
+    ops.SendInitialMetadata(ctx_->initial_metadata_,
+                            ctx_->initial_metadata_flags());
+    if (ctx_->compression_level_set()) {
+      ops.set_compression_level(ctx_->compression_level());
+    }
+    ctx_->sent_initial_metadata_ = true;
+    call_->PerformOps(&ops);
+    call_->cq()->Pluck(&ops);
+  }
+
+  bool NextMessageSize(uint32_t* sz) override {
+    *sz = call_->max_receive_message_size();
+    return true;
+  }
+
+  bool Read(R* msg) override {
+    internal::CallOpSet<internal::CallOpRecvMessage<R>> ops;
+    ops.RecvMessage(msg);
+    call_->PerformOps(&ops);
+    return call_->cq()->Pluck(&ops) && ops.got_message;
+  }
+
+ private:
+  internal::Call* const call_;
+  ServerContext* const ctx_;
+
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class internal::ClientStreamingHandler;
+
+  ServerReader(internal::Call* call, ServerContext* ctx)
+      : call_(call), ctx_(ctx) {}
+};
+
+/// Server-side interface for streaming writes of message of type \a W.
+template <class W>
+class ServerWriterInterface : public internal::ServerStreamingInterface,
+                              public internal::WriterInterface<W> {};
+
+/// Synchronous (blocking) server-side API for doing for doing a
+/// server-streaming RPCs, where the outgoing message stream coming from the
+/// server has messages of type \a W.
+template <class W>
+class ServerWriter final : public ServerWriterInterface<W> {
+ public:
+  /// See the \a ServerStreamingInterface.SendInitialMetadata method
+  /// for semantics.
+  /// Note that initial metadata will be affected by the
+  /// \a ServerContext associated with this call.
+  void SendInitialMetadata() override {
+    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
+
+    internal::CallOpSet<internal::CallOpSendInitialMetadata> ops;
+    ops.SendInitialMetadata(ctx_->initial_metadata_,
+                            ctx_->initial_metadata_flags());
+    if (ctx_->compression_level_set()) {
+      ops.set_compression_level(ctx_->compression_level());
+    }
+    ctx_->sent_initial_metadata_ = true;
+    call_->PerformOps(&ops);
+    call_->cq()->Pluck(&ops);
+  }
+
+  /// See the \a WriterInterface.Write method for semantics.
+  ///
+  /// Side effect:
+  ///   Also sends initial metadata if not already sent (using the
+  ///   \a ClientContext associated with this call to fill in values).
+  using internal::WriterInterface<W>::Write;
+  bool Write(const W& msg, WriteOptions options) override {
+    if (options.is_last_message()) {
+      options.set_buffer_hint();
+    }
+
+    if (!ctx_->pending_ops_.SendMessage(msg, options).ok()) {
+      return false;
+    }
+    if (!ctx_->sent_initial_metadata_) {
+      ctx_->pending_ops_.SendInitialMetadata(ctx_->initial_metadata_,
+                                             ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        ctx_->pending_ops_.set_compression_level(ctx_->compression_level());
+      }
+      ctx_->sent_initial_metadata_ = true;
+    }
+    call_->PerformOps(&ctx_->pending_ops_);
+    // if this is the last message we defer the pluck until AFTER we start
+    // the trailing md op. This prevents hangs. See
+    // https://github.com/grpc/grpc/issues/11546
+    if (options.is_last_message()) {
+      ctx_->has_pending_ops_ = true;
+      return true;
+    }
+    ctx_->has_pending_ops_ = false;
+    return call_->cq()->Pluck(&ctx_->pending_ops_);
+  }
+
+ private:
+  internal::Call* const call_;
+  ServerContext* const ctx_;
+
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class internal::ServerStreamingHandler;
+
+  ServerWriter(internal::Call* call, ServerContext* ctx)
+      : call_(call), ctx_(ctx) {}
+};
+
+/// Server-side interface for bi-directional streaming.
+template <class W, class R>
+class ServerReaderWriterInterface : public internal::ServerStreamingInterface,
+                                    public internal::WriterInterface<W>,
+                                    public internal::ReaderInterface<R> {};
+
+/// Actual implementation of bi-directional streaming
+namespace internal {
+template <class W, class R>
+class ServerReaderWriterBody final {
+ public:
+  ServerReaderWriterBody(Call* call, ServerContext* ctx)
+      : call_(call), ctx_(ctx) {}
+
+  void SendInitialMetadata() {
+    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
+
+    CallOpSet<CallOpSendInitialMetadata> ops;
+    ops.SendInitialMetadata(ctx_->initial_metadata_,
+                            ctx_->initial_metadata_flags());
+    if (ctx_->compression_level_set()) {
+      ops.set_compression_level(ctx_->compression_level());
+    }
+    ctx_->sent_initial_metadata_ = true;
+    call_->PerformOps(&ops);
+    call_->cq()->Pluck(&ops);
+  }
+
+  bool NextMessageSize(uint32_t* sz) {
+    *sz = call_->max_receive_message_size();
+    return true;
+  }
+
+  bool Read(R* msg) {
+    CallOpSet<CallOpRecvMessage<R>> ops;
+    ops.RecvMessage(msg);
+    call_->PerformOps(&ops);
+    return call_->cq()->Pluck(&ops) && ops.got_message;
+  }
+
+  bool Write(const W& msg, WriteOptions options) {
+    if (options.is_last_message()) {
+      options.set_buffer_hint();
+    }
+    if (!ctx_->pending_ops_.SendMessage(msg, options).ok()) {
+      return false;
+    }
+    if (!ctx_->sent_initial_metadata_) {
+      ctx_->pending_ops_.SendInitialMetadata(ctx_->initial_metadata_,
+                                             ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        ctx_->pending_ops_.set_compression_level(ctx_->compression_level());
+      }
+      ctx_->sent_initial_metadata_ = true;
+    }
+    call_->PerformOps(&ctx_->pending_ops_);
+    // if this is the last message we defer the pluck until AFTER we start
+    // the trailing md op. This prevents hangs. See
+    // https://github.com/grpc/grpc/issues/11546
+    if (options.is_last_message()) {
+      ctx_->has_pending_ops_ = true;
+      return true;
+    }
+    ctx_->has_pending_ops_ = false;
+    return call_->cq()->Pluck(&ctx_->pending_ops_);
+  }
+
+ private:
+  Call* const call_;
+  ServerContext* const ctx_;
+};
+
+}  // namespace internal
+
+/// Synchronous (blocking) server-side API for a bidirectional
+/// streaming call, where the incoming message stream coming from the client has
+/// messages of type \a R, and the outgoing message streaming coming from
+/// the server has messages of type \a W.
+template <class W, class R>
+class ServerReaderWriter final : public ServerReaderWriterInterface<W, R> {
+ public:
+  /// See the \a ServerStreamingInterface.SendInitialMetadata method
+  /// for semantics. Note that initial metadata will be affected by the
+  /// \a ServerContext associated with this call.
+  void SendInitialMetadata() override { body_.SendInitialMetadata(); }
+
+  bool NextMessageSize(uint32_t* sz) override {
+    return body_.NextMessageSize(sz);
+  }
+
+  bool Read(R* msg) override { return body_.Read(msg); }
+
+  /// See the \a WriterInterface.Write(const W& msg, WriteOptions options)
+  /// method for semantics.
+  /// Side effect:
+  ///   Also sends initial metadata if not already sent (using the \a
+  ///   ServerContext associated with this call).
+  using internal::WriterInterface<W>::Write;
+  bool Write(const W& msg, WriteOptions options) override {
+    return body_.Write(msg, options);
+  }
+
+ private:
+  internal::ServerReaderWriterBody<W, R> body_;
+
+  friend class internal::TemplatedBidiStreamingHandler<ServerReaderWriter<W, R>,
+                                                       false>;
+  ServerReaderWriter(internal::Call* call, ServerContext* ctx)
+      : body_(call, ctx) {}
+};
+
+/// A class to represent a flow-controlled unary call. This is something
+/// of a hybrid between conventional unary and streaming. This is invoked
+/// through a unary call on the client side, but the server responds to it
+/// as though it were a single-ping-pong streaming call. The server can use
+/// the \a NextMessageSize method to determine an upper-bound on the size of
+/// the message. A key difference relative to streaming: ServerUnaryStreamer
+/// must have exactly 1 Read and exactly 1 Write, in that order, to function
+/// correctly. Otherwise, the RPC is in error.
+template <class RequestType, class ResponseType>
+class ServerUnaryStreamer final
+    : public ServerReaderWriterInterface<ResponseType, RequestType> {
+ public:
+  /// Block to send initial metadata to client.
+  /// Implicit input parameter:
+  ///    - the \a ServerContext associated with this call will be used for
+  ///      sending initial metadata.
+  void SendInitialMetadata() override { body_.SendInitialMetadata(); }
+
+  /// Get an upper bound on the request message size from the client.
+  bool NextMessageSize(uint32_t* sz) override {
+    return body_.NextMessageSize(sz);
+  }
+
+  /// Read a message of type \a R into \a msg. Completion will be notified by \a
+  /// tag on the associated completion queue.
+  /// This is thread-safe with respect to \a Write or \a WritesDone methods. It
+  /// should not be called concurrently with other streaming APIs
+  /// on the same stream. It is not meaningful to call it concurrently
+  /// with another \a ReaderInterface::Read on the same stream since reads on
+  /// the same stream are delivered in order.
+  ///
+  /// \param[out] msg Where to eventually store the read message.
+  /// \param[in] tag The tag identifying the operation.
+  bool Read(RequestType* request) override {
+    if (read_done_) {
+      return false;
+    }
+    read_done_ = true;
+    return body_.Read(request);
+  }
+
+  /// Block to write \a msg to the stream with WriteOptions \a options.
+  /// This is thread-safe with respect to \a ReaderInterface::Read
+  ///
+  /// \param msg The message to be written to the stream.
+  /// \param options The WriteOptions affecting the write operation.
+  ///
+  /// \return \a true on success, \a false when the stream has been closed.
+  using internal::WriterInterface<ResponseType>::Write;
+  bool Write(const ResponseType& response, WriteOptions options) override {
+    if (write_done_ || !read_done_) {
+      return false;
+    }
+    write_done_ = true;
+    return body_.Write(response, options);
+  }
+
+ private:
+  internal::ServerReaderWriterBody<ResponseType, RequestType> body_;
+  bool read_done_;
+  bool write_done_;
+
+  friend class internal::TemplatedBidiStreamingHandler<
+      ServerUnaryStreamer<RequestType, ResponseType>, true>;
+  ServerUnaryStreamer(internal::Call* call, ServerContext* ctx)
+      : body_(call, ctx), read_done_(false), write_done_(false) {}
+};
+
+/// A class to represent a flow-controlled server-side streaming call.
+/// This is something of a hybrid between server-side and bidi streaming.
+/// This is invoked through a server-side streaming call on the client side,
+/// but the server responds to it as though it were a bidi streaming call that
+/// must first have exactly 1 Read and then any number of Writes.
+template <class RequestType, class ResponseType>
+class ServerSplitStreamer final
+    : public ServerReaderWriterInterface<ResponseType, RequestType> {
+ public:
+  /// Block to send initial metadata to client.
+  /// Implicit input parameter:
+  ///    - the \a ServerContext associated with this call will be used for
+  ///      sending initial metadata.
+  void SendInitialMetadata() override { body_.SendInitialMetadata(); }
+
+  /// Get an upper bound on the request message size from the client.
+  bool NextMessageSize(uint32_t* sz) override {
+    return body_.NextMessageSize(sz);
+  }
+
+  /// Read a message of type \a R into \a msg. Completion will be notified by \a
+  /// tag on the associated completion queue.
+  /// This is thread-safe with respect to \a Write or \a WritesDone methods. It
+  /// should not be called concurrently with other streaming APIs
+  /// on the same stream. It is not meaningful to call it concurrently
+  /// with another \a ReaderInterface::Read on the same stream since reads on
+  /// the same stream are delivered in order.
+  ///
+  /// \param[out] msg Where to eventually store the read message.
+  /// \param[in] tag The tag identifying the operation.
+  bool Read(RequestType* request) override {
+    if (read_done_) {
+      return false;
+    }
+    read_done_ = true;
+    return body_.Read(request);
+  }
+
+  /// Block to write \a msg to the stream with WriteOptions \a options.
+  /// This is thread-safe with respect to \a ReaderInterface::Read
+  ///
+  /// \param msg The message to be written to the stream.
+  /// \param options The WriteOptions affecting the write operation.
+  ///
+  /// \return \a true on success, \a false when the stream has been closed.
+  using internal::WriterInterface<ResponseType>::Write;
+  bool Write(const ResponseType& response, WriteOptions options) override {
+    return read_done_ && body_.Write(response, options);
+  }
+
+ private:
+  internal::ServerReaderWriterBody<ResponseType, RequestType> body_;
+  bool read_done_;
+
+  friend class internal::TemplatedBidiStreamingHandler<
+      ServerSplitStreamer<RequestType, ResponseType>, false>;
+  ServerSplitStreamer(internal::Call* call, ServerContext* ctx)
+      : body_(call, ctx), read_done_(false) {}
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_SYNC_STREAM_H
diff --git a/include/grpcpp/impl/codegen/time.h b/include/grpcpp/impl/codegen/time.h
new file mode 100644
index 0000000..c32f254
--- /dev/null
+++ b/include/grpcpp/impl/codegen/time.h
@@ -0,0 +1,89 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_CODEGEN_TIME_H
+#define GRPCPP_IMPL_CODEGEN_TIME_H
+
+#include <chrono>
+
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpcpp/impl/codegen/config.h>
+
+namespace grpc {
+
+/** If you are trying to use CompletionQueue::AsyncNext with a time class that
+    isn't either gpr_timespec or std::chrono::system_clock::time_point, you
+    will most likely be looking at this comment as your compiler will have
+    fired an error below. In order to fix this issue, you have two potential
+    solutions:
+
+      1. Use gpr_timespec or std::chrono::system_clock::time_point instead
+      2. Specialize the TimePoint class with whichever time class that you
+         want to use here. See below for two examples of how to do this.
+ */
+template <typename T>
+class TimePoint {
+ public:
+  TimePoint(const T& time) { you_need_a_specialization_of_TimePoint(); }
+  gpr_timespec raw_time() {
+    gpr_timespec t;
+    return t;
+  }
+
+ private:
+  void you_need_a_specialization_of_TimePoint();
+};
+
+template <>
+class TimePoint<gpr_timespec> {
+ public:
+  TimePoint(const gpr_timespec& time) : time_(time) {}
+  gpr_timespec raw_time() { return time_; }
+
+ private:
+  gpr_timespec time_;
+};
+
+}  // namespace grpc
+
+namespace grpc {
+
+// from and to should be absolute time.
+void Timepoint2Timespec(const std::chrono::system_clock::time_point& from,
+                        gpr_timespec* to);
+void TimepointHR2Timespec(
+    const std::chrono::high_resolution_clock::time_point& from,
+    gpr_timespec* to);
+
+std::chrono::system_clock::time_point Timespec2Timepoint(gpr_timespec t);
+
+template <>
+class TimePoint<std::chrono::system_clock::time_point> {
+ public:
+  TimePoint(const std::chrono::system_clock::time_point& time) {
+    Timepoint2Timespec(time, &time_);
+  }
+  gpr_timespec raw_time() const { return time_; }
+
+ private:
+  gpr_timespec time_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_CODEGEN_TIME_H
diff --git a/include/grpcpp/impl/grpc_library.h b/include/grpcpp/impl/grpc_library.h
new file mode 100644
index 0000000..d1f3ff1
--- /dev/null
+++ b/include/grpcpp/impl/grpc_library.h
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_GRPC_LIBRARY_H
+#define GRPCPP_IMPL_GRPC_LIBRARY_H
+
+#include <iostream>
+
+#include <grpc/grpc.h>
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/core_codegen.h>
+#include <grpcpp/impl/codegen/grpc_library.h>
+
+namespace grpc {
+
+namespace internal {
+class GrpcLibrary final : public GrpcLibraryInterface {
+ public:
+  void init() override { grpc_init(); }
+  void shutdown() override { grpc_shutdown(); }
+};
+
+static GrpcLibrary g_gli;
+static CoreCodegen g_core_codegen;
+
+/// Instantiating this class ensures the proper initialization of gRPC.
+class GrpcLibraryInitializer final {
+ public:
+  GrpcLibraryInitializer() {
+    if (grpc::g_glip == nullptr) {
+      grpc::g_glip = &g_gli;
+    }
+    if (grpc::g_core_codegen_interface == nullptr) {
+      grpc::g_core_codegen_interface = &g_core_codegen;
+    }
+  }
+
+  /// A no-op method to force the linker to reference this class, which will
+  /// take care of initializing and shutting down the gRPC runtime.
+  int summon() { return 0; }
+};
+
+}  // namespace internal
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_GRPC_LIBRARY_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/impl/method_handler_impl.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/impl/method_handler_impl.h
index 692c00c..7f3be64 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/impl/method_handler_impl.h
@@ -16,15 +16,9 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_IMPL_METHOD_HANDLER_IMPL_H
+#define GRPCPP_IMPL_METHOD_HANDLER_IMPL_H
 
-#include <grpc/support/time.h>
+#include <grpcpp/impl/codegen/method_handler_impl.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_IMPL_METHOD_HANDLER_IMPL_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/impl/rpc_method.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/impl/rpc_method.h
index 692c00c..5da7041 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/impl/rpc_method.h
@@ -16,15 +16,9 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_IMPL_RPC_METHOD_H
+#define GRPCPP_IMPL_RPC_METHOD_H
 
-#include <grpc/support/time.h>
+#include <grpcpp/impl/codegen/rpc_method.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_IMPL_RPC_METHOD_H
diff --git a/src/core/lib/iomgr/timer_uv.h b/include/grpcpp/impl/rpc_service_method.h
similarity index 62%
rename from src/core/lib/iomgr/timer_uv.h
rename to include/grpcpp/impl/rpc_service_method.h
index 214aaa6..ef70a3a 100644
--- a/src/core/lib/iomgr/timer_uv.h
+++ b/include/grpcpp/impl/rpc_service_method.h
@@ -16,17 +16,9 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_IOMGR_TIMER_UV_H
-#define GRPC_CORE_LIB_IOMGR_TIMER_UV_H
+#ifndef GRPCPP_IMPL_RPC_SERVICE_METHOD_H
+#define GRPCPP_IMPL_RPC_SERVICE_METHOD_H
 
-#include "src/core/lib/iomgr/exec_ctx.h"
+#include <grpcpp/impl/codegen/rpc_service_method.h>
 
-struct grpc_timer {
-  grpc_closure* closure;
-  /* This is actually a uv_timer_t*, but we want to keep platform-specific
-     types out of headers */
-  void* uv_timer;
-  int pending;
-};
-
-#endif /* GRPC_CORE_LIB_IOMGR_TIMER_UV_H */
+#endif  // GRPCPP_IMPL_RPC_SERVICE_METHOD_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/impl/serialization_traits.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/impl/serialization_traits.h
index 692c00c..95194fb 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/impl/serialization_traits.h
@@ -16,15 +16,9 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_IMPL_SERIALIZATION_TRAITS_H
+#define GRPCPP_IMPL_SERIALIZATION_TRAITS_H
 
-#include <grpc/support/time.h>
+#include <grpcpp/impl/codegen/serialization_traits.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_IMPL_SERIALIZATION_TRAITS_H
diff --git a/include/grpcpp/impl/server_builder_option.h b/include/grpcpp/impl/server_builder_option.h
new file mode 100644
index 0000000..c7b7801
--- /dev/null
+++ b/include/grpcpp/impl/server_builder_option.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_SERVER_BUILDER_OPTION_H
+#define GRPCPP_IMPL_SERVER_BUILDER_OPTION_H
+
+#include <map>
+#include <memory>
+
+#include <grpcpp/impl/server_builder_plugin.h>
+#include <grpcpp/support/channel_arguments.h>
+
+namespace grpc {
+
+/// Interface to pass an option to a \a ServerBuilder.
+class ServerBuilderOption {
+ public:
+  virtual ~ServerBuilderOption() {}
+  /// Alter the \a ChannelArguments used to create the gRPC server.
+  virtual void UpdateArguments(ChannelArguments* args) = 0;
+  /// Alter the ServerBuilderPlugin map that will be added into ServerBuilder.
+  virtual void UpdatePlugins(
+      std::vector<std::unique_ptr<ServerBuilderPlugin>>* plugins) = 0;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_SERVER_BUILDER_OPTION_H
diff --git a/include/grpcpp/impl/server_builder_plugin.h b/include/grpcpp/impl/server_builder_plugin.h
new file mode 100644
index 0000000..d73511e
--- /dev/null
+++ b/include/grpcpp/impl/server_builder_plugin.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_SERVER_BUILDER_PLUGIN_H
+#define GRPCPP_IMPL_SERVER_BUILDER_PLUGIN_H
+
+#include <memory>
+
+#include <grpcpp/support/config.h>
+
+namespace grpc {
+
+class ServerBuilder;
+class ServerInitializer;
+class ChannelArguments;
+
+/// This interface is meant for internal usage only. Implementations of this
+/// interface should add themselves to a \a ServerBuilder instance through the
+/// \a InternalAddPluginFactory method.
+class ServerBuilderPlugin {
+ public:
+  virtual ~ServerBuilderPlugin() {}
+  virtual grpc::string name() = 0;
+
+  /// UpdateServerBuilder will be called at the beginning of
+  /// \a ServerBuilder::BuildAndStart().
+  virtual void UpdateServerBuilder(ServerBuilder* builder) {}
+
+  /// InitServer will be called in ServerBuilder::BuildAndStart(), after the
+  /// Server instance is created.
+  virtual void InitServer(ServerInitializer* si) = 0;
+
+  /// Finish will be called at the end of ServerBuilder::BuildAndStart().
+  virtual void Finish(ServerInitializer* si) = 0;
+
+  /// ChangeArguments is an interface that can be used in
+  /// ServerBuilderOption::UpdatePlugins
+  virtual void ChangeArguments(const grpc::string& name, void* value) = 0;
+
+  /// UpdateChannelArguments will be called in ServerBuilder::BuildAndStart(),
+  /// before the Server instance is created.
+  virtual void UpdateChannelArguments(ChannelArguments* args) {}
+
+  virtual bool has_sync_methods() const { return false; }
+  virtual bool has_async_methods() const { return false; }
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_SERVER_BUILDER_PLUGIN_H
diff --git a/include/grpcpp/impl/server_initializer.h b/include/grpcpp/impl/server_initializer.h
new file mode 100644
index 0000000..f949fab
--- /dev/null
+++ b/include/grpcpp/impl/server_initializer.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_IMPL_SERVER_INITIALIZER_H
+#define GRPCPP_IMPL_SERVER_INITIALIZER_H
+
+#include <memory>
+#include <vector>
+
+#include <grpcpp/server.h>
+
+namespace grpc {
+
+class Server;
+class Service;
+
+class ServerInitializer {
+ public:
+  ServerInitializer(Server* server) : server_(server) {}
+
+  bool RegisterService(std::shared_ptr<Service> service) {
+    if (!server_->RegisterService(nullptr, service.get())) {
+      return false;
+    }
+    default_services_.push_back(service);
+    return true;
+  }
+
+  const std::vector<grpc::string>* GetServiceList() {
+    return &server_->services_;
+  }
+
+ private:
+  Server* server_;
+  std::vector<std::shared_ptr<Service> > default_services_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_IMPL_SERVER_INITIALIZER_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/impl/service_type.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/impl/service_type.h
index 692c00c..250bc8c 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/impl/service_type.h
@@ -16,15 +16,9 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_IMPL_SERVICE_TYPE_H
+#define GRPCPP_IMPL_SERVICE_TYPE_H
 
-#include <grpc/support/time.h>
+#include <grpcpp/impl/codegen/service_type.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_IMPL_SERVICE_TYPE_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/impl/sync_cxx11.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/impl/sync_cxx11.h
index 692c00c..76dcfe3 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/impl/sync_cxx11.h
@@ -16,15 +16,9 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_IMPL_SYNC_CXX11_H
+#define GRPCPP_IMPL_SYNC_CXX11_H
 
-#include <grpc/support/time.h>
+#include <grpcpp/impl/codegen/sync_cxx11.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_IMPL_SYNC_CXX11_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/impl/sync_no_cxx11.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/impl/sync_no_cxx11.h
index 692c00c..cc2d4f1 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/impl/sync_no_cxx11.h
@@ -16,15 +16,9 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_IMPL_SYNC_NO_CXX11_H
+#define GRPCPP_IMPL_SYNC_NO_CXX11_H
 
-#include <grpc/support/time.h>
+#include <grpcpp/impl/codegen/sync_no_cxx11.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_IMPL_SYNC_NO_CXX11_H
diff --git a/include/grpcpp/resource_quota.h b/include/grpcpp/resource_quota.h
new file mode 100644
index 0000000..554437a
--- /dev/null
+++ b/include/grpcpp/resource_quota.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_RESOURCE_QUOTA_H
+#define GRPCPP_RESOURCE_QUOTA_H
+
+struct grpc_resource_quota;
+
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/grpc_library.h>
+
+namespace grpc {
+
+/// ResourceQuota represents a bound on memory usage by the gRPC library.
+/// A ResourceQuota can be attached to a server (via \a ServerBuilder),
+/// or a client channel (via \a ChannelArguments).
+/// gRPC will attempt to keep memory used by all attached entities
+/// below the ResourceQuota bound.
+class ResourceQuota final : private GrpcLibraryCodegen {
+ public:
+  /// \param name - a unique name for this ResourceQuota.
+  explicit ResourceQuota(const grpc::string& name);
+  ResourceQuota();
+  ~ResourceQuota();
+
+  /// Resize this \a ResourceQuota to a new size. If \a new_size is smaller
+  /// than the current size of the pool, memory usage will be monotonically
+  /// decreased until it falls under \a new_size.
+  /// No time bound is given for this to occur however.
+  ResourceQuota& Resize(size_t new_size);
+
+  grpc_resource_quota* c_resource_quota() const { return impl_; }
+
+ private:
+  ResourceQuota(const ResourceQuota& rhs);
+  ResourceQuota& operator=(const ResourceQuota& rhs);
+
+  grpc_resource_quota* const impl_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_RESOURCE_QUOTA_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/security/auth_context.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/security/auth_context.h
index 692c00c..7a6f2cb 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/security/auth_context.h
@@ -16,15 +16,9 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_SECURITY_AUTH_CONTEXT_H
+#define GRPCPP_SECURITY_AUTH_CONTEXT_H
 
-#include <grpc/support/time.h>
+#include <grpcpp/impl/codegen/security/auth_context.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_SECURITY_AUTH_CONTEXT_H
diff --git a/include/grpcpp/security/auth_metadata_processor.h b/include/grpcpp/security/auth_metadata_processor.h
new file mode 100644
index 0000000..30e24c9
--- /dev/null
+++ b/include/grpcpp/security/auth_metadata_processor.h
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_SECURITY_AUTH_METADATA_PROCESSOR_H
+#define GRPCPP_SECURITY_AUTH_METADATA_PROCESSOR_H
+
+#include <map>
+
+#include <grpcpp/security/auth_context.h>
+#include <grpcpp/support/status.h>
+#include <grpcpp/support/string_ref.h>
+
+namespace grpc {
+
+/// Interface allowing custom server-side authorization based on credentials
+/// encoded in metadata.  Objects of this type can be passed to
+/// \a ServerCredentials::SetAuthMetadataProcessor().
+class AuthMetadataProcessor {
+ public:
+  typedef std::multimap<grpc::string_ref, grpc::string_ref> InputMetadata;
+  typedef std::multimap<grpc::string, grpc::string> OutputMetadata;
+
+  virtual ~AuthMetadataProcessor() {}
+
+  /// If this method returns true, the \a Process function will be scheduled in
+  /// a different thread from the one processing the call.
+  virtual bool IsBlocking() const { return true; }
+
+  /// context is read/write: it contains the properties of the channel peer and
+  /// it is the job of the Process method to augment it with properties derived
+  /// from the passed-in auth_metadata.
+  /// consumed_auth_metadata needs to be filled with metadata that has been
+  /// consumed by the processor and will be removed from the call.
+  /// response_metadata is the metadata that will be sent as part of the
+  /// response.
+  /// If the return value is not Status::OK, the rpc call will be aborted with
+  /// the error code and error message sent back to the client.
+  virtual Status Process(const InputMetadata& auth_metadata,
+                         AuthContext* context,
+                         OutputMetadata* consumed_auth_metadata,
+                         OutputMetadata* response_metadata) = 0;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_SECURITY_AUTH_METADATA_PROCESSOR_H
diff --git a/include/grpcpp/security/credentials.h b/include/grpcpp/security/credentials.h
new file mode 100644
index 0000000..837a0e4
--- /dev/null
+++ b/include/grpcpp/security/credentials.h
@@ -0,0 +1,224 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_SECURITY_CREDENTIALS_H
+#define GRPCPP_SECURITY_CREDENTIALS_H
+
+#include <map>
+#include <memory>
+
+#include <grpcpp/impl/codegen/grpc_library.h>
+#include <grpcpp/security/auth_context.h>
+#include <grpcpp/support/status.h>
+#include <grpcpp/support/string_ref.h>
+
+struct grpc_call;
+
+namespace grpc {
+class ChannelArguments;
+class Channel;
+class SecureChannelCredentials;
+class CallCredentials;
+class SecureCallCredentials;
+
+/// A channel credentials object encapsulates all the state needed by a client
+/// to authenticate with a server for a given channel.
+/// It can make various assertions, e.g., about the client’s identity, role
+/// for all the calls on that channel.
+///
+/// \see https://grpc.io/docs/guides/auth.html
+class ChannelCredentials : private GrpcLibraryCodegen {
+ public:
+  ChannelCredentials();
+  ~ChannelCredentials();
+
+ protected:
+  friend std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
+      const std::shared_ptr<ChannelCredentials>& channel_creds,
+      const std::shared_ptr<CallCredentials>& call_creds);
+
+  virtual SecureChannelCredentials* AsSecureCredentials() = 0;
+
+ private:
+  friend std::shared_ptr<Channel> CreateCustomChannel(
+      const grpc::string& target,
+      const std::shared_ptr<ChannelCredentials>& creds,
+      const ChannelArguments& args);
+
+  virtual std::shared_ptr<Channel> CreateChannel(
+      const grpc::string& target, const ChannelArguments& args) = 0;
+};
+
+/// A call credentials object encapsulates the state needed by a client to
+/// authenticate with a server for a given call on a channel.
+///
+/// \see https://grpc.io/docs/guides/auth.html
+class CallCredentials : private GrpcLibraryCodegen {
+ public:
+  CallCredentials();
+  ~CallCredentials();
+
+  /// Apply this instance's credentials to \a call.
+  virtual bool ApplyToCall(grpc_call* call) = 0;
+
+ protected:
+  friend std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
+      const std::shared_ptr<ChannelCredentials>& channel_creds,
+      const std::shared_ptr<CallCredentials>& call_creds);
+
+  friend std::shared_ptr<CallCredentials> CompositeCallCredentials(
+      const std::shared_ptr<CallCredentials>& creds1,
+      const std::shared_ptr<CallCredentials>& creds2);
+
+  virtual SecureCallCredentials* AsSecureCredentials() = 0;
+};
+
+/// Options used to build SslCredentials.
+struct SslCredentialsOptions {
+  /// The buffer containing the PEM encoding of the server root certificates. If
+  /// this parameter is empty, the default roots will be used.  The default
+  /// roots can be overridden using the \a GRPC_DEFAULT_SSL_ROOTS_FILE_PATH
+  /// environment variable pointing to a file on the file system containing the
+  /// roots.
+  grpc::string pem_root_certs;
+
+  /// The buffer containing the PEM encoding of the client's private key. This
+  /// parameter can be empty if the client does not have a private key.
+  grpc::string pem_private_key;
+
+  /// The buffer containing the PEM encoding of the client's certificate chain.
+  /// This parameter can be empty if the client does not have a certificate
+  /// chain.
+  grpc::string pem_cert_chain;
+};
+
+// Factories for building different types of Credentials The functions may
+// return empty shared_ptr when credentials cannot be created. If a
+// Credentials pointer is returned, it can still be invalid when used to create
+// a channel. A lame channel will be created then and all rpcs will fail on it.
+
+/// Builds credentials with reasonable defaults.
+///
+/// \warning Only use these credentials when connecting to a Google endpoint.
+/// Using these credentials to connect to any other service may result in this
+/// service being able to impersonate your client for requests to Google
+/// services.
+std::shared_ptr<ChannelCredentials> GoogleDefaultCredentials();
+
+/// Builds SSL Credentials given SSL specific options
+std::shared_ptr<ChannelCredentials> SslCredentials(
+    const SslCredentialsOptions& options);
+
+/// Builds credentials for use when running in GCE
+///
+/// \warning Only use these credentials when connecting to a Google endpoint.
+/// Using these credentials to connect to any other service may result in this
+/// service being able to impersonate your client for requests to Google
+/// services.
+std::shared_ptr<CallCredentials> GoogleComputeEngineCredentials();
+
+/// Constant for maximum auth token lifetime.
+constexpr long kMaxAuthTokenLifetimeSecs = 3600;
+
+/// Builds Service Account JWT Access credentials.
+/// json_key is the JSON key string containing the client's private key.
+/// token_lifetime_seconds is the lifetime in seconds of each Json Web Token
+/// (JWT) created with this credentials. It should not exceed
+/// \a kMaxAuthTokenLifetimeSecs or will be cropped to this value.
+std::shared_ptr<CallCredentials> ServiceAccountJWTAccessCredentials(
+    const grpc::string& json_key,
+    long token_lifetime_seconds = kMaxAuthTokenLifetimeSecs);
+
+/// Builds refresh token credentials.
+/// json_refresh_token is the JSON string containing the refresh token along
+/// with a client_id and client_secret.
+///
+/// \warning Only use these credentials when connecting to a Google endpoint.
+/// Using these credentials to connect to any other service may result in this
+/// service being able to impersonate your client for requests to Google
+/// services.
+std::shared_ptr<CallCredentials> GoogleRefreshTokenCredentials(
+    const grpc::string& json_refresh_token);
+
+/// Builds access token credentials.
+/// access_token is an oauth2 access token that was fetched using an out of band
+/// mechanism.
+///
+/// \warning Only use these credentials when connecting to a Google endpoint.
+/// Using these credentials to connect to any other service may result in this
+/// service being able to impersonate your client for requests to Google
+/// services.
+std::shared_ptr<CallCredentials> AccessTokenCredentials(
+    const grpc::string& access_token);
+
+/// Builds IAM credentials.
+///
+/// \warning Only use these credentials when connecting to a Google endpoint.
+/// Using these credentials to connect to any other service may result in this
+/// service being able to impersonate your client for requests to Google
+/// services.
+std::shared_ptr<CallCredentials> GoogleIAMCredentials(
+    const grpc::string& authorization_token,
+    const grpc::string& authority_selector);
+
+/// Combines a channel credentials and a call credentials into a composite
+/// channel credentials.
+std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
+    const std::shared_ptr<ChannelCredentials>& channel_creds,
+    const std::shared_ptr<CallCredentials>& call_creds);
+
+/// Combines two call credentials objects into a composite call credentials.
+std::shared_ptr<CallCredentials> CompositeCallCredentials(
+    const std::shared_ptr<CallCredentials>& creds1,
+    const std::shared_ptr<CallCredentials>& creds2);
+
+/// Credentials for an unencrypted, unauthenticated channel
+std::shared_ptr<ChannelCredentials> InsecureChannelCredentials();
+
+/// Credentials for a channel using Cronet.
+std::shared_ptr<ChannelCredentials> CronetChannelCredentials(void* engine);
+
+/// User defined metadata credentials.
+class MetadataCredentialsPlugin {
+ public:
+  virtual ~MetadataCredentialsPlugin() {}
+
+  /// If this method returns true, the Process function will be scheduled in
+  /// a different thread from the one processing the call.
+  virtual bool IsBlocking() const { return true; }
+
+  /// Type of credentials this plugin is implementing.
+  virtual const char* GetType() const { return ""; }
+
+  /// Gets the auth metatada produced by this plugin.
+  /// The fully qualified method name is:
+  /// service_url + "/" + method_name.
+  /// The channel_auth_context contains (among other things), the identity of
+  /// the server.
+  virtual Status GetMetadata(
+      grpc::string_ref service_url, grpc::string_ref method_name,
+      const AuthContext& channel_auth_context,
+      std::multimap<grpc::string, grpc::string>* metadata) = 0;
+};
+
+std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
+    std::unique_ptr<MetadataCredentialsPlugin> plugin);
+
+}  // namespace grpc
+
+#endif  // GRPCPP_SECURITY_CREDENTIALS_H
diff --git a/include/grpcpp/security/server_credentials.h b/include/grpcpp/security/server_credentials.h
new file mode 100644
index 0000000..892863e
--- /dev/null
+++ b/include/grpcpp/security/server_credentials.h
@@ -0,0 +1,91 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_SECURITY_SERVER_CREDENTIALS_H
+#define GRPCPP_SECURITY_SERVER_CREDENTIALS_H
+
+#include <memory>
+#include <vector>
+
+#include <grpc/grpc_security_constants.h>
+#include <grpcpp/security/auth_metadata_processor.h>
+#include <grpcpp/support/config.h>
+
+struct grpc_server;
+
+namespace grpc {
+class Server;
+
+/// Wrapper around \a grpc_server_credentials, a way to authenticate a server.
+class ServerCredentials {
+ public:
+  virtual ~ServerCredentials();
+
+  /// This method is not thread-safe and has to be called before the server is
+  /// started. The last call to this function wins.
+  virtual void SetAuthMetadataProcessor(
+      const std::shared_ptr<AuthMetadataProcessor>& processor) = 0;
+
+ private:
+  friend class ::grpc::Server;
+
+  /// Tries to bind \a server to the given \a addr (eg, localhost:1234,
+  /// 192.168.1.1:31416, [::1]:27182, etc.)
+  ///
+  /// \return bound port number on sucess, 0 on failure.
+  // TODO(dgq): the "port" part seems to be a misnomer.
+  virtual int AddPortToServer(const grpc::string& addr,
+                              grpc_server* server) = 0;
+};
+
+/// Options to create ServerCredentials with SSL
+struct SslServerCredentialsOptions {
+  /// \warning Deprecated
+  SslServerCredentialsOptions()
+      : force_client_auth(false),
+        client_certificate_request(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE) {}
+  SslServerCredentialsOptions(
+      grpc_ssl_client_certificate_request_type request_type)
+      : force_client_auth(false), client_certificate_request(request_type) {}
+
+  struct PemKeyCertPair {
+    grpc::string private_key;
+    grpc::string cert_chain;
+  };
+  grpc::string pem_root_certs;
+  std::vector<PemKeyCertPair> pem_key_cert_pairs;
+  /// \warning Deprecated
+  bool force_client_auth;
+
+  /// If both \a force_client_auth and \a client_certificate_request
+  /// fields are set, \a force_client_auth takes effect, i.e.
+  /// \a REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
+  /// will be enforced.
+  grpc_ssl_client_certificate_request_type client_certificate_request;
+};
+
+/// Builds SSL ServerCredentials given SSL specific options
+std::shared_ptr<ServerCredentials> SslServerCredentials(
+    const SslServerCredentialsOptions& options);
+
+/// Builds insecure server credentials.
+std::shared_ptr<ServerCredentials> InsecureServerCredentials();
+
+}  // namespace grpc
+
+#endif  // GRPCPP_SECURITY_SERVER_CREDENTIALS_H
diff --git a/include/grpcpp/server.h b/include/grpcpp/server.h
new file mode 100644
index 0000000..81c3907
--- /dev/null
+++ b/include/grpcpp/server.h
@@ -0,0 +1,225 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_SERVER_H
+#define GRPCPP_SERVER_H
+
+#include <condition_variable>
+#include <list>
+#include <memory>
+#include <mutex>
+#include <vector>
+
+#include <grpc/compression.h>
+#include <grpcpp/completion_queue.h>
+#include <grpcpp/impl/call.h>
+#include <grpcpp/impl/codegen/grpc_library.h>
+#include <grpcpp/impl/codegen/server_interface.h>
+#include <grpcpp/impl/rpc_service_method.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/support/channel_arguments.h>
+#include <grpcpp/support/config.h>
+#include <grpcpp/support/status.h>
+
+struct grpc_server;
+
+namespace grpc {
+
+class AsyncGenericService;
+class HealthCheckServiceInterface;
+class ServerContext;
+class ServerInitializer;
+
+/// Represents a gRPC server.
+///
+/// Use a \a grpc::ServerBuilder to create, configure, and start
+/// \a Server instances.
+class Server : public ServerInterface, private GrpcLibraryCodegen {
+ public:
+  ~Server();
+
+  /// Block until the server shuts down.
+  ///
+  /// \warning The server must be either shutting down or some other thread must
+  /// call \a Shutdown for this function to ever return.
+  void Wait() override;
+
+  /// Global callbacks are a set of hooks that are called when server
+  /// events occur.  \a SetGlobalCallbacks method is used to register
+  /// the hooks with gRPC.  Note that
+  /// the \a GlobalCallbacks instance will be shared among all
+  /// \a Server instances in an application and can be set exactly
+  /// once per application.
+  class GlobalCallbacks {
+   public:
+    virtual ~GlobalCallbacks() {}
+    /// Called before server is created.
+    virtual void UpdateArguments(ChannelArguments* args) {}
+    /// Called before application callback for each synchronous server request
+    virtual void PreSynchronousRequest(ServerContext* context) = 0;
+    /// Called after application callback for each synchronous server request
+    virtual void PostSynchronousRequest(ServerContext* context) = 0;
+    /// Called before server is started.
+    virtual void PreServerStart(Server* server) {}
+    /// Called after a server port is added.
+    virtual void AddPort(Server* server, const grpc::string& addr,
+                         ServerCredentials* creds, int port) {}
+  };
+  /// Set the global callback object. Can only be called once per application.
+  /// Does not take ownership of callbacks, and expects the pointed to object
+  /// to be alive until all server objects in the process have been destroyed.
+  /// The same \a GlobalCallbacks object will be used throughout the
+  /// application and is shared among all \a Server objects.
+  static void SetGlobalCallbacks(GlobalCallbacks* callbacks);
+
+  /// Returns a \em raw pointer to the underlying \a grpc_server instance.
+  /// EXPERIMENTAL:  for internal/test use only
+  grpc_server* c_server();
+
+  /// Returns the health check service.
+  HealthCheckServiceInterface* GetHealthCheckService() const {
+    return health_check_service_.get();
+  }
+
+  /// Establish a channel for in-process communication
+  std::shared_ptr<Channel> InProcessChannel(const ChannelArguments& args);
+
+ protected:
+  /// Register a service. This call does not take ownership of the service.
+  /// The service must exist for the lifetime of the Server instance.
+  bool RegisterService(const grpc::string* host, Service* service) override;
+
+  /// Try binding the server to the given \a addr endpoint
+  /// (port, and optionally including IP address to bind to).
+  ///
+  /// It can be invoked multiple times. Should be used before
+  /// starting the server.
+  ///
+  /// \param addr The address to try to bind to the server (eg, localhost:1234,
+  /// 192.168.1.1:31416, [::1]:27182, etc.).
+  /// \param creds The credentials associated with the server.
+  ///
+  /// \return bound port number on success, 0 on failure.
+  ///
+  /// \warning It is an error to call this method on an already started server.
+  int AddListeningPort(const grpc::string& addr,
+                       ServerCredentials* creds) override;
+
+  /// Server constructors. To be used by \a ServerBuilder only.
+  ///
+  /// \param max_message_size Maximum message length that the channel can
+  /// receive.
+  ///
+  /// \param args The channel args
+  ///
+  /// \param sync_server_cqs The completion queues to use if the server is a
+  /// synchronous server (or a hybrid server). The server polls for new RPCs on
+  /// these queues
+  ///
+  /// \param min_pollers The minimum number of polling threads per server
+  /// completion queue (in param sync_server_cqs) to use for listening to
+  /// incoming requests (used only in case of sync server)
+  ///
+  /// \param max_pollers The maximum number of polling threads per server
+  /// completion queue (in param sync_server_cqs) to use for listening to
+  /// incoming requests (used only in case of sync server)
+  ///
+  /// \param sync_cq_timeout_msec The timeout to use when calling AsyncNext() on
+  /// server completion queues passed via sync_server_cqs param.
+  Server(int max_message_size, ChannelArguments* args,
+         std::shared_ptr<std::vector<std::unique_ptr<ServerCompletionQueue>>>
+             sync_server_cqs,
+         int min_pollers, int max_pollers, int sync_cq_timeout_msec);
+
+  /// Start the server.
+  ///
+  /// \param cqs Completion queues for handling asynchronous services. The
+  /// caller is required to keep all completion queues live until the server is
+  /// destroyed.
+  /// \param num_cqs How many completion queues does \a cqs hold.
+  void Start(ServerCompletionQueue** cqs, size_t num_cqs) override;
+
+  grpc_server* server() override { return server_; };
+
+ private:
+  friend class AsyncGenericService;
+  friend class ServerBuilder;
+  friend class ServerInitializer;
+
+  class SyncRequest;
+  class UnimplementedAsyncRequest;
+  class UnimplementedAsyncResponse;
+
+  /// SyncRequestThreadManager is an implementation of ThreadManager. This class
+  /// is responsible for polling for incoming RPCs and calling the RPC handlers.
+  /// This is only used in case of a Sync server (i.e a server exposing a sync
+  /// interface)
+  class SyncRequestThreadManager;
+
+  /// Register a generic service. This call does not take ownership of the
+  /// service. The service must exist for the lifetime of the Server instance.
+  void RegisterAsyncGenericService(AsyncGenericService* service) override;
+
+  void PerformOpsOnCall(internal::CallOpSetInterface* ops,
+                        internal::Call* call) override;
+
+  void ShutdownInternal(gpr_timespec deadline) override;
+
+  int max_receive_message_size() const override {
+    return max_receive_message_size_;
+  };
+
+  ServerInitializer* initializer();
+
+  const int max_receive_message_size_;
+
+  /// The following completion queues are ONLY used in case of Sync API
+  /// i.e. if the server has any services with sync methods. The server uses
+  /// these completion queues to poll for new RPCs
+  std::shared_ptr<std::vector<std::unique_ptr<ServerCompletionQueue>>>
+      sync_server_cqs_;
+
+  /// List of \a ThreadManager instances (one for each cq in
+  /// the \a sync_server_cqs)
+  std::vector<std::unique_ptr<SyncRequestThreadManager>> sync_req_mgrs_;
+
+  // Server status
+  std::mutex mu_;
+  bool started_;
+  bool shutdown_;
+  bool shutdown_notified_;  // Was notify called on the shutdown_cv_
+
+  std::condition_variable shutdown_cv_;
+
+  std::shared_ptr<GlobalCallbacks> global_callbacks_;
+
+  std::vector<grpc::string> services_;
+  bool has_generic_service_;
+
+  // Pointer to the wrapped grpc_server.
+  grpc_server* server_;
+
+  std::unique_ptr<ServerInitializer> server_initializer_;
+
+  std::unique_ptr<HealthCheckServiceInterface> health_check_service_;
+  bool health_check_service_disabled_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_SERVER_H
diff --git a/include/grpcpp/server_builder.h b/include/grpcpp/server_builder.h
new file mode 100644
index 0000000..4c8dcf4
--- /dev/null
+++ b/include/grpcpp/server_builder.h
@@ -0,0 +1,302 @@
+/*
+ *
+ * Copyright 2015-2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_SERVER_BUILDER_H
+#define GRPCPP_SERVER_BUILDER_H
+
+#include <climits>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include <grpc/compression.h>
+#include <grpc/support/cpu.h>
+#include <grpc/support/workaround_list.h>
+#include <grpcpp/impl/channel_argument_option.h>
+#include <grpcpp/impl/server_builder_option.h>
+#include <grpcpp/impl/server_builder_plugin.h>
+#include <grpcpp/support/config.h>
+
+struct grpc_resource_quota;
+
+namespace grpc {
+
+class AsyncGenericService;
+class ResourceQuota;
+class CompletionQueue;
+class Server;
+class ServerCompletionQueue;
+class ServerCredentials;
+class Service;
+
+namespace testing {
+class ServerBuilderPluginTest;
+}  // namespace testing
+
+/// A builder class for the creation and startup of \a grpc::Server instances.
+class ServerBuilder {
+ public:
+  ServerBuilder();
+  virtual ~ServerBuilder();
+
+  //////////////////////////////////////////////////////////////////////////////
+  // Primary API's
+
+  /// Return a running server which is ready for processing calls.
+  /// Before calling, one typically needs to ensure that:
+  ///  1. a service is registered - so that the server knows what to serve
+  ///     (via RegisterService, or RegisterAsyncGenericService)
+  ///  2. a listening port has been added - so the server knows where to receive
+  ///     traffic (via AddListeningPort)
+  ///  3. [for async api only] completion queues have been added via
+  ///     AddCompletionQueue
+  virtual std::unique_ptr<Server> BuildAndStart();
+
+  /// Register a service. This call does not take ownership of the service.
+  /// The service must exist for the lifetime of the \a Server instance returned
+  /// by \a BuildAndStart().
+  /// Matches requests with any :authority
+  ServerBuilder& RegisterService(Service* service);
+
+  /// Enlists an endpoint \a addr (port with an optional IP address) to
+  /// bind the \a grpc::Server object to be created to.
+  ///
+  /// It can be invoked multiple times.
+  ///
+  /// \param addr_uri The address to try to bind to the server in URI form. If
+  /// the scheme name is omitted, "dns:///" is assumed. To bind to any address,
+  /// please use IPv6 any, i.e., [::]:<port>, which also accepts IPv4
+  /// connections.  Valid values include dns:///localhost:1234, /
+  /// 192.168.1.1:31416, dns:///[::1]:27182, etc.).
+  /// \param creds The credentials associated with the server.
+  /// \param selected_port[out] If not `nullptr`, gets populated with the port
+  /// number bound to the \a grpc::Server for the corresponding endpoint after
+  /// it is successfully bound, 0 otherwise.
+  ///
+  ServerBuilder& AddListeningPort(const grpc::string& addr_uri,
+                                  std::shared_ptr<ServerCredentials> creds,
+                                  int* selected_port = nullptr);
+
+  /// Add a completion queue for handling asynchronous services.
+  ///
+  /// Best performance is typically obtained by using one thread per polling
+  /// completion queue.
+  ///
+  /// Caller is required to shutdown the server prior to shutting down the
+  /// returned completion queue. Caller is also required to drain the
+  /// completion queue after shutting it down. A typical usage scenario:
+  ///
+  /// // While building the server:
+  /// ServerBuilder builder;
+  /// ...
+  /// cq_ = builder.AddCompletionQueue();
+  /// server_ = builder.BuildAndStart();
+  ///
+  /// // While shutting down the server;
+  /// server_->Shutdown();
+  /// cq_->Shutdown();  // Always *after* the associated server's Shutdown()!
+  /// // Drain the cq_ that was created
+  /// void* ignored_tag;
+  /// bool ignored_ok;
+  /// while (cq_->Next(&ignored_tag, &ignored_ok)) { }
+  ///
+  /// \param is_frequently_polled This is an optional parameter to inform gRPC
+  /// library about whether this completion queue would be frequently polled
+  /// (i.e. by calling \a Next() or \a AsyncNext()). The default value is
+  /// 'true' and is the recommended setting. Setting this to 'false' (i.e.
+  /// not polling the completion queue frequently) will have a significantly
+  /// negative performance impact and hence should not be used in production
+  /// use cases.
+  std::unique_ptr<ServerCompletionQueue> AddCompletionQueue(
+      bool is_frequently_polled = true);
+
+  //////////////////////////////////////////////////////////////////////////////
+  // Less commonly used RegisterService variants
+
+  /// Register a service. This call does not take ownership of the service.
+  /// The service must exist for the lifetime of the \a Server instance returned
+  /// by \a BuildAndStart().
+  /// Only matches requests with :authority \a host
+  ServerBuilder& RegisterService(const grpc::string& host, Service* service);
+
+  /// Register a generic service.
+  /// Matches requests with any :authority
+  /// This is mostly useful for writing generic gRPC Proxies where the exact
+  /// serialization format is unknown
+  ServerBuilder& RegisterAsyncGenericService(AsyncGenericService* service);
+
+  //////////////////////////////////////////////////////////////////////////////
+  // Fine control knobs
+
+  /// Set max receive message size in bytes.
+  ServerBuilder& SetMaxReceiveMessageSize(int max_receive_message_size) {
+    max_receive_message_size_ = max_receive_message_size;
+    return *this;
+  }
+
+  /// Set max send message size in bytes.
+  ServerBuilder& SetMaxSendMessageSize(int max_send_message_size) {
+    max_send_message_size_ = max_send_message_size;
+    return *this;
+  }
+
+  /// \deprecated For backward compatibility.
+  ServerBuilder& SetMaxMessageSize(int max_message_size) {
+    return SetMaxReceiveMessageSize(max_message_size);
+  }
+
+  /// Set the support status for compression algorithms. All algorithms are
+  /// enabled by default.
+  ///
+  /// Incoming calls compressed with an unsupported algorithm will fail with
+  /// \a GRPC_STATUS_UNIMPLEMENTED.
+  ServerBuilder& SetCompressionAlgorithmSupportStatus(
+      grpc_compression_algorithm algorithm, bool enabled);
+
+  /// The default compression level to use for all channel calls in the
+  /// absence of a call-specific level.
+  ServerBuilder& SetDefaultCompressionLevel(grpc_compression_level level);
+
+  /// The default compression algorithm to use for all channel calls in the
+  /// absence of a call-specific level. Note that it overrides any compression
+  /// level set by \a SetDefaultCompressionLevel.
+  ServerBuilder& SetDefaultCompressionAlgorithm(
+      grpc_compression_algorithm algorithm);
+
+  /// Set the attached buffer pool for this server
+  ServerBuilder& SetResourceQuota(const ResourceQuota& resource_quota);
+
+  ServerBuilder& SetOption(std::unique_ptr<ServerBuilderOption> option);
+
+  /// Options for synchronous servers.
+  enum SyncServerOption {
+    NUM_CQS,         ///< Number of completion queues.
+    MIN_POLLERS,     ///< Minimum number of polling threads.
+    MAX_POLLERS,     ///< Maximum number of polling threads.
+    CQ_TIMEOUT_MSEC  ///< Completion queue timeout in milliseconds.
+  };
+
+  /// Only useful if this is a Synchronous server.
+  ServerBuilder& SetSyncServerOption(SyncServerOption option, int value);
+
+  /// Add a channel argument (an escape hatch to tuning core library parameters
+  /// directly)
+  template <class T>
+  ServerBuilder& AddChannelArgument(const grpc::string& arg, const T& value) {
+    return SetOption(MakeChannelArgumentOption(arg, value));
+  }
+
+  /// For internal use only: Register a ServerBuilderPlugin factory function.
+  static void InternalAddPluginFactory(
+      std::unique_ptr<ServerBuilderPlugin> (*CreatePlugin)());
+
+  /// Enable a server workaround. Do not use unless you know what the workaround
+  /// does. For explanation and detailed descriptions of workarounds, see
+  /// doc/workarounds.md.
+  ServerBuilder& EnableWorkaround(grpc_workaround_list id);
+
+ protected:
+  /// Experimental, to be deprecated
+  struct Port {
+    grpc::string addr;
+    std::shared_ptr<ServerCredentials> creds;
+    int* selected_port;
+  };
+
+  /// Experimental, to be deprecated
+  typedef std::unique_ptr<grpc::string> HostString;
+  struct NamedService {
+    explicit NamedService(Service* s) : service(s) {}
+    NamedService(const grpc::string& h, Service* s)
+        : host(new grpc::string(h)), service(s) {}
+    HostString host;
+    Service* service;
+  };
+
+  /// Experimental, to be deprecated
+  std::vector<Port> ports() { return ports_; }
+
+  /// Experimental, to be deprecated
+  std::vector<NamedService*> services() {
+    std::vector<NamedService*> service_refs;
+    for (auto& ptr : services_) {
+      service_refs.push_back(ptr.get());
+    }
+    return service_refs;
+  }
+
+  /// Experimental, to be deprecated
+  std::vector<ServerBuilderOption*> options() {
+    std::vector<ServerBuilderOption*> option_refs;
+    for (auto& ptr : options_) {
+      option_refs.push_back(ptr.get());
+    }
+    return option_refs;
+  }
+
+ private:
+  friend class ::grpc::testing::ServerBuilderPluginTest;
+
+  struct SyncServerSettings {
+    SyncServerSettings()
+        : num_cqs(1), min_pollers(1), max_pollers(2), cq_timeout_msec(10000) {}
+
+    /// Number of server completion queues to create to listen to incoming RPCs.
+    int num_cqs;
+
+    /// Minimum number of threads per completion queue that should be listening
+    /// to incoming RPCs.
+    int min_pollers;
+
+    /// Maximum number of threads per completion queue that can be listening to
+    /// incoming RPCs.
+    int max_pollers;
+
+    /// The timeout for server completion queue's AsyncNext call.
+    int cq_timeout_msec;
+  };
+
+  int max_receive_message_size_;
+  int max_send_message_size_;
+  std::vector<std::unique_ptr<ServerBuilderOption>> options_;
+  std::vector<std::unique_ptr<NamedService>> services_;
+  std::vector<Port> ports_;
+
+  SyncServerSettings sync_server_settings_;
+
+  /// List of completion queues added via \a AddCompletionQueue method.
+  std::vector<ServerCompletionQueue*> cqs_;
+
+  std::shared_ptr<ServerCredentials> creds_;
+  std::vector<std::unique_ptr<ServerBuilderPlugin>> plugins_;
+  grpc_resource_quota* resource_quota_;
+  AsyncGenericService* generic_service_;
+  struct {
+    bool is_set;
+    grpc_compression_level level;
+  } maybe_default_compression_level_;
+  struct {
+    bool is_set;
+    grpc_compression_algorithm algorithm;
+  } maybe_default_compression_algorithm_;
+  uint32_t enabled_compression_algorithms_bitset_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_SERVER_BUILDER_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/server_context.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/server_context.h
index 692c00c..45f2614 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/server_context.h
@@ -16,15 +16,9 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_SERVER_CONTEXT_H
+#define GRPCPP_SERVER_CONTEXT_H
 
-#include <grpc/support/time.h>
+#include <grpcpp/impl/codegen/server_context.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_SERVER_CONTEXT_H
diff --git a/include/grpcpp/server_posix.h b/include/grpcpp/server_posix.h
new file mode 100644
index 0000000..ef3ee01
--- /dev/null
+++ b/include/grpcpp/server_posix.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_SERVER_POSIX_H
+#define GRPCPP_SERVER_POSIX_H
+
+#include <memory>
+
+#include <grpc/support/port_platform.h>
+#include <grpcpp/server.h>
+
+namespace grpc {
+
+#ifdef GPR_SUPPORT_CHANNELS_FROM_FD
+
+/// Add a new client to a \a Server communicating over the given
+/// file descriptor.
+///
+/// \param server The server to add the client to.
+/// \param fd The file descriptor representing a socket.
+void AddInsecureChannelFromFd(Server* server, int fd);
+
+#endif  // GPR_SUPPORT_CHANNELS_FROM_FD
+
+}  // namespace grpc
+
+#endif  // GRPCPP_SERVER_POSIX_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/support/async_stream.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/support/async_stream.h
index 692c00c..ff9e455 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/support/async_stream.h
@@ -16,15 +16,9 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_SUPPORT_ASYNC_STREAM_H
+#define GRPCPP_SUPPORT_ASYNC_STREAM_H
 
-#include <grpc/support/time.h>
+#include <grpcpp/impl/codegen/async_stream.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_SUPPORT_ASYNC_STREAM_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/support/async_unary_call.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/support/async_unary_call.h
index 692c00c..2e5181c 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/support/async_unary_call.h
@@ -16,15 +16,9 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_SUPPORT_ASYNC_UNARY_CALL_H
+#define GRPCPP_SUPPORT_ASYNC_UNARY_CALL_H
 
-#include <grpc/support/time.h>
+#include <grpcpp/impl/codegen/async_unary_call.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_SUPPORT_ASYNC_UNARY_CALL_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/support/byte_buffer.h
similarity index 60%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/support/byte_buffer.h
index 692c00c..53aeff1 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/support/byte_buffer.h
@@ -16,15 +16,16 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_SUPPORT_BYTE_BUFFER_H
+#define GRPCPP_SUPPORT_BYTE_BUFFER_H
 
-#include <grpc/support/time.h>
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include <grpcpp/impl/codegen/byte_buffer.h>
+#include <grpcpp/impl/serialization_traits.h>
+#include <grpcpp/support/config.h>
+#include <grpcpp/support/slice.h>
+#include <grpcpp/support/status.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_SUPPORT_BYTE_BUFFER_H
diff --git a/include/grpcpp/support/channel_arguments.h b/include/grpcpp/support/channel_arguments.h
new file mode 100644
index 0000000..1eead4e
--- /dev/null
+++ b/include/grpcpp/support/channel_arguments.h
@@ -0,0 +1,142 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_SUPPORT_CHANNEL_ARGUMENTS_H
+#define GRPCPP_SUPPORT_CHANNEL_ARGUMENTS_H
+
+#include <list>
+#include <vector>
+
+#include <grpc/compression.h>
+#include <grpc/grpc.h>
+#include <grpcpp/support/config.h>
+
+namespace grpc {
+namespace testing {
+class ChannelArgumentsTest;
+}  // namespace testing
+
+class ResourceQuota;
+
+/// Options for channel creation. The user can use generic setters to pass
+/// key value pairs down to C channel creation code. For gRPC related options,
+/// concrete setters are provided.
+class ChannelArguments {
+ public:
+  ChannelArguments();
+  ~ChannelArguments();
+
+  ChannelArguments(const ChannelArguments& other);
+  ChannelArguments& operator=(ChannelArguments other) {
+    Swap(other);
+    return *this;
+  }
+
+  void Swap(ChannelArguments& other);
+
+  /// Dump arguments in this instance to \a channel_args. Does not take
+  /// ownership of \a channel_args.
+  ///
+  /// Note that the underlying arguments are shared. Changes made to either \a
+  /// channel_args or this instance would be reflected on both.
+  void SetChannelArgs(grpc_channel_args* channel_args) const;
+
+  // gRPC specific channel argument setters
+  /// Set target name override for SSL host name checking. This option is for
+  /// testing only and should never be used in production.
+  void SetSslTargetNameOverride(const grpc::string& name);
+  // TODO(yangg) add flow control options
+  /// Set the compression algorithm for the channel.
+  void SetCompressionAlgorithm(grpc_compression_algorithm algorithm);
+
+  /// Set the grpclb fallback timeout (in ms) for the channel. If this amount
+  /// of time has passed but we have not gotten any non-empty \a serverlist from
+  /// the balancer, we will fall back to use the backend address(es) returned by
+  /// the resolver.
+  void SetGrpclbFallbackTimeout(int fallback_timeout);
+
+  /// Set the socket mutator for the channel.
+  void SetSocketMutator(grpc_socket_mutator* mutator);
+
+  /// Set the string to prepend to the user agent.
+  void SetUserAgentPrefix(const grpc::string& user_agent_prefix);
+
+  /// Set the buffer pool to be attached to the constructed channel.
+  void SetResourceQuota(const ResourceQuota& resource_quota);
+
+  /// Set the max receive and send message sizes.
+  void SetMaxReceiveMessageSize(int size);
+  void SetMaxSendMessageSize(int size);
+
+  /// Set LB policy name.
+  /// Note that if the name resolver returns only balancer addresses, the
+  /// grpclb LB policy will be used, regardless of what is specified here.
+  void SetLoadBalancingPolicyName(const grpc::string& lb_policy_name);
+
+  /// Set service config in JSON form.
+  /// Primarily meant for use in unit tests.
+  void SetServiceConfigJSON(const grpc::string& service_config_json);
+
+  // Generic channel argument setters. Only for advanced use cases.
+  /// Set an integer argument \a value under \a key.
+  void SetInt(const grpc::string& key, int value);
+
+  // Generic channel argument setter. Only for advanced use cases.
+  /// Set a pointer argument \a value under \a key. Owership is not transferred.
+  void SetPointer(const grpc::string& key, void* value);
+
+  void SetPointerWithVtable(const grpc::string& key, void* value,
+                            const grpc_arg_pointer_vtable* vtable);
+
+  /// Set a textual argument \a value under \a key.
+  void SetString(const grpc::string& key, const grpc::string& value);
+
+  /// Return (by value) a C \a grpc_channel_args structure which points to
+  /// arguments owned by this \a ChannelArguments instance
+  grpc_channel_args c_channel_args() const {
+    grpc_channel_args out;
+    out.num_args = args_.size();
+    out.args = args_.empty() ? NULL : const_cast<grpc_arg*>(&args_[0]);
+    return out;
+  }
+
+ private:
+  friend class SecureChannelCredentials;
+  friend class testing::ChannelArgumentsTest;
+
+  /// Default pointer argument operations.
+  struct PointerVtableMembers {
+    static void* Copy(void* in) { return in; }
+    static void Destroy(void* in) {}
+    static int Compare(void* a, void* b) {
+      if (a < b) return -1;
+      if (a > b) return 1;
+      return 0;
+    }
+  };
+
+  // Returns empty string when it is not set.
+  grpc::string GetSslTargetNameOverride() const;
+
+  std::vector<grpc_arg> args_;
+  std::list<grpc::string> strings_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCPP_SUPPORT_CHANNEL_ARGUMENTS_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/support/config.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/support/config.h
index 692c00c..16bdab6 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/support/config.h
@@ -16,15 +16,9 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_SUPPORT_CONFIG_H
+#define GRPCPP_SUPPORT_CONFIG_H
 
-#include <grpc/support/time.h>
+#include <grpcpp/impl/codegen/config.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_SUPPORT_CONFIG_H
diff --git a/include/grpcpp/support/error_details.h b/include/grpcpp/support/error_details.h
new file mode 100644
index 0000000..84931d9
--- /dev/null
+++ b/include/grpcpp/support/error_details.h
@@ -0,0 +1,46 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_SUPPORT_ERROR_DETAILS_H
+#define GRPCPP_SUPPORT_ERROR_DETAILS_H
+
+#include <grpcpp/support/status.h>
+
+namespace google {
+namespace rpc {
+class Status;
+}  // namespace rpc
+}  // namespace google
+
+namespace grpc {
+
+/// Map a \a grpc::Status to a \a google::rpc::Status.
+/// The given \a to object will be cleared.
+/// On success, returns status with OK.
+/// Returns status with \a INVALID_ARGUMENT, if failed to deserialize.
+/// Returns status with \a FAILED_PRECONDITION, if \a to is nullptr.
+Status ExtractErrorDetails(const Status& from, ::google::rpc::Status* to);
+
+/// Map \a google::rpc::Status to a \a grpc::Status.
+/// Returns OK on success.
+/// Returns status with \a FAILED_PRECONDITION if \a to is nullptr.
+Status SetErrorDetails(const ::google::rpc::Status& from, Status* to);
+
+}  // namespace grpc
+
+#endif  // GRPCPP_SUPPORT_ERROR_DETAILS_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/support/slice.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/support/slice.h
index 692c00c..eaeb29a 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/support/slice.h
@@ -16,15 +16,11 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_SUPPORT_SLICE_H
+#define GRPCPP_SUPPORT_SLICE_H
 
-#include <grpc/support/time.h>
+#include <grpc/slice.h>
+#include <grpcpp/impl/codegen/slice.h>
+#include <grpcpp/support/config.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_SUPPORT_SLICE_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/support/status.h
similarity index 61%
rename from src/core/lib/gpr/thd_internal.h
rename to include/grpcpp/support/status.h
index 692c00c..91b629f 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/support/status.h
@@ -16,15 +16,9 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_SUPPORT_STATUS_H
+#define GRPCPP_SUPPORT_STATUS_H
 
-#include <grpc/support/time.h>
+#include <grpcpp/impl/codegen/status.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_SUPPORT_STATUS_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/support/status_code_enum.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/support/status_code_enum.h
index 692c00c..bfb47f3 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/support/status_code_enum.h
@@ -16,15 +16,9 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_SUPPORT_STATUS_CODE_ENUM_H
+#define GRPCPP_SUPPORT_STATUS_CODE_ENUM_H
 
-#include <grpc/support/time.h>
+#include <grpcpp/impl/codegen/status_code_enum.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_SUPPORT_STATUS_CODE_ENUM_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/support/string_ref.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/support/string_ref.h
index 692c00c..0e0d3d4 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/support/string_ref.h
@@ -16,15 +16,9 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_SUPPORT_STRING_REF_H
+#define GRPCPP_SUPPORT_STRING_REF_H
 
-#include <grpc/support/time.h>
+#include <grpcpp/impl/codegen/string_ref.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_SUPPORT_STRING_REF_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/support/stub_options.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/support/stub_options.h
index 692c00c..e9700ea 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/support/stub_options.h
@@ -16,15 +16,9 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_SUPPORT_STUB_OPTIONS_H
+#define GRPCPP_SUPPORT_STUB_OPTIONS_H
 
-#include <grpc/support/time.h>
+#include <grpcpp/impl/codegen/stub_options.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_SUPPORT_STUB_OPTIONS_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/support/sync_stream.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/support/sync_stream.h
index 692c00c..ea60b6d 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/support/sync_stream.h
@@ -16,15 +16,9 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_SUPPORT_SYNC_STREAM_H
+#define GRPCPP_SUPPORT_SYNC_STREAM_H
 
-#include <grpc/support/time.h>
+#include <grpcpp/impl/codegen/sync_stream.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_SUPPORT_SYNC_STREAM_H
diff --git a/src/core/lib/gpr/thd_internal.h b/include/grpcpp/support/time.h
similarity index 61%
copy from src/core/lib/gpr/thd_internal.h
copy to include/grpcpp/support/time.h
index 692c00c..c7408ff 100644
--- a/src/core/lib/gpr/thd_internal.h
+++ b/include/grpcpp/support/time.h
@@ -16,15 +16,9 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_GPR_THD_INTERNAL_H
-#define GRPC_CORE_LIB_GPR_THD_INTERNAL_H
+#ifndef GRPCPP_SUPPORT_TIME_H
+#define GRPCPP_SUPPORT_TIME_H
 
-#include <grpc/support/time.h>
+#include <grpcpp/impl/codegen/time.h>
 
-/* Internal interfaces between modules within the gpr support library.  */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_INTERNAL_H */
+#endif  // GRPCPP_SUPPORT_TIME_H
diff --git a/include/grpcpp/test/mock_stream.h b/include/grpcpp/test/mock_stream.h
new file mode 100644
index 0000000..93963f7
--- /dev/null
+++ b/include/grpcpp/test/mock_stream.h
@@ -0,0 +1,148 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_TEST_MOCK_STREAM_H
+#define GRPCPP_TEST_MOCK_STREAM_H
+
+#include <stdint.h>
+
+#include <gmock/gmock.h>
+#include <grpcpp/impl/codegen/call.h>
+#include <grpcpp/support/async_stream.h>
+#include <grpcpp/support/async_unary_call.h>
+#include <grpcpp/support/sync_stream.h>
+
+namespace grpc {
+namespace testing {
+
+template <class R>
+class MockClientReader : public ClientReaderInterface<R> {
+ public:
+  MockClientReader() = default;
+
+  /// ClientStreamingInterface
+  MOCK_METHOD0_T(Finish, Status());
+
+  /// ReaderInterface
+  MOCK_METHOD1_T(NextMessageSize, bool(uint32_t*));
+  MOCK_METHOD1_T(Read, bool(R*));
+
+  /// ClientReaderInterface
+  MOCK_METHOD0_T(WaitForInitialMetadata, void());
+};
+
+template <class W>
+class MockClientWriter : public ClientWriterInterface<W> {
+ public:
+  MockClientWriter() = default;
+
+  /// ClientStreamingInterface
+  MOCK_METHOD0_T(Finish, Status());
+
+  /// WriterInterface
+  MOCK_METHOD2_T(Write, bool(const W&, const WriteOptions));
+
+  /// ClientWriterInterface
+  MOCK_METHOD0_T(WritesDone, bool());
+};
+
+template <class W, class R>
+class MockClientReaderWriter : public ClientReaderWriterInterface<W, R> {
+ public:
+  MockClientReaderWriter() = default;
+
+  /// ClientStreamingInterface
+  MOCK_METHOD0_T(Finish, Status());
+
+  /// ReaderInterface
+  MOCK_METHOD1_T(NextMessageSize, bool(uint32_t*));
+  MOCK_METHOD1_T(Read, bool(R*));
+
+  /// WriterInterface
+  MOCK_METHOD2_T(Write, bool(const W&, const WriteOptions));
+
+  /// ClientReaderWriterInterface
+  MOCK_METHOD0_T(WaitForInitialMetadata, void());
+  MOCK_METHOD0_T(WritesDone, bool());
+};
+
+/// TODO: We do not support mocking an async RPC for now.
+
+template <class R>
+class MockClientAsyncResponseReader
+    : public ClientAsyncResponseReaderInterface<R> {
+ public:
+  MockClientAsyncResponseReader() = default;
+
+  MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
+  MOCK_METHOD3_T(Finish, void(R*, Status*, void*));
+};
+
+template <class R>
+class MockClientAsyncReader : public ClientAsyncReaderInterface<R> {
+ public:
+  MockClientAsyncReader() = default;
+
+  /// ClientAsyncStreamingInterface
+  MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
+  MOCK_METHOD2_T(Finish, void(Status*, void*));
+
+  /// AsyncReaderInterface
+  MOCK_METHOD2_T(Read, void(R*, void*));
+};
+
+template <class W>
+class MockClientAsyncWriter : public ClientAsyncWriterInterface<W> {
+ public:
+  MockClientAsyncWriter() = default;
+
+  /// ClientAsyncStreamingInterface
+  MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
+  MOCK_METHOD2_T(Finish, void(Status*, void*));
+
+  /// AsyncWriterInterface
+  MOCK_METHOD2_T(Write, void(const W&, void*));
+
+  /// ClientAsyncWriterInterface
+  MOCK_METHOD1_T(WritesDone, void(void*));
+};
+
+template <class W, class R>
+class MockClientAsyncReaderWriter
+    : public ClientAsyncReaderWriterInterface<W, R> {
+ public:
+  MockClientAsyncReaderWriter() = default;
+
+  /// ClientAsyncStreamingInterface
+  MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
+  MOCK_METHOD2_T(Finish, void(Status*, void*));
+
+  /// AsyncWriterInterface
+  MOCK_METHOD2_T(Write, void(const W&, void*));
+
+  /// AsyncReaderInterface
+  MOCK_METHOD2_T(Read, void(R*, void*));
+
+  /// ClientAsyncReaderWriterInterface
+  MOCK_METHOD1_T(WritesDone, void(void*));
+};
+
+}  // namespace testing
+}  // namespace grpc
+
+#endif  // GRPCPP_TEST_MOCK_STREAM_H
diff --git a/include/grpcpp/test/server_context_test_spouse.h b/include/grpcpp/test/server_context_test_spouse.h
new file mode 100644
index 0000000..f5ca552
--- /dev/null
+++ b/include/grpcpp/test/server_context_test_spouse.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPCPP_TEST_SERVER_CONTEXT_TEST_SPOUSE_H
+#define GRPCPP_TEST_SERVER_CONTEXT_TEST_SPOUSE_H
+
+#include <map>
+
+#include <grpcpp/server_context.h>
+
+namespace grpc {
+namespace testing {
+
+/// A test-only class to access private members and methods of ServerContext.
+class ServerContextTestSpouse {
+ public:
+  explicit ServerContextTestSpouse(ServerContext* ctx) : ctx_(ctx) {}
+
+  /// Inject client metadata to the ServerContext for the test. The test spouse
+  /// must be alive when \a ServerContext::client_metadata is called.
+  void AddClientMetadata(const grpc::string& key, const grpc::string& value) {
+    client_metadata_storage_.insert(
+        std::pair<grpc::string, grpc::string>(key, value));
+    ctx_->client_metadata_.map()->clear();
+    for (auto iter = client_metadata_storage_.begin();
+         iter != client_metadata_storage_.end(); ++iter) {
+      ctx_->client_metadata_.map()->insert(
+          std::pair<grpc::string_ref, grpc::string_ref>(
+              iter->first.c_str(),
+              grpc::string_ref(iter->second.data(), iter->second.size())));
+    }
+  }
+
+  std::multimap<grpc::string, grpc::string> GetInitialMetadata() const {
+    return ctx_->initial_metadata_;
+  }
+
+  std::multimap<grpc::string, grpc::string> GetTrailingMetadata() const {
+    return ctx_->trailing_metadata_;
+  }
+
+ private:
+  ServerContext* ctx_;  // not owned
+  std::multimap<grpc::string, grpc::string> client_metadata_storage_;
+};
+
+}  // namespace testing
+}  // namespace grpc
+
+#endif  // GRPCPP_TEST_SERVER_CONTEXT_TEST_SPOUSE_H
diff --git a/package.xml b/package.xml
index 7c32a73..52d5cc9 100644
--- a/package.xml
+++ b/package.xml
@@ -13,8 +13,8 @@
  <date>2018-01-19</date>
  <time>16:06:07</time>
  <version>
-  <release>1.10.0dev</release>
-  <api>1.10.0dev</api>
+  <release>1.11.0dev</release>
+  <api>1.11.0dev</api>
  </version>
  <stability>
   <release>beta</release>
@@ -51,32 +51,28 @@
     <file baseinstalldir="/" name="src/php/ext/grpc/server_credentials.h" role="src" />
     <file baseinstalldir="/" name="src/php/ext/grpc/timeval.h" role="src" />
     <file baseinstalldir="/" name="src/php/ext/grpc/version.h" role="src" />
+    <file baseinstalldir="/" name="third_party/address_sorting/address_sorting_internal.h" role="src" />
+    <file baseinstalldir="/" name="third_party/address_sorting/include/address_sorting/address_sorting.h" role="src" />
+    <file baseinstalldir="/" name="third_party/address_sorting/address_sorting.c" role="src" />
+    <file baseinstalldir="/" name="third_party/address_sorting/address_sorting_posix.c" role="src" />
+    <file baseinstalldir="/" name="third_party/address_sorting/address_sorting_windows.c" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/alloc.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/atm.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/atm_gcc_atomic.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/atm_gcc_sync.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/atm_windows.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/support/avl.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/support/cmdline.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/cpu.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/support/host_port.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/log.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/log_windows.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/port_platform.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/string_util.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/support/subprocess.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/sync.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/sync_custom.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/sync_generic.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/sync_posix.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/sync_windows.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/support/thd.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/support/thd_id.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/time.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/support/tls.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/support/tls_gcc.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/support/tls_msvc.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/support/tls_pthread.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/support/useful.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/atm.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/atm_gcc_atomic.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/atm_gcc_sync.h" role="src" />
@@ -93,26 +89,30 @@
     <file baseinstalldir="/" name="src/core/lib/gpr/arena.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/env.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/fork.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/gpr/host_port.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/mpscq.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/murmur_hash.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/spinlock.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/string.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/string_windows.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/gpr/thd_internal.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/time_precise.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/gpr/tls.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/gpr/tls_gcc.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/gpr/tls_msvc.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/gpr/tls_pthread.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/tmpfile.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/gpr/useful.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gprpp/abstract.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gprpp/atomic.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gprpp/atomic_with_atm.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gprpp/atomic_with_std.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gprpp/manual_constructor.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gprpp/memory.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/gprpp/thd.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/profiling/timers.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/alloc.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/arena.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/atm.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/gpr/avl.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/gpr/cmdline.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/cpu_iphone.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/cpu_linux.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/cpu_posix.cc" role="src" />
@@ -133,14 +133,9 @@
     <file baseinstalldir="/" name="src/core/lib/gpr/string_posix.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/string_util_windows.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/string_windows.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/gpr/subprocess_posix.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/gpr/subprocess_windows.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/sync.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/sync_posix.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/sync_windows.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/gpr/thd.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/gpr/thd_posix.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/gpr/thd_windows.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/time.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/time_posix.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/time_precise.cc" role="src" />
@@ -150,6 +145,8 @@
     <file baseinstalldir="/" name="src/core/lib/gpr/tmpfile_posix.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/tmpfile_windows.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/wrap_memcpy.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/gprpp/thd_posix.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/gprpp/thd_windows.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/profiling/basic_timers.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/profiling/stap_timers.cc" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/byte_buffer.h" role="src" />
@@ -177,7 +174,6 @@
     <file baseinstalldir="/" name="include/grpc/byte_buffer.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/byte_buffer_reader.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/compression.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/compression_ruby.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/fork.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/grpc.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/grpc_posix.h" role="src" />
@@ -213,6 +209,7 @@
     <file baseinstalldir="/" name="src/core/ext/filters/http/message_compress/message_compress_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/http/server/http_server_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/context/security_context.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/credentials/alts/alts_credentials.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/credentials/composite/composite_credentials.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/credentials/credentials.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/credentials/fake/fake_credentials.h" role="src" />
@@ -224,22 +221,47 @@
     <file baseinstalldir="/" name="src/core/lib/security/credentials/oauth2/oauth2_credentials.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/credentials/plugin/plugin_credentials.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/credentials/ssl/ssl_credentials.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/security_connector/alts_security_connector.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/security_connector/security_connector.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/transport/auth_filters.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/security/transport/lb_targets_info.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/transport/secure_endpoint.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/security/transport/security_connector.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/transport/security_handshaker.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/transport/target_authority_table.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/transport/tsi_error.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/util/json_util.h" role="src" />
-    <file baseinstalldir="/" name="src/core/tsi/alts_transport_security.h" role="src" />
-    <file baseinstalldir="/" name="src/core/tsi/fake_transport_security.h" role="src" />
-    <file baseinstalldir="/" name="src/core/tsi/ssl_transport_security.h" role="src" />
-    <file baseinstalldir="/" name="src/core/tsi/ssl_types.h" role="src" />
-    <file baseinstalldir="/" name="src/core/tsi/transport_security_grpc.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/crypt/gsec.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/frame_protector/alts_counter.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/frame_protector/alts_crypter.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/frame_protector/alts_frame_protector.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/frame_protector/frame_handler.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_handshaker_client.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_tsi_event.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_tsi_handshaker.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/credentials/alts/check_gcp_environment.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_handshaker_service_api.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_tsi_utils.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/transport_security_common_api.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/altscontext.pb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/handshaker.pb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/transport_security_common.pb.h" role="src" />
+    <file baseinstalldir="/" name="third_party/nanopb/pb.h" role="src" />
+    <file baseinstalldir="/" name="third_party/nanopb/pb_common.h" role="src" />
+    <file baseinstalldir="/" name="third_party/nanopb/pb_decode.h" role="src" />
+    <file baseinstalldir="/" name="third_party/nanopb/pb_encode.h" role="src" />
     <file baseinstalldir="/" name="src/core/tsi/transport_security.h" role="src" />
     <file baseinstalldir="/" name="src/core/tsi/transport_security_adapter.h" role="src" />
     <file baseinstalldir="/" name="src/core/tsi/transport_security_interface.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/chttp2_server.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/chttp2_connector.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/backup_poller.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel_factory.h" role="src" />
@@ -249,6 +271,7 @@
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy_factory.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy_registry.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/method_params.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/parse_address.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper_registry.h" role="src" />
@@ -260,17 +283,28 @@
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_index.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/uri_parser.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/deadline/deadline_filter.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/chttp2_connector.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts_transport_security.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/fake_transport_security.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/ssl/session_cache/ssl_session.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/ssl/session_cache/ssl_session_cache.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/ssl_transport_security.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/ssl_types.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/transport_security_grpc.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/chttp2_server.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/inproc/inproc_transport.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/avl/avl.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/backoff/backoff.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_args.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack_builder.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/channel_trace.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/channel_trace_registry.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/connected_channel.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/context.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/handshaker.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/handshaker_factory.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/handshaker_registry.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/status_util.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/compression/algorithm_metadata.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/compression/compression_internal.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/compression/message_compress.h" role="src" />
@@ -305,9 +339,9 @@
     <file baseinstalldir="/" name="src/core/lib/iomgr/gethostname.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/iocp_windows.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_custom.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_internal.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_posix.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_uv.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/is_epollexclusive_available.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/load_file.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/lockfree_event.h" role="src" />
@@ -315,14 +349,17 @@
     <file baseinstalldir="/" name="src/core/lib/iomgr/network_status_tracker.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/polling_entity.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/pollset.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_custom.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_set.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_set_custom.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_set_windows.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_uv.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_windows.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/port.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/resolve_address.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/resolve_address_custom.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/resource_quota.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_custom.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_posix.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_utils.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_windows.h" role="src" />
@@ -334,17 +371,16 @@
     <file baseinstalldir="/" name="src/core/lib/iomgr/sys_epoll_wrapper.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_client.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_client_posix.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_custom.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_posix.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server_utils_posix.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_uv.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_windows.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/time_averaged_stats.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/timer.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/timer_generic.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/timer_custom.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/timer_heap.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/timer_manager.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/timer_uv.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/udp_server.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/unix_sockets_posix.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/wakeup_fd_cv.h" role="src" />
@@ -359,6 +395,7 @@
     <file baseinstalldir="/" name="src/core/lib/slice/slice_hash_table.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/slice/slice_internal.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/slice/slice_string_helpers.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/slice/slice_weak_hash_table.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/surface/api_trace.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/surface/call.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/surface/call_test_only.h" role="src" />
@@ -383,20 +420,16 @@
     <file baseinstalldir="/" name="src/core/lib/transport/service_config.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/static_metadata.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/status_conversion.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/status_metadata.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/timeout_encoding.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/transport.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/transport_impl.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/debug/trace.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h" role="src" />
-    <file baseinstalldir="/" name="third_party/nanopb/pb.h" role="src" />
-    <file baseinstalldir="/" name="third_party/nanopb/pb_common.h" role="src" />
-    <file baseinstalldir="/" name="third_party/nanopb/pb_decode.h" role="src" />
-    <file baseinstalldir="/" name="third_party/nanopb/pb_encode.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/subchannel_list.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h" role="src" />
@@ -408,17 +441,20 @@
     <file baseinstalldir="/" name="src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/workarounds/workaround_utils.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/surface/init.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/avl/avl.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/backoff/backoff.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_args.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack_builder.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/channel_trace.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/channel_trace_registry.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/connected_channel.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/handshaker.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/handshaker_factory.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/handshaker_registry.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/status_util.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/compression/compression.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/compression/compression_internal.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/compression/compression_ruby.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/compression/message_compress.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/compression/stream_compression.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/compression/stream_compression_gzip.cc" role="src" />
@@ -450,6 +486,8 @@
     <file baseinstalldir="/" name="src/core/lib/iomgr/gethostname_sysconf.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/iocp_windows.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_custom.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_internal.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_posix.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_uv.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_windows.cc" role="src" />
@@ -458,12 +496,16 @@
     <file baseinstalldir="/" name="src/core/lib/iomgr/lockfree_event.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/network_status_tracker.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/polling_entity.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_set_uv.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/pollset.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_custom.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_set.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_set_custom.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_set_windows.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_uv.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_windows.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/resolve_address.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/resolve_address_custom.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/resolve_address_posix.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/resolve_address_uv.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/resolve_address_windows.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/resource_quota.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_utils.cc" role="src" />
@@ -475,19 +517,24 @@
     <file baseinstalldir="/" name="src/core/lib/iomgr/socket_utils_uv.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/socket_utils_windows.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/socket_windows.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_client.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_client_custom.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_client_posix.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_client_uv.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_client_windows.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_custom.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_posix.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server_custom.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server_posix.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server_utils_posix_common.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server_uv.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server_windows.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_uv.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_windows.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/time_averaged_stats.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/timer.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/timer_custom.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/timer_generic.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/timer_heap.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/timer_manager.cc" role="src" />
@@ -508,7 +555,6 @@
     <file baseinstalldir="/" name="src/core/lib/slice/percent_encoding.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/slice/slice.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/slice/slice_buffer.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/slice/slice_hash_table.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/slice/slice_intern.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/slice/slice_string_helpers.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/surface/api_trace.cc" role="src" />
@@ -539,6 +585,7 @@
     <file baseinstalldir="/" name="src/core/lib/transport/service_config.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/static_metadata.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/status_conversion.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/status_metadata.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/timeout_encoding.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/transport.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/transport_op_string.cc" role="src" />
@@ -573,6 +620,7 @@
     <file baseinstalldir="/" name="src/core/ext/filters/http/server/http_server_filter.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/http/httpcli_security_connector.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/context/security_context.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/credentials/alts/alts_credentials.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/credentials/composite/composite_credentials.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/credentials/credentials.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/credentials/credentials_metadata.cc" role="src" />
@@ -586,23 +634,55 @@
     <file baseinstalldir="/" name="src/core/lib/security/credentials/oauth2/oauth2_credentials.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/credentials/plugin/plugin_credentials.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/credentials/ssl/ssl_credentials.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/security_connector/alts_security_connector.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/security_connector/security_connector.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/transport/client_auth_filter.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/security/transport/lb_targets_info.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/transport/secure_endpoint.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/security/transport/security_connector.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/transport/security_handshaker.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/transport/server_auth_filter.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/transport/target_authority_table.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/transport/tsi_error.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/util/json_util.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/surface/init_secure.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/tsi/alts_transport_security.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/tsi/fake_transport_security.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/tsi/ssl_transport_security.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/tsi/transport_security_grpc.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/crypt/aes_gcm.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/crypt/gsec.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/frame_protector/alts_counter.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/frame_protector/alts_crypter.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/frame_protector/alts_frame_protector.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/frame_protector/frame_handler.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_handshaker_client.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_tsi_event.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/credentials/alts/check_gcp_environment.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/alts_tsi_utils.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/transport_security_common_api.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/altscontext.pb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/handshaker.pb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts/handshaker/transport_security_common.pb.c" role="src" />
+    <file baseinstalldir="/" name="third_party/nanopb/pb_common.c" role="src" />
+    <file baseinstalldir="/" name="third_party/nanopb/pb_decode.c" role="src" />
+    <file baseinstalldir="/" name="third_party/nanopb/pb_encode.c" role="src" />
     <file baseinstalldir="/" name="src/core/tsi/transport_security.cc" role="src" />
     <file baseinstalldir="/" name="src/core/tsi/transport_security_adapter.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/chttp2_server.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/insecure/channel_create.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/chttp2_connector.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/backup_poller.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/channel_connectivity.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel.cc" role="src" />
@@ -614,22 +694,28 @@
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy_factory.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy_registry.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/method_params.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/parse_address.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper_registry.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_factory.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_registry.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_throttle.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_index.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/uri_parser.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/deadline/deadline_filter.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/chttp2_connector.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/alts_transport_security.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/fake_transport_security.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/ssl/session_cache/ssl_session_cache.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/ssl/session_cache/ssl_session_openssl.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/ssl_transport_security.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/transport_security_grpc.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/chttp2_server.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/insecure/channel_create.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/inproc/inproc_plugin.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/inproc/inproc_transport.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc" role="src" />
@@ -638,9 +724,6 @@
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c" role="src" />
-    <file baseinstalldir="/" name="third_party/nanopb/pb_common.c" role="src" />
-    <file baseinstalldir="/" name="third_party/nanopb/pb_decode.c" role="src" />
-    <file baseinstalldir="/" name="third_party/nanopb/pb_encode.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc" role="src" />
@@ -665,23 +748,82 @@
     <file baseinstalldir="/" name="third_party/boringssl/crypto/cipher_extra/internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/conf/conf_def.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/conf/internal.h" role="src" />
-    <file baseinstalldir="/" name="third_party/boringssl/crypto/curve25519/internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/err/internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/evp/internal.h" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/aes/aes.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/aes/internal.h" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/aes/key_wrap.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/aes/mode_wrappers.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/bn/add.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/bn/asm/x86_64-gcc.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/bn/bn.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/bn/bytes.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/bn/cmp.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/bn/ctx.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/bn/div.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/bn/exponentiation.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/bn/gcd.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/bn/generic.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/bn/internal.h" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/bn/jacobi.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/bn/montgomery.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/bn/montgomery_inv.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/bn/mul.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/bn/prime.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/bn/random.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/bn/rsaz_exp.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/bn/rsaz_exp.h" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/bn/shift.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/bn/sqrt.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/cipher/aead.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/cipher/cipher.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/cipher/e_aes.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/cipher/e_des.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/cipher/internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/delocate.h" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/des/des.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/des/internal.h" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/digest/digest.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/digest/digests.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/digest/internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/digest/md32_common.h" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/ec/ec.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/ec/ec_key.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/ec/ec_montgomery.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/ec/internal.h" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/ec/oct.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/ec/p224-64.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/ec/p256-64.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/ec/p256-x86_64-table.h" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/ec/p256-x86_64.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/ec/p256-x86_64.h" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/ec/simple.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/ec/util-64.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/ec/wnaf.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/ecdsa/ecdsa.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/hmac/hmac.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/md4/md4.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/md5/md5.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/modes/cbc.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/modes/cfb.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/modes/ctr.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/modes/gcm.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/modes/internal.h" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/modes/ofb.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/modes/polyval.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/rand/ctrdrbg.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/rand/internal.h" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/rand/rand.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/rand/urandom.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/rsa/blinding.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/rsa/internal.h" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/rsa/padding.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/rsa/rsa.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/rsa/rsa_impl.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/sha/sha1-altivec.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/sha/sha1.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/sha/sha256.c" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/crypto/fipsmodule/sha/sha512.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/obj/obj_dat.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/pkcs7/internal.h" role="src" />
@@ -767,6 +909,7 @@
     <file baseinstalldir="/" name="third_party/boringssl/include/openssl/x509_vfy.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/include/openssl/x509v3.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/ssl/internal.h" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/third_party/fiat/internal.h" role="src" />
     <file baseinstalldir="/" name="src/boringssl/err_data.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/a_bitstr.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/a_bool.c" role="src" />
@@ -836,7 +979,6 @@
     <file baseinstalldir="/" name="third_party/boringssl/crypto/cpu-intel.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/cpu-ppc64le.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/crypto.c" role="src" />
-    <file baseinstalldir="/" name="third_party/boringssl/crypto/curve25519/curve25519.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/curve25519/spake25519.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/curve25519/x25519-x86_64.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/dh/check.c" role="src" />
@@ -1022,6 +1164,7 @@
     <file baseinstalldir="/" name="third_party/boringssl/ssl/tls13_server.cc" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/ssl/tls_method.cc" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/ssl/tls_record.cc" role="src" />
+    <file baseinstalldir="/" name="third_party/boringssl/third_party/fiat/curve25519.c" role="src" />
     <file baseinstalldir="/" name="third_party/zlib/crc32.h" role="src" />
     <file baseinstalldir="/" name="third_party/zlib/deflate.h" role="src" />
     <file baseinstalldir="/" name="third_party/zlib/gzguts.h" role="src" />
diff --git a/requirements.txt b/requirements.txt
index c976cef..53768c6 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,6 +1,6 @@
 # GRPC Python setup requirements
 coverage>=4.0
-cython>=0.23
+cython>=0.27
 enum34>=1.0.4
 futures>=2.2.0
 protobuf>=3.5.0.post1
diff --git a/setup.py b/setup.py
index 4f67f82..97a3107 100644
--- a/setup.py
+++ b/setup.py
@@ -48,6 +48,7 @@
   CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_linux'),)
 if 'openbsd' in sys.platform:
   CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_openbsd'),)
+ADDRESS_SORTING_INCLUDE = (os.path.join('third_party', 'address_sorting', 'include'),)
 README = os.path.join(PYTHON_STEM, 'README.rst')
 
 # Ensure we're in the proper directory whether or not we're being used by pip.
@@ -118,6 +119,7 @@
     EXTRA_ENV_COMPILE_ARGS += ' -std=c++11 -std=gnu99 -fvisibility=hidden -fno-wrapv -fno-exceptions'
   elif "darwin" in sys.platform:
     EXTRA_ENV_COMPILE_ARGS += ' -fvisibility=hidden -fno-wrapv -fno-exceptions'
+EXTRA_ENV_COMPILE_ARGS += ' -DPB_FIELD_16BIT'	
 
 if EXTRA_ENV_LINK_ARGS is None:
   EXTRA_ENV_LINK_ARGS = ''
@@ -148,7 +150,7 @@
 
 EXTENSION_INCLUDE_DIRECTORIES = (
     (PYTHON_STEM,) + CORE_INCLUDE + BORINGSSL_INCLUDE + ZLIB_INCLUDE +
-    CARES_INCLUDE)
+    CARES_INCLUDE + ADDRESS_SORTING_INCLUDE)
 
 EXTENSION_LIBRARIES = ()
 if "linux" in sys.platform:
@@ -160,7 +162,7 @@
 
 DEFINE_MACROS = (
     ('OPENSSL_NO_ASM', 1), ('_WIN32_WINNT', 0x600),
-    ('GPR_BACKWARDS_COMPATIBILITY_MODE', 1),)
+    ('GPR_BACKWARDS_COMPATIBILITY_MODE', 1))
 if "win32" in sys.platform:
   # TODO(zyc): Re-enble c-ares on x64 and x86 windows after fixing the
   # ares_library_init compilation issue
diff --git a/src/boringssl/crypto_test_data.cc b/src/boringssl/crypto_test_data.cc
index 8a25dd9..75c355c 100644
--- a/src/boringssl/crypto_test_data.cc
+++ b/src/boringssl/crypto_test_data.cc
@@ -2490,78 +2490,79 @@
     "b8a29a9a10c0d6a41cf32b5bc40edd7a1d97b295c63aa62c30498f15d70e427d5612ec3f6a2c1f2997fa9283f48018435fa6092269dc2e4ad524cc6da9689302f5c398d79e2b2d19470ea8240db9df0bc0bdc911c4d53f4f24a7ce44ec76378794d16d367434b4f8b6184c7651db77fcbebb8fcc5d3a51ee9739922cf20d4a8888139fe4669a164400\nA = -e3c4a10a64b7e67d786aeb81bb7ea14655637ce963f46cce59bc0cb6b5a9cb9c92afec3d527119db97bd2605d315cf28198992b4b2206e5616d3c560bc8163f56cb1f5626a7ac6d8427520\n\nSquare = 429e4283af7f895fe732ee88e4904348ed01bf579a93cffb7aa8e135d41cb9be218f8b9a9cb4f556124105cf042de51f34c8162fdc7a981de88e005a014149c955068e87214c174daa40fbc618c536a6e507ebd313763fba197059d68c69bd39933d614b2c32f235cc955e335c4a37b9e98cd7f98c7f26ea2da932c7f82ffd95be22a7741da423123f8908cb188abc26afaf4ba6d47b56e11\nA = 20a5e2a911627544219a1639c3321bbcd6192a32129b248cf62351f85b7a719cb275a4e44368a74f4d1a307ffd27ea2cae4d8584a57070609a30fb4e365564908f3d501b53c1a54f0e37745e9\n\nSquare = 9bcc8d423c3fdfaaaabe24a910e6ac3619eaa15e23b9f317c844d39d164c952fdf5c4bd270a83f3902e54d3817fd78c96018a706c1f652025dde0b98afe35597e0d8782deaeed23337ef6b3edc9317d54e3c8a57e4e7e2695f9d2681bf82927bab193ca1f135bd0e542696772f08520faab61fb4ea6ff0d15bb91f21e68bd7f084a6b8f24a47ecc30a779ee86610387b29a1de94de517f81318001\nA = -c7b60f4c355f2ca3937ba3c124eea2cd8d3536226a44afcaa3d17abe931c09ccaabf25a1986b172fcf46fb02a0fc36f2c163b6e42cee047c54ab05e9d30f03f6943b9fbab83aa6da12d7898c001\n\nSquare = 45df25540de94883dbc182009c29fec43627d3e5758e6a07cf40064e0befa0df184528a84757b445dd079c2b0feded48b651ab18b4bede2a81796be45caad0125c3692560d19cd9a6c8c0de8383fea0bc1ab46f6aca4e9c36b26575cff88fdf1eb1e13182308295457374968fe3a9ca34c6acd24c753fb84d41246614789dfe154faf34fc684cd15035dc9c1c6b0ea171e089e0f3236840e355bd123ac4\nA = -216f8a9a3e54d4afadf368c2693743efd3eaa4cbda7a87cd07f5b1a713eefd2548343e7f091ee4d9d6ed1d4343c06a0597db0eb5194b91bf2c858210557a8288c1aa7b0e0607a24dcff9de04146d8e\n\nSquare = 5cc707d97eb107c5c40c0f19fd432cbac9855f280082802dbe4deb45bfd193ac7a9149fd12c4ae6e9282411e2f1f2ca92135424f215b800634092ed4ff2859d16ab9fb8619ece41b50f8888d3e13773d38789e19158e18396096dd57fa5470f50b391c22378d980e59b4585f013e6db52c1e24c14ad83262fd37d42f52323896f7d4cb3e38868abea8a07e7ad3f90512eea001c5147645bf00396cb0e7a553f1\nA = 9a1d1b0beea76e7f32bde9f4f2c8bcff9094db2d32c04fb7ff43624b61033646e482aa0fadb9f8b4225b47121070b4ee5d6818d3606ed775aa631e0ed42da68c2a09dab26b6a4d09ac226cc09321fed9\n\nSquare = a32fd053eb90c365e77ff47573a24add3b25b4c301f4c662dfc1fa635af8e18e7947381989b37a9c9de2713ca438b9f85890b7b160fe251933aa7dad1c3839d502debb42ddc927fa0e9b40c80dc3d408889be567699a856b1c9cf3a393b3b818432e95feea825c17d0981b942236b3779f2acaaccaf9a5817ca47bd03045fc4de454d8f1d4377e218c5f7ece369aacc35369ab57a71652dd42621491834119afbe729\nA = 33190b787a2c3327b122d1f5823bdee5c93b19b586ce1bf79d801a19b2558aafc8f6274d0908bb7a8362f7f71d3fb52b8ffc87d458249caba7af3a516ce868e8a620e3126ad43d6aeffee11866fe77677b3\n\nSquare = 74215d33fa398e21c34034af6f9c7af6a3e01982320ec8cf23074a938f1a31543f80e6aece01de247668fe67f276cb4411db27666e1dc8fb2bfa4eb68cfd3563167d1ac4efa3361f920d8dd0fbb7f06362167f5ab5ecfb72956c20db934f67ff1c75aabb594c853fa61f43d219a3f5d0d45274005e3b167cfff5493b0f26d15f85d8e906a0a6e7645eac1f40c6dc637e6d1e061e5b9071a1227469cfb2c0f17ff983684100\nA = ac6c0b9c69785f35dbe244dc85a54313ef836ac67c853531ef5db45b28835ffe61dd258c5528b0acea50f5aa5c0f5d08dcb8d82ee19bc432fa8a45badadb50693fedc1cc79a17d63aa73fe9597f1d4ce8ddf0\n\nSquare = dce5cac967c47b8a58ed6f1bb1d1e6185e849400228afa2bfa05b9c2dd327b04a86f2a4da2d02ea102868ea0c4da0f3e5a40bd02c87a08aaa5cd8d9358b3a5ebd8c9fc2dbb1268c261f46d6717b0307b993deff0adc8190d32b4f2bf695eb2cc74a6a9a712c5a621c673219ff8a24ded0997508f8f9eb1ea872008c46e71fa97f55b839950e63130c38b49c0ce3ce724a0e8faa9738d2e28ce6e7fc7eab62b3561d2981f314f751\nA = -3b735400064b15fad81b08362b8557f8318c20656839ffb4d2513512015036ab0039442032f1cf515f8c10c9933afe4206a2f309e933d1561b06bc665af2f04f4d064e073eed2280053f56cbeb137a9482c0a077\n\nSquare = 6b619bcaf632f0d8b1d715e8850c0cbbd29ac6373a9a5e93dd1bbd2b82744a8a50a7446b48c6e215911ffafcda9ed7becaf5d26b7d6df7dc8798d53239f62a482f974bdb654750def1c941c49a24fcdfcfe73881b556a7b528d88daeeaea8d62b357211a1946c81cbf0819ad8d0188f60aaaab4ea2dfef7e9012ade7abeaaa4a23d7403c1248c36aa26b43b8e7de8a5aea639a0449f50359e9b4c1b125a548383af33703f8dfbc2528e4\nA = -a5ccc69663a8712c15f96e6fc746252af89a8c2a6317caef905dd2d8a6d4fe878ac7aa66cdb3c3721ba7dd36da310753dde9801b31d759339ac919a464ab52541bb2e0dc938752bf0f1ff7a9524eb98340d62576aa\n\nSquare = 77ea5b715823045afe13d10416dfd46a511141a7d1279ebd624f1de428cc04a4f246246e65c3f84344cebfa32864de9264b2e54d4b3010c4de9d3e6a27aae8f5f9e9d8e49fe26b73ac7e65bb216aa6a42db36ac03d749b5dc04192df819631593202a58264714628686507fc5655f169483b0ffecf45995cbc12faa105895564d287a9f4b220947d6c93786c85b2ee84a0a29183483f7c241d6a67fd0b1c38c7f74421355a14c6d9ed5720e24\nA = 2bcd67e6bde3f54c4ce0ea428418fc5c97272217c6c7de90549238ee322810dcc1bb9385967673aa3f9f5a5c05d987c6445135cf1efc26b3c17e55b93cc052761a77c9dcb5c22927b09e90a92e053ec1bc799bbe7597a\n\nSquare = 40d113460ca3e70545bf3613c2ba5de5d8485641ebf531a43b6b8bb76884ff4f348727ac6606e026981d2116ef1e60d4b37b44ed7e2003410d7d636b58aed2f92e962003f28342aa5f059d23b3d58a1ddfb47833ffe1d1deee0a7e78b8f7d9d6487f22376664f1ed9ddb5ee3d17f43afda296bead11680fd17576a122c2599fa9802ddd84a2115f9fda03aba898f66e303895f452077c920a322b6aaa0965f51fbb36f01b1d412c6ccf390da050d24\nA = -80d0699a46619db033461aa6060983def7deeb976d1a71f5c6ddb85e8b46dc70b7ddb1d254971d38ca87c7ee3905e63506c6db105dd683375f4239523cbf1874069266c2c0f4b37edcdd261c51088081d25813758bdbfc6\n\nSquare = ace99f98cba0d1dc1c758dc7211aa4078a2aeb6d3fff19bdfa6981ded0982b15bac792e6b542ae48a86f9b40c6de937e402e230fcfc390b10c3e60202dee1337ab39da7a342999487b8d8b0e494f2809cd1bfdb39209da5daa590f78ded211b6bbd3fca9013300b951d8906c9ce8d1c0dd9554d5d1d352f9784f822c928dd9700ef8a5fecf3771966abb1dc6a70b301461eb6b6087d6ab80a4b624205489584224cf6578f75acd8091fd621d02306504389\nA = -349936d60c9d77a0974dc8985930d8674976db6b3cbaa067554ca6b30b1de33f2d4e1c9564ce102ac6387755aabf42916f63632a375d995913f9d45ebda54bee3fdb7cedee46ebb5c8ae7764e4de323c17c797d3b529230cbd\n\nSquare = db6c73be2a59bdd35dd312240aef18dde4231c72aa28551bb370a87dded587accec2279bea24c930236f06f24d537fcf242497aafcbf72f085fd3ecf030cd750fb382efea0f82ad9d3195680324d73fa99d48802d085c150164aec0d29fdcc3262264bbe72311f89989cc71a4afdac6ab103ab4fbb6e973a42a1f8711bee463d198f727dc7bad848ff8fa77cd3b2f612d142ba46e95bd79a86a1fe4c2b8f9181be84825d05989695842113828a83b826e7d2c8c1\nA = ed01dd49d2e5d51fd30e9c578259cf107771b4ded6bf21f8b9b632fd360e34da740e0b1af6b5a67789fda5a44025af0f1547271ca8accc7a975d98ea7ec3d41c9697018d84ffb5d49b88d884ccdb011f715a199ddc44a4109261\n\nSquare = d6e38250ab89ffe11abaf8c5d07ba11e9053f1924ee1228f834111af16ed282389d04330cb0f47dbb186dee577aed82878ecb065b759312eaf167c4698eab5ed03a8657341bf5fb14a8e28e3b443a6b657c1f4379ff2549498a33922ea84f1fb19d10866fb0ad07ce1cc44c93cd4d9ec6bbb0e61c797750c6b5d7e8d55499655dde112f4747798f0e985fc2b937a44da9b04c2dc4b0816cfc57da1f80179db653c1ce287e786ed7eff7ad6d1383fc6de8c941d4af7bd1\nA = 3aa2e696ee570160b2a869c3f21c3f223959a185cda2274feea1c829af2234c70a504c959bcc49fe0313f4f5ffd27448e28aa0fc6ce24f36943d334c626459d7e6017339e787ab074879ebf697a93ad93835d69ab09294d007a0837\n\nSquare = fc39360cc0fe040b6f8340e0728c650e5e74cf1664f7b301e79986fe066f36e8df34d38d1a06b74a1bdc76867baeb3f39a9161acd200bc7532fa4aa0ea829377659646f073db82ee044279ae5fd797edd37d3261970819589853cb320887a085c4011c23d0da9b6d6f1b5911bb3399146c2912a967ab3b3f611f0bd52e00f418e6a6f0297fcf5c4a1f71c6bb8cc8e1c76694bb7301502d1d00c8b6c05bfabbf5d350590561abf3e2b1a82e98b56583e2e4e25cf707320a0e40\nA = fe1acf3d7b54e718c901c53f365894c22c8bb4182fee8a4c2558731e01e1519bfd1bf6e353483b8c4219453fa66f06063c6c99050068c15cd13cd1648ffc42b5badfc70f6fd4a0a5552fe637e54c4f92ca45c60cf9a0163978ac08d58\n\nSquare = 9abf1324ef65c726330f64643a024c466fad37604f4dd3dfc404d31c2a430fcfaa0c78283666c15a094d494b96d3c12de6e29a34d2c99f4f8cae8217bcd2a989d59807ac68c46d60600238a86155de499eeb35642d0f581045481b40e4f0a76905f9b6bc5b9585f77f8410b99333f7ea983c3f29f3fe66ca7b793b784a5a6a4f74512aa4385dd1e996832b1f41bb3af965be58c4ac5e867cdf8dc6a4f9d20a6f1e16e153fcbb45ae5fe8a798cb06a4ffe467d6b6aca2b31f335a344\nA = -31c243593ea611dffecc65d1439db345b2e89941113f9792c",
     "91a76b4890db6e4dbaf1482ee812e295d27956e48d07a14de38357f15b5931c5cc08d1d248df7bfee1cae5b5ce98984c5043a3e1a2b449ba1671bf1cfef91011e12bab94b6e\n\nSquare = 66aee3e4f43c672e0478c76e2092bef33e7c60afee5d4c7defbcc5c0c86d8fe956c90a740cebe604224cc3f518463b1208699b8ea2316315474991d0f120ae905a67028492cf46fff2ae244869db2a02d06aac6ac6eb054fb3c14c756d8a3e7ca64f06586e3e86e4477f185ed527a8aea6a3c741f3fd4b64a2ee77ff140190260c431cc53f411fb227377c02f85d0258a75bf6d44dccbb8bd04ebdafa115dd55b176b6eff5567e5b1bedcae15110826574053681fe25a695ac4540186e90\nA = -a221dfee30286adc076673cbcebd24a41a438a0a7a6a547c75d33149cb1a094a8425feaa5a23cc234a722db4cca8d5912fe1dfb6db4e92bd87c12f0d06b6d954fdb9b172955412b2eb5c9fa3b4df2933390384fd1f929a2b1a8dac479ec94c\n\nSquare = e880f8655b51739e34393c3e6d69d63e0256b1a887f7e69f40c78d21133b17e92277a136f5e37da2533ed599efad189975d22ad0340005ef58db0b471651d749dfbd48b3f7b3b8a42d4677048a855e99dae6c729d8bd7eef86911feca9f5490dd216b06d9e8d1ab695c1081e72449baad28dfe113744853382901e6bdab5413c67c52d6cbbb2e0bea711edbb3a219a4046e8739c04729cf8c8210028dbc4087737bc6c1d7e0c15ecf16774690168342b1372d3646d4d8696384bc932144c98529\nA = 3cfe075d4525a3c780d6d05f7bb708b2fdf7277a0f9967e0a209fee9d42136a0bbf98660d8ee8cb4720a8042da09f6271c45ad13db24eaac465f8207f78629e9085c1c890675f441c78efa38e5022b1b80afde5e3fd08e55648f2817631eb6cb3\n\nSquare = 8d6cf4eaf58099b1323fc598b7554b371f4afef5ab501dd162ab8429333d46916fe15dfc4ed6a99ca7fa7fc1aaa0cec3533b41e291fb7f69b560259507226eca87aabd07b1ae2eb93bb53f98fec508f051cc04db4a172901e06b74229c4fa3f550a81626c7a63fa99d41e46c2cf792287a5cf7bb68946971bd43c7c0356312cdc25e524665dd39a24b6464bbbe64fe8e87ee313b860639728a9143c3a6118bc8b150dde6c10a13bea637fa8873c393e6338319c506aec6ee973b4b52a272a74bb62084\nA = -be46a8072aa44b3bff0f90c81474dd576756fca624c15f55a17e1d0bd2842467ae000b04f79f561690c93ca7118ce17ecf830a8da3678c15436876d2a74324d9714dc8ad8181904be657d7f1da3313b78448cc06e32299a09ed59bfc1961e8bd722\n\nSquare = fbaa4fcf9800673fbd3a132305ed3e14f4889518fb56ab82aa5e9b3529b74d7f9a467626d68f4709a2030264aaebcf05c0a0edb511e81f357d85b79d925a24605f1bcd4645915bb75d363654b676266329df532cdb39152fb360df1b9500e0c296014289650ff77faa78a604397a82b34d16484e94a8de123fe720e514c88f11ec276725111563db91477480c3245542ec6bd0bb2f4aaec02c6c4eb1769030a31b05da3798c224c9117f7c38d3e98a343fca03ab584ec2d7e6db60fdc4273c3d8e23cc1ce09\nA = -3f74b25f2a9c4d8d977e69a4e067f9fcec281136a508e365b282e5fc3b1d097bc6a0f59f7827fb90d4890b08840a0a1919032c67448f8f1a771f785a0f125a4aa4137c154fdb489dc1099d57bfcfc75f4ca5e69f93f2bb87ed09cc0dc620d3e76ecd03\n\nSquare = 5135becca97d93dd4b16a5a1105ba3a3e3fe02bd6a7c3cd182186fc63ed4351641182a2727ab6715e9672458dfbc31aded4781fa345054eb4c317872e2af6d4ed64b2ca7e8c25e1e664b5349df937118632a64e4ce439ffc625a5ad3358270dc83fdfa73c7afba03406094fa36d87517e5e2e1fee5526fd2dc00d9210a0f6c3745b3d4bceee5f8b03d976d696c57a09d1e08e4ce780972eca4f2ed6500c23bf5782c31f13059e48246180fd09db693d2fb5d48d51846ece8beee45cef7efc87c003b44d7b137a900\nA = 902fbe2127354a7df5cb7fd057f3d080a7bebbdb83c86a50560b8c287a37a841bb9c8421c63d359078d2948b6b57559f98fad8f8014f93c912cb70a6701c4dc4fc5e88aa413fcfb685c32975a8b72424742eeff8262d28cebad00c5fcf88baeafe8f6730\n\nSquare = b5976cf6a6560412aefa6704b126e0d987dfcedbb4da436c08ce17b1bf1b6e0bab9f934abb5c4186a5415fa38724fb8fa341d381319e7d768209ab108c8debd99075d31deb3e03ff7d23957d4f3204d543b7d9079cf337be3037b1cb4908fd8c104d92e52f041b4cb27c045a741f4d64009980e8d27af75d9493920ed98c7234777592d6577f2d1b3a0eec645ab4cee2f28d9e4efd3e4514db6796487ba68a462fa0e316e1420d6604db2b901de46553546cab42976fd0d459afd81196275cd88ec4dd448ff331bb35499\nA = 35e700e034950bdd7318d5b3c17e90a4772ecdacdb055b9391b31538eb823fc8a4599f029e78e4fe5299ba1a423a449dc257a431d189dd5dca275c02cc1f12417e111c73b731631d8a1741b907dd8f24de226ddf9e3044cf4064e8e51ebd55be774be7ad2bb\n\nSquare = b7de0f73397893a97928e266bc56299cc8d43b16a251992662646072b58fa578ca80f7be1e12619012b130e9514be803dc166b12ddfd26f558d36c2053ee6209b01458379e49469753300ef20f6b3dcd5383b121861c76ab25debb28c448ec33a81250d05f7eff80a5a4133d522d270fab29f739b607395a77278609aa5e1a55ef58d1d48492b71ee30a24a6505aab1a3ac22b9d143c9d6781fae14bbb980fe3a99dfa9a1a406611d7d0304493342f53faf5fd79f9c96b9583a219a1b22aad02dd58f32ee98146b3a8cf054bf9\nA = d8f4d3bcfc7eebd7068b851858c3668ce062a834927e165679b49132d4f780ca682876c65c7cf2e7ce34ed10e43696477da6301d13f92abb8c76e2424c4bc28a6565f15e59563d607b852dc946652b68fbfda1c3200ecc2976400ce7296b96e75fb059a4c8eb5\n\nSquare = 5ec02661f49fb9807bb73debc3c6eccdac1df1735e0d61fa7e0eee07471068a5809796a2af490c46a77d61f618b44a3168dde67aae1cf9e530382411056958d55bd18f0e76fe2c31c98b00f87fcb7f5691ed5b65424f82204156dc361ef6dec5d44cf690582599b3994ee47ef42850d5d2370a4169c5f73942657f85422ca24f66943877f73af493c865fbeb29574cc1cc730e9bbb097b598574f6b90257748e950bff867bcc01bf62f8df67d7aee1b6dc1d5db88826e86a3f9fcd8663e09cf8393ee71a09c43d0d38ba6ef643f4ab1\nA = -26ef9b6708a80d00f4d01e0f0a5546ed217085ff23519819ee89af430580ea1f086beb0eb51982682c6d3b922a2c92752dce63657836223a9d94964bd584bc8e37c6e30fdcaffbdb128344d51a92705e1c9f94205ca36452c15a08f7e62e0e02479ecd48085de8c7\n\nSquare = f6364409467a829abc2b13c93979dec84984caa12154b7cda2f4c8d91bf24ad7c45a968ffaac8d6722cc26e6aaf52dd29ea2f09370ba46d79684b7a06faedcd17136f35a58e5b550f3a2caef7b195d8409914fedd3c3154101bd735155098e8b10fbbb1b2e13555d2ab5d5b52b203d4efb27e498b240f37178f2e89b413f94859b0e8b2ec10b926c8c0b6f2937ee2d0355445364841c7e0539f7073b88c7d568edf1b253f3c10627e22c2ed731b7d4d199449cb0b5e7a66109932fe2c9cd741d75170deb9f98469049549c10a7a622bf6e91\nA = -fb0eec3246e99212879e51b17ea6615275818ecc5ea3058b13dbaba2576ef90e1519e3629b09fdaeb02661091c395c862b848f6326b9f536f7af45718c4412f09f19261b537bca36742d3ec66f964343516aae2ac27e249a15beb545b447e37b4062180f6c82809429\n\nSquare = bc4193ecb5dac900191e02be06297106155c6840c4908fbf6e41e9aae137d53c3d4ffb87f334f49837dc4ab7a66299994e4f5c9bf6ea03e7db663bdef066e94c610580a8896a9ae9c8f6587eb83d789683f5d6391bbac3a1dc1de60b4108428e6f5fdeaed6cd3e74fa01f85c6368023b61a413b69b14276b66f22653491e4f25790985053d075387cb13c79dcf963b6d880d01174314921afe1cc700c02efd2979dcbc59c417a6316db9ac45a2d60d2a036571bfbd75f9f5e42048ca086cfb4b818a9beca4a6e0ed51afa320ef3549151fb39e100\nA = 36e1f16043b4c9b4a304496c39dd63459d6521d2ac92916d348daca3f972835973fc8d21b07b09d8f5e3197b39a8f3fd0011168b815d67c48143c413e169ffe0f56ff2cf8b6596bd0a3b5b7a6b9a14ffb797f350b7e6aa7020d84d1d1b8006850139795abe2c74f03b8f0\n\nSquare = 4cbb5bc1dd7112326e2c94581f19efc8fb25339a299fa9c007114c3a22b395e9d39a8ffe21134e97ad1b87b97e667ba48b2a40af61afc81fb1e20e8e38c7ba666b146016af4dff3faf5de306591e5ce6eddc1173fdda6fe241a9f2fc6e054c41e56d296f8954377df0d140096b9e9d6a5a23a231db4dfab0cabfb11190c7a0d1c55ae35203836d433da96ca7339682bac0a7edb8b5b4dc267c6e83ac9b67a0d0d564717ee3c20aaf52c0a750f3aad94a12537c6971ee009d0f82ff576e984b06c7f7b357f5c049454e31326b952af17aa62104780e9ca1\nA = -8c279ebe466de3115b8740f3ff9c1f605b4eaa75512d82fdc8ca5ce84e11a68688154fd603ae1d607807dbfcbb822a8dc259098842c6a7b7ec350be29a3daa20fd5b093a56692e9d42e7a389c4ad2122a74205f835e268c9742d09ad36238c34e143f6e2ec69c0f490d29d1\n\nSquare = 4f771ade09cbd1a033d2bfc6036fe46ae6c12acc6f2b9bd52e7781693fa6358cf93089f23d1f0ee6fca476a43093b9b52446f3a7abd72ed0ce9b562dc438822ffd84bcd898ef9d092f1b0b7ff89c4fdb33d8715dd4a0d68ec49ad41338fbb62ca87867d847a4d99310641a37ea78b04c85606069d0c0950484ddbeedac8ec6f95124e7fd83da4e942d40103bc14474f5cb125fa0b06cf167f076979948003dd8dc3711923f5af5beb5f56c0a48ac0c5240b62738c1cdb06b87ac3dfa17befbe938ddc7281f6c248c41a1c7b99b93f69fac83a46eb298a9fd8b9\nA = -23a845bf2007ba8480e3ece0a1bbaf8bfccba6bf061e3fe1d8bcbcd6c761e650891c0958bac68618a1f55b27d2bc6e1e1b50afc29f58e2e034bdda8405e5378cb5bff0d84efcb458c5428fc607597d89d589d85d90f3da4b89a64c9d1623b98b10518a6f2e7d2295c37527026b\n\nSquare = ab45d12a4e15a294830741f4b9d4a14cc7dbed1c3454612047f890211c749d92ae0418f11cd44acbf1585b1f7323b33ac9a4b13c44e1a7e31b0dcc1c6dd4eaa12a655b5de08f3b948270a152db7d9e04dc54677075797bfad6a9a0e3958458d40e3df5e15028954bae99518de4dd3adfb2ec4b38897a8a4e4807849e1416aa4040c95a0e49a8d2889f6fb0537875f87516c3723e8d3b46da8da855929c67c0eb83daad62ceced52b4f52d2bf1c4e34f26bf16aa7da3afe0f5df76c0858ed98f21e1fc3d01e1572715b774bd5c2faabec5fa3fa59a7a1f32565a4f1f9\nA = d164d875e1f766b4567e9228241213e69d6b6c58620600166fac56938c5d",
     "9643932d01f1f4a2263dca4b9ad26dca1548e4b5b7e27581a63375d0e624f4e4c99b7fb9aeb25307c61142760bc4771e48c7ce38f5eb2408def632096fe40b80d488fe17a455d80edfc1c23c429775b5\n\nSquare = 5ae4e7dc5727543af39ed3d5e9ac086d1a2220421231b82f6f41caee7b9815b4049aea0d43ff499c6c9e1f226f8641351d03f37731c64686d9a9ce68e9234d6a762efcffdecd42f81044111599963d9b6873cc20bf4c8284fae03d2e4f238a14a74df4388fdc80fad0375a5d0d974da7854ede5896ed2ab25d2b49a3c39093600f73120e4fd2faf75381854f6ae80f81b977f62fc72f1fd01c278d183544052b77bd753dd88ffdf5c01745521fb8474b5c23b0b7dc709bafeb91cee0863a0c23ad7192c43cf15fc181d629853cb9b8334082c915dd3d04e3a0a81511d2e84\nA = 2622a7bf45ccd3cd567c757f4c5796b5a0fbca555bd0ac2759c24083172d82d6a887dcf93d9788fde052cb20a8963cb6db22bf5eee6151600f9d1896a7606b11a1b100cbc0925bce037bcea57e361efcc560a9abc495d7f7f45831c6429ac8f979dedc08c304f4da9c0d4d687376d5e\n\nSquare = 473cc933f5a650a4ae358c7f486d325c0e20c83b54838fc08b6ac3ff010f7c4b6a609bdf472974dfc5abda0c6b33c5ec7dc4628d85cb4276108e2b0bc4e19cba135533b3d7bb6a94332aea3165dccb230860d2353166b9905635e606185b014730e9dcf2c433e18cba83859fb2eac4aabef68c8314ef86dec2d534a184ebc4cb193643add0897341690cbe18bc2e775327fd7d71ffc7ebc49bad83cd68394eb276b2e615ec430180303010a454ef73b6a8f02bc48a1fc8a32f8150ef1b733f07da752b8e808000329f4924976bc8b8573927f18ca7c88c210845de6dcd0dee2904\nA = 870b2c4b054076d0d02877b19fe1210a8fad3422b00905a6db748239b8e807716ed9fee0d8c25496593717917edceb5db57f9960bddc1956b6652868d6ace82827bbbada5ae8c15efa26fda22657126c6300906f90e8fabfd58ddf312ce0eee760e0090fac44f00378c676115cd0639be\n\nSquare = b151124402d2f04b0e6599222d380dcf67b9716ef50d2d9ded0b21521b34a7294171f71b41762511b7cca93d9f50e9e30083ef19144882928011dbb143807d1b88c55eea6b19f0c4180023be6da63a59b6bc027aff3f5abe2f65c73b2de1e71c5f4b248bc4547040764e83a860cb3f882bb8b5f7821f92802808fa37c50f2f94d8f56daca841f42d3362762ba843aedbd03d3cdda887f75ba92423965ab4256eb842ad755aa7a2af331b488186f891065b07f5a299c807dc24fc176e085a8024bbbf12f386ef49ccc91bd4ada0936b6de78088cf5952ae6c04f6916799378bc0ede0da4\nA = -35439da9e361700152a35ebdea253378a1febec5f288e5b2bb0bdf25b84751b47e4da5aad7453b70cfd6640d5832237d2115575c738482ac6036c5fc21a981c0a7f979c8d621a92c02166b777475618aa6362a0e225dd6138ead3b2766ed9785ee01e4950a863d2fa0b7f5cb4c9a108bb626\n\nSquare = 4ed7263ae5beb0069f24318b38afe951a5a058a2e960e67f086c9680d0cc6d713f943812070bf94152f7926bdab9e5908941261244542b832f458f05ed5dc048c8b9eb84c2a85efe717e257796b4ca816948a6c8ea209c0675efb2fb5af4622b44e36066593db01b17f4dee21d7c1337ff41436cd0e5a8d01e4030dcd3d49839e59996fbbf1d39bd205343a424f2395b4d3eacdeb9ed3235d8df0dd00a2573260af63db3116a7c65d1dc69684a05caebff34e3d2cba9d4869a953a7b1fce10ebd008cba021008ac3187bba846abd7b39a1b97c9c07d8080549e313dd58b716022de3c1920329\nA = -8e1141dcebae61d5c4d81697f001d792ee2e847c589816f923f0ed42bb4de0d8f911b8ca47ffe77f80b9da6896a9b42f0030a3276218868bbe1a3fa64fb0a577704339af5dd82e66780da6f58900da3f1d75ebfcc302f78ed66ea3c7a737898a29b1f2500686b43bae1e6571addd2842cdce4d\n\nSquare = b09f5e9472cbb75070a67d025957fd5ac3be89c41e4acbcd5f75780ca459562461082c3f19c5a4a416a668b0a55f31f74cf2ec44555ddc43fde64da0ba781adfac4520dd0f78d04d9d2fd33d8b49c72663a6bc845015523e2e4e7ccc69e5b748b8b891e4089420bf0a3f6032602824c7230b5ff95f85a688dcdcfc890af3384710a9fe32ecf9ad7c6cc5761f13079b19d7b2906c7e63c14b64fc88c6f4bd7c41c0356c777d35c3626d49db8cb2d1e89ce682c7fccc3a459b08c20c4e5fc3a8eced9b37d01bed5af6ce9baff0d2b435e6e62871fcb20cf9ec10d1897a5c76e73a441e07fbcc2d9f4e4\nA = 3528e6581de547de385c93ccf1086a17614f23356a918b25bc6d73656a2302b318963bb679c9a93357f4a4f614e74f2e5e88e9c8aed8a6fdd8434630f664ed15ebb6095cbff1593f188a12f4dd6087a85b202f6c24df68ac3b137406c88c5098faf47d1eeec0743b35baaec7dae29b5a44eb09daa\n\nSquare = 5d5dc40783411475a4aac7c1a1eb760f76fcc6ec68dfebb754251cf499870654cd309422935ec841e6be4f5a15078356235c2b8cbe1ae755cd6d814e811072bdb76156b83c7d2064a202ff90af1e0f88f5889e5729a3cffa9faf33c463b74d0ad21fbb4473d4d3ebfa8a52e9c209ded5ce5131b12b69747c365146fa17ee5810e0dbab992f9da28b6c323062484d62472232721d608cdb9b5a341a677e2d7a6e5a983247d9a4001e16687b489b10b18bbf205f982b7ceee27cc3e9c6641827ab7952373f15d36e5f177b82d7eebb3f5054e12cec82c5f520a2675afdec6cbf6235d358c2fe73344002e400\nA = -9a9a19fcdf11bba84b0395088c5d187d84d69b68b77bc6418f63c88bbd8dbbccfe02917d814f9e2241fa0709817a0c85bd554fe887babae7439d96248514c12d71587c906247b3e965e954cdd57f1e51f1979f73c3237509863169efdf281c1359488daad3d9eb990a50ecf4d3fd25d4820077832a0\n\nSquare = a4d69ed4c4c9c08116ec5cc49ad458f0fb2ca00f356aeb148f18037bc49621e14820f325af39f3954bddc9cf01de7ba1e443088545883a94c04ff41a7ed5f65676109c5b711b4115775489667e00aa1b77f6dee5ac5c1789bc71c9fc797abf41c7c5ae3e2c1cf82d5b49b6c0da25190dfa9360b99b2f63444d21ec6114038b8284bf598eed24a2ab2b9802d6edd5b0fdb52f60621a87a14612844ffc71ca98180ff0915cf75f47432f73d28dfd7a932a125095655f07f50722b1673df2cc4f7566a1c6035792ff3f02356b9b9d25e905121df768dc6a1884cf5483eeb813c1c009fe4ed043febd61800ba978a40\nA = -335b12e40bfe0b847ed6ec143490df33d2e64ef4363869cb78dec008cb5cd66ea671dba964a53e48267da288ef4040e06371e1209691b81df02f2c86a79cac85fdcbb6732a1e5309fbbdbcd899fdfed18518d47258c9e63ff7f116ef4a8f5c4867aedd907ccc7d222cf8087afebc108f2a0f197c717198\n\nSquare = 74dcdacc1a4f02a99e3642f54f9d917b117d2ae8d9c392f8b6dee53fac66ebe1680c8e8cc29f5330e0eed3f63d10980060799bc37b34c93dd7b384d4ba30a5b5d42a145acc412ae838d7b9b7137637546d1118f7cf3eadf88b785f0aa01da8638f027c56faa16aba8591b64b45dae6138c9a40309b2ad29c5029a867465f9c6de8fbc5fc4b0442c8a8946272667c7622454ed6f2a236103bed7697dba20db84b5154ff3fbc6b4b9eb67ee43bcaae741d87ee2093ee67defb8eebc4a4a22d97a4e2aa7d4c31a1c88abf4a440ba4e2a5e40c4d903ba5ee4d80b4e8dffb8864bcb9806e015c1ce16490068df87282393111\nA = acf70350e554732c1972903cce269b215e985ecb8d6eeaa67fd5398d0a1b57c0db63368c0f8c2288c3a0466e2b3db081106b90920c46462faf00b5bd654f7140a689b78ef656a26b82af8dd1988f166ea04e9aa777a094d892bc7da4bc7bcf0618526f496cddea6d67df7bb0de9e99a35a0b1b210ff07497\n\nSquare = 9668b9e40a8bdde3c93943a918ca71fa0009cb05a1f592b2bb2c6c6172b2950719bfd80cddaf45d044cbb6aa99715046088f40ec6812945885679231c07f4200023548ead086b834abd8c8f8294db28b203329553242fd2f778ef5cc5ed0b48c7356d8c2d782a01809ccdb6b012896617f11d963300e7bd38ff512829514d94343476818ddf9d712bc70cffe7f767a9fc75a5630e6250ed45e6831b4660eb49d47dd1b8b6a0dddf3fb3ff0e12834337f145f741f70a2aa43769af50f099e004269ac47fab79e060800dc74da88141adbc46c15c7330931e3a2bed9b958f78b30214f81a64d121f96fbcebf7569fec0cdc6b11\nA = 310e7a40667d9d5dc29744b123cdf6a663a1b995f62fa9d4d853cbae0dd23669f4778bb2040317ebf6a06ac6299b21067aece5c5c1afbe6e789d656745ad66464991cada0eb237c6ffe991cac4670bfc90eed5f8c75073f4f846ea244bca0e9502ff56f8e9bc9b6caf275aaef38e26566fef35329ca45392069\n\nSquare = 49e677c8b052b7db97542948542449af47e14248021f8d3d3f92b9af41c803072f71050f16dd848aebb270affc47e85427a7c73f227f0d63f140d0d293157af0d972eb5b38de494fbc78ad3a4c3d1ab40197bc4427752b6102d1ced6d6cbc9d7caa0d1bcc57e708535822180055ecc9d9667e0590274b778480a3720823e931ff6daef358b1a1a9092f1f05fbb5b10ad5707a124e8be63bc696f083eb74e5b4f0e3110de8f297ecd30dfd2bcb010dcad4e387520d3d00365fc51c2a3dfe064b1ac77a9295f66beffbe5dd4333e5cd823b0f36b0b94d66507b1d9381060980f62f38a62e38e5a75203233bb8d64089bfd100f3205f1\nA = 898b5f3655de74cec3b0fde2ab03fd18cdbcfc3eeea48ba39317d26917130c2b78e05237cb0454ece268f091cab699fbcd51ce341b53d6ec0cda5d0d5388bac25c6517214a39d03450ef8502e1675bfe8e57bb6086f10ce4cf8ce65eadc865b5bd8a00dc26394f3adb2ace609149e3582cf44246184b2adc0ffd9\n\nSquare = ad00f10fed55175159b2409dc80899f9113ba7c8099d0402ec0f520ab4aeeb46d36369494a4e6fa23675adb38148fd2efa082df5094c0acfb77a9ab6ba7a299298d69b04b58011c35325f46b765e580b5c05eca721904f1fcc355dbe39faa92af5c9a6dbc4ab80e62b815b45983d9506ebd52b9efa7a6b9da352d1e4fd6ffa81d3b4596a0c14fb825297da361461ff2240e4378340d2ae529932d78f3d9f6b3c6d65d717e66122e5f590c50ce0a5d81ad8e0f24e104c0913cd8d0eb2de4c8cf62a7535bab5502df3fba08bb4dfe73d89c8b00edaa7d5f3274be9959e7ab6b6dde54f2491728a1dc11fa8e1c6a95e67eb7617e9b7471ee40\nA = -349cc2a5658fdbe9ba5c350d3b25baa38b1ede01926694bd550d36883e53d8758e8f1ebe83e2f4560605510413a7d880929e2d9cbc2730b1736dc2689cf7bbcdc68a342b6398e547a9bd67cabe298796d76b98ed4c1dd9c22e36145892e8fcf2258529aed24252a70b6ca8fd2aad8a84becf7e1bf98b1e9bb024b8a8\n\nSquare = daa3835d3189ec9ade592e6076e76d441838077a9431273bdec02379b3a6ac38aecbbd57c3755ea58d",
-    "def8105ac28f2ecc8598ec0c4bfc9c1c80222fffc776722eb0621cdd8a0d55f08767fc2922282a76e529d81e4d6e21a2542b8c9a403709ed1132e3b52786b81e684591438fdddb5df2f0b72e6b39cd2db6c0cc55c759c2dc1b6ccc20a5cfd10c6fd345fc766035c7478570d4ac534db3fdb718e2bdad3d096b137bfc09a562043800957e2afe4fdcfe292881f6189edfce52370c0438c2822ce3b14d73b3eff32f7e5ca97e989326b4e3a8fa35544193f8590bbb0ddb1f914894ab87998090771a0be1fd23917cd792be86ea0b98e6eb24\nA = -ec953f1b7ba7d561edaaa23076987daf86f50e9a66c36f0993290549a9006dd9d424885c0fa77295cfe34fc81c5edce9e2371b3039ea18d8f998d1956196284e6d81eb1c62ecaa8cf3fcaca28ca7e64342803c8dc3c139080bdd4a1ff30d7288b085a579d9e90903bd363b48f2072bb6fbfbd9ba2cab30a8a63784d246\n\nSquare = b33f4f3ae453058f4e865ec78f0844bab7af66a97dc2f265ca73ae2232777474bfdda39e10652d7386c16f145272192af728893c3d8a8e92c60d77722b924c30269ff5a399a2449ce15e50320c528c22655ad06227ac4efe5a993179ec61c2fc9115f89d75b53961fd16f7797657f6fbf55662b019608a1d30f64a2c0838e0018b7526921fdd34fd462bfcb2462b7065e2bc7abd57d71371e45dfd8fcfcc00a71f7e45430820747c9a060b72e4f6d2919cbffd00beb0c31a2bdc32afe2cc540b38dd04a2b73ae5ba481a6e535f37a757bbd6aaa972986213afadfa47cb7a15a6f1d443f93cb0ed824a10b4b7d82cae524a096b65ccb39be3c37c07f59\nA = 358da59ef65f62f633675764e292e5a68879df24a4727eca1fc4d232b3a6d936976c92eeb11456b5e8c11319838c145c6529d2f3acc828e55b8274bfe9afb5db241b102715f8e8164e454ef39f13ff1b37cf367a5a66c4f743c750896b7c3c29026e448bb36c6c06b0d9a3d048086ef0c3cd922a02e794223f388b5d646db\n\nSquare = cd4246489f6f221f920acbd8bdcdd17f47d2b77268f72254de4190685c123e8c5eab8517fded1852e8316c9e549d3fa355142d91b2921a3c94aafd8862cd2235429340da38a2af131b8d002f17662354f5805f6a7af7afb6dbd2f641036600614cea42bd8b24d86a5109eed29c0865a5f30c5291b1d1ef3223f9b9826dee773d98ce972da92daa19e843f84ca5f1cd77925a3c1117242ab0fb509b94a83f8de4fc8d21f856f37a4d025b3024bd0dbb6d8acfda4ab2993fd6eb7a7448d4f66ec725d37f0eb14eb242c0ff3f0c4572ba6b98a4ce905fe1b7ca3daca56c225171428c56af938fb66b37e99e54139157bbf41f536989ef813af738837afcd62290\nA = -e53ad05c88568f09f616797f0b7f2756fb543d691ec2a5b645c1e5892a247302826419a35b1348cfd2c1c569c23c31b4c46d6c57d4a488c29ab5beb77904d4adfcd0a01ea0a26bb0cc8790441cc2c8c900f030d7315b4319f1a3cf5685a140e03abe6b94730ad79e8de1f4a0cded86a3d6cfe2db267fa7dc9b2bb32872a90cc\n\nSquare = eea8028b26e0df090504d54da714a6f5f2695202e53cff479c78aedd47a8dc676243ec586740fde53b3eca9ca02b91031ce766242184109503fbe25b1b6d318e3cd5970fabd16dfa22984dd2e9f1e0f14c189170fc69c031d66663703e6235a942d51a4545bd7b0769d01d302ce2b00b83f01568a1e378f61fd0ca6201b0490330580cd9de85719e174a71915d7efbf65cd73d8f4e66f27e0dd3144d58ec09ed0f7ed7d1238ee596922807100fb7a11127944ddcdec6a9ca3bbf6df7301e354f3f049bfb7c275b43c3d8cda5907a932fba507c9145ea3166081c1b48fcc710ee32cd931f936c796b14f8a78a592e67753a7c9e428a01719c8ba82652f3a89fae110\nA = -3dcb44be1e54c5a5d7db48055ca9afa1ebe2ae648aa6e16ac497502a7deee09ffa124720fad0ab163ce8b3ea6a90f110ea52b67dbc424d0cf1e8c9726dfd9e45bebcefaa5cd5706edeed27896525f31c6bbea3d67ee97badefabf3e2532470b66e3ae3100f66ddf50cf02fc3a8e3f44c304251d3b6a7ca3a6e4bd5d16a41bd97a4\n\n\n# Product tests.\n#\n# These test vectors satisfy A * B = Product.\n\nProduct = 5befab3320f8f90542f3120235abd926aac3805a19e343f690\nA = b057af553afb120db6b7764f8\nB = 857734c4c27a1d17f7cf59dee\n\nProduct = -ab1ce167f4b2945c55ae3f87df50ad07d4be87cf9f8aa07b0c\nA = ae7a6a87ea8981a567d0b3ecc\nB = -fb0fed5f8c737bcacef4d6cb1\n\nProduct = -c2606cd48e6b075c8da79eb4668e7157f1f175c2860fd4c475\nA = -c28dc31984d4583e9d45424c3\nB = ffc4581a5c3f885cf42767e67\n\nProduct = aa6805b5408aff7f914472756da07830dcad902834dbdd6944\nA = -ffa07ff9f503511954e5dd3f9\nB = -aaa7af472ad8957763f5a7c64\n\nProduct = 58ca2569173389df29b5ce4b784086055dee821a7243db7210\nA = af417d936f4690008811a1ae8\nB = 81b26b80b43aa65aa55ded52a\n\nProduct = -a043d31dfce8bd01724d31c863d0a64f1bf013509d77737c42\nA = fb5fae5edefb6997d44a1ecd6\nB = -a336e50c6f7845a1686cc88a3\n\nProduct = -b5d6a45ffce851b201239d938ba551bab7dcb59fc11fc35fce\nA = -f918faa58bb57a2ffb8b01f05\nB = bae08c3006fade695029a1df6\n\nProduct = 6f2fde7d1a18625d727c6345ed85e597d546d9228bf7f0564a\nA = -8d108d7a16f0696d4ceb24445\nB = -c9c764cae465207097ef8d2c2\n\nProduct = 93808b1140841dc9735cd61c6f855ddbbb83066689b0d7e1a0\nA = b386d08daf3fa2154e9c768d6\nB = d2557dceb2d02d04d9c578670\n\nProduct = -ad04212ca8cadb1f7861c5130ba3a747046a2a7e4a0c72b69a\nA = e4e5f7d1311e0c5f2e404d55b\nB = -c18057a328d8c7375afdfd4ee\n\nProduct = -685e75c232f2b4a0e455fe5ee8aea52f292ad8b8178320e692\nA = -a683312f132b2320632e74ef6\nB = a0758f12791453b4af354730b\n\nProduct = 6f588c53185c503dc5b0dc3002d3817ca2e7eb2370b3e9a647\nA = -d70c9b93170261091f0c53f27\nB = -848c86c51a186ac4c9080d3e1\n\nProduct = 5e3bc5a04e054a9a244bf7c86cae215072fdb70e9199989427\nA = 898b64ef09d7cf63966e1a3b5\nB = af638b12f26aa5d12e97439eb\n\nProduct = -8d8372b235b16108285203c03a8aef6fdd3c0e1a9fd31d4f68\nA = f6003dc83818c14fbe36c9998\nB = -9343f6cbcc81fa4c9399dce5f\n\nProduct = -5ee6509abeeb7af7fc5caef40d1822ad3150c8d74f522dc7c8\nA = -875ff6f56ca72cbdf614bb9ca\nB = b375a68a21dfb1f159c22fa14\n\nProduct = ada25be404a17385af5a330da799e5909da81bfa0715baa6f4\nA = -c9b8df392e76abc3eb7d5ce04\nB = -dc5ab818c70594dd917b4243d\n\nProduct = bb24422ee4656ddfcd50ec38201b15baf679d3b75e5cb878ca\nA = f8e12cf4defe388b78510f687\nB = c07ee817b4ae95c2915b88966\n\nProduct = -93da296ba164c7220a17330647aef0980c94eddd2cfa2a3b2d\nA = bc5dc74ddf7a1363d1c2b1f25\nB = -c8f069bad7f93cbfe6df51169\n\nProduct = -6b2e1d132c4e0b0dc9b7e7de7d424fda5180480cb5ff47c755\nA = -a8048acb66a8bb88df39266e7\nB = a34e0b265d71435ae8c92a463\n\nProduct = 6ccb2cd93783576a8602ae43f41c786008b6623a4cca0a010a\nA = -b071f1f54790c951c1dd2a1cf\nB = -9dd89bb4d9b546207e282e2d6\n\nProduct = 5c742ba47d0d64bd97509927ce957deedb855766cc24c60016\nA = b44f3f252c368096fa62747f2\nB = 83439b97dbac579fa4f7b7d23\n\nProduct = -7347ba65691c913286c2fb55e45b177f031c1d86ae0e9f654f\nA = 937cf0643ffa53cdea24d642f\nB = -c81881f78243dd5737a7d28e1\n\nProduct = -9bc0649a703674e59f83ff9b8a560e5cbf51f65ca310f80f95\nA = -b536f8d9769be6f62da941ae5\nB = dc0746fb101881ae0cacde6f1\n\nProduct = bf4992fc3a124de350f9fb90ea825cf663b1fa051282ef22e2\nA = -ff7eacc7de1bb01d668c693aa\nB = -bfaa6627f9fc7ba68ae41bb2d\n\nProduct = 7c8992d34cc0b63f1c953f68d4e12a99d3f3a34d16bd76caa9\nA = 9e0d5a850d078890a983c0ec9\nB = c9b72c118b3e1f1023a696ce1\n\nProduct = -a75840c95082b9a0ae0d6e0a4eb5e09288e4e2a66e9697d9cd\nA = b2b042a21045a74ef1a5091d9\nB = -efbf8b120b384e869692a1b15\n\nProduct = -a510b333bdb4ed7479c142e8fbe2b12f7671a42acbe16c0998\nA = -e7fd5e0bb5496b9d876c27f65\nB = b6262653b2be44501af1d85b8\n\nProduct = a1c1e90afc4684754155526e307fc6ed798746f347bae2c880\nA = -b84674832b26ded0a690a8ff0\nB = -e0b7bdf2fd05a038ed3640b78\n\nProduct = 5588e0c33bffbefcc5695ca0615abd383343f21a8a0d22b222\nA = 80cad81ad9a66ab6a1c2e5669\nB = aa0453a77c8af1584f54750d2\n\nProduct = -6460c2fcd6cf3304ab163ea883ac48e2031cd10f2e9014c0ab\nA = c49ad3d7c8848d4fbf913b10b\nB = -82b3dedbe3cc7cd532ad632e1\n\nProduct = -a18717330b711669e85abde8c4dce426529aa621ba3da2a477\nA = -cab4a9c0a331a5a5e826dda1f\nB = cbfee5041c13075dfe3399aa9\n\nProduct = 8ab6282ee892b53c083d319a9dcab48af97a1ac8493c0bfcad\nA = -f7d13e47f9aaac8c25f9bf75b\nB = -8f4aa95231c1e2336aa092297\n\nProduct = 8f2d1c23c78777ed371f13155445ca3c88cbc0a9b299bdf9d3\nA = 9d8248d00defce1ad081337c3\nB = e8b479295ecd9cef7301f24b1\n\nProduct = -86d5e0c5b581fe59819730b4b71e33d1f85f9ab504c7dbe2d6\nA = b21b45e88acff48562a19729a\nB = -c1cdfebccc763beeac394b997\n\nProduct = -484ca05aefa113bdfcb1bc623f730c9f9555b462a8ab4c9606\nA = -8c12b406c02c4417163c0956b\nB = 8422b15c80c1c087b17eedd92\n\nProduct = 614c3c91f60050c785fd229a3ad74674577a90cacb654e0a5c\nA = -93d45bce155a23a397506d96a\nB = -a87e339c3fd5aebede5fb1b36\n\nProduct = 9683285f194a7e4feeab196a36bdfc4f828035fd184b9cc692\nA = f196d8fe760fdcae7eb60e2f7\nB = 9f7d88a2163ad818bf3a6377e\n\nProduct = -988a64599c19cc64f3cadc1a83fea6550185f6cc3ab82af822\nA = d0584b2a306671e4d2c9d0c7b\nB = -bb6e7559df199c68d6df3a3c6\n\nProduct = -68456814cb0edd951196d04c853172afdd5787a5bd69a57876\nA = -cefce1b0a1fb22862418bb597\nB = 80f614139947aea5e76cd55fa\n\nProduct = b4b1cbf5d6566e7a57aee0cc5c9c8ec4ad885e8766aa7662a4\nA = -d68ed1bea046c6cad057e21db\nB = -d7988b9be54f6e332d019032c\n\nProduct = 6b09212675ff5257a1384371e17b37dcc268bbb141577902e4\nA = a8208053adc20a609d5d01404\nB = a2fa927c5458c4fe662d7a3b9\n\nProduct = -8361bc26f9bcf55f677e047d822d30",
-    "04027da0d0455b244d10\nA = e82b6410b29020c2d6810a977\nB = -90ddfe0e7f0d6b9cdc0815f70\n\nProduct = -f1b6da00923fd513a83e32040a515649fbd362f69ebc016d9f\nA = -f9b697d9ec774a8d1ee5ea905\nB = f7ccb46a8869cb028492bed53\n\nProduct = d06206963f2e150bacdb32c823c3a47f013d5a267c3c0d0c88\nA = -ea8e63afa99c719897ad7f2ab\nB = -e36f11f55b6148d1b4f46e598\n\nProduct = af774a5eae6084df5ca499ef005642730adabf6a4f9533e2fd\nA = e4c7af7eea3ec9cc2443b7319\nB = c457bc264c8461789931baf85\n\nProduct = -76350f428bfbb95e6c253ec0f457aa84cebe8c7cb1af2a2120\nA = 8fd1ff97465775d44dee58ae0\nB = -d268a7d328f44baf80e35119f\n\nProduct = -787ae3f114f9a8dd4d249d5d3f3b0897b02564b9469416cefe\nA = -bc0b398bd0ec045b0cf147b7e\nB = a4050955c234e473257d0c641\n\nProduct = 9d6320b3d4aabac097a079b9bd2aca7f1898bcab0f23409fd0\nA = -9d7a4ebac630cc0662b816fb5\nB = -ffda517d3eb3214986b04e290\n\nProduct = 80bab8bd800ac8c9dc3bb57dca306f10af6fd88c5d8314833c\nA = 834bc50140d6c6ab938dc58b6\nB = fafee47793cbc533b3c66af3a\n\nProduct = -b08920f5922226b1dec87151ae087d8a7e5c1aea8c9be148b6\nA = bfd5b1ad323c79428cb2db36a\nB = -eb956a10edebdd658e6810fcf\n\nProduct = -6d428e08e8350bb4b0fae3b662c82df2aef7beadaa17430dbb\nA = -a57da276998c548101f514e9f\nB = a9040c1909712e1149d295765\n\nProduct = a57da276998c548101f514e9f\nA = -a57da276998c548101f514e9f\nB = -1\n\nProduct = 14afb44ed3318a90203ea29d3e\nA = a57da276998c548101f514e9f\nB = 2\n\nProduct = -295f689da6631520407d453a7c\nA = a57da276998c548101f514e9f\nB = -4\n\nProduct = -867614005cc204a8d19720fe13\nA = -a57da276998c548101f514e9f\nB = d\n\nProduct = 12bf3b676f64e5929d38c35e803\nA = -a57da276998c548101f514e9f\nB = -1d\n\nProduct = 24d8f92c68303ed0b96f91a8167\nA = a57da276998c548101f514e9f\nB = 39\n\nProduct = -49b1f258d0607da172df23502ce\nA = a57da276998c548101f514e9f\nB = -72\n\nProduct = -6fd5e6ca25c3d51b2e529f22173\nA = -a57da276998c548101f514e9f\nB = ad\n\nProduct = 1276d4705b81b82da4c7e82559d7\nA = -a57da276998c548101f514e9f\nB = -1c9\n\nProduct = 1ddb9abfc5d4017f068a67b5f4fd\nA = a57da276998c548101f514e9f\nB = 2e3\n\nProduct = -3a8b41c914b1b4a4e341433601f7\nA = a57da276998c548101f514e9f\nB = -5a9\n\nProduct = -97c0f4ba414d6e7d4c8b7ced84d4\nA = -a57da276998c548101f514e9f\nB = eac\n\nProduct = 1198739e0c23639c176d46d13f7c8\nA = -a57da276998c548101f514e9f\nB = -1b38\n\nProduct = 159150954ee0dedf541e4dbac0ec3\nA = a57da276998c548101f514e9f\nB = 215d\n\nProduct = -441d4bc44c86f02ff12c3d91a1562\nA = a57da276998c548101f514e9f\nB = -695e\n\nProduct = -64726b76005ebee27592237ba5dde\nA = -a57da276998c548101f514e9f\nB = 9b62\n\nProduct = bbe4ec7cf7c5bbd198e0ea86bb658\nA = -a57da276998c548101f514e9f\nB = -122a8\n\nProduct = 21f717d05681fd2eb1796776a69ef7\nA = a57da276998c548101f514e9f\nB = 348a9\n\nProduct = -396ac788a1748bc6955f99be4d2c64\nA = a57da276998c548101f514e9f\nB = -58d1c\n\nProduct = -54a213eb083aed1a04f3d1b2da62e7\nA = -a57da276998c548101f514e9f\nB = 82eb9\n\nProduct = 1366fb9c20fb14b8b9a9be4b3e3dde1\nA = -a57da276998c548101f514e9f\nB = -1e037f\n\nProduct = 238d65fd26da4733e5d93ab2485d40b\nA = a57da276998c548101f514e9f\nB = 36ff15\n\nProduct = -38272a99be154d531e922be405aee9a\nA = a57da276998c548101f514e9f\nB = -56dd26\n\nProduct = -64651b62b6a454c08951632c7f2c398\nA = -a57da276998c548101f514e9f\nB = 9b4d68\n\nProduct = fb272e3597b816144f8b945ae6130e0\nA = -a57da276998c548101f514e9f\nB = -1848320\n\nProduct = 280d9f5ed7243712ecb9a7c6358bcb8b\nA = a57da276998c548101f514e9f\nB = 3df5795\n\nProduct = -2fbb6bb8e1ba78cefc47fbbc20e188ee\nA = a57da276998c548101f514e9f\nB = -49d6652\n\nProduct = -57f29c13691ffa1642d2860dab9d288e\nA = -a57da276998c548101f514e9f\nB = 880c2b2\n\nProduct = 139c19d7668e6aabf2d7206cb0723ed34\nA = -a57da276998c548101f514e9f\nB = -1e55aa4c\n\nProduct = 2950ce04bf0cf836d4fe94b88fb757d0a\nA = a57da276998c548101f514e9f\nB = 3fe968b6\n\nProduct = -5175239488dad05a58414251496d2a06c\nA = a57da276998c548101f514e9f\nB = -7e020414\n\nProduct = -945ff0ed38bc6020cf679cbd3e0758c6d\nA = -a57da276998c548101f514e9f\nB = e585e573\n\nProduct = 11c69ae98f6b27e95477986f796bc67c8c\nA = -a57da276998c548101f514e9f\nB = -1b7f653f4\n\nProduct = 209afe75e8fb5ac76d13c06b545f5d4d73\nA = a57da276998c548101f514e9f\nB = 3270154ad\n\nProduct = -386d64b215e41506514f4988ed237e4da2\nA = a57da276998c548101f514e9f\nB = -5749c891e\n\nProduct = -6c13cccdb1d140d0babd52707ea72fa278\nA = -a57da276998c548101f514e9f\nB = a72fb6288\n\nProduct = 136228a8a45540372b9b3cd7f82021f6546\nA = -a57da276998c548101f514e9f\nB = -1dfc08a2fa\n\nProduct = 1f0ad3babf9d132eaa08cf5cdb8f19dbf01\nA = a57da276998c548101f514e9f\nB = 30050f2e5f\n\nProduct = -50d615ce183258e95af77319b766fac81e2\nA = a57da276998c548101f514e9f\nB = -7d0bf92cde\n\nProduct = -817d358293b86a56a4e881e50257c549471\nA = -a57da276998c548101f514e9f\nB = c84efb12ef\n\nProduct = f09b9e80be251de474d726b16e25a6865fc\nA = -a57da276998c548101f514e9f\nB = -1743322a484\n\nProduct = 22996cb0f9c60e35dce49f3825f8a479db26\nA = a57da276998c548101f514e9f\nB = 3585acec11a\n\nProduct = -2b307a37c91791a61c0691858f5f783e4678\nA = a57da276998c548101f514e9f\nB = -42cf6be3e88\n\nProduct = -8826698fcba6c30d755fc523de1cc25301ae\nA = -a57da276998c548101f514e9f\nB = d29cc8af592\n\nProduct = ae37fc99fd419809310782714530d7428d77\nA = -a57da276998c548101f514e9f\nB = -10d8059d4a29\n\nProduct = 1d544a20f9bc7d95ab67d1f65743979f23bba\nA = a57da276998c548101f514e9f\nB = 2d5eadef1c06\n\nProduct = -367897184e9929a0294d320f10278889fbeb7\nA = a57da276998c548101f514e9f\nB = -54431582d0e9\n\nProduct = -943a509076a00060a2e7fa1cddb7468d734a1\nA = -a57da276998c548101f514e9f\nB = e54bb102f4bf\n\nProduct = fcce6e42879af5ad13545c0bcaab85b690cea\nA = -a57da276998c548101f514e9f\nB = -18711db522cd6\n\nProduct = 258c49f86d0cbb14ae9edbd3456be8cede2022\nA = a57da276998c548101f514e9f\nB = 3a1562c7c269e\n\nProduct = -4a8bbce59ad7daa51136d557f7fa16e9a2faad\nA = a57da276998c548101f514e9f\nB = -7350e780b0f33\n\nProduct = -82f53ec9333275d5cc271876a7db936db49280\nA = -a57da276998c548101f514e9f\nB = ca94ad312dd80\n\nProduct = 11daee4fcc713db5b2806e47fa5dff3b5b770eb\nA = -a57da276998c548101f514e9f\nB = -1b9ed6758f9635\n\nProduct = 17038cac4f0c94dc24985ea108ae6682e175752\nA = a57da276998c548101f514e9f\nB = 2399b8a9b1116e\n\nProduct = -37e5f14394bf347a3ed061769fe8e6424af4348\nA = a57da276998c548101f514e9f\nB = -567840a7569fb8\n\nProduct = -9253d4a32a88d8f725984514d969012ead7cc9a\nA = -a57da276998c548101f514e9f\nB = e25b246f733f26\n\nProduct = ace3648371c16a931d29004e79f5b9678391da5\nA = -a57da276998c548101f514e9f\nB = -10b717b27b6a13b\n\nProduct = 1faa5b45d04c143c339b09d3aad94d39b94ef960\nA = a57da276998c548101f514e9f\nB = 30fbd672e106aa0\n\nProduct = -3fdfe246d27aae0d08d63b2bc501461d2bff3b8d\nA = a57da276998c548101f514e9f\nB = -62cef5f078a8253\n\nProduct = -5b792bfaeff04ee3d948cb343a249d49eb344f57\nA = -a57da276998c548101f514e9f\nB = 8d805ac65649c49\n\nProduct = c5f824406161eec321da5a58e3e00d393b55abe9\nA = -a57da276998c548101f514e9f\nB = -1323dd41d2e1e077\n\nProduct = 2226dec8a57be8e84e42559007e2d101ccbe67f8d\nA = a57da276998c548101f514e9f\nB = 34d47842b5d0be53\n\nProduct = -340f50f812c7420b502000940788a700f6769788a\nA = a57da276998c548101f514e9f\nB = -508836d8e1193d36\n\nProduct = -a00f1d96e19c590479625c5329a87774b5964cc78\nA = -a57da276998c548101f514e9f\nB = f798fc858657f888\n\nProduct = cb94f830cba8997331912a6a31c34f1bef826d121\nA = -a57da276998c548101f514e9f\nB = -13aec7a5c52a0883f\n\nProduct = 16b45140b048d6dc0b9fc811df7ce7dd88357fff04\nA = a57da276998c548101f514e9f\nB = 231f27f3e347bd67c\n\nProduct = -2aa94179351b4e87de5849ab619d94f47450640199\nA = a57da276998c548101f514e9f\nB = -41fe3ec2189599cc7\n\nProduct = -5489401d3da93158d4284e557d74016c0a7cfd935a\nA = -a57da276998c548101f514e9f\nB = 82c5281df41bfc066\n\nProduct = ae04d5b212ecfc9a6d7df07794d565df52991fb70e\nA = -a57da276998c548101f514e9f\nB = -10d3139229f5d02432\n\nProduct = 27821bc811f45d63089790b41d307be978d4b19564c\nA = a57da276998c548101f514e9f\nB = 3d1da85cc012b3e234\n\nProduct = -3de3c9e9d7fa3020a578706339314890dccf63096c2\nA = a57da276998c548101f514e9f\nB = -5fbcfb28bfc9044bfe\n\nProduct = -627dcb299a6720044abcf11469bdfd3f951edbb5bf7\nA = -a57da276998c548101f514e9f\nB = 985b930517b78e6ba9\n\nProduct = cc0622441497a37fddf1856d5e2c99df52b99ea4573\nA = -a57da276998c548101f514e9f\nB = -13b9b88948fb7e95cad\n\nProduct = 1a5168e1a492210591ad1ed660adde9110390e4caf32\nA = a57da276998c548101f514e9f\nB = 28b631c6e04b6ab0d8e\n\nProduct = -4d8ec27b7460ce616421b9f5cae708c2ac241daa59b4\nA = a57da276998c548101f514e9f\nB = -77f99bdf1eb09da6dcc\n\nProduct = -55a",
-    "fd796db7bce822a00073fc8926d3bd0c79772f036\nA = -a57da276998c548101f514e9f\nB = 848cdd6212b9bb3620a\n\nProduct = dc494b0d73e8ec07cd2bb6dd8191d2b4d48e7700cc34\nA = -a57da276998c548101f514e9f\nB = -154c39567bd8be5f6b4c\n\nProduct = 240e9301b4345b914ecd91a49a0e651524dcecb6fdc6c\nA = a57da276998c548101f514e9f\nB = 37c6e7ee89cf87674814\n\nProduct = -39002ecfd6d96661b336157ccef6536756ad2e9219be3\nA = a57da276998c548101f514e9f\nB = -582cdab09915a652203d\n\nProduct = -695f49fc891d53f396f0593efae3973082b76d4f9e944\nA = -a57da276998c548101f514e9f\nB = a30074dbce2246af043c\n\nProduct = bba2b7b45b97cb0d7fb30fed95089870742ad69e7aed7\nA = -a57da276998c548101f514e9f\nB = -1224195afc7b394ae8cc9\n\nProduct = 1910edc278515ab7d4cc09b496dc3c06c32c75bc7368af\nA = a57da276998c548101f514e9f\nB = 26c6701c39334169e7bf1\n\nProduct = -3670b7f9b661aba35ce50984d83173c84c8fa60e04d100\nA = a57da276998c548101f514e9f\nB = -5436e84b4a29858a68f00\n\nProduct = -7fa0d3e0082b37475342b7e22e5dbad7b8d4cb5d64f871\nA = -a57da276998c548101f514e9f\nB = c56e0f44fc63bca242eef\n\nProduct = da7fe3367ce640fa5941c033ac1874312f10ba5950da75\nA = -a57da276998c548101f514e9f\nB = -15200043166ff309f0426b\n\nProduct = 1871d72481f66b1d413100edd6b339cbbaa67b3b2b3cd57\nA = a57da276998c548101f514e9f\nB = 25d057879db26fa29a5e49\n\nProduct = -3cf1dd1e2df3456757d72f35353c3c7a659b2ef844ad857\nA = a57da276998c548101f514e9f\nB = -5e46be70de21949df67349\n\nProduct = -5e861cbe47aefab2a7ea59292aab1258932b9a322f66e63\nA = -a57da276998c548101f514e9f\nB = 9238670897685a6c9cbdbd\n\nProduct = f623344788efb857db55c924e95a437effa4dc8bb2bcd24\nA = -a57da276998c548101f514e9f\nB = -17cc0ec84c228225a7cf45c\n\nProduct = 15514c916b0ae7cde6add16c629d3e19ba52a101d75dff72\nA = a57da276998c548101f514e9f\nB = 20f9f925b3ed307edbb154e\n\nProduct = -460cf5b14f9d0b547c3084bf44207bf881745c409b08d07f\nA = a57da276998c548101f514e9f\nB = -6c5cbfd29f3dae1dce99221\n\nProduct = -5ddf7fb91d765af97dfda5333d8779e80837c2b51cfb4f43\nA = -a57da276998c548101f514e9f\nB = 9136aa79080defd1bcf90dd\n\nProduct = 12c1a0edfb6ab6a0caae2553fb3743827e1470a8954e0a3fd\nA = -a57da276998c548101f514e9f\nB = -1d03b512470dc3052779f3e3\n\nProduct = 28388a244214abf046488a8d95308d95f021eae4b994a5a52\nA = a57da276998c548101f514e9f\nB = 3e37dce784274962ff862e6e\n\nProduct = -4da476e76119deef291c0f56934a912a0877278a19a561ee0\nA = a57da276998c548101f514e9f\nB = -781b2f2dc40094a7f8fed520\n\nProduct = -5792496d33dd45e225f9dfca17419a04e075ffc0c90b37b82\nA = -a57da276998c548101f514e9f\nB = 87772a4fb582acafd3e4ef3e\n\nProduct = dd3a3506a7d748de16fb43d666928a87de0354d8e8a1bcaaa\nA = -a57da276998c548101f514e9f\nB = -1563841bf7851ff158a395716\n\nProduct = 24e8fb09a9ab0808ff643122479dea5ed41060c6c5b74e8752\nA = a57da276998c548101f514e9f\nB = 3918c30b5568318a58e9be16e\n\nProduct = -366c125f96b38b58d01c939c27c4100af3377eabb792b5491a\nA = a57da276998c548101f514e9f\nB = -542fb814f45924aa09a16f2a6\n\n\n# Quotient tests.\n#\n# These test vectors satisfy Quotient = A / B, rounded towards zero, and\n# Remainder = A - B * Quotient.\n\nQuotient = 1\nRemainder = 0\nA = 8cdaaa7c422f3c2bb0ace2da7d7ff151e5bdefb23e6426cf3e6b21491e6e80e977bfa6c65931a8dee31fc7992c0c801d5d7c\nB = 8cdaaa7c422f3c2bb0ace2da7d7ff151e5bdefb23e6426cf3e6b21491e6e80e977bfa6c65931a8dee31fc7992c0c801d5d7c\n\nQuotient = -2\nRemainder = 1\nA = 107f0e6cebfe22ac11294a06fed2b994d01c9b3610d50bdd254adafd08c93be8ebdd1e85e1286fe9c9e682a90cbbd6351681b\nB = -83f873675ff11560894a5037f695cca680e4d9b086a85ee92a56d7e84649df475ee8f42f09437f4e4f34154865deb1a8b40d\n\nQuotient = -4\nRemainder = -2\nA = -3d8746ae2123c2d3f1d35910b42af1f86f5e81f8e98986cea20b2a1bdb8af6cf111f1258f112c837accdf4868463fe9eba536\nB = f61d1ab8848f0b4fc74d6442d0abc7e1bd7a07e3a6261b3a882ca86f6e2bdb3c447c4963c44b20deb337d21a118ffa7ae94d\n\nQuotient = 8\nRemainder = -3\nA = -5645d65662eaac73050de06f8f982a9b2ae680467712284be3e2b0e58ef4bf4d72b5be5e12ee1fd803b47f161759662ff5c4b\nB = -ac8bacacc5d558e60a1bc0df1f30553655cd008cee245097c7c561cb1de97e9ae56b7cbc25dc3fb00768fe2c2eb2cc5feb89\n\nQuotient = 10\nRemainder = 4\nA = 813bc46ee19ffeab364073a89f96913f340d43ee72129ea9edac1beb4ebe1336450d2eabc7b26e51c400cec60d6ee459033b4\nB = 813bc46ee19ffeab364073a89f96913f340d43ee72129ea9edac1beb4ebe1336450d2eabc7b26e51c400cec60d6ee459033b\n\nQuotient = -20\nRemainder = 5\nA = 12805392c55ffa0e27e85e15f2b339872793664e9ed3074cd2600aa52459a57197130d1ea46775ef43115c9413248cc7b34805\nB = -94029c962affd0713f42f0af9599cc393c9b3274f6983a669300552922cd2b8cb89868f5233baf7a188ae4a09924663d9a40\n\nQuotient = -40\nRemainder = -6\nA = -3579fc4d6083394c691b060cf9e20318fe17da0487337f76710bd11512578830ba94ac7b587a2d5ab7cb4afe611e349cdcfb86\nB = d5e7f135820ce531a46c1833e7880c63f85f68121ccdfdd9c42f4454495e20c2ea52b1ed61e8b56adf2d2bf98478d27373ee\n\nQuotient = 80\nRemainder = -7\nA = -74ebad4b39ebaaff82cd91082408c979527907c363d8f0f75db410523f8477c074c45ff85851b6275b1ebc5279029818e78d87\nB = -e9d75a9673d755ff059b2210481192f2a4f20f86c7b1e1eebb6820a47f08ef80e988bff0b0a36c4eb63d78a4f2053031cf1b\n\nQuotient = 100\nRemainder = 8\nA = d2d8a4419fb3b1c22bfca04ca08c2ee066ccbc9fce2f41861b5eef91efd3c13eeb7eae5abea0ef1849662cfdfef7bbff892c08\nB = d2d8a4419fb3b1c22bfca04ca08c2ee066ccbc9fce2f41861b5eef91efd3c13eeb7eae5abea0ef1849662cfdfef7bbff892c\n\nQuotient = -200\nRemainder = 9\nA = 1bf534da2f4365c96fc5dd4928e73ac24b157b5136ead90cf6596033ec387a2c14bca828000ae1725f3a5ace8ad67a8c07a0a09\nB = -dfa9a6d17a1b2e4b7e2eea494739d61258abda89b756c867b2cb019f61c3d160a5e5414000570b92f9d2d67456b3d4603d05\n\nQuotient = -400\nRemainder = -a\nA = -3a172cc9483774544311a1366659d9e61cc9fac7dc11c68e36aa991ef4d5e96becf5bac3e0967c904d926617ea11bb9551b980a\nB = e85cb32520ddd1510c4684d9996767987327eb1f70471a38daaa647bd357a5afb3d6eb0f8259f2413649985fa846ee5546e6\n\nQuotient = 800\nRemainder = -b\nA = -5ecff3a3e47fa615b6e3ce2dedfdeefbfe1d437c394631820968a9650b59dc3a2dd1c9a0b06537e4e5c408a59e580921503580b\nB = -bd9fe747c8ff4c2b6dc79c5bdbfbddf7fc3a86f8728c630412d152ca16b3b8745ba3934160ca6fc9cb88114b3cb01242a06b\n\nQuotient = 1000\nRemainder = c\nA = d3ef80fca0ab3ac3432b22e2b485131d816810c39d02a9c82dcc05ec5e6406bc216026de3abe53ab103ea3b2ddbc2ea377ae00c\nB = d3ef80fca0ab3ac3432b22e2b485131d816810c39d02a9c82dcc05ec5e6406bc216026de3abe53ab103ea3b2ddbc2ea377ae\n\nQuotient = -2000\nRemainder = d\nA = 163956bc32325f28f48d41d32bb08d2a9c4ccbb0d818368fb13941e82b27da21d04094f7e897ce79c2d0ff8470505f1ef63fc00d\nB = -b1cab5e19192f947a46a0e995d846954e2665d86c0c1b47d89ca0f41593ed10e8204a7bf44be73ce1687fc238282f8f7b1fe\n\nQuotient = -4000\nRemainder = -e\nA = -3763f8e43bd05e6ffeec6d509bbe6ff9a9022ced8cb191c9abaf5fd0e0b75a53e2ad581455e3af09e702a77b164ed3fb54ae000e\nB = dd8fe390ef4179bffbb1b5426ef9bfe6a408b3b632c64726aebd7f4382dd694f8ab56051578ebc279c0a9dec593b4fed52b8\n\nQuotient = 8000\nRemainder = -f\nA = -531dd44dfa9e79a5aec8fa7c84bd3b753c146770d22d2c14a6d2125f7ab95e9b320e84c31cf3e0d883e1295a220f2a546550800f\nB = -a63ba89bf53cf34b5d91f4f9097a76ea7828cee1a45a58294da424bef572bd36641d098639e7c1b107c252b4441e54a8caa1\n\nQuotient = 10000\nRemainder = 10\nA = 900996b61f58713f0755e68bbdfa4e0bb47f034bb0304f77829847923d14715def1771f43b526c41b9667438b434d2b966c20010\nB = 900996b61f58713f0755e68bbdfa4e0bb47f034bb0304f77829847923d14715def1771f43b526c41b9667438b434d2b966c2\n\nQuotient = -20000\nRemainder = 11\nA = 179d7ede3db0c105525286551331d5b9e1f97a7883f0c13cf250afe9765bb5aaa527af7945c19cdd4596565cbc8532a3cfa5c0011\nB = -bcebf6f1ed86082a929432a8998eadcf0fcbd3c41f8609e792857f4bb2ddad55293d7bca2e0ce6ea2cb2b2e5e429951e7d2e\n\nQuotient = -40000\nRemainder = -12\nA = -293dc443c294c6a6c53dd49e84f58305d59a432afb6c7ea2039cd02a513231239571ae07f29b5427e869b9faa485511ca45980012\nB = a4f7110f0a531a9b14f7527a13d60c1756690cabedb1fa880e7340a944c8c48e55c6b81fca6d509fa1a6e7ea921544729166\n\nQuotient = 80000\nRemainder = -13\nA = -5b637eb8aa51ef15a18d9b144031c9756527fc0fb96c84b6df03700e5079ae1b3e96940a2c1e07f3b47ad8a9b2b8ca99171a00013\nB = -b6c6fd7154a3de2b431b3628806392eaca4ff81f72d9096dbe06e01ca0f35c367d2d2814583c0fe768f5b153657195322e34\n\nQuotient = 100000\nRemainder = 14\nA = 87c846f5469d4c5819aed0c7e77797209b2c1b83a7a0e2be70280b9f30946b5db9bd0f25a06cf4bdba1c7183a1b9eb75c19400014\nB = 87c846f5469d4c5819aed0c7e77797209b2c1b83a7a0e2be70280b9f30946b5db9bd0f25a06cf4bdba1c7183a1b9eb75c194\n\nQuotient = -200000\nRemainder = 15\nA = 11c2a4509f419aa977c3d37fa446fcf21b4b3b9f983fbaddeba4f51c285ac40322",
-    "00711a54cc6edf24297b1f3d46ad020131a00015\nB = -8e152284fa0cd54bbe1e9bfd2237e790da59dcfcc1fdd6ef5d27a8e142d62019100388d2a66376f9214bd8f9ea356810098d\n\nQuotient = -400000\nRemainder = -16\nA = -39e37ae0edd92b957e84682358039f5e432c42492a44f3de01cdf74d643760260f2837946608663e12291e9b0695449c1153800016\nB = e78deb83b764ae55fa11a08d600e7d790cb10924a913cf780737dd3590dd80983ca0de51982198f848a47a6c1a551270454e\n\nQuotient = 800000\nRemainder = -17\nA = -72f725edd5a3dd6f20b5e9ca7da08a99f8ec9214c80588182c0d42e03bcff34b488b28c03cdf41813a6193c10672a8ee68f6000017\nB = -e5ee4bdbab47bade416bd394fb411533f1d92429900b1030581a85c0779fe6969116518079be830274c327820ce551dcd1ec\n\nQuotient = 1000000\nRemainder = 18\nA = 966df62c26acab2d3d1dbe729e48d0181c68e9f5eba45f6caefa38d60e34057d09fe620abb8640cec8cac755957aaad7c6fd000018\nB = 966df62c26acab2d3d1dbe729e48d0181c68e9f5eba45f6caefa38d60e34057d09fe620abb8640cec8cac755957aaad7c6fd\n\nQuotient = -2000000\nRemainder = 19\nA = 190790727c1514b4ef83a1c6aa07493c0af7087fbc8a675bfd9a1e97b8ef80ef684219d6c6f1a5fb5b919f105fd7717cdd5aa000019\nB = -c83c8393e0a8a5a77c1d0e35503a49e057b843fde4533adfecd0f4bdc77c077b4210ceb6378d2fdadc8cf882febb8be6ead5\n\nQuotient = -4000000\nRemainder = -1a\nA = -22d115ab02f8663d8c009960086a0275d301d358cd3b250bb9e7c16cc6ebed4a8fbe43bbced856d93be64a17377d95f5f9c8800001a\nB = 8b4456ac0be198f63002658021a809d74c074d6334ec942ee79f05b31bafb52a3ef90eef3b615b64ef99285cddf657d7e722\n\nQuotient = 8000000\nRemainder = -1b\nA = -41f2e708ba47494a13607223b08e6d99c0b4247436632961d873804e83446dc97139ffaef3e25969950bd4b5bb4ff73b1a25000001b\nB = -83e5ce11748e929426c0e447611cdb33816848e86cc652c3b0e7009d0688db92e273ff5de7c4b2d32a17a96b769fee76344a\n\nQuotient = 10000000\nRemainder = 1c\nA = e4b52f78179039499c2f6b500840f41103fbd60eac0d7082297236f25189c18a8301a92f533945047fbb83427dcade334336000001c\nB = e4b52f78179039499c2f6b500840f41103fbd60eac0d7082297236f25189c18a8301a92f533945047fbb83427dcade334336\n\nQuotient = -20000000\nRemainder = 1d\nA = 10888959278661bc36089519a215bda60f9ce24ff7c0ac1f543b6e652f94dbff1f32aa40cad2b4b4d676f16948551501c29f2000001d\nB = -84444ac93c330de1b044a8cd10aded307ce7127fbe0560faa1db73297ca6dff8f99552065695a5a6b3b78b4a42a8a80e14f9\n\nQuotient = -40000000\nRemainder = -1e\nA = -3ada453530a180fda58533ab8c62beb4f693a134f512e4d23e487dac3b575e5390c0a90992400e402bb47aac93d46ded55f54000001e\nB = eb6914d4c28603f69614ceae318afad3da4e84d3d44b9348f921f6b0ed5d794e4302a42649003900aed1eab24f51b7b557d5\n\nQuotient = 80000000\nRemainder = -1f\nA = -57879eb5d92d565daac3ac5173639bfe44b6ecc69ff770af57bd79c9b93841c5677042cb362b794f3d8b24b0d3b73ed1cba58000001f\nB = -af0f3d6bb25aacbb558758a2e6c737fc896dd98d3feee15eaf7af3937270838acee085966c56f29e7b164961a76e7da3974b\n\nQuotient = 100000000\nRemainder = 20\nA = 89a2f1792afc54467955839eddc9ef2e37d391ce7a1a4a205291220c1f49f59ee31fc7a7a7f7706c199bf5c8c951a0d0743d00000020\nB = 89a2f1792afc54467955839eddc9ef2e37d391ce7a1a4a205291220c1f49f59ee31fc7a7a7f7706c199bf5c8c951a0d0743d\n\nQuotient = -200000000\nRemainder = 21\nA = 1c267719338a4562e934bc57fabe6da86ca534a34244bd38c15032f01f47c2fd498c83f644b345c5c661ada0e586a096bb63000000021\nB = -e133b8c99c522b1749a5e2bfd5f36d436529a51a1225e9c60a819780fa3e17ea4c641fb2259a2e2e330d6d072c3504b5db18\n\nQuotient = -400000000\nRemainder = -22\nA = -250249f2185d4b428fa9534f03ef3cbed535bd31c56c0b273e6c3d35e0266f7777a6e59a99da5738b8e3af8ac60061d6716ac00000022\nB = 940927c861752d0a3ea54d3c0fbcf2fb54d6f4c715b02c9cf9b0f4d78099bdddde9b966a67695ce2e38ebe2b18018759c5ab\n\nQuotient = 800000000\nRemainder = -23\nA = -710b30c23c3c4e646ba90da33d2ce35af2ff181c40b02e3ffa607966730c6b6e274dd4c3c78e578e0b10f431f2d832274bf6800000023\nB = -e216618478789cc8d7521b467a59c6b5e5fe303881605c7ff4c0f2cce618d6dc4e9ba9878f1caf1c1621e863e5b0644e97ed\n\nQuotient = 1000000000\nRemainder = 24\nA = 877f1caf75e7166ef18484d0718947893fd1ec016984387debc55c19e378a487a5ddbb03a80a88316f6fca16ae148933e719000000024\nB = 877f1caf75e7166ef18484d0718947893fd1ec016984387debc55c19e378a487a5ddbb03a80a88316f6fca16ae148933e719\n\nQuotient = -2000000000\nRemainder = 25\nA = 1ed1b7d9e4cf3d44ee98ef69850e61a39f54cc407c6795c07c887374441fd9ec258c21193f8a8c55802fb8f8c579cf94cb0ce000000025\nB = -f68dbecf2679ea2774c77b4c28730d1cfaa66203e33cae03e4439ba220fecf612c6108c9fc5462ac017dc7c62bce7ca65867\n\nQuotient = -4000000000\nRemainder = -26\nA = -35d324ba37d2000f960ca1c9e1ab96e341a2ae6a5ea5cef014c73a39dde000d8ad9606b817ad67e4e4593cc5894d354854898000000026\nB = d74c92e8df48003e5832872786ae5b8d068ab9a97a973bc0531ce8e777800362b6581ae05eb59f939164f3162534d5215226\n\nQuotient = 8000000000\nRemainder = -27\nA = -7039477c3e0a6f415e25e9f9b1dab1edcd8a23f984e7e3bc149c206a3b756b1be001450af4049cd4535e4243d7032afcf6790000000027\nB = -e0728ef87c14de82bc4bd3f363b563db9b1447f309cfc778293840d476ead637c0028a15e80939a8a6bc8487ae0655f9ecf2\n\nQuotient = 10000000000\nRemainder = 28\nA = d6c59dd07409da98f7bbc7ee471b6e06c4d9e832e9f4d04ed9da63564d37d3072a950564cf549bb5d6e7dc85565d3cc8ba340000000028\nB = d6c59dd07409da98f7bbc7ee471b6e06c4d9e832e9f4d04ed9da63564d37d3072a950564cf549bb5d6e7dc85565d3cc8ba34\n\nQuotient = -20000000000\nRemainder = 29\nA = 14d27a16a9cf2fdbc85b88a604dd8f0e57b5b34a27089d75d805e05fbb367dfa61c085aa98b896e3e53b85ef774a3fa52417a0000000029\nB = -a693d0b54e797ede42dc453026ec7872bdad9a513844ebaec02f02fdd9b3efd30e042d54c5c4b71f29dc2f7bba51fd2920bd\n\nQuotient = -40000000000\nRemainder = -2a\nA = -3bd0119619fbb5b260c44050d61e6b1925a49713d754ceb06bafb1d730a93f199df654b153c40e75096ebbaf5a6ce3c801820000000002a\nB = ef40465867eed6c9831101435879ac6496925c4f5d533ac1aebec75cc2a4fc6677d952c54f1039d425baeebd69b38f200608\n\nQuotient = 80000000000\nRemainder = -2b\nA = -61a283fe41d965ee770704bb453f689cb82a81089422d6d904a91776a06d32857220286e6ef6327807b724062dda143b46890000000002b\nB = -c34507fc83b2cbdcee0e09768a7ed139705502112845adb209522eed40da650ae44050dcddec64f00f6e480c5bb428768d12\n\nQuotient = 100000000000\nRemainder = 2c\nA = 87bd03a64d9c56fe340137065ba36bd07b556119546dd1fc3ae087ead32bc79ca7efb5c7230ea7bfb00ad419096d9279fbe10000000002c\nB = 87bd03a64d9c56fe340137065ba36bd07b556119546dd1fc3ae087ead32bc79ca7efb5c7230ea7bfb00ad419096d9279fbe1\n\nQuotient = -200000000000\nRemainder = 2d\nA = 1eb7cfb197d19f56ad994eca52d1af6466fd09da07d68d63067602046b2d42d3063ef5eda6b58afd69fd92b0b727a0ecde1420000000002d\nB = -f5be7d8cbe8cfab56cca7652968d7b2337e84ed03eb46b1833b01023596a169831f7af6d35ac57eb4fec9585b93d0766f0a1\n\nQuotient = -400000000000\nRemainder = -2e\nA = -3ab858b3329e5bd0469118be52a867b2febbe2894d962cedeb3a5be1738db1cea106cd0710c9f6937348c2c63b109ae623d500000000002e\nB = eae162ccca796f411a4462f94aa19ecbfaef8a253658b3b7ace96f85ce36c73a841b341c4327da4dcd230b18ec426b988f54\n\nQuotient = 800000000000\nRemainder = -2f\nA = -6137bae6cf7573afcbb6fd5c066ba37648cba8db0ecafe9dbc66959b19deabf42f3083719a2268b7602bafa2140a1ee8ce7d80000000002f\nB = -c26f75cd9eeae75f976dfab80cd746ec919751b61d95fd3b78cd2b3633bd57e85e6106e33444d16ec0575f4428143dd19cfb\n\nQuotient = 1000000000000\nRemainder = 30\nA = d00fec043edadc093673e5f5abef0c6bacdf1f3faa49a831a645bf80db7539d657f69403b122a5c6f879eb8e63be54d35ed7000000000030\nB = d00fec043edadc093673e5f5abef0c6bacdf1f3faa49a831a645bf80db7539d657f69403b122a5c6f879eb8e63be54d35ed7\n\nQuotient = -2000000000000\nRemainder = 31\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -940693131e2ba7b2af531803794983337dd526f0d84d08d58723edf002a388d55c8502d88c2a2a6e78233a2a1b1c8d339a13\n\nQuotient = -611b743a0e2acb1043bb33de50a59eaa0405b37bf6b622075dd69291fe5b53305dbfcc377d1f3082319c153d0c1ffb3b3346\nRemainder = -16e346b6a4297\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 30c77f3380ccf\n\nQuotient = b9e34073d5e6e5b9e5d2d7250150f8ad86870faeb88d5aed5029fb25c176de216e2388e0f5d33f7c3b56102873eb40b06f2\nRemainder = -16ebc86eb88339\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -197b6f6ad5b75c\n\nQuotient = 141bc8752e846cd63743e6fce4a22efc3eb5f0ce46ba81b8f578c94c516288ec3610fc9923f45d4af2b94c0b0a20b48ed0a\nRemainder = 9bab19f12d81c3\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a67342",
-    "6000000000031\nB = eb90162ecae18b\n\nQuotient = -381bd85c951e1dd775b0d7fab344aadf06b1b592c643b5852fa44aa55159eedf3b3e47fe0d9f399ad92da85ab2bfd18240\nRemainder = 1e4f817a2f52b71\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -546c109fa8a9d7b\n\nQuotient = -5e385a83b56830626cf8306acc232f955178080e86384bbcf92eec3a8961360223c4cfc1d8d118022972e61866cbfc46b\nRemainder = -292e149300fdd1ad\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 3246242094394c8c\n\nQuotient = 9af0246f4b49316df43f61ae3795a764fe9b1d071ce227982ebda7988a7a7a98129c94a76635c6913cb15e4f75ea1608\nRemainder = -dd3b3e32ddc79cb9\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1e928618913898b2f\n\nQuotient = 1fe40099811c648aa4e84e4fbb8cbc19706774a11391fc03a9667d8dc72dd0b26c4a46d0bae56ba90fe4bfac1517d241\nRemainder = 16e021603d30dde2\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 948887c1634f4b08f\n\nQuotient = -3f4fa4c179dab02ad461bbea8f890292c934496db560f72878323a4463d77ae261363f4dc8f53eab145fcc3815d3253\nRemainder = 407ccb4f0b814dc5c5\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -4ad17434071e1ce664\n\nQuotient = -4d17d19f7f6861189a520776339a1e425876808111c303e391118714370111151ef4ad2e6e84250f59b0fe09ab3293\nRemainder = -36f745b0f421d16db7\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 3d71635bcc25183cdde\n\nQuotient = b976d544af44e711351c6618106d3a002c42ebbe22fe939a2457d24e8dcc35c95dde5c7c77af6b4545344a198be82\nRemainder = -107334ab98e5099fec5f\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -198a54e35fa0cfa328a9\n\nQuotient = 1307bb8e89aaff7466bc238d32672fbbde7be19d15423bcfa14f9a23fe85af9739b72807fd4bc420ad0b0fac37a42\nRemainder = 170ebe9b83d4c43b79ab\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = f8e923a8bbc0242eafe3\n\nQuotient = -3925a167c1c4d2fae265f277302b989466e309a7211e0b7173031cbbb91ab7fac8dfe43c9d832764e222e9d8581d\nRemainder = 4d404e93edb435dbd60af\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -52e36cee22274556059ea\n\nQuotient = -4d5a6ef346a872142b999ff9a5429198b3c2a97e968f55aa2c01583efe30e9687c57e2bca2372db4d3d443052b6\nRemainder = -3a2ea5f9d204dc31f21833\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 3d3c79a115d9071b573d2d\n\nQuotient = a49dee54430f1737a04543d5f549efafab25f0f28f5e304f1bbca191f99521c2c4be1b9927bde19e1ec2060bb2\nRemainder = -17d02758f8fcadca911a95f\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1cc65a75211f2826c9d0811\n\nQuotient = 1808ab7c0ccac2ff8f7cb61248bf4624fb60352a356fdd1408904f8c6fb0cc52b7642ec59183bcaf5dd89ca0ac\nRemainder = 5c95323f3b8861261dc31ed\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = c516e6e3fa6e3dc52cf5933\n\nQuotient = -437e04d7076794850aada0cb4ca7a1055df103e74e00766be6a2fdb2631bf294cdbf2695d0a2f8f9eb5587aa5\nRemainder = 1fc63797594c56160536faa9\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -462ee529b488d1db2b6c60e8\n\nQuotient = -5dde5497accc4575a412e7232ce75bdf7905936e09e382d5c9f133faf82a05ad9dcc94ad858aed34cc14c714\nRemainder = -15e79293d5e055f906381a899\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 32765b0a34c88864d39bedaae\n\nQuotient = 11ac52a9287472e1d3b8577b3d50c95076e190714796761322b3ce869d96b44387e190e824849ee345d0a22b\nRemainder = -a158ccc7c055d64e7df3fbcf0\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -10c061a37f6cbd11bf0c327643\n\nQuotient = 1ff5cda1551867577c5ca72c86516a82fb8fc5f59ce967b73c6bcc1b85168389872c9a747ddf044d6dba174\nRemainder = 21e766a0020ba429b330a325d5\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 9435cd2dc2a92c950bb9e69b83\n\nQuotient = -2719c892fa3f4dbc9951b2095056a16159adaf32dff902e20a800a0cc2e858ccae408f2161aae25d3e1f6d\nRemainder = cafbe9caa1f83fd0dd3d5a6881\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -7924e4dcf8f96da61f54bf83870\n\nQuotient = -5080dc99dba295f4a2d9a474c2ddfa3b232a82fe629fe62177514988983eff8195b37d3fee3afa343b497\nRemainder = -94ae72f78982ac1ff83f300cfe8\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 3ad70d4b6b9b5f5b2eb65da67e1f\n\nQuotient = e475eebcfc53d49ffad2e0c2a4ba48fe7ce02c42ff107e01ab3fe5b26eee45c83c4f58c181d77c259155\nRemainder = -c83ac7582a02b47ee734e0f24dc5\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -14bbcff5423a260b21895327b18bc\n\nQuotient = 201308a421b85291d23465d648ad2a8d6f3393efc16fb675a42ea7bbca635ddd8c2449b1b34e5db30a03\nRemainder = 8e07efb8ae4c9df39533042362081\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 93aebb72a81ba68e8881fd1a56a90\n\nQuotient = -2584cc534f88f091fe471c652ac66a695906a7cde1fc1cde9be3ee09026b690c1a899378ff31f6acb90\nRemainder = 794801d9d5770a60e312b99d6b9f91\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -7e408caf387a0ce9bbf4309c80755a\n\nQuotient = -63f7bfc0fe5a5421bc0a19fa6c87713a72eeb2a33e5eadee8c2f32c20d14f403ab8bdc424b9e8e0c68\nRemainder = -24227c242afedee2473c1a66a5cc29\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 2f622c665af7f8126eabfd90df8e9c5\n\nQuotient = e557e6d2180aeeee5d2cef453fbdf38e84cc148f4608ade8836045498be2d318520ffadcea6319432\nRemainder = -dd290149e0e159f9ba6bb9f5a4b003d\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -14a7623d1d9dfc177e913d3119d0d30a\n\nQuotient = 1651d852316d472b41ba0460566e43fabb9257861859ad0fb6ea5a6433a4164299e078f4d50c58afb\nRemainder = fb60aff5fdd2a2b794b0d973ac4d92a\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = d439da27b5e70342aa5cb365ece15665\n\nQuotient = -3ae357761a8ff43d3b1bc53eb336260342a39d22f8fac44eeeac96c2f6de32580dd6a688faa9c515\nRemainder = 4fa6f7ee4faf2f6be99c5ce4b65cd642f\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -50700f9c0da59482165a47a3eda2bf07a\n\nQuotient = -543b4390e4e254226683aa0b83b2ca176ec27a373969fb88f766ac72adc9125ff83b2652e46afd3\nRemainder = -12ff398d9a7d9e97a7f63a0bb293c8fb0\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 383c5a4f1767e83fc382ad4f1c7c2b7ddb\n\nQuotient = ecb72c14c59d49287fb6b2cacdf04619ee617d5f3f0f1b2890fd4e79746a4fbd848613cf5eb437\nRemainder = -1035512a2717a89062d48f1bfd213333ed0\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1402b751a1e5f3fc46e22b43240d6ce9b27\n\nQuotient = 1e800ddc5d5126f322298383f32fd593623eb88a91b2d68c5d9f56e20c16ffe2cefabe873570ab\nRemainder = 72935d534bed5ba557b91ea023601f50b1d\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 9b4df766c608ff3efe5ea1f65cc850fa73c\n\nQuotient = -2c2dc2378abceb983904cdf6728f361d279b4c821710ae785724a7251",
-    "c43fe4f705f023afa7e2\nRemainder = 249f6433af4e8e224eb570fd438197af62f3\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -6b382f812816c77d65c94c0c660b31a69b8f\n\nQuotient = -5f3ced1e42fbd3c6b2c6f1e16953e0c1bb6efb4e49566f974a968f69a1a66a3d7558f5a802a8\nRemainder = -317a7fb1af65982fe4641fbb1e5837e6ea3e1\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 31bc97372d17038fd842b72eaba2abb26df62\n\nQuotient = af3fef8111c449b9e0858e7e53e1d00b764232f7a077d75043249c387ece30af351c8a40335\nRemainder = -a1493bcbf57a8480461d62796aa8f8541ece4\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1b076b2f7b78b4a0f0e24ba3a05d6c697efab9\n\nQuotient = 196734cefb08f09cb32ffefc07da8d9545d3451d5a08736757184bad94c73be71311cf1e01c\nRemainder = 273e33521f4d74840a96b3fffe169f79d32855\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = ba7746f4400f812919a3dc86b00642e1487691\n\nQuotient = -3c5989cf33145057a9c8e904435d12939db519cc6b9ca1c0a11934399cb139a73613950f2f\nRemainder = 456ebf56c636d54e37709b9e799e83b7a08cb93\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -4e7d4f389423f42e980eda55b4a6a45f6f4bdc2\n\nQuotient = -8432cf3338bce1d12586f83025aea50cff3864af3eb2103a36bbb0aba10b0ba4831641633\nRemainder = -4f62c678137df301c4bef216e6aa910104e76ff\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 23d4c57b5a8162aae8d937be12efbcfd7b96ec06\n\nQuotient = 9f94c4399eef16dfc65a1e015e0786c86470299865932c4d564b71c9b1551a9c0308af38\nRemainder = -168b74a6073b4a5b54fa14aacb5c3bb7897ed0fe1\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1daecf01ec633610373b79e04c22cd7499012bc66\n\nQuotient = 1d5b838dce6c0324f157ad125adefde6e1045dce9ff97cf8d1d39b79bce02128e3433ffe\nRemainder = 3aa816216d55fc3c910a030fd10fbda1e12f2ac2d\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = a1598a12a84e9cba42ea0e200e88d4599c9f615fe\n\nQuotient = -3edb182b53890ca8762f3039d2d71a8a27c36cc884d0879e0635e6326af0182bc47cad7\nRemainder = 4610b2b1305220bc0de584dd3f87d90109012a8077\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -4b5c2f1ba3a82047c9de61d47cbf1bec86b6ef90d6\n\nQuotient = -7571ed4c509630886483f6ca0923859e644063acb38cfb338bf3a681fe449501262516\nRemainder = -21c579846594fc3e5efc53ab01576a7b32d69faf41f\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 28550e1f7c6492f4cb682c37b105f92b049c13fc03b\n\nQuotient = 9ed8fb31327a110ef4377258681c5287de8ef9dbe62aa4fe84a7f2a94bb69607cbdb2\nRemainder = -1b7bb759dd0ebc346cbe216e56be8063f063490c17c5\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1dd1e61caed1efc07d21ce05d889de1ad65808cae026\n\nQuotient = 1aa716227d1ca6af68286062b2d6dafd7ade16abbd5d6fa4ada0365832fe18f73bf35\nRemainder = 32e714b0c4ecefb38735cb88cd5e07c21c81be858cae\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = b1b959a7b3262d7f4dff488315903aeaffd982b726d7\n\nQuotient = -2a9979a530046939e0b43a25edfbea6775784eb5cf346a9fc3a2d22e1aad473cdada\nRemainder = 4edeb91a2472e80068b1883cf2cc45d68ff9bbed1756b\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -6f31bbe097587a68fdf01d0bf93830bd03a23920ccc0f\n\nQuotient = -566ff76814e1c7d31ad53bfb9f3c0607ef1f7d1cf9bdee6e1cfb78b3ad7018f8bbd\nRemainder = -1eac095d6d84021c33aa9b219d191bd0637f20b5920eed\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 36ccf5bdece624b4f54c729a8cde13325d8dd764f44894\n\nQuotient = aee4f377611179d8b6315811dd94639aaaee63e99bddcfa8eee297ce1dc04daf8e\nRemainder = -59cb3ba7efa1637c46b21795872e8deaff90f13402cfaf\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1b157ad838684b45065aa77ca3238a4d8c5427f719cdfb7\n\nQuotient = 1c72d32cb83cf4a9043d3bb5002f61b03e29c34e44a9fc5cc4d613726f5e618546\nRemainder = 7312d11fb5828c7f1a0060a5152a7644fc1e6a59de28d03\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = a681444c4d47d829f7b629b561ffaa0c3be1232346c907d\n\nQuotient = -2702afc4095a0396215e3ca36e2a59725f743b30de0dd8d4ec4d943fef6c37162\nRemainder = 223dd3080ede3a64744b14df8742cedd71388b0df99073bd\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -796c9ea38ccf516a2054a1e584c18b64b996c9679960585a\n\nQuotient = -805585c6a7badc933bced6f8373ffdfe9796e963d3fc90e85b1a22c38f842062\nRemainder = -a6ebff3f651644915d5c466cc2915d104f0f85a44e08fd6f\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 24e8fb7a6a3057ddcafff92916c46f7e4038b98c3104ae831\n\nQuotient = 10383ff8feeb180d4fde925b534be97ec3d5f1f1dab5d8cd9ab5d8ea646cfcdf\nRemainder = -a7efdd0401c74a69cf74442fe3da907acf92e8edc51668828\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1240a71ed8d81e86fd9b16e1d64f438b35d6f8eff672494017\n\nQuotient = 195d95a520fd22317492117dc756ff97806c48c1aac67a41ae56fe503a60cec\nRemainder = 8b8692bee56f8a1ada9ffd8b3583eae33a0df9b73a7d8585f1\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = babe02063b61cb90634ac0493174073d2419e00728d46ad2b0\n\nQuotient = -37791adae674b866e4791c107a697363847dee4a58a37806391426ea48b8c9\nRemainder = 33986fc6a5f5c4f4e31458fc7de55e08a4e9320509d90299b93\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -5563bb852e7338c65aa21c516eecf47f498e5788c608ed46cae\n\nQuotient = -68a30494eceff55e4f54a556dd9b30025ccfa22c0952fd746adfd13d31d00\nRemainder = -1b511d0ab81d528d00a1058850bef48df2e9ae9357e779bb9231\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 2d44e919fd27bb3fd2093062d11830c30fa77febafe0a2082cc6\n\nQuotient = bd30999592dbeabb8871b76aa04cc1c6c3794a83f0178c2ad505d8189485\nRemainder = -b0dbce286df5faccf0bdb40ca60f508d436f9410c5e49c3f1360\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1909930e2d16fc877c15895a3ec8b2125858bfa1c5a1b8776bedd\n\nQuotient = 2171694ef4a9d57b83b09357a511d4e11cecbab5e9387928b480d686a0e9\nRemainder = 29abc8898d5ef85f87323c2a6fa36ab6e1bdbcc0ca742b1a2347e\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 8da37bc9c7c9bdc62f49cadcd40e156e776b7f4c8f7ad543f463b\n\nQuotient = -267d470f32911150d9944e684c14e1834734b15475bee968748dd5f6502\nRemainder = 53a2ffef61709bd7143c4c876e021f20a99ba481f2b11abcd45da3\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -7b117ddccee97816c2ca2f1a612cc0d94ac67f5a79ed41744c8fc7\n\nQuotient = -5a21a3bdd3a3d4f1361a978706ba1cec409c296a5b3c369e91fc8317bb\nRemainder = -2cdc818f1e445fb3772d2a56833aefb2f5565a5fca80662e6fc1845\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 348dfba3c793f0018d7d3a70c4060c3148b4a3163ba60af9d6f8b04\n\nQuotient = b301b4050fdf4ede8f9c746b26d968110e1eb119ca42cd9c9bd8d4fab\nRemainder = -17993daf81711fe59204ec82e363d2b91971129af9206ff9506d3cb1\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b11",
-    "85454dcf046745436391a673426000000000031\nB = -1a76328184b9bea8770c91cfccf8ab98e75b2224d666af58022aca80\n\nQuotient = 19c401336dd43c221a61264f8b91791d250e6c99c61850efe6d1e3532\nRemainder = 6c9e547a77c98eaba1b021777dbd98ea88f7fd37c95a2b182f2b9067\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = b7d7b1f95f4fe2f267af88b81af88fbdf603e54ab6de73ccd000c32d\n\nQuotient = -38a77853de88a8db14612884b515e3cd7c673175779d4ab71ba58f83\nRemainder = 51851549cfa00dbfae388cc3b46fd4824268e00e12fba288acceab339\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -539c0171f48e4160e5c308ee9e74f35d8b6d032e946dbcf748b1335a8\n\nQuotient = -79a7eab82e5b65f4f6734e8803fa7c30852ea3ae56e801c5dd11778\nRemainder = -f89592eedcbcc68d5df80663b3cdc638d9d779707d4ae5a552d97d009\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 26efac15401a945ffd37066bc5af23191292765164a0f1e4fd537fd64b\n\nQuotient = d33afb58753a21581c5b2351a74f3d220599ed56ebeacf1d43eeb2\nRemainder = -f699437f44af44b3ddc080f5b74f753d35f70baf3866040ba3c64b30f\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -166cc6a3c60facfa0d8d318f26c6514c7eb9113f6b625c1de804ad379f9\n\nQuotient = 19e55bdaaa5a375c36e6869700f8677db563e5cf985be2a8d1b012\nRemainder = 7bccc3a653f29f3f45b52b8de2449c868c64d976666c01bff2dca03a8d\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = b6eae7a82b5dd1554795573cbf558d7cfed813eec270c326bf290adccc2\n\nQuotient = -297530094c3e4270ab5cf67e60fa5af6a32eb41b18b050fa6d46d\nRemainder = 62d8b502e172da7bce53fbb7c1ae376b6c21b3a3a47523aa0023406e353d\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -7241ae5f1aaee9340d437ad2dab94b70dd29fc6fff7fe31b100aa5001644\n\nQuotient = -640f3c38230962c6d6fca459afe0e46137525e8d62dd9b84da73\nRemainder = -16fcadd5155910764ecf0b4bd0afc3707e2ce49cedcbd5414f1c7d860e95c\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 2f570d2da7a4e62097eb494ca43f7bde33e36525308dc864ffbaeb5d48f97\n\nQuotient = b3895ebba13c8f383ac0482be02e1f5518511420cb4513426bb\nRemainder = -21bc847fdfd48c7a4c36c778681ea20481081cbb7af6b281c8b8ebf2b2c3b\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1a6233954b3480af5f911a6bb8ad33967d5e0446c3e56f521e892c986b6b82\n\nQuotient = 243f3fbefbf842c79c5e96162fc42fe4f177a59d27681c54b3a\nRemainder = bbfaf15a90e744dc4a1caceda3cb339e5491e4507a1118613c5e9739f976b\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 82ae783b8a13e2e65d52dd3a6d6b057163347872f4d72245ff364dbf2421ff\n\nQuotient = -30f7cef2948c9ebed8fa3c5ea9a9bfa96ee4e9729c9b18e9d3\nRemainder = 1feb3fd887629cca60c664e385dddf538d9bf7fff2d34ca9e0e7614946d807f\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -60bba60d69093c0134fcb90aefdb9c190e7bf037ecc13dab3cc7915d7893046\n\nQuotient = -6b6f0183c1f598a68683ba7435c05d700d74681fe472669a1\nRemainder = -1f4d58f81a8c18523918d31791a00ea9aafbbb87792d90a5392273ec4e405da2\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 2c17372a5128d7c403a3b94838072ecf9aff88d164764b12bfbf6261df957e2f\n\nQuotient = c4347fe42b2a7d9d5a650b72724369c5c1f59262a7be3fc2\nRemainder = -1103ec9c4a15373949cae4e34b7b42e242da41edbf5ad8362ce5e5426d3154a1b\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1824671758069b7660bad819f06c86fc76a9344ea38412058380363e5c5b4086b\n\nQuotient = 15e8c8d6847dfe974cefeef5fee93da9e58b74d640c6c413\nRemainder = 61dac240f2b39832903d5ecad9cfda5162bf8ebb0610545f259b75c3dc6ab8771\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = d83386fb9682576cc70cf84520c53169e391b414f5421cddca6e257bd77753c40\n\nQuotient = -3572711bf994e6ad48535cc4d65ac323ef1ccff530b4337\nRemainder = b5899d4cb879e37022c539962959339d055900cca16153da09b54c658753cf50e\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -58a05faf5c61f85ac5a090b6bb045c851ea17332d9bfad4309ce2b7a79ad3cc575\n\nQuotient = -6931ebfc6e34305e5d7cba5284829d088d1ec0abdde508\nRemainder = -1b09eafde481064bab3a5c7fd895edceca40b1e62a9cf953eae1061dfbe00936391\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 2d0769f392ca9ec629ef1bfbdf08cd8cc9219330ffe3c05343df792dd94b1147714\n\nQuotient = 9a4800f0cb2bfbe8d234410deb510103b7da30cbac7d9\nRemainder = -971e4a529e439a1b96b942001631027ff2fbe40b8939e224adb7f2ed30faff64d1c\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1eb3d7971125a036c3a67d9f5ce580a4ef4c469a492be53a55bafd2eafd4032b5b9d\n\nQuotient = 23116704b7a1a86cfa2ee5707ee46268634db5d50dc0f\nRemainder = 467c6b64c8121e4f250492191ea36a27119a0a6d19af519bf7ccdc2436c885c99d85\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 87134e98f73470e23a96c6a9139af3d4d21574de8aa9ea1d720df8940bcbda343694\n\nQuotient = -3b7f72ecf4f55c02366c52f38a827f5773b7cdebb9ba\nRemainder = 194b334b2046a66be3ddd7c6df01c88967fcb11e97b8206d000bcf6043c6e9ccb13f5\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -4f9d0341cadfb1f0bc38184d93503faa196fb8170f8ba2b5d3b512c09d39b7f79a5b6\n\nQuotient = -6db1d69019dd4cb26fd65d5b88a31bb6413b30278a1\nRemainder = -2042a060391e181882dc0c8d91c3b03c1ea35e2eff01babb3ae876ba1e57a505d44856\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 2b2e8f445c0c3aaef0285945e4ca37a700310e003086f34d02c891b94b117f3d3032fb\n\nQuotient = c0e5b9a5853bb21b5e2e37f469764579d5cb2bf984\nRemainder = -154669d4bce7914cdc8d79f2b8d1faa43e8cc3b20fb0767e1c9a47c9e1daed4b665cfdd\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -188e619dbb719381e701363de874fe168529c10f30d3ff184e4356991fdec1649f72235\n\nQuotient = 180054f8c36833d44cab9dd61e6d89d28605c564af\nRemainder = 59192ec5c6fbd9773b8b7dd7d8ab1800dfecc8eb01c29997d15ad75b79575d9e26e1fc9\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = c55b5eb165c63ac2794bfac21980ebacadb93f1e059309fd2b855621572e8d9b3f29018\n\nQuotient = -31412e97045c19ec38951b0e3884c66d1d7479437\nRemainder = 56f1425227bfc6eb1ecda7bfae0e5cb59e92a2cc5306b28465c8739e40893dc5c1e94cbc\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -602b8c25ded1ab3877f58cb048c733649c7dcadf87b2652e35c4e5544d2306107ebff7b3\n\nQuotient = -8da1489ccf7203ecead94c67a5750884122b6e75\nRemainder = -15162026586a1e55dda72785f31c9e6140d166a1fd34c87a7d8c78f8d8f87bbdcf8f75b1e\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 2171ee4a6f7f67d5a33d0a08c367184d70ffe39da28562655e75f6b66c866b1c2ac93e467\n\nQuotient = e635f8bdbf80e99723aa5718d3fade4e573be2c\nRemainder = -ffbd73bfe05f95bc2b135f12682288c620215eac3d6d56503d93a90e06f236e597d1df975\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -149375d478a096e724b84faf795c589ef0d772c4623f5be38da99006cd833dc5b28363faed\n\nQuotient = 20f76f5c6d0c8284764a10f6936c22bfba5f851\nRemainder = 82e3fb3f7252dd87b5370d26d9e8b9e98c7d333701f0ce8a05c337054c7aeb343d04d7e342\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054",
-    "711aab90a05b1185454dcf046745436391a673426000000000031\nB = 8faf8c0a3ef94ab1069394998e5412a7d84f44aff97edf63abc46d96f897172c38faa0b13f\n\nQuotient = -382586dfe93872abbe3a504fc62a8973913f96\nRemainder = 4d407323ef56093eea2f3993334215950f4e1a85ba18cdcd77d819d92b8b292c3ec8edea425\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -545d81ed25602b158bc79aadf98a8f655fc399fb8652ae94333bf54c8c9ffaf8c6b3f2a9d52\n\nQuotient = -7d179efc493eaceaf46572a1f3a62bdfc4a38\nRemainder = -3de3d817a9cf7d529b5229a503e8ebbbd2c53215ac3c584c010947f780198dee16ffbf47791\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 25dddb00f65d6a1ba8caf7815a8063c5da656d775eae9e0108c68ce11dc925183810888dd04c\n\nQuotient = a9f7e5f235bae0e3e29393ac5c99d510b009\nRemainder = -150478b4a0df3eb20dcd1be8da283a00636c021c5c6337e7732aae9c4b49853b95f6d2475ea7\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1bde6cae7f5ced9006c0b1a61fb50982a433e4e2050aa486298f456556d8e909e96933e2ba3ba\n\nQuotient = 16de125df5936181981b4c2d0051a8b4d211\nRemainder = 29ac7c8a11f9beb9ad649257994216146b663bf4f237c561bf315d95778fcdb1010283475ebf1\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = cf24735a60ff5906410be5c4d98e3c9247919b57e404aeabc7eaefbf07bd64762bc61b96c9040\n\nQuotient = -268a52cd10ab4814268f66d9f44f71a98eb\nRemainder = 20293699f12fbfef2e391963866fc082a7884cd13b1c9bd8d5d203558feed2b889720be936451a\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -7ae7d548212830013b7d653072c33f0dd54a6ebd8792bf75809d29a8c798dbc67c3edd99a69b85\n\nQuotient = -8f051067ccb82b6a3dffedd0ff2ee97c46\nRemainder = -100dac0d3bf5aacc5fade281c071eb2399560a65349566567ce1c0c34e43f175a575ed1eeeb3b07\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 211ebb5dc59a051fdfa3b18ac491971e863f2086cdc099672c1215af4ec877e29950efa4f487be7\n\nQuotient = 9b7ee4c499386f922432fcb1a453ee2ec\nRemainder = -f410122a74386d724cdd45b2e548645ac5ee4a44cbfecb82aad34ae470526674da44ebbf557bb75\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1e76750814dec1ecbb1af0fa2281ab3185e94e47fc16a77fed312f23f261ad7709ad7c9f85862c1d\n\nQuotient = 23efb26228d7bcf281cd45f54572e2b3a\nRemainder = 65bf2ef1c2f8e94d98060aa305f85e6cb869c74eabad99877010d30654aa2e578ef6aa3c5f1122e3\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 83cfc25e90a61cf8686e3d5857b2f958674d478622c54cf8427275ca5e9312ed24e44ed4a1b5e413\n\nQuotient = -2cfcae0e922f2d884bfa0a3346dc9812\nRemainder = 14de2725b11a9c6784d9608c52770d29b9fbf824ecd4890bf28f3ec0dc6c52e4df9be540332b8882d\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -694b057ff381badb37c7c15c81e74cbd6774e8d61c9e7d450811c36262ea834fc1287fa59708ee072\n\nQuotient = -4c0238ff3c18d4d58e543f020002802\nRemainder = -2ddef796c50817e82ea6f64a02a8c6b30ab40070ff5401c2d39ca14b9c4d99de33834bfe566a0c2efb\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 3e51c9ab14f522b55e8f9d3ba995c0846a864dfa2d568ea211b0cac1463ce6a1da72d0a15746fdcc9b\n\nQuotient = d41f9102a7785ce64f76b7d7b870b0\nRemainder = -106eaafdd518c658bd371164ee43ccd915a01b513fc7d220900039ff840ba36450e16ce9987e08e7141\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -16549c5d57b531528dd4d781f03cf275b66cb94eba038b782b739c3ab30b8631c8706abac06004a942d\n\nQuotient = 1616b432b3277e774aad92b0cf544c\nRemainder = 2c89373720b834d718ff3df985ae47c3a7cde0e0309f682f5fd48dc97a1ff3d69fa0dcaa1245e956445\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = d6721300e877a8145d05f4f3d8085697c2ca5f34a5357fed0bdb7169f83b6f8d855232eeea594846b79\n\nQuotient = -320fd6a7375a42a3961362ae196d1\nRemainder = 5336711bf81237ea3449f4e9f4e6358dc250f8ebd86082cab92a8079f2c8f835bc783082efb0ed7e3f66\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -5e9e8e1d446fdd314d487cac1226088696e33161d923acb67d3c75e87e428bdbc193e02f53200610fcdb\n\nQuotient = -4bd06daed3f30345d269f51e4381\nRemainder = -1f3513bdefa40662f0f50a04b418a833aa2f85522dc6c399298b1b147662ef2164ddbfb7247ba9511b8ec\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 3e7ab7ffe5f63a6c1e109b95b83af470ff820cdedbb3c90c398ec42e44a45e1ca894870a7fa51f17ad5c5\n\nQuotient = d6fd01a0c5b55fbe36e58bbe77b\nRemainder = -c51af3e8b430870388357cb366ea888bd7b4ccde09ad3a1d2ee1426af060245c6d6b5980ae87fb66c4642\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -16086df3dd5e665f2631a294563c68931faa19ee67d6a2153d262940a648ae71bb3c1745daca5ea977331d\n\nQuotient = 18bd9a8f5678d28cefd955cf99d\nRemainder = e193f2fece67b7abe16373c3f84f18dfedcf654d951bf47585fccfaf67ee04f5037354d057c9f5eaa8eef\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = bf758acacd11f3f3e6665cd740517c9ab2384266f3c7ff9afd0888cdad2f6c9401c24d6c11fc3949aabbaa\n\nQuotient = -371239db55c79521206c9e60c0\nRemainder = 93773085af7582dd298b09d7098835787978d820289ea6850f27d0d77eecce8614785e32b228f46ca4b371\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -56033fd85be464301f10177b58d895fbb6df6154da5c2a2a7cfc3a24d83a96f5295fb17a08148a4e51dde91\n\nQuotient = 696d8e378d12221e2d970c53bf63a20ef381db8566701972c22fe067cdba99c57b68706a5c6e52f21bb3de861e49ed2141b3036f07d1fd0ee\nRemainder = 9f0e50ca76031b\nA = b2668f5fbcf4170820ed3fc9b12a61862acf8e3cb17175482efe23c5cfd3556e77634d407b6d1f98a73437a8d6066319a7a860afcab2338a1b1313037e30f4d9\nB = 1b1313037e30f4d9\n\nQuotient = babe271ea266bc7bc16d193097903037819f82366c7e9ff8f2cb14157b40433c6ee327038d5dcc44140b070d823befaefbee5e13419f6f17\nRemainder = 93d7c547a9ba0a4a\nA = 74b1a591f449377836f378e05d2902b29964df59c6926e5a9182cc09ce3111783cb7021a185340b4880d56635de268d6f3855c4d9997373b9ff8df899ee3b3f1\nB = 9ff8df899ee3b3f1\n\nQuotient = 890139fef28aa3b77814e1122b9c7f26e746ee3c507e6082b508fcbe380de83b06a01f735239c6847c30eae44749fc8c5e3bd97eb40ba297\nRemainder = 6c97aace900389d0\nA = 7e89adea82b4cb6feb41297b6dc8d948e72c3d5554a987900e7fae48cfb38fb5282b13d9a1f5793cf7cbf1ef551865041c3ffe0e287714a6ec7123556af55a48\nB = ec7123556af55a48\n\nQuotient = 1fdeead441e2d7a6ce3cce2389b2a22248ddca7970ae3f7e7d8453052fd08534ff7c46f6a4537fb6f28df6c5fc8a7d384336e679b74205315\nRemainder = 2903c7cc2651bfa8\nA = 9ca66de3d83f0a747fe986464522bde5e42aeac20e8ace1ea13fa6bc9514c58517479a4281d4128c6d775489b85dfd114ad184613f308f6c4ea484a22ab0ad1e\nB = 4ea484a22ab0ad1e\n\nQuotient = 12f16c8f9f898a08853982e2ac5a906d784c5ab8d74007ba3ab311e861d7c1ac115efe694cab7583f75a4a59ceff2887dab53b2f1022aa452\nRemainder = 4bdaf1f352e87aa5\nA = 6e6a97b358b591b78db43772378dc084a11836ddc9dd4607f263ce620714e8fdf6bf67387c163b6f2999f84270802b4bd5c0f0377e949fbd5d42fe145e66ffeb\nB = 5d42fe145e66ffeb\n\nQuotient = 14e0c06c8cff1f9f5dd8afb6fa6c340f0953a18ba7d2b26b22d8e7f946ef20fd5ac277ceb59cbd4ce3e8213803c3b5b0452ed449e22bf2c29\nRemainder = 55422f1caf4a9a00\nA = bc9c054ff568af73e301e0751bc1ee055e82826cdc53449f2d9f45feda2ba227bedd6df9b74fb58a85917d60b087bef04a156a571716e9bc908ae83784ee35c0\nB = 908ae83784ee35c0\n\nQuotient = a457ea94da3237c0dd15ee30e9c13e7b4ca1dc90fcd67951b873787206babaed837a3eb17e298d74cae92d1059636f9aefe11aef9ffa31053\nRemainder = 124768541b600598\nA = ea6dc82b1906c277526ed867fe8b0fbe32feecfb935dbab860aef59a7d72799fd4e952e70b4c9304c7b2a06af8badcd6cfa12d0b6c9db38d16d2c4a24099ca14\nB = 16d2c4a24099ca14\n\nQuotient = da0a37eece8972a0e2e8817c54e",
-    "67c4d9f92373340488539d5051984bce0ae3300ef6ca9d0902daa4d485dec3b4db6c8b1ffd2c5d08b18ae\nRemainder = 1ba15c46023500b9\nA = 36ca8763e20e6ebf07a55cdfdd83892bef0bab68ac092093bfdac1a49c1da015541196a24249bb2262e70f7ed53e0fbae61f02ebac4b61f740548136ce50f243\nB = 40548136ce50f243\n\nQuotient = 3d8c433daedfbf681b528f88d610204d33bbe74d0b13978c34a617ae94177e07a757519b5a8f1a93a73d0751c7b5b72b4bdf475a9708fecac\nRemainder = 4cdfd72349c6110\nA = e0dd7e73b2a64dc017da65992176e2535c43b6fc14f2f7b0a7d894d768bbc77507eac0112b2dc3ca83d70989a1b949ccf374be6a012d80a23a74bba39671fcd0\nB = 3a74bba39671fcd0\n\nQuotient = 39d084b444e39c32f2883e9968301151802da15141f65893f37b8b834eb01c074aa1e1a978c5c99732c87ae106bf8db09e1728c8bf2aae88\nRemainder = 2950443357cd7477\nA = 16df31dc290559c3b6a3d192cf15d825cfe79f8dbd5c9848eac7fa90eea5d87f8b430cccf9baab3e8e4dc33467a4234d8551ff25e33af175654686ff1368e96f\nB = 654686ff1368e96f\n\nQuotient = bbead8f70c8e61114f22d36e97861f16037efabe1347613e78c51d7f539065421a66c907faddaed13ad2a0f0b00f8fd594e917799cd937e5\nRemainder = 3013136f5f728b68\nA = ba5e688ab4f8ab5c25592bc4334b6dc2b7a06d491d0f919b716bf1cf109b62a30d9dd59dd4bdf870dd2687894edab303277a5f3e3a537cc8fde3ee3bb61767d6\nB = fde3ee3bb61767d6\n\nQuotient = 42aefe467ff2a5614efef1edce25a1acba9c476b3abbcd680140a3aecf8f51c1ebaab8912de217451bfaca2842c0bae717b8a030b6318c0\nRemainder = 1f130dd2ead0d35e\nA = 17bd50b5322c51ac883852ad2a4446c039dbc210ca3aa0313065fc88cce6819b324e93b036bd0c71be58586cd2b243d01a4a918c10ea0cc5b22f9d795df09de\nB = 5b22f9d795df09de\n\nQuotient = 13de73dcd72a3638fe2a907fd7f6574bbb228698fa60e4ecffb082911c5f09c74bb4f50564d3d4035d07eedea38b634a3e3acc26c8e9aeff8\nRemainder = acb8702f0113e0c4\nA = e0327b2e59236a3f91ccf960490cc69b2afc854de9299ad2edff9618f9fe24251886afc65f5c581a9bc86013f356d599e98b8b10f5236a51b48a6b29025983a4\nB = b48a6b29025983a4\n\nQuotient = 27d11481f00519b786eaee96220afd45bc51700f7366fb5e7da35bbc84891aac3d9d2b709dddae371a6b78439fef810c68eef586e1d68350d\nRemainder = 3d1890c5e1555d74\nA = f3504d5d96c9e27a1527725ced337f1cd0a183531642051e166507432c01e8d44c4e8918701c2a05eb8a9d7e26bf04993f9adeef2826ae4e61c602477f849121\nB = 61c602477f849121\n\nQuotient = 10bdeac209c67b023044186704735c7291423054bcddc24b731ad601b49372f4d5ce6e9d85002f8dddf0411efce943f81a5e42cee2d0c9fe5\nRemainder = a93a0c5bd51004e4\nA = fa29e37b0d0410d19fd180149b14f94ec2edccd347da65f6832850aa06a61b7b78c96faf64dcb347893c93c560b8043466419864a382c6f2ef1412873b2d8cbf\nB = ef1412873b2d8cbf\n\nQuotient = 1c9b6cffe44241292320c0660b89f2f77aaadc8d36e33f5ac3da0f12b3c114a156870a92079f7192d237f8bf49aeee6282531c929cc56d75\nRemainder = 1ce3e5eb13ac7958\nA = 144325a641463ed6bddfcbd73e50620a44c606d71fac38efb1c9d2747b4903f7b51fdedacfb66db022aea09b43c7c2ad7b851035165ebe59b552d4f7eee617b2\nB = b552d4f7eee617b2\n\nQuotient = 1b4ad18dc0e634053beb3cf840b53e35117ea06309ea8ca22e37123fd7e1d391c96c792e5125e322c27daa73301024080d73ba3491484b659\nRemainder = 3286bdce6dc3a828\nA = e3a2b90d3ef446f6bde30d3e726cf3e78212324054b40deb0b18fe00645568fb0a6234b6bded6240977373731bb30d1349e25cefd54b7a9985735e9b78002691\nB = 85735e9b78002691\n\nQuotient = 28f5e8da6733240cc2f18e3cf4d42a50d92816062af33a9e1871fa89bdb39a0d905c49faf51cc1c1378741bea34d25ac2c8e522881a6f6087\nRemainder = 135784870eb40c68\nA = 593206f9367b72f9cc59b3e37d2eb23b2061422859162ee53656899c2471017474f500c6e23efe1f6b1e57852cd4229329dc182ba01a257122d76a26aaf9b844\nB = 22d76a26aaf9b844\n\nQuotient = 1ab276448d16c533b6e90b5b5ca266e13ec27b5a58c80b7657df963ec2d1fe4eb1c1d24873eff6408bcb3d0cf97c31e85240eedf0efcc1e5a\nRemainder = 27b105741264f875\nA = d84fde3d851b52ed3b2a1268e9b765ec6c09c5768bba709b3b799802fadac30a6c3184185e6d57249b1c34619f3c9d2b90bc0c348b22537281a39fcadf738083\nB = 81a39fcadf738083\n\nQuotient = 84a87678485b3e60ee1cae3701ebdf0a29ee44115a492c34a0c8e84090e14070eb2ad0abfe2c339f26b5099327515104fe3d1c5546feea98ed\nRemainder = 95f7434941f9d8\nA = f79a0643bcd9c28cc22cc7b4178b3340e4685dd2672792516d6fc08567d2de2d3e25d43f100a58826edb146ac94acac4213bb09bdf8a258001ddd0ab110b89fe\nB = 1ddd0ab110b89fe\n\nQuotient = 516a2ac26e5b3afa502c7f3c6f15376f7a380e5842c229443343b5b74dc3de84db3ae99a0c57043e32a504ded19943c0310cababb3e92cf8\nRemainder = 327cf78eed336523\nA = 17c0d5814e1020d5d69674bdf6b9df193a16c0c8567a589d014e8eb7f6c9c36560791f7acbbbacee7c456eb51a4cdd7ca88011e9d8d9f2d64ab08ad74f7be5cb\nB = 4ab08ad74f7be5cb\n\nQuotient = f0da0beebcfaa716f494cf3fc81fe65117c90adde3b3942e8e66986fe8050fd5c9ebe1c88c5db04cea4c4c14779555d70cafb53870671f95\nRemainder = 3b2f844440d7be00\nA = ebba8c393c2a22b094d824ed95b4acf6875719fc165f73ee6d359e1134949169fdacbb42d5deb8cea96e11e3aac985635b5bcc6c02a6778cfa8e03d9ce6fc680\nB = fa8e03d9ce6fc680\n\nQuotient = 56527f07593774f0fa642241400985d0bb9b41d3dc9e025ca069130d93afc972d75e3fe0f798e127c3e1b4e925000459a3a5a83b15186e516\nRemainder = b620b7a3b752b78\nA = 5d6cad9e26267abb480b2b9ac5ea323bc4c3c53e0de8ce40c89c85accf0499aea5b11703a04296519047585ff12f8795f98da0546c20016a115100eddabfb468\nB = 115100eddabfb468\n\nQuotient = 294dca3b56ce9529aed2c132a9bd6c0c61de7a58ac50582f396b4fadcf7873b502bb869f801a9ab1f12384631cefee72b3e6050a7f69eba4\nRemainder = 53a0fcf5486c7a6f\nA = 24aa73803f270185d23310df2cf3ef67b18d7800bc41aad2ca13f372a27ef0a9217194f3f512e79f545a903895def195a5eb9a1a1b6b3f4de340e9da9b305d3b\nB = e340e9da9b305d3b\n\nQuotient = 16bf4dab1c29bd284c9b6649de65a4ee58f21d6a8b51627ca133fa817872b1a4a9956662db0aead5898ed0eda08511be7c47449638f2fab95d\nRemainder = e7751deb047d98\nA = 77b04d93272491322ed2fe651044e28cadb2ae7825f02b55aeb0f73b8b8a8b336802416fe08c718ab681581ac04d87116323f61f50bfd2180542fcd4a46dcff6\nB = 542fcd4a46dcff6\n\nQuotient = 388ae1c243bc9111e663c0c80495c36e8767bafe188b532b7ac84b5160d902af1b638aec6e4c66955d16bd8ce94ce6027a7bf95910f705ad0\nRemainder = 7c667ea307017c2\nA = 52f357e9a57722a867d8199242e100f06e8df810ee913d6992bfd9dc03ed78bcf44d692aaa7be806df0c9e0802851d7ae8405f76114e6322177907198f85cb62\nB = 177907198f85cb62\n\nQuotient = 33dc2fcceef7dce92e3a9df58566c6e28d03b58ff6ecbbb31e43936cda6380a56788285d37b5e8f11487afd78c39cb2150cc98d9d78a0c6cb\nRemainder = 429a380c9f8eeeba\nA = d99cf9a0bfc347c9631ae8c69defe1f1509c3ecaeeee5dbc61317bb73fa5cc6e704f64c865cf4d898f8a2f63214dbd511f61aa6e09856222432376698f8d2f67\nB = 432376698f8d2f67\n\nQuotient = 18ecac9e5539a014cffd8310ceb1170577cb23aa9cb3c523d57ad83069d1609ff743cd3c275b67097a038b85afcd7105ad21672f9ecbbc7df\nRemainder = 37924fea665f5c92\nA = f87aa8b6e62b09291e0e9b832ad71d8f85d60501a8d89d2638dccd4022e89bc4932c186a198557282527dfa86dfacc2f90fe0656695b61429f8220509f5106b9\nB = 9f8220509f5106b9\n\nQuotient = 37c0649a53c8cab91a7458702870bf64cb1de9fc1c6b9a3b92444119d368501b62d3a5138af72bdb7752eab8af6bf4e3bdb9e3beb1805b88\nRemainder = de179463e3e91ad\nA = 995c04c1f24c4efe88393bab7a7545e39193662d5db7c8e557d6c554ed4367f5af82c463d0ba6bc3148620481140add5677937989e03fb52c0323980d8841d5\nB = 2c0323980d8841d5\n\nQuotient = a6d193cfe7d8983768ff29908ee6e07fee99927a4bc4ef41d01f63f3b4a2e7029630b7d925d0979458cdaa903771286af672253cd99593b3\nRemainder = 6bf69921db298b3e\nA = 55c856daa8110599cc4fde0a44acbd69a68eb177e0438f7d843ba0fb74caab2a7e0c8a6f176f5555779e65c555e9157a16a1497edf36ccb583a458f0372a57c9\nB = 83a458f0372a57c9\n\nQuotient = 63f379bef9866b59f8bfd6bb0120a75dc03506b0034e7440764afc8ec14d8d735aa6f03a568ea98d0a74ab9bbe9c6e11b288467e5f79a2539\nRemainder = 11c077beb8667d88\nA = ff1fc3ea60fb37ff23e2f2f4e207a86e055cca41eebcc5bd6376904b51fb3d233cb04666fdc92be33239b5ee552870e45717890e35fdbe3728d6ff55d5662419\nB = 28d6ff55d5662419\n\nQuotient = 285ba8cdfbf00b112e496ce65cdba2271c82a273b3d30bed82ef2d360790c5deb97f3311bd5eb9876a61e33b3a37782d00c2d5ffbeec752ca\nRemainder = 1672a8aa119c3a1d\nA = d614352268930d301aa4046cd38e2eda4dcfcc52eac984943f2c863de5c4f8a44473a8ecebf12cb8f4da4722d305e5c9c3eddc0109d416e854df334dbfcfdd4b\nB = 54df334dbfcfdd4b\n\nQuotient = 358178128648fa9ea28dcfe68b4cecc7071e129e3ce4d113f5d1e387f7e5a412e9d2dfe5ff16d9987a544004d213ade9c134cc240eeb6871\nRemainder = 44c3fdb374bc0c30\nA = 18b973dd011969e29a1f4a5b8f118313f715c2e31dfebd9fe0957cf23cf36eded89c38637a8d3512bb23324ff2a3627d5b942300200c823d764b7a6c12d1c91b\nB = 764b7a6c12d1c91b\n\nQuotient = 19ea7212f6604d423b308fe3f2f4986f31aea9d6a117a3e207e38ce5bbd8d7a866285ac60433630de547fc84e364c451457fbf864a82c6613\nRemainder = 2718de2dd0796f08\nA = 83577f755a448d5586e19486b04de7836818223ea920465c4eee979a9ce5",
-    "696ad8e2fd5253b5d5dcfdf355465e8c0819658ccc5580fd29b351169b54c62b779c\nB = 51169b54c62b779c\n\nQuotient = 13e0c5b9905770b60a6f978d1c983cbc84dccfaed0f4222f534df80c7d3d129f5e8f74f19581332a7f6d383915424c71db4ca19bde2591fcd\nRemainder = abf5f6c8ab6ed4f4\nA = e2bf43c91cdbb244790eb165cc13feafea36f5187cc9bf8aa8cf202042efd5441e3822a1164992da5be750aaac0bb11f09375bdfbd4a39e3b682c7ee6ab5f5f1\nB = b682c7ee6ab5f5f1\n\nQuotient = 3919f31521e87f90df3a4463d0c83fa31e3f569449009d307962d26f07d854e8d3f0badbf55311c206bf34e6227949327a93b1a5ada7a930\nRemainder = 6c3802d44dd4668f\nA = 2546880cc6f97fb379afbc4a2664115ba7909414f35a5bf88be2ed5187bd1a24afaf82eeceb0b438d4999ebf9b7ec752236669425bd3cce6a71d9ad67ff2ff5f\nB = a71d9ad67ff2ff5f\n\nQuotient = 121d5ad4115c2768b962e51d09f426d61624e0f203ac6c923289b4e7964e165b34f3dc1ff938a7cf37478d407de251c64db71d3ee629c1035\nRemainder = 660a35e1c1245910\nA = a36d3250c123697adbbbdf489e6cb40be57febaff654ca951c9fa0b396b1714c55ed6e05e468153ac443dabca29de9b43cc0cc4e62cdf24690593662c86fb5ac\nB = 90593662c86fb5ac\n\nQuotient = ad81debaa02f6e60da58b46e76ce041fc4da64138634ea7b3c165b8fbda027eb64b6b5339e70babbb83430d60383c2cfe22029e617fd03a7\nRemainder = 2e4aeafa2ad76832\nA = 8992cd131757ba5cbe54aa58be115723ea3438ddc782a4d1996980b7b312fa76e4483584df744b10340e5fc9e468690cef538920a732a8f0cafb4e30846cad1d\nB = cafb4e30846cad1d\n\nQuotient = 67a71b9ebaec91121a8cf6bc2932b6be01af7954eca69c5202d771c2c2d13683cdf90ec942a3445771ccfe484f947f078de825ea88b3c05a\nRemainder = 8395953f744cfb31\nA = 4f8ada84096198175174896167405b85cbc03fe0642f6b263a70f9a22f19ad6c9aef38da8ac036d409e6fd925023c95312cebe04eb653e0ec473dc8dfed98967\nB = c473dc8dfed98967\n\nQuotient = 9416326e2347a541b777a0fa1b0c35d8fe76c940d24c6f6806d6ae8ac1e280c16e480786478bda3f780ee92f3f3c361574efc2ed5ca98e26\nRemainder = b8ff45f31bdb58d8\nA = 902f5e48b96b9b1fd16c3b21292ed495987ddac4e1d92b2ab10378f2966c4399d6a41eef622a4991ccd1f647531dcd145de4ac99b3036779f9414ed2f4ba7e08\nB = f9414ed2f4ba7e08\n\nQuotient = 403c651b4e571e8301c4158fc185396554bf61d900708d2af5c2bdf495b3cb539b0b9b5acd0d71654b3aa68024961d5a7bc9e2788e6c822b6\nRemainder = 7856ec047cec8dc\nA = bdd6d846983fbf140173a26d2b709b9f31b4fee1eac9d25fdf0ef3523be0e6afb372acab470cfe1806b36d84017ec99302eb9eb5eb2862222f4916d8b6201d14\nB = 2f4916d8b6201d14\n\nQuotient = 1b6d967173f9777cb6194c8f69289b91da731456fe5a1515a49e4463cd906c84f97381cabdf9f358d97fad5d3cb140e3a3de397e7f9f683157\nRemainder = 83649246ade8bb4\nA = e3da80658acd53ada7c2dc57178e697f2907c5b0c64f4a87a794ca7521105a0568a32874207646df3768ee60964b7d1d2e29ea6bf7fbaa7e084eabd4ea553a72\nB = 84eabd4ea553a72\n\nQuotient = 27b8f1e49e404455cc68217a20766590e749507976a3a6de25a7cf2c32593aaabb04d84deba1ec6bbe048a2959ffd747243c396dc53c9c811\nRemainder = 3daa032278ce53d0\nA = ff3ead7c7b27f607d16f1ef4ffa91b6cc28301b9256cfcb0c22b6818371ce648ae8812dc50a86e4bdc0d0b1e5b0d55c6ba07b240886a6d5766cfb3ed0937a543\nB = 66cfb3ed0937a543\n\nQuotient = bf987f58700508356fb6274f64a9f78d455e4c436fc6fcc980ec0800287ab3789b91c29a8a72b16645ecfeec926b6f8242f3c7dc3adb40cd\nRemainder = c007da44faa80584\nA = 971aa67c9af10f70977f600e10f9278b8e66d2471956da38e5f4b3fedce9a5fc7ff42b800bb4a78314c70bb59394d0880383f5182b6c1960c9e5b47ef8e63be5\nB = c9e5b47ef8e63be5\n\nQuotient = 7332104442474715d7c4cdac15fc1731240f8b4dd0e6ff3284a15a62a8f9a071dedb87f2220efcc5839cb7e6933a8f65d767819db26e134dd\nRemainder = ef65a7789f54174\nA = bcea2ae4b1edfebf905a5820f0481b6c58d76a69df9dbe84764add3f49496a5d7005d645eaee3754e0ed105c13a114e6a0eae5cc4efab6aa1a3d3a0050fa86f5\nB = 1a3d3a0050fa86f5\n\nQuotient = 3f6182804a7ff12fe7ed3c8521b55564559b1a47a78e1fd56597b9470e7e0f6e7e48c58bc8841c9d118718ccd5e0c0bf9a08d8e244ae60da5\nRemainder = 398e30aff5bd284\nA = 2b877181a960c5e29ab1b2672ee22539256a82369e8f6cb5bcfb69e5e4a41f782e89b58fc0ef6ca336469ff929729f8492b44f12199f0e1c0afd12b2c999e787\nB = afd12b2c999e787\n\nQuotient = 1a80a681d2c42edbcbde552323dac3a1c03b43251a99b5549da6cb39ec6947daa0d574f0df68512984fa8e269b0b27a5576b3aaccb76ebc23\nRemainder = 378e44fdc7a5ec4c\nA = d37e62f44de27a1418f348139eac5ab9fcc1ada21ea6d7695273daf638b4d7eee6745f54b99a9678cf742d304736ee356f66d16d874f8cc67fae9be5dfd41a3a\nB = 7fae9be5dfd41a3a\n\nQuotient = ee982a63816d56758c29d284c19b9b984908cf0a9ae3f1f926e162a2cae4f88703aa477c5c14042247635c103494d11593c2c3839baf4d93\nRemainder = 39afe3275c01aae6\nA = 9a0b0476cd33861d2fc3137df292728e1f636f6fcba5105f384533723231a3104e7c77df46f7f34a4bdc63d5c67b418cafcf106b26ad020ea547d34edac1d3a5\nB = a547d34edac1d3a5\n\nQuotient = fb3f4a39a661e5c31228a6b7b4c27e6e52d1954e8ce262b98b61650efffd762cf2a1aec228bec5d5787683cad6b2e6e49a0de91c15c81874\nRemainder = 63e5ed36ff73a42\nA = 4453712f56467328401a69d4d749a0771732734a760a74094e50a62a030cb604e735bfe0bf0641754edff94ac0e0549e8c10941255f0f21f459e52a6cfe4d9ca\nB = 459e52a6cfe4d9ca\n\nQuotient = 7af60a7c0f995178be76c070cf49eee311e6d1e3afaf50c8c93ff200c1b3fe742b23259b4fc0b9ed0947be4fc9a6c212d86de9a0f7dbb5279\nRemainder = 19657d8ce516a138\nA = c9c92a31ad0f3cfb56a294c42a26eaecb77edf33ed40a7e6797927a0c996a7c0a701b484741163df388bb082e3daebf4e1b7a99002632d6f1a41c1d517238557\nB = 1a41c1d517238557\n\nQuotient = c890c55a8e2a3105b9bf9344a57a9b9fab5fa1fd57083d52431b695553bfbe7a44a9b6cd1f83958224f351f8511b14215d1648e88e938573\nRemainder = 1bab5b03c372daee\nA = 88341550e470016c7ab600b9f6cb410071a77f907a58cb6da4ce3e955d1e859534c2c1098fcfd91b9fa66926e51896733c36a824c3a20844add94e27f30ca651\nB = add94e27f30ca651\n\nQuotient = 34c240c42da400317f66f5151630493a2f200ee418d5ca3300cab10dfb429c2acd7280bf066fe19115f86db83d8f5b93cda714533b16abfdc\nRemainder = 18cd326996ccebc1\nA = 7e96d7b90ff09b114dd4393e9bdfb13d8ff517681126c566e18dd6369d87d248734d94bd02a1f19cca90be7642822b636369c51dee441a9d2663ec896e1d6c6d\nB = 2663ec896e1d6c6d\n\nQuotient = 10d18159e75efa8204e325e6be830b4ee8d2c07419e8276edeac6cc286488fc0c888300db3ebb5f935aa82654d3b932540f0093d1880e1d6d\nRemainder = fe9b6b8ba7c30f8\nA = 731aa6e2fb2ad1e1f80d7668c7b0642203af24af382abd207a5ffb588209e8b5caf953e9a96b478f39ec03a397d1433998e3c95e382d93376d80cf0c957788e6\nB = 6d80cf0c957788e6\n\nQuotient = 450d1f4a105ff8d1a3efbb12165ca98c67ae70404472e4862db479e03313b08783ecc42104780c9d57df0ddf19c5b4547ee9ba52ea82dd0c7\nRemainder = 169e15b4d5aa180a\nA = 902bcb1904b80183656dcbd51879e2982e2b46a547c9ae3119ffc12c6a003e4321b519289b7f22fad19d16480182d1d797c3045b2d29dcc12167f9ce5e233d89\nB = 2167f9ce5e233d89\n\nQuotient = a426f71cb3d75365cd076a6c35c10765bbc3f4bd317fb83a70083b0f7dc43a4e0b95508e60dc1dedb780e9b485f4f7a8870960de669b73af2\nRemainder = da381ae5c97a506\nA = bd59dcdefcbaecd9292c4c3685fb87d3a94c0f0ed01e43e63e1f36fb65d6c5eab3b584f3d1f76d31458c9f6b4c69869d96e943c61df102771274c5b4d821469a\nB = 1274c5b4d821469a\n\nQuotient = 26ccd4b7be090af22221729b0ca51a5e66435c2d33f8d88f94405f6c0123ccbbbbc8080cd8448a977946019ccbf5d267ac3f151ebe686720\nRemainder = c41f9e7bf20b376c\nA = 212dbeff03f14b5825f0d7cf8a7501db21b60581a01a26d522ee44e7fe69545cfcaaac64dbc76c7e3027ac39ddc2d80af6f3fca1824c6ff6dae90967d9ab48ec\nB = dae90967d9ab48ec\n\nQuotient = 801df28f4fd987b4e980760f4f2625276a2a7191d453095c82aa98a2253324ad2873abae70cd98c28ef3ce102fdd53469b9f01889f3ba8b0\nRemainder = 8e435da582e59809\nA = 48341b28138dd04807e522e341f74ac46b0449fa45f96d7fc586997c056a21eb3c399752a6a6c023509f042cf9e879f397a34af9aa2ec2e8904674f2ea3ff739\nB = 904674f2ea3ff739\n\nQuotient = d3857b72b70adff9b5dec3cbc63de7c90ccd7aab6595339b2de39bd6b9789045141d224aa4e6bf9a06e017aa3edd00e716a771b3f5b97771\nRemainder = 14135c686d2e9f70\nA = c1cea45dd46409d5e24fb7ed7d849dbb079247af2d312e01083754ed07f65f090e4dd50d23a973488702ef00936c5d78af603ec0fdf03dceea8f939c922b1e7f\nB = ea8f939c922b1e7f\n\nQuotient = abe20c90896e261e7d31bf40e7f3136d36b0b78006d12225a4dbef6aaf2062b609379eefe7e5af5bcec17126286f196f1330da8477096763\nRemainder = 230307c44cd55896\nA = 19a637e4f3051be0f7c4d35513bca4a91ca9b8082fe3c73899b70b6805a7aa0458512495cb6ee1ade55ecd5851be1dba96d65202f06bc7122633a0d905017545\nB = 2633a0d905017545\n\nQuotient = 5ed3765c4a777a903e182f7c9ce39d19c01460f389b904c3ce1d3525edf25ffe7dc0f4d9e24f0bc8b7e01bef19c83e74f17884bd7bfabb2c\nRemainder = 40f5346f8775e20\nA = 546578393e914be30581e24508a33f6560a5805dfb1c675d1ff1d6f5eaa7ee638b9e0265f543413e04e3f1f3b0895dec271c9897a48d9ce9e3d7df32c15b75a0\nB = e3d7df32c15b75a0\n\nQuotient = ed73a67932746985465fb0606fb0e81595514f1647c911c303d4d31eb0306e3b2aece07320f6fe",
-    "a57a7071d73150591ab2a82a7d53968a81\nRemainder = 2e495a881876da00\nA = 8976445bc318921f7e12c8d4e8e50596849a1503b5efb65e939c291de136597c05a1fd16137f0bbbd7197df943cd612118d1e55a50ee097c94331c1cfb1e941c\nB = 94331c1cfb1e941c\n\nQuotient = 5dce24b7a16d847b0c43cf365ea20bee9679fa0e8732813e827cf6ef3c9bdb7fd8846b5689ce8b80a7dc0dd05721cb06d2700aeeb7ff04d6\nRemainder = d8ead1ae3126aded\nA = 59b99e5d028e6771d27004bc19830a5fcb347f7ae04c0ba7c49130bfb198c5b16821e425c979e6d2dddc14889ae58475bb52c6cdefecf2a8f4dd6e462bbc8f47\nB = f4dd6e462bbc8f47\n\nQuotient = 170e10b399a4c5fe354b536fe59d53602102f215d5107493680ab6e181f67d75ffd45bf49ffb23cf9269b856156b5ac6b1c5def4ab1abb18a\nRemainder = 57131776937c5df9\nA = aeb35966e2a616762768b7f63ce3aee5e81561080617bbabd7846b3ca03fafaaef83dd05b8d16cef40db0a56f3b0ef6eca5e236681cb57c8793dc0907d9aa30f\nB = 793dc0907d9aa30f\n\nQuotient = 1acdb88f047f9bf679c50ed67ba01dd24dca92103f8ea2677215b6142083b64f9fd2a365499dc8f2bc61e29fa176f7d76b55557fa58e34f9\nRemainder = 5065b726dc6b3758\nA = 15a6292c9fb66c6770a8dbc6fd431d2a4b57338581f78d0860fda90182cca563eb2272a79fb4f5a6fc72c90dc23e8a95713b65988b5b3f9bcec4f0466c1c47cb\nB = cec4f0466c1c47cb\n\nQuotient = add8127c0a27c961203ea0351aed5b3c75aa816e9c2684574e55f55c7140adcbf69d2cff843e5f53c157bd60b43c45c8b6658de72062fbba\nRemainder = 67f48d3584cf4fe5\nA = 4e8938c8cc46d34e3369c5d8536b18c963dbde56020678f77cebac5f8777e0afc62ca2ba4f533cf6cf7561bdce77b6f495bc1b05f1416d1173a6a288012c7c73\nB = 73a6a288012c7c73\n\nQuotient = 688ddf883a0bcc1ff9bd582119c2fea7c059e19aded8c048390a1d8fd7d769666987418bbe0d4cf4b67009a342958928769375c1c0d558acf\nRemainder = a5356d04b64ee12\nA = e0c9e32056977aeca72e229d83f0d320fbaf5cd8bf3e033289f46101c75ef59a854982f33bcbcfd200034e8ff439d669a03fa404e7dbfea822664967d67dd5f1\nB = 22664967d67dd5f1\n\nQuotient = 39d4d94587fd1445f31457c275fd6294fcb69ba155e7da3e6cfef38ed1272d6c95755bca49007ca62cc101b038d264876f18594b8fd4c329\nRemainder = a34980d5046e2ed0\nA = 2efcb12fb55c923f5c6ca7ae076765059e15d9e75240a6e5fc3db92de184143fab1934c7450c3a380a9851846c9f43d67bc199a314e82e72cffee795d695f82e\nB = cffee795d695f82e\n\nQuotient = 145ea82eff186b7db4b11fa1514674fb9d41c698efb33227eb1abbc4eb78bdb2a280c0c4c47adaf4e010a4336cbb5650becd1ef544e223e53\nRemainder = 36052bba2867f5f4\nA = f6a6c7e33fd4c664652d696c495df387b85b132cfdfe34bbd35759477b4a3c052f610df57e49e85720489e4bb8dc923696400a4a28dd000cc1bd491446a50b96\nB = c1bd491446a50b96\n\nQuotient = 35d0c9d870348b113868282aaba22b21ec87cf421519a23b288b150604729356f924090ba038d7400c0ccd4932836c65902b4d3c46a202a0\nRemainder = dc8c7d087bf24b0\nA = 22228c8a5966ebdec64007704a373b0596ae702d62e29e468653b21a890ace2f02c27f26b043f48495687ce8c2ca8092ead21aa250ce0f6ca26129615a2432b0\nB = a26129615a2432b0\n\nQuotient = 52fc995a486c4bfd17ed9722948e9ede1c4ac2fe80e6bd7482fc47944c4337a185a506a9ca473d49073e1b813ad742f19b13d57914888d5f\nRemainder = 75c703f654ad630a\nA = 3473041ae301dd2806da30dcf06b9c09600086d6873cf3ee9d5a0be638849afb56bce2664f797de4123f6f8fe3e12acd32e33a285bb7f493a1cc13a7108327f5\nB = a1cc13a7108327f5\n\nQuotient = 1744946730b2789977620f2e7439641125dd338d1b31fc50813b34dea70b83d209330bd17fd527db9a402ad9752c26b8823082ec9971f4ae65\nRemainder = 453a3d59303ec3c\nA = c0f592d83649bcafb7e2de1a8a71fa863c1f51b595bfa638c8fe30731c6fca36da975b6f19c657e3ca29efff6febfb311c003ec68189998c084afe4979b5bb19\nB = 84afe4979b5bb19\n\nQuotient = 468f3eece20aa9d6473f3c559760793e702758a3d9cc19d7817216392c7cc7c3968778cf2fe0c3f0c1424d7512cee19ac0717952f18aa287\nRemainder = 5904e71034e3a02\nA = 1f0c99a128c757d76ae6dfcd01012f0453c8f89b00476ec46321ecb872f99a48b4da29a4abffd0bbff2b727dfa182652ca85350b4ce100fb70a6a40ab6c41d95\nB = 70a6a40ab6c41d95\n\nQuotient = 12198913ef16c1cfc7c1be13f1cc5991a61ff74935e09f0c46d26456b7cf2825403b9851d07d27e0197c1fa2ac5e32e836979a184f14cd94a\nRemainder = 33431c3df719f946\nA = fbfbf5494a9c5384c7ae3df6c02a5e1f9f32dc31cd7f437832696bba164bae1a9d95daefb8bc08e0e8e637436fb747084460697b5ef5ac9ddec06757dbe61aea\nB = dec06757dbe61aea\n\nQuotient = 376c2f902566d83c21eb7c3aa3a6fa0482ed52c253f67f00d5b915d0183c2d9a2891c2ff837fcb426a4c990c48bda4f90e0bf69d13558696\nRemainder = 31540f5e05e8b4df\nA = 2527f8cafaf7e8319ca53104229199188ab1ca5fe592bde8ecf605e17ca6446414e06898a85e177d6985b5cc6d4eeabd6b222b5f44b4fc1baba050665c090b5d\nB = aba050665c090b5d\n\nQuotient = b8fdd5cd7b2d9295258bd99e2780921cb2ea70627a79088039fc3ab1c62bcfc6307e86db4a7803f18e5339f152063f9e41d370e97b1ba2f5\nRemainder = 4ed4f2d12e4f4ba0\nA = a25bd113c5a8c67ef65aa80f1512de43c9441fec0c41250048d29c406fbdae80912eb3970457d621c552e3af7ef2d6bc1b5448e7df5be724e0adf6f71df7eef8\nB = e0adf6f71df7eef8\n\nQuotient = 5421daac8cdeb6acc2b8b0dd85b592f255ee4fedb3a9e90f2a5bedfb0f9f033d7c562c96958346bcdda4664c67848b9d9fa7d3892bc4e9af\nRemainder = 7e5661558c345eea\nA = 490aef65c81b32f5df76dd58decdec3e3f73bc1fcbdb6aee0c93cd98725056153b572509e75d2cc4b042bbeb0a77d27fbca1e39efbc765adde41a7dfc5c3576d\nB = de41a7dfc5c3576d\n\nQuotient = 156a8a24e7804c5f576cd1757dba44cb4185bc13cb56603b54ee3b70fa35cd98db1992904d4f7d99a63b3a486e6fb31141a9d39cc0301f897\nRemainder = 29e9c1627537e5a4\nA = 5e4a10e772de8dd2c96acd714f7d3880ae8ab460095a01038f3aa9b8ac8165889403b42019a1e70e0e7f32e77fb388eae3579dbcb690729c4671868b0526aeca\nB = 4671868b0526aeca\n\nQuotient = 1b0eff2ff0aeb2c02ee3cc9e0bff808f4d616eb290293b13a6b58a84127972bb417d55e1d001a9720ec72562ef3ea688e64c4f32c7e26cc87\nRemainder = 664d57c57d4952e\nA = 806b8504abfbeec4d5923f83ddc071be88e11c4394168854448df96160b95adb1fd9c288852e2f3df3e36916ba5118815ca2e83a6a7d9e074bef9c961e2958e3\nB = 4bef9c961e2958e3\n\nQuotient = 2e363b13b0457a0e9effc2d7e297df78f35e5d24d0f8ad4525b573fb2f66f374871291ee8a8ee3d15a823b560156d474c678f79ee480bbe4\nRemainder = 5ba8f49e0ca36ab4\nA = 2e1bb261d98ec405dbb068daac5efeb0a51f08149181864e9dd6bf6cfcb617b76d8facaee2ef468807e0403bc550d58e8ad9e5cc0f094b02ff6d0277fe642f44\nB = ff6d0277fe642f44\n\nQuotient = 149a5b1a81b9e47ed36be76252055bb202dc25f8fe7beaa1ce59c279b32941cfbaf8fe4555867850b2fba43b10b74534db82398320f9786d25\nRemainder = 1ef621737e81780\nA = 63de892cf5df40c98de78c755c99e94e0e76cd5dc0b49b8856fe69dd0abcdc535bb1416f0d02b4eeb54e8a939cf7ad4edfb7de4dac87523e04d8ea8637e50920\nB = 4d8ea8637e50920\n\nQuotient = dea8a9211974758752d89965eeeb93cc616f88ce757ec2809f829cbb8d99b4ffdc3f0f643779fc5e0bb53b5273a5b15965f4a364863592f\nRemainder = 9ae7de3edb6c7edc\nA = acd5cebd069f7febc38c318867ba3a562bbf8ea9b19a6b33538ba107e49439f8ac6e880c6267c29b39141dbe2273d93062464de307efdb7c6b738c0bb282c3e\nB = c6b738c0bb282c3e\n\nQuotient = e9149b347cdea84d740be70060b239af000c4336ddf36fd5159083b795c4763588c87a959df0104212a04cc928baf60b0ea72e8cccc6d477\nRemainder = 3ef5c6ee67e6f5da\nA = 6ccf1b8b406e6a106160e73ac4122a04c0814ef5a47708a6776eb52002d52772d3fce3fc05398172bba191390aba925bb23aa1eee626410877822f27d1e3cb09\nB = 77822f27d1e3cb09\n\nQuotient = 1606c2fe44cd0b780ee474a9c7daf0b2bebf62db0ba8ef5a99fe22036019890a4c7dff73e678965bb0e2a6e61d00a74a1d33dc1106842115a\nRemainder = 7cf920ba2897f714\nA = ef9a3983f26237576311a871e4a3df0538593dd0cfda58ab90b889fdb35c700f7d158abafad127605057ca0532e846992c41ec06902ce58cae0c1fe238c726cc\nB = ae0c1fe238c726cc\n\nQuotient = 8ccf17de5068451fef1c2808c62e19997c7f920d5cc0fde1f5a247cc57c6d730df553cf33094b786597a343a0ce9e4bffef568247e904343\nRemainder = 2689c40a54df34bc\nA = 8435babd279b7a3833d01988c58005d4557f7689ea9b7168ef42ce2b31a1a3c32a982aff654f271a651085335496dd826ee4b3bc27f58920f05dc6676e51c662\nB = f05dc6676e51c662\n\nQuotient = a9e78c48c779140b1d15843089765ce9ece3855537ce88cad3eb7aa7bd6ec72df65adacba2bdf6c491066406bdc3dd3dd734a70e93eed958\nRemainder = 53da0b15ac079ccd\nA = 78550cb7b58b58d6878b615dfa25a5b90a1ff631740e631c7f8829962446903c686c810c46a1551b6c1f7a89ae898435bb8e36d1bae24a80b54edbf4bbc9af85\nB = b54edbf4bbc9af85\n\nQuotient = 1e3b41304ee07f6baf1ca061e0e28a3740991c6ca2749eba70d3ea1f9cba8adec45cb69a31cbff22784a9e056e884713c0812e8c7981e49328\nRemainder = 3d051148ec43a72\nA = 76b9453d315e7a9c592e1f2640f5b6b90a65e7f2ff8ac24b9b47e35abb76fa5d303be6d501b341a882bdd9d2a1c81a9280724673f87fbe9803ed5a2e7edaeec2\nB = 3ed5a2e7edaeec2\n\nQuotient = 1921410e1a538a71d33d9c5de95593fada116200c399fa7590ebc374282570477f5f4abdd5166784ccee9671a1a23b96378df62168049f6b8\nRemainder = 1a1f4aeb882d7546\nA = e4aa84f782a65d376b10e7789a7d56695885aae274db6cb37e0a34414397a57b4a5f76dced11376af5fd11d31828203e685861a6dea2397891",
-    "96fe73d0e46116\nB = 9196fe73d0e46116\n\nQuotient = ed2afbd2e63617a651911017d9d02224d521e99275ab642ad1a941827983b17ef0f2067b5405b20e8e97f2ae6099150a1989df94276aadee\nRemainder = 4578107045b9cb81\nA = b547cd987638ff7e3c30fec9b728bc10c3b8cf16e7040bfe0fe9a26e44d2898c4c4d28ef525cde2b4007b2ffb3aa80fc4514a99b9aa2e112c3acc56b72ddbe9b\nB = c3acc56b72ddbe9b\n\nQuotient = 56181509251931afca3bb9dca21eedd6ed4226be67497d8d1bd0ec052af146993e7358f132e842f9b6c4934cf1b4501f5d6c5912e65c8d3ce\nRemainder = 1b9861df51429a6\nA = 32988a4e0769a5aca200f6f6f1498512e13b4904a9a311cd8a962fdd688de0c6e50b04f42cdd2cf8bf9b0a6922657f9ad195773e1250f85509672452618da9c2\nB = 9672452618da9c2\n\nQuotient = 1fa45bb973dd1d2df0002772afba55284a1e41f6aa4b0d1a6c6a4beb8ae00b52e88a9889037b8bfa9b7ee38036c57b713b48af156c3f9e8d8\nRemainder = 2525d52ecdec8814\nA = bda657ddeabe24c82c883e85822941bf64448b7cbb368468078101289b6fca36680b3884e35edc1fce5a5cdbdfc11359a1ba8ac0785c09ba5fe5cdbd30726df4\nB = 5fe5cdbd30726df4\n\nQuotient = 63e21f5568d07976aa81a2690b9e81b76fc3291cdeb010d1693d0e80191186815c7b2f83551a5f1b172640425d4733f06f4df1b2c8a7e6ed7\nRemainder = 14781a368471ecae\nA = 9f3dad0b3b56de15ac46cde1d79aba6a2f3b34d685cc810e9fa3f2d865bea4afb480d58653630319a258e9e8ded9be93cda3bc52b80a9359198221221724cc3b\nB = 198221221724cc3b\n\nQuotient = aae37878db016dd758003b85ef52acc7288b7b74c4723e3876a710baed4751d3be2ae49123b248f2b2c55a5be702c4428b1dba9b8a6ae8a9\nRemainder = 6c754d5c167e1228\nA = 4b93a98eb7b92cea0a4f5c2223e77abdfbd332b39f295b4ac40f71625d88e4add7e482adf3010082d8dd8854cf714a54fba0887de87946e97137cf7eabda038f\nB = 7137cf7eabda038f\n\nQuotient = 9881f551c4b7e67611f37df29e77cbe4e2d9fd5e17b7da3d013d6f3d4312e53dd26dfe3a2a12525cfef1ef81e6ebeeb7ef8fb4f918bf15ee\nRemainder = b14595005716bfe3\nA = 7737f8e7337160c14cfa8411236ca0354d8aeabf389b9fc4b14bb2ec3bb68286f3d82eb394dbd8062862b955e9fc8e86eb646317d1315d09c81ef51b30288cf1\nB = c81ef51b30288cf1\n\nQuotient = 4c8519d4d85ccf845fc5b8f31c27c60f0893ffda29ba86e8a3fd5fe67de5d29cb29362679abde996039b8febda2ecf71f6b9e1c1874361464\nRemainder = 10fae644af084f8a\nA = 900f7846e927760d9986894de6489e53cbbcdd59f7707917e7581422508f2ce79b77bd2c56d964a41e60baa927ca679faedcd9cd8102dde91e1f583ae834b092\nB = 1e1f583ae834b092\n\nQuotient = 16ef17b40bb73063f3cd0929cfe2405ca0ff2d3d426ac05f8a8dfadc85659105f7f728e113baab59247c4c7936ab975c08d6f1c72c12c532\nRemainder = baff11e6961c72e3\nA = 130b212cb6f3d854e4f17524953fd8592f5e59dfe92fc7d955e2899d1dde1ae4aa20d749caa349ca8d1bda7eeec2310532a7af54660e2a1fd4929335a1623bad\nB = d4929335a1623bad\n\nQuotient = 1cdd7ee2eff733b83beda5b862673177e2f2151ee0fd9ac0bf0ec5b7e05516f1d1b59ea754b0483d0e4bfb7668bb99117907a58a8ceb78028\nRemainder = 29e33e0c2a515780\nA = b0131ec2c1ffe9a523591a9453d2fc740bf885e7efc1a0158905da1e646745ef1bbf39b406564cb3da2f842bee307b36219bdee5991c969d6199279c25d4e380\nB = 6199279c25d4e380\n\nQuotient = 20bfcd06f9c54c537ae563e33dab31047aa30a6bc4e7eb0902bfbab3bbb7e65df442c46625c39e08c88310116348e9ebca2450ab463727f90\nRemainder = 11d8f2f6d4c1f55c\nA = cefafbaa2990eaa88184162ecb118d20e5999e5a8fdd25ae7f6248650ea74a8cfb92c58efecdd5d31eceb618f1596d7a6bfd31d092cf86da651f629975faf91c\nB = 651f629975faf91c\n\nQuotient = 37204c5735e4ba5e47e845d8b652cfc2b1dc715abf21ea0ecf5b1c6c8b9e596591fd7a7f41787be1a028c147a721ebb891b0abe3bd079b589\nRemainder = 1ee700ffb0ea02d8\nA = ce22d36b3cb913b32bd0e25cc14c7270d3f7b8e600a9b6732377f846adafd7fbd8a09d12fb7011f2283d988fc29aa25948dd4a0f24512b4a3bd460ee19887d35\nB = 3bd460ee19887d35\n\nQuotient = 191051194e4362bb201f5471d4bfaf92f79b6fbd119ca3dc1afffba334869ed9f8acd14fc42a2d8f616d652610a483ad90f5140e9a5ca4172\nRemainder = 74785b6874d8fa37\nA = f3c79f9a6af1c5bec72218d969620149afe8bf068cf7a7aceda977076665bb5a2c30729ac3aa976c9be379c6a5458f1501db8802652ef69d9b9f4f097027ddd9\nB = 9b9f4f097027ddd9\n\nQuotient = 6c46c17fdb03d192f75d636e1e2ab4e858d55f0f205cffd75550c4347726b5cfe036c6c901782cbe5a04f1985d9fd1dd39d747d25a6a7a88\nRemainder = 9a836be71a24e72e\nA = 4f6cf6e357b4985442a25b5c84e2cc0a5e685e2f5ff71ceba439b81f4123e16db2296dd4333fff23eea92bdbb812daf1d27c721412fa9847bbc9a0bf08879b1e\nB = bbc9a0bf08879b1e\n\nQuotient = -4984390f93e11c9a77880cfbe157dc41d43fe901c8895ac5091c5367a77370b16d42e8cc260058adf4d3fc8ee8cc6c0099804f4c319f15561b0a2b1caa7d703db82a726c9eab569c\nRemainder = -19374dcf21822188d720d6ec892bda2c084e8af84f38012da7029a3c3660c7e813fd4f7644ca80373575ff98ab6d743e939269c51bf62e04f\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 330af318ce0ffdaa92448777ed117de9c104e0f975651322c8e01b1c470f3cfb7a78b11f7daeea57614cec37d18b89155f19babeda0016171\n\nQuotient = 1a56f7d6c06a316a9a466319cbd558a99f06843782673a54775d859768a61933de3fc410068d00d5f6ab13fafc9228fd40ad41434501f8827bd7461441140eb6977f18d102d446\nRemainder = -3c3d566cd48a909292be2ce30f88ebb68e9122a3359f52d1d7b0189c467b829a9f226c0b64845715020dee12d179913ddb7f17da2db86d854bd\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -8e770450768d07ce20ff8f5f6af464b1ee5f1d0e8faaf927a19d3ff801f6089378133e822b8e63cf29c4c9ed721adfc91d3355a3c7bbde77bdd\n\nQuotient = 42131cf8f52a6a3f189697ce402a8c9439bf05cb3dc1cf8bc49dc2f07cef15b3bf0102c941b5b3bde6440abc6eacfbf77ea8da06ce932fffb226b33dedf001e9657464b0f06\nRemainder = 4cd483574fce075404dd22072abe61200fc455c15b382c7f2962ffd82c38ec1e2c60f71267cbc35fcf77fe1f9301d6b5f884f1c416304aa9f4d4b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 38caa64e74b29a7e9bbf341edbab112a730b17103831a9ecb70ef077e9660b2dd1fbf71d7f6bb4cdae2ed7cdbe9070ec9fde996c91b9bca5b83450\n\nQuotient = -11d6883fcd705ac97cae5bb7f8a2929d6f636f4f232ae9a4af9769183dfce9a9296fa0714c3f4fa1eea467a5c96a484a59d0cdd87496b9398e7a818daf89a58add3a39e80\nRemainder = a6b7984fd80d719ffe2e6eb756e4e3bd7ab51f6088e04ac8fecdc744b0385294dd23b5007910109abf40cfca814c10addcb5330e422b6f5eab6efa2b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -d25d50f53c694cddd56aadda2654ae5888603b39cdbace93d19c117af5505750aa24e615f95446862bd693f5b444e2a876eb2cf49f6c7acd007eae02\n\nQuotient = -3fa898b02c621915f44b213ba4e80b8e85c7a2f4c78df2bda7d99494bbca3eb2d9354965d83e1c9001f10aad9b3f3ed837a630b329f5a4b28935158fbd9d291a120b08\nRemainder = -320d41a3875da2e83ea9a83947f5abb1a7026c84020e983381722bf7aa87d5987ab088cb2c37fc3781c82c81bef3263fec560023e236a747030618e9d2b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 3af2721aad4b18db27842b5e539d8cada9dcd7ac4c5b885065dd2496a6f76fa73c8a51b239b5c068ea6feffda22d8ea806fb488ad5a94210264597edb40\n\nQuotient = 179307c3e14de14a744d082825ed723b996a4e15f156ac473960583138c43f4275b4436c50ef8f21a7b450a969819b81c15bc355fbc5fb55cdd8e124d931d142851a\nRemainder = -9c8eabd36a25e995c1811b79a2a0357f6aeef4477cac0ffdd130046cb2a647f928a34d91d9b489d394965719cd58604b957c693a93145328e5568d33d88a9\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -9f2d3da1da77914df66bc889a40847a0d705d4648a11f282e09173d170e96d84b5a45092d995318fe7a954b54b88b784423402519a38bb521e84a4f6c5485\n\nQuotient = 6c0f316406afb4cc2aebe34f7948422de0b612a02dc47f4ae59419c579fc465ceae1980a3e524fdfdbdfad4862f168a9851664688c9ba01a8",
-    "bc1ac156a6276643\nRemainder = bf52a2fb6493eac22fc8b334ccd8e8fa347620539d9189d535373f94503310a027c5423197c7279bb51ab8c459e27f548d57b55740320e80b753290d077aa7f\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 22b9e55639ad3ff4f071a49c8bba6bd9047e162fb31882421db8ec5ce46f28fbc35040bbc74ead5a948c47c43e9c7adc32fa52046b53f12b07b5224e0d8e93e4\n\nQuotient = -1008fcb6894d8c411905136fb3e05b38ec5d8df35db06379fc2d6d3e3579bcb34fa6e021b98b899d9d082c111b1a6ac8e50418fcd5968ade6aff8828d8e4777\nRemainder = 3d7dca387b00c677d855fc4af4d86d86331fe4309929039e828765f0937990bffa964d3ffc5d4f2f4b8bea978329e7cedb847c7cc341ee52217f903ddcf9446ce4\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -ea045323f406bd7ce25b3ab4993b5f6dd92ca80e3a02607a862deb13470ccef229fad67ae958cd87fecf4f08d9609595077d0d1360d9fe48c4566e237aa877e7b1\n\nQuotient = -42a50301031962754ebf9c4b1e125e6df3dd40ffbe09c044b1cf4b62ffb4f92d298b05933a450bcef65e86398da80740a610ba45928000a5c12d26e9f6a4\nRemainder = -c5485b82cfefb3f980e0fc7c6cd89b1345a8fb942299bdc36ed4ff8916016315a0da84ca0ee2824dce3c7e5ed49d517c45173c9c8e30b224940af6cf828c73db8db7\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 384e523d5a687bd1a90101e43334894b6a27e8c6809a8bf5bffabc34d558a8309997dd6f2a3b7c1a63100dcc0b6647b444ef7e5aa4a9c52c7caba1ebd096c3fae6f95\n\nQuotient = 1054439945ccb5bc5461fed04e364c7a36d5dd2c0428872676debe07654b2ce31e435a90c81f2bac1032143acb0c49ad101398feee8426bf270bdc0229\nRemainder = -7bf919e14b2559ab82b3c1bf428d083a4c851a7a1fea44718377e9e945caa5cf48e0b1ad727e251bbb330292402a75ecd96a56db4ad07146533a3ab5a717d0a25a3a7c9\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -e5cd83a644ec86b94f5e33d4dc307a2f14ee8653288145dabb2b5f894560c164470197fb9e37749656f47df343c245258627aeea17965fea10a57336bdc6b4a47443492\n\nQuotient = 62675274798218da426a54ed7158f8f737b7b3c328a9c351371f0cf61f41712f9b28741f187eb635ce45866762fb5fc5051776151d202e2556c5845\nRemainder = 1aeb5d1fde3c259917e430e6790b00484d0d9508391ba6ebab0f6299190d4b34f5f7d8ea2174974471a1e28ee2c15e05da645db971f699d5d0e80569b7eba7908ae579f5ed\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2622350611b486e6be7a7c1c073c230d604d782c2696038a3233ebcc3f01c6a711969094e47f49e294f2c5bcd04fb1b7c0934f19bf6e7aa519a8d4ec2c172ac59cc1a57b26\n\nQuotient = -12970cdd96b92c37787971cd8dd166999ff241be881eb9543ff29165a9c1a3beeb38b1910a5724ffe2b73ab95ac1ca88d3989aa531374d4ec6122\nRemainder = 627455cb555398150e5b4c1c53ee16dac8d80d9616ed1ef40031424287f8028a9cad1a10bdd8430f6f65368cfd00390c8d4355aa5ecdbd1ff0266a1ade235f33cb5309446961\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -c9dac93cfb7abaa3fcde359e09a92ab0b5c06359bc09ae9bade3c6783064dba90b233b4c8d5c6236a13ef96c7a223e37bbdd931eae61e845e5a10088f75b3ff5f1158e833b15\n\nQuotient = -6742b3871dece5986d4e219bf5f43c101da8896f247521fa286fde696e0b71ffeb3b6a3e4f33710c9ab150b7a1f747cee76839c5e7f2509f62\nRemainder = -203b2d6eec9d485f7b439fe9d4c640bb31170af38418faf4daad577c30e44ca06efda55ceea4fbd959b3809fa2002b6e2cb891decb09334ed89ac66ff05502036b2155ff62f8aeb\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2457088096865cd052e9cd9349c6e5e34e46c89d6e860a36f8e2a0bb1e5d983e07d05e6f6b31edc67e4793cb4d40979c029c80a13e654b66c8acf6b894f615a3ac800bbd09ce020\n\nQuotient = 15eafc416460d757d0abbda8d094eb535262a71dd033c25e704a6df54265b6123247e5625da476e0c220ba88582a1ed94265135bf8bf1fb1\nRemainder = -64ccd9a0ae0b0abcb5507d51b2e6c8e52e67907474605c439796febda06eabd8a3185fdfc0bd088cc49fdf564b5b45890b07269c15b1aa2f993cd9872b97aa6cc37dea2f03444b3ed\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -ab34d3906d8a2b806b22c73d44948d703c1e05a9337f75cb0b5df5205c5e2d23f8a92d8381372f9398c9ac2f7b9302b83e48b26512ccd0b06e6b8ef1b930ec2678d71e2eddbf7349e\n\nQuotient = 3b22916d9fe3145fcc3b8872bebf5aee4e14235f618e0aed09199852c6bed80df39256d8407d334c06f4479f230913370b7d451fad99d\nRemainder = 1b02a7b97f9ac1f6306aa00fff0e59f55fce463ffdc640364a950df29474e08b67cdfcec0628e973d42fa1e4f98e988ec4c47e4915651a1731b71d5e36a10a0d1b3420427dbb79ba7d52\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 3f74cafe9ab0c1b307cd7571fd442665fa3205fb2f45b3811b92d1d38b096a2025b8170663a29c52ca84da102e62048e583fba96a594c0b23952fec587814857c25221ff2cd0533cba6d\n\nQuotient = -12ffa4b6fc369404968911c17358012b993c18c2ff34122e06f450d3d441926b5f5638b40efb012d76d8bcd3c0012d0a0ce5d55c596\nRemainder = 64548684fd5f6c816bd296234740a4eed772570bd4a48852462f9cddf14f1350ce7c7c6a58aee8f66ad7df87927458db09e3af08eb5376de08444f35e5171cfa0992fb27f70b81574f6e8f\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -c58383afca9e1c480ee75d3cb6b0b99ea42e827d39fc96bab6b0dddc97e3eaaaec02a74847f9f7d49937f5ade3580bfcd491990737d172d4079437067251ab403c36a9826e974b113e2d2a\n\nQuotient = -4964410c2b038573107b0151b36177cdd62495e0dbef536b59c8aacb8836bb45e7bb014e5022360621e8e82a273d0d462b8eb6fc\nRemainder = -1250c42f8c9b129a5c477be446b86356edd1b19409d362c3a5fb5d59c30f1c3fdc1424a88a0d6ce20bae885905d98c8a5a6495931f73edf4c60112ed78834e3bff6de3ed54c867fbf16a1cd53\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 33212ef4a8e80daf1049ac6f639f8e1990142ac32f7ebc97675ec90f8eb1a2814dfdd295ae67317253d0187ad33f3932a3a7efb056d0a3c87d28e64e23e9f1de751ee6f0f61c6f39d08d72f0a\n\nQuotient = 17f77efddeed52ef2e423bc2c10d2ae15c97384b766f4108474964c2a44789e61249103d9f5fe00b4d612772dc6ea12a42e395\nRemainder = -1ec95323b7b95169d5ec0667f3cbf683e98c15dd0fe44df4ed9de9586e43f1f69337e41a6d11d889452665dc0b03cf8d9ef2effe0b350eeb9f6468751b8a2c42608ba2a33192b770cb62381a966\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -9c91fdf2dd1827ed103a102db254630c278bf8b47bb12a342a92f081acbdd8ae5f5476ae194e24b187011ac25b19fd09e6e690777f9d3efb6b3a32c8f5905e1478a27fe4b1adf17a70abb4e7571\n\nQuotient",
-    " = 4f5dec525ffc737094f40d27446ca0be5b7a2aff02d51d99609165c4cea0dbbc1d92bc0a8680782b616c149bbef7f5ca912\nRemainder = 1bc84ce56a9a0c74962681c02ac927051c81f3824d9f3f0f91465df333ecdb449473d9c26ae3abb9509add5795e89ba5eba6ec7c89b114c86e6991ca0c185b34d6e66925a14fd82809dbc4936d273\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2f47be01e6dc6a86097676fbd472c2af0c83a2f743fcaa885e44fda7e9f350e9fb7a8cd07fda59ccb7963f1e95e6a1236f5f94939decdc85afc0e523c711b24641c844cd3113c17fe35ca988ba407c\n\nQuotient = -163cafed5bcfdeda88555f30bd4cc2da2cefe2bcec9a7c19c36ccd04a45121a5a0dc28d0bf6ab7fa4b78933c47a5d5286\nRemainder = 93f856077f5b2907cefcddc4d767ffeb0acb7af64bb9dd8a15dcfdda6c244c24fb8404ff9ea2fe1dc337faa05930d33cac4f61e171d0236e222374cb3da76396ae1329a407fb4ac652fcbdc568d0fafb\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -a8bfcac452a5e48fee9132b73bc2fef771450143ab80aabd8690ce54c9b52c2b5a669076a7a35fa6d926268077bec6d90b722b5d074f28ce3843fb0147e567c45f4e91a11416c082762e71b5c6129c08\n\nQuotient = -617dbaeb8c6f9d584e8eae923c872048f9f9bf039ec6b50cf8f09c061bf79acc3311b37c2502e560848c05ab316fe8\nRemainder = -1ab4613767c4f1f7d127e848f2bb7c72a3a9e1dd6173b63198b80d3bbebce6a31494f19b53ad9e3a77248e6f9b26fc59060e2759a20dcdbe785297bbd912da9a1819527fac550d64bfd20ed1f96450c30f3\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 267d9397138fd0374a7a58593d41627ba1203a646ec2c04997acf607e9d217b8f40183d2f9304447d6f7e727a476e636ded4697a5ff30a9ae3d249baf97969658209c1b32ddc0edf920b0b278e9b5464313\n\nQuotient = 10ad85703fd51870306c5e36b51512341d6d39e0bac47a03732787b2f62e49c76666f7f49b2596de6cb5c5b2f31b\nRemainder = -846b4479713bb19ebb8c1f1b75d2be0f39fc1095a3d2ca149b5565146bc19382b86e5ab0d098ab1fca1ce701d582400190fee34b602845c3c0c498925710f0b9e3af2412ed5ead1fe03d77e9b2b407ac83823\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -e0ffa4e120f2f46fd1430b6022fd03f71a22f9b120f8d40e901279be235b32d94760fb8c2403d23cdeb728ae73e2b16af7322d6ebd5f5673187668c99805e700f1e997423886bbcb851448dc1ed4cd66d6598\n\nQuotient = 41567bbf616ab41da51108d7edcb5a8a4877c5a8663b3aed7559421b1fcf4b535a54989efedfcc935b3917fcd\nRemainder = fc026e554a0821e0d36b796fe6a676fcd7383a55fd6158d78ace4edfc3d8aa87c65f0eb41baa2aafadc51218b0562ff4b5c9b17bbe84afc491d9e309217a5138ad48dd51e1b1a9aa51d69963b608ec47d63fcd3\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 396e9b45ce43d3f89386cfad8ddef4b483ecb5173234530c67447ab74629d246c18b9da09522c77f598957e3fd2a1c0c9417399912fd547fb1023ba6b90d63d223bcbf3e7ba155e51bba7e8635aa5c39d2b9dbb8\n\nQuotient = -18f1f395347ce8df530d9330c61c0e30ac9531b50a0af2ae7809db1258285c15ba7a436121287990fcdbda2\nRemainder = 51417b9e9995de34316a66a2f70c146df8e36952fe64124819607bd8691a465f4fde98e590dcd56f0faeb95d1b67751081c2393626713c27ec2a2123aec2a4ec3761e5ace4aaeb612d46e52e16d72a186d2ec8a7ff\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -966dfc779cbf9c388a84e947d1128e2392399ff45d9491259c7cb19589154f82f41e852e0c6bb5a728f6e87ff4ff95abcb9b2b57af1b6b7fc125497775ecc1338e4bbcb5315f7afde4e283347184b908545211afb6\n\nQuotient = -3fd962e88dc1d501fe9335fff8b6b2d50eea967c3035a3dcbcdc9599b81f9a445ed5a6ae7413b8865fd4\nRemainder = -97f06f6155f8d0ee6850728192e0b4fcf55fbd9ba982c5f1d598ddcbc4e1c4be0e209fefa6ab3b7eb2b4c645e4dc40217202285ab0a7270d085dd9d4fd24e5293faf6797b4c3c79bbf3ec63fd82942549f9e8f862297\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 3ac566d6b2d18572360fbdc626ec488aa316a74f33d71a17a2d0e1d2bf26395623eb91dc4abebf2f944e9bc3d669fae2e4332088e9ff9d9f43927a7888b1390ef60f05efd6e63ec606ecb3e164ed6dbdc9d088586aa71\n\nQuotient = fb5ce21bcf28490afb64e6746a1a81792c90eae17407c0b4c5ebf2464eeea43e516be2c615f84901d\nRemainder = -3d255bf94c3d610c32266fd472d070c0f5e7dddb88d32723b2e1a20709aed2faf28701e0d0227c2b33ecfa9e708e5ac354a97be732b786210d86f1f05d191513386c580b1ad1f4ac6890f87fd0d4270f23cc5c2064502c6\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -eedb64a6e204ee3d6df508830704f1d5b2d2e627698d38a114c07458ea0befd593a80dfd2e08fcb1893adf57061ec4fbcd3130692de7c46f5ca51361e9b79bb7a91963618b8e5b7591392a5f0e3be954e8b9978c97f12e9\n\nQuotient = 6933a3123d0b32693351a834751345300c49324b861a663e8700bdb3b70ad996747b284a8ea5c02\nRemainder = 13849ef93cbc77460c3c496e8f31f7e01a98c21cdfcd6877547161f9601680665b394933d3a0824f0d32854508c89f0e4a0873280c779c7ca636cd89cf6ee5d42a917b4f382be3b9654039f623c11b43164827f870fa0f0781\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 23ab6042240a7709d43de7ee17332a9710bd0d913c42b3591341527bf48d5bc30abb962482292d45a15cb03c9457cc8d78d1e00aaa63358427b000e59e4260bfe1e2cc603e175d7fcf02bd9f61fae3740cb8e10a510ea3d1d5\n\nQuotient = -10e67cbb33dc6e24765893a047252766c2bfad8385150689dd4fec9ef495dff63ede1fdf78bb6\nRemainder = 9dabe2cbc734b910fa1bd25616daee5657d25b6e4dbc2cd93cf8549715c87974a8336fc5070d86c11f6b670d4b3bd5ee8ae3af2bb321fbb4f8fade3f5c6c2d6c366b4d800dd13ce897f13b0d3fb79f1d9ca525b4e7286c56ff29\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -de093dba98747499f2876c8b6b7a6b9587284835ae35f0716dd594c826cdf5b9179f2c6b08d800a77a6936602ff2b64ee0b7c94493bd5009633f5bbe423454b7f018ae96c21230510ab4bf5db394ff153b0e9eda3ef90eb4c253\n\nQuotient = -521f5e35300b9ec2742ff472cf61235dfe2e449772afa638b1adb812cccf269afd164b7602\nRemainder = -2ad10e8758e1d358d4744ad344ce319617027107c0b8db195d1b58c6e6035450c9b377f026fdf9e5737750af5615cff2ac3ccee623c060d779373136d48a735b353d64bcc5f2e6ea1e46083fd799b5f57dd5ad0ff3e6df9764af977\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2db1990ba1e353a1a62de1b914ccb691380b6ea937c13621a29f0a40ecef460cea52cfbc77d98706fb3c9939ceaaf962fb8003b0cfb40535e0dee22e8e7d04b5648fce2e58803242c199421cc4b26cae776d3603f2ce410ddd1e0da\n\nQuotient = 1d45aa6fe6837a1b7ac95efd55d1690b66487202949a286fc85da7ac0b50b860215e44fb\nRemainder = -7984639b596f1d4e6efea9d8b4719215588620ac959034b303584679a44fa84a4be0c89fd2e29f54e62959f9b7a858c06b0cc051176af82d4b85e7334555ba11c39e6cfa1829995c383ba81dbc220e527e90a1d440c1d0",
-    "69703cc1370\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -80316fdc405bb002990d3ef7d0e98defcd1f0e370d1e51db2d21ecbd96230baf69d00b168afcb7b8da9edc3ef7f6621ae5c5a0d7797e5c92283342e42468dba1036fcb2ffef1f493ff97826477364f6b5a41dc56d6389a01b83eee041\n\nQuotient = 3c0c3f7a777e611d1bd0d17d669a1ef7920b72ea8de06d4b415a73b836e37d6cf0780\nRemainder = d8c77134a75584ecd5ab29e97a909ec139464901f9cfcb1d3d9e29a63d204615b6845d466c8710873980f107c40ab54eca9f8933ef6d726f9bd0f3e9e97eade5eb1a9bcaa7b01b6ad51ff3ecf67d6e4d345f128e990494a2db434fcd3ab\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 3e7dd961be36c0c286eb9e78bf3b33e6f9bdf2c2137a0c660f1d21dea31ac9a044e526bf47ec8190e137a60f1f55e947046b9cd04a2485679e48cac80a1bb064a915208889289d63a6e338cf7069ad799861c31ec6eafe02a4ef2c2641c9\n\nQuotient = -178d749de2dae3a2ea4898c59aaba98ad9f340762040f5aea13cad45a793f1256ef\nRemainder = 6c5d9b19aed9f099255b6e3d251aa50d1e534e6c86d82eebe097dc8dd0748201e48ac62eec070a999c21f5c7684e5a700212e9079b5fb731321dd1e16ca82ce80c1f5c17fd1720f1353bb90997f47f5fce335a43a6f59facff0b3724423393\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -9f52ead13916f9807d0cf0c6699578af52c54816828f22de62328fbd7b4fd6c3740ffc82af4e24892092c7ecac44b5e775944445e6615fce25610984030a345731f944128f5734e6e315a0ea97aafd7563105695d026880d065761687b75e8\n\nQuotient = -4fe43bfa9417839ee408b254603c3dd176653b6915a89de5b781b400162fbed6\nRemainder = -1c15816e03751a203ae23c48965c8541849b09996bc81d28e28d7871fa87d1c3b2d383c056d3084d7d01d853bebe270fe2c0839e71851e169d417c47caacab2aff8a8e05f65dfb20eb17ed8f67475702fa83087bd868246cbb885d52639797b85\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2ef8419306ebfd215d9079c7a2b959a53ca2f4553845e3cd32caab2635c0e77fee8c5c016c121e3cbedfac57f810c132486ba78df9e719a976e0112516893f14cf9b89f95a89aaabf31cce509ac8e7e62ec3833f0be4336afe6d7d73518141d39\n\nQuotient = 127e8c06e12943017f9dd57ca24dca0ead230092811d307386c81b6efe009c\nRemainder = -24f3431858d5aee412443feab243b465b849f5dc97e4de4db88c7adf774d9bdda65fa0a28cf6b18eac6078b00cbeed2ac406f8426aef868d4b59ab045825d4b0a18af6c9105e32abc72fadef55b221278d329ff6fb9019630411bec143c4156df7f\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -cae6399216401dec0f8ff5eaca884ab061469082ee3a18e49e0b4d5f9cfc98a598c373249a8ad2374e0b3de71370e93a98650684fbb931aa5d8b4482cb0be142492bb71743c251346df66896806f926a4a5dd4c16ca3294f01bb998835e6583d29d\n\nQuotient = 3f180694e59df85f48ac02b6d4faa26278af9641db18d79f198da5d802f\nRemainder = 36cf82dcf8c7ec783b4de68e0627a4a4b2a508637c176de09feef62dcf382bfa5d8b88539b5ca2cab6cbbdbbd0e54c092f00ee13f4a352cb570034cb0a012cc0fbdb6ed32967f3b81d146f352139bd3d9a5c27789468b7d79b84d6a8f6085f859532f7\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 3b7983bfaf565c5ca444367654a07b8bc2bf7fdc04ef12128c392bef2f6b67d9475b4d2f0ce1c380913aa98616fbe1d74dc5c9d64df15f5c9b87a8bfbcadf335a6e8f863c7a01ac175a7d79645ababa5f961fad7d1b9926f7284e254fed33765339e0c\n\nQuotient = -11f635baf7b7d613e84dc38978a21ade2f4cd741d0c4f6ae592d93af9\nRemainder = 4317c686dfd56216bc4865f8dcb6a3446e13d8b33861e74d6c4a3223c387ffb8caeea0141049898609ed1abfc2adbd21756cf64a72272aab6c0b8f2177419abcbf9086635dfbea80a7b884181f2f2ec9a402cb0505e8208909fe062d5e6dc7094d66af62\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -d0ea50558197566f22704e66a70328cacd6f4b7ca9b00c16b7c4b4e7dcbd47c9b2526b3858ebb4de7a571ac570872f3b44ba1fec655c0778a8a87ca24851f6072c5c0b7591b5e67a8cdaca78fa46f201e02379fcb9a8470e4a4971acde36cf501d369751\n\nQuotient = -64a078497f85588d3402355bf3e83d25ca1f0ed2c24a395ef6de6b\nRemainder = -87fc31ac66a24ebd629a26209ccac1b2c85e52dc83c5240269ae5a27333f33d31152c9470efd41472af034e8536bbe94b0a49e892b1d23db3c13fd84b7395d7e3f19d7d4cb4a4c07dd1860826696cf7202483446452aed2b4980388e7eda0ccac792d77a33\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 254a85bf512d9159b00a70678239902ee7e15ac2790ce5747c4a4743c6a0851e6a179b64c75acf312dd37a7b82a729246f79196b8a399ff476c48a05f89c29fb106bb06ef0300c4b330a7b2bcd4ea1e82584c7a96b99ec2131c885c5851343cfa6ae4d384e8\n\nQuotient = 116a06b1d38067cef9f55875fee1254c8ce39b42c19fb232a287\nRemainder = -c15a797fed3810e4f536e9509564b2142ffbfc0c961ee5aa923d43a824765c05d2a99fef79bfcb6310c77a91d9bc6d0762bd687493865de270c99989e891fbf6da7ea5c7c7a1032449457eb73222a011bb755ff44e4bdce8e86f8aa9f687840c0832f7fd8ce48\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -d77c14100d19fbaff6334ca6aa504001a1d56f274632dc89d48e1d517935503c26b60c047cab9e186a55b72439761c884f63fdd2a38ca1acc653f6ccbb4b7262e6215e6d00c8829b448b7ac8716fe0bfdbf8088c8c61eee8f8db43b7b5551f6278081ac2eb1c5\n\nQuotient = 6fc9533f6d0e6c55494cb1b319ec47bde8e621aa92d91155e\nRemainder = a1a70f674cb141a896c4adace0dc58cdcbe2503fd0ad36ce348dc5b8afc96d0f2f8c65bbbadabf2920012798b7ccaedbe8d896dd2674082ad3cc75b54c5c190ad56ff34e8cb5dd29c031656497d48571295d6da396d5f4cdb652732d874a79a674d06a1d7b979f5\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 21917f48bb8e65646c618068fd9069c06e22ce8c679a845f9c4ec843849010abeee12e2d3c61fb963297abca30813c446f2ae82e909ca6ac7839fb58974fa65f3b5d91fb8b3f99d948519ed56653d50026d694060208cf48e3c757f64885b4ed4328c6f071e9f5d5\n\nQuotient = -1abc689fd19523d2e295f260d248041bd00ad3009cc7581\nRemainder = 1ab5af1478fe7373d012befb319b53ff9e36899c1749ea763fb74f7d24624e70ee78faf3115c2a423629528f45295e4adec7b122b993b5c29260558be4831df06468bb1c63e8afcfb1b9b533ec6acf754563d2ae25e2adb4cfe5ee3024611e03a156484a130ee01f3c\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -8c5a7b6bc8ed6ac015ec24efff607b0446c1b736dc8b409e2f433e69d0ca015d70c64b4c924175d0e0102ebc3e1dd96dd4d5bb01cccad229e699f9d8f9ad0e04339d70cd113e93d50c10c03083a81264396f5db2d979d272798ed30efa15d52289d0c72f42582ea56f\n\nQuotient = -4aa210fbc0457fa7366a8aa9a3acb3f9fce812303ec9\nRemainder = -737bc4fdd3d5496fc7f936ccf14bfc3d93f5b7caf4718c444db7a3228b41015c67aed304fec7704ea8238ba6cccb1e94cac3bcf4764a44bafb49e5fcb0339ae44c0114cc304b9c4370363657cd2bec09b",
-    "f962ccb21f6091b081e71d2bff8556600576e18d4f78fc68b12\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 324774e49bb429553c10156e8db122670d6dcaf6ef5291f515c517d7ffaee36ec5ec5ccb4d12dff71ae7a05bdfbb03ebaf4dc6c4e8bfdc165b77cae20153c27d53bf27d92ff25643b4888cb586e773955a1c02ecbf0fa6958a8ec0b832332eab2e449be6e72c48d2f1ad1\n\nQuotient = 1c8631a18d189f1fb689f896005f2dd2098e0dae9e\nRemainder = -1a1ac9612fc3354056a5378de5b315f12591ee71f0fa9d8a6b2ea2b1c4eca9947e5c4f5ed3d4b78e69ef7a1f5a9894b9c7d85f6e2244ae76881eb06584eaa98c78b60b46084b517f4882758691f91d9e2acfd580d5e901dae14ff4a4fd6b0d7c73450e4928fc6f02fb5463\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -838df2a27bbb033fa0e581073b879d6e8747fff38539801a1870f2e52d91bc84cf10f2560e93784650fba080304244dbfe9da679f207b6920be46b0214a1e490537e56d99beef3f58b30f311a12283501ad79a5407ff209d19a6efd0421aa144e0cd427380d89bfae5d1f5c\n\nQuotient = 4213d04b9f0b30026bd355404bee887b22b2cf9\nRemainder = c2bc097d1c20f050e88912f066b658446cacc7a4d510343a8d88ed007a8c0cfd5d44fe5f067a0e81536d121b39f2d0feb8dd053bb5632e3f9c04be5f6bf4091d646860cd38c96271cdba466ef8b7e2377a51d5669117e664269fe3c08a51b10e1e019ac063d670a3c7db12563\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 38ca0c2f03a5c56676a2f95cd7a69d4aa2085343af6b1d2a71e0d1c54157ec0e8f9125df2a499cdd484c04feb23b1e0042ca908db74744584036c79f21c25c40401d551a65afed0ef35f1ea000fa1a99cb29e6307f6ca0304145f7e483d008cf9efb028ebb654115a8c6b87a08\n\nQuotient = -134e043b3b88b31f89ff4bc709cfa1bd2c1a8\nRemainder = 99c1c846cbce5e9a26c5afcc0186bb1e43b2501ab3205d13fdf01dccb9b1a935bc1cf8adf74d58f1c316381577366b6d126da49991a0d5e02acaa678085f335ff8b8e975e5bf2e52a05488ebfc21a3e0d0bc5bbe67442f77bfc3c1f0c03b7f7ce42bd0fedd8a498f018d8cbea47b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -c261a6c562fcdd56e67fbd2b91027f17c95da43175eaca6e4069c16d240ebbd240582dcde953eea739a4668fbfcdc6af8ff3ab58674c95de90fdb43f64a61108b030d644a44b0319b912bb563f61e520dca9c88f411b32e99c872cf00a01f5badad584636352913b7429b99ecfbe\n\nQuotient = -448c4922b7a7d5e1efec2c3f41d0264b76\nRemainder = -2599e928027d10d3a11056eb719768e5edb1a625fc0b8a1dd4439ebd30a82bfdf89e617ac7c71622058cc64ba32dc242d96fe3ecb856f1b146f831334af562cf88139a99410dcb869b9ad6ac4826563b400b59f55d8fff262dc920fe525b12b2fa167ec237028a098c9117cb77bc3f3\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 36be11eb72832f8ae7b6bdf689f794f62cc1c885e64706d14a77a11df9761c2e9cd81d8f6a0ad0cb1696c69afd80c8bb992cda5100cf1162d600515568b9dc9c81a518da9d240888d4984df65c129ac0b4c557b4e63ee5be79a27473ff5bca58e559cb04c4ac93b61545e7351bb6514\n\nQuotient = 152474a1a76700598c18d9301866ec00\nRemainder = -274a2f9e2bc5f9d75f9897b28f840b71bb10a3e4e7a35ee1dc1150be61130b4e0e987e8742c5edb75a1ce3158eb8bdb7d657b8ba39436d7c88fbff160c7488ddff2f13b3b95ffe149a3d0d2d406b1737a7671f69c0e5d7074a151cb2776b2d13ca24bec261662f2967fd22339ed6c3f2b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -b17c79a31d5085b49793b6a6d628109a6047e3b1afc947e5212d0a9ae32b1955cfd6fed07fc60634ad15f32a9e402d7d5f750fb6d1ad958211f9e8ecda8990689e5212cf72b24e9b51bd07a6e0477dd4c02381d0ab6c0ad3cac1f620f723ab004880800736804751349f6bb19d3db48da\n\nQuotient = 5665f53d5a7405c83a5ff382ec376\nRemainder = 252d055186ec896cb3142c9e4e49c441e2ddad365b86ad21ae4ef1c522d3306c2834d6993a5e1f8c64a1ed582bad8ab746f7e773fc004b1c47814f73560db72f7237ef6e2f671d3b19a8777be2e4c662a76db87ea64f32c48ea371b1ffb15df26726854a417e18afcf49054c6d2e0e337e71\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2b6eb2caa3ca650be02fa199e9ea6c48646a76434e268713753a547e49571f9817ad396f2cb7b16d307801fc8892f0af3e7f93ce08f7955a8acfbc0b56add4b4c7ef7351f60e402b9a8ef7fe02ccdcb4b00b7ffe78c7009268dbcf1d606c3a1b5307d9a8ee6121c6a635a742b8bf36b56cc7\n\nQuotient = -eeda035247bb13860f228d8f2c\nRemainder = 3976edf710ab42bf069e5829de7e16962d1b765f6ae6ad0ffabe723e21ab01cb9f3f5f4edb1d8c13cafc0556c0aa93d72dbcff754ae9260abd294647b71785bb049bbb865a26bba22defc458a14af019a796e942e77d03484028aac2b3798fa730ae0193d89728bf80a8728715a0807b3c497b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -fb5e55f261aa96f54983869d58b3e9f0757d363b9c43aca5580b7c0380096f396ec79d1b30037702c19be5889fc6376793cad51975100f33ebf43e0897dfabcb9adf3adf8d845aa7589ba1f6d155b25f73dae3b2f835595ad6050401fd4e6392012d06194af415b810b0c10a53bc56350bfcc4\n\nQuotient = -5b37eb0c3e3f8f8d9ac6f4e4\nRemainder = -28fde388257b9a11441c592580cd38caf2d69e2ba57d43151c77d26535226e05e08a9e6d8ed470d4354e9f46b7626e5f2b22b652a2d78f817bb51598c727a765941fba63510b58fb3dd5f30717f237da43b42d20bc260b06d488c9c912bfcea1e7808544c58960a3e1355c50c889cefe75d4d9937\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 29232a3fb059242cae6e0b419ff13c479048cfe46a9063188706c6a3842674b16a1aeaf771c5b0ef401d2dc8a57f6fb4fe1b3c7bb545c18ae763e39421e6a07c4469d234f9fc737ac21ca67a5553c7ed693eede4325dbd132dbd9889d815c02f426801eff1f46e7a52f72845234acc6c153f34065\n\nQuotient = 1c7ac058af2e7bfbda9484\nRemainder = -54d7aa6dace87e61e24d87053b9d094bd160916b720d7cf4f740a4fc5a7f03909773d0456c530ea0204427146fd44d3ecec51d8627b5768de1494bf42081a8a4fa97163b0b93b59e70e533f3257723e441cafa4aab471ec4086601021c4462e1f74bebf298ef45fec98fa8e6ea97415f84c93c12633\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -83c2cdca7577b32c20e9e20fb498a2bceb7174ea9aca09d4dd2fc7a1d3b922797b4e9640c7eb9dbdb4d93c7fb9daadd680c1c7645d8102d77e9c877a9f65b13239f9a650dceefc1fd41ea9bd2b38a622bbec99cfddbc6e88f377cd51cc29fd17a27f3d0d970403a2aeeac6ff9fd69c3bbc5c2b0fe7e\n\nQuotient = 472df5f4393f33cc382\nRemainder = 16579a289cc776a47611353e158c43dadf0a78833396f8419fcbbe47d90c7e840e2c90e73e563e6c505bfcf691120ab0f1e9ef9c31db608cade70eb8e487b1113a46e2b5c7f4a172ad99b502eacdc0f91c295fe608389e61d030607a94d09d349fe1a0cc46d1e07c8db533cedebcb4a3b89afd8b924993\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 34b7f6780620246f5a0a92a768072185f02e57a52db1d865c21c952f4386ddb7e2dc1df076316cb4f2f394397cbcde1af0197fcf33e6428e6f5d42a9ccf623f7",
-    "5fae5940873097d4591d9b1a4cbd00074d134272700ab06d901742da695c3ca9d4f917a808113336f883e769fa8051cdcb0cad7cabd1cc\n\nQuotient = -12b4e74d76bd306d9\nRemainder = 8768fbe8ddbf60b548938d8b4a74c4a326ef335257e5f513e65a7d2cfbe9d456425ceb719407bde3cbc74c9c978970597b5663a0ec61962e77eb351adaee2d2d37f1fb55b5d2ceccf282ea3a0d398be1dd1b166d55dce04a39ef434fa392893618003adcfa61401276ce4e599051ad93152e3477ff524f0c\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -c898a753745f0fc178227a7004d917557cf3dcae2e85e95aee51e137b29c895755853ce2d61f214b80070174cad8ebc2795a7d070790acd335b383f9dc88c01227eeab85f1f29d76c1136ffcc7b9fdc073a3a03d8812c7c561b32d8e69754fff64acfd64994b7e9574d2a7cae6bfd5a6fd61dee7ee993bb7\n\nQuotient = -548c97fd02eca7\nRemainder = -939e90e281f97a433eb1c6510668d0fc448f03d737d92693b6362c692167add7e4442105d60ff3db29c03ed06c3121aa4a53c4625906519a4092e4821c918d2264ed0cf088b7da43a222877f3ad9a9fe8ec06fc66b9cfbb44e0fdca1dbe4e461dda9b85231b5b9733e0c78852da83bae557755de3680ab61d4\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2c61dce04200e725ab0ecc5016f66044218391bdf650bc0bd31f3749ac06c24707e79526ee459ccfd4bc22834f8d23f391f2e99135f92b5abd0b04079ab75a263c0e98e46edfb440cd865269ed7872e8c1ada312df1bfd6a5fcd2ebf548d7b7d1d75bc36f62e5e9d15262bb8652a8041e5c8f4d673eecb777d1\n\nQuotient = 14622572f311\nRemainder = -6d197a84d2ed486327790059adb5c073218c56345f48c15caf6892734fff0aa7af4782738bebf24d984bc8adb3056f67e57f9960001a67fa462afd8c57ac9d60ae6517d58ffb4773b637ebe6bf2473a5490511fcdc576a4c40ed03b3afcb2fd27c57b66a26f6d3f9b2bb101502b1117ba3ce7214c9db6302fe20b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -b818674faf69bc92085b7230d9335d7bead0413f2905539a54e8d1233843ef13f07cb5538e0787097cb24f152cf54a92e62ef143e31cfbbaf3c09650b14229a4f61a783eead26430949c88a87f1618788abab9728aa52dd8419f5d568e6a109f278b2afdea91cdedca43e562d4bb8fb7f1b7aef13992fa7edc320\n\nQuotient = 5cdbb03ee\nRemainder = 1cfa68d5da7a600a7ac598b9ca1a0759f972fd9a46ba62e5e96d8f6f00fbccd0ab26ca03d14470b43793411ea9803c9409908625fd74ef8f9b2d7c2064b2e3439adcb684e6f01432a1feb0f492fcdd2b8b5a6cdbd0bf460272218bcf763974be8784e5306c219ee535baf5541b8580952e3690b585fd99f77c46d69f\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2869338cd16322409d3efbd328b27e2ba53cbf71816ff5c093849b1d866b8cdecbd6bd8ffea0b7787251acb760f85c277ded21e56acef05d29bc728cf44f55be87cb4c8913408a01a1ad53461058a1cf94538f05ec14a6d3eba804264df957de7eb1a61b794a1141218966463dd42402c260c229241ec46afdb5a06a\n\nQuotient = -f16da1\nRemainder = d8b66b622b5a54963c2c84aa186bfde5b67a3562e07a23a5f6843bdb615a3c5d4f007ad8b275ad7e4c5b1436252efe35699cff2e0546e6dd8c7230d6ad560c51cd54db6d312be32ae4c708e9047c3a25c211e2566c58d6b9291de31612006d4e847c6916702be99b3f7ce40e1ac842908acb7f03dc120aa8998c60737\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -f8af8fb7002a9d2218dcd0f0c139b8e3dbbd48e25a5c910f6d0b6684bca224f62768b64955580306bac6bfd45b99ad77483563fc7dbe015edc06bee3ff93b0afa8f5866c23c7a7570b366550490c97ad84062c2495cff30717aaa965a8e15e270b504dbd4fa943be4f97a7fd1f3b589bc9fcf4f907a7690d99c978a374\n\nQuotient = -71bc\nRemainder = -13316e9b053a06520526f579718c326402d2a9686d51a340375cb53d7cebba99c8d1ae93388db0a41cf55d5753dd1174014ff3305fcdbd5b02de9e90c45ec0d2900ebf6ef847c2a045eab7f80f07f01c81b9fff093a779a280ae42239df79de8d2ec4bff6723788c86786fe276ae6a4dc1472442b552258e1e5b597305187\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 20fe256859a2e4c4f77db6adef78b2aa4758b29ad0787ce7e277bc68391d5949bb4dd07a9b1a79fe890c8a760871d81adfd3858e27d1bd6de33fd31b8aa6131fef9130a50f995c3be1d615d1bfb9878804b7f6494237d8ad78ac219488f17335ae54b494532f03a3fc8e9576cab6facd90c662658878fec86db66bacda3a7\n\nQuotient = 10\nRemainder = -23e09736f469c83f280052ff01071b1bdb52b7e2b061e8a1a8c6a4e091fcd7ca0b33ade885d928a11a3375599aedfe554d1c2289795daba08f07327a19a8adfc219592bcdf9fc5aee5961a48b3b1b5fc380eff5ed2ba7d7e564462397fb6c6187254ee41c74602b141d7adba99205d2e0b35da57efa96397b3a5d112751cf7b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -e849bc0bfd9560cb90e42c8e4e88df175133c14466e530716d89ad0326b660b0e617b4efe8df6b000f517d3cc24d9dd4cafa2773dafd4c6bace0aba54e43c17e8e3ff9497a97ed83e6408aa0aee0e6485dd1d89d52520d1acf4d587422b0c5cd2d5e7e81fdcf842d6331779e800f96628206e8be020ad4021789008a641f67b\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 22004040a65f9b6f120bb7243c638cf3a4cf6fc58c230da932c79568f68e31af7a7b8569aae77af671f8335ae68d6dc1698baa9d6ba9cd633a662101b45bde51d55098b50fabde8546f317ecc2ae7a39521bc075942e3751a349f51ca3c371f3b8a6cbbea3e11a334d677c07612bcdca767194c07fca78ea8a06cc3b0dc6dcb8ba\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -cad46f410062dc33ad4d712c3b743ae2b7613576b2bd7c346a8479ed679a08e3644c7ee4f23b95f1cc9111905714b170abc37ee1003956f64f0a7e876b38d524fbb2436ed56069479d8d2e4029770f7801a7278fff99b3dc76280f35c7d43ee594073f725554a92eaf4f785c18a7cf6669dce5adb0995233241f3294cfb5bd8f4741\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2fef69f9745646aa13e0c38d77951161a1f881a7ceef032698da3fce00764959f11140bec7d7f53d6777c3622453d4525fb068da48047609d18d463a8fbacde1d21035963b668ca11d5b9ae66db13de7a7a5b66a40608dfb56d9f9f0c8880426641083a05b5ff9e6ba0d6da3a04af1af01dc218e9b4f6ad7b1d3a4d1d26a5c906093b2c\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90",
-    "ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -c50a24e5ddafb768f64677233c5cf09da1b4f06894bd68e194b23feb5c5d6844320a12a02d13ad012f13b1438eedd6313bac9c1f9bb4548fcd314988d8fe0ce6458306735307afe08a96a0c2bcd9cf126f529e48b7ff4b8266caa28c40b5c3d2a473ab8805c860d27d7ee9c032423148d96fad019490ea019d40679de7a2a3323e80979f9\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 3a8682d0e5a4efa985dfa8bbddc2c0d72a4400b8b070a8cf7450aa8f831d8a91c9ae3542641b7a4ad793e232a0d301b82664fe2c7f20bd9bf8275828a2a20027d6056b211638b9b0220fa4252d058bb485dd3c4622b1eac97d54b9634b558ff1bd5bd11085d4f3d288f7965af52beaa922b23ac0207d5763c24c085076128e0ef7370eeaa19d\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -f00fb238bc9383079c7ecad9b9f6efc622d58a76f2d5d40ec7cd7c3c083c459fbcf3d128df4d20ead5f585505515aab11c36584ca622d28e0cf037419a649d598346063a07e29c61b7a8e76d1949dbce3720d45576763aa0d391b39dd6b694c7cc60a1b4f4f107d87130402985695e1847e82cce39b8d0fb5c88bcf3b37d6dbb90baf5a8553c3a\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2b809f6baacecf61198856d9edbb768ca2df2abe9b7b8ce1669fd9259732c8569c0cafde2e32d253094480ed281a8db230f84e780c6e8bbf3657c0b0baaf19ea973fd8daa2870c9d79f3695d78e063f9130fe07ce806a088ca267fd2820f10dac34b5b32aebec20e4362dce26eee0c29d2fedc1e020d452bc2499234d07a2a6e54314e3fd6dd85fe5\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -90ed75629073df816ec1d6dfedd1cdbed9239661e362db706288dc4d774d806bfacfd4b32c3013ec67d8c2af133b46989f12f809fe202d33d5ba53659bd2a9a85d3fa542de4a5c656aacbbf8899aa66ba816b809f2629f37b0444cd3a6dfc99103bcf2a5ee87790b8401be806b5d7fb7064ff0a6fc8ec769d0ccbddbc3d35f7dc4d388d8d28021c95b6\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 3f60052c9dfe0bac797a674ca7f11377a24c28a1396ffa0f46acab7909543086aee1995cf51852ea4a21ff4bbf6e7309cba9848a7b2e3b33dbe660bdc58d513d16bc709f1f2253648b46daa7aa037332552db1da81b4ab9850ac4ec66621648fc856a71eee3cedc6617071600ecbc5ac8636233f288ec249b7ae0bac942a5fd539d03990c4fb28a46653aa\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -c12fc156d9345cdfcff94bdd324429530ad8caf8afaaa1a82297eb3a8aecf2ac021384036749e489fae05e8776da0deca7e4325436bc8f383bed579c2d67a456c4e23871489780d760d63d0bc0d1d0ab41f06a091b44f602bcdc0bd4e817202e39ca6a934c0c9405adb5a14d24da895c58a81d1c7ce52734183e00d80a414ddd8869998822364e029b3f42cc\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 205dc6227dbd3adf8ee49dffd43f835882822b1c94f92cf38f5efc62f943075d80b33588973a0e0a8ff5e800ede21d394736ba98d4eedc53a9122f8c262cd09fe9e91cedfd0237003b0124d757797ee13cd03e7a3a257bd8df756940a4d22face9287edca00ca23e7d5e629966ef710b07e54241dbace041aa6d9f82687c3ecba818203adb376ec0b201894a500\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -82c30a9ef6a83d81b77825c71ddc563939b8508f1b7e44c725ae0f61006646ba9b86507ec9a4dfd3755ecd8bfb451c2d43a61599732b8aaeedff7a304ce0a9327e2333f75e9a010556ecbc3abaed02214f25e1c8373bfafc2c288ea36b8d5f848b76295a141d8f633609a6656c07f3d98177f5fa83833476dcd111aad179001f81d6013ca3a54cddcd8dc0ce7eb24\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 33aeafda3cfc20710f0b4a3d9ace4817eed80ca57ce6c82dc2e7946058a40983c9204ac95a1399fa633bc96cb10af3ddeee3ad2337c64391a42dc7794fca629e3e1e4e03a2ae24a000e7113b91c1b6230cce9592e45b6ee7984680b45aa0aabd7f56cab1a64ec310cefe5211821a75deef2e0c8e43eb467dea79dc8c03d2d523734498d079d5493",
-    "c904a2ebfd8a3a9bd\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -b897bc87a40211ef8f93645b1f6c981fa00ab3b12e117a89375400ab5f4c64bfbba01d265c7bc6f5e3a8e26de5de9df3b8f70f4a39c0eba577db5e4b7a68f751b4a69ff4a38915983cbf70dd7e066779405d572f5bbe0719c978b6865ea1a72d90d3ec8a8c146f20d98595036b3de88a7500d7b476644913e4b63e85c4e2632048e9600d553e560759770a902cca680b17\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 20604e080549e1c503049ebf4a56cf9447d90fe699a9773915b0a65588890e15bd58f55ad7b52bd7b7992a8b24704f1dfd5fd07c70aae4ccba5646405ff8a9cbf542dc334cc0c27a790c05420b552539fbf0a155861bec0e4d9e3fbf045720ea3aed58307d5738b64252a963f3fd5ecd0587cb4d7e159b4980dcb112e26c9c34f10a192e090ade157eac1d7a6f970871eaa69\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -f11fc9682601cab97c25533b2599f50edb1ac65d46f1969bd9c3cb3717461627621c8cd401a0a0b91f3645b8804e095aecab31c1bab0c26df556adafdd7e7f4f0510e0bceefa3619e26b8c9a1bc613db03857f53e9eb5d4b8f75a8cd1429feb81edc705e5a779d5f95373d2243368ce17ef22da79a6a2672496bdf629171b7973fc4659c8eae9ae867cf38d6d7617029bf59d2e\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 3cb0ffbd9ad21d0e86e4e4dab4d237e2a17d97356bdd305fda772fdd99acefcfb8309d813643c852f66e1c6c7fa41ffd44f8335ef7333b2b3e846139fa9be2c4ea762afba4e11263c0b5fab18c5efff2a18d83ee89844f5f4db2c1325f0f55e066a9e01030c07a85e2c9bbd37b5e767ebcc9b95f474ecff24df9ae52a19edeb66546a3a28980f616eb5a351cd399e5f8436f17faf6\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -b8aaffe779855c6ae51807f8cba780aa64bc22e8fa5e33f7f1dcb084fc476791565bc33eb37b4f791ef5cf46d64576f48b5fadc9f096f20c798355861ce5d24a7be1450bb871f9821099f98213d74a5e5cf83b895ae65e0e0fd096698463906a112e6e169a1cc0769df7a5ba6812300fdd33611761b6339385e1a70f8f8b2be7679ca216f5b183140e69586a27aaa9f2fac118118875\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2b7ee3ee34347dd89ba4a81415aa1269d0390346597b07444f0febb71d490a01b6fee174634bd88e8aa180409549b2726d044b4690353de2fb2294c8f69c612485aa066f68fdb89466760a85901cbc7312bfe5a6f656e67dfd2d4ee099ff97694b01d6d5b8626ab1650eac5267be53f5f3ced5dda1aa86bf42ae132a28fddb94902a515da40e0fd0586dc8b17a34af8eb03d06f70ab89df\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -bf8213944ba785e01b8d37a12de77b2ce1492f34bf6f67406cb51da89675b4f70f4d4f314f30ca8d65cbc48ee2fa1f0a3e4ac0de3a87d2c4c589b6812e850623d78ef2e46fbb555f6d3c69b211892c11a4a2dc3d8a9a19e96a07952602ed5ffc0232c140c3e828acf990e5425d8dd9ce0c1107ad1c6f96c8fbc90ffa457abab0d843094dca3c8a45ddad81b7850190625613a4851485f38fd\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 3083421e375f0722b9397e156de47f77635d62ba1d51794469371b473b71c02e3722841bca2ca06b5d1cf1492bbacfa0abfe394dfdaa7bb8787550ddbd953540e9c97631d9a1efe0c8f8e14f395c82d20245cec6d8021f8564b4d66e7779c3245734c56fb74481172f4e349d9a113cd0ee5263c69ebf746c5285cd4c0fa91d9531f769fea3610c2972ccfe9a22c00aa62ebf52b3a4c6135f3069\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -d736bce537f47ae4797faad797af8cfeaf8a4fd42df1f7e61febf8ebf6e47dabc48252ff7948f3dbf8cc369b6952dc58f64cf09b4c53447d135c7a753c21b6052a9726a47a61e13628edf0f2bdb357f2e780ac1ae1f28f211296c8961c2955b773d7dc2904dfea96780b2877af133c9591a0dd54cb20884f014f363862478ee7ec45236bfdcf0321af0692e68f744af28fbcca827ebdc7b210da38\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba4",
-    "66381056a3b92c35d9b8b71372b\nB = 2cf1708f1e675ba688c0d19eb61a05d2c8642528ea6b1512375faa732acc59ec04ea0aa55e0049144be09eae1292b6cba6db7a9823f1e912df6a5032bb9674f4f26c0c8244ea0dde7acfda566574956cdc33e4a27bcdea25fe255c19f218cc4316ae8428ea61d1bf865197a066b959c5fcbd7c9596207997d05fc38e32322aa189ea06cf5139522571661745c0d72b740dc6d842f1dd8481e318b5792\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -a9180e44a284b5bbe72fff46e55869f749b626ac33c8cb17be1fc260d7c6f460f24a89e1367112e00d0da4d213a821d09f103f35bc4eade5605bef23c5d048b1cfb45dace8b9c637af626a85fc773cf51e6602a7a5999a030030cf114ed6a4ed7583465b9303a72e7f60824c12329517c6763b0f64abd8ba2b9b26cebe882a51f05ef8076e527d53a213db910a5f42be5fb78729a3dcd08d69a709920a2\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2f26e156b3b1117f7cec542b20fcc06ca66cec03a19b6f5eeebf22b4c0fc265df5ff06fc9dcac569735135bdc142b526b295225711efb71577b10aacda2fa446f5208487c725407c2188b3185237740c813e4455a6f1dde4f62916237f23164a3471aac0fcfe24ad1ce1dd81a6144f5861ad0cf22dc337abe10fc4a88b36116dc4929602ab48eb971fdd7a5ff747d6b9e0b2bff75c59621550991966a0a19f\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -9fe18ae697576dd36ebdb621d14cac1cfdfd1f5cbb7cfa8962c5a7dace96f9f54fb4f4cf2e650dbec5d1ba89ba53d251ecef7dcc1cab8c2ff3d77903f5fb5f29a4e8e3a2a3c05c105d5733b5132f2f8d88f99d17de86ca1191c32ad8ed469bb649ef188306f69f183bd0fcc32759e4f855170f88c0a3f6745aa98f6225536821bfa056a42b37535a622f42b009859c974cabf2e14f75c749d0fe5a01fb3ab0c0\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 33ab185854b20a8126884eed85181b14e75d4ee452958cc1043b099bc16c24b9c2f3e0b792744f230013907844496e600389800e45fd55133fff0cf19c9c152b9d031039eb90da568f9c5212a3ba283f4d1353ff8ff9dd04d292c265bdcb77c3e411716f471930bccbb8ddb819ebb0e0036dc1a18457cd97f4f5909a725baabbd15e8ce33875895aa8dce77a4dbedeb0271a2a4a17f77f5920c3776caa4a75ac650\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -e7ca0c037bf8bad5f8d9c5a2737e044d9f7284c616156d142612a53eb217f57f4aa00b6daa424e6c0d9163939e1ad0510a1cd64fbd576f3e54c59d7aa6228fb3caaba7cdcc951e00ed141ac3a68abb9780bf46bf544fe0e347f677288e962fb69782741df49b27cbbe8720c6f8f2e769147d89df6e17e3c592bede2e696d384b9f01b99b31c505d67eb6193a8844f8c4cdadc9fe45dd446a0dc572c9da6e58ed303f2\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 22b76d6973e37aff4a09216e57662f186c0a0748c4375d6bed370ea61d1f6fac2d9bbe04487a629118b6b0b0c8cc4179fff7bedcf048cc529498bbd9cc81ef3a103d6cac49d58bc41c83f961b6df7f00c7171fb7d9359e03c76e4364cffae5f67321ce646e9b05f9c04aa16ea65389e940022eda6dc740ddc070bfc7e589b86fd1559dc320701c39de20d54d0483fdeef6c4fd012850630b982c2e243ac1ff918377ceb4\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -e6e4d69a82b83e26ef8ac0f4c3a211153ea6655b7ca12840e7b866510d114693049c5b8b22c3a097eac832bbd1986e60564298e54dba3316807ad64bd6c18903a0f22660c9e8d5dac180f57cbb90b176b842d5b58d6dd9f47499a037833a92a18f397238a8bcdc4afd129382fd6d200d3d267ca1e6bcc2cc65950831cb8e30bcc01665c8149b874c9f11168153c187341afdc43e4d8652ce4fbed9f9eac75db40d64344ade\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 319a81f052db21ee213c536db2cb8a71e0dcd0a9b2ce780a9588c38b717c5e487a337f82b5223f638fb552e92b826192e6a1c27771d1e86584bc6c7cbc5d9a6ce6edf2ea2ccf6939485959ccbf3183b40e410768c4665adf90a0ae2792fb4b5d8aaa06c6294e31893620decc3bc72fb4eb68f1e56b48e39c59abe869d07509b7564268d0b7f178ef09ef5dcde6e7dbd2a20fd1d4fcd707943dd63adf590a117ead1ad10ff85cb\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -eced809145e696ceaa0ee8f831eca67049509b31a1b15e7fc86cdd97a73a2ca05bfea5f4b283d287e49906463ef36f2f8ea23c2aa12d5534c08e9769055e04822be0f8ac85f404f5c025a6833b4115f78da9470451c852ba0f24062397d20385f58c5aca10f3f09072b2592e5672ffb989a390abf86cbce74268aef1f4ffde730b3b962df1088bf8745105a7462379ce142f819c253",
-    "8d9bba99e094ffbc4478625bc54df16c5e1a\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2c1ffbbb30e71d5fa77b5473392f95297b489c85f83013262abbe948842473154e00c86b2e354278844083f960fd746a3b7cb9baecb9c66932774b3a28f678d50dd8fe52fbeead43d8c8adad7c0fcdbe5e02664b0feb0ce214c5fa007c5fa2d08c5fe96787b95639311cc4b7eb2a7217c9c38c6d93444fa60c1f52ddae9bb2ec1a49a593e210e47377d3623cd2c4994ad9343863443911062e12233176f4a65ec715b3c9731c4a0cec\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -c3bf056b905c0392a7b5fa57446ed350f325eb67d59f1784c744b04c7f4d8f5397db913407aa8a7f1dd0225c1a9673828db0d8bf3d4908ef53307131bf5b5c4c6068ad73b874aab98e8db33b0a758532172acd8b2c830d0679a8226537090166317b8eea91e8ee4a7282c0ab0ab6f2b7b63d728d22b534fdc88294c376a8d036ba9a644c2489bcc84f6aec83afbac08067a7b93f3897f8dadfb68c327b751841927a728faba47dc44ec4\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 23fcf9510caa531a304eee8d0b2d49050fca83abbf287b6b6dea06501c5afc6d87d2924df1d45b1bf6c4bf77b563a3013cfb4ad9094f8ee9892d33f6ee1c70131cd5721c5af804a9da7654510e8591aa185ee723f8caa78046d9e6fbb891e6024d2ec70110ae61c3969995e35941d2c7f3779d5bb71ce5b693bc9ce4b087068adbb554acc4ab23624e060f7cea169ab512a06ff3d2a36c2b6e3bd9a75f1a9ad30a6a16b0256c42eaff2c3f4\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -c32d5e643b12db6616554116299c1da672efff1eee394378c5e9e5f702ea4ad64f0dac8904bd2751d2cef91adcb283599f6c661967dbab27059e94dd50025489cf74c6897a22e95013669aa3063fcdd4b73aa6a9a1ba5cad3956bb26346e22df6741cd0ba1c0ab87fbe74035618a394383823216df47b910cae495b8fe7ac5feb3b2cf0d0ef6c75db477160b75324db8eeac48a0fce72b9abbd7079ce6f529a89025a03a3777cc7d1deaf3e4a\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2a8f2c530342bb6ce683a760540e956a1155c0fe065476e400caec59861ca97ca71e51a11b3213b2baea1a41a29449998778e0f533fcc181698d293f05e28bff2750ef4095170de98a19a36ddcf59a65f3789a3808ead51680245070262c9544e446f23652eba47065a2bc4701c55378bd49733619ed2c213f8ed12a4a317c465f37efe07ff2df8e88fc33d3eb42cde9408dda28215702bfa607030839285a8bbf89b5e8842fa7d7f50d83fd4ab5\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -bcd2b2362aa146cd120b729e81c98ae598804006d046a7ed0f9782baa10a85e37c7c22288dc61c24830a1b42b123d63779e88d7555028292fed5ada1793264b35e961b608bdd7398e421c5474c33a65059ef13787e0cedf4f8f032beac48c4b5e5a67417109142a43b198ab617d1de1a38d6fb4922c6ef70a5aad3faf6f8d5da3af9679c94cf61ee760ba792d2972376425e2ec9c4109e969e3d9c3dd90cdbaeaeb7382cb7bd024b75a1fd6d621c13\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 3940430ace4b5b87bf4baa2673582db3d27307ca4cd8e55e976ea3e10da72b6deb7de932253bc9228c85cd4ae7766cd0264004c658a66d81e60bb9bf4dd66e2afe11057b7f7b53a1ec222510748be53a93970fb056e8082631b2b77413fccb6e61cdc6f224b7903d75345afed8a4f194b4bcedfee1f16dc256c2bb9f4a129fab6a9fe752895a93937a3d087ab7ca212991ff34f1bf1c55987a574674af43986312bbc3bad3280bbddf4ab0217440f851b\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -f0dc20b88450f45381791e85d080e4f2cf38837391e16e608b8cb5e0ac0ca75e9f72cc04bf2f56f130d46aff31efbabc0ab14f0c0ad680d6899797297152be85ac012644c8d0927b5b6c70dc3e5a8d79ef92a0873ec22af3d9683bb5db1ffd5ebfb698c5ea64cbe2b6a8b9f14d4c18624be1b78b19eca14942ae9542012692cd0d5289ebf75fcf5486596f92659143e9f952af3622137e633376fb95e628055e0fb1ba3a37ccdf0af69a4c0d6b0793078e0\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2f2135850715f623909e41a745eaf7b37593567fa8be2d1ccf76d10b93a096e244b91d8700cca37a2ec1bff7c3d21cc3211ea8b03a3594921dec32faa185e7f3d9d17e98cbf8d881fd2abb944181659242ede21df7e5e8784f541cad678df1ef6ca4a5fa91f7856c62fe593c4d24436810cf4fbd11125bcb571f6975d82afeb81bd0c7700e053fc175fb5fc7b329c438479a863b8d5fbe6b4436b67355c51d0306e8847a27a30c9e61f0e08232673cdf0ba4e0\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4e",
-    "fb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -cf429f101a2e19a65af1e238f6745215cf476ff2609c846f10289f1ef21b89af2aec53def3f4ec07ea42041f8b5862dc37fd03b2df12adaa8c9f1933cc69b526d47797b40f49545fd093b8ceddee3c55721d1fa19b336218de0cac56d410cc6cff4e620578cf820f5cdaadc367dc4d6372aab1e0ae3831a6d153c14920b1dcf09e7629b7442a06385420d79742e409677e3b82ec58bcbfa668ca072e981e20728a983d84a432605389c855a6668e0ee0d2b67449\n\n\n# ModMul tests.\n#\n# These test vectors satisfy A * B = ModMul (mod M) and 0 <= ModMul < M.\n\nModMul = ae2ca2ce7addaee2e2b7752e286b2bb6a58b51cfbed5c924f00398e59ec36fe6341cd83da43a33a12410f45f6228079c4aeb3912be87e2e81fa1799151bfa0fea29873097475b2c3efa312145d0bf7e51b2a7c9bc961a4f4dcf0c883ff90b919b87c21099fba40257645be31f95a3a277\nA = 6b18497fed9befdf22a01d988d34213f6687d8a96e86c188dea4172e7c6095a0d18d3c86c0f5a1af9c6e3aaeb6baac2a510930b3ed06ec78ec2e12b\nB = 1a058d99397db0d209f01212dd4023ae01b15da04fe62d1f76f21622b2695558c67d706c535ca7f19b36f8ef2d508ffd6cf6fcf25e5\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = c462c7cdd79b7604246a0cd97b40ea5a9a77408f13cbb548b56ee713c690dac0507fd988bf28e77462832f4307b08564a51510d4a951c1ad7564316dbead2b53540090827a8ade8092a6133af0e5fac7310f787dc1472836178ed6992b9f71224da3e884bef8e8379a58e6d4be0fbaf59bc520f786631857213305e23fd5ca65\nA = 16c92f77c139706430f396f72ec7adb045745cd9f5899b0074d9955bd32de66f57c05c7929b575312a7f1c04f19e724d64744bff7b31ad0e6171437763\nB = -8734c4a2361fc530f60b28a5f1c7e93136c5ff6bfc7553965eaca54c61e6befb3c0f8cef4280e780cc5940d21a740debba31f863ded75\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = c462c7cdd79b76042469eb41a7a83115eb84103da4ba438c3e33227631dc185054ba4e607141d1e60990d8aad4e0bb0ceb645ce9ccdfe72d4738cbe1f6a73ed3e070194fa4feca6001c4a853940a227d15c1f1cc153d8c96e90e24805929fb11e0665e0c41c77d5a97fc5903a8b215360e26f6a19922d650f460f7056274ee92\nA = -6715098ab2ba3ea1e6341e89936e3ae913cdd450dc831c8534071f3c362841e47d88f2cd29c0d1239aa0949f3685f12f8519625bbf10b2c7a515e6d00942\nB = 536d4b3e4815ae5ed55bae6950f5a8a61d52439d2800ef1b5ba2285b85ed0f6ec4af9fa0e364a6b14f6f6b8bebce9200467804e787f9f3e9\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 309b3e30f74c58beca8b2c23f64fe1203830db8a7e306e1fa2e2022f0d6d422851da509d1b2936f088f0e35effe12a7463f47ca369bee2f2980bc48dd8e696b2d8c6f35cf55fb8baafc2e613b4c684de26129cf196741aab873f81e498b1e03018a539b5eadffeb5953029f31f8579df7ec0ff3f752491910\nA = -11fec955948e007b59fc50e729941ee9d43d552b9411510b73f6b4faafc0465f261f8381d96f647267f72175883172918b5c866cf1f1ffc43c55f3c96a60c01\nB = -2b3792f39499767e0a8b7a6a406e470a78f97ebb36765beab5fe52e95abf7582736db72a2ebfdb2405e3954c968b350a459ff84ef815dbc5910\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 9143ec3e9f74a8eec476cab17ad8636eaa7c60e108e89ae0702dbdb2b255a217ba2530c6fd52658cd931b962054a9c20c8713976ef3b7989c40611cd25b0a9ad0635d61f6dc95dba6e0c4a7d53ff539b623b97ba3d66344fa324f905abb861c6b1e830c4b0fd5f6a4b01f09c8e1408941291b2285c4625267a108c\nA = 7713413d87f1e50840255927ff27bad79e5de5898725a876e4647913158cda9f5fa031dd7fc11d2e8130a0ba99e8706341c1a98d5fee3218763ceb1d131e9cdcc\nB = 1384e60753dd4bc20cdabf398525e7c4aa40065255c5058cae0b2ec90a3821bea8de672a712431aef5864eab719ba621cbbd8b46fe86fb31286091\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = c462b3b4a0432890d141c0f46a28190a2e30ebb2e4ba90ed132169cd72316b290dbf5c261984d98e63eea6525fa890bf52185ad7f164cf49f67ca91c2f35511f3bef6eb7f3da31a602a78e4752e326d79dea729f4ca6438f2aa65eff44bc60979b42e44f6a301cb5de8fb42abb47bce5633c6ae9479d39c9e8b507d96161e0fc\nA = 17d806d7c76aa8acb051fd9c0c782443f1b1b6387455f7cfb737c41658d0459bda5d13587055eafb87ad8d209bccac1fdc392aeca0774ea48799511c1fb9141cad2f\nB = -d7c9b6574354e131de4b8643d766641e98554a03238ebfce1112c3da5f049d6c410a7f05758571aa2625f7190b936a214797570539317b32fb94cfd8\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 16c84ed15ec6352a8ce6d5c2bdc0d9f13b333072fc7041146e944a29391f83e346b8ac0bee6dde98a420ba4f8852801d7c5bea6f1177a6cbf799edf2146f8297013e0e796917cc967786788ff12d9c1d07d9ce4b897bd22a1b8a391d3b4ecaa5b5c85d0a03aea5145db6350c42a964a41ee5f83e7d35e14cf442e5d99ccd0ac8\nA = -6d84cdf18a2f53fe496248fafef183914d55c42267af3dd42a39515e80cf29211fd58454986f5fb6afb56170dd9865d3158249090270bb9af341c830522a4dcabfd494\nB = 6f6f3f74187b7d74dee92f79be864d0a2c56d4bca3283742e9cdf15112c8f4208e3ac8ecc98b44b4ad74b0671afa4aa9e48dc31d34224a1f66bb2b4658a\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 8fb782e4883ccf3aaa2d3e020b08993d580c69ec8fe66ecac152c5babc8aeffafe406736cea492450fe6adc25dfa2e12723a3f9baeb02fc0f785b3db760ed28048e1710a78a2ae0c96b67c109c5034375a512b6fc7906847253f66316baa0ef90facc9ab992235153684d49d6939ab9e91086529494d7386f604ed69aca2f53\nA = -1f745c8f0c8fe6ce3f893d77fb274c61b72b2d9f9c5a2eb2467bc00d1f496d0ad469d76bce318bd64ff1107ee5fcad4469f84d658586a5789c068b0cb9b866d8fdcbcac5f\nB = -3a2347b491813252e8ebef1bd181534b074a368d076b8c80bde2e54ec3b4ec99001f43080c7857427e069d99b1b65cff998a141ca6963aa5fad1ee632986ad\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 7c0c1c05ae1d6420bd93596a01aa0153000ecce660a8a14d6fde7d4740719cc495fe6681a9a08163b2dfd51659b3ae7db0fbe09504370bfc695457d7b32665a4df53e879ac817bf715d5bd6ca0e242b1ebacb1ffd6698ec90c442910a92b35ec103b345f9a9e5c7b005f8028da4dde80f36f6f6e5675040d19e46aef06040eb3\nA = 4c09264420a9452c6f0b55baee42c076aae5a73697cc6bbb88b7c922f236ee4c18e477f88e2c40cee03f0bbe87d3ac8dffd75f635315f856a3881c6373e8b9a286c813325d3\nB = 10474ece7ddae5c53c4df5b594439124370932dd94aa5d5b4ddaa233b1a55634fb7d72e33bf1b02965fa9d1538f97e1cdb5ec0477cec8ebaf202aff8533211169\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 481543f1556df756ae2e422ffe35aae020c9bde9e9b1f760b43043a4654de363dc67f381c0df1c3c1b90edb4343c47ffb8345a1aaf5dae56f446fee08a0b9ee8c42fff57143e10846610a9925be96418c4c957b4e92af734b96fd6f21974877dba52a0db1fec4aa97640e357434f95ba74b6b8323cbe",
-    "17118dc489552844602c\nA = 11bccd165d9fa2d8b01a48c0ec549a6e600396cd2023f0240056193ad27e971c604eda8aaed6ff6be8be1001f3dbdc8655f1ae84eceb963938ae7bf428eb5c968f584798c1bd8b\nB = -cfb6629ddfc98a242e3290959f4d0726c0b1770b52393bc7488a471a90f7f0951362c03e67f443c9ecf4987f5303a789bf65e0fd59cc5eeb9f5d4f40d3e4a14080c\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 2a770ccfbcb2bad207d0e2dfaeed04b6e7509daef00a1df88e57509451739a8a0f15106ce8b53d280a4b4e09900420714cb6961ebb0e00e88567c5df50d2f2908b4bf8e0a9a5a8b3c6120503c14f16a99297459543c467dcb67915e0a10e19f72ed5b6891a6121b66abaa602818801d3306630bb04ea57e6b31b2c05e368d398\nA = -442c80289bfbf00db06eafbf06109b55f99786a323fc2c6db5686f99094cc24aef50475841243ec3ade2a1e0ff28b4032fd8afb8bb5e28f3b2863bdb9fc8f033adbaeb5f2ab16fe9\nB = 6d43e3c46f4a55d49e78f40d34033a7f5fcbe50873930e7c5452b6b3b176534e6e70033868c85b4d63052964093214dfd0bda6a84e893b1aae3cc72aa83d039e51c014\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = ba0e8c91a86af1001b13deb115c77609a1e7a3736a6b807255aee898e3100f469ef6222be532dedb1b8d3db4b3b55aa4b5da5629c83e9b2bde76bf2f2a4119a5378b5cde000980b3e58595d988ff776f0388fe025625ccf368e20914fa90dc771c826e4a836b2890e82ac2274471d586b4de5dab3278f0e70207562ac6e6493b\nA = -14be403d28c8451cac4dc83fbf895a9d2b74f730c39b0fcb33d7258f99211dde31a78f182ad1d27a559031d67d6f2f94a741f141bab80fc692afb452ee2d502099ebd5760ccec7f7ebf\nB = -2742dfd02134594edc6d3025aba5ca4a34dfeb43821ad84164510b43be4fb95748f8d0eed7bbcbeca14efe843fb676882784bb36c889be29bdad9270e0956286552119561\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 20c691d6544912fadfd9894cbfd42745991f39a29cbe3a1cdd302bd0487bf70c0179b9579b77f8481bee13ddbe42f32d734b6118af92884c946ea8576f6dec867c1c251c73777cad7c7c76e90da00ae07f96c8d6a751e5b18157dac4468c05d32eb86e74e0e8312bef85905af8193a3f5c799c5875badbc9eb7ead1258e56d7c\nA = 7ae9b4d5151b11bb7bd4d1569a6f4804f3b4d77948e0c6300e4f28d51c9a0afed2ae7503e53489edca5359e2b3d0c82a9cef316cd7e1c1275c31fc9c51a8c1e5fdf23935484e467d6460d\nB = 1f46f88d39fbedffa8501fa1268bdf3460aa98e12b629da59676e61852a4d3f8c59f72a2fd717fe2faa09639bc651ba516cd39297e0cac67444ec57c0db47c2a4e250033d02c\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = bf21b3cd55c0df8d4d568d00f757b10ef3de782ae71b289cb2b59d36df1341382bdc1825ba13199f2cf279a72968b3bbf5f7e3d13ea9adeb96d81132788231fd988eef04828119dcca21ec1fe844998909cc95a8d01720e883df27f07ef4dc3f09081015dbbdf019b96707c18b0b1db6e689e8f86466a2afea4a9cafc576e10c\nA = 1243b14aa3d16a55935f6f8ca49295e35e7f75b03de7192e1e8a479abc0a430e0d340acc05eb9a61a5dcbfe3ce3a4c5c940699f5043e924f282bd21e341edf8b7a6741c6ac72d7587a9e7a60\nB = -bcf08b2153e8ca911096189e35dbdb21b77ce89685484f574c89f1747612f39340bf1b204a23530abb36b2c5e195940b86ef1252d6729393c25d4c73dd434b6dbc3057b05d3f15\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 460539d96c07e72acba5b59c88fe904bf7f1e1648612908444b0b08172d05968b31b43456918b4287dbe01afc3cb4860d9c2fe549a580c989b6507094f6c241eadff910d2603f747f8e289e7a8176ca4a978bba89288a4cf875bf3e03939af966c54e77c28119a39d34a2b7055465f58ef2efe7c82ac547fb675653198e4b504\nA = -5a44cb669c055ba7c28d49f84bf8d12179aa30bbb9db2a48d7a6b09e44dc0e0f7471e3629cd2fb51e5a53346ae025fb49f9591ed1d71bc79daeb3f1254342d8a2b091ae07a758c1555efe59e78\nB = 646cc0f766346aaecbc5147a4488ce157a6d844045b80884eaee9d419087285fa71108b5ab4a05689aacc8d2e3dd0e6714c55eb8f77487a3fc5e56c3c2df0c4acf28a457051118560\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 79b536f4f30f9f7483f90e65e6456ef8072d9a7430405cf8c9377ceea2c676afc338837643436d55ac6af2326ebb362684bccc5092367209822581700d641cb8d331432b761e4c6e22639a27335f45a25ec019d180fc53dfb53d69216d7cfaeaa07db8288adc35b7bbccf2829631c1eebb821e4d3299015c3d462dc17aee5024\nA = -167529b1e8668938ec02a68bf4d76c22dd018c41e19be25e2f821f63c2046085d0af30d8b4212ea0f3f9943be1c14fb2d2a944551107cd2bbf8dda5bf258957325f06277036282977db4575b0deaa\nB = -378e1be10a57e03b197bc2b1287d643ba6d89da4bf6a6170816691fb6529c602eced237863ee39659be3729825f032a57eb5de0a87b0894d1a1244523e85b6f50a3d9976dbb038490e46\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 658169197ddd0bfae101c10c3e6a2b10dbb456048e81160b47b197fef439b1e0ed710399cfc80ead8e436f1c0399064f92da50afc335847515686e055fc7bcc0ca721184435955b896b0af4f4d96672ebed2f154538d49fa507b945c0a6ae926793751231980274213c80046666c28ada213a2f87509d1466b8d1b2122e93f8\nA = 49136d37ae8f3da71a6114327833e8aaf3dc8b5a9a27e9d04c953988456e525263f86ba94397321c2093803b789f8db3ed7cdba19c4b796500b979e02952e1625246f8e977e01fccc133f94cb22832c\nB = 1dca005663385fc00b4fd58c73adc7589d15ddbcb8cb2fba03a737a320c447a2b21e576ceda73811a31d8277883fd31e22f776bff3261a098ecf8f40f2855b0c723d1265eeafb43f85323e3\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = a49fc8084f3e780537b4038bb769b8db3653a3315298a99c2ede6739a1732a636e9787f2e8b09d0b9bea08fac43cccca71a315e6f4a7d6417d171b4693dbdbee8cd9f95be0847ffd40ff027267125d67b89737e1d0365bef6c4429504d13cd8ddc7810f456d6293c0c57c14a307b94010d79d5c13b92a907f923966fd3c5c8ea\nA = 1e7d8de2061cca59d1cc19b356a8fcdf2ccf917e0d81598f014167c5a8de027ccfc8f2cb8c37c396ebaac83ba862c146bb2d551d10ce03de9528f97725804e8a6de57b9d9da811200604c2a032462b6ac1\nB = -e38592f3acd75b575f64ced439d5ef2377d21c61bc70625639b01bf755fa2c6de803ce155744993493debcd4de40860bbfcee86d0b117d7f8c3f8ace68b67cb6fe7a81a145535553896424f7a\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 5a99c8a6afaa97d8e7d84f4899803c7786b1bfd2ecabdbfbb3bbb92247ff91ac213a72f6d23c24699d60babe91a7d9cea751e686c027fa1c954474fa5680f0059118426c71299462b11de5f2817d190599cc4b352df4d2e80605f9ad1e32eb13712d3027a2b6a19d52151e37e7fa057d8fe59dfc8a943a42a1756a38f103a75c\nA = -7df29221e6a102e32757c18f87927cdc90ecb012ab0557e0ab855daba832d76ddf595b9c5a62988ca968b64fd5bba2a147a5991810c17cae7edfde38bdbb7e13a1fe5206724c05a9fc9276c8d4e503a860c7\nB = 5c586d1aff7dafea3b8ee42e0e8854712c95385374b5bd1fc8ec41a72b296e070940c4160509a4a1699a678533ff3d12299338fc441b0f01e29a48677bfc5aebc644555285756e97c74e1af6aaa8\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 21fd2d881b6a52332dceea42664aeae1ca110512c13bb33e25ba4ec0f39f80eb73b1fa08",
-    "34c998c23a2453dbff971eadb183c51a30ba78d593f23be9cb6b2b33a554ef31e4a36e0314fc2ec889f18debb956b89d1bf8172553271bd56d89ed0b30abb70e68abaa2c76f73cd5a3de93433747d09c845b5f8843f9fdf9f6c975c8\nA = -19fe3bdddcf08190a037768b77666de803ca4f7f0d7dbe6aaaf334a486dd0da7ca024d1b3df11e0406b0326595a171be30b04574c1a7d04f4d2ccd334663690fd20e4fd168386280510a00a70c1a11e99483048\nB = -33b2400173c057980b0e0cfabbda1a5cb5b83b7ae80708c199f28142237f04b071c6eeb63d42e80eec04b76152250c9e4d4c4f19a048cb9815dce6e66710fad1d27494db5c31d9af37d2aa779d12d7f\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 1c45cfacf30682a876cfe253f05b393a2cd4dc065ce73126508ce897a99a723cf5145187643ee62d746f6edf70269ddce3c348a1432316286a648ee9ac31ef87feb14f25c42f2dfc2e84bb5bdb4ec0124e249c526c55ff2cd0ae938555c5f86d856eb181572ed01dc045f1ababa52d249e56aba0ecccda905d7d1e64bf89bfe8\nA = 6a40d948eac2fe5bf6db15d7f6b89fdc0712e32d39a881c21859e8f7722391ce05973efc7c40e2c0d7f56c217d8a986bfdb08bf87bc0435873cfe4d01967c46f7d39464bec411d0369f6f5d1d83f42596fa47451d\nB = 12529775e8253ba220d890d4912fb95f91e4edb59610e889431208b6bb42b089cf2aaa12ff9ff98c2482e7f4cbf35b22d15fa28aa288217bf766e937a706fe1e600143087b0a67f668cb7b762c9b9f38c0\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 3b3b08e8eda8be3918bf648227eb0d569dd898729d9cd54deb32b1a1dc69cf7b2c4184c8ae9641f0f75950df263a5e236f428ca86244e617b14a04edd0f31c02bd4d84f25bacfcd4a2786825f0361251475eb6c7e99020dfee4298a1f1bc260d4e364a332bc6f651dde7ce5026dbeb0e5aa75ee98874da54c7930108ad28e3a0\nA = 149d36918fffa682cf90c4d3f3d48e6408e7ddcbeb44e78b9cc7fbb08108f65215761a61d79f37ec8f67cc51e0a9b4bcb3834b0ebcf6734985153f29a2778473b80147eddc813b4fbeb98843f5c1ae6cea68f88dbb4c\nB = -ca87f66182e271a69c0964eda92a009d438078b584c3eede28ce1a501838c5f497186d305c09922f32ba858fb55f2a0dbfc9cd0f93b789c1f800cf092726d6d33db19e4f26c7dfca69b83925db14544ebfe2\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = b199655160d88b6b4157ada0e5675f82b33b5592408bb57c46e2f7d8791bfccaa51436dc3b772b83e907c20ce7edc2835ce96595b78c0647d244e9bad6f4184e0003eb0899e7a47ba0be888b9bf795eba95e5073a85c4d20416fcd4a8d4e1e16b403deb38845fb8bf9e9264d68807acf02d579e8cd104cf2bd555e6cf73d0450\nA = -70ccbb73e33a7cec30ef2071f3b1f2e008e70fd6d00fe8b7aa4b9146fc6d0549c57d984cd014c7e0a4ed6d33376998b7c2c9778fb9580d8ca4ba795c88612721c153c186740c58df3fa63b6cf7a4de76e049217218c05c\nB = 6cf4168d44a8da8e8446b4420466fefbdeeaf9623a40e10b77547687b25f36916f2c18cf6060c03b3b40e0959479f6aad5e44dcff0ba799262ef53e280f4a7f667d262d472b2e573265774deb5ff8f25dc1822b\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 6ff91af444c61d2e2fe8ad73bdc5377d5becd55074eb60f0f98eca3d8f4be8c02f196b3afea12c36f78b78ae6a5ab677ffb7d9c0bd58987cca816affe468c7fb4b56055f5d2326532d6ed1c00ca2d052ecd103994e8929bce04e067082b4ded7e1973566f99c514b4e0d95b9a8a931ef4f6355066940990fead70208a63841f8\nA = -1c924bea12ad6f8b65abd1796e381fee2cfbec15138191bc22d57165928794bb080c83878fa5fd19a5d657b2fa91165459966f50aabf19440f7d75f027b32e999ff4d3f7a7ce878fe0f33a847d644d86ca19713ca9968d97c\nB = -3abd4b281b8f25f5957d1f2fde904457d49a3a7eeceada26b454ceb4ae0e879135d376571f08b5038b7b3d73a9a9fecbe265b72375756a715a523ba66737085e5ef7a4ad988155adc93eadd5d95a0faea56914983b\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = b9076229b1a1241e8b4da3fe143ac31d060785be6ac1e841c2fa9683d2bacff2e2b5dbac33f58b0b1718ad2053c37ee55ea54a9d258ddd8930d2784852844d85db24e4721762839a5c73cfe588efedc8932ccfa585e1b5975083919be9e32a86dbdf5cef84d3d4b2ccaf7a006c0cadca1e35fff2da9da7d7e779494d8f85bf4c\nA = 75eb0fe6c07559c2b0c7b2acd7d29b5798f6c4cda64a504ebabdf54bdc773ab28b218f0defc040016178958d5561796230b71edf49bbdcbd3f14494859843c8ca7a0f777cb05827f2839f3982832f4f3e3c5e50af17ecebbbc3\nB = 1b8aa718d61447003fdbaa748a9d86befdd2675a677cf34a1be7c81e4577f665d71135a8a243976a4f6ffa1636695567bde522f8fb1948033a7e0941f833d827e957781cb4349a08c6be418befc8959960fd5fc1b288c\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 9df82b7c34ca97a3a5d4efa28d5ed4f35484914dd73af9090c4bb31ea3496ece8ec650f4e7b07dc779c97e597e76e43cdadbfc6e72b61ea718c073be1cd204f8ad2bad0df1e530e75705f3d3dc285e9d793c8d42f04dc20773d3fcda8ef3ac1cb10d33d20a91add0358ab8658f49d2fe51d0d2d72684e31c0eef85e5695bb4b4\nA = 1fc2a171445ee6add5c2e4d29e50b91d83338f8d63c111e4d3e95f16d2a33be02bef24dcc3d6ce6bb8f1ef980dbf8fed409a0232c0566153014eef840aff58ed8c33e8d463d408f93e2f5381a26fdea63676c4e5397eba1d39f928\nB = -bdac7a177c77451104852bb99004ce8e617036906667258d85adcbe8cda21ab7d03aa7dcf62cb210a9db8fc750c7e1ad290b35473be0fd607fcdc686de0b78fd9f258f5b25e2ed43c2ad1a38859f882b9f6b293dc258659\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = bd9f3d2e8a1086b177698f87a9860e3a5f030e04a0bf4ee9436ac55e005bda01ff4ac662cb85d39e98a41c723ae542a83a936c3bd0280c6801ffda080ec0aa4230b45dcd0bc5eb41cfcf272028bce3572847637a92d1543bb2b8408e880f5b776e1cf14fa28d15cfb584f025596ff10c9f091c837a3aa622d9e5c856db8ac207\nA = -7fd5357cbee7c5e31fb62ad03bd47b705b574d915200fc7f1013d836b9cb683db020b152ae9464de6aeb8baf14999ac7025dde6173fae6ade325c60ec310eff6dc4130a8efffb15ddae90d760cb7f76a27d0368175d4a44a22f7f223\nB = 5894a0223e4aafe4efd4572752fbde4952c8b09cdfc35137e7e6ed650f8fdcfce9de673853dbf73730b159b2656047e69377d7c5025a6b346fb08831e64bc8bc34b75765012460d8135a4f7a0f41d768fb85abf17f5e2f5c3f\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 2c61867bca70e8662c7e5435a5aec020faae86fb079b992bf49d8497fc5f96abbd38a6f04f6ca8510e0160e546b3f68b7baef4ef0f404e881771cc12ec5ed3e3787c2d2ad6bb957cc59f8d56f0afb4bea49cb671cb42f4e8a0ee1dfadb6fa14f84a5b3269dd33e20d658ea4cc39499c7a39a4b5650ad7018d32f97954610f676\nA = -1bf5ae15f24c7c14eb59605136a3f679f303cd5b81e4a27465281d17715afdc2c231d7ccbc59f80ad176f4e0326eb757b52e3695e27c6776d7936da47e3a8a904f735b151422029535045ef489e61ec93f02e6d588491c8dad1cc311f52\nB = -3238dcafb85ce557036d19e42e7e7e473de9f9da6f920e18845dd010546868d2652decc94596cd2c36bd16b02c02559892b9f573bf21ab18c3c75591413d046b385d08aa66d849ab8adc9fbf788e837b047a7ce2b9c63f7fbd263\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = c1d04b831b712d0619db462c3f3fb5973f5984e9a48493ff273a5abe17a548e185d751628899e2851e425a7d4b2c72d4d908dc813cd122b8f497e08e299dca9166f19752ff8cd9840a70155ed9e8c063a3840838b3679f96f1cd5f1cbf0e037d222029e02769dce7fdaea0bbb5417f85497d77c76a387c6b970eac15dcd128ba\nA = 7aeb60c134e84f289e419b74f99a5ce",
-    "5b4aed5fc630d5d591ac7643251ad32d6ca7f052fdf8857f67138262d221de644140e9018f7b84879d74883f8f251303f65e06bb52246ec6a912772cb698b47de41c1826ddd065359f6b9f1ccb0cdf\nB = 17f81e53d9fa6201e4d3eeebb32267929cd5258d10f053e7c021c4afd17094f8ecf433b1ca752f8740f6d6bd84f801b1b9fd64bc4787b9ae5e5aba0b4318a63dfe27e92d5a3ade192af7563c74c9d6006ae7701240efdd6021a83cf6\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = aef89874854ed34deae1b77286f9cb0e3017e3ae77fe050bb244acf4f30dc03504c73c1a4d44b769709bdb53811a5d0f8a76a08e6a66fc2cc4e98537ad6a8049f02494305b89a49a55e71fcc3f5fc42d6b478456ada9b19ec0a03f5ccfac5538c0040092771660312be5e51996073ff1a506d7460c57d54e10dc2991c028606a\nA = 18d3af14bbffbfcabdaabe44074b407d69abdd80a6eaa5954f0e45fac85af7ced1715c78da872f7a8fabaad3207e31f12b7195cdb25abef0a1e54d3b13349d997f207fe130d7985e2033cfec899a0af310c9827749cd22bd062eb0b1faa254de\nB = -85a7d9f08a60031e689b0e611d7f7f46e1178eaa2e6459602e738990c77f4d3783ac43fc04d53504cf67fccbeb02f9846756f8e32fa4a9316b6d3b45f644254077bef096a72bcff17ffa17070a4355121cc5daa2f782fc0d0bb48101db\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 14a85edc6297763547702c212b1a8274b8f85d53ef35cd1b01ed51039bbe030d0a1b9626ae2f571a43f1224d723847a1c6708f2238f6f6fd75db6656e6c703a5acb57f69717efe8ed58a3713ba2720d8c001d026d83de0ce5e24b67c41daacedaadfe404aaa9b672f00562e6901fbd0710c4303fec41ee3338100beb36c9b1ed\nA = -44414ec207060d105f599b9a66aafecc5b232b55214c1a5e1922f6b59439b3ff77cd3a327bce4f7406871196b90350e6dca9aae147ce03027dc4de7563c734f111d95171f489105de5ca80047cfa43f7e932917b816ba7d41fb95b4106745d700f\nB = 45f2cea1b9b75880ac3ec206740cfe0ecceb488c9155cfacf5885a8cb49be78af8cf221ff8de2328f4880479c031f830a3c9eaebfd83f7de501b7c5cde03c4720c56a676d331b2a13c4689a2e34a43fc11f62825b8776e75d31225ca7ff65\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 7670c1e2e141d8f8f5466de8ae2e0ba2eb3eb7634699eab8415d3a37f8df291d00def88361e9fb64a2f116433dac3ac2764fd62f3201dce4e48a3b7019e5465f82241ffda29d5eb0462fde74dea3168f8993ccd4d090b9c31a5a6cd7e05f725bbc89479836b89379b422250ab049f31c860110df5ed69089716877fb0ad7b0dc\nA = -15b4a2f808a85a5bd466a342c4853c04ac0ab73f8e53a4a0477f73dfeb8d7a911ab2eb5d3d192b9b084d0e38db491148947c66f838aa5f460c37341b129137614259efa531c0e6ffdf163ec6851737037a5299060418d96da035e6f583e6ba79d0414\nB = -3e94fdf22004384f7881875b1d8f58019ed8afb1b6a31f5d591e77b0998f3100b34174d6f3466da44b4c7fc8b92ccc5679c26c146b704198a65a88554d24291adcf897bd758a035361f671a82972b5962002c6a828792980f86a64547165327f\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 35b49beccd8d2010a8d777c1ff69e28e01a1bb78c6466e717f0a934bb62f9bbcec5ed29f9cd2c14d240a6c33b28c986eb9c8912a4927605532483dcfd31a50876e1819f3d7a0f49bd276ced5c4110470244fca52d2611ed7e31cd8b73e749aa70743b39e92810b3b52320342a65cad3180f6e2966059d15f79e5574348f5f66c\nA = 6fd078e3cbcda6a71a710e99204da640edc71a65974fc765999a74ab50a0e4b090d57ed0ee869c8da2cf694b6fab56e87c4af62fbe73eb8890bc066ec3460beba04dac3b8fae7e4f316e8f954c6e8d934e946dfdc9f4cde0f26bb3d40d5c444b03bfc65\nB = 14d8041a3b83468d2f44f150ad8d8d0a1a22035d630f2a17b70d5c3d557d3abc7e4d753e1ebfb3a3ba465520b84746073d211a67e079ec7f47c2cff9c06da69bb5cbafcb6cabe7e0018867c42e07931d6797d4499463e3cf786c6d5d6c8cbd600d8\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 2f6e0fed8a9720fbd83ce950d7545d2c6d5b271582194570424f90309227a51777cac974bca0ad3c1289ceb91cf75af73b0645cc20d71e7789144876b8c1bdd550328d9907accc316189e8ad81310848cddd2dbe362c9398d814a048f93f9368fdbec0f19ab87ad2a59d4066d738c3da3cb71d4716f2cd2336ad35ea1438276c\nA = 14bda9e4aac85b0ab7abece728f61450b7779d3b5fb83be813758e742d2ad76597f132aed91e20a75c554f0d61ec4dd118eb733d04942b2548b1efdb4dd22fdb543d9bc1e4bf0574ae2cb2c46fb98cc4835b6a074d6df1a3bc5443beabdc784d542e3349ad\nB = -efd765f8ffd72d041ac3244078b8dc4482233e9411b289cbc2cfc26fed2cf28e286835010438ddc9e7021ceb098b10c68bcc4732608ec1f4052df9362176ee14812bbf09ccf7c2882714ecbbf92bbff61c06e9dc35a368208a05dde949fa2cd091ce0\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 1f0c436379f6dff55a59093ff2a0626a9b959e3e3e59365afc33c7a7893f04bca863ec910c446957baa8de4e35a1f4e9c4a776ef41b053f03b775f327eb7e5fbe68bbb478aa4339ae703ee4b573d6931e47e09271d40239d527fe77098a7fbe519f5eda1f26dd6a7d0ee6833efe37187d8a85844690fecf9fdc3a4d80b921130\nA = -51eb34de29ba24d2b1fbeb0a1c324f4ebc69cda2dff971a315c0c2775d988b03ca29891ed0790f3dd507a1d26ead461dade9284613e45df338dd83aebfb66050465d8aee554970b43f7d4e0428e1512289fa1f9b23867b67095c455b66d536b91207b749189c\nB = 55259a1122eb7eb611a69118d3d42c2f05dd228d71c0e1e42ae3a8d3d180a95b74150d844e916ac85105805126e4b995f2ed1cd3fcdf28e1fd241dbe3125dfb3e4d90556256eb513a2f7c9b596719c83b26931d92bfd3573560e8bf054138f5d6b9cde72\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = ac321a272d2206df4dcd6ed8ca194a1049c1e3a20bf325fa44809d302170f850721c077bb5d792f86f7ab03ca259567397cc2fa1429771190bb632ac2c92d3fccf6e05e13cd33149994cda5f9c57da155439663f6a13c66f9da553f5038fb92fdba186ed9ca04b8ec87cba4c5a68c8edeedb94e38a6dbe293340dee1a4ecc768\nA = -19ac99d7d51456b00a193b3b04693c7e5436e05763f0154768db078ea5111cfe9eda3451091af213b9c8cc649d341de66c12ab2803ea39655d3d7de182a77355ca444c5d2778f791d39952a7a11839e497f5dfd8a703df49ec4d7628bfc25a992e94a6477e6be39\nB = -286d1d436f113308be594f0f43d7a05120639152b7e2f93058cf602cbdbc016512bfd23f7aa937fb358b7b602d15998ecc150f2b9224c58527c0c1267739e065e24236771e2c683957871637468181e6e896b513569bd004b9845f0f0e4c26a5ca123365e1c\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 3466804a1b7d1af8b6060aa93a4c325d9cadb33ebcc8bd991f9e44cc2cca8918411efeed0f005790d649382ec40278c8cff903cf3db177d24466c58cf6a56ffc14e595c36bfefaa2327d37f616b1466eb702f5c49170598bc361d892e18051b8233dbc5b3fd6832befd9a995bcef3b0f3beda6efaf09f7306ec203172e78264f\nA = 6710c19330d3f974fc377e28039e0c0ee0a558621fd67fe724c326537c18c66dc5eec60980e07d401ad5556a05688d2dbe7b271f9d5eda3032bf7cb7c420e7b5d65a195bc037090b6fe83064ac3731624ce2baaaa62a6eb07156ca12ee51d4321988026cff573ede9\nB = 137ca18f47a151363a3e8c52dcf024262ba525ec8852e8e406f460fffc2cf88f1999b17a5821849317fcd84d09c88ebb6eb0340120f113d7ca5fbd91c6a40cd790bce7b422552cc0cfd2a6417add2501db1667f2802e5d0f4df824adbd033a90a155cebfbe0b53\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 6f248a70b2cddd9627b32fbd130f05a604866799365f94d97f1eb582b28192959692a870be7c2614536a8de84",
-    "cd8c1364a75a3927ef9dddbb8c6c87dbf526f2d3a7916384f2daed96002831173fa4a51863c28b4378f99b1b201010581d5eabd66ad1e328cc4e647bf5e0588bb775e130b4a4d029eeeeb5852c5742862ddbc3e\nA = 1f014cdd87cb33ffee623cf454edf2c476e91df279b4f0879637eb6e8e5ccab305186de67585595d34ebc195fb150408c4620cf6c7a0b0d9695ba0e0e1d7552ca7d0be3dd678b1cce2beedd11939891a6804770f1c843e16dc2ea6aa8e4043940c37fd3d950caa122845\nB = -8d8d9dedc80994fc5db04d8c935301e47054250fea9020bde8d5fef01f2307cbf458d5afef5210a369c396287c5eb453637a2d721085af3de0d75a5dfb5dfd22fde3b229d438439af7b296b9e68ffc982efc6c825556c52a735f8be12a214a06c4270824d5268fb6\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = a35ff7e232f047e575b200b9fc4c9253de6ac04c612b8a82c275a951075eace5e7d6664fe8f78301d554cebe7b996c1f4ec3ca59d8d12d7196eb3909223de94c220f0445d24233534af1c93433b05c5924799d2c781fdb88c4537bb8d442e6bf76b2d966827bfb4f40378a3f135103513da056bc0d375b1339561700d15a0227\nA = -58346cc8a9a1e5b8babaed8e7f59415388e0db654ea7cd465d96781c57faae7a8af8e7578e46f3a8de7bd1027188e1cc32fd1c0d60be24fa3289a12cd822a6c9a77dcf8799624856c27ba88fbdb047473274e651760581b44457ed048cf76c166d38bb9b2afd3416ac7e45\nB = 61951a16dc6466a9fabae99df29b7229f1ab96b476092dca1e4f8fc8e7404e2fba56ee66486d1f27f89bb3f86f271307228d7d6cbcff943961e177300b6acec1eeb46af1c5725f745a2d2af0fd9642f57a09c9ce6742114be0aa6e939e638bd5c7a92a7c206b2d36e35\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 90b441d8277eb1ed454964acf567067925881b5db0b446a7d554dc61ae87ff979bfb0e58ca1706123453e62ce31284a5a2db1228d259e27abc7fb5cc5848dbeb9a6808fa1b4afa844ab39b652abc41423c2833e1209a1674db518b6df7ebae315dd7f416df54e73088762ef64cc2cd0a08b1cb01c49d9299d149cbe84145a55c\nA = -1ebb693ea7d18e0ff4a9a51124ebb78bfa3a4635b75a6387e9fc745a2325409f927324d1289be8a4f5cf2d5c04adc7ead20564f97e453287f03e5ab59a6133584f970446652d05a131d7d382c47b7cb97580ef6710a532dd4f5a0369dd3db500ae5a3c5efb587cf0cd2638382\nB = -3916ebc4653e7d6e0a4f1e234d765d41e9e948b5acd7ebc73cb595559c1b20b037a3c8da0a7aebfa5fd327bdcc922551cdb8db3fb0a581fa0620ca2d2559ccde3ebc44542b4d80926d061e2a35c08c09547e0cd587c396ff2959ee93ea64b1e6b7e2b624cdf445988e1f42\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 3ac61c3a028f4a2df6645acbd36818a2f76a3229d229ce22471760807585a909727411e8b68bfa4e76adc459409a101a1ce83900d46918e8d0903a163de87c07bbafbd60c7f536a62c59370ea53b6cea4384345343146bbf529334b4201ebdc7585b6e5eee42696400c9be9f496406a4eb51d2fd1b40466224f1752b181774ad\nA = 5a16d5fb9047949684b80805e5d962bdb939d0d0368b48517a2a826679c37ee0ded4fa83e657192d9ae84294e450f7e2f2773d1f13395169582cbf95860891b9fdf8f3240a16aadd1198e884f22b2718219d478e2410fd4bb98ea534a3626201959af099fa55488f5390791bcc7\nB = 1f67066dd06ed4a49cb556dc2fce22814754885a7cf6c13915d974b46b0e6269c0fafd688f45ed2deeb026a7cbb772c080dfd577d21ed2c81e50e7537a70dd550eb94fcdf626500040da88c43dabce13c82a93769a9e0ef66a471661292dfd3b3af07169e2dc909e43678400b\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 7087dd62eed6ccffc7e1370cca9444dccc4ff160458941aa9f49dec1a2e9ecce4cf50ac2daf06994c5010cf225cc92238cd60e1aed9edb2befb0fb354ffdde94ef5e8ad0415bc95851d59095a5c4850ec52a74c78eab58309f395d3078dc481feb9d30bcd9f113af7a01611b94d085e32193dec738a64c5fe9bdfbf5dbc98cda\nA = 13596eeefbf06e9ead8d883113d8ae6cc3da8b6fa13ab66681db5a9c083ef9e49d905ec19c39b149cc09452eea0446b29cc92d4e865e6f681827336945282fa6b276ef552363229a976c503b822e6e4a9862d3fb30dd0c3627ccb97a7046a6a679050a39166388a9daad5ec5555dbf\nB = -a4e574363f2e5982cc087b38110d257019962fc166c2d6e6d396220bb308a8a0dc7d90c5cb2ab85faa19b07ed7dc11eae9bf2abde0a5fed279e77a717b43d35e70fec4e18445e37741262d0b0c20dc4375371d87d839d39934f1dc41122e815f3f37352d04d0cf514738b351f02\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 8495eeee238164082240ae1db1e3c1e36fb6621e6b714c9de914f9de8a587d7106b8dc5214f7c60c0ee231d7441e03cc26462e71adf8e29772ac95d0395722d2756f9f64daa8ed41d7ce824a572d7f9fd419112ae823b5b48b8aaae09fe093e9ed05918c4ec88ab159890910837ad0691849b44be95993682b2da2b124de39ec\nA = -403f21e1a7911806747bb78a4f20c4e6572d49c6c4ce071db0c8c91ee985e68a16e60093e4628414b2673d25c9f13c4c43600633af95017e3846512197c9515aaf9953570ce5861620716b3d80eae7de0f033772fba82652484cb3ce7cc189d1fafb14e044e07a88da302547f2e623d8\nB = 689d1b4a968b7c00082ae3a29c8571f826c4630c947a7767fe4a71af43a5de84db9b5baec0980eafd0019e09de1b5c56173ede68c9a6acf260bef3d9a03f4c83a33106c94ca7e1a8615b3553088d1d05a62ddab0f1e5a126df5d960f67e3b92981022e1f0358c7970bb2fd5dce7a7c\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 397df584bcd3b2e1ec7ed89de624e9d104bd6812901e38c5740755ce91bd54155c0b624c590ded199590be5d98bd1ad4acee56a62d05d6b5fdd1ade12f7db8e3eb08c4a5996450cc1204be7ba61b768af0efd563ea478033324731e24fedada1ad6e564238c891494e85ded4feb2165fda22f75bf120856034a9206511885fd5\nA = -19cc480d1e07523bac502872a971d78bb26955c5453386f5d51767150e229daad3ab2dc85e0fa0cf6e72389391fe627fd2d9f263f105508642eae5a095ec4d88545dc9d0a2c436907460e1ea7db174673000eb2e0b60d57163ced261bd0f6cd8ce54133cfa10591f1fd27996353110060cf\nB = -39c45512fc7c9620194fb7ad22abea8f6dbff4a137dc4523115ad7e262934143cf1f320892f8c097a400d4099e787ea7041d0d69b6269d191fcdc8ea28340ecacab71058cb39a9c7362c848826b35ab560c27113fe53c497ca452397891c81365b6e7f07f916d47961e50b8c7c5cab38f\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 263ab04c98efac12210beb66b13fec7c260c5b1cbc20cd732a511fb3786b917a617d6622847f4eed70f25982ef5d0b0d13848c62dcf447e3a1d491f4c80e69cec03cd318f6f93134d582210bfa81c1790562053a71091333348c6624d4d793fd6ef971d284a4ebf0be0771efad302015abfaf3edba017907f10ea14a46d9fdc4\nA = 7a354753e39b9ad1c0ad6b65575fc7247487f3ea320fa82d1d333ba8dd5d0ff925331994a6961c9c603be5775ef1842159551f0bfb34920b93d90ca60e6abd514650f77ee8ffff2bac0eecd0fe8ea0fffc6ed0285c9f3c3cfaacf338043975457d62f9c8dda8cce1e99f34529435016fe2ed4\nB = 1a4384f9620567c698ced05870b4dae983d8f0df6aec888353f9dd6ac8ad54340c3ba8346bfa47bac38897f3963fce972f6d55f3407ae03f5c7637be1a34e483e50dcc27148b76ef079f117104162beb191d146ec828ad5c5bde5ee1683a031d554c276d837bf1f2f622cd11baabce10212e\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 91cf4d1899e170bf75dda0d51a6481f79eb94c333b876382c9d04681073e949191223926523f6531f0a45765d7f382221eaa080d7bd05a3c19220ebe18802b15d8009714e8e4e9872223049622ca02040eb041707c7e525f698cc361847c66fe3673a72e4d701466bc374f55fa5437216eb59375c0e2c4f7020149d0118ea72a\nA = 12f35c48024e8271e8f9a60a48b5a214bfb6595a837c041b230e6ac87a4c1d4b3f93a2d3a193c750c9857c8627d0f7c454d6c4f224dbf14a865eb83e990b1d9b8bfb729b8d3dedbbe9c95032e4d60676c2baa2aabafa698392590add3b83b521a7a5e7d6",
-    "f8af207e44ebecd735374acd01ef5822\nB = -8fc18f92c0613d085cf3ee6f586b39b99ecca864bcbe60fffc63c585e5613df68f3534ad46e244916b1f9188507a3692526c9e403b8e93480b0a5a6297f65215f1a5d8e20631a9d559fa1acc15a98c9397761ce18903f393b10444ba51bc92ac44df90d4cf0852da9d75902230c6de6f26dfdb\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 9af562a7b61c6c84c91bf979f32ba5d246d2ee2050f07ec2dd5cb3f9496bd37c3922ecb2b5b17085a13e93ab2dac6022077cc18c621cce3a2d2247e5e89de8692a36f596e5dc7a6969a4f3ff0d1580eed380e6550c6218c1938caa2b7ab401ae6f520063c811088504d60a19da3b5018d640ab8d340f35d1337a2ede8bc64bf0\nA = -63bc10b8fbcb391dea305fe61b404d3bebd035514a812d0e1d38daa3d67f9f1bb8f02d2979270cb9147aa51d66ca73d4b5787e472456a13fbe0d568e92b622439d33ad3c357a56dd26806ebda7b3bb592385ca5dba7e5eb5d85eed0a1746441e8d56e22decdbf8f4296e30d222da5af17c427e832b\nB = 57a602bbdefcdd00f42ed1e2cbde2ba858d171804da56b0ac87081424ad1569df1308fee7c9ed349eb496d5409c4c46921f09ff0830bc9f57e920e17df16523598fd90314141955ddb84a1522ff3ebfa812cfeb6670525123476a739f64ebe6a5f1fc805a880f8e5a71b908c483a121b38d05cc2c\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = b395c9f264172a3653af6637e72c4c8e564d1ce68032a5d761bf546e0c4b51b33cb026bb4256fa639ae98e54e5ff7d8921ae411497272b53d97c2c44b5b9ecc5aba43dde201f64f1d033056f19ceb0cbd04decb486a1d07ab1c64fd213d7eb6db9cd11efd743462e137f368acc4ca0b49a7f85587bbb5ede4be1616889e2699d\nA = -1e71df5f04001f6468c3a192086bda948aedd19c5da9a5286856f30524238d95b0ae71940f2af123315ab5d2fc61964d3e970d5858b7c1a78d0f2cfd10cba7ba4830a8c19a09b59794ca5d7da32cd8376b5ab06079b51cd9819c0021ea41a9e43aee147befdbb17a92cac7c7767705fdd908bcd291fbb\nB = -394c187308320ba1b14d91d75b8ff993dfd57f9c84e8185f12bf9924e046629ffcd7174879f9925bb643988259cbe9dc9277fa83a25012f91159b012f1964aefddd5a94ac6c2a55a22bbae93085dee079f84cea1d53dc4771901db9a3db5a14eb17c25aaf5377e2beaff6276cbce7cee97a9b8f32737\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 6602ce0fb5002eca37e85b60cc871b7b2eed13d38c20a37a6e0886ee4814f3ce2515f8714c67ad81e8c3abf6a00464e6a51b15e55b6c11296ada43cf459e15915026d3260cce8fb796241fc2b0bdd2b65ec04bee3b7ab6626e10597f3b13b43d16c34afd5b43a219917626c88b24c6f8392bde1b2e65a50b7f1a8dc5eb096702\nA = 4855ce75a3d7dbb72a257f6291e9f6ccc158647aeb2f8beb3e8fb32f6f59af1a46617b77440798562d6f58bfe826d3ea7dd28daee8f5162d7d24ae6c24c2deb2669b15898689ca789e2005903f3a94e991e7d3c8f3ae6181029d959bb15e71d7ba94d2dfd3ddd10f6fc49a65798b5f6ffd64682c78b5d91\nB = 15b3e9992aa3f042fd58ff97a8c04aaebf46b75fdc38caa9224394a1805cc26e4311bfb498d5a04d19396e98d11c8810620979362df82b23a115fc1711b57c7a56b8408e2682a2edca36cf9311addfedd2d0889a78cc1ab170d1379245de6f1f6f4db815fea9130463dfe5283f195e6e81486a1d39634aa\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 6a81ccd82f00d829bac186fb38b85097d52afa3ca83a026856bb83f94d6af6f6c6f3141d433f8fc159d11397df8d2f44c769f255cf8148249d8e9fc4f59ec3bc8e804d7d5189e71e20b8d0e540b59a2854ddd7feeebda5a95f17605e8bd5f311a63cc2e4ce23a51229d0a49ca04982c1bff79c201de6cc6150b690c98106a39c\nA = 1f1589c9b5ad9d878631cb03c23ea7e94680220856285668838452a63b726e01709588b38e578da8a4845aa5cc2e4723beafa4f81a1a2e463f67d9a3e432de7064ba8bfcb943cd9efb0e5a136649cdcf5e85a667917075804991b997f318752304f4946d69abf161625ed0c03bf9abeb4ef28034f818e2a643\nB = -909dc7fcbd27d0bf7d6a3d0e2937ce725b5cca0acf78c103d633206cb431e2e2c785aea4bfe2042df32417143de76b71d21587112f36d067f878e556b94ef63d59a07d19647593efdba7f3f5324d64c55f93a283a0dafe080167f6576053f9beb326994f4a1d53e18e3f3e770e69450bb70f276d128e48ecc\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 69139f2e10726f83300505d15dcbad5b5f284d1c06789181683b7b8caf35dff063dfa4968c35facf32a3628dcfc19b3fa4c30ba0e030b06773832a2631529fe0c0c402e05a0c4e9446a8b6c22754c70ef540f90d903d83a2e3592169ce6b5edf939ac5ff25b8bd48aa2425321602a9571661a1109e275a3b3039ff0c2f430b18\nA = -5d02cf3969bff8789850ac898c00fcb3ff1fc49a22cb243ad18703bb8fae25f83502bcdd885417fe46e8237fd0b444712c4fdb8f4972dbf9278a83eb305efc7a8210ce55167c069d1c4136a9b66d0c4dfadbf036c079d12aa082fbb42bfb0098006136a61f3da43aba3d3bcf2f5ac2d7884caddd0cfc28681d33\nB = 50b369234d993721288662d83298d99b9052a0a66336a5a31b76dfb20ec2b5be3aa76f78b2c17c63d78402a15aacb585be5c8d2e7083145e316e71e111fd34f5c79363c4591c247b1a94b20ee042d840c42a3001d6c8dc7cc1e1348e0e3ea8c6551f9d24af2dc2d0c38a54ef065ff048b148ce4f11ed2b549c50\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 87de406a6c957e85c759f8ff684023a0f98e93ad4ffcbc6fb0038c7a7ceed2486f15f36555d286338aab3283aef677118f7cc3f88a7ff0ac9fed31da6786ce895c3c08d3edb652bbc9ac2b44c4cd24ad281ca3a8e8e6e4d730f4f0c25487cfc1b2afe222934eca8b1e1572780dcc149422a88eeb1bf31065c929685a0a97ac3a\nA = -1878e0497aa1c2942a2e6956957c876dac73c4bdbf42bc92498f29a006bc92f788c24a4624b87324a7c8aedc6b2c0c8a1a442aa91557aed9bf2c02b6664979e8a9a21330dd839f4ba8f84515fa6f7db9287f7c20f31732b98fc09ee7796dc524870dc35851814bc57e1a8ac49d8935fea04bb08b8760df33a98149b\nB = -32f4e94bd073cf3f70810d9af7a873996a0510109bc6fdebb855f27dcd012c59507491152d30849d75f95dd868992c6fbbf29b1d899cfd401e9e7f4e0436732cb4cc9e6a6d6b0cb63fb0bee21e422b7f7b7b14dc5d2b6d10447fc4add390fd3c8e7b06f1d9b181adfa8d04459ed051bbdc9666623b00e3871e597be\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = b456ccf9d066dcf4247a21c7f3820e324ac9cf004cecf8dd1f6c3aa40c2a33e24c423e97190fc71bb9fec21d36c5a687065a7877237a2a05e64cabfb3b20bfff0b1f5ef2e9adb7edcd7140d1047b0919a2c770579ab44a08e5ad9f63a06f90ec7d5885b91de5e524b2e187937609b4b81d40a0b33e31a48d7b9868add75286a6\nA = 6c484e3c6b530dcd3644b19fee66c41c7c2c1dbcde574d87ee13cabef9dccbe5b41e25c32c6a56df23f2e87176afd28249e5fcb918723707fca94d7e2c9623a3493d395db802a1b49d550f52c29666f785652fe81afcab00a60a5b50cbf523cd13dfa06d5a5b0809c68ff7264a2cb35b8d52284172c62ee658e8417e6\nB = 1b4fc753d0530bd07094bae09a02b1ea684fb4e8519086b1e2ed9d59af011f61d1b94ffca6f354a5b428417b328bb1e8af3f6c7ac9121dae58de9f1dcbaa9c73a357f408b870e62b0c7db1a72c4c440f2e6fe90b199b9dab29fc23927190d3f2bf8a7ee926a152e64474283695614ad696c85ea547f5f51d02d1b823e3\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 5e7c63276f350f04816a6ed9f98507a78314f1d99081fcd906affa3b8395fb58d029ec657af82e77ef45611bc988095bba9c26f25f8fd404432fecd02398e69635f3315a824d6a98b33eaf6a91f12957a5e80cb48d5b086c795eb3b1e04da5432a7e8be3d683addc586a44b6243ffbb7a979bf9664cc7ec41e75f267d58a7127\nA = 18efe267d4c62576294f4ba44c67a058cdc0bb44c48f4035682b2d6b8a63106081af43d99098ce133f8d7f9cd04d4dd7414f704e32871d43d6e5d73fa9f447873168b43b32d6ad19378d74a967f92ec7629a690d29a62a5a6e734e9ccf5b84857a00d97b9db846b057004b03d88b827dde717fc30e6a",
-    "5246c752d65dd625\nB = -ebaa580d3eef5361547c692e107439c8391ac0a2d1cec0cd275d0be69133eba8a94bd186ff9a129af3f5a015d5ebd30215643554d7064635dc11ec7a8ed2200fd637b099e534237f0495d2b629abd4c8f84aa1d925d53e98490d02f9fe51bdda08b043f67f0903c0195fcb886c04397d3612e4501ab8c7b7db69f781e169\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 76fcb39f94dd2756e8266c025cebe8e801524a757b976e35ed45e3da3db720061cee9037fdb34776c704ad2059ad8920e400bfbf10eca9bb157eca7750cc31fda06473bd22d4def80189c47ba32e2824c721425f225563df2a2ea1edd090e01c0bf980677db5a5dcad37d21a68e2832d1012586f506480e929b2fd9bb4aaddf0\nA = -75f903ed9bb0b6db8e3be16e797258f6c18f6cb7b16f835f04e3045f7e4974d7a86a63f2ec351c88fadc0635b6dc83a797cdcb5cce1a1674f89e44190991e0930575b19e2aa1512bbbf2ef6f8c3e707b17516756fadb635d8c6bf9caddeba14834b5950a4d1e98bca79a4d15e5fa5fa3c1727d7a49b33d481d32fb14ae4164\nB = 4ccc582c8460f7def2d26167b68788a681c41bdf6dc805dca83127a18bff6f5ebea6db75cd959beb859637b200ccb5c7644d571f436e46a357d027edc9769da226278f7ab947963f7caed1e7e70e572980e960e9764a40c6db67bb526694b084976142471270b2331da563a10427cbbb38e76203d7da5d67487eff701d75188\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 5adef30c67aefea4da3884b8a1d0ce6724492bc76b477f1053621e7d19f3cac15448e9401d34e05ac4b508b9d1db9a8d323cf43722e0af6e3c3b6d463c6007449c3bc3236d156cdf988dfc308a1b4911554ecace52938a7b10f463d14f917ec3d9fddcf6d33081745009c59b58aa22bcd7dd8c3bbd489997d4e0bff5473ab9d5\nA = -174e8e057a1d66e22eff88de26f43fde1c8efe5611f6ba4f318f027f5a5818df02ec3f014dfedcdfc8c143c5005c3c5098d409710967c93474f5854c1113fe4030e6682bd56d389ca8b9a4587b8b9262d146bc92fcd81d75c3bfa4281898f394f45d5dd11cd4c7344ee7a933ee346bdaeb6f5188967c388b919a0ce6730c0bbdb\nB = -22702bcc4f9d5bc6f803af6af8072780ff7de7a346d6b9293ca751d6ee3a81493fa86738c44cf2b7be4bf14a55a4f8179c35c09dcb1485f4c08ec5e9f9b1efa91f4b5f15a31a46e1ed71cd934ba6bd271bb22bb5703aa468d297f360ecbb48f9fd6c572683e83ebc3d432203347dc62e19fa06f93e087283347950829d4256bf5f\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 5c2f67b1607776c10fe2c30b112e541c4d8229f5f99f615fa02cf715d3f20556a28eff5c233c58994e9c6c1fcc37b3416b0875b9a62fa5a09a4b8f9e216487203b387ff97fad1f39f674ab19c5e34cb2f162e6b0b0b0084f0618e64928423b73b189c744e3de9fa50d66f45975f68b14866cc16c8c6c722a54420adf027880aa\nA = 67056e93b69e8a7b789f1f8b835d9c6ecb7762f844d656b26df9844a60bfbe0d55684f61debeed31a24ef4246485e8a1d43d49eaf97ed9e7b9f2d2916a8d85b8c9e8ad5575cf5a3fea42392e5d1dfb23f7ad41a7b56a4f21e2828aab38a602d560c99783a4f807120292ceae366b1fbfb4be8e5d4561bc8944e7f17ebbcb0fb6296\nB = 1f874f244ed6cff9f910ba9a58db0dc0a7435e8d99ba6412e976b8f64d4106d3c5c57ba079384fced1c261aaa538e131734451fe84fd3cc5cc8b3ab46b2031f888d95084cd3a35a61092672a9118eee4ed1a0df0409e3613b3ef45a8b16b71ec892755dc3f83c5492b67fb9a143ee6102d053078f4875636b20b536d5cf851768cf73\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 7850019c6712f18eab877faa8489daba23cf34b512a3193852508185b13cd5a2e9f503fe8d61b74b5d3930021a5b8c38322aae9b9b1b4814fa4c2c5bc409b58f11fc8fd7854b17baa94a6bff5f234832f9468d90d148fa2bfed774ac03f2dab6a506a70db4ce363f932adcae202f04fdcae968f632dd674416c23d4e21345ef2\nA = 1e378a0f27e6259763890d29e112e3d8d2bdeb9994c49fb67ab680b6e71a52fa0a7db886d3baf52f36d943b5430ae8bcd82e229f4197239c35678eed254c5816722b995e9c311be942f8124e2f80c1e59658433a57f346adfcdb83202e55457308161d2f928b60efc39538a6469f90f1a868cf6077568c8241623896ddc2705cf04e4f\nB = -f4ee37e39d4cadb692bab5483ceaf0258b068f2c0354c540438803780c983469ea28324ce7e209c3bf55b91f0a2f4544bf318585e4514333eafb9b8c2f02170c620e9b5280a828ce1d8dfc64ae9c28577e15071825a85a59656c5b47d9a382af6b78a5b3dab1078dd647e0b473174b8415d401543d30a4018cc3eddbfa546d0fad9cbb2\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 4c8f8b671443a3af5ef5749885ce5de8e2afeadef9051bc49c0d7e72922d049b1accdb79d82288e472b07578e8b6d2176d6cbdd7f0caab593dc0fd9224a94920235410501fddd6001b62a7f7d8eceaa7a8e4c0de52029fae68656e8120972b5cc1c2e909c2742e836f2fecfa51e12e4f8a2ec7e69eab061c81785374ac607fbe\nA = -5769eae759dd6bf94468eae94189d3396886d4569b0ce264c22d39b623be3abb01bd5008b9fc86701a3373f7764118becadcc69481cbb134c20f669cefeb376dfc489dd4ee91cb333d06afa391dd322abe2b3b715d11ee372666473a473e29dd90fcc97e939049b455be52b3f288db306999019c1177ab5820d94859a9d2f050b7ee1d4a\nB = 44adcaf1e2afbfddae19b23cfc0f0ba1f940d32945d0b541db23f3a0a9d06fb1f67ade9a8e620bd96f4005ced99430c7a55eb7e93a701c829fd5b9e55dbb4d3833afbcaa0d9c946916b1a86af4a6393b1155c6439b8b82260e09ccf0ce5d1c4856f4d524983e4b0fa123267694a1c6118beb8be26113a02721a02d7b0ccb01ec6e9c0f9e19\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 51e25767b8d4d7b2b0c2652d9ca6bfdbfea06acba543b1bc8d3d25b2fe5f2998febe1a6e742abc3f482b4267854c2223a5918a9b5c84e0864278283bcb5bace0c046db1d0240443404fb62d70ebff3ccc655e5f5977958df4c878d9859a69731744f3d33978ac31551487270bb4fb56ccbf59402ef9fee42cbc329420180de08\nA = -1966812979042198f70b3f1238c93ac5c6e5749f1108c2bba869b1dac7680f910e56318c9b59be9212e713a348767ba6e75917fb599e929ea2144880d18d4fbda4f4663c7abb49b02245169f385e09098a4e01b56dadfca8c803acb7cc244f3c98bc17440ab2afce318476b80e1d0b4ed9a8d6f2a0be64633f8faad5eb48de2681a38a633ec\nB = -2e4f5eb92fc34c753c61dcc826abab6fc4f427c6ac7e73ffdf65b1037464b2a9a0b0290e713d81ab57c0e1dc30e76fdf96046fe10a34cc4511398319ee34bcaf73763a9042fcacf59a100c43d3333ffb3743048e8df0dc61fd0da3f935fadf882ffdfa9f0f42980c1af6edfdf161c4b16087e2b14277f655abe54582de79c51193e13169b55e6\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 33539b5f38a9943b15801d449adabe02da6e21651d96acd9aa40e866bf65015fa40178399254e8af6bb082d021e2a05da0f45b699d193b70112e114f0d25287476dc0c733c5cf9df57667ad0d3ffc4ea2f85b43cd10459cdca9465b0974e578c00a6e275e0b97ef2a4c9886aab7b5947b78a88f84a3f1d8c5f26bd07bcc59886\nA = 531b891fe9e8db322cec59a2115574c7a304c423e6b11516906b840542b2c608785e2c18033262ab9cf68f63edb40ad4f073ce8841db602cf8fae0a6771d741c6392976c9b333ecfcd0c8e9997da40616ae2a9e0c6be93fdc7af0dc0668ded1e42a9f729c70f74500ee76a91d3d993c075c2f645b35792a20edf17c157459e35c0a48da6c4c6f\nB = 1a6fdbfed1054a0c5758f92f72db7e5737b0740c4d8c3ae4713366ef6709b21eaecb6b74c92541a9a0c99ae18ac6ef7de79d4c84ce39ad59cea9c203734a99bbb895916275e8778cfcf7fbb7b7d081a677769e4ab96bc7bcf23303100e629fa8e07f5b8fc2e39c7b5724c72907eaad09d3088783b3118e57c9c8ad1799b43a13f73864c5602c478a\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 2eab6018361f557ab06725ad90f6886d4b468ab1a193f8fdcfb4ad15fff781c8681329a27aeb5f03a81d7c404b8017b12fe23165e941ea767c733513a07e921aedf20596763f6f977316e37bed70f6a617e5c2757c229c59b3d7b1fe8755b5f65f7f4",
-    "07f13634aca7c8a267e661ae2f77fc5a95f56cd6c8458119df587478b1b\nA = 1cc779145b2b7bf9ef4c9692845e162329940f96eb43e04db8728bfe736698082aae6b6a1b3c32867c293b08547a0941cf4059d2d567840ab6ea526e3724ad59e715a3782ca656cbb739dfdf0c113a18f0dd62423d4edb60057fcaedbb852178d38f1b5a232842b4fc645cbfd97a8cac0b094b870064302dcdf23df2c9e9f736d93409cbb8ce9ab3\nB = -cbba16086b51bd83d3460e51cf193ebc79b826e4f30978274eac3b2dcb04e9d7b56a1449b7cb128bbfeff5c4720bae45271fcc64085d3ee501f0f21fe73cb7db5f275d88be55c339f9180ea21a8cf3755a875331931b75d23f57c2030c89c6f9c1ead431cb4dbd4480564c83f8470610e5673c7eb6c0fe7351ffd7ee460df5db7872c67041aff0227f\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 96fd93535728b961b4167be8b304e570cc34e787c12a9a5d76e099b336ed6b837cfc246c5bceb04b0f4744c5da7071fc01d70e342509473e5bd7c60d6046c9b4f21c5ee71c4e678447f837db3a7694fc3936ca733efdb7d387f0f6e263b3ac0b89054a826da9716691c9d580ad38d701d08ca090b6c59be466e1b9833e75d820\nA = -6791fd686f46c3773fc8d7f4753d178a93f6fa4941f4305d9689c2a305bc67840bbef80ff05c7bc6de3a595f73846609327d28540cd705f5aa94a3ae5915ef55304c37c4c43a4b46906889331ee16585629bb303673d439de9c0236f708fd19a977e6e1032e0576a921853f7dd328979ad1f1aa945905dae93a82b3af9451a541f544c18ed2546b66e\nB = 6ae062b39c77bebc2fef05743e6d35e14a31c6fe1fdc42d8de2db94ce70a6d60d66263c7414b1081ef2fa6ab511b361b8baa9c71ec628dba5bfd772c440baefc2fbed68d40897878232d9715c4b7e7c9bdd41cfe7b6986d825f68be8cc16d04afb0cf593f3028f3dcd91bc94923f3d7211aa5f0f12d3270e8df8bc191808f0e266c4fce2af97ac7ce06b0\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 949ea5f645ffe5d0d03359d51a663c7dd6e6013812a47be309575e036503126f48677c68c4ef6e7b3f72d76657fa282ad5881263e649b5297da82e24298300d032af3f5e8309ac7eb597b16e257a6f7af3476a264415aa7783433e83be57ffb3fdb404a9ddc3527d6a9c297f8cb7b6674961b3af837ebb65f218147a46c39cba\nA = -10f59ba073126d92a201529a5374500612bc59a9e66322c6706b422d35a4f82d97e668b268f5527b4641c6099c80bcea504234f3c1e3fd29eba0f161da97c50aea542becba499f29d4ba5571873d4dd9eb3f48cb26fa6c929a704fe8e49791b2ca3293c2428d9cb453263935c9c90a4a2b39d23a0baa12535845f907d42b729033a0a1e74d18da30a88ed\nB = -34fdf9ae6760d4f434d09ce2a7760ca2dda14bc256015809745524dc49d841b07102aefe5a1d0182e3e09d4d45b415e46f653185742b9b8ea6960160752080e5c9577a12182ccf1a293407b534ea8ddd33ad16cd19ba537d8db5b542f86a2a292423d452bf18d82361240a7efa831518184572c5a8b73b108a81d5036b3b530d98bd47c7fb2123418f12e05e\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 9ab739ddae55a0d71b39974628d4601122ba6c5035c3ad0439691317f23dc33c0014f3e870a105e4dc1432ec79693bac658433b21cfc218ed411e003990b94ebfa87767f3614ec19f5bc30704adcaf85a9d3d15ea764c8f0bbd52ff388659637746d39859398c79016ace8c6f97d3a5616711a235b85f334fb889b9280ccbea1\nA = 76b15a0aa0f59ec804a5e9a627e1fed524320b29120b6789f8e71b1ac4e00a9a8c826919035b84f87d291e2f35460bee181342136dd9eaeb99ed00c6328b8e44c49ede3921d6275f6e7f03de179fb2374ae2fa6c58852fbb2649e214691daef945ead6c8bd5a53ad2b130e9eab6ad046ddd6b80874ca6515322bc171ee32749333669de0d9c883058423579\nB = 1fe2171056ed4585a143b6b2bb5f44047664f64d710dfc05c18be5840ef9426ef05b6e92e4ecb5544ee4622e9030153dd9827f2f01ef38e62b88ecd6c46b4457d16644ef6d863c226acfd6928a40de614a5853137124fe69127a7f05463eaa49bc742d8f7be300d06b302dfb0ba86801119bcdc01b516afa360aa8b22b7c6c1839cff859ca1bf26e3f7e030512d\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 5631048ffdb2767aa04d59d8a5750016b38b983a2d53743ba4de5d93bcfc8ec30183a84bb1e290ef9c72c7ad357728acecfc613a6f9b3d712456d545ed54a337930937f4589fe41e66ee930db3dc10a4fe41481008c69eced65b9d1c46b8574c5ac8f7d94025d8fff00ced17a5e17508527681bf94c2dedd51502a2c4652538c\nA = 1aca12b1933f25ea081e12ff4a4f6f9ce379f96d976da2ff7b8eb8ad791fabe31c1148fdec22dfd67828e540c955a1e13f40c5b125e1c7e6bd839bfa84e5bfb58bfed76058c6db77af7a34ffd25fabd60e19f65e1faeeea6371d7785f2e5bddc8650a7492e06691d61f997483661eeff54a30656f1daacf31182486bc40647975151fc05d2f64b50e632f5d5c4\nB = -88ed894287043e7e5cd2eda3c1e5c97f85809f7a246b0c20891fa9a024f3aba4ec1f3d112580fe6ba6b0bdcaa1325ac7ec9508aa88c187af08e4f37631eb6cc97e4481b18f747ce6d35ff355e425a4833834ffb8d34a818bdb015fb818ac9f58feb87020234243aff912da5590ea3f6cba74f1a9fc3ffa2b4aeea25479c55a3b572621e75d86d8c8f6ee4f587e0f5\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 6ce341aa4a571cd5bc110dd436acaa09f409661967de0bd096c77c60db58b2b0ec95cda50acd7fa20ea4266b2c579eeb6ac214a75d40abbb70845db74c4d6c93f8c545add269d45fb15d985e7e630d0425565d06dad4a3ff9835411e51fdd9780c24f466dbf29244cd1b8c3445af181d0928db399bbc8632f7ebcb9d48c0b754\nA = -52c53999b02a92d6254557203cb31a21dcb896495d1f29f3277d19129ee43e521ab9d5a297204a844a9537d63b74686eceba72ea2e7b98ee8895513395cf7c44c99348f5c4eb657874a8115f0027d6a416b8a04a1ec0e6809b7701ee7d41e99996e307bee9c295ab3df1faf674e0067d0ab3bec4da998580203e33760870ae472a3045bbd66e352b8f4d284efc00\nB = 4329d110504caeb71ce0453b0706ff675f646e70a6bd9575791a38f672eff226f4958f8b1fe4123c0001d8f8595d8030d0e9798232942725a9b9d654ecf50546adfba7103fed796b455ffbb4c153e70f941bef7953c8a210d6f2f4ddf5d9a79d9938503ae8f24d69d5d7df1c988630ed960e12dd877bb80a1ab0bcf6db67e0c0578fc0c40408f72b19052534da8d31ed\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 4b9fc1e0eb4be199427c48bbe1b53948d0135bc1965b8aa5421a4ec704b13cf934c650405ba02ad611b0f29d46d82d4a1fc5a84651a29364524e37be2fc7001cbd3c792aa477802999841ff19620cf66dd2453c9b05aac349b9094d43b40e358f32805d87cea3cfa98e05240ff95ec57d88e0a12917628ebd34946eb1ad6799a\nA = -15a223b691d8b3696306b0ccdb52c1d62c7c2d1ac71e5f07cd8fba960417b42fb5ebed5eb9469be67f231b5254bb0fcfadf5ac5d2906769e8bf8292f0442986cabd88805a162c0c1f60f9ff0bcc2029ce33452d05f754375c0bd147fba745bf8a0008792d4f90d0e0f2cf391f2d7865705544f4a220ded44732321473c0ae7870394d4e625df11bd0923340cb70b995\nB = -340e5ccd644849d982bdd455ddb3b9a23ca14e168bb87256bcc370ffb6b7fe78fd062b3bcc1ad3c8c3b8cb549f2baaf1b7f0f6522aba02fd35b651f7de52b3aa2e0e40352bfd6ed0f84a2bbc3b3a396dc8512ca1db01cc69611925f1037794c82a418f10e0d994f458d1f19051e8bea32b90ce744d46718f42e711c094ad0a1ee96c88920188078f1b044ccf307e4cad7de\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 31c090e5160faff9a136a7a482b42a43ae3c7d00c215cbdad28804be0e7b12b0b3af820c1350b1622a22c8875f24d48ff16231c826d1a946c66f70aef92d4e6582e3ce9213d907267251ac74fa3cca9f1c8fd53fe9898aec19936a2b797fc345d68f0791cc740199be39c05053d5591d874b415e62653b04a3f41e263d00f230\nA = 5419e87e50b28b6d24927934b541d8de548a8f4ec7e9b00aadb6d23f2d33406177d3fc72d29ad2c2e141ab2916adfd30ec4791c626af61d8d192276d632aaf3b54e2ffe83b44f6f1ac441e6823b6b58cc08fd7a0af945a02eabb5aebb2c7ff0622a17b38077cd0cba906ce23e71ac7f4da40ef6066565b4cb3a62ebda28f3629eaa251dbd9979b123a5447ea20331723e\nB = 184782ba4daf429cbd13ac13fe93fe5833f09915cbbc707feca3293e505ce9cf0b4b12ffc8b178e0a4617f809be53d4895a4182e7a8a65043361e654befe8b0",
-    "1429ba4b7420193d1d7d90930ee19cee0316f33a5795335f5fa517e1ffbc99b95101b0f936353afd3bcfec34851ebff1ef02fea991a01b587d28640c935ec91496d1aa3ab8d38a6ac75b3a4198ed27b9019bb3e\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 5eb9f3ca660de481968a3c7321281f22fb9273b16fc10d8eff1fe34842364dabcfaee4993c1c8ddb7c8d6e509a8d2afc005075d5fd3c4471f0622753c7797aea900e785ceef905e2606f64f34e47239c40b74f07e2ca70bd5a18cb0a88780489f3e98232221f65ac9c5ce703a256b7b75eb1dd38778d8bc05a37ac9ad8d36b35\nA = 1c73d8e3d5db127a81477a5c4c6d61ac62af446981773ca15a9a01fd5175a2826a8763f91d68df28ee606e8ffc203305875a238d2095345556f12f3b5e10c5bb6ce3f90342ac74b9ac057195c863c4b9d28ca1d958a98649c7f8897bc6abbc39becae963f61b33bab4fd20d9d0e5464f21c2cdf06d00f597dfde45dc5919f5124f26888b12d72cbd2f57de3f2de7c014f891\nB = -e406fb60e35f0abdd313b8431f4cc89fbb034daf71fae0cc727e9a93cdfde53566fc74e48f4cc2111fad158c63293bca0b21b98416381b81d2443d0e91647679481cd6b6869b37112d3b6e575eea7fbb5bdea422558d817b49ac36a829926553202cf9dcef09423c085d26176a89be741ae20a434ea461def090dbffaf2e2ef97bbd4ec779041ed69ec07d125c7b85a2d215bb0f\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = acf9d363fc9b76ecf7e61c33270031340e66595e559dd1c9dd4d2243819b660183521a4124558fd4b216dcf5c52c4127fe517c48cef428b9ee0f1bebabab487c968a80b9815e82c12e807c096974ea3893a8d5597f745365c352a6bc6ce92479176092f02907538c5e784bf26dcde7672338f402753b08de8aa21b9480df6955\nA = -7c03ba6e3939ebbeabd35cca277eecaec31f326ab75f1a29e05af50c4e62e0175d4d6a57acab87cf1fa3a51791e9a2b2d4d5db570ec3941263902b0c74544c323c106557cd5139d2a25f3c3ef81ca009d4e3c16f1abf6e2b5196df1b30def46d61eccdcb3741a6dfc8e8c5e6db68ec29c82b0adf6e35ce7aacef8da806b3b58bfa489d319869b20768f8eebb604a9624d048f9\nB = 4e021959da96ebeaad17f9896ed53010d80ed3fd4c3a826a266e82b80ad81b3032303e7c0e58034a652b8aac00c08d42a530039de60d74ad349438f5ecca1256342ded6f30e3bd2aad5bf2b49124cb27f45f697e157550dbbb37f5aef0f04839aaf1ba43bf1e77a1529818d0fa91d940904eda6b748e5c86cd1b37592542c43b7b4afe2b8926fef6dc01784fa431d43900edef27f8b\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 24124c69aaabec7a7b4e7a82245f6cb14b199852a8b314a7b8d9049cb66096d5ac93ac75eb58a2004de8b0fc8375638c0878fb6a45be8bfbcc292e3571df1bb8d6e346d5595fa395fef983a365e4e868154fb3e337d47771419e7f1dd5e4220900c564d7cbe8e7792ab288f99d265aeb296c5ebfdaf08b88d9b30ac660cc3ff8\nA = -167c959417e9566c93e7e05d2a410f4850e3a313e516ec958c3d2fbdecbf58072d05691c68981e176a867d7467091dfeca11f695f750c8c44ebc4d08e39e679d96c4791ceb1ea3b89fa3ce26f7ef214c5368c03ba694f7ae592bcd8ae53a66cb3eb1e0cd3c105faae6eb7e7a8fbc88248be722406f2d35e46c751b5ceabd992091eeba15191ccf6dd61a7ee0c624d43b188c42b6a\nB = -343940f3b2a5f73a51d6f609e8af306f44ce7b5c2e79edf6f4dfc07866dc5c4b2e0ba48099b5503af87762a44ae451d166f8914ba25b3cc41a766583bf73d27e40784064582fd9fe952fc00e9aa2d4e4f1ef35818978e725e69c1bcf267fda4d635d1d292d54d3ad10bae9763dc5d7f7226f371184465695f2d384d749fe07967a1bb64df22f294ed88b13600c7068d881f713cb8e3ce6\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 50cac148215963e58cf6d2ebc36fa518c63a0ab8fb136ab84c9657fee459043ee9f42aafec89e8ba5fd1cc5c4495a41e80590ce197e12c087ff7e6ea88ed798735f55a1634562b82f8514488ada526e5dc10700058980885000e266cad55948d1e080f6343f84b12a3698d9ad5427fad4017d931df77ed2e45e2fb8380b7fa39\nA = 6a9833d768a22ea46aab1a1619f30283a1ec254a2de5652981d73146aabe31041ed04d271c6f2e5e2d090cd615518a06563a94ee2b12cf9f142de3f15599998a712974d0ce9b122a2aa65bf8750f54c6324f12e321a888154330f0f9e1e5b7999acd70d4e6da95c2df1da2d19544b7abd2bd3041e3228c7cdba44f7d1cbfbcf968f8fe87fab523eede0485efaf5cc9e56095cec8983\nB = 11e782e2b3f469b1e3d14ccd1b8301ffcde7e371f6e9afc99af5809110c6d70e1cca5c0bbfeb95fc3ef8352581c11ba75c0f8c445ce2aea903769a24289581c95ae5ebd9553fee61a30d155bf6011278807833eb2ce7ee2a98fececa23fabaaa259409e88e3c4f4eb1e04176d44878ad3f6961e0615ade2fe86b6eb02adeaa7c9019d63231a28f84b7dcc8bb0e71e2a717db09301e1dca20f\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 7cd49d72bcf5ff4fa2c686f21e1f0146c4f24b9ad2e900dca1c0a5d2fac5047509064e65ac582946b251a3f04850c9abd8b80c92af0fb11ac13debdae8b94927f1de0e4bb217e78f5d04897c6a0762667d3d883cb754dc610442c9dbd44228a7ae4f14fca145550d813655befe3bfeb52f1c76f989ea8a1dd9c10fbc7e9d6574\nA = 109fe33568598972063279b71ba0efdc2e03f770cdec331428fb8ca084c9b20d0fdb5cf9ad7ce90c8cb8f0fef10d219d7dfcc6b4599440db8cff9971da7852880bf004266886eced8763b3569720df3a1fb0dde2717ce0183f2250034871146628430f206c12f5fd87574c206b203d90c0f2c705cad3484c73da8bf4e9f7e1bd433a6f7fd27df63079d30c490aed7161bc594eefad4bc0\nB = -b95da952cabdebe0194b7fba519768e1b56149353cd12023b97397b59e0d7f4dd1d27b65b833948f58e66d3f6928cc3140cced835dbd612cc82a7e9fae1621986f71ddb6707ad57926b03e87e165d30fb145795a70627975bbf9d9ac9bce07492de5227c666663cc28b3e70b19dbaba7f16849535ce5fd61e91cd2875e0a534a10c60d21f919d566a3469d108a35ec3f023210efd5d318c7210\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 98a89cb3c9602fe503c32c44609bd4487b6c8323737b3376dafacc3eff96efcce7a31f1b61ee6799dc9561e77ac058fe5195cc013e72a2864f7e492d9f35244b321d46270a582f6f14f15fa8203d392e81b183a1d64d48b51d70e38d49c93869ffb9d7509f15ccde547d2d9c4dccd50eba49190b6e831a9f4f9000a95dc83f3c\nA = -67d7fc8f1766c40bd476cdb65d4dd161c3d4c2c5860a0c559f0e87ada213c9ed33308c36bb1c7d615fa69ec53656bbae6b57181a0134af23ea2a75f8fed3290a2f483392a3745fb57adf2121738c84f6d34325121a702c8ccac0090ea27fe9a5ebb6ba9d4f397e4a7e3151850b3d7d25643398bd3e4c1da081471389799245d986cab825a2e6ca72b38ff978a2753c835299ab4597bc65fc\nB = 676ddc4d18960817ff8fd2adffaa68c87d234d62d445d6ba3847ded849356d929d9e4ff01f517d7b1c0778bf90f475923517d855956f17ece1e032e2fd474d2133d6b8a591995454d8b587cb4f6fdd0fa29305f146d340cbe6b6efd28a926c73735621be0c5decb792083b3f063a43dd9f635e03f78c1bb56389a5cc993c8f36134d755a324d4fccc2ac3bafa270df67db0a4ee6ea4497aa33b5a8\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 76c31404854006a7d55554762094df6e11e0393f5b0451d85de2e5b104432df72023a35f44da10dbde01cebf77b8f9d3ad582373c5d32232564729af0d03c5450e439045d96a2f0a38871c922af2bd38c545d219adce0ec80fccd121d6a733bac09253604a8a0b1ecf0f24e44b818ab9e9974181cef10e9eb17684c57d72257c\nA = -134e8784878a8f3cf49ccb952075f9f9bcd24a20f8883955f262867045c11a9c566abee00638927e5de924872fb98f6376e321ebf3f567db6cfeede62e04f839617d78b7c9d3487b60a0d3897b3fa49b14c12511d04854bde4a9dbe5f31424a3d05cb75d23b46f6c0819536020880afa5a2c173f6881754b56f82a2864c99c820156f96b5cc4665d603597331d98d90a52f4a30c6215ee5eaa2\nB = -3c5c0d35de5fb21c84d2db228829f43b31132b582556b92b495f59df502a6d00584bb5bacd9b8c1a8c7eab91db0ea24b40f07e62a712842d5c2e1d208a6412a068cd5c6394d715260b67fbc03e3ae7eb4862f74f4d7484f747774fff03830c65fe022d579adb6737f6dfe297db750e6a58d1004e7e2716838befc2ea97179ecd53b7f36e3540e1c3a0f3e044bfe2d0efa9b89d2d308cbd0bd88ab3706\nM = c462c7cdd79b7604246",
-    "a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 5b704b3181e5d0494937b4d6aa8172eea82919fd1d884493197a6a85ff047a7bcd5dcf072bdcef0287be20d4ac49918d1df550d184f86d7220f0a84fc4da3ad05e131c443fb529df01fec9fe4fa6fa2f36e791f9e16b4092759016d2f9b1ae7c3d071c57edf26386aaead767a3109c12a5004c7b9fa595e6d592daaa2dd1df04\nA = 48a0ccd2d14e14e2aa862d306501efe5de239e8ef36ff6251c861a0aee9f739411f402491bd99aebacdc26c4f30306f9137ffe4579c2f13efa81b979ddfffcd23675ac6307c0aa3ba8ee77a2e3a3c8e241bd2ade6484e6ead32ce8d752fb3584d14688f223758c5cb8705cea9c56136b219d87f9904bb56be2ea1c9a035df33455206e6b7972cba32ca4c3db41991117d88da3521780fe65c4023\nB = 160120a35ae3edac3edbede9ff1c6f317d95481227d87785b7ee46cfb80fac9973e418244884caca3211a3f6cd3bb419cf70fbc22d82ba5ab98ad80e1f6c2cda753aaf7be78613ef25577107a47ad1ee3c3645db85c4d29bd77900e99e1f439cb23c6c68662c05322f94feffcd9e37d8665cde984387093a043447de590e7874e6acfa37ed302040df4d5c3dcdf9fed91b3d17ab5c141d4494d0f301b508\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 448c3a64958b82ccaaed3c74706ce0a48c5e059c3610cc03a6b5a03a7de5d4f1d1e4b08a31478fa8edd58401f0171697f0662146ce2b371e335d695f9e4a671255f29fc0b9b7d1b2eca4cc7f8357aa0920b5942e31bcfae84e909828fbe5d02251ddf10dbe4c15351f675e96e2eae6d044da1f0858ce8ba9b7aa146850b85d93\nA = 1b2a52aefe44170376df29d17ae2dc1501c9c296f72f271c21f53db71247e72c3eb2b780190c45343bcc8f548507559ced3bd4a6fb13f9174dbddf965b9c4a56c3d88727736d78be9db2268cd02382e50c6fa28ddaf8eab9f44ad45d5882a5100b3027c150a7f3bb36f29d24a76e40f3820ba116d645800459f06c20679321cf5be72450879462f0eac99ab6ff8d26b464cd0e6d78621c9263394c15\nB = -b7d9bd08d7d8e0e9596851b7e03c78973a502afcc7b5fe5b0db6034ebb8a11df1ef7ed0ae1371eb4111cefd61c61935d768be3e3755e481daced219874cdf0d07a76e7144be626cf1fc21c8a0e9db4389ee213193775e95d4d86741d8d8fc820c239b7a90937000dc3e89b2fcd61b44e1c38c655bb3d31aa7e422b4406c9e4a88e6a2c18ec7c048f4a6b5b270c90d9fb378f64be3b5b351621db48a6c18625\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 2192157490ae044a26c23eea6da51d3a3dd08c7fb67a9beb76d37ee24ac0089863aa7f00849b81bab8259f3a0e1bc744d841e07aa413c286e4bef2ff3356bdbecee756026915894584b4fcef7e49da4012cd9fcb5dbe3f3b867cb6a7ee959a328b0fd56a9eac1f4e40a22bf0a30073cd2d48f99245ac03c373810c54eaf3306c\nA = -598eef47b40d1fa1ce260edc561bd1c1ab286a7e068af412ec2baaecd07c5b9cd596505ea1bf0370ea961c4ceeb9be76baec74e6952cb846f20e5da406bd01368b85d59569b403b7a305cd7448f331f10a34def43c738fd633df9a3eb194c32d53aeb567889927271d71d3929d43fb9338248b64f7d23cd1b053239e09cc2ccf5fe9c9ce240f1a10fb151a8583e4b4cbc70ec3082dd20a9962d564544e\nB = 559fc917de34bd7dd7a23a432142ed79e3ac4a6caa357eea21e423eb9af7fd94f1eca735d2588ec4c2ff013520c3a0e209627217cc69bd5a07ca46a43ec1f1bdbee5f09ceb1b2c18bd388d3852e51070943f16152a73da624be680c671057677356c6f281a4ba1f7c60609125d7fd9086c907ca5c191820d80e483886b70c1074e2963c49996ee92577334881edafd88270bb967da795aa4fefb739e4367390ae\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 3488bf00f67b852592922fbae64fa56d2e4e7081678e789bbb3b4f48df62576d537da2e99c9bdd721c725b9a828194662bbd51ee20ba73d4ed5562482540880686d9fb1e8ae62d08e39fdbbab1d18e399ebf07b3a6559dda8b043fc25a8152858d39b10ff64776e00a839950e7a9ed5ea95b594b6e9e9d4348ceae08071ec5d9\nA = -1b135d8cec9969561be396323e2f8be0c60903ca59b6c418cb19876e9e3cdcb9ce4f5251eadea11fd6e785476c70822aebdc94617063d161ebe55584a8a774ab230b8228a2b65bd5a6c873bb6b261429eefdc7d0c64c7e78133e739efe57f835ad03ef8f84601e1a2310659db5e0ee706f23e3c5c38c9f8c36e5b15b654d1cc528f1dd392f1b08921af8be6fe4e4e6db774392441883ef867bc729338943b\nB = -34fb63435c90018e5843098e379c76ef3ba0615b6b500854b3dda3e77fc5646228fcf3a6e1cd87a506e4959ab05e24474990ad98ad0865942737734c03dc289307f1b1f424b9a8c2264350943449b3d2b0f71f989039131e23095d122ae98c0089a184dc530669e804140134e5b602861a5e61c030fc3d3b3eef0a59f8c0579fc9b0afceaf16698de3fa07c43231312254c04ab11ad7a29efc4597780c2cd1b64b43\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 8ea5fcf7fd41803606c95729d2d910941e43b222f9b0c93a1a803b197fababbd653a92ee34e805906fde29b307a962a294aa4dabebf0d181c046653ad0fe6da1295eef817f3289dcc6579cee8869198c39a9f79992cf6894162d35d812df327a64470c935994aca4985d0e6a783b853ad762338dabd575ca71034e29d768d014\nA = 6858d029a62b0f75e4c59f3ec067e3990b2304c90a097daccaf554abec49a9d297ca14648471dba08f22ebbf8e238c89ea06f188203599aba56611eb3d4df09ea795a7e28f91f4a9a582c6b949c6ffc584a076de653446aff9b24e87202037974aede37aa9a121b5b70a3e9b5ca376c9056c2c91f5d5484baebb64cccb6a09b4f40529afad1ed64b4cc4aca586892693fb5f92edb6b4d5f678f7a2441e51410\nB = 197d6deff7adc30b025e7e418cca0a641e1a1b35f78fb56b9d8847f0690313475e6fbc6f73c3a718b10bf37434dd9fb1eca33a99bbba674195b20d35e3b34ba9d7c8438eede24ebb48e6d39eecd93fcd7dac44235ad32f208919f57b261da70ca378f9b03ae5e5a733f97f0b3f4102d971272015bf50b6f3e50c7b36cdaa14a8a580366c9cb0118ceec6e627827b0b8f614656292675ddb66e1c55355d5a1d78e69ed31\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = a25db977e7a8fa4578fc530995335411432ced67e131fee2cd7ff56970df64a6f0f4a7d225d2f4ccec8e98273ec9a0f1aef01dc0b866e425d64e09cafb9ebe3f80bc0ad71c769f1ecd5efdb4a990ebd3a94303f52f4a97e3a1d615918f8b2df5321c4aa9339b4453d7a710a803106dd0ab49c6cd9aea431f97fea9fcae0bbd90\nA = 13f97ba15ce46ae32147a0aa4c1639b6b555f4d8a1af15ede4f1103f7a0b06b4625bf456d667720adca0c4e26e858f008b012fae63cd89322b33fe51e87714519e7dc3cceea27d968b46ebc04024d063b17901a7ae978591ca6ca41afffd81769f04b714134cfaa6700cf23bfda6ce67313988bba5fd3782bc62f76cf551d140c978dc002a779ae37400d34cbea013a5d1338b203ff267861edd88ab8ee1e4c4d8\nB = -88d8a4c8c680fb01f493f73753c70ee753951d4734627da14962e36449db5490b8c575729fafbd203a125b500b96364e6799d9cfcf0efb4ec877e86865eea5e99e2fe5e7655c1ee0eac641e73b71c66d7a72c2934d1ccfefcf59781035b2c7b89e5de3f7d1e9128cac57947d22e7577832ba374492a2f53be37e17733d8bc625fa77fa5cf093975049a5c477f792fe75e85da26cceec820c8b255df0292824b4c3a8ed455\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = c1f2165a402fe9becea284dae60453965ce327f540bb8969562485fd1bb60372b8689d9c9c97c91bcfd699dc370117ea8b704f06cae3d972dc6e5eaac971597c69d4dc24a68b256f97229e643706aa6d2d844078a5fee2d08270820055ea58155d7bc754f09d0c6f804e55ebe53e3ec418747d4130cec68533f6f0c2f8fd2409\nA = -626a1580e52ba52a877cdcd62b34cbc7f949148671d4a61201e03e98985d704b2975b9a2d9c4557deae065becd662ce8448171ac582894bfa2c59d4ed20c6d0471fcad1d0fed1291df5e4556aba72f3645486580c8bfd0e3c8f6cb34fe17ccdd75fad4d4a2db4e00bb8c2a23ed17a31e95631320590f40416c153efdaf897e3b278a1faf1917554d9292f90c4edd5992748b58492289eecde1af34976ea8ff507fb9\nB = 44c336d7739118340048939d6c198f73f90e13030b69be286ef920902391d87a58df3632091d0ef25340eab395203e8dcf3389e95debb7432165147e145735d2e3226637b4b8cb7d85d68308be07f217f57fe439b31fddf3fd469869a20f1f852e1645b0d4903432ecd1fb6397db4c11f6b6b9c0fd25778b0ff00bab9ff576b16538a6b7da40f01fa7b987af8ead41ecb66b",
-    "8940c0e8a1208d0026773e711153d99348e92303\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 98eaf476f11168bb63fddf7dbf3347e619f9b580ea6804ab893214e94ebc089cb652e307f1f37ea7ab9052a352e260ff7d1e8c17461bae68c52a8a8f1a57a84c79b2c8fcc2d504ac4f553d2534f2a776ca129ec1942d83c8ae24c772f6a8429bd61949ca1aa714cc3881ed731497b84415c88ad4b9be34197a549737edcfeac8\nA = -15897a5a986641fc2cda42d185d72aa1552eb92f788bb71cc74c0e424bd038e02c620d0686ff88ebdf0bc1632093c0d89e724e7d5b526b0ddc4c7e145aa90b36be0d8574901fdf286df84a6b52674a78cf21ae4865618b4347bd905461d878537b33cc41710ddb290964c48e44d4d2ce2ed82847de75938d23ed418bb9ff1caa03b5c1ac5d65692dd1defbc6013b3270c4314a45dc67883762fda5509b915e8277c1924\nB = -3a7141f54a0bcef68cbc3006166f7e15a5c2394892a428fa417a485981316a537cb3ec757d4a2473fdec2cd61010a9ff865852af8f43afc79a97d394bb6c58643858e2b4dc5cb958c33781b5c35aced7882e8b8d7b4e4249c2b82150adfb0c8f2bbb1cff3d2ea27ed24eae030ef468ae4d6b7462f0b072cd2a2f02426b3290b87b14d14b34e91a94c5bd69e9eda53335cdfa7df90a57f97f3d023ff85537fe0a8bc5d8fd7901722\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 34464b7a50713d17b01b5940b5acfaa7006aa6b9b083bc17e0535b08783761391eaca8703af2edbe13dd0fe9036d38aecfd9faae08c0861042ea1a25b41fa8a15b7721909783de3aca127e955e177987518dd010306a795bb66466fccd55bd9e2bde17470cbd36b1e8f8b63805229754387a5fb40f3ee9a8afb2e51e25c8bea\nA = 701ae8c5bafab7f41c999e492f04a7626b2b1054e6dce1b83002b2d3de46717225b018733b0fa8fe3f973202da8a090ae3fd14f48b27097513ecd4ceb1b9729e7783c17fee9be5221fce4ed3860275b3b36b7416594d2b65e198ff564e82301cae23756c878494e57b5ea8fd22ad800a582cae32fbc985d122cbc6e0eac77c1000d3ede45ae7aa087534adfdea8e9f924efa1b19c43dfd3b7bc83d7c40df7c6578a320a19\nB = 18e0256543619a750384d30b6a7afbbcbdcd9a2ce644dbfc97a8ff699e118032558f706502c9b956695cb25a46d7526596b3d0b67b69611009265838bec533a9488d24583e7d7f2284e23c3cc4ccc5920fc57e24f60da0d479d41f5b9c6ad9152903a4f37842176c6257fb1e3e0681d6d583e704c1d1b24cf616fe638106638fe9d79a0c74f0df67cb2df9d99185324ebb037d01ba0066ba947d5345cd3201b19769d438c43292f572\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = bc57cbb3e1051d3a3035f77c2e375c7e3221dd472edb1a5ccaa7521849fc0ccc7568238aea9335a733d839e89ace6f2b66ef238267e0050c065c3d9553cf50cc5cd93d34fb43c3ea1c31b8ebf0b751f595a7e5e3e860b366229de4286b9d3f0267f78c6888ab3f208c55d9292079116ea0eb9f4ec2934c97149aa132c03336ea\nA = 1ffb0aac11f6d1d257ef7aa997a030e2a12b0615fb11ff04f344f6ecd550e8e77e9883c246e009af33a51204e4066ed4249950e022a61337848dae17c88317e15ade5b5499c0d7597a69a02b6c18db0f975c19c16d2167c583571e947676ae9c15be60e69d76e78329aed5fa57dc5e616795b5487f3d52bfe74b54bbf93ceda093c2e14104a6d2f017f0d200a9fc89deaa283e04b0bd9015ec67598425312868eeefeae9c996\nB = -9de2d82e25b449b8ca4b02b2d2fc0a023fc5804ea553aa84674a815bd74193a2e549070e2cfa0b90a53070646875282fdf855940905f834f5a07f073093c658cd1813fc5cd7092af592092d789ab5481bfb14b6683139646cff8eb1c5dcdb6a33113d1c97d4b587f15f972c06046730b7e712a8e3dd5f4bfd07cfae289047de31776f222d11510ab6b70a200ceeb6802d6c33f913c509b31b96e2b8dba9e25b0d2250c3b102d814683f1\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 9f7f4e010370ec1d76fa83f73c80825c3b71521855fca5db06d7ed830c910d0430375bf319671f6a83bf6b57d9d53cfaaed5bc5d615c5690df0067b18791c33cb9f0ac9fa5f0473e4f4eb7840b0b660962097606b3de5744089ffb37d9c0df1123a91a5896d4deeab8aebec469b099a3a9a4f6d822030ec2fc4d11636706fd0d\nA = -7f56093243ec2399548ed95df79363e6ff09de211dfffc314b7cee526535def0f9a8eb9aa6f1736528ee7aae8be55c06645708d576111766ea33e0564c12103edd61ede3128a7a642f968eefd0d7f3768b1325c2dd910d459b15e54145a234225fd29932234e59d3ff5099ec4d5b5c6075f56382ade1101115c7b94e1e2a7bf075dec210fdaf2357c735416dd5d616335002d1cde6056bf7c478f810b78c661a3dbe6e54084bc9\nB = 4df1a6296428d06f51f31a1b0f66d0b77a04db3bb8e1b80d64da649899a1a55d4041bf0bb47d3e3936ee0f3740e1e8c2b235e1b8944d28c7d617d1f968abcde9dce10d6e3c27b2e3607d8df815f5a39da9b5569e95eee1fe5532c0a80011e7415800d8a9ec175fb1d13dad959becf04964b70dabde6d37072dc9f6d914309b850cda33a565515dd6c0181fc48bc7033b314ae0bd5872480e02ffc08dac4e3030d83b33488cf149e19b0021b\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 6da5fcea305cc6eb47fb17190889e6a39c339da1bea2d7c95e997fc538b4aeec8b0edf7c109faad7fb6c656420f4afa104ada7a0d3d14d3ef0fc6774b59aa2687c0b4efe7c3fc83194a89c832f7168346cadc2b1fa6fa9a23a67c91ad731b4cfb9943738c7f9951945b2eabb3743473d9c0444ade756291f53fc7641501597a2\nA = -19dfb98f9f7d20fd331ea749d2019d8367935fb75ecde45d6dabc815ab9e593e51178a72816f85aa678304e6ff3a2c24079a59aca253d76c4ac633fea1070753ce770765bce47428f8f5ae40c26a3ac91ddb551b3d575bad9a3b6fc7954acc93aad2131b78fd212fb0db7cca4195b41651a5311bbd4d8c64f1c93e6520eef8e6308e98caa1cd0d3c9b4041182cbfa131c4948257f1200b1c5351bee77ac8bc8e44680ce64ed0648f3\nB = -2736d5038c60553927f389c0650bb1355b0ce745a7dc5f52c9909039465344af910a5f6a9cc4ec130b9877c1cbb52fc08b20d672e42b853d26a02bc07eabb9e3f91399db8465b6a8b1c9f4a4b9eeeec6e9b6180f1a770c139c8f29ceced61cc7ba182884ae01d14dd85bc924391333e8ef039b586b6a0ae18db3570aa560c2b0226d5e23e7e753873637c25aeb19e74997da4f5d0755571785bebbc7dade57446e0df4cdb8df23c1003533f60a\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = c0265805aa8ab52da5aec06ef7cad2026fa0b18edb27b4903e3c068ca6464465e34d3f3bdb4bcc10a19441040deaf5569645f7e09b36c56631b3a6144d6206d39c9bcac53b54210db6d484cd6a2780bc68c07272de03a9bba7e51c9d86cc8883cd2e1864a2ed711d505930143c883c57545e9c40851c6df8b3314a8c9a0d201c\nA = 5622f906b077d243521325be82a43fce321412bdab1f15e4ff0c11a7066a288b7939afc01d30243c8a4150e74286611ac1ca4daf457aa23508a7af869d2d55f54f2746afaec477cd7df0d5711dd636802ae7f673b3f730236ac3899330f89cb71d48c2838322fe856d9d8b4053d9c1e66acdb5e43614ecff954dbe37c5269d7ffe00b34e682c0be3d7cf653ef212daa3d55dff92b329126636e440b0bab55f4810a2849f77c39ebb93e\nB = 1ebe0d1800b1fcfb67d7d54568e45dc604450c1dbe103ee21d48dda300c1d9b9415dcd9f5a56cf12c2ede3c862e895efb83621435377387b29b882b2acac78386895c7daa90810092bd3062a3a4867f92d54622d7f0b89b40fabc4709fd507d4002ca80de231596630c234fa418611ede0ae4a9616d570232c1b03329bad02220ef64e455c164aadc16190ce35b78060a6b117b4b0641fa64dd8e8cddb5914e7657573804e63dc7b216b1a9aa175c\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 606d2b6f756548568013bdaba6e811dbae88fb01f5f36d30d15dc1e099d86bdca9fc1eb3a785034ea14cb7f4776586327d57ca5a52ea1b30f26e2a76140bbb0e930c7780673770fe22c5ed443c349510e1494ebe402f2621b1e6bde39b8691edbe5c7242efaa6634553e6af146dd40666edf4a3db5d1e7f9347fa1189c1e5168\nA = 14ea5e6fd612945c71fdb17ec44d95015773edc908a85a6645a8eb823d11226545d05b81791401cefc81ce9765eacea7a619cb482f29d38988d355ce731bc9009969b7487a3acca2d2065c1faadc5d6dd8ca1dcd3f3d4ff61d0a75ef75272e62193618f6b802f70795041de26d6ce367ba996dfb91167cb1fa16c8977f982e1718de7d60275a7f66e4ad72ee55ea06267cc4e8b08f488579825cc674b0bdfd34a01bed08b62004fda",
-    "15b7c\nB = -8a542280f6c8bf4d9fbc96d5bfa6ee0d16a09dffdcbfeaa2dfa1097a760dec7bc540a0b5b2020bab1eaa594117a40a9bb99c3f16fc340c262b29909608740b8e77fe4706a88dc0fc3bcd47998e88fa02f617062393978ac1bfe14235d43f3d5edbdfb9f140412f4fc2dfc05a700f47b1f0f90da7ae07ae781d9ccdbb951f19a8b8a9a7dd8a65942842cf207f3baed3a0b2f08a06ad0d9ab7ad0110346293d51ec53ff8165b925c0e7906be8b7303252\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 512220042f151479a6a8b7c743ba83366cb7733caf37164e9c823422ccbf78b0b83f426a7230f559d50bb0ed3d9486c6a6e25f4cf96c4fdcb2c861566c6a73215b6d08995a14569710cf9e54abded1d77fc7722d06fda4557a3a99862e5ce963e1be25336fb42a4629391cde3aacd47ea5f5426e7185c5df27d9136a6df26f54\nA = -4d108217b778694931088bc255d1f69cf8f5a14252156163f948ae58d58f2ed54f518177d668e795474952c930052c1bcfcae11bcd15af168ec2e881e6ddc8de257d0cff90ff3ad409bb3a080d30fdfda99078cc3ad8302a4bdd77de66ac082b40fddb3cb36c75a86bacaf60984a74a0fd575d751ed2830650d85844aba9e3f781b2dc6b515bdb8d9459b083e1aa653ef177de76282e86c99e97dae9c0b050c9e6456a051e7d99adad7be4e4\nB = 7b9079504c635655a588ac360955fceb10cdea5f3de548ca2db681da38c17a70df5798f72cf18691d14a5f400ac69fbb47e64115cf071466c54bc7077a228249209542683ba57791352ef3409f6a947865d8f234ea9d39491b5c001685487b32130bce9aeade97d9537afe3f2f87e8f3315619ef7f215a73cb724f1adca99b90912aeecdc81485c0d00a74387ea99c965118fc6a9af1163e60d1ee6a1eeb12d7c2bb9a54f747a415beb5873d616fa0eafa\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = e36899d83a143c82e19e11494ba18478c0a9497fc89fd83df38adcb6b33918645a416626409a156899c6583ab9a4426438d9c32cac54b78df579cb7b6b1feb3f39ca4a6183743a4b823082896a89f9f1722be842cb2d2ceb605f84a9f9b61cdc7e184593fc2f9ff2994fe6cc4860d255809d04ab47e154eaec9ecc807ceb298\nA = -1422272d9e91a14b38b3e81cbd9411a0cafca23addf4f33c94a1bca70603db879dd8a9c0b95f5986bcb447731219c4f9b32a1e3253b027b7963ce40279dbf4008e526adc0bd7bcb2b533392a105c6e8e1bddfdd2bde7dfa0d2e3b1c6ffa07fea07ecdb9fc828283e93b0ce4861945562478b1a56de32251b7d31f9a2309488f7cbdcc38cd6b1c951570675ef0d61e1df69fed78979dc755f160d93ab5a3e65dc2944d3333cb85aaf87a153a90fa\nB = -2424fc1e71286ce3be684a10dd885e4891b52e9009c3021d90ebcaf68b6db81130bdbb74869cbf142e0f44ae72684fc12c85abb5157987428c7812889beecfd7bb43fcac2eb6298ebf1dbcd2e70e4274841c2703b8685df18f6e5bbaa1422004797defc6ba843e77f891bbb46699a863bc1d77c5e3cab809c247e2975e8170da00fd9c8b232abc3fc6b16951ac4e6c96f9503c1ff2d6832ff9c35b2c8aa408645849c577d2b8599ef520da57fe2a9eccfcba6\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 4e8a59476d47ee2cd0217bae2981cf25a2c38e5f5d5c30c2d8bf95856a6e8f42429e565f1836365e550d85207246514624e7ed932d6f5802a50ff9f15d500dd84b27729c1717a3df0f2d6dfd40f0094208445193ba6500ba03fa3f4bdeaf9251aace8729b32ec3215bcfa170575e26265fe523cf44a071470e3b1547901e9227\nA = 452cfc78cb9597e67aacd4ec83e5b473ab8b7a1dcb6097fab37e25d5a6e25c69c73a6c20de0e2a744375bbfe7f612036e69c7a503255d9e17c6ec1dc6cc6f634d4c79bed4764496e5c7c026fdf9408242d3b234195e67a5681e7d7b861f58eb631ddb9aeeb0e5b3ff7a7657a7fde5975b8a9e1f643893bac47debf7918c7ef8f6d7439320dccaf63b80ec9761559078baa8e35d98fb9dc242ba83536eef7ba9901395ef02b19990d8312203df7dc1\nB = 1dc222e7a737e6d97a703fa232defc6c0a4fb2bafd247c8e547b9c474421cacb7692ec98f94be19a5e40269e1f5713d06a6d081a943dbc667bc867e481b99c55e437061cd44c4482649faf870d9347e0252ba9dbe116fb4992dc2c2a0583c1351e9e01e71e9324f5fa942322485bca93c2d95cf304028e68224fed446966073ec7326c93ae326a7a533a36e053437910418bf1761abd9c4c5ab7e6f538e9bf963903e6c80f21a0a38a683e8166e4626a8d8b743f\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = a4d5e9fb7f0d75ce41ffecacd2ee1e4d15f82dfd4decf5ab1bee75fb97792d0d574fee60a30b15af80bd38e6a25b1821e61628dbe456e39fea3f8a9ee6ef3d2332412be1500fada0c1728a1457656eb3e9d94c64fb2d0ac89f10f2b9ff57d73207274ae7e8c7538936cb7241615b830cc9011d4363ef88f51c7b3ed503c25179\nA = 13eeef030b3110451fcb1a258434aeb51d3dc805b38c72ef7c79d4b0e18d600e5dd28b552b59f3dda1898367ec7da5dc6d9089a585cf52002eaf8f9ec64b8d3ec50d0bef7dc3faf203c48583ec89757cfeaf888ec4a91470a6b8ec9f26a6b07f3311b4fe972cac2f2ffe47f5c11d2dca87c62680e2229120cba4de9cfce9f7f5c33af8398c07ffabac1675de1845e05a32536329647214e54e5d9216fc0cbf2730898eae19e425688bf184d16bd1d655\nB = -ea324da99252edb03f40100e528d9a5080c43be97fe4b7e03d9563ba48040d328e57d0defd4b7ffa9bef3ca0d2682aefd2a0ffca8566e755b11f2e3c6c1b707f1b9465592aba6181e583babd5c70588e7123361a8ae77d8c398e33f894ee288babea1d7eb63e2f3de469e502b5048417043c5a9a9a3eb921cea1533162e3ce9c79e6caf62bbe7e17b180b72c59b9ef5fe1a001b733d909a8278029fb4a63077ef9b3545f1159ad73dd75030aad599ea4884677e01f\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 2f096fb8fe2156c41ab695956f13f0fd9a084f87ea5f5b1acb6b60c62617b8d7079f4b072223ba18cde474af3942599fe070ddb0ac1a99f42b9506a2648e1b8f6106015aba0bf7a824842403bd3f4ac8b6fc4a9861bf0e8ac59be0322f0495e4b515fd579dfef273160ddf96e453f4ab663e703609c709fb1f016ca919fb26c\nA = -4212bf679cc00adb2ca502604b71dd5dab99cdfaf55ae92aee6bcf8b3b6354a384656c09eec6175a95c8cb4591ce118e783d6344525c25e5b356e45802ea3ce1fe764833132e6b7bec434e4481c9cc2986904988bd8da7dc2e31cdc481fd0e359674bbff524124bab1ba4379885a6cfc1b73d953e6d1aa1b938129d74fac9dc597c31383f2f7e02fd995f7065290a9812ba8e205316ad5bac6fc65c6c7310f1a6b033503ebfe85bf6d3851bea1b65b9c15\nB = 7ad83f97f40d5be508cb394c128764532f0aee9a108eb02840ca1c635860b6d751d5f676e8670e2f61466397e1bc68f97ea52d64b335d07aed22f20bb1ed19e3e42e4205d650e6d37714c2f80d39b111577725e3bc7ce75bd7ed5e44f8377d5fc2b97f05c3c1ed5ca1ec90ba3ff7935a25a8acbcb15fe1fc7aeaa1e444cc2f06c1e6711721d24b8969d465e4958cb87924b3e0fe99ccb371009b5b15747bf6dd5d0fb73b8fdf58d955c8773a55424a34c741406f6f904\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 909626a69c803e9acdca97c56781eb672d6fb31430a53b853f467ca26d4ae96c182d71c0212894b776c88e773acbe9602e3ca56584c39b5947724290def7dbf04c6853a108c1282def95dbd5bdc015b68daeea0ee959b35bc5af98a4ae4cc7486e627bc9432bd009b21ee9af3085f074a3ae1bca879e321018e991e7898f2897\nA = -14eb8e28dd04a159c576eb10578c24fad9eedd3d8b7560b681002a54a4bce2167de05cd061338f63c50b86327a79595a2dbfc1d3f4e76aabaf88cfedb69faf5148c61f8cfb2130511a3bf4a17d846ededd4c08f3b635182dff1854e8c4c48007af028e06f01235fc2becdb32adcb9e2058dcf8f8655624bed9915faa06be972282cfbf8530bc0cf2de5b2057df32e4a6cbc3c772feea0a511cfe3408a6dab0e2714fc4cf15602ba0da03bf0016f1f3f5ddfe1\nB = -388da160568aef9f82fc16f48a22e8d7aeac99121cfac9b748c815e5d3a823b673ddcd20c1168f98ba204df5e52535f61b224fc0374092f8c834321949fa0a812b5e65c492fd9fe8246b74143a943bcdbeba16024e311d673357a3dd3eaef9ae3a72bb06e03e34e091cbe5b6a9eb9fa3d7f36c03baa5c3e242f2c186b58db5dddbd73f6aa54aae027529b8f8f0a536b9b283ab08247b9977a2ac2d0d9f162ad03a2fe247d2c589b1a2d14b5f90d5b9c0a95918ea956e261b\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 128e8844a2f04704a4a60cd33e85cb7ad373ff683abd167894a35a1d",
-    "af947f504c0abd7a614e293ce10797a5330147c88c4d5e1dad1bdbeaf74095e3f5a515f2af68b7bc11ee1f53b493133905b654318dcfe73118ef1931eac47deb6c4958406b704ce027d9b027803eb8e639b52d5983094b8ff4b54e86a7dc6ea169ff1af4\nA = 75e6b045aa44dd9b8f4b434dd4bb1346fcf558a5e96b00fef9b6cfaca72fe8b1672edc2a64beee8b959683b1861138b297629b44a0caec6bad2ac05665728379cffaf66a129f0ba40aab7c6b1c3fbdabaabc87ed3dd580ba80ec7ee765e9a8fbe845c0d207eee7a1a3a0c39650c75ccb6bcdae2e0d5149991dc3bf899ae9b7626a2baa17b168b260d82fba84a12f10e09234035e08b730cfc230f0d2651c03e34d4952fca6409b5c6ea5d8791c90466bdc4adf2\nB = 102fc193633b0e60a48dcc17aa76f3e52cbbd1012f179736a0ba7a102f8dfadaf434063b0ed1b1528a018b349eaf192fe62f868b538cddd7e8e6fd98b93147727d58561517b2836e4a373bb31fc8d5e42d16126ed80b880c1a37940c138fc1f7255ee0b7fd39b1b799c34e5178580cdc076ef3fbff65fdff7497398fb1cac75e5c09cc7df1168a20f88a16e7b3ac78091a90f1169bccd48c0d06b4707ab79b741a168deae5ced5d48bb5f5dd3f465e43c82b9db7edab24569b2\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 9aa9699d1e5d2c6acb21e31890c1899f30a925b834adb5b8bc8cce83a1718944a2c90faa71b34379a21340457478c0c43121dbd65d62e290eda2ba6230bce4e6f18555a1380c7c95c1700793157f7c1cbabeb09460ca28dc596bb17851ab2ba6dc6bf311ea69bdb7fa8eb78df74adf171d4677a154b8536f8104d919bdd58648\nA = 157fb9e1b38f288db78a1a0e22fdd9f48a59779487a9ada2774a094d34536b85993e7b9ab6e24f081c4cdfb64a82271100a054169e4f1c24e3957ae9aa8300e85eb2a45a6d5987eed4f0fba6fe8557cbf6128e018c5f9df028131bbba6c544b2c6312aeddc71405f0e4ce648fbab9e5d51685949408e4ccbe06fe501a36fc13ee65c31f062313135054b7679eef45964c77f5a1556ac09b11c496d0ba8c6057e283bdaebb4e6d9e5c557d975745f9f98a288d5bbe4\nB = -82cb6334479bd997c771e894cac1ead87dcbaf8f5006be5c70ad48ef94303137bdc45f261af91a201b276a17d884a56ff27af7dc06cc5b7b9c94f7c4d4a36f68f8d309c477b4969a6e7cd1b2afab9deec06555cb753d8a0eb00965359ef865a84bfa87b815a42b2050e1635d5ae5e3743c007bd79e820aa37a968702a960fafbddecebe63f022553cadd7a4d4fb27b4dcb981e8b490e80bbbf13af8c4412d158775db71f5fbc9986e7b8a8f9299574abf7bdf9ce7544e8c4e85bc\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 46e401989fbcde9d830dc6e3c42768999f153d44d270d4805c5beefb470bc1e82706aa7173b359763c5e15d146eca91a32a36f0a80802871933cc7f2ed15a5472988849a2d2f57543345b531538db57ab9bcbfbe787efb0a82e61baa505aad628df5f9e881dababb35bc2decff267eaed3d3671757ae1764ec5163b792b4db3a\nA = -590c16ea2cf7fa7f63b5cf74804333f22fd2d0e1da7d226da8425abad2b39a4672fcebcf5cc15d220b0ecfeec09665e682fff0140f16889f7a6ade9ec11aae3fa3a369b3fc133babe52e42b7a8bb9a24777521f4d9e0efe7d7977dced9e40784c24d2c6056b3b668ada7856da71af73d2dd33d2e481ddf40999d86a6e236d0d73f31a67c52cc8b38203bb2840c0b92c2612ffe5fdb6be87f9a787d70b3dd506f9a63d144db3417495f0a48523c812d14a89710d95bc6\nB = 5a2865cf2254710a1a51ee3056b0c1f6c5f77d22d7aa8f939e6f48ecec529a169e630c554bbe682a8c4de9ce4daca77a278d7e752cb678141ddefa75ba42e661885a82ab55d699414ffeb75802cb8f4e7583bec8a7ab58803b378bb60fd46f476ea490c9aaba568ec17f3a6afdd6f20ec54a512f7aaf62d2f941e35b4b72dea77095e863dcb38bcaf8777707c1dd437ef2ac6b6a8b2b832f80ad2a6d6f279c053d02058b1a657a1cf5b6b269e15d29087b0cfc0c2d4c3fbf32a167a3\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 1c9649f4540556ae82ffd71b2c71ea8588aeb845c50dab595db9f8faa01a26c809d30d8433b6c0add465e164cda2b6723c942ee87241eb7baf9944cae08babd8e22a0eaf35c09e9efdfb9f8bfa65d53ee6eb23fcbe1d12a66ae05e7592ed788b231b000f895d098a24febcfa4372d249575926a5faf966072f29a62a401ec51c\nA = -1bc9ae5fc2f6a3f1274584bac1e145f02c5e8c4779f4df15e98dd34344c988c1437ee4428485a09090d81b18606a6ea5c1b9136872ab5b37373fbffbb5b3fa8fbeca1e112b9f1643658c2f38b9548cd8f0f271779ce0acad403177057ea0a2af2e7435109879941fbf463488a2522b831b95c1cff21d2d816d70c25156369dbcf04a0e28e1d746afb8a77713703fefa512816fe73e203bb4c3428efe09b946b750199bd7a03d30feb90230c219a103ad4528cbe0de1e5f6\nB = -39cae179d955049f830867d4115d3bae25127c945b1fa0c16fa850e8fd77c1b3b9b7916b9983c1659b7cee77b7dc72abfff1c56681b7931c5e58cfe4f1bf0168ae32df0df8f652223885717a98f858a497b1a4be62a2215c39316c34451b0d957791f49139921d9ac8041899b8fdd5d3d443547a26ddf5748147e4c3e93f5043ede42f38a9baa628df65d3d6148ac2ce182056700f0f94029be05d3ea3a218b40f65a87b4baf097fce107c080de24880259f1046175db1297016af76d94\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 9fcf6a47addfa336557749821a88ccd2573a5ce2c3094a17d9a29b33e043bea165499e89fd2c939f17a670694aff05e9af46836b62c96e597c83681092d63ab9d6e22751aa8fd4b9ea94a90a373876ef0f6514304a495edb5ca1795c9ade7965c70f9aa92f8ea460ccb670e9a62c81e9c\nA = 71b93fbad39b1c2755f2051ff7d532d59c985756410d58aed3947d6ae737ace5aadc35e7e0d29c684b9d4bec9c0fa277996bb30230f70431cb7b905\nB = 167be8381a3392dd4df62e150025e13b388bf366922ba8632614928922cc290772135857d1b5234d51c27862cb1a055c1b86260b6ec\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 8e2ba940fc5165c6c5f7f4cb55cd89d1d5f59e90e78730bd66fb120a814514784879dc43ad4f355030ddb3486a59bc34b601474978a94ddbceafdc0ee23cb18708bdbd824d37cc32577802ac6057fef29a71f168e816309fc80cc46f251e7289c6a57fd222d5868263360af63dd73e7c8b1dd6b3f3b6939849580b9231940a4d\nA = 1220ac4bde4feca135268550ddc79d8b05ff72f483b39f77436f348c4f5360c22c598f7dfb76697bf6d2ae86c68e90748b8b729b25f932b2e5fd33f3b5\nB = -bfee56cd412318cd62e7b6cc49217345d3a94e7fbf6fa19053fa685efbc0f8b320b7e43883189396781c49371dffe7d126c032d1ae4b6\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 8e2ba940fc5165c6c5f7bcac0e449b64801e75134a390f120acc58cbee43888f50d07f7aa6dc2b33643c025cf745434d20eb1aeda8fcee5fa3fa5baf10d67c21390297857aa50bbcc4a29a6b10885f97fea60f1b88fc72512c111b938142ee8d67545efe386622162e8fd50418b09769b8c22efe54fdacd652580d609f0528bf\nA = -7bc53f6f2e78628678ebc8e35ae4905caeec61acca5c64fdf595689cf005bde2265cd43172802fc133dafd933d7b48def44256868d202727a4aa6c0cde66\nB = 74147c93e729707111d0d531b1c135453f3e59f63a7e082b43dceb8b16cc5debdb6d7c0ce0c00ec9b5ca51e7673e411c3cab34938124db6a\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 43c47d7e319c32a758360dd726a1d91e2cf5c57f73cdf9ad2040e61a9c282a2962d96d300e04288461eb1ed37df19e6b88f104a250f9885898740f6487b081515314e0a217df2d4345d3cf81eabb2bfb346b634b9c251624748f6e9407cb677aff4c53fcf42cc027de267e6ec011e14bc7f3bc6666f693d21\nA = -1e6ce0b44105047d0da0eca7b936980267db41d41319dd5315889fe8fa2329023d7cf54f71ee179b5bfedf442cdad1920d311966f7175cbb953bb42ee105393\nB = -23a330c7e06cdef4b6b121d15a9c0bc774eb5e432e72d04c5f03a0c588e55e010b61f57c03c51edb1211685d8dfd2a35393091fd0e3ad2304fb\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 768293c84c431b9c8dc6e538ca3f856c60ae5e1aaf42325865418b7bed16c7fc2589968319cf41cb370657c8edc7b969",
-    "de10e0566b64ec796470b630e22477e7aafb38e99b6012f100c9d23d5517d486e3cab1fc60c1568c0228c9b55d2d77d23b1351fe37ad4fbf9c07f29330a539de4a32709d043dfc9e21aa1a\nA = 6bbaeec78b6a41818b7eec42fa3be7d639dfd86fbace2bc14e0369dba6dd3f04ede8b808743d809f43f70f1146dfdb1d649546441919e27f1f7a9760da4a3b152\nB = 1199dc2f52868a0cf440f6666b576541c7aec1e9cee14c1d22010ab0f53fe8bbf3029c639ff78d89dce82de85fd8eda4e67395d435df60158623c5\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 8e2b90afbdafa02ce68d537ae807b4e7f3e05a66b20b84cff309941fc3150f99d083841ddaf6f19f5a76886ad5d853c73051a0457e95eeb0fe3776a084a027ee77d14f3825713a59622ea163a679cff904db33bf6ab23b06eb4b31f4e34fb122c8c170321164439db783e7bec1c265eed33f33bd9cb6d1611c00aa18a9b4b90d\nA = 1c4821515167f7073d4b7cfa318ead1da1131499c12497447846caa84176a9d4af576fe549fd8b0f77bf8dbebf6c395f84dffd40400101bf28b1dda0bbdcc5da255e\nB = -de60cd639044e863c6a49c73213dbc2ca84e4225aefa5f880e829f2d9cb48ae92e3f2680c462ac697dc34da38f65fcdc1b4d8c3c99e8cbe29660b539\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 33e8e8e193b4b99d8bb382c29c1fc5403190d7654f43cd77e28d1bf77bc3a728dde9de9a89c6522ebc7222d25f46833fd1753a44275b04485c77b675d816090280b3541ca61bfa33921a79f7286830131d6eba13acc46cc2c449b3a359f1cb49d67a4d0cc1245f3f8b59b1684aa0c3ff1c928b8e880a3375ed811dffc991fd1d\nA = -50ff3e00feeb2efc6df6387d6409a622b7a8297a717b8d94d0dc41c6ec6f29a8455c3580019349660b31dea1e4f66b74147de93535e671c853b604ba06a9b62d34646c\nB = 49ff858c7081392defc3ba12ea8869fd61188ff15d9339be72657b00530b851de53b1fcbe16034816e73251fe1ec97bcecd8bccc470373974287ca328af\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2c88dc40414969e8b614bf8db05fbc38fb2b7ce144d7e707f9f8eca40ae2309c1fc67e713a8da5fbb20e808ad20aeb369cb72a77fd285e38a7895ec0fc795ade4ef1f1680f3a3b3cee4569cc9d5e699984daab3385815d2e515ba5d67d21dd1defc12ca81bc8ea645f8f8d103b4a0a9cdc92eb50690c07a037df274bbd5217e4\nA = -167ee0fa8e5d8b569d7848b068df06f6baed80f6fa6a442f9d11d9712622b512249b92c7ccb821ac751fe4ec0a7a47e04ea5571c7cb45a7985749ecdd87f0c0faea01d232\nB = -2207fd8dbf2b8e9a5e3cc515479cde241dd3671803f9fbf7859459ac66705be055fa759c85631ed2a61139657eee7eb08fd963b49e33666e60b7e75dd26b5d\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 674885ca3ef617a53eaedb9564cf96bcde131760ac541a81f4b25c174a6fe1444c2c206f7171e343e1bb43f81610162994c497419e75aaa25b664c122ed2b27640b45bf646fc5da1703fbf1cc66e10a3c306eb69ae5f937081a1a18dfc8db376ea18f4c1c499109b0cf8806eb32cb1f28985da790047bd7b32c1f67bffb9761\nA = 413cbcbbb5851a4ae12555801f7f80ccd888bb82ef1b5c31b99e1901d7e0ab91ee489c84044bc21fa2010f11aac21d0531fac09feb482fda579cb9f224c3149dd6249b0225a\nB = 1b6bfea70f1d80350eeb45f9a5cebda954d72cf5cd27a299ef5a42e1ed0b50a541d1657b70e50b0cab69b22e31d0944fd735957b1ff764865d9385af302bb802b\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 8d74ba5fdc67733ced4d468f6eb6ec4c1ebd79c97682c1d4daa06105788ed9c5144992e555d903804d7ed0dd9b29ef2648568ab7ff462a03e0bceb5482485afc3b91448fcfeba435dc587db6f3a022428d37fa0e85392d0e48e7d4ed6b21253084e653da8175587b3b709e28426cddfec8d9dc582d4ac2f3d540305c0fe17327\nA = 17c0b7f0e2cdf316e4d32f040e26d41dbde1e6689d98f0652da1c380daf5dfeb6a511b72d82f1b32d3852e9aa2f594be10776a8fc89a8a35c160e8e41b42a06a342fa1c309fd82\nB = -d7b7701340c5a358455ca5fa314ad83860d9f765978ff652d7f542de2e123bb976930b8fe84b9608648324450d8ed2bac4e44f2fc71711ae813cd8793af8d3796e8\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 57e60f79b4e156ccec4c253e70df8d86e4aef326150d612a5ac4dc285761e88ede412d28d9dfa5a6f5c073d3c91a65ba9c86067d81f296935f0d0ebd2af82e7f6b5b336422429cc3b8427fd8d3f5a6fe936f4208362632093bdd3cec1aa8f4b176d260f605caf4a12cc011f3d1b76135ac2507346674e41673eb16c0f55d8010\nA = -4f1568c207a9ec970b5c26f068f3cc8019e8cb483525d251cd2919b368d072ac8f40017a19fc7437cf88e927c9e7d6f539ee84865f0af24be0d6d98fb33d74e3e0d28020c00bcd61\nB = 723db98a78f42aa45496f31cf78695583526d25e167da48ec310e447ad3540be2636813a2c2f7b8c622795ac451992e91bb8e43e5737f0dd95623282e729d815b08ed8\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 237eb5726e2c628a515104bafd44348dbf099569815784eca5d6a415d3c12421c8c70fee23d6d82f7b5b136b70ffed3b6d9e98cb47854e79239d96c26f2ec955e4ea8dabc29a1b0765c9b7af6ef09ca673d1ee21c680e4b8cfebf47bbc74c993d017ead6cb6f3319ce4de9e9765cdb3ed8fcc57a1b153327e1a6a965e5dfa89\nA = -1fd1f634685eb1470dd9080529a891253a28a0b31e15c662733e20d43fc4cd71f4cfe83c3774adf8293a0fc3bd806d0b31b61c6ed0b4414ccdb91e2994e22797e5771c63defcc0887f1\nB = -3ec0478afdf54c949a097ca411be41f931acb750ef4f0ce97d0f0fc77cf15970cfbe24b170aa332de04836b7a0e6c5d456814182d27c8310d5fb662a818bc421587d95fc5\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2f1d500443fc4f4b86e7ec93e4d0dfd3faabda35a6dd31445021928373be14c37fec369ce80ebcb77aff2151b7ea94d21592da1823ebfa0af196f286d7a69ea54799573bdcd4d09ca4f33b8a3a93b35de5ff7f65099d59367914f1c79440b471ced6773b0802bd8ca99cf531b62892eb1e78d67f8210592208859b0aa1754b14\nA = 572de2984fe2ed0d5ebb5bc3f62b197fd592795d91cb16b48a0c898991ee3e884e5870b92405f248036ef9b3898c5ee6100a09ede5a48bf7edf3a067e4fc77e7e6bf6a6e3d4f538e3d66f\nB = 12c379402b18a34dc8b80c0dcd25be16c99d6f76d5d64b6050b90910cce594bc022794640735710c7ded857ebd44fe5b2e51574a2296f7d7a61b59c0123051bf2ba4a168cf8f\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 4001c734e1391a88640007893f167eb79ef61e4717d5eb14b8d80c25ed59c753be63fc8e54bdaded22c9c7d3e49753eb49efa010439807dba0d90ec4f9b498aa97f109af542bb41922936223213ddedac4d0fad8f1446498f4228b758aafdf1d9692f59029c76ca2832125ba50e811cb95f2b982a7a4d87b4726e6dd8b1963fe\nA = 16792909716b581a936287d0a8550a1f3e840935f0f3ddca75aa32e3489269b078fd19a16f8d6b2326eebaf46da76e90890c0ead3b35689bfda8c1ead17a4f672588f982cfd3da2c2b9bdad9\nB = -95ab2c47f85001aa852d6999f29644a6a55f9e4e12bf905f911f90d29cd1e4fa4fc9d1a2aa6c215bcb5c5643561499aab8f2678fdc5fa9c6ec138aeb2d62f635c45f239e46b0fa\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 1bfad44b58d3f8bc987116d4cc7ac98f89f838a8712d81d726189e9e1469cf46fe04675dc0b82e6e556b02c350ef4e30ec6203c7f1df937ea80f435af7c10f48538fe7755ba78993f304e64ca0d783b0f46f61bd14fd3fd30768f233c59018ce911a94b495f58e",
-    "b96438e416ca3c7eba5b1bca9dea5a770c1d2d9f2f62f821e5\nA = -78a6a6ef40e443c52036e75f0b35938d632bd45aebf45a1fff5c2e1b6f601a57382b9a82c3e8b2984e643eb1570cd83f3a6be6daac567ddf9f37bd96785662bc3cfee6f47503d239c77781a8df\nB = 4920f870cf9f371050e64a419ebe07ac92dd3525b41e8ecf6939a267e1ba853d54862dfc95dd21b3526eb0a0a7a7f8fb67df2e9472dbec81e15cb13266257177c5f2b92fced4cea5d\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 6b0b84505907a5ca37abeff9a5ba169975792c69b5751d9845c0f09dea833fb679c8dfbf3895bc470529e0cc736c9b4a0d08b75d709a1d04525ae583c5ba082d3bca1355055c7bb674aa1b92689cfdec4dbac84a96e81c855280e417f60e7e4931ef4f428420c0b85d2cd11c1030a47788d6ee6af0a76b5364fcf23b270e9d4f\nA = -143d843e3b12431fa0d873815a757a214cf731c298db61ab13cb87fe78b0a6184bd1fdcfec0c7661b10775b4ee2c815dede0ed497977c9ec5154f7b24a8a786501ddb8dd257bea51b9fd9401ff760\nB = -25d4da7b64f439987eacbde66abadf0da7c1653c1c1c6d9b2092351fbc714a20d2d7ad8093209da371150b69b3602480595533ecc1f3c5005a8ead10732272246d8cdfbab87c49e65223\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 6bce40524278ce242b0b5292d27751a3dc414f962d9c1cacb45fa3ee693ac6890d2ff1647abe578c40ea8d4b326a2e0e2fa7cdec28fe2da089338b5fed91c4277cc5be37537eec2f17edbf48a45fbe38f15c58c3e733d408d001262dbd40c9d246c323e7978df4fb7207aa9270a12921743cee2a483e7e71b221b09a6b2c667a\nA = 402671b0cfe14655bc650bd35dd0c36ce7f65de274a0cc4b708c6f6c3e84c2125ab2430e702421904950b29aa8a03b049910305127890457cd0cc97a3e05df67f29d28b0452969986959df02f59d207\nB = 1648c29205f19fe4c646eb62e8ae9b65260c2cb8424a526423c6bc04ed55870cefef9b8ba808f8ed2e1ab170e2e411f68b934abb1a22776969f79f9420f8bcbef28417582942e26646af60a\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 40db38dcdc201648da555f1062bbbb92c632c29b66902eabf90d98dec69ab3f3b28e60cad1571e7246f4c9e6aa62ad26a6d0bc08598c7a8571fa830cae4c2875c5c95a59f3295f998681edba7749b7e38cbece8887a7823b4752165e1a897e638836d408f439f009d0fb6c196e83e83ca3289d2bd0f0eb36b721331e4f9f80fd\nA = 14361ace8ec5223bf0165b78913b77ef921b7089bb5e28891d120bd3db6513ddc90404a4e6cd027f9b51fbc02e80d376d59e1f2b043954199ef8218bf26cacdc5e749f668ad3b4ab35cd796f94c06307e6\nB = -851a39d8b0101fdb22ea9e367286e572dd132b8a77a6a14dd0e995131467aee898230f37dc6224e35bed2eaf459aae579181a161450bd7ebe6b62ea7154a8a0ab590ca4a6c2f05531c4e24650\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 4b085796665458b798f824d1c1a88c23ecca456fb88713b433228ca8735141a616633ccec4bc53ea4f6e0c74e4aab6fece2e4cc4c4efb479638cf54caf55d4addf75908076f5fb487ed00d540e5b984acb8f81cae3ef51db926a06382a288092b352793de721c23c371fd0ce7a789486b2e8b867d35f47b5daac2d339d22dbde\nA = -511565611538828ff7dbc45c273fe46f4f5105d41ccf5dd343b41e9dc579429e56a9cefc54657ef0422960d1375b72411a5cc93ffa323455e006e242580358d6cfb641f46b9c36fa777a613b17dd4a187454\nB = 4f22597947638b9a9e9b9b7c2a8d37f77259f1bb1c7db65003b6e1a1c807469c84c89a75b80bbe0324fc3aeefaedc6ad9c0d9e470dac9c30bc48f6abbbdce9547ad7624f0ce9ff3cb6be23e47bc7\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2b90a57349ea94ea818207fe15c164f9d3530c7cdffcae178557274552f79c4ab56acd78033a570bd6c3e45789704ef0b0ef586594fe4cae3ccfbf9ceef46e769589b084adcee3ef8345375b7103232465b991273df724964248737d5eccbac558e35e4190112571d3e7c291baa7aa8b1800121bd573b8419f627c0091e1bba8\nA = -170cc62ad57094d307ce1b317ae5e825c2f2e317ad6060437afa105501caea00dc9a86af8729e2f3c3a854387dc3ba368c0a84aab1a527ab34fe27b0a69bc71c728cca87be728457c65eea7d7538ef3aa282615\nB = -3d9da1377a88f647de57ade46dc7caf71b4f42bbfaa5e77f16cfcc90f00b5d3e9e9d82355104c7cd0db4c1dac0496be3aa35706cfc0a30a1329755faa439694e8e9b41fba8f1ebb46140818c7008e27\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 4cd4da762c7576d582572d3427abc4b4297f740705fc14a32b46347541b152d0d1e3a11f27213badcea1e2009e34a63350c7a59e4d43654b28298d2757d6b54c4d82f580e98de4230cd119ba350416452cd4b8adff29b9f35ae0c533f666cfed716838e2b91941dfbea8d6a978a369d5f27554ef411f15e5a89850655d7f3f5a\nA = 4f4a28af27b926d8ac347503d6ac0bfec388a6c0b38a577501c3ca4aa709c69601824ddeb5eba4d9e437a97f3e4477e1487d5ce7b4a35b90fb863657a5b2d901bb8c3c838db40b89b495ee9875e8eee607d7b8013\nB = 13ca192603bc8b2da29dae67159e4f8d32f351a503434ed9e4e24f74abb5908ef7da80781c71b1a5ce64fefd13a16cc1eab05a370bfba2a97e6cf90cfe98d3a487ba72dde0762c36c10e1da175f1c1b5fc\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 3812e9e835ae355fdf328b29ed8b86dc3f6895e379b8b5d65a5de41eab5fb20ad3e2290c8ca69f9500248ff883d9715f59d0db6257d13c5cd612211bb1fb99867161daffc77968bdffc1fe48bcde0fcce02ca93975b3cd9e93b56974ab4beb59582c3d0ef2a65957f701549f8bf858de0c5bc98af3e5722f1450de391876a2d9\nA = 14ca6101af00d67139b985ac9f149accc260336237dd2dee802b5cc6e506e217b74c1a007ec10c20012f071ddad34e7407012669109ec1f385566ff04cf1a1ab7562353c0af1ba1be0baaef920a188c60db27970f64d\nB = -94b683326e9de19e414f653aeb2cb4bd7b17e76a23de6a4d91c43d717a35e08f2155b444a9549dfd01a8aec4dc901ea9f629f16bafd2c84828b12d2f63dc154323eb2d54938895ec4c9efbcaaede274fd4ab\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 5ad7411cef0581b2e675d03b0ecb9969102a283eba5e779bdcbb7646d94e843083a07269c932d18b973b57abe54eaaad0aa76cf7b61f30505a263bc95aa063efb264ae829eb1d1d5f7d380a0b4db59839de9ae6230ba51901e71b3e3d59e8c34a79678e751c8b7ab139123bdb2f04d90a18ed81d2046ae86da1a73c8dae4fc4f\nA = -469f61cbff01f0e4124ba69a860ec6dbc75cd758dd8ac7cbfed97645b16488a329adee62d1a66e90ee4212569d56d58b61676262f49dcb68296bbe5d8e23853e3fefe8a304710cea568ca65c183531a992ec5b4d82e226\nB = 4a0d48e31cb8c24a3b2c9c95fd19edbe46823032ef4c97fe65d0a30d5c2cad7a4fbbe89e0ebc9940ed9f9ccb8ab18bac269759a9740a7985809d0f38259e680f0703febe7fa012d1ded47f0cace4a133f59a721\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2b2953981db406ebc544c39dfeb08a8b089064533221536c7fa2bf2a7a0d3a1192859b7dc0ea5036eeab5aa371e3e0070c3980433adb3e3a5202ff257bb546bcb9550423201a35501fd717ed4c0016eb3a675ed399340bac7f058a04e69c1774590fe747ffb9c27e78ba50fcee30ce533a1659fc49dc080a60f21357a6265d24\nA = -122621d97f42b65b060c84df3f0c0da097b5e240731b77a37bb9471e7e398b242db6f1b5e25062a9bed702860ccf6aaf386c1d6fcf60fc31b8c190d3486949c5772b9e621b863a7cbf29449ddd68b7e0c21e669492e58e94a\nB = -33978406dd30ec2b192c416e422428683deac210017cac9e4355e8446d6969295b0fbaa8cabc92c1fc0068da70efa047f938a419bac160ed6f794a9f69f53a88648c9725610d5f309b652f5462bd3011cf68ea859b\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099",
-    "c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2104dfef151526e072c09a4a277eb981a035379de3b1a55a88cb060681706f26131c388f5572c5646826b119c85ed450207f32733487e3c4e1e9d701a65058c4b4ef0cd1db090495643038229ed177b54695ac32110619038f1c1cece14faa693d88476e3d70329b0084d0ba5d547bbaa5b59ba1ce1fad5aa2f1c11a75bc7c0\nA = 7b79e6f1330fefffaf8521089c3348593e40ab7e8d4da3d4346571b43b12740958336580afd13619be3dc2d42eefd9e30599405da3e32e7f3a5655ece8b77a367059668021aa092460de75e627526da08e6206b0f8f539ef40e\nB = 156e234931907c0c0970c1fe6bd4b24225ed94d5f5b1be4693c8e141e9a6032425b4a47b6eac6265afbeb9d796eb230efa707d5ac4a73808225181cf814b319142e9d175ac461c75e6d479bb6bea53954bb981062eb16\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2a392c5fc96c29df2f5ae9eaf76e7d981dc1e2f3b47b43a98eaf556a9465ae8727c622188123c64658053ec50c25e54ac5c6c8bc279b134d326e911f14c873357647866eccb4f9038ed0cef5082c2058ebd71e1619f7c8f8f2fb80871ebbca3fbfb7845bd855d307d2efd853f1bfd467fbe030862f165e53a9cfa633d0d3fa23\nA = 1e0430e7cf15173d00592037e83e717c90d7dab4f54a5b2f0f5772762fb5f56bc0b2a53ec1bc3b960afc35e7b043f9d85d0af6c29288486af3e186e52bae6300b58917647231b40a12648cc8c020a797683a9bd7ff34eb6d41b928\nB = -e08372fc766eba6e0ef55a9149d700b503e2e3f978c8a397912e2735d5bcff69c461561ac0822c44160c7c1bbf722df421b74beada57462ac54a9bdcdb42d6a27b86413036ed2282abf62800fb2518a32a4a135bc948053\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2608f68632ef14dc3979725c8cf1a0db10a1651f17d91247edfae9935b53f6364d233b030eb99871a87b7bd876ab2cfd5a643387a7af9d337e81770db04a14f4f8dbda2cff604838c9af9a31e8dccf9277d453176589ba33abf77855b9501e63370b2e6cd22831e1e70ff1815302c0a026c70042957d08e74dfaff940a91a7b9\nA = -5d3568858c05a15bc9777af949eb01d33dfdba58439fb3f7af2ba792efe8e78b16d7fbc2a303a4c4c4be7c9d43f57405e88be54d6ab55268a4739945ef582921d2877019659dadbc76e0939f4b2cfbc91e5356ba2ed531526ed5b9b3\nB = 47f81f65ea1af04f702757c02a175a299b23cd8ad551fdb67020c50cbb4110b5371dc5790b12484e9ce647eeb24c0220a5e62aaec3461a9dcdaf1a22814b6f22d66372cc5ee31944bef33469f905458c172ec7871d9dc9c301\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 5735109bd21d31b5f54e9221bbed78c54cf387e39c13d31557e8173e173f786b2d2f1acf3966c3bf4552fe9bc802d0868a5a7632404cb91609a7a45fe0fb83fea8d83b0319666c1b0ac520169c15be708343359447f2fd37960c1e96d32799ac9394e839b391f59dd347acfb79bcc4e34e76490880d163ac97ee69e3a0a6e68f\nA = -175011349a0a1ceba11756bd528f2bd631c106e709aab223032d08d52d7d6724e8c5b055b6f97b48261f4860eae297badc1214cdae9b2500a7a47b4b777dd7b8f1006757754ff1143b637d2a3adc555f38eafbd5478cde0b04e5f46d3f0\nB = -2aa7f75d6801b04ea9f690aa0c5448906595fd28b53775059c01efe54b463f1d87c9fb4b39cb038e770f99bb995a2118b86ff8d004bd964e958c2af82becf362fb0b927c671cc3bd7185990419d26a827a2d81bbc0126e1029556\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 3b4ad19b75e1301d19b57ba9b68e0666c28c7c5c99df1d5fbbe0685dc1d3489ff39c919222719c5d8b7ce2d7ff967730d776a02b36a86064ed66a02011bab82eb575390f85f0104715f6e4954a1bb28518450182a8ef58af35d00e2fe417f07ba25dd9c85e00c3451082becd22e3aa0c9bcedaa96e6423c7df6c375b4c799c65\nA = 58e1ce4a9b512eb0632b02cf1207936d6707b802140540fbcbbdd712e5ac1426b4f36e74a9a9ddc812e572855d4fe4fca8a0de6644226f5698fb46a5f2a479dfc8b588aa8e02ddb15acdc79ed3d17143e290f1317274f425b869df54a4807\nB = 14e341cbb5f5a7f3b4dd864172b82ceed2887fcf20aae7d0598b3d8afafd2f10c27bc7456c1488abb570be3df04f43d892dc6a8dbe7621f55bccb0ee3acb1ade989a510b4e0cbe29b6b93968f323f0016d87944c908824d249769f8b\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 7fe0bbbccad6032069b1a335b3f2dac16089051cd9321f903181fad23be6853e2d209958e8c48e008be94a62c6206b34b4e994ca08b8f24a2df0e6394ea65b3b7aadb3bc43d04dc9d35a77e673c4476dedefd4568b4ade5d16f9d89486f3d5ed0566b1eb428cb0b688f10fe3901037744f278385754fca481f937cb630f60308\nA = 1cc0e3ed58090db55063c9ba11401636f89262d6ec096d361f448496e05181c5f7f2604333f26d511c13534618e90637adc807d622097f7eabfc03266135cb626e1bad20997e72da71bf2b3f65a4973dc27d2a594b1fd96b7bf7ec14b9e4b983\nB = -87871b2058d33cb67d83b6a56ab27839c6a6c771bd94e55f200a1257f2c737e39c4a0403fa410ea64e8f442d300df1c19c2f03d07fb74d94f86d26814fca23d4cd2cd3718252cf0cd8a0e36726f6e68827a1dab6bbb1d23b884381c702\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 35d7ac5cbc7e6c262ffa41be168b02a3bde9e112c512d1f68421d705ea34461ce3e0dafde67f44d44cf31d91b38d4d5f2fbf8c6c6a44ec3ed0298dd58f3d45c04346c11e57229dc3d2cdfea02c802732d9a811d7be5e81094d72172cd04caaa3c9d55a951c09f454f42add6e89e2d8a98e124aac86379df377606e7af9bc6baa\nA = -4ee01518f6581c560a186fa05c6f4bc26809c4822cc74a0bb74d5a6b0a368aa9bd0108f26113443422b8c589084ad49f919a9e7821d99127bb210670e732b7cdf610e464e300a39d3dfa7c82f90cf00ce329bc6763d7b1d4224a020095112fefa7\nB = 72dc8973f7af7122a05c90df190bbf1e39abca908c197590dc7ac41fd0712f48f838ca62a72a177a293ee6b2afa7a10c21e7993347c3df4f161a5641ff62ba123999bf1eabef29ec0d33ed0919818f4b7c35b5f41e654759fc9abdc0f80e7\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 5d83a9b34631dd6c63c05a0c012adf97b4d0f20f61907e1c2145330211e9a7e38128517b058e0a85e993c385068d1cec768deb814bea1323dbd333de091ad2cad72431f20c1e70ff7e1b119768ba44e14292c38b88dae7e55ac9e10ff98e9bcd5f0ac05af499196b4be0c6222d1a63227ee895fa6a8221a4a182a1323183cd7f\nA = -17b3e0c9288be15fda58c8fd228216bc466731d631218a7ddf1d2c9cc858c0219cb0757d3b680bca1b1964eb15031b5b9d761a8bcbd160db89be339067a2ea35e1ac3cfed701912a17ef9ea03999d92e3592e893183ddc05cbb98a656983b54590c72\nB = -269f96a4634eb37cf8a6608408128587ba45958405a29827d0d03d34816fcb1a2297f1319485439d3e8594532545086efbe4d21d31d30e2daf09b74fa8cb27df54e8f9f993630cd9a292c977eee70887158bd3fa3cfef321ef900a0598ac8cea\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 7fc1c65eade94d9de7440eb8dfaecf1004905135efd4f98257c3295b1e76ccf1e2ab6808d158d360b7419c6210c50efe960610973d9ae855c72ec0e81d423e5863c80b542ad455700d2d0dee5fc403dc01eab460c24687401cf6a3179642e59f2a30268df95fa80dcdac230702352bbf6b60acb9ff5d45c5b09a3403b954d173\nA = 7906bd8d3bebb1303c1df1fea0b2503b0abe9c69b4f4f5bd01eec9e314788cb7d44b93428adbcef570477e8ecac2a64822e481bdf520fc381e1bb0b2cdae2fe94e484cef5236dd524e4dc364b72f4c06d57f29dd3c5079e532b1ab1e71dd6a65b3362df\nB = 1479ef2807b9c23c094d0416f513894cc92e023b134f44a5333360dbbe98b8161ab899302f4fa11b470b97dca0c4e8ab7ae47e5fd0962834e6cc1763618193f4ee027f667368da580c623080de137b5869c3081128e6081b9d5e2dbafd791773242\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde",
-    "2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 730c04094b1ce944588e8291f7e6cf763c70b79cf362dc8a1bc63bb8790cd4cfe4eb51cf15a45a8464d69ddc3e1b9383cfbfd643f317108cd9ca6a6eaaea177c5c8b6747bbf40108cbc0437eb8f11bd2a0939da59b70c0c6129e2c249823897f2ee536b0427bc45035f121d2cbe7441c175899b97c490e6c3ca01539bcd05848\nA = 102cf23cc3b81785c73ac3613c816de47fd585c7d5f175185818dbb4bf0bd47d0dda9702bce97b29d66e48bfaae0fd07b47b40be2b48ed702ef21c54b10bb927f9d6b43604bec4f4b2796b44aa6b4e83f8bcd00f2fa3871dd901570e1a32888d8691454c40\nB = -cc5349a9c5280a933e87ca38ce458a711c71ffebb40bb1f7612b42b4684afc495e99c4a5f32eef1c9564c2b7612ea4cda7a0f5df6b3ec9026447dc565ca08563d46aec7ced9fc4cc5645960210d44cdc3944149051d569c9295dc50862f8f6d1f6cd1\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 1cfe1842a53d00e4619265e2fce7cb566ffbd912c9213925d01408a956af304eacb85e29fb6edb812a95e90769bf1c3d62b0cf6cd5bb8f8992391d2ad70f38a14fb9d1d1eb522aa7b7fd9f1b52790beebfc887193882377b7ce567d317d8432e1d9a908d6ccfe8d2de7de497d77b023b3959cc042ae30aefcc0229617fd2a146\nA = -5c3d24fdb193ed83f5f6a825c1716f98e3cde6b32e09659f253ca3fd2a39402b5bc3a6497ed7bc908838e93422559a13cf59156254bd3fe1e3b8600b2a777943cdb39b9d42c58043f1d587424425d3ef5f5538ea157112970ce3e09a87fbb5f7c96f1b5e65fa\nB = 675d9d2a05288b438ddcb330acbd59e4639375f3f14ac2d0e9e8b72de6ffc1d217ce62f997577f7eaddbe4603541b132cd41f2f2740363d9c331ef22df92029d143fc8495ed0152b918aed7ff22f564c7cd94fd3fe4178c90365ace43def8fe30ab05c0e\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 83ed1948276d689bb7fde814e67fcea72c4e3509c48873c3e7349a8fa1c08ae11ea4d814d8deb1021eb8b8ceec342cba5002a2ca45d5f340ae1aa500af4c7db120d0402c6cc8a840404be7221bbc46ffa10236043e5ce4415d3ef1355bde26d2d26eb7127326d4b8d671bb96a08e38a2c1dcc281830ac77202903a5e4777ff02\nA = -1be86e7c87827922d2e8a06e3cd6b64ac9a280c525749bcdbfac4856916321a964c9346d17465378251e6eada42dadf38bc9d7d87367bec94ebdc21af6b1302e520db08a64ba6b39920683725ef02b011a3e4ba46ef0eefadb98582cb911d0cbeae9c231b5e432c\nB = -352059faf97b433089a688c702b97adefd0c91d51a0395647f822c6762fee3287693e302fc5a5584a12c048dea1a320cb96fa70b5daff7c2ea21d249467d14c6bbee15a1e94c030e908342a939fbe8ae0de58cb6d6eae7758485e392ff6d5d64465b701692c\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 402525e19b6b68942253d1a51fd9b2ca36fc84cf938d80b3d52fd4302de142b9d93d1663e89340fff10c2b5efc8cd47fc3b5cc5ccd49a6ea3038ead6454bf190b7f88f52c56bcf00c6ad5b0f5dfb7615915ee8af137dd99cd3d21172ab772f36d291a6856a8e7912750139c09aa024b930a0a6b9eccc83c2c5c0ee2473ea32c\nA = 65e5db532ecae639bd56dd63045bca39b33b4d70b2db82ca3d0ee8ca436e671828cde80217b48eae7487fe110830589ab1be889f1e1463f3b0757d529b2f0cdd2ac92c35e8ec141885bbefb6040a3b5e00e64a541913a38fe05824a929f8c5a2c46568c61989c3ca7\nB = 1d9c73eef8373cbb1e8393feb26d55c33a245c33d7031c234abffb2f06a1601f7f3a79ef1e8664c51ce5dba5f5aaf3b9a9e42470d381219b4616ae93c7f6e64792d23bae523b6a224c1f714ebc82a11f9be42618922b8d2eb7b55e4d45572e68a19fb0ba72228b\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 7a9cdb5dcdfb6e04351057d731fddb9e85f41eb432f01c0d980673d294d05ba9b0180133a89930e74cfce78ed54991b494a19e7f80f310b85904784cebc5639bbc631e80751807868e7fe16719e8ffcd1f2cbd1b9f303c3ed488b647670be3080668b5fa0e53b6342c33c87f0ca1efe1ddb1c877bfe2556aeb61805b06f41343\nA = 1e412c3d66aea2c503f3aa5dbad368a61d969a2951c0094f9da32d2794e47f3bf4c481ae23636baabdebdcf0753d431426b1865e62de8eae7238a9245d62820ad7f17b5380d701f5db776cd4e1ddbdfd542901731ffcea5bcdc247fa9c83f7e08a9389e5a76d38be21bd\nB = -afd61df72361260484fade8b432713eb740df83a401d73492883a5139c918d5c911ff5dc00140637da1c6acfbab4b0bc8fc1f337243d90beeb1c2a083ad8069494c73a99372bd38712a5b5393c779ec1915e878600e0b48157bea44ca8e97c6099c4ab07fbda57d1\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 712580a1ffde78c8cf98ba71843c8130e835fee3afbb45e372d04c04cc388e403c9efac742611d7974bbae982c3aadfd1893f5da280afe0c1db1d81a9ed73b6ed9b7f05a20ce828316103259112d7754560d66733041e9470ae0d4dc95fd0484bfd56d66739f38ead7efa4051187ea41f7bea8fe5d958a29af41328246e2bc35\nA = -47c5755ca61ca8b7ea927f6fbe347f1362915548ab38c40f0418f4c9ba4ad520c3b2469d9ba3976669dec0b278461bae80eda53e9d11447512963e797f45460f74678acdd69fb9efe3897913b6568f8e03a6d90b4cb5bfb06af132bf118574b70e6bd2f6d6cb4d0089379d\nB = 5bda68c0a64218d3609d75eb4832d5468298f19498507d7d515f4c410f04dee535947571a5e75f1af7f94a5b3b05fb742fde23e7cf3f8b3dbee0a569e5a36d7a3d31a26c4a48a299044fd72339d2cee1a68966c851e76b93ae34130b75f4abe4f2260207d2254d23f56\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 4a1a514aa4d1ada84fa841d0b668930c904783fac521377a7d622201867d773ad23dbb667e0d4181616358f3cb088cd157c8e72bcd03db64647b37aa1813f870cbb0318ae0a3667f8e6c19f6e0706217646ce633f0cc8bf4e8f0f4d7329a8647252ca6d376416d545e73cb9a3cba40f8f9465d85d57c2481b84b6d95dd42d50a\nA = -1d68bddd8c3e6b78daa0acfc63a6f39e97f19527a43f6cdec47568d57b47f4e4b7ee88e4a28d683b569e406ecd2510351dba25f10b9f7c82d6da16d848bb970cedf7675e67937921bd334eec4bc8fde83d67aca57eec804ce22bb342167602fbff452d5f0f2a7f38b576e1e50\nB = -34d219765916a4c8ec843ebee9a7aa1162974d41cb4d6b60532513608452da9993749455d9701af6b7b6c7454d7f2fd5c344cc938baa5259301d4b56ae8d25b6f6510ae6bca114cae6791fa5a9551e8a405f5b1c0bbfc27138563b2d64f9a4d7a8f42a23bfacc3f1ec9393\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 3fe24e66e381eca525b24cf767215837019f44ed4fac6ab118d02cdbd658066505ee5b0feb7af51859992ecb97d727121e38873f748a61d70201cc43228a7732156a80dbe399e05764be19e37dc1b93222bcdcbc45b1a4817460f7021dcf1d70e632bc6a306628790201222bb522f4cc80adcc907463a539b02f74004d42adff\nA = 773454a43f495959dd55b8a064d70b1b1ffe45c084f5f9553582e24fb402b564de68e5379a8d9d02af101594e717a6c6db2e7173e557a64d2f28fd45c4e06041deda040705d99acacf8086830af19c7ab5e27f91738ffbd937dc27e5b7869bb6caa12c2d7930366ff75eadc570a\nB = 13d884a2396268f1a8186748a15722156a172a56dd3d8c77b9cb7001b6ee06720653507eba9bb9918f2f699cb37f3b5ae514f5180108a704647f19b0fc075826153edda66dc1105c1008ea8ec6f8c10057f8e8e479e1a1274edfed9ef719b30827a30f26da78820c3696d01aa\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 715bab8708e53f76d2ef2afbb845bdaaf978b54ce25f84dbbf9074f16d30a18733a02a4ba5d7b092fa6c25d3b9b0d8243c743910f1b7b785d9cb02343fc6d59eb0817bcff05646030ce4fbb2b9ff76781cb1af66b46553d365d02c61e677ae97defe92d057d4378dadf8cba9824b0022c086e0d78b5442bf3d3263ba22c643f7\nA = 168186208c734383d472374fbedc2d5d430e85690a48",
-    "81b740008623120a4f7f83b2cdf85dc28bfaae5870abcd7ff1bc782ef11c78a75c99d41f8aacb52fceeb5f10266dc65eb00b0868937340146d8850887686d54218badb97647a6d82c0c6650ca1f9078d73fc6222aab95c2967\nB = -9711e5b3965654bd9427f79c89a0b3f3cdec1c857f4451eec236c1f221bb6773e5dcc30e7381a18a813ac2b03ff4a4ba679aad41e0e5d7181d4627f682ca2dc8af9a8b4f878771446fb225a979ef9c7e641cac819c307c8dc50d9c1ebadf912ec7c844e416f95b546cf09391f9f\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2714b99dcde70d6c3be8b671d78abc155793f13105fd4b7c5d760a4c68ae89987311dabf2a9238d18299f983b8aca69a9ce398fdf2c9775d90b11b3dba17bcd8edf661efb6e9c50b4e37553cbecb54eb214fed1d0847287732810e550a4c86b51d4e5da1cb7722ce4317e69644620ad806d6d1c94e1e3fb4d87de6178a997453\nA = -75231ed37f1dfa4487c9fc79a6f7b36929fdca086e42ed41f79430b2dff521919236fe415ccce590e1d3b986e16dda866f3f0d29ac1adcf55d87fa5cb67dbf4693293188516e360bac513303769c42181483fbef7abcbc4fea1310c916396d29f37d9058a62aead94511aded7c4b8de8\nB = 5aadfe65df0e5b877fe45d42d7ca02882cb6c686d486374da5ece6f87771675153c84d74b6f40df1db567b7e1e3c60c41d21816f958f5576fd2ce2f84a8c3be4749dfc7e5561266b7c9698c7581292d0d813cb77955458d63bf94ce87472924c4ca79504d1ae9d5f025c7a2504156f\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 6613b1c8ccac0cb8fe2f59e76fef4dd05acf1f1b2bfc20aa3f193622ce3e9d4c7824ad544477553bc68f05f0b546e7c1ee87301e111af7929d1f40525291b88e211db7175f4e5c0953141914fcb4fb951dbf77442e7cb28fde495704f1b5141de1e50fbd0e359d0d86ad709c8f564c84dac81c7602717c269219ab1cf12e809c\nA = -1bc03897b02d1edb633e2c019e40c20c1d89a210b0733412aab675563fae8bd75dd7e65988cd8df4d9b343586e27f548becdde274f62dd421679554ed9eb127e527a69d69fa8b17aac0424dfa2a7692d1e63617ea45564b55f01a70325bca050862d583cdad96c4a2e123d0ed827348a745\nB = -3d5239dbe7bb3dcfd8027204eccf5e9444e68d322a0b0c535a203a1d0c054e7dc1e588bacb891388241462a5d2b43e6cce34ce46a23e6ef29670603d31001374dfa347dfcc794988e58945d0d2d17da6565cfea559203dec119fc357d396f65b296deb07686b0ad2d25a13fd4fad88d2c\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 3a7fc5680aae875b9241200b9f4112a82cd624ffd9044138ae3cd65200631ee9d7b918fbffadcad7e598791a9f0bef3e23005d6bc0048ba92461283492df3bce74c66e417b082ee052fd8f808d71f3ab18f9ffc40f8fb51ebbb936d09c26a3514bf868141f7cf238c1abb3d88e5d50dfc188902254f07d63fb8cb611ef8e4149\nA = 4a30f32d467b29dc83b40bca2fc4ccee5f08a64069cb87f20e63387b2219b12aa312400c4ca59608f50a71d2535cde40a6d248290793fe01693ca40b93a5cded2dcfbc9aeb36e187c9d650782d12bea917daadbc6525f266e074037803e4b2f300778ca8dcb304658cdb502c93c94a16c6261\nB = 1ca5e5218dade077fecb81d579e1c9290431b34df5ec84aefaaf233d68f17dcf60ee010db26320685af13a821b6daa9d73d8f3a30826c3ae7b2bc5e219cadcff826283cd7dddd04cea7a5e0585d6e7c9f23b27f14ff815fe53bcd75fe700b1b91671bddaba737fb43bfecd2a77e5b752a206\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 768d312175ce7d2601f30bb38339f046e4c2ba5c19ae5f7ca5a562cc2462c579fce9985e9e8afe2578db542c8d9e7693e0c74ba161334b249ce720d568e9c18f09c87cd701e6f2080b752362f2fe6252a1d0caaaf1fa18199776e4c6078d89d520b9c63db159d5fba7e0838811e68794b1413c248f3f7173ef29eff28f15b656\nA = 149353e91bdb70cdca8f06648388508511a64d05221305cad7187ea40d9ccef91fe17ceb1e79667bf66e8e6b7a57faa90a83bad119c02984a8f860bc1f23ffd33d4ad84896610301cd2e8e80a5ca7e8d3ee63e7dfa459793c9dbaef3569eb4f8a021c6a3d032a9c94d3f6b8278274d0088a98228\nB = -a7cbbb6a434e4b022d312ecd4a45fc7fc4d3aaca038cca0fc56e529fe7119ccdddc8e76d51a2fb862ad3d27a16ec8a51e5f66b9c7fdfbddcd05a0ddea14172339cee340c8c651eb653c6aab6551c99ae94f26116e15dc62f2c2e63305bbf84590fba1327ee721150d46464d7e22d45d53ffd44\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 763912f4b16549e6ccd60eaf7a0a1f64d9c3bc83e4a9b87e209a3959ba3cf609cf47183bc543f08e346b6e12b8bdd5d1c07c603f74b286ad432d58d7001299ec7a4dcdb56ca875dfc7ee5c75bcfe2aaba14959bf3facaebf8df92bc12937cfd4a4865b3dd74b243ff62ba256d110b01b4089730cf48efdc66fe272f9241014e\nA = -4df3899b40d51c83dacb442fb143835bcdb550136921df78800f0515a6cee77fe3236dadd2a0800b79ebdaaf8cf4aba5ebb60cdff3e4b4531ecd0903c1674a4559339123e9f09158080fc53c4c6ae72c961c8da2f357b7c05368157b4956e592c41b25642457651abfecb4fed5d9fc1fc3825b772d\nB = 450eff382e73f2f38bc3a4abecd5f8de478f80a6b99fb6252173c90d7099629afe859442bb1f796855ee9a2940f21d1f9dc44f462edd74b479e1f2926ff6faefeb55adbc6152b5c97967b1dc8c44dfb85b5e02e870d2920b75422c8a427e99e35e2a4be92cb0ddc04cb7f4044f716be97b36f045a\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 56ef57d56c6d1b94cf0fcdedd3611a8ee444c2e25522b9ad175587619598da341916b183be03b1e73be300f9969120d8f3a23750cd8c4ffdb87124a2139e8ff2c15d8dc944bc3c3a066aa16dbe6dba4a74925e16acdb2b2e83cd7fd5cedade6a7f7409a509c00dadc182b2860609cc9a375cb8bbdcc350bcb2c0df9b3bff882e\nA = -143caf995b7783b1316b5551978727f06512fe114b419c735b3381ec351275fb7fbd6ca88b848c3e8c9faedebd6d084cb8a231636f68f6803d14bafd90534609d4a4ac0fb953417be7fee4e4cfefa452c5ee5d1e1b97ee75f83cca8691a0efeaa8bcc1f1e0f18c0c5d6c7684c9da6c9495d31a32f40a5\nB = -3025fa05c55826c40089b12741b7d406f748cabf692bb0227519a124653160142633700e3c0676000943556f97551171d231c1a35f7b7d8f96b0366eb74942466ceb4660f09aecb2fb2ac050ef699eb05bd8834a2ba959ac71550b5c026b9093c8cbbb7c5fb9390a7818db682b7c11e58996c9d0add5\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 42f363c34c20c443c1ea7a1c54f98c6977b6671164a80308000533b2404a7f280adb1f3b98101cba25249131288f7ac68b0ae2572c7777e7381c1f4d05fd82188c4b1ed5636652e0bfca4d096bbf4189a9358b79f6b6333b99e5c4b7a940c2f7d1413bf9f47a2ef66b620b5e220b2c3dd7267452eb1b9d8d9cfb17bbfcdb6abb\nA = 499d05de867bda3118a8cb82b80ac91fc505e0fbc6c7dac5fb61713cb6e715f56a31ae8af4b400461d7ad1687a2631faecd90d7829f67d1b9e36ed7d55704b3f2aea65eac061172d698384daea710ed92cf1140cd4da427174bebd173c2ff1675b2407a84649b0a318602f33105006fe4d5ed8d0e015b99\nB = 17a426a12a0175bb46bf7a7e727eb5238af383cee6f4d5e2bd82b0d29b9fed35f3d8ec95cfdfcac49bee47b25d3b5f375a3340fa83f8dd9330a593a974d208debb7e567e59dbb7251b54e42dab2cd50fc63aab050a41bd88282373f8195c94c35f61bb48aa921f574cb4ff0984ccedc070efea8c46e5cf8\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2f03374e9596cb56cbbd89794090ca7a4b437f4c05fa38a09db60e5ca900b208fb85b52f71c29fd35e62c9f9529d7ffe46fcc54607ccb07f6f8e13fdd4ff1185033ba4fcefb1ed4bfc42c3ea9f05276767d8dc9b7b4aea4c8bc0ce84951d1f590cec0751f73667db19060e2bff64da30fc048a1f5700fe3f489920675cc3540a\nA = 1073531f678877ba854fd1e7f857659614c526847ffbe8ed131dc9f2ccf69e1f1e917bb44a7b905f7ff758f61c06dd59ee09567d9f0df2550fcb98b776ed1381ce052988aa08fc5153e31c621c6a51ca61b386e3a9163a5cd69608b3e200476a8ada35d906c41d044bafe71ef5c6f732935f15b53bf36f7ef8\nB = -d",
-    "e3563925474e5408e245184b57f328e265b6cb62eedcaba809d8f257eccc0a457eeb82c451f93af93ce9f36dd1aab386e7c02b356f31c2d170169dbe15e70cf5bb9073b35fe0e7c7fd7faa91c5b2b0740734f12eb741a9d9ac6dcf7cff59f6e16324ea39e1e07dc5b9daea27ac674dfe5d0a5790abaebde9\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 1aa22f9013bc1cdebbdfecedf710c1bcaa41c696a3d7dfc1c8c601fcfcc1c85c8cc24be7df2cf3c7311b3b17a4ef2dbce545dc467d2a92d371e02a196a9977cb9042b236acf99d8c0d34a1c4dd8792d3497cffbc87c397ccee5d01fc2c89ef051324a7061e423720d0a3821a36739797393bdf7a45b5fc600824a17043312bc\nA = -4fb2e3fde2a0c653104c077cc6459c9234f86cc2d7b317329b68289826d3e2b975f1a69bed1a53418a0dd86e1b2723f4c4c5a29d003161e667c2315ec24a36f8bb5f2eb0a94f261e791bb829db685cd0ec9e1e301dc140ea57cac1da228124ae029e2b8ab1fa3ab99c55a9ca94dc7b767162c0a24af851fbb984\nB = 63702537a07971e399aa9a1a0795db052d6c8185c79107216babe11d6d8d472b61e604cecf9eaa6d44a2fcdd1ef0b6b52226ea0c6902d929b09e16576e6d1a6921765b2134c5d23c69ed61f36ea9a5552e5819350366240693558fac7a9d09ecd3702076c8c758a4bf6843fa843dfd688bef3f73515db31bfc26\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 6acb23ea695d4b60cce53079390da3cb3a4bc3a6486c238c421f3bf6c93c027a0475f656c3e5435f0211e90458ae81772aa956ef284093020f7b58ccd9373f3fdd39fdf4adb8dd64590f4a7fc05238ba20017bdad07f5f9a6f076b71554a7741bdd8c98ec68f8fee88396cb1f47c64d6da4c228caa3dfc7a9a1c032a9ba4fedc\nA = -1b2496ef929bc673042996ae80f27c6bbd33fa7c20580240ef8fba985d1a6117d6e746989924e34f281e7d2509175d0773dd999bde16662e88fcef52978d19cc45fbae3997fa580a66171d398f4f0e7605d9f4aa4f728902cb886e6b6dc9f0161e7cf1ebac05a09c5a1bd69a92273280758173fd2c14550ec221275\nB = -28399206ae2820d26a5aa0bddc4903776611d08fc4cb34a22a8bdc2a19e9f8cdab94217f346a8070a4145f989e1dfb49cfd100267635af0e062872cc879c534ff138fca603b5d45a6860ea85b6de37cfca000c81fcda3d14ffe81da919b2a25214209b085bab9cb511889665fc845acbcd038711533da171d8308aa\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = c012c4d17ea4c95a360218adfc3363f6d89f5aa524aec70049ef94c2c05e59a66ce01e25588e164bf2412f9517b7740de53d037e71ec3a1d426f05b18b128c41a878da75421e8c8ef3ebd5effd40735c00818eeb1ec63182b44e817403c9f1f6c1a0155334be63a3a15109be6d45ac0d1b1ef5cc99e9b284b00c487d91e5472\nA = 796fba6276fb7129eef2d1572b305f63d7b8c49371cfb3b2c67b141071e66ccdb5e321fa2c1bcf624c77317e2aa135e1137dfa46a34c3ffefa2fa3e316be81f45614d422bf86fe4518c2fdb7e416bec199de033cb5fef7f193a80c0f0e6ee924a12c8f705f5ed3793ab770914924b45cf2578bdd09c701169f0a881e6\nB = 12cf934763127284e642ddc232b1c889cd86617307b6ad72a9fe0d48befd7c5c5370a0062dfbde2add256dc0af850813b22320ceeaeed347eb9319bf22320b2fcadeb51c4bb26a160f7459fc172c27a91d367d5a232d00cf7bb778fba83afb744177bf1ddf45446baa035fcd0065f9b493d92eda37e9138f4fecf3ec55\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 3de123bbd50c35805b943e76e97b7e664eb9feb99860750bf97e275029e836217375cc1910c13269ffbd0bd72bb82ca445ccc4b693742a96d19d3dc23f78e5ccbba46d9ff5975f239551c36403ad5fe86997536456c4a5ce54807c24e3b5317b1c7b2a1661aad85b63859d427f0703b460cf72b9acd3f87e2e69d7f8f15e972d\nA = 1d0433d84f1de082d2058475e0168ceb369013a67aa9417f066c29c28272a0b3f8be5ac7190ab78591ae72a1dc8ce628c683281a9ad563e134387b9258b9c96d2df288fc118a8cff068ee49d635343772c2fcc252facdfc93112358414e1734d6948b909b53e46263e9a0cbffa141ef77bc98e7fae8ae2bd85bd875aa7c1\nB = -a31a574d105305e47f4fc00ccea0cdf854556886b524901c22e6f3b59a42915932ab209a8d5da29ab70d1472dd5378d9c79a7447d17665f9d1f1edc1e545e417cb65415cb8a368075c16264f42555d26e83adc704b5c126c6129318a8f394af8bdbb32c8114470d11b2acfe806acdc7b96e1e348a32ff96a988de76d4623\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 770f0c3104c0f3395fabeb75ddfa2c21a111d23438463941239f7c63e4b6e6832b84508ebf3cde1d90cff0a2801beee05cd5118f9a726a987eb58def6780be899b473ea71c697557ff63a4c6db894e9438595acdd98abfb529d75bdf3c1d619d6165a9edb6aaab8ada50b61a3a84de654706a9aedb7321b0523558e8f18116fd\nA = -5fafbd498d610e9f29c38a5c6c262b71672fe9e9c84f0f071b549390353e4fd0101a059b7c547007e27df97761767302458f1936395142ce5776b0959fc5ea039429d64ac5d50c2ae0ee45d60c0c50b7ceb4ff9853d57c6e883f588017ffcaddf5a1aa3e23ab068877a114d9a2cf742f01f5f5d611424c8ec0d082f5c165b1\nB = 552155ef110c126afcb87dd20251220c7a43bd0215ecd22249a21c93583e120ba6f046c6fe03086ef3c97311c4d520110a450470a473d8633e3560d2cb44c25559af07516aff50d6d176e8782c06cd9aadd3354cc695c4ea8dbf85e01dad479c8e8438154351fd5fcc6fc7e9d2162ce2f0179247f756f0b9b34b54be74821c5\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2e9ed66317734668c4c354d720a011fc65bb67439b2ac9203dca65a8f567682be40cbad4f55a83e836f1fc135596b624e4327acb085a61b6398237fef5a6e6560b488d4a673b5ae7d734b896d9647d71087621cc81e94d58e01fc2cc2dc775f9ab1b6031840a672fb715b77bd636e3d87b4949ec7bd60721bec8f9907b7c072f\nA = -1a6b046d691830d33eecf2c53953676ed3f6fdd20c2252f6e915052ec28ad1fbf7a5f264acf87ef8ecd515ed921ce6b85017f3d8a8f1d14f269f31e3307c6f935ad468cf012a912b0650a15106fb949cbae7b36c9cd496538bb0646a7a28989dfadc719424519bfa43cd8833d3a748c758f813881d83c98f7cb2a63c2a4d06b8e\nB = -34f87db0f839af6e4c4bf146789db36b3d0bcebb9bad81db690ccc3a35070d8830c9745b2fe730a1f3a252612e7026bf9889169b57b8984a5479cc4cdd6844ee3e150a2e7bf7680eebbef30e0591c895cc8b2ca488d489554f2339e2f55598717ddd8ce444a060cc95cad9eb478491ee8d3b8358c3762a970224abdc1068af0bde\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 6455ff7c12bf3bc37120fe3f1302a9916a6ffdae6ee6a37fc23ca2f3a7ad910dc0e1027d4dc304a8eb4eccbcf3c87cf52a13dde472c07e2df2420c1d36bdd5e88c3d76e774ccd2ecaf6a0ef55b8c60231b1348a738f812a4fd9d0c158fd5a9fb19cc7cf9f000860d4cb6509271c8e43ae4193843324db02a029beb58ec2955ad\nA = 54ec203e2ababdb0348135c0679eca2a8e778ed46e53f195331a48d3828e5e40da804ecf95eed819ecefaeb9c5377cc1afb1fb220175990d347981353e7d90637adf8cbb16812af8a3783dd312d967a490f8efe3f23746929cf2a5a8df58e0b878367f6c5e4d3c086f947fc2bf70bfc3a0008a8bb1d7d83f002930640b6ed94c334\nB = 1311b88a05224e15f1465c8da26784dbaeae84f818e029301ea39a982f714c64312f9f02d094c401abb6a89e8537d64c178637364bd261f4a27beeaaa901cc7b3d4e36ebcd9453cda33d47a53c6dd1d121dfb83a222cfd16158eac23482c8abbfaca59e765f6c1fe871d884d281793eb19f6409dd6bbe4083bf762ef24c24f0127613\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 64104f6c06e563ec66de4442d35d88117f2535edf9e012897f44daab5a1b8a8696f84db7a68d64ae24a394debb993bf6734c9df542c7e473b2e497396ce39a064789d5d7b339b65766b002a18096e7fb9f312ea5997c2a85463fbd6fc18f25769ac2a2123ccb0e72f14b0608c4c22add72bda138b83f986e78d5c9da31b15b9d\nA = 145f580c2ebc6c0354ebdfdbb1d3d7fa17f0b55493b0b9a11b71001c840a967dc77f0206c3dde161b5a773a6b5fd9471fa08b205cb6f728e3afba44",
-    "0b55268d6a9542e234ec313d53583c580a391d8da5943f4a900b279ec9d8933f2cfbb260b74ab714a8b9a1af3190d914b6e42212df84f933a237728a5fd5473ce2e272eb82bc83e\nB = -c67f9b9295dd5844307b8fe3cb9c1875257258e4be6229ab097e148c0175ecd0de4d84fe03c8da6e27153c709c2526092b1abc73b5fb40f1d4da9e0f3d8d2fd5f8a4e6f3c30befd80e189b73fbd77e8547b34010d2aa57072db0f00537cf3ced95eb517b23e0c854b4becce128a575a31037c3a9e106a476d8b0277d26dcee435cebedc\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 11913c40d577f70a5346ff1cfdca492ff52b640eaf257510d311872c8df7ba9756973da5b9206c6e5254bcbbb4bcfdad5fc4594e41ee44e77f168e2d20a4b228480a9908b102dafddd039ba7f7619eed7057e8af3a72ee491a61dd049bd947e5b09a94ef94d5f336945f47104fddb8493ef22fb648ff5376b68e96c0555d74ca\nA = -5537630b7cfb8daf76d14e617f7b69f7b75b472801a9a818179d83ef2984d0abc8ea4214ed3d3d2bd785060e9c2819e861d0df760fc1daca8340e8a2c997c9ad201d6d2f12a82ae3883cf9f5c51ff1c25277c28175859a7b8e5b6cdec7cb3875071cbe415bb698b85cb19f617162587516f93c728ba8b2cfc19f238e2cfda115b8ec0431\nB = 597296cb27080f33a24241c1e98fdec32f7a4013a7340d367e4cf2a521cd462a2803109c27fcec353a30dd20053a1f744394fed75829e8396f8de434399bafd6cdb6e0ee81343f0cb99ef3087a7c69bd43bd722745a46cdff0c2c837fd87543c3c63df3896ac101a145b478dc224644996fc72460a89beb5741b91a42f2fbaf0d62c099b32\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 42f420adf5c6b32ce53fe23af4e392517e37013b8c3a7d035a93f6ff45142b0b0bd5525cde85f9b7bd9ce219bd3514617e89ef4d9279cb9a3e89e44f1994d72febd23ffbdb0a4f19cb76448199b31c5cc6d7ec1e46fdb67be1211c0ccd93c123d56ac0d9cd2ad11f0c58c713165003495b75b60665047ef80f6a393474cb727f\nA = -1c6ac9565d1950ae6c55025f76e0a040eed0462218e97aea87208ba879acedf413ffd5e63a92dd8658cf5f49d633ce7b126091a55701168ee4932db004dfe8c35c939887fae3a892b0b04d8eb74191bf8fdcf5566b4d3796a5d2596b1e750f64201057ae60aa705edd58aba4b48f6a2e511bf5007a6c44a27e3efd5bf2708f7046c1fff7864\nB = -244f2a90a57e5d066fe22f4d52f91b44882b8ef76d1dafc3387abcb224eda4a2100239e729bbc745237f8129d457e98eafb2ede2f3afb81e63520493da2a5730f1170b31fcac21259e90c894f8bc488c5e5dab2c2635bc7b1ff56c3685607f6fead73a09f83a7a168c4245729ce5b06e482d7d3d72eff33d14cfe2f32f72175484ffa292a9af6\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2239459025b257fd0b6659f54b8874f93f07f4d6240f8ad761c9da288cf1537d8bd001eced284bddf78edd611c7f28f1393c6fb879aab6e7df8eefd347d63628b1ae086148f488b01272f67ca19db71a2b284eb17e17aaf1e3e8f23ea253595de474d5cf47c16aecfae360eab7855868b8af361491f6ad96f893f9d3eb66d07d\nA = 558613de283911aea1ee21d6b926f531f778c5226e978ce329860682b5375fe5e5328ae27b00f504f2a2d24470d16c1edcb8e76b4d1a740e55538e79ac7da4b45c5299993513ec3bba7e7395dc829a00d4e228618dd348fbf838eaf0bd50f6c70253fb1c1c734a07d0813915be25d3163df13511f3675022cb85af7646c14ba5d13f615ded8e5\nB = 1f3c3c468146c29408d9207e15b25186d3b06b3fbf9556eff7ed7ef7788032d87ae1a4d2a0983902d4c70936c615d8c9ee26c89af8b58d60231ede54e859763237d5ac59af686300a3e92f456484ce77700557ddc0f93bb40e5d2e5117f2356ac7ffca26dcafb3ce7a5573e07ee97515b6b082fe75fcc9dccd76b4fd416e69a247fab2b30965d9be\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 7650985e7c6e5461268867dfa9782cd8154bd6a4bb5857d6555e9d9746ee79b37e44638940bf8d5e974911327f0e53bbcfda0739056bae2248015c35839f35e7e359e93d3a339e7af38c0cb43eac5b41e1406e34cdd4afd458a5d126f70b5d683415b490e0ad61269ffe7ea8972eda6addd447d97e60891e5099ee920e18f233\nA = 184845d3762ad1a9c925c51fabc7b9e15570a84a06ecef994910845d56869264273d75fbb84a31c97c27eb9779e8b39f6829638a78b266326b60546507f65128caaaf36d4e7f85939b75cfb3145e2b1bd8372531cda579f59efa0da9c95a8efc72faf326d35c660b4444627d328bedf50a919029dd164de051a4c0c924103e365cd640b9637d8244\nB = -977390f52af784b52c1d54e82131b072a1c308406e9b82587102e67c6f7145f0020952231a5f0ce9d130677bb5a7a37d5a06dc570a13a29673c8a9068f06242ac438806c37ec46136e7c1c1487ca2d330fc1f3c1f42ea51ba2805b74c44a61fb2fac109710dc3dae78a07057a753898d4e849b910f035bfd807178f0108812778345b256c7b59f8883\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 35d48c3e43070a10dac0e256afb83b219aacc0036f554bd998b9092ce3bf87bb5d3b00947f2c86fd4e7ab830502d15fb2d4e47ead087f5c779a9ba56e272ea86116e2c81345d379dda6b581e9c8f4df8ea56c78f04d4f7412d245e00ac645847af6ae97d5d2ab27e48cc878d8b510c2dc753f6ceb1b9e7bdd923e0e065a6c11e\nA = -76e575cc79d7f0c313a489b255e85d114f3933383cdfe75cfef649f639921eefb9b3b3184351fd0ad252c6e477e153ee586a0ff6da1e1b2bfd7e953e6dd778c849843fa5cc355b31f5529ca45aec81ba67a1e364d5a74a4656d266f7decdd47b2fc2d81d6c298afa2d1c39b5e8eed519a9997a14513537cdcddde0b5b41314476264d59b7d3f0e9a65\nB = 6b7faa437b4e8db8fba56c62eddb8a81e9090d1b6655a2185d656b2db0e85225992297381d653e707aa15f3017880b0f07abf3dc455cb09c4e551b3df3516c6db4ead79b88339fc33dda96bba76ff7c388363c36b67fd5dd0ee63f92f67549dd77e37e9902ae51cb58057579f03286fc48e3b7fba763fc5844c222e6a1eed9e1634d0bd034cff222bf147\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 445039f359b55eec647296fbff4f22beac09cad32cae79c13d591e314fafc2b77839816aa4f641250938865b0a2c30a10e23da71a6dff5985ebf3df4429fe64c327557b12d987ad9e9971f7c7b1e4ad01c94e1e5322dbcbc4707a959a401624619029558fd6f5b14564469b13146f9a2555916491e4d77caa70f51716b299135\nA = -18ddf976fec2090f7d1f4d41b8f875e56c813c04338f595d6e591b3eabf9e105be792f45354ee9beff997e6c0e8ec3fdc714c07b3466ad1a949b9d30da0115f5484c3b9e00c7cf0c117db57c3c6cd7434371c6d9ac7a5da1a0e2d705bacfc22f62785222d59bb5bcd3e3bf2df8e845953c6ddf1b546cb75b1698dc8e20bc611294ff288056723f1e46ec9\nB = -2cbaff39103570df7d85a5673b50fb8818434bbc19ab4e33bcc8289a4047d85de1b7029a5cda3976ab12e1d891b7efe3d5576bcb3713c597771f93532853290068761bea04200fcaf9b05d8553b960ef5e28064de89d9e5097d12b26af0b64beb40b33ff82a55af7c5838b44282917fd4342e2065942c724f3cca515d9142fb8e46652242e8f0ee5ae07b6cb\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 6727c0d0ecb4a375d0fd1bc52146da1242099d445ed9e87b1fad4daf8369fbeeec49027d88bd98efb425c1e3f73e412fb327680068ae57d4a53992f3759af0ac1b96a92f56c2cf552e6682d1fa90c3910bbc5c0b1754862ee13c5ebd62d5b98bfe8dbbf9bf53bf9ed0b967f3c9da24d4334b9f3f75314b429b05b8e27142623c\nA = 5cb6c49efc6767cf956885690ef740337aa71b90c1d4b9b0a9e4734de0c0c50f2358fd45aeedaca6e1dd0fb510bf097bf46513ee09f3343bbd1c11f507eb61d51ada40c5d6b730561756480063f60caf05141bec9a769c241d367cb92fa8e229ba2e471fc73f48812a25bfc7553c395ca77b80443ccaa82fbb7198f8c35c3b5a2fff977d8b2a29cf9358ee1\nB = 16ff229a0e67a410555dbd4b687f1470ec854ef67db73a902f2d19953c55071c4a26dc320baa8571586f1fd54fa490b0d87dc83e5bf20b78956084275518b307ce69aa4ca1079e3aa753d97fa1cff62e0b5f3b99d96a24e411fc3a3e375ea21b7b35a578a72df68d28286fd9a324c06930905f696424780083715f77961532bad061f3901ed276a9eb6e81ad4b4\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323",
-    "cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 6e9947beae4d934253e481d27e854a59c4047eeee4fdc7df7e174a8f045776109c148ba3721685195b8fb59263def88891c5953b5a0ae85fcdbf02abc76f4d3c0f5d9496327d063ce8b3ba875b4f119dcd8beefb3ac884c25955af61c35a69d0670c3c349564e5b84f7df4252d6d3b29d9a75f09e9ef79f0fa9f797bf75b8ccb\nA = 188785951a3befcab56128cb6fb9576bee2412e6cdd7dd1bf5643babae83c8011af99aada405e119c3be33653862440005be994bf37d3802cb6c73cc312824c56841004c8e871ffb560e93a1d222c93d63684e90a91394b9c8ba8cac27b414bf818ee0de7217bc2faf099783800485ce2e93612ce39fc7e2f1db708bf9bb032d92b66159073fecdb2e0257058f\nB = -8dddf094f30284c213577ceb7f1b2efb1e4213a548e6aa840f801cd6382fb6d4995908b7827078dc3f46fccdb9e071bb8531ea8971de0ddbb714d678bb71ba9d961e58cdd5f41b8472146ff9b814a5d1d6368bd94812f8d38f235f39aeb2421a57499fe7102c1ab167df7d33b32a6dc7c8eb8f4babdd6b6c929d1ebd9bf4774aa40cefbf136feda7b6e10ba4dbef1\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 3f4a8d90017dbe8e77205e65fa7a0875a1ace6f3f215c2974e47dbac779804143da3dbce92db391c2614c078997c7d1a15439ffb51a5787f5bbaf98a4dcef576a6317b9b92dd8141a8fadc05d3be7c150630668e620a4e07b4b00519f34e422610a160de112f1ab8adf09a9169ba95b60242c89196ac6e155021dd84b3054511\nA = -65ff4322f8e46e03aa6c1fd10a207a5e51db6991bdca232c0dbc9d73ba77fc485d881868be7b14c25b05bb59b7f5bb6c4b2a7d53f35d2d7af282a0423285c5de656429ab7d3af7d92837e41ca701f527845e98c2bfcb51647512e6abc6675cec2a7d34ce55ea4dcfe9e7a8397d45a7a3e73bdff06e303a8f04ab6285eeb1bb78b1455931cae203078eaae826a6e5\nB = 4d936b603eba3aeec3d3f1f9acff02a0ecc28a8ec64b6bfd9b153b1bbacf4f1e186d3deda8c1c81e759237921cec53251250e3e838f5063c4a1eb6cc93637f35aca10b965533d18b713617a312e74c446d63eccee93cc97e3723ab27357ae9b3cbfcb3e2bfc589a1bd582480e776198df047c3ad85f611ca6fa480c70aeb98af02f57d56dc9659b2a6bee222dc3e0566\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 8a7f3cde3230af1f1fc25e0c0e9ebeb69161d3864fa5a03e5d7f8c82d9940ded285df35c008f61cc151b4578e2677b2f2cff3236935de5bb1d113597eee448496fe29bb18343687f6e9f1c783863e949a0954de2993d47a03607423b458bfd18c844ab57e9e2a43930df159ce8564edb5a2a37a06425626502e3ff9363b73c79\nA = -100f2984dc1451fd7b71e5d290e4b7de2d26175a47b9bed524fae02bd5abf96faba06e955107329559bff3805689633a4a57275732bc42183acdc792cbf7b6b24dbdc8921b73c0308d0c0ce5d8aad75f7eb16352e67116e859b323deccfe5d9ffdd1f0265297bc9eede073146a06acc3c330458b07b8fd0bb652c7325cafdcfa165f69cd0de8b145d49ddd576fdde15\nB = -21ac4953e54347a56800d75f6feb6ad660b0442174cf3c5dcbcf6528e2b5da95a614d3a8399da14507df4b8eacaddcddd627b10ec2dc5fb8c43d96a38e6dff37189ba275afb9484df800587f4953e327af71dbd58780bd5885b4cdab15ea0f2864f961bbfa9bba6b2d9448443af87c0cf178990254c1ae6e19003b1621f3240a6e5d0a3be2deb5dd253f5e1f88dbb60b522\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 76f8b44df8d8547f8b3d8537393d2805c699eb37d19bd115bd5539adb6b6a00d004def3b7793d5c71e0ccd2b7e9fb87103c1a5f56a8f18ede1bfe1607a346297166596aa78dc584c7c32832e11b72fb4f2d40ae1591f341919bc0157080ee8febb7fee5461a918d2178fa407c37a8243e24206ce2c19c3addcc2b7c3c1912b6e\nA = 56f4d397530f5c90203df1ec799f82a0096888fd370d543e33b5a2c8042108bb75a86265204c40fa5a9a44965ad2fb41896b134ea56c79699a230f38c0e3fa4e5d346cda70e0253b9993c9da5642f4e645a0d96cb732f8f04c99a83d1f1360a385c6e1a972b89915489245ce58830788ce23b9e62d6b48a7ff9a486614d6979033f7914a0735d201c6f29e512374088db\nB = 10fe818f6af7a95cfefb0ea0726f9a3e0e7c30dc9785b1fdf6e2b810515448386c7efc656479794d389e109ef3efe37fa6124c5a7db3164268da0d98538606c57bd2f7df9482860e81f272a27c727d7d81a66fc1a9bc8c385cf02b7ca6bc7ec2d8d6ba1dc992caa216d02c9bf0fba8ee754af77567c6e275ac1b6b1b36b065760761300d156e40da8445712b8fb206c0df346a\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = f580f9d2438b22700c3ebb23d1dc296f3d33deae2d32dea51c7ed3a0ce7b06af11046bc1cc279bb744bc31e7f822c17ffcc5dcbbdabe213bf97bb85c7e19ee71a513bf59b25b3b5787e42e9f3ef6aa1acb8705d69924a107b4f88e0cf9276c2c7c47fa4bf56c4900b557aa5587418f0ddd899630ad3ff678b5b907c07247b2b\nA = 1017a4fdce8bf41ce804b7c9c836d85ff6ee899807e1736bf0357b015b701b9675297e5ebf588ac6c295feed3c6a367987e192be0d89523ac7d64b0b9576f311b5b2705c5398276a52f06085027480c2ca72884ad7be34967bcc6c8cb4ec4fb761e88c16866a2e284b40180eb14536810eeeb180ab701ec47ece62af65a0753f95ca657e7d04ebf3c3a7db02993da9089840\nB = -aeb03379fcd4e87cfd18957a72fce42e016951a72b673a9e81f666b3cb20d2bba81400ecc2b38601bc3270eac46a633a1a6b55c50f00e9d7fc8a20176b93e971cfaa4f41573b17b8ccc498f8a3230825afd0d7f102daee347a9d59cc0914ac8689c1d8b39ccef1f3def44054307a7cb7706535f0cf4007231ba21696424c3d5b42c8e85c278f7c2e8b7d1787effa601ad357eeff\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = be05efeee19cc91e30a9277a6551aaea63aa3861b63f6061efbb0b92296e09f4709529eb849d9f40406fc59c526a4697144cef9661b556040458940ffd6a87ed56cb073d2ee0e6d1f05936fddd1b9a8974a3088577847ddde6bbdfb3d69158d5b3899c13ec78fb5cb6aa7204efe308bbe0b52f18381fe838536707a8a27ba0d\nA = -669660e75eae9930dcbdb99c477c980869417ec9c0e8c4053f0bd8ae62d496daf7539f37af96fd1cfcf3149bc02b8182a46b413e3397b49d4b4d204491440eea65505cf5d33a8e797af08f3da41f5a0804214846bd95d730260c6545d51126278181719ddd396c55f119e84da71f0683eb6db8393b098b3a0c5999862644e073b4918b5c8aff17efe860744d85bc94b582d45c\nB = 6045f903a750b69b709cfd6a1c8ec9fc0d7da9c53a9d26fdb0ce9a17c6a0ed5ba633d6fc01f004f4a48cf247d61f7df609008ca5bdc8eafe06dcfa06bb67efa6a584b5a2f02768718a908978edd475a2d2926af2a6e523549a5cbecedc78323c5c295bc0b8d3e14053078492e82e339ea2c6301412a5dd7efc20da0aad0577a37d853eed820776e672bc6d23dc821b5855eabcceb18\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 705bf20b7d92e68a69019cfd721b27373c7ff22f911066907f556321371fba70dbcb9774d3a26ca43e44ab20c586a3c1546fc3152ce011be66e04a59c6631bc8bde18efb7bf1743b9ed75a7a6c5bf5a4117368b81b112a3cd4e1c44a621f534a11c426451ea5fde880939ee5bb28d9843730e284520a976cd9f60c94751050ec\nA = -17c1dbc1ad1d2d33dfe1af7b4cdc7b69fefec5a92656957e111aac292e44719c7c752ace33dc74a6568be38b576a5ba174bcba77a034af5fe101699c99ca39f8a3b0a20679e6d0180868a232fd8fc775089e185e5eb81585403f32619a2f4d857bb091a824a89de2e84529e5b0702b45771a5816c5a823d81ddc89f8a70cc3d3a0c6bd6d85e9d72b69d2713b61c46161f7f4700bf\nB = -2252b54c602456c5deb86a0f249f3982c3836b70a946f636b22fe00c6e3b91b94e19200a33087fe734ce9a3f92a6099ad03a95ca523b7edb9e1ed3464d38fb96c470464e1c54790cd48769677efc5e1d22f5be4c15288bc5ea1dc184a05fddd5e576b3b4962f37437b4f9709dcec374377db44c8ba1d8611c0c3ec35f9bba213eac59a047e78195ebbbeff941c7f862e8c80eafb72b1e8\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 7306e3172929c00c29ca1db360eb4ce82066f237e9cf6aae368d1f531620e9b61eb64f5b3e2b735a3b565587d7e955d052df94a20e4aaabe493dba2c18e85fcfb65df166cc48733632d165129b112598bf5e4c58dff662e558e5f71b25f36708d3ab6536b1cbdb5aa2ee56d9e019a9c3629185b188af909831629ffceab6",
-    "34fc\nA = 6b31ef80767a7693e7d0a9ecce54beaf5848120f036923d80b7a0245aa6a46135e32314f3b227268e0bfa1f45b4dce83bea890526c7ac3efdc8e485189ce2c51597c2864c2d3664584be23559c03670622a53edc2c17b3f1a92640078ec35189dd7953e55e4da0290ff1e2996d164d69f1bbe6f5285ae89209d611a7d760e413e23285066eab8e126c320bb6130a91d67ef26d4dabd\nB = 183f06828033287497322b05ac08f62dcc5fa67b7a10c6c5a319c9a1e642754230c6d9809dcfd2de4bb9e360d6e6e1180f6ec6e0d4c6185e34ed299b6171e653521d0f7b8975ed5e7d2c51d27f9784a4b6f9b5e97379fcdb42e4df981462cd5bb9d0501f93f217d954f6baf70343ec710065eacbd2b778430ddc36a7ef0515f29d5fe78d8708d8ffb6c3391c6f632cb1bacb4ec52972ce0a5\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 361ce44d153f4d251952c0b90681a19b7d2d8df7a6c5d459691a80c06107b2e818f93f30f8dad352d2dd87b01530d51fd1c67cede9b1a6167697098e41bdc5dc5e7a3c310116aed0c7b5fd99dfcdb3517c13daaba6ad10879f600eab846cdc110d392d9bdc0e8ab34b317840a725a7a12ceb48c75e8dfeffe2947aa85b2a5158\nA = 1e1f2e44bc7c79a00afc3b2570d5cd27ad5ec9f45aa94f63f2ec3fa6b69077480212a1cbde25ded7ab1c6cb1ec26d5905948e5c1d6d109bd5047b1e038666054606b42e880b609f6f00a219dcfb504d481d6fe709f4362940f6c4b6f2e05d243722cb32bee5508ec94eeebb53b5befa551d3ab5dff9cba3daebdbc97179e56cb778aefdda6a0c24265728ff9e59ca3c2d615398d97e66d\nB = -e018708df037aa2918850fabcad82731487fb812213b1c067d0688462a4d518e5ec7c4c84f2cb2017aa6bc960e2faabbe361ad8f66355366cae869d366f06d7cc32ea08dc51631e7f36a4c775611095d8aed06a0086d0a471749246d7157947a1eb5d5503f207723a7062382b3e45bb84c6f555e48f6d63aaa1c04fe13c0108507c0ced669a5296bcc16debf18e03c32eefd177bbc1dd2f19cd\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 3aeb3ff6e797d271fd2271499a740a91569f300d7392a7b5898084012a3c5ad379a57d5169e43089cd58fc7210314758d5368dabca2f0ec5cf6786801bc99b45cd60403c732d9f98936aed76da724bd3e7d4b622dc690778f11fb0310fd4cd980b220627f7a864e107f93a6259081c6581e5dddba4890508af8057c1af29a745\nA = -75e06b47f60edd23148c3736c9c125a617beea7c8fd47e662c9d9be883ae925b7801a0030df3f4bdd3c9fc386f18c4e002e5daf4a6f7fa27b2f71252c83d5f1695e50d62a10b99e1900987b342290decf681a064f789e11bc3fd75d64e2e78ace56e7491fbe0eddd6f9958a5f95775c920ad6c051ebe7750fa76891ab00f42c910550a42bbc1c1e5aea0ae13b7e6f916a5d228bd57e854f7\nB = 434c8e4767d0d7df2125def75a978bb1509a26bf8305cd03df748c6c12b6dc580a2c1ca9a4526eaf3936fbc4ec797d0733217a54ffc9e1d7c6ca04fb39679859d5bd3fa64cd0a09cf1a056094b9c20ddf1f00e134533ba9892c2ca7346ac8d0655250eb45df9f0b7983bbf71102c6f1a2d9497e7a45eea7b3095cac037b7aa755beeea8a6191da268780179a652d94a732a2a5c7b626c0de3145f4\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 734a429c91f5b0f06fd47725ded06222c0193dd407e9daf136696f203e153c9bf6df59016849284cef93fbd35edef2cd31c9b956fbe562d2a22100f177254144718ac7d22c99783fd523b642984794bd7beb0d0b363e28d3f3469ee332ee364faaafef25c1d4a11b5e517e44a412ba717a113ea9e1e8f2d6db8fad6f10d06950\nA = -18dcd213e9938fe4b6a64abee3b9867f65e47e5b0365d45a8dee14ddf787f34072ce32f38d4d48ccad236005a23c5fcdc02b72cf27001495663fc56f428072d3f1bf5e33ab2c5f9dd9facf122f7225ea03c2f67321530a642803f65a2e9428f32d0d974e68a25f705e4f8140568f7e4b132942b49f9ff53f04f241feaa29aa353925fcade33a0cc192fee2628c2111da1e652cace9d304d0f1d\nB = -2e5397658a5e6db9d30f09e93e67a30dc84b1e17c25786e041fca48ab710e1d0497ce615264f1abcb23d5aae8412b58430bd801775acdce06cd362438898697940712062b611c92ae6ad10da31784207c5e7b9362b20d7254da0df8caafe0736002dd466d76b1a03e91a8dbe8a71107abd5f07b00fcdca2017391c7c3263881a3d02a89b0e16a2a765a32d24ae6584cf44a88975c539402db9a301dca\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 427609751f28edb62c717bd98ddf999cfcf65128b652be1b5aac0dfe1bc0f7687c580ec70c8290455a9448c69dcb550c0cfdd109af561ece2ec8707c1d02e8097e780f32ddd932e706f81f68711acda0e7610f4dd0fd55f6ac7ca3a3184f655b0b29d2d62974739b43ded96b413b9e3f0033ca1edace24b6bb610bf06b5d940a\nA = 6576c31d48daaf7d6bc3658952c4ba18095f1a0d73726f6fe59381af45a2a6b592adc79fbc3b597e1eea711ab295cd991441fb5fc4ce5f047e571a7d949c709e0d31156184be4b8a6a49691ef93d7d3b120193f6ee82246aeb896b8b7b4c74c27c02cb39fe0335883a3f088a71ab42b947a0cd59dd2155c65a0274ec0836bb8c2fe394500724ef84d869bee40291363389e7012d672b1eab6696b\nB = 1ba2888f30be283b588cddf00eb3ae3c641e35fc0bb3a9fc85d7fac1e81052129f499afd3e8458d4cf893d51fe4a2bcddf70f28c8edef16c7bbfb791daedf1a8248faebe36953560498af652d1f1c7aa0e9a5a667d9c94f7d9525cbd5a82147d58b738dfbba5aa162858c2c66d0dd7d8db38d41a2261e6efc7d0c8b2dd2d6962be0fc796705cec8e87a13092e4a3febdda3d4dbed9d11a1d5f92d7dafcd6\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 533d6d8d7384e6e65569ba0daae0a8cffbec1d20e417a6edb42d401a59de0a91a7e6854db081ce33b76faa63f6d866993c245e69ddbe6c86d339f7107a4807856cbca23cee2bf5496388ae8fd8d7c78767d0775acd7bd6202dd75451b424034e2766185969b5663b638d539f718e50a9f752f406c224c000bf1ae1fdd60a2a82\nA = 111940235b144a42a13201a41a3f9e4ff02948f8e9127d9a3007906988a50b36d7622d1221155f2516812074a7888b1d8334a01c02ee33b3164d761d02b36729c299ce2455a462bf18471fca42e5b01615d53723c3fefa5aaf4a039a6caad35c348a0a4dd3f0204f084f35c0b93ab233c4066dc50c5fd3897a769a7c5bf309f7a9c30e905466c8394d509b79d62a69b58c73d8d3f1665ecd9a8a4dd5\nB = -e2633e43c38c0b4b8713c20bf4e2b8ccba680ecfc1139954fc42724277beadea438596942fea1094091671c2060dfccd0351b2fba8cbed35dc963cc18f8e8835052da884799d88ec1887712000a0726b17cbc4302421011d5be8d234440eecc363f09e2c04bc9cded3cbbac9a5bdf0b6d418822fdd90dead20e5bbbb3566ca94ab85f3a00d32842eee6521edd18b9aa6872340b2f47deb961f58bf231e01f9\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 33960d7ceac73f342d46275e04fed56563decf2fa4c0e9307c90288e911ac8782f8e1354fb051a9da8e2db83d7c710b5d2b611495e72ed42259ce783a7e7a8f601c07061ec749481d39a082f29dda1f9c7f444a33ae1c1055d37a677b848af371cd3bd41c851d31a07e144d7add66df39576b8200a8b918201630b3da8e664c3\nA = -402034484e499a8efd610200790d443c5d3be35d19d8808da85954d42dca3f24177de48f55fa2efd7e4f7f624d806a8d461c3bbe0b626fa1f3cad2145746464108b367b13f3537ff395262256bfccce5f0414e1f98b59ed29940171d46ebc4bfa1a27802cc30d9221cfbceeb92abdfa6e84ab4a54965568aa10ea631e82067ae358a1a93a3a3fe3a5ed5636a0c4cb373b4d49f46f8fbbaa665a19200b7\nB = 78ec7dbfa2b28e268619ba6db34a23adab25e7f8690aa9464a7d8fb7c6b87d5dd9d33d4c023bb665f2d96febf2638fc087ed30796fe7517fd58e4120c0d319688e67a32bbeaf62a987a9764be75384bd499b0e00a850f27e303f615031299c631844d10abc571f9f2a0f742cc0e8df2fe3c244bd825bf1d9134b2f1059e2a1b61985ae8daf9bfbd9eb24ba268ca58553891945ff1a314a78fdebb5444677ac081\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 3a1ea3fccd6f336e6d444d68af1753b83145131954c20f1e3c433a89eeb7e267425a34d91f67fd65191dce85769ece2fc7ab12d032f3e30f8509095ecc05148e47a85391b21a18257c338a6a3ca9816987abc8143fe443342b34afd8a52fff00dda2e42b1b39322bd38c6a1f711051f791d6cad2a47ebd423a9b933485fd5861\nA = -1869c53f86755aa350115a9f49d6248cedd42a339506b8ff59cb878b7745956f142fc4387",
-    "322c41f369773ed375b72665026771d4ed1b9ece08f84e4782d4c3b0177853cf9ac3a55f7e52f39c1b82aa42b30628a4fa6a838754ec6ff9809308f675e455bca6f44e298394888d85fee29d8a0c8e9cdb9aa08d68cd70e13a243b5804a3ec199f52ccd462ba6594d856602cf1d5efa509047633923d31f78da3\nB = -2023c544b6cdd8d971bbb345300f7a101f6dd44dede6bfb5f4e6b4eafb7a40728a3063f6d4bdd0f606ddecf062828cf889b2f632d0c9254c28f36dd974aef116b73cabeb2bba98635841c2b4d2aea833e35eb1db9fa9a9d33bf7b51c49a14907dbc6036b027a039192b47406bcc56bccf375fbdf40b82ac4b3c660a43d5a6eb656868d383cebd099d2a73506f675cf29649617fe06097a46de93c13d1e590ef2cc71\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 4331f18a94c169cf0253136bc4eb7480c9fa4401c18db1194371dd53e5f7b75f07ec2e1e1c4116a5d2a8b2cded4b22925b67a88af9b8479c6e821d58cec7ed9f780a4c41e729982cb33f69b87d01c11cb9a8f7952db1920b6eb2124fd5d820555a99327117d7e8e26d18e748fea3ebc17e1d07161fda57a21a70c7f4e251612c\nA = 5e7d4ef7d6ace6cb106e38d96085d3f3505983fd952498af3c1d9b2af61e4ba10e14961b339c6e64e11ac758d5fa18c3222138290866970d67d0a4f4e19f453503eb8dfb85b44d1050c86943e7c5d6faf7851bedf7d0cb6b13d2acee25372243591d37dd230907457fb440f83b62395f80f59a2d02b87134887406a78efd77614f3193e517f234434ab3be084f1484d3f2c1f68c67c0d6e863585a8a5ddd0be\nB = 114b6e6726433ea88a2ba965f0881beb3ff4d377526e4e099741f069abfaf29e129a1f5fd243c6599f725a389728f755f9cad767ca1d6ae5c8b3a32102e47af211e86d67574bddfa42b2cb466d968f38b47333b1b55211fd9a315acd5ef62cfd3e83c13ee9d3fa20a06b2292177961dddc7dc39abad9ea31ead1fedd3d699f651b656edceebb0bace11bebd0cfa581dad577b8b42f0a844bcd8c8227880876dd7b0aad1\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2468cdb1a26eaee34db3d2724e37f023c8a1788526b3dca99321b574685cc8303c609c85401a58fe6da181daf4111fe8c6d4b7428b1cd301cdb9bf8cb6f33140756c8b490d3b2e538ff294fd6471c4d17b9d9e4adeae0df088cb9daee18e825a368be57af4a096056b9e76b94c8d3b911b6a074ed41082926773a585007752ce\nA = 1e6a59efe0b14fa017c32ffd0962700fa9752242b06ffd0b604b9bfd125114d4e0909534ede704cdf1c9e88a6567f4a2989df752510d087d7b7afb515ad594627ece54b8a8e539074386121c9a3e1c12eb2641ded8719e56d42ef50e2f3b5d7d59f8a6f897174cc00a7449d2b91f33e9df07902a95479731a44fc4ebe8048c449bd515ef6cffed70ae78c832cd43491203a247fcfe0a403862266777947fc2542a\nB = -8a9d3646831dcc852fecc8e2335549e8baa2e2d82fcb90846ee82bcc715c716d4a9f62be29d5e1531db73c2186a4d2f118266de33d966b78f989600d772ffc55b1364117d6750cef67f4bae851e7e3f8fbdae7b79de7eab54cc1fee56e25d0632b2929e352c882ce78fd64dd0a1473e80b6572f0d4eb67f6bd6e45c7617314219d6f7de5e505a9b395096cd36650d23e8d57d6abfa9faaf0ddbff90d32865bf5ddddcaf28\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2909d3aef7a21244efc9b5b16626e260907ac11f3d00647f2170ba37197e47b9767030195c2f6d5eda717a83a152141bffed2e26777417ecd8e27aed8666698c2e85a414dddd52b07b52b0da7e08b3217fa6a331f84820d21086a4424974e1e8cfed3501eb054242a9f8bf0803a94981b7b81776eca6d07cd50c050dddf81d68\nA = -73ecc8a6a1507fb5dad40677dc6ec75f0d130ea704d1e87b00d2bd56a6be21714bb30202739170b8dd3605f0553ff57439051efea2a97def70a6d2cc3fa2b9ec27a00c1338bbd588513f0f320272b8933fdf6635e585d1e79203efb5c95a454fcd7f33aa2aeac08902107e9bfb29587ce8610d50cdb7f2033c5b726742fa9f7f20b4780cf9244e6abf6b812171a64b870c3ca4c9e898d4c15e9f5b0194ae736c3783\nB = 4049ae926bb52e862606842bbcb4a5148bd1063b6a56f331cf10000c524b4aaa80b3bd914cd697ebc98d68bd3c2bd5c87fac4ec68606c264c56e25b19d118dc9f2eca19bebca07269714f2955e107b3fbf85530b1fe99c42d33031958280b8e8abea5a918a41cc7e6980149ad68fbf1c0041798d2046d7f88a395348b295858c61c2f33d8512b6fe75aa8fbad62e2f9b0b7876ef95af8a7b7338a2d6b25ec6355c276fc6ce23\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 22407e4fe280ff5a10eaf46d8e1f5a1e77a07410cba4106466d703b11764c60124fa355733b47327e952a12869476306926cabbd797fc80b4a6dedfbec0b7718ee754d447825cc405a98b85f1e09ebb9294c4a4636aebfc61af4545b921cbe759d3f389beece3f29c2c7c07691a4c46a1a72ce418a239fdec80df48732627866\nA = -1e165ca7e1eabd2ad1264d5ed9c3d2b687f2db5b507a0e4d21d9e042cd46e93c2444c6aea8491b5caba2d8146bac656b7754b7b1ae0f6216029c7167fd3b1c3ba2e20469d386d8566ebbc05cb51bf1f1eb2cad9dc4fa454b07cc1bcdb9b8f5a43e354c4e0f4e62d52798f667080a0e0a15414391269fe8c92f06da74f6209a3b215adafa1eb6866f8b3e419468e2e5b4db0d0ada80514249320cecf034477977bcceb91\nB = -3f314681eaa4cb41a3feae8467f7d76b8b05939731fdfc943235aa4d67bdca30e64de541d17a8971e829bc0159384643672bdffbc93b3eaded7844d824604f46aa58b1f1b9d788106aff53438954af015a0387268266a6ba262e2fe7a4c51b5af6ff7f918674b7407ce8282f66e84fd2582edd809b465e4401c67e5faaa9e5748c06e3bb8ddb23fa649ccaf9657dbf79b937eb8959aae8d5bd9513c1e601c0e536cf60c4fc3802d\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 385ba217033463cd9cb882fe30373c2d8e8475dee54aba1ca9713a709f40844905c2544ad792784cc8eafbb412dd68de6f98522dfca1c3de8e3bf4cbd09bee4656c4341153b17c98f9ac09411d16ec9880835cae772bdd8eee51eaba7c02ca6a1034c2c5d2d48e7ae3eb0e22f59bf69537ab6f1e49e58a71c64b8934113eb069\nA = 5137226623f4ce4dc9b80a783777ef4e53ad3c2ec648264db472c517a96383ba1173e52c2659a97ce36341a11e832f4ad293b89696f91a051c35bb1db6182260d4a276d1a9b4be848c206899f87a361d318d38b4073a7470c5743b816cbbc3bc1b20dfd7971b11ad4e20d947e352d42760104a5a3cc590b985ee3b5e98c779e38d2581413a2208d31873f9644ec979602671c9da72fa6f66c603c1bb6d8e690dba8bf4933\nB = 13b45d4105e3f5e8e0ba36c812faeafccea2f1a30e2ce8ffad57ffe0dadeae3a23e813758f270423ecda3da083b42432eead7f04842db8865f9f1e2226a3d298ec1895ae69adc55d1d338c3fb787f0676664564eefe46ca95206e81678cf1a2f173c52d809b1e06641a9b467f191ea09fcdc597271eb43da1a9a856784972ce0eeedd49ad363dee882438f09863ba5af063925871c525c6c0ffdca428054e039e149a424c6d1b5b2b4\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 7865f718cb30026837ca006f5cd997c5b917726ac6d9bd8c3fb9eabda0854d528d6cfc10e4cd3f93f6848582690c6a83955072daefc6959d33192fcf42a111650e50776ba9ae43d3d26e0ef2c6b60c3871aec33eda8c56353903e7ae96592fbf350b88d2f56e03f7f327022a2aa9b7c484a000135b85bbaba6f8836cbfc81901\nA = 16978c06a03276fa2e0bea45740a98d55fccc9d27321fd0a5b8522298a2a90d391c06c5c59e7eca85efeb9b4c91d4a1e9178adf816d597311f004ef98d209b59a2d4b901fa14c57b7297861ee58b89c9b2e931e4ce5818dd4006f3c40168bb4d3dbbd059c1f1cc24ecdc64d37df16b8e8d0529247c06f905ca88a5d283ca1b9e6856fbe8115a326061905b369791772a47900974339722d19b3aac16a0bedd93e1e4e4289bb8\nB = -de6dad276dcc0a9e271ad523620ec570fe6e3b350b934932ebbe36dd571edcde968b6590be14326e0f6394c0a2172052ff8dbc3ff15d94fb6e36a098286333768a84fd0404dfa354173d01f98484fb20897c439c48952b7f1791209fed94e9e72bfb3df5f368d420d587ae8bf036db6700f77b130459e9de2a541ed885c69c5641defa9436a4f7a69d2848d0e5d1074f77fa688b6dcc4d4c7de25a3b1b040546ef7f418112127cff173b\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2d3dfd14e7ec60f842d1db83e29a0f6b052990fe8900887dc44476ed3948870c57e72e91e1941c476baa6aa86f76dd8ab6e6ea41707242c46d39b54215bebdb1f28e59d719fde18bea9994610214ea6",
-    "8ad9f2da24e1ad8a06f8bc698f8e76379ff332a2745af472d52a4b8e57d60280e19f93d5be669e0832824321e9ad8e76b\nA = -5144d5ca834f7bbb35d3fb95818c1f89ebe08efdffd35993a7691c05aa1b67f6a28e219b27fdcb66e516097c9ef5f00e4257c561b1f94c52c577471cfcd7a55314d3b0fa308b59449a36adc884c48ef5f34753bea746bd6fab2f20b86814c9fe50e8abaab742916313a50e3c390c67fda8e3729ee3329dc5e4b7d3107083aa3a07daf7952ebbcfea15fae7338cd0b114e9ab2f81dc2e80f90abff7a7ac59e3aecf76fab87633ec\nB = 48b927a46dbc4e23d714b256084fdc7cb9d4c96a988a71c956e0bf98785ebc9bf22b9d5c6ba0c419e60afbef7b96cc0c4a13e397aa2d2dd7995875d2ccb127169423455d138131199a263151f28d232ff4ae24e316907ace1fedd02a02cb5ff9c831de33e6702010fee2232bbe3c1c193ce792eadcad0c81e7d7c17e49168377b68690bc61f22dfddb17d82a3b993804726037cfac8aabe8548befc52a3c6c6baaec89a392133cd9c45b1b5\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 3f66970f600a9d09d73fd1ff813e977f539d69fe1784b8a2f99506d868418e4b47338ee0cbceed555f88824f98ffed39befb69e8907a5822ef7cd2a9950a070aec8fe4db9d68e1c0620f9eab4ab529c7e69466e325fe1c6c011bf7ab62bfd1a136597d7d5c47e8eb161ea048477bedc88fa30e4f7ddab2cfeec3fd0bb3fb61a3\nA = -1343c391be3f2b72c4b79d8d6091389c9602e97774b18eabeaae81fc0539336cd8c899341cf75fa758421c7f32eba9df474c934642003408b32db66cfa92e6e414b42b1d49c7e655ffb4c80f5bbff8d2774ee4f7198839680175e1ffec0428939653c6697eb3681d0f92634cab1cabc63f423d5a71d65fc7150aaeea74f9e0153923a1c65dee4a165e6a01a88655fbecd2db7697f4d2b49fca2508e2b8f84129785d36d88bcf59f4e\nB = -225a0a4afdde6f6450f28736c3ef6e67d67ec6206a63b11763bc6e69b03f1494b275ac504868caa6d56d684a12dc1098ab0d030583e73a2f45a42b8607c0f19031b9c5f07fb71919868911806d210d43aaaced5894e844881e89bab85a203af9ec3adb105e50b4250343ca50c26df14c46d73a22c2e4804d26d44ff0bbcc13d0dc7e326c9e4eb441f493c9743ae0eea0de045e05d19ac32d2379196a165e63ba640ca42e4861caa24c29cbfabc\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 54e95e86e87bc220c8f53f8485402327885be34e34063a1b81e52a23fc3056758cea1c039ac4e513f70ed9d394f5806fb771dca8e342368184e674e6296b9a705c6380bdaf11550cffc73f9f55b9385c85fb648f105f11138a3e1f9dc0a39a0f9755f8328701484d45784e3e4b2ebddb32c9d9132867c6513201116428b791cf\nA = 5f1239e0b5dbfefaba906bfd9003336489ffdf634333cec2484c582dbc19b66782ba40942d047c3749597ec4d89ef61b7803d33a9842f0c903461be37c679ca213aea894d36c1e12bbcaa1c679599d2adda9bd23e712dd0d0bd3f91d146e7a04f3e7ddec8b0db7e12377ab32ba241ed1e01da070c1f3ec85efd8387a7b9421453969ecba8cbdeeeaae6ddb098084bcd250601af780960c32f0a1ad7d7e61fb19f40dff1060c5f332830\nB = 1113f145de014bb6dd6ca05de159b97e9736c45bd3bbd8477f739daf79615fe329ce948cab9787838d7daf797218af5ba7925685ea341b802690bc9588ba3e916145cd3ae9d0c4a149637b890cf50fdfa8f89a62e508eec68f9332787733aacdd57ec1f359ff7fde76138d5b33d32e64cf7d252f2bcff14be3adb1afd8da9dc930f5261e6d715ac75752b29f083bb1de7b0b89ddba633b8137f3fd299a7f77abf79781a10d897e7bf2c958a097227\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 6e0160eaac8e1c31cd3cb6c5fb91ba086d033b4b69e41dfffce7569e61770f6629f23e12f0074c47c46653bbba94701ca798e1a242f7c4e25708d3acb5af6ea307b95cfa220f8879cb4cfff96b843d6eeed2b15c8f1bb21bb2b511cefbad0618d49d9ba33cade6da6ab3b846a6a24e35fb36d41201d3b85be831522b9bf509e0\nA = 14f4e24627c773527ed2243c0d1947395aba5c9cf95ae62a48827ffc1477614ad9c7aaea4b4fdd97e3272d3e220601565aebf87928c301656e9edb08d6e680de845615bb3a81c61ed043adb9d708ec1447f057087211673fa6ad8977166a2b4a8079a4f29d48e7fdd6875ccad05d2c219922b814589996cd9642ea2b798197407acd274da30d3ca008fefb40a25b38cb6042a581393283d6448cc69df9a5dc2b0777052566a8608a1010d7\nB = -b4188ebc5bf3ba31cf7c5e100e79806e92ff6f863c3d68a66aeb3ae8385f596dabe6f627f3812d0f2baea319d93ae00de41ab65e42eae7d396cc8fd0a2dfd35f303117fde4db5e8438df0c2b3b680dca538b42a7c844a9bf0d3697fc89ad0a73594627578dabdc214e0f4aa06b40987aed473e7f42d318bebf7392d9c898b4b8d73a94726aef65807b2ff746d4a9aa76303ed7b4fefbab34f5c87c2df82d20457f68289f7b96dbeab581294974e322c\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 8dd91f390c1f85f153f332de17e5de82979755d835398cdf3dbda1ee73c68f8e7565a964ae33fd5b1f1060572bb3af67eec79c4c3e2eb4de118d471f74351b80a5dcafc682bc3cfde642e611ac1d5bc2c49b308c30985b1161c4d78cf7621b503e2dfaceed886befc004f3a729b4a9bcbb8f13791d973bf38fb8101d6b7a4d4d\nA = -70e99398673324ee83495aa0aadfffd7bb9c94ee5251fff365124fabc50175d794fa84509f034c2b86d83607789338b0eebdbbf709a129a0ed0afd21c130d94b279c56f1c7c1eacfc6cd13f724a9352b2b37412242a47b23ec61ef0040a8855371aaf238003c45ab9d18a66cc7dab9653b93c323815e5404762d3f964d4654a6995af507bb2db2149eea59acd72af4d034217eaec0be5ba1d23890081a6a234e125572e3bcf68a6ea52d9437\nB = 661d8832671a4974b493e5d71e547cd46b36730f4017e50c5d1a7520fbb75f0314cbc2ac948744dd494d566ba580a2108106b120a797cfeb1fbfdefdab6bd6b2e073f90c77e814cafd0b7f79afeecd59778b1dfee3446fb32139b2311011576674f96f151f896b477c631237995e11e61e715dd8dd38e802af93124c66eee735c472972000cb4788b26752a630ba63b45e8ebbd979f0a4da5b359abd2905f0b7f3a21b1d381cd02ac08e284218ce41c907\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2b591d2c57f6a5484b43cd7ca247c48a1b38319e843257331c8807d499c7763de4eefed529e70d4c144e5e843ac00ee8d106d0d82163cfb7afe528a7daad8e7ed105942d1128a67e38d59325cffc0c3dab9185247e0082e3ccca82a900d917c9bd0f892d4b518a752f8e9d38eab2acaf3b3b59f15b0fe4cb9a3dabe6e0191493\nA = -1896f67485a740720e23e1642ef02742ce5f10a92e51af19e112cc99c0fbddb60d7190086c942d293d076b474d056e74ec9f0c42055d745a57ba370c51ab2b761d889b766cec909811e2b2fd11d6916b753ae00622f038a4bc55b813a5d06e6ac136e81689407de721ee852cd21ea989ea7c8cbd00b64614caf0974a62097b2eb865f46fdb0c1a2e4f2d839066b797e51392e5ebd14dd92630c070acb546dc7438631fef01594878643a4cf77f6\nB = -3a8e2f3b8378a2605f5affa21c4fadcc655f2f8357a3427d2cec0118e55fc2bbc25931259e294d91bde8dcbacd39e6cbc125683da7d0dcbbc67d7c5866f08e7c4732cd4384d9366868370ea40a75beb23b81306303da4a3e26ad357c5c743d0a4ae775a472afddf8f21cb4a1a3350bb6aa71037607c334a0c79468668d3e727cf1d0610e49f27780901c68aecf1d145953e45f5b090855be714cb39aba2efb0f7db2786b331dd9bb8843de8c73c95ab13b6b1\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2f53bdd643b5b22445e2af3667a93de52f8bc7bc151e196c0ab0bf3b4e4dc0e5dae9e507508711a9e3de52e2aeece6aff7fc8a1db65588de3272839390a35a847e29204d3b9b70e10352c88a10c86cd33e067fb530d20a3a5ffe67938c5a7a9218f1164f36a73324adef64da64d5fa5540d29a76a87ce010fb7d73a59b109280\nA = 75e31ab221c08b3bd73bed03f878bf7742f9b36a89bbfa7e90f9b05ec11edeb0140dcff6e9ad1d62cd7af34bb4284b3a52bf1b48a40f744b561d9ece056a9405ab15f508700b14914e4f427ea1df3093497410a0108066e9b259c1a26ea72082b3cf0e3a99ad054804da7bfa0200d93d65354b75e605b47a4e1e17ef851a37c59a95e1b5172801e6ecabf70f1e6e382740998fcfd8a297aaaba7d04b668e3d6eed40358247767323a8393ec359628\nB = 107aca18938a9cb244ad646a37a212859b3dda7518a5827aa2146b47bfb3bd08d772eb7a866e1f674aab7a1c74cfdc2bc6e9ad1a365686213655b2c7b1977855bcd42ccecb804bc01d92bd7d2667069d853f18a0f0661f028955e39f71ee82b9ce6a81dfb2951b33b123e71264e819bba4d0a8c53a1d99964ad9ffb58b7cb5cfcd3e30b1baf5aa5b3cbd20a0df7ec37563e2b32b4cba91bbf3bb6fd1cbfb2fe0f84d720efdf36e9645c7e9ec70442ea5174528",
-    "bb\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 32d16f7ae2632b5cec2e90c34d191599acd9a1b5f97845595988c1d0d4ceb9acfafbc4aeee9924ce55e109ec88c57610fddc664316e0f9a5e3ed56ea447111c0383ecdf117ab42351b80e72720a4b1d98d4c73f5235507c5b4f7849d5e9b527d054858c0436ac3d2de2704c4bc25de4cc702f5880d5ae34094766938bee555c8\nA = 133a439cf006c753c132a8559ea13c64f598c5f8bd5043b89d04d7ecbf0ec58b225551c8df8dcb341198fb0b487774867e5b68f9058f58b3cc98168fbed0d0ffa86bf74b4fb0d4235976fa86d52b8dc7e82df176d70892954223cc484ae58b6a60459a9a0803ab856ff9699789172b163615e322e193bd758016f634c83cf50403e416ae241d9b1e44add17c2a663771ac88cf8b9dd94622d80d879ae41f0f4e7a1a32a1ab164f981900fc159aa85d82\nB = -fef33e21c07dc26a47d692c3094205bf4efae6af32f1c0f46ee579c1a22746a3663d66f2919f46f973fe558c61264157d531e66bb9ea10b4b49d9f6ad3ad8762a6ea8169a9cfe01d3dd65518c2e6e58e8c88d1b2f42d207399d7326752560cd45d0ff571309301683770793fe3765c1337d14021d39ea6980934c5fefadb93047ef07c807d0ea5625ae0cefd098988d6eb7af993c062ba313e23176e7abdebcc6e566304a5f9e03da05bc1cc58dfbbc898a67a5941\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 20877c7f53fca97f8e484ba31f23dcf51ac0f4fe4c5121eec576e043c6ec5492725f1b9f9ecfa64195f71909500a69fab2e591377cc2120bd5f60d3fb3812f9e80b2f6c787e0081c1439dbea76b819ab44bf6bffe87dffd771a870e4f5502609249c5260f91175fb217a9eece4166540be877d564049389306e0d6b313706297\nA = -534042b0811c9afca04d20d83898e7653f91a73de1e4b516f3228c6d6d9b963c7f8f4c36e05383da90f4edd072a7eda382c47b84b46b4dfa16f269c2d9ad0fc53ed2ce51cd31e4e32d0c1ee21604d3c7eed2deb35cf8df6fe1c0740a1515e4c702a2074ad6c0fcd403603b4a4e2195d19b265958ae854ccb0b41cf22480389a053f71544cf594f6833f3e4d91fd3d9091df0978d04d3922ed72a4fa3579c5fff50eee812dfb2a334148227a0f5739f8ac6\nB = 6935a3444434b0b03d27545721e253e4281884da027246e46ddefb01fa7cf7a9a030581dfe618431a68ef6d79b03b34f3ed598e7c8ac030e2b4cc887dd31664604fb8afe4e71fbc3135d6d3b4e596044d6b615de7184ebf8dae8fd58506286ae4d3b797aea911eb59ada39dac756d0e9eb6a6c767ab77b9348929a00f8e311f639d19ed88c86eb91f0d4cfddd34e98130eb520fcd2b77507c24b6804d3d65d1b21e6f6d55d1f6e92bba0544829687a096be79eaad7d88\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 24823628d4fe9540103ce5f611f8a6ccf18788120280179a40c2636f30a13e5076503e8a4b6b6ffca21da5b0f9f0d85feb2ce10b51292ed069f35289ebf5130972d720d20dfb8e6ee80c3ac598570d38e57ba33dbd75f1b03eab7847d865c3e8e471ccaf302461a6136dd13b8d31c9f163799a3c24c7284b8826608a9543816d\nA = -1d476cc98529efe5b926aba3160b261723b009e9b880bdea04e9b5b03f173040ffafd1627b38be8e00840e85d7acd3abbae2f7a60b305256b920c2b25a8a4373ebbf1a0c69f6e74792cb0d849872500519b6d1c190da30c572e26b44590b7ffdb464a900fc38db013feecf909b43bea549e05f1b7e70d6ad879c613293cf61f0cecdba1a6565eff1bfcdf740bf553ffd5bb7d74f7e9537897184c527b990dea20387bab0dec3e32727786bb14975b23ff09f8\nB = -2b6e12c87ad91a2fa878b9245875209cbfef400e637b557c868ccbd6e94dae65f1ef8caab61f292d739b139e384137a747210c09ee6f3b2ceb6dd212e14525852b8c54215191e116b7097f6729f6426a8bebdff86cdc16effa08d932ab512d7265cc0f57303aa5e6fd2afe0a45180557935c230558d02c3030b38ca88de5fc75c1240d25a22fe32c4e5096aad0078d50989812d7dd0cbb02c736fa563efd32d14109c44297cdb3d4fa3b93a2e15bbb6eb678e93e943979c2\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2c4bc23d0b4b1f79141be9149ee20cc9f1b58ee0a76d5f4205e0862492c18daa20171285d6ff0b600c358be487e78cb5450d151efcff8d53004eece94c5a37f49a15fb2b5f62a79568382cf0a4232407b139e1ec5a9595bee8435b4f138dd72fdc2946b03817e49864812b7b61f179bdd8389791178a95bb6311df0a5c60db2\nA = 5b0a181f07068af6e1e4b715d92c1b8391949a1e3cf0fe0aa49f3333c826f5582615d39ec28b1367804c1ef54f15fb83b3c578ef3ae957fc89ef22a343175df3ef2fd425f724ec1c3363aa000ef624d64c6d678a4cbd90b41cf7d69a7e03dd60c5d3470dbb75228b34d35469847772ff3d74b1a89a2c492c082d3ddb45ba4df6e3f228de6c64913b79679cbbbc36a2924e722c2c640d0c5a0e90ae86b5364dfbfae80df3d75823aa58ac6c1da78e988a11831bf\nB = 19567bbcf615b777b35fa7030db7da18126cd695ca7dda67f5146c97beeb20df24ba0fda4a4f03523a0d9b9f85d9acbdb5793ecf9c1f4ceac81299a1aa34417779175a4bddc0e95ac68309da51e4f115dad6fec33a75d0c5520692a38df64e8d684c9304f9e2e6ac6a66d2e16a03c19a30efcac712aed2b9ee774ea28af4f37c45609464289de3f9be379c733d711875216bc223f2f468a0c9b4a8277bfe49c590ebce2e027102537bddbf2856c3b6e9389c4d1f5390cb0f346\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 36e1e0b44e5afc35d1e19e88e75f030569eb99d326721ced9bd7416ea7367a98305354eeafd204f1f8a652a8442eb0823d2e6644e6320933ac481a3709777381dce8a7c165b23aebf31b2ea2745ce5b352acdf0707234c824da9e1af98bbedf80e940fba00c229539f310838bd625f1fc103f267265ac1243855622c5df72c17\nA = 1dba8bd9d1e6cdc117a5a01b5046353084946fdddf2696f831a942d9db4637a5ee76b84d4ba63156b8cbc72e40559a2fe9b8e2682d8ba1db0cea042bb86f8ed71f6609df52526c42e7494f6114bb62263d36784dd55d396018b8fa47fa49ca6e5c76ebb0b00e6c764e36cb3ec75e3af6a2c14dee01fab78070239638521743d04f184dae79d49a2bf209ddeb4cc72e0c94a93a47c107f5369070ad95ffce034c554fe2a8391e67f817c6cab5b88ae9748072da5c9c\nB = -849602ea3b79b33af2bd3ef9d1250c507d332e759d428902dbee054fdbcdcdc0a357a51d00aaafdacd696a15a64cbbdb7e1fdb347be5ddb1f609a4390a6f29f79ccdb51bd1f0547d0d9a2780517f8753a906428fd236f8ee1b433e57f2810d0ad51846304a5729f53a871d8b0e14355d24d3f092e50de4f044e2b8aa14cd8a51fbb2ff36b0b37defa7be768c56fbd4f5169d9d4698fb9072cbb0a037c219552728587d7c35f27456c02020f5f9374b6c53bcf8eeaa14be51899d3\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 77eb3cb5277ced02b72368e41f04a35796c2c6cc1273f109336fdfa745aba7c755b6ff3833e9b124d9c78584f6bfda1c94273522f020371107870c288592b7c23964320729d2308bac8813586e72078119852e1d7706d8e15c195486b8d94358736869b15d59c037ba4dc8032ceaa31eac3a9e3dc51ee17706a6956cff8537b8\nA = -6a0753edddef8b74f762bf802d7fe9b38638923ee2d81bfdda354d40df4422e6ac43724de1715c4088da2e68b63c10c90b236d7dcab39b9a0ecbce57628f4c2950c79cc88a89daa20d7a8679232c8ce5fa30525c56011570107697222e0eaee6871adced52ba01a3aea0ccc9901cb3a09eb4db2f93aba0083180bb41f3f9eaae00fb458381213dad01997e9b88f21b0a79ada1ec3837ac2b63611455fab6839363b796b105c3be6106ff284544bda2a32352bbce6ef8\nB = 542c5fde65111ec8a38d76d8c5735cee17329dc41cfd0f13bf47e6d0e0093a129f3449db380ee9a70ec1e44640839ff18b950c8fd89346cb4701ef753e6ef49dfd9bd27d9987e572bf8e68df399cf945813582fa1d33e07be938a7729efd9a5e7d730bf61c537770a0727f6bb9ea6add5aac9267bf910eac1b7d92ab4184734ef8b1d184c292b2b4295ec1bfd17b8a2a2e4d315a8b37b8ff9bf6a1e94a4772267195c5a7ea6f0a0c267337fb97a023f1b50ad697ea31451192cebcbb\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 660a1f378a23fc3b47f693a347d90640fef43add9729d74546933f4b78a26968cc9a70ad6fe8d85bf28164881bf7a99e8b96683c6f4fb54162c144f99a27e3feb736f0d382d7e5b934cfa835c723191e5692b7672cf6918c4a7a93b24af00b1beaf1b80320b14cf2d1539e3376779872542406a5df961f765e59f3480e1cd40b\nA = -1cd74c052e62ee8156ba5d97f28aada75211979b1c5925ed015ea75f693a",
-    "04c4dd0a705f6a723ae7b79958884c96fc07f81fca064ce2affc70768923bfbca6049952eea3ae048425b7c6ad1611ed4b8b77f7605629b9d198a77a27f25eff2f82867845cc868edee4ae31afc5d022b2ffbf43c14fa01bef8d7cd9d0e58362a0ff9abbf250e43ea5065512cd707791ea4868e95d8fd2357b3b3aec1a06888ae940751ceab01cf9e49015d42371fac30d48ef5853b6894ca83\nB = -2ac904d3632e25a4d536097d80a157791a6aca6eb10246ea21f4cae07aafe907c6e4c726694e14ce12e376c02d326f4bfc02ed539a5b4615a3cf5c838ffa52124f9b843598a3821cf9f1fe94e7206d6a525fad1ef77e7e77162e8c6d3d860d4f568e8f81153dc47f167860cd52c1ca59b15f1eaac6b9023c8b375bb63b6adf6972af8ca62b39f044378b11c4a969f3939d9fed5cbe18c06749956c7acbf963f640a1e1ceab73fc4c77463ee8d1575d018f49bf0f08161ce4f88aaab5a70\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = cbbeda9c467ca801ec66fce801c6765a20148787dc6becb199a15c58fae8d20c1d391a1d9d57e1c74bb412e1b8f271dc2cc53c3355c83f3e2f00f15eaf0df735160a48e2273fd1bd75533cf94c5175ce67e79fa6c1422996fae36ba288a658a7a5422a59d39dd81ddea50979e933efc02\nA = 7ea551efeccda23622a1a5029e5525f46d5ccb83c28ec9adb7a3e97c2b7d936238c483a4a9bc92fe0e21208d5703611e2795b91fd5019272d255eeb\nB = 19bd92c534f56dc4235dfb7efff6d941112d66acf81b079382c86fb10dc5473bb8adebfa53ea3fe6e4df8412e7807aed029694ca786\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = b18a9cd6a0a89578ea773fbfbf642e05935a995a38bbd54480ea3ecea1751370ef95ff5ad0e3203613f0ef6833237d549676a95b720848c5e9897cda82642a2f373951d5746b559bae2d98ac00fae26e5957c61ac1de95318b1b1aa6d5c64a6ceb6575f1b807060f9e2a241e378e6ebd72ade7d2df18d5353db7737caf52f888\nA = 13c68e450e9e091ae45863f6c1faed25906dcd90a43620b1a40e7a506e7a954256bab0225f3678e7ce6c4ba6e3a83c8f04a3491d9bf097adbd98fa6e78\nB = -ddef76382342178fa6636e62887fce6e19590065c766b047073329ea15fbba96f2cf088fa5a989f6ee3f6a513fbf66f621c6ea6ef2fe8\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = b18a9cd6a0a89578ea772021f58ce74cbdd8c44a09b3937b198adbd8e95e8e35541eca26438351bfdcd8600b4f9b71616e1f16cee707c712d40da9a440681f8c8647bc90ba4c68b08ce4cbca458bebd5110222f06b2ca980a2e9419e71064324e8c36289eff9c67f6d5d011e6db8538a54aeff8c20800b0949fa42c38fbabfa1\nA = -6d7e88715e9854b435876fc9bb2d25218a1451efb73ad9cc5f52b2bee929530e6618a858000b3f24fa5f47b5f461c84eca971e38cda6e1f475f6612ec32f\nB = 49eb76e4614ac7b0ed3f534811a4ea6da5ea24be925ffeaa38bb228fa117ed56ae976b590d6c9d9a7a8546d8a6ebe4bba771d6587ac44f09\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 44f8596fc06afdb72a6e4f876b70b8d5d734589f41089c510b0da60ade642fd79cf8e705f09910912624fa1f646da596c137f124ec1a327beccba62a44f228f3c0977fda2af631e249b2a4de17d170df07bd812c233a96d17e1e93910267682d24c5c485f99aeeddceb658a7db258a2fdf73eb0266d26b92e\nA = -122231b14c249820f0dae625342415f0c6e7f93787b4206b79e9ecaeb09623636730810c7936e17a1eece68edc7c97218efb17c069bc59bdb9681a79c910c4a\nB = -3cdaed858523fd55553ef85d018c1097d7b88f6c30060d1e77b84821ca20b5625723c7d4331ccad1a70371eacc7f7aa11220f83f1bf3595650b\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 6de7efcfbc1e8d2cb14cbe4465c4ef71f0d1d7e80a1d80d9ac2d0b161d45fc9d915c54e33131591e8daeaa11ce02404c9b8494added1bd83e344ad4de7c04f626315caa56fcc5ca2ddd4e1ff064a2957afeb5d280477bf1f1195c7294d89049024fe821dceb53c7d270a8b4653e2fc0a4d8a3863a854bc3794753a\nA = 47423c4fec1eb6779fd23e3d4070d0a7bf9a946f5610eb469876797a39c58577242daef8c34926f6974089fc595508d9c573d0a275cbeaf37172f10b8c849a493\nB = 18ad789cf09e9ea182eaf43b28b4f2540e533f0fccad325430b73101c00e440bb64b70ce0f2680184aa8caea2f6f6517e9b80285fea8b61887a41e\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = b18a906994d3247bf8a00f20e4b349a500159d086aa863772e71a68f91af9d19e4c021843f8bb6eeed1df708d55047dc8faf219e00d559517632dbd1cbf4bda61651b9644481d052903be1970f04bb4ee8faab9adbbf858324e6cf5aa9384ceba655a1a107210a9497552ba8a56d5e0e70b0c757baa71d1613683707357827f0\nA = 122773509ee608cd9ab3ff6763629a18eae41be64bcfb05122e0b3e112db48c64d2a5a515d96a042850c1c848ae5fd5f0ccc57b273d25bd8d68568cb00bb17b1589c\nB = -af398208c01ec9700e332f3e694894c7cc412a73bde8a79e08764ded92f0d58db8056883972c79a0c9e0ce810786cdaa3629baeb9e5c370a5a59d3ba\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 64ef5e7063a1d95226569a27218e35e93d870a19a43fba9889a2ca98ca5c573fa56ebd77f1403b3bcad17c1351803a809c245a97bbe32b45e21768f28c5b11ad542f5e687a17f7811df6c8735e1778e94d9313c19fa32a6703af7ccbd88b489c96632d10eebb580cde3b905f6345a2a2b86a871b4fab36fa4b0dab9a6c1c5096\nA = -7dbdc37a51b601417efdda2516aba15827a40ffc304c523a47c544d5c0bba6c1367a20d8a6268a5c3f723b1b68de57eceabbb00d44185ec4ba7ecdce5d80456f8cfe7e\nB = 641cf85fcb5fbacd6214be4b7b06fda1b80f4683c21c1d08311f6e23a15434b42d30a51912898a1c46b46c00aef7ab7663ecba683897825a4b07d2b7dd7\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 370f20360ac844bf4275f78b7fe71ba5db6f0bbabfbac3384c04b256eddaf04725d2d57b31afa48f047aade156c34441b4a41c0b2146790a2e15d13b584021ad55965588c6e55ed3b5cf5c36b780a27c5dfb72678d57528ab17ca2ac696aed3d9abb0ca448d9d5789fe37e632fa9709f3bb924c4ce34244d239a940dcddd9c77\nA = -1a0cc5b07271098a23f01b3c0d47cab8b294794b74a8b162ff3b313fcf85ea81fc99433cdf4450970311e1d5ff81e9ba27eb867073ed250aaa7795e44ba8d4000e879bf31\nB = -308f93984acb78c5dac2426d9bccc2e3ac361143807c7d34c24ef8f8db5e68a904ac8bfed1edf3cc90d21c87ae4d224b8c46fa42eea77797f94aa848160fef\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 4c8f466d1d9829aaca1a22fb6ca5bdba885606b9264933ac2b4c18e3afc0c406aa71ee7ff490fcaa804f457096e44576ff8096fb1d2b3c68450a8bc36d1a2797ab8b621ddc91d75e7d6ba01d86e959171fa428a5bb1f26766f94a553c94f6dcc2e0af90d7776ed3d9fb67e842e88f7d7342afd86e2f5d159db7304ae4d204a3f\nA = 57e894e37159cf3c161be9c97a946454e43bf09a7ae8e1437570a86c6b06f84005c1463d27d726afd2e25aebb1657eb78957a9a12c8749049d12007a81d766dbe008aad6d83\nB = 16dba5cf077403ff4af47438f5840f65fa4e058c5cab3cb730154ae0fcc982ea097c6d0e75bbd635e97314f33ec7e31f0e41cf285ecfafaf36382b33d5e83cd55\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 29d13ec304f26247a45ab6869720720fe019d6cf370b9e2df9a65828214aeb4f8b17969b8dd54339d08eb99bbc66720ed78ef79033fdce6da33501fa8588af86ec18be4c4ecfe01781f9d1379865100dbbc020b892e77027d1f04f8171ca51fb73129dd9a96568904eb4",
-    "4e19f56f842b223724a9ffe28826803185e4208f0ff0\nA = 135ebb133a0beb909101da896e3aad7e26ea72b23e60802e54cc6c58a07b1205e2ba1fef6eb86c420f011b70e3f725aaf9fd1873b6e1c1cc7005c7c09e55550414875cfe846357\nB = -e8cbf3feb7be7fd12b01d5bd024e47538f434b496613320ad71f48a8972f687992f97e4b69b5842d2d6a4176a5701327c40325e98b27e4c0f8fee5a457d92181e40\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 4309b728306535bafa6787dd79e58324b3f86eb5409d772018cce2159f75832b87909a672b8b4b14342b352e76ec5a6dd66737cb0a20b81c5ce222133bfddfea878b132b6f9fd557133973a0b44aa41a01d54ab565d6b9c62da67378a4058255047a95923daf5f0f7adff2a3f06074ab1facd986d7d26cb475ee818199a390b6\nA = -7a63e108bc9790ab687e0fb8a1cbe1e9ff876e7b5eccfbc136ba05fed93412dbc2ffb1ec49518e9fb867429cea1d7f82e2b159b75bd40eb8370e8a54bf0e0ac0ff24aa3662774bae\nB = 51ee025b2ee8abf9dc5ebf1a4600131c00ae4b6bff966dae5c49ab5b9017e6b1abd6434736df6daabb2bde254022783764c94e66743dc752c9040563df7016a1581fe7\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = b9ddcb9ab858d2229cbfab87d87236e8206cf5e1a042eb5ddde201d56e2695a3d0b2a42bda6a284fbd2a5b2c2b80446ce88c024137780c277ec80bfa6e9d15397cc5bac98e58c9130756ed0fde58d475a033fd94b1fe0ecc6fd91a8b42177abf3f77e87c0847a4244b9fd4980f3b42c7c955836bc994f2babfdf9c5b43315ca\nA = -1f971ee9a7c966d1e82166503681afc280fab255665b850645321f67da8934baba1226e9efb59e0ac4483c8724f63556a213f2224b993e4e082eefff0056f7aa8a3cf5b655e0f72ddd6\nB = -39309313b04bda1103ca6f56514026538b4a29ae258a2a66424abe2c652b959f5c1dc4755ea37ebbfe404839505c2807ebe069c9abb9150205fe35bc286ca12b64ac46133\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 47555924c31f040619681d4a12064790e981db2c7853efa17e4d20f741f33c56d80862caf86bfe0730870b6c0afa9caf66e15047e60256fec29469d1760d5e9b77d79a84fcf7a1dcd0168a59f870f1635eb033e0ae0ac17bdb73da803206d48cfc1da48507cb812bea540daa2393321ccb0d88b57abdbf3a3bb765692a2c2ebe\nA = 754d78d5608fe8c7ed8e26a174fa27833a24c48d23f0e702454b7eb578cb107da537dda11027dd6b41daad329e036794de562d7623bed8d9b0e909cb3fa38d4d21a95c5f4246e0b030a32\nB = 1839baa8b8fb6575832136f1d4632f72f36cdbbdcbd00f197fff3cdb88b851cbd74910ef6d43cfae9d3248e9c85662d7fb596ae45a460feaf308823f06345bc5fae8823230af\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 9b2f026b11d0674e9ec060fdb24b45fceade3070db4405b363d53df1219a02a664882819fe602f430636fc0bda935b14c55c8a0bbcc9b6683417e3ffe7f5d58fae229122ac6e42e76899254295dc5a08ed43c79120a5e5e4124b8fa6048ee90836bd2de51bbd2c6b9b53212e913cde871f11bf32f91b3a78575a006da36627f0\nA = 11402b3b1a45d67cde9730062e38aafe1d04fb1f8bb1975f25cd9098813efa2727cb229adf9490267bd437220d9ffa05bb993e45d2f889f140faed3ac3c7b53216455a830d6edceb02e8db92\nB = -d8e011f18bde068badedce8106f6602429fbcac4766334a0101b57fe94603203a4a8975fa499d8a68198aefd9e68f28e68914f920eea1083e37c67d59476bca9819a8bd628b89c\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 3a74066e7eebd9b63a1dd28548be60573c95f29816f3b3ceef68a5f6bb797d7eb0b0f4ee612dca794ff82f5d7461d995b9dcc09649e2587639ea017865328bb5deef17b5283691724e8aa331d75c635d5e19ebfd268fe5471714aaca8b48aeb846f241c1675e18d35f029b132f81128f19028b0a471b3f75a530321135e35fbc\nA = -6c5dca3fb7b85573d1c8899868940794e428171e207b5f9f89fce4b7159236c0755e2959d870754e902e9c40dc1fddeeff6364f898ec0dd669283e6d26a612d9af3c3ab04468707bb8a7827756\nB = 5446269bbeb613e69286f1012ff62ea767965533624542f3b5c866cfb569d6193aa603061701992cb4873ea8b766606da1b57d7b37cf52f52bf85b58309387200b0ed36164f30d52e\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 2a4e727ac67451ca9dcba648050a085196460e4aa4836c5652de863c3e2a76213e0f590de3aee8639304c54a9dcd5f7d5d3592f647e3d07d322708e1e26329f4a31d66c7f2e9d482f22cd9823074dd57d14040a4f00ac2af9677a2c98d58ee1e094b1a8c40092e77eae454638bc3655e77441d4f218c637f95c147776f5bdac1\nA = -19fa688008a12cae228c6ac4982ecbc88da248d7ec785bf2289dc9103bfa3a91eb1e5fd6afe9e0cc035d3312e9ba64028fa6a229db6d0eaf8af43d8c410be7c689c3e557137ebd60d3fa04edb60cf\nB = -3e8c87fba4a41c3a84874c987acee9f560b9f027338b584a775c1fcabb766700f758c4d451077a9427257334a569037b0bd006375f71223add62eca19b1e26b86dde0cc251e48d3b60ef\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 52e4a3f6892b425b935c6f9d1396d2034eb0331cbc5241e1d745a9619fa0cf0fc521585cb9d6b1034c5fbbbbecdc81c757f768c7a82f6ca291cf5afc98500c579f82ccf0be233066730f738c205c3c188f94b878c11268871ba42a5d950dc8a399887997cef2b6b68badec1ca641b88d1455e6d97a2841da49df7eeb766b7be6\nA = 67df01e34a26e8239c8edc7ddfccc3850f39864ed237d4dd67588efbeaaed1f884105508f69e20ff6a5cfae1516f6179ae6fb515a66ef0a7d633ba4218c30875287ecd0cfeb5bafafc492619942f97a\nB = 19f5076405b3c81519c0863d0c963d545b2834343e42bb3c779788cbb46d89be3f775b62f4114268a0ca0e6af6c0dd659607d40071dfe7f1ad0df9a5c53b741c04612158de396e9c96f7523\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 8ac1d96abd2cbcaa8f7e3267b716f675aebd23694d24c112d202653979636d4d47e27cc36f850355cfc5ca16b78cd1848944f8759fbf6b03fbb7eb347536a9328a5cbb778a6bcd983081374a3f543b1380add14a9468358009ec2baa7ecdf13e7260968eea74083459406e8889936b2fb98c8b9a3597e5f9ca10b76e1dd0337f\nA = 1c9ab23ea37f324544280d176cc02762db7a39935f1ede9695b53a3ee2db49d0485c6a3742a3b5cfb51f3c21711bf89ed05afd0886bbf61cbd57b23439a8a165484ee8e4c0e1c0ca2b6478776aa2897d87\nB = -e30d28dd01655b7a419d939e3e7530258a667420fc759bad585802c63fe5efbb309cb502babdad0afb208aff5ce5830071c5a974604c69ee47f76fd87e2460a5b03a57ef0185881502625886f\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 5df0700adbd880a5730d8c0637a362a9d42c64503c3b9784046b946c2459a619b5bf804a41c92ed6370bba730c7d39fb2e01558f7ec38511b0449d6e9db8df2cece4ed348782ff1582396ca8b3196474e7e5817f8c197c44d771923b6e286e41e7e23c33fcd8765e06793169999544a310f2e080ffe13640b85f21a18fa11928\nA = -5c01fc52e86f3a344180bac284d2376d1bd693f20a46479c77fa57077df62f83b1e81c94e577d1d6733d276f9cf70555b20e3afcb97534e4e0108a6cce87e9292d78b2d7367ff15fb33d2c3289d2a2913b58\nB = 6bbc39283be06382ea91ad6b1630b38f32385ec90019d2ded7ca6fdaa39defbe22585be0df9c0cf613f6f146c71f901adf525336f6573f7f43e661c44b7097f110d4551e8c75449da8fd39201ca0\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 2a01005f1f387c4d8d24a365708e2506b044f86dfc011262",
-    "d3577f7313a8f51ab943037361bed1858e021f8a46491a5c73284c666eb65cea1392a780219f13d7188721d7d4b975272293a5eef63480f30cc9618aa74bc51f4175246301a46fdbd34a6ec72d5974aa920be5f321a97b8f19c0ec56ba10eaf2e61f2b45f134b304\nA = -108bbd8824e8c16b81dfdd4dfee691e012e578cb9cc80cf050c0ec4cebf71a968732da36552979ffaccce6667e46c29144dab75132cb087681d5549dc5508f3719e129553fdc97f545d7ddb7d3a4fc575ea67c5\nB = -2ad4d4078c47a3c8f5f9b48e10d52d72349ecf0f54abc60bad63bbbf4d8efb185de90e5e1a686859e1c429e30977fca492aedbf084019e9ceb4490aa471776ed2e8a09151b37c5caed9ede66922b7ec\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = a1b1b2d33cb610f1b398e03f274ef39a583d13af14b79e6766859b9ca748237b481a3cfd5d490a073e82e3c53d3ff5cb6219b2b2f71927f27ab6f567547a22dd35fb5919e1ed2b6dfae4d536d6d44fa6216d94d26b33f52db06c4ecb29702588b73ebce87569639f786df4fcf569bb07d5379bf8b83743327248c2d71b5dec6a\nA = 5bc53b3895cff2bf7bf10e24fbdc43d17d277a982d5d92f17b9b5a2b9ed8b6104229292ef3997591e2e6a116fca21ad5d061ce438f33b7f7110293770f8313077152c7546cd522ef4054147edbe1878072b1043e6\nB = 1599b541c9809779df3ef40971e7a83f21564bd5d6596d51a3d96defa4dff41e83ca6247969a3dd9a746ab72ce21137f2d7ea015ac6b2ffa8a32997e8b821064d35afde3435b23e47cccafa74d5192535b\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 4fe8897417446c493725521c0ea5b2110f91a1b5ba236cbb6ff3f52b0036a49fc82274ca949ac2b592fa4bcc792114bf2f2a78a2cb44cb22c6fe7e4bee7981604de47f6da2ed1fc6a8eb32cd9b8aaca0f2feec76a2438126ae6f409645d897769a6d340308f82dbc6a98ac059fca6f903c5aecd668fa838b67300c654d4013e3\nA = 1717c6503d069103f10bb4b36427fbdd2371b30793e492e4161fe185b2e27469fef6a25566d6b46f6a7f97446315a22d1f1f662f912b17e71feb2c82411ed7eebb84d4f594deffee14934b75a845d83761f36141ecb7\nB = -8808f540521c20eefaa037fc5da782c891fdfc668b955eaa2e4edb592e027a964b4cfbc94c548d785d92992abe282d90dd137c4d76419926740ce138d567da7350d89f2e56772d8f5bcc9ca8d7076540fab3\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 8b9311808bef497d8a5d14f7d851567a196a051610246964917a1f9d4f4449357d2411ba9fd93983f6edd76b8a8e1501146b08b6e1fcdd97b6a41cf637b6ff0cff7a2d6351aa1ded93f8fc1cedc81879eef751bebfbd1559d5d0320595c79e3eb1db0951d7c67c663bc57a672faed9e14c7da6be6b0c6bcab3d4d515e51a0b5d\nA = -511312fce1849c3d177d42088e55d534f9f7096282916e16b041f66ea90e2cccddab5cec0ba8ebf0b047ccce72da349f420cc28ab19bc156c1cccdcf5216f19ea922698127f090e97444751dd58fe7a2c90197a9ab3d35\nB = 6a5cab5e322d5f651f798aebf43a62af772fa2cc379905e72d253c49be8193a07ae6164f21cf08baff906ef800e361e1cdf1604f454483e10c8b2bfdcce77c12b0320dea63f9ac0afbb86115b656d0198aa883f\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 665e16ba6cba87c646637a233ae04805a302ef4a10d79c5b65b146cbab8c9ccd491faa32937d0ee955dff7dd0ea3f79fa43c133021c8680490b91d9c1d8a8102ab709ada7508bd59042940b2bd3a4f8c195f781313e45fa8d3abda1f8e13b35811b638b2ab101d1caaa92188d2b75b2b10d596ab159583135b0d4d15fcd3d882\nA = -1375af024e9974cf8170801f4a709b4e5862ab7d18464077727bfc2581e557cada991e9484a1acf80182458158c44871e67e783f7573f214ee4ea1f1821a65068f2bbbed7575f03a4bba36b0fa8cb6dc58c73b100a6c4a6ce\nB = -2d64b6bd987d496a3c121e89f4b0c88b6ebc6e30fa9d47981b52862551f3b7251a3fc376db0f2d6daab6e6fc5ea8fa10b040d0dce334ee91d8cfa6db9648df907b199bb11b2b5c41c67d72b760c404b0451f70fccf\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 49e9709810d9f3fef159e5cb45211453e7a94878dfdece19af839b89c0e43b226d7cfd46859963c7ccc753350e74c2501131474e3b8e0edcda18583b0392ee15f1dedcb7144000fc7fa7eabcbc83d12983d2ade477b4687d75b723c1a98a951d21b2e8ed95735aaec77e00de288d16422fd259c665a08a34331cb99299ac11e2\nA = 4e550ba2fc2a44452f068860ce2a59230738a7a15f5de0aeb4d15bda8c61ee3003568dc5971e48343d402112d7a86860a7f08f5cdc0de21fb1aa064ee5df26fa23839b5ff6adaf64a4a18c07efb3582c2fc9612d2208fe99f8a\nB = 16f31365545772f276d8ac952506bf4033a884edf1ce583a63d8d9f6809e29d9cce3b3d227f839e6c09b459951465ab4570d2d36127c0f677fc0a63975801896f2fd17887ca16ff7f265e2e7adab1516ce56ee1ee9de1\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 89ca20a3fa109a65b9449edcc729fe97ed45a9bd69eeb31d4a566ec1787b24cb7a2c25b3f89b36fef1cb3645b17c69ac8ae243cdba35e17f5738b35278478bcc391add0b5ec42db9ec1eeffa63a3ecd2ac0338db57cde9d2eb9ca4bb1df84f1a62245c4e585c4f20f26c98fa1957df34409a99a18bb442ac14f0bd309266a35a\nA = 1fd8a096be30e4435ce8cc604ded337a3d9d2fbc9666d1893c38546c4e155315b536d1bc323c1e7be162bb0fcd58440915b053ca0d0896e99265241f2afd46605a2a7486e1394a07b23f3382cd190e943e596c747b6529b04bdb13\nB = -a3960a51af5ecaaa70146ce55d639005e9b6b9b58592441d5876fa71470ade6d1e2cdde17bb80532551bee0dbbb71a0cb24dc8a129c1f6e28920055d87e9c66be27fc4b425737f36add7d72e39bc83aabee5534637e2e22\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 654d9c55d4a62976670a5ecac3a6165734a65f1edcc1ca81a8c444dbc98c3409ac8c4f6fbb92f122045fef8b7971a276c7dc4eaba21f7be7495394053d4f9bb14b63fc02c8a55ad8fa9bb9aa26aca5c47968ea1b7646ec606f53606d5529ded83639984683b8a020e8ded4b2d9f668ceadeaa8160245b36a819db14e58cf2bf1\nA = -67abdbc70db183b8c25b0664805ada269922556bf15aa80a47d31f215e216673b8d59edfa10a74f3f09d066055c3b9abd5434ce95eba91dd51576adcfbc7e2556df95fd6642a3b7e0486a635ed5699eb7fb285589c887c8659a2b7db\nB = 6ad3e854ea57aafb8980f1e99ab9cda24f183dbbc513e1fc92d4e239077816843f47927bac28e41d3f31c9ef134b72c09dcf14e2e9677a430d43002ae70c577d9958341243030fe58a800a068d6b01fd377e61844f0d434dfd\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 74bb23f7b0cde7924ee52e58bc0680f151e6898cc1bd4a2eaaa05faf218b419a19ebf85b0219f924a26002f9251b83506684af659e5b680e05138432ba227977f38a479ad9d1f3cf68a86ea214645fc4bd1a032f995307e9c9ee432e816fd852655ef20214e24522c17799ef41d1eebc6e097b9792757f7fc43124c609ef9696\nA = -19d3e6fd6de9092cbea55d65154208a0c93ae409c3ee35569cf774b8c8b7b1c9dfdd52e9f408e14ea3153073ed8d92746474e524a903a45a882fe46af92b033f2c41eacdd7e3c1ff661dcc5349ed6bd1aa845eb1762f27593708aa185c7\nB = -3d466d29e8c0008ee6f402551e3d62fe044787bc9f243db9252ea97da9bb75f5be416def97f13cbb008fee77f2eeda672bccce1f36fbcd26e1f1299619535da0a3fa3ffa0c6fee82a494efd7407cc770cf46ed1b8b143f42790a2\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 197eaeb8221b431d5fed3d701a175abc146a9fedf8060e8e611a54f8da2fb27d2fee4539ddce1f3481e6a64435f09a2d5012540d6069900a332461471b22192fb87b63221c7822d3f2fcc35cc38feb6b3e49b5b0fceb52b0ccbdb4e1fd7b0f3eef3d582a6ae194c249ebc52f215b568712b3e50bb8e01c64b114955ebac2da48\nA = 7bd216d",
-    "0acd4ee392258a7341cd56bfb0968492fe75da0c9d935713a6ac883525a4a520b5b7940b05e3f5e0c40372cb11b7ca193e93f0d3883fe5840e66346aff0f38829322bbc1f0a0e63ce5e528ba5b13596ad7ca19d20b2a7c9bea4214\nB = 1ed4805e53630b886cd733e5281f6d2699b3c79da615f4056120165cc63858ed2ddfcfd0af0c5fc54662aad90f26c55dcf70a30d04ce05bdf61028730b900587716e690dc0c6e02419622ab8c115078b92315e7c7a5ffe38c4a404a2\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 40f69f2d1660eeb6e1840164817621dc95eb930875333bc3f62a644ca5910c1080505de0d54fc9fb6404a61bb2c03b3981e558abf9e86f2047c3928599b529ef3d91c7ccd13c1d69431fb9ea3f02b001427cf519d9fd8182219ad904f47b3785fa05ed24cb0ceafd537311633a2e26c27e61be92eefb28a49d7f583cb6e072c2\nA = 155fb75044fc54a6ba6c46972e2f97531861b8d6afbc358db456bac33a44bb0545deea2fc83023c08b7be473eb68accf5b65b3c5d6af88bc6d8ce722c80d5d1527e475905226b01ab9d7b5a6557250cf8be935339db330df2dff92f2e88e80da\nB = -8c6016966a2cdea4b2d8625aa367e1d079638870f1b61e6b3c3a1e6281ece41018d2ce93684d1f0088d021107fb595390664c11435c6c0a7b93c2c6895217a89c469a37d3250dfa457b928ba6119b5c9ca5f2d47b36e60e4325bcb4383\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 9b9e6e1727326fea099eeb008a36539f3d47e3882b77d6089032b99c6cd36ad79fa75b7c19d1509b3ff022ef781b6a8c16fa6881f9ee2c4e00a4dbc93a49829622f4ce6ba9c55639656102d81167ab8a5e1fcf14d71caa60be732f1fbc71250256520c7c5a4579c3fdafc39356a2bbf2c7ecc526dacc0293c7578424c939ab6e\nA = -54cc11ea9806ef27911ba721f19e2ccb111045711d301863792f0cfac798758f0a29111e3a0f84d294a79721067f50858767abf507cc10ec9ea3eb27a91f06e7f6b7b4be7001b548cb7fb734166bad6739935081bdf6d35d58ef56180d377e5fda\nB = 7263e8b9a6f5387f44c55af64b64160efe97ec8a8159e723ca8977bc17c861e22041ea227c9c9bb467faaacfe352b03cc620eceecabb6db2db108b49c69752bd0cc61a5e998ac2f404ad052a51286ccbcfaa214ea8ec14cd9a2a6db56c3d9\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = a18a7498ac9194f600cea3d66615595c27a3efa7ea196ba12a80b5f608f85fa72afc366d23f5ca98452dd190b8f86031a9dc097f94a217b29fa676a6042a3aed2355cc8e767d464a8adb888491c8cb82dbec8f117f57c4a07b41e7e6f6cbd7dc25418603b1d1d865dd2140a649c9d52019ef39dbb6809d1b28b3c1ae64fc6813\nA = -1b663403c73e4a9003467ed12766f16354f79073ce89b66066857d19f3b42791eb360004d23e02874254bc6db54662717739eced153944c4776f334576746c5c4145b21a23caa2b2a137498554c7b749efcaf3393c5457b2bb87ee2ca3bef5f191107\nB = -21d12aad97a5c6e639a2ea0a82b1292aebd418567718014465a22b9ac5c8c927963a2a4530c41d5a7a6c14805e56a7092c8716e4767b54a393d8552c5d3c366b39fb3b8667c60e6075e9293bc938e407c53afdd1174843b76aed187f56bb4be5\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 1983576ed73d4d87d8b94cd3f70c149c0273e966176b85fbbbb7b3202e2c843bf1f8f4546ad7a4916ea4c731a22bd337b6177fcd2da8bd301f3af9bdcad800449b57986e7cbcbc7eb313d6512b2894c0cbb6cd753a870860a49d6a682c20b5e883b8c4839b3321aede51bfc42bca163a924191feaf05e196d8dcb7fdd9941a60\nA = 576759af0f02406e8dafa330babe9473d9d970bf371ceab30d2f98f4470f669e042e1708e2677d52cb9f99deb9b53f30727d16c389bb63e71e923475314b615762c7612269b5ad7bcb5108068bb5159cb8dbb8d08de2bd4fa4d9db6cf6e3f5997b9b416\nB = 1a4e34794747cf4aa626e964b839ac497b1357090ff63088f9fd4399312df894e41b395d17b8ca1806baec6115b1476912ca9c4309f00a46d5f7a52c8f640075422af06d6d6d796359132f4955072ce90e61b40c992a155b2bc31c262e753aa7d00\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 3448648ff9f7425937b6faa54551ce14dd15566e5d41b2bdb1a8db62037459235a5b9546d289cc2295b0ed584fab2e1a798bc25a0c114238f61ad3381a5b441cb67f92cbf66007c980db3351adb9cfd2cfc769b5b9b0bd1701425ce1ee8d4b9f438ce1207fa850aaa1d3d1f970aef874c2b2499a150d29c2ceb7bac375009b77\nA = 1fb54cec882c274b98913e76342a9b8e631bf1d381fd8a4f7e0eaef475642ab3f5da70ca2e38741bd0182a959e5e985f1e0e7d737beb8c725c9b5ea22f7ec25b6e564809601e8405a5b1362e7792791f55ab64a57c03a99a8518d7f65feb0e21be619a6a95\nB = -8180d172d3afe00e0423245f47591d5f750f20d2cedd8ba6ab6f9aa24f74498a96c9001a0124c4f98dbd402b63e71eaa3a7af8b0d2fa417fb1d45f64e10030232b9155169153496aa202745a432e547002954eedda7cc9c1ca76811bd902b192f1a1d\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = ae0fd585408a99643271eef575285a6261a4c4a92c1956b1ab436d3cacc8d4cffc07044e57b357ffa43bfa9aaea57824319579c5c3e2fe4dd48bc818178beb5fc1ed60afa08828657d00bb88894c975378b1dfb452a5b88fc3c1d81099644a998a47a497c8a2b12c444fd2a088f47576b7f4fa40f34a208fbc3348ce33e59150\nA = -7dc7dfb753c0bc3ab4d07d5aa78664a7f57d64be4d4780ea81e3efc967fbf1bd1390248bbe259da32108ad96bd8b39f2c9f118bfdc96bd06147f812af831288bb687e4e1742dcd1dbf2b7adc41afa28d07dfb8df8bb2da5359e66330f5c65964096a96b31dd8\nB = 756f3e407a3ae698f103fa37759e90554f38378a9b8eb38581e0970ec8f9c00f8392612c61aca5fd37d1063b78c19e3109f35c0684ce523c634190b3164ef06959cc42e2b77e1bb2fd50eb59c3dccdb6090beb809ecb0ca30457a5c5948328eb218e219d\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = a2aa4550e855623a8ed488bb63db8fa4ac374c1ae953781aac590f78a364fc33380ca2806445fca5bb9ca2fc7ec4db5819dcd5769e3b746286c49a7c80149e7fe276d095929e2cac6ae57e8102f7d4c96261ca44cb6f1601f429528495b6c3169e15f9babc5be696074d45559d5abdac42393094c450d6a4a45bbf60ed7847da\nA = -16d0aea9c752b2e6e4e13f7ab1f0a2c1776874967b0dfeeef7e00f8d9edd1e11d2aa702be45fffc284c47811c51dcee184a134b8f6d1874026eb51e2ec80c94837af4602cac3efde556ebfff578fcc56c00de99a43638ab68387ec087ee269ca64233eb5b1762ae\nB = -3c6b60b0ce4b13a5d6d9ccd67c76ec6b71b94ea7205e408eea099c7ced2f3a462954741d353d0af850b10ffede8ce0bf80b6893288413674504829793d7ae0cba53b163e3f26cd99beb0a9ad540f6d2cd5097beac604b1694a9a2f4c48b28338f9d6a63e75b\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 8a1a8fcb68c53846b3edae33ec070ef5cdcc1346ab3a98a116344e6d2810e2e3f60f0fe435fe7ff257c7ef4c122b3c34c776f4912a9621b6949308e2cfe2e0827536c7464371ce804bd7cac1d76c5bf8b4a6fd4ed56b65434c3fcf0ac7be543fe2d09ac01c564d7b9b463740dcdfa9068d4d8e33f29297ab452e6ec55c263de\nA = 7c4878334ccd9e20cb11a643b206626ea5d0b20973f18535cd8f0fc2f0325a67d3558e4cc9cceed0d88c6d2215c220b8d0ce230fd701502b02081e3f6548e58e02bc2e79e4991f8ef188a84b0a367758b4e534b72cd87de7f82a26de14fafd162a50b359574812cda\nB = 117d8b1d2a3e2049e6edbb9494c68a97145ac3e658aeaa05e8ecec4b090d5f467cde34e05fa7f5fbfa32f1d9dad70955f22130c358468eb371555fdf57a40e1df398c166a22a9df2e1f4e18590b00856b4f880f6629f1a4296056dc66a29b6f0f25490c6a8209b\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 2cd3de06953acb87b773b8bb28172b24adb283d6adada676f5f4548990827635c5",
-    "1506c85670767828dc5b4b91b45a7ab89a700d70bdba4e0355da32b52c173305767721d18dd2cb6c55f890611e7abc854277a453c7500efc4cd4fb8e6c9bb7a73fe5c77045e715fd35d415b3496f7463ec902cbdc18f9f6f67c33fd78c3210\nA = 1a20ad042f46330df937b879c72ef00dcf39fb85b59186b8e7a9d40723288677ff6ab2b9bce95f34f2de37887c8a9cdcaf231254bd00c7e25b6042695d7dfc05a11765120d1dbce29dc74f35aa1492ba0c5ee65114d9a246b57dcc2eb2ea4a310be98383fb934121db20\nB = -f8ec67323cff9d53499ceb3afd44b28f0538c39dae8c965ea27d645b430c2f8a4965eadc8ed864f2549eb636ec558419be71f986f4c5783d0dd5253738b876d9034735bd13b18fc670438387f84848308d9357ec2aa4f6a453bdd36ff08d54a6800bb41df416b17d\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 1aebe2bc35eb2e449bda63513b1bfb55988cc8e6ec8b3c8fed5ce4dcf53b95f1b438c41e3b2348412b35e1f734edba30273935b03d16efaede429960442a01849c352349e23b4af88de4d01e9ddb53ae900418d49a84b7fadd2669261a574557c4fbd782f8e8f400895f6a6c9679b72983ce01bcfdb641f5067c94694e9eb80\nA = -5f97994c39265b5389526e3847876a10aa3699e3c3762a127d1a9f892180cce68ca6139a6f71b235da26c287bd3e1aaa1436746d983c23c3105c33ed2e06baa1e880f1744d81a80b98ee1f16220940d721a92118a9b949d4da7d1477db8f5b357b3ceb7df34eb5f62078cf\nB = 4bb4f8f4f4c8e63238e8774ed61a7eeafb3fe9a6e19cffa648defe82f4846e3378c892d223957564fcce79596151658a726031a6921cdca0adf0f5325d858c048a6b94312ebfd19b803eefcb93bbfaaddef120ec3b8c366b6d978524d5c74218da77e4c3b5ebbc66cf8\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 5d64678a32c163874d1c81824d628a1051bce3b55c37055acc47a8630d3fee648df5d319e50b4c56f465bbf696433409b89c07e442425d3018a059ec757d77b3a40d516ca3148010036b003721ec9c999665915a3c442d95ec3c01c232feb201be08c88fa3c6b0769e3da30f1d73b66f98e31f4306bf4e23de78e74743b224ab\nA = -178d81e419f0473c426e24428caf25d61b648bbf963f7fb753ae15e5ea3706b53b00bfc8fe917ac9fd6c7096518584566ff71e6d35197f9aa25107a235678cf9ff8ae1501c1d5a15d2a27d39d066e169745e1e8c808209bcede0d732423d0c9cfbea322ba3201ebefc5315c0d\nB = -27ed464895b65d9518923fde5caaac0c72aad0d1b38fcb7827d6ad4e0c8dc09e119b8b98183f0ef8d5d1133f3f108e951caee035bed0d48bbeee6d1ddbff5864bc192b84eb8a500cefd223972ed51c7f720d1736646825f95f2f10ce6ad47a267bdd8c80f65d644df158d7\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 52dfb6bcbbc5cff46942d76ba45301cbff76e9b894703a6a7fd1af29d615336372d147c3932589affe5c6533f28d3e6a57ce2d3cd7448bbd81e09a13266ea31630cf044f654b87ec3fa3294eb65873964110fd42d86e78d128bead5f117cac98145051552cc3a86c193d738b973f866d068a8994a49df3fc7c7314fbd9805e80\nA = 797c67ebdc083f3c8b3ddf9847b7f3c2a39e35ce2119f746ec87fd5d86671d8fcf2b4f6d440c43e93f45019032e629879799eb58adea729d43d2e40ede6485143bd35979609a12faae7e4393879c40c0511c886c66a24454e4f9912bea944eaa417c9942f09ddfb227feb14e4b4\nB = 1a599d1cd0ab3614f50b71b93c999942bd3d4cbfe7900122d5083151c71d9e0c299bd927095c5c3291418424a7c12947389bd4e0a3c2fdf67b3f512094ec0ce5b52695e527de2b3804dca2edaeb1ea4b487911053272ea926cf2fb3386dc4b1dc268b808bbcf4eaedd21168ca\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 99bb9082e4537426c61f3b813f8c97675c44ba9ca418960ca6e2464cf61ad4eabb01ba00798463567ed3d829d3f14201c740f19fca623b1e9b57b534a65df0f070a2130489afae89b91003cee432fab11426c4d13b7721e6f9db1bbaf0adc0064b33e4b9f4b795511a0744b52f93e3db7bc9c0a991e4e122c463ff344fe14cba\nA = 187a8144a0045a92dcad94f0bae7285309ec8fac7dc864b08914e5a4dc3b1a6bb9212161a18c22682ace16a4bf3c03dbaef088b09844902a3255fd6adc0b7c6397dda86d6ab67204d8061c36ca20fd4bb348202037b249f6c110c31580148db46dc5b1bfffa38a683a27054c35326b\nB = -e93ff16817b725016279a32dac247961ae9bb00af890fb49c4fd8cf5e815cf98b58cfa1e3735095e6034c9a2f2b5d8030ab30e2271abb45b347d755cd9ab5ab5ce37950380cb306bbec42b6b8056793a0955bcaeb23e2d6a9548684030566eca2d34c458f224c8e337cb8e3c252\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 631f53d02c031f592b3dfaeed106160488c08e0672083ff195b22a2c0b006f11165a245acad6f35dfb15a871a9a2b45c544111f71f86c920b42fdb6551e56c55199e6173c00e27c9f47256349a80236bcfd3acd1730f823031ff9ef594725cb9429ea183a7fb2e03124ebdd98d435313e43819d995c4fe81fdd4ba718aeade94\nA = -72e20f1aa2b5f2c4218fb9e11ced3f45a218f4c83a2017d97d0cfbbf227c9082cd43f939c8909e52c8795cfaa75d80392d3649dd85ddc35bf1cc54ba389bed9e9dcf867da1c05eda080274beb6b868b54fc85e12ae127dcbfffeb043f9d59333d0ab3374c24971e1bc7269450b418c8b\nB = 61cb021a3a957703d14061c21d3b0fc19598e19a17df9d6f2418c76d4d37b3f62bd4037aeeb1eda37f83df44c440f5e49924cc72ec5b153856c6b621350ec89d98859d9d1ec7ac4f0c418c6599674322e7d618c5ca588d5a873d5af356d4771c6cd375f5dbbbc69f50b982b8c4d1ec\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 4654a62d9491f28599a976288cd2068d8e3228da12f645413a92f482efc66d1737495cd4a4c733f147eb5414a2ef6266a116ce264491a3463c9df1b030d83b315f76f3bef8cbccb5c538478a65092547b91e991e6be91ce4549c3a6e34aa7b466e63eb3b88054f6714083695c616a078ed54e1ae46e00f3593af845fcd0ff51a\nA = -1a342c154aad619e567fd32e7053aef8d98335a4fa0e35bf06acd7998c43d821de1076dc1fb67dfa1156d7ff30203ec736384a9aa7f5f08cfb302eb3a2a7179b2664094c2cc0df73fa05bf2af24a62b8e394fc76014dd83b434df26f8a67a624884a0b9b4f08f33e9828ae64f5d0c8cdc2b\nB = -2c57e15889c3dc9c94361c17585d506933a72fa954ce44dda9f5e33408552ebf49cae87bd0be35197f887fc6c7deca1452a4345eb67d19bd2e7d3dcf651667a8900388e4d5ec71e9433e3b01d2b3d91bb94d0fc3c51c70793f978e4b5ef93a9c6356c0b2f7accb9e4eb457a2174b50dc6\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 6124d9ce4de2880ae3811836235d6d89a1a4b710f1d5a517153ed7729dfb5b56b0ac10a4bbc811db9b26465f03cda355701f9f28c5257fe288743cc0789cc54a8661f46e36eec357580b00a84f1d4c8e3d689bbc18242f1cac30a87cb7a47ea06f80d7c5633cde4c8cd8a1a7e27acdc3a2aacd608cce9e2efe7864d41a56ceb8\nA = 7b48a9663d914e0225d7275e965d866ee6649d7267474d5336d28d54027ffe8572f4aa26230dc7abe9957d211e6c2c8f3185cae962b878cfdfaaf6cfe32058c299247f372ae170a1f7cf71380787f6e90995da9ca5a4be8ab1ddfa8e6e5dc65b6f168b9b8e29e0257e0eec853a6e1911b1afa\nB = 1fc4dc77f4a18d4406a4ba536e500aff68d133c6e7725717ae6537b527c6f40f93202a2292522fe7d04e0ef804d1a7013b04cd3d88462fba31534770b56d2e5672e8a6ec7a723186024c40b4717defd1433b9967bd692ef81d5d4e39ba10a3223d250ab6e71d5d253dd0a732ed386ad57e54\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 6443de73e1c826c90aa36fd7ec5d0c3324c42058b1c35d3adeda1685470d363732d23cceb08c3f973034c24fe65506bd33dc45d7d617a53048dcc103d3d1b4fd0534586c2fb7489ff5ffb98303bb068fc14b1bb6bb43f763dca2c891095e613bb7b6920163aa6cbce8cd93d9d39f4512b6e0b28d361ae11cf76037eab4cbc819\nA = 13f739846ed2c3aa0a1923168cbb46f4f0a2f3942ba57bfa5c426cb4d4b3d80d9530405a31bda329a1814c560d54defa3e03fc4f808606a598607783d539dbb1338d5bc0c2e272a7ff6ee6f93e1665d6f5a0ade30308fa047d",
-    "b086646c763106cb875e014e2c18ff8837e4d4d86861b85a5b7197\nB = -ba019333046f76325fa9f258006a7c10d27e89f6d482b95c79296c07a65b8e3bff4a9c9fa7e5d0038da129390ac851f8c0651dcf655a3d4164a731cd20a701895c12a906c732906038a8e459aaeb293fda21346964a6d53fa3e370ebf43c7ec8f66229405095c6a509d0fa15dcf45de8d0e901\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = d3a6fdf4a26993edd175de9a0f012e1eb15a5a1c4dd2741dfc6d0f9177cd5645508b8ab09c7fb34066ba893c38144c7f2ecadfc2b0d15728b407e5db4fcbbaf1871580426400433f14dceac43d28f03376e791b7ad01a112981f29ff4b66102305f0ecc4fd134c2cdc79a5e9d9f085bfcb7e6c187980e68b6c7639c12e8d200\nA = -464cb16fdd395e32fdc613c63ab4768f8cf72a5b74a0a5b0cc581ee4aad1972cd97db7966d3124e30c9a1c80d85c46da2d36eecd7c3bba5866f9eab4d0fa55b2d440a311654466432c681372a80a7896c9163c12314ac51f652aad68fd9012dc63fae6c7673c5da8faafcfa1b4ed5550f2baede5cc\nB = 40389ba4d2f5fc152308c9e8a8c36258c770fb2d03e6189b96c4f8dee97ccbe426cc14595c8482e9e22486b61fc570f0e7aeddad2f4e3a480d4b75d14294a3b912928da5692043bd98ab88ece87a9bbd973ec82f990c0ae6091245318c2810187d69c38fa80e835300ed06c0723fe475f3fb22de6\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 8a0f9eff3a210912828fd7b5f2d72479cc9ccdcfd3e8d21739e301de02dd5c257c7ce4bee2def06c9d0c90d5a86bc45fa9f31e456d353775916b3d5684759e4500f99ca1f91f6767a5e2f4b735ae4b756d56c358a06447fa2c2ccf0ce667be4ed143e9e1dc627a561d92ae53a62477270a7944482cbf671138bd2a85fce92b08\nA = -1da555639228fc6ead68049d836d60a4927ee77472fa0ffd3c787d55b6067012560f5b1c2ef8bbf6119345dc6419444c675c1c9cd50602a93ba3718a5b3e1a30bc108d796998b24474cdad19bc2960b295fee97e03f2ca7589a3daf35bd28eb37a67b5d2cb35a30998d5f8622bd7e6b7d3fddd1ae9670\nB = -291fea1ae6dd1c66c62ae3a3d22904f4b4adb2a48cb795d50074095345d661a033f67b20c5d7231236dab871892deaa9458c235c342bc81457cca3f014a75f5124ff4da005dcc1108e75527528e5cc9c051a97fc6cd202bb9166f9e72e366bdd77c965a70592e5684fcaaf2e03421a2025ca190fe158\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 50f4d25875150bab63e4162265a632109d6b4743f9d6b55306858034732a4895ffb3720286acceff287c38320ee9945dcd0a1bbe5ae1456b7f36337cb7d22b679a6821a450765471257d52b6ab7d59a763e75e9e64581a93aa54761f6a760866d6baf186cdf4ad2b1a6af26a3e76cdc261d1f07b0a7122c8ffdef595812e7208\nA = 78a1609a7f08c93c9bf9090ca7c93459aef815719b5dde5f217567a9f68ceca05594f6ab17a4666ce1c0c4434e0f4f38ca1f33e501d6958a10da47211cc011da219d4373d2bec4b7c6477b1ab3b00b6c45279212db39bcc11d1e7ba49916c4271adca7eea531adad509ae119348f374ef1203c5af8bc019\nB = 152b46095d3f8db5e6e1a9e3f35c085da00e52764b261c3aa775ecfcd38572d2e86bab2f4bf29c2de4fd2fb6f35f66e8685714634e1be980773526bdbf9c43b1335c5d59f4dffe1a1fe2495ff9b7a3fae3e53e7c3208968e1ad1dd1dc8cf2e2415cc76dfe5df9e2e1eb63f7c7687d539706502d56247728\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 5a3ad8d6f1b0763b77f5d40169ff0013de638b459e401f50f4cfb505565c8a4465e28ca1bf988071701dbf52ac456e01e170788ebd2b7cccb50dbfe1a65a89a8aee18b3c11986c9d6e6571f964f376f322e10a1ddd9310bbb40f14b0680385c40975aba43153970237c535c6b0e2cbf6bec918a8fa26cb2f69e98d77215c23a6\nA = 1d5c14b0b51cf31e9d97b7c49cd26097d40454978663f8a74095fcbf9c63e533708befb1a467f94cf599a41220ce13493a273fc30c49275412c5205db712d5e1832b39e65c150c3a4b251e2aab853e4ecb4f00ee5ce6982ef9215775a33565bde3ddbd932665aae506941d3ee31b3f9e4ffc0651f1fb4a5c6d\nB = -93cae5dd84584a2a3d88028d6d4cec4146cc5e350b4d92c52ba2393ab69fc1dba96e244f98e2f93f31230904169641aff30dfbdd3dc5fb1f3489d63aae1efd29335345a79ded546e42f2ee4a70ed932699fad17a771ba65fe6e689664bdd1135219aaa905c962d39531eba3e82c3425c24041e17858cbbcf2\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 61211c706730a1b98c628b3c8cb070a42e2ccf9fc6302bb1c2960fb165087f210e9d93416ad9fa21634a05dd0723cc23b8d2a846ab7c3bc402999138433725e737102094db5792249b4b5b1514a416b80c804ecfb04653c5ab18b0a34d8777f6c2955ac66fef62c9ec2819f0e3c075920f951f86b32e02bc43239d9218580067\nA = -46c8c68f492d8f7ac7834f89bc76098146432c59b3301d4eb70d9861a6e24c7c9073f910108c7b35538a79de10640291b54e5755359baf47482b97af56475211573576e9412ee017dcf961a090a6ffb5cd995992ab68e3fe60b6186f7595bd9b8acf8695c4f7359cb2ac709f032fb993d16a74822b4935536453\nB = 46953f424d988fd20700ea08880e7e09ac22d60cfc294bd4aefe637408a3cacfcd0ea6822a679b68b665d6bebed3506d25edc83cc7154b83e22953f9d91157cebd219cd5177fede28c63a15710d0f92bd9e542a7586855bbe57a94c520408fc920b3f8d65b194af2b2a580c90db1cdb27ec26ba929de4573c6eb\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 50a063fff02f2cdc68edccc23976f4b3db99641073c85709626292b9475b9a988fb8509a6223f0a517dbae0cf7cd39dcf1e8ae75196d9f5008c661d8b5153cbdb9520c71068e4719820bffda4c393032edabacf99339e0cbafddb6042ef887b8c498e87e16b62417934015172e63e7457242b864a47aa10e203f47320f03c0e5\nA = -1740e8be7b4775725516d37ba643fc64203f3a61e6b0164d112af56666ad97afb0059c2c4981fa81d72264f8669db4e50e11865907655b1f669c88f5935cacf1b12c1db63cc84507af12cf0210f990994055d04d93f148f213e3d4fdcfe9dc42117c059897697914e3e3fa8fdbf0eebbbb9c3b9fdaa7efa0c9d5c93\nB = -226308f8fbb35b5f9d129c0f6a2bd3e5c272a408bf32020905acc6d02d7e506191e76a3a2ac47cf7a63e6306b256f489ca5cdf76c7c3eede175ee4a7acedf922955e92599647b69d463cc14f2b178b88cd471b8a1c1512caa66b6d5fd8840b98b8d070e6593136e98cce9643e006b714388768920a79944be36624f\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 747cba0d1cde75dfcc0b2af9072c5027986b3e3917845870c73c452858ba21d6d1615eb71ae1b5a03ca44e22845d5432b368541b52a4bb02498668e8b99dfa2eb90ec1948d90564e6ebc388ee9816e329e1d8da0d3e2b12d901d47e22e8a1fabc37408be0f89e7a4ab0f30a03f7e2ed817006809e69c21104d0efe548165f64c\nA = 5fa76e37aaf0eb3d34d4f4c590e02b6c63fc62b1d4c9e172cb0dd82409df87ecb43a1680a2764f62d13a5e919db2db08feaf98d5cb92a859dd42bca1047ff57b8fe5974fb3ac11ba2c0d8e2203750f30650db4b2cbd31d07fe18c4df84a0dfdb30f9e528932c097e89d8f8be6ff029dd970a7d2c2551529455b9131e7\nB = 111199f91b3749f8cecfe90e9b9b6951472cb701beb39d63068c064cbb2a1e1d30736026f781836a52ad0d828be6c20303c6c0bd03ad664dbf6044a5bfb67fc20a049fd37c62ab0795d836487b883768ef7c8f427eb98e5ab6621fece77b4955822f8efd190c417ced398c221215b50e9532a869eceeb605fa1c936554\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 646cdb3ed472a7b4599f02329054846a8da173000eee7533240ade4dba82ee3d7a6a92baa3783c19dbd3f76fce6b5bdd83f1f229b1c71a6faa18602e368f1b0b9f8c62bd8c854844af85c2081924c9a153e27853b2a48147950fb614028e090e2198e613631c95e565c2b9b64a43237fd4052089f9d1dd2c00525dd35fa946ca\nA = 1c8438247c0ca376f508ccef7933724df512f9e0877596f7f4ea73dcd824809bbc472749833b537eec01ab23656e9758da22ab8a4aaca1aab3fe8d2cffa6672ca0c44ac029c2ca6c3e71780c28c31b5f154c8dee782f6ba009a69d83b1a3a03a2d6275bb8bc3932a1170470",
-    "fb7e405ae081f4770b535edf49f73a12ba589\nB = -e365c8edbca8dcc4cc11986a5a901e4ed0adbe89b0ab70a53aaf5821862432a1320cf1850b515177b630e12692cb025e3aa43e9acee0d8ad5e48bb15e9a3f34cbfd39d285127b52dde58751f572ae68ad98692899ab12d35e33652c4426ec60c5029e51f7e32ec3d2031032aa7b6b2b63f84fb0023c81d031773f3652cd6\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 7a3e22f4a3f7ae7512ed73a07abb5ce291bc90bad507a5ccc0c17185804b9d231b0ae2e72bf270dbd60170f34b240f716529a449abea0b3d98ea2890a4ce3d9e2214819aefd070e00201e9f271de925c4ba59651e55174c97a13a30197e46997c6c2b152548111aa98df120a617c54b71f8eb8b0c8b4dbd5251f5509fdb8a1a8\nA = -78a99d206b4f095847e9a21de273aa6c47034c9afd4c081a8e93c2d75f4ae5b090921ff5108c863785c413e2f7b4a361506fb66b7561b8b1c5cd537e90274bddaa4e91ce74ad81c6dfbfe1a34a631dbe455d74ed9d041a9183da3bc469bdb214d2ffe893f89c3ae30f8ab99c3aac4d2fe864b891fbf4f537745fddcc60504e\nB = 5c41274e9590c1ea44c113ce505931758f2cef80ba3b10440941ec9aa2ac984b29868bece2922eaa225555dde84a8334f1caede99091165151a39538e5b7390e81df757f521236314239c213e9b874e396a022f04629c09bfaf929a0e9fe0b0c7386b0541446f6a2570491067f64e662d8611c4fd6d1c78a9f3ae69f34d14fc\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 7fd27b6549494c9bc860146a3e8ceee785ca03faa94b0ce0a964844e7871e813414cf3f111da49fed1ede5e71e5539f34173d41f9a17ed129016bb9b04c86487f5def9fe350fd4dffc67b6e181e3cb26378ea15ff9b9ebdf1fc86c072c82ecd8bcdc241301daf1b774af5f90f37e45e6126c5da7dd3753a1e5b366038af6ae31\nA = -1930548d105661dc25a5ee303b61b559c4bc1f2e28b2c40cf3e25f98dfe01a7dcca0f3dead6463b55a5b2e0440a651cc9e08e125535e081c742bb3b2f8955ae897909cfca683a4822896d8a4a7073c29a80571445c6a0d53d2efe4a30a79d2fb5d08c0f95b735a1cab17ba40d71b054c9270ba6bc870e58591fb1bf9dc9b7ee8f\nB = -3e2a4c1509494f94406e3843c9446edaf0a6060144637234c6d9ce84d70fac54ed163d77d210bf557bbea0404922c8aebec67a0475a3c7b74bfa2f226403ce987c705c712bb8eb0934c2b390a173c3836378fe71a6939e48d187b27cc7236ac115309fbeabd9ffd0396fb7fcd6d46a1dc683606c757ddc3212f5d2ff3f2e450fc7\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 2078bb5c82a394c30a287aedcfdc5271eb3246be05954181ae4f86ad2880ce674640ecd55c2ee3f4e89e2762139586516a28558481303e3071cc9ccb9a538f887553bf5726f3849fc41ab027fb1c680ce7dee3982587ec71b3760e5da6956d6894ad8c4526d8de953c0e681ecd44883a21f0abef1544fe601743efd3e5eadb8e\nA = 40b4ba1e977825b7accb941fe0c0a49936a8a47429dfff53502fc0680d705b9fa0efe003eea3ff0b649998fdbae8d0831bea7f34159aa4c7add6bc7cd56fea97d25fb9a6a10f4572c26d792b76c18ada19b0ba06b6142c420dbb40d66be669b7c51d8cd2a5022fe1a8aef7b60965c0176eee69c32ca5023782c5410adc1b15dbdc7\nB = 1bb2f18d7c8d306bf80ae1901115c8dc3d286baf537b812ce06d6872b61e5bd44f3c53d7f31ca8461b3628b255f85338cc325856fda5a6248b7c476532c1bcdf9713dff9932a50e52a9441aff96092d3fb0fd76046a8d88288d0cd55741083a1bdb20fc6e9c20e82490273354bd826bfe001322dde9a15763f2c0e6ffd2cf60019aea\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = ef21dcee9eadceaeab13287d6e3c9741811f6ea9d5bd111799ae05260b1de2ffbc192818fa45dd7befc3baf6840e3b9d24cecbcb2cb1c3d653c4aec6531b941d926fb6692f548cf81526acd0b6b0289d70dd11ba50ca8de6e174f502eddf47e57440142c7f74f594a9abcb48ce1873df057b132ccce8b364de3edf411089d28\nA = 19d0109e0c47ad45f57b8bb8519265a4390534d2ea07f969d84ad33556518b6234d40d1631be3c3cce6d59b7be14750aed114008458f50a6a84ff75b4ee7e4b826ddcb2d2293842ed29e4e484260a92199c5c66367c402bdff0f1a8057127c6ffe452498bb352802e0005e6cb084663bcfa82783a3d72f3a2a341b8075983892e86756\nB = -81fce71491eda139ed996f6a289dde8635a3a257ad6756e844c768e66746011fd797658184fb44b0e3f3c5600c56238ac7687b5be42529d5c9b97c3ce10f3219e1e451bb2dfbbb44cae0828ef894eff3b52b8dba4c115c3b471984441045f2c2db426cf5f86949d5bb7662cd40bb3b3172a19ca3fb6858315d688f13c17550e700cd5dc\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 8a5f90344071790373044193cc4fd92116248aacf05ce639b6aac4461ec3ccb0805ff9876ef44fa71088c295db14fc820f7ae2c0aeeffca055f8f7238c6c90db706d02f2cc43b4960abe3ca4b6dec8bba55327b958e75c60c5d1f43fcf9136f12481c267481a725eecc403a16aa6221346df680560ff316a63ec8b51dc37aad6\nA = -7a54e7ca04b9a22e2b986e72e634317ffa20f6f4ee90353d559db3f3c1bc6b3b92ac6b364f6c5929090373962b49b59cb5d87554387761164982955470cb45dd00c4a8982dbaae3a1ffe700e8903a4a8e4a21eff9d00fa496d475e0e1a205be267499dacecd31551f8a9d437f37dacfdf5a2754f0876a3e02509b78674e7ea2169c43f29\nB = 652001f073d63ddd526abc957bbb48ca74154c8f9698b988178b3313dcde9acbb19ea11a935184fcbcc31e0117d8d2ec695ac56b5a71614a12cf90f21c8882187428755b6a5f11c314ac8b952ced0f65db0987f0f87e20b82a811599f4160e65c7418af7f33604e7b8952b70581e3e02dafa025cecda970d04383ee552abc620dfb9c5df9a\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 67f903e0e5623258826b681506f3e94cc0b086e262bafaa1395294aefc9f6b6323410a44427010d5e8d8288993973ad9939199b85cf02ae0a09dfb69801536a3fa6af5ac373add7efd25ba5fee6d8f040e97056f9f6fbb45795c0bac94c51ffeaf496710b00bc9ddd8e445261d976168771060c9bd9d83838a84ee9428f59d6f\nA = -19c695ee3a4ada840a7e3626e61047c5081867b15843ee9a6506ce45540d23ad25ff23b72f988bf26ab8b98363d9a2997773604f43fa732f59a4b16ddf3a45acdbc7976a1fce01b3dd55559c20acfbb7501730f794bc45fc09b1f035d60413bbcf32a83fd3c41599049a674f165ac5283c42aef213d777ae47eea960f7727f5758146efe5bf\nB = -210697d47beb73f45207340a183a729a1e78d84bdde1c7d8f80bc84559c4aa4572ab0e6927ea175acc7a268d05616201cb235e610d1012500c8ba9351a37bd68b4ec42227bea55cef5ba7d12ffb180873ab9d33d09e6e969df99fca728dc12dda6903169acbad38388fa9b001edb09056a2ee2aecfab0468822bca14a4bcdd3a4122290ec5ce1\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 5fbaff0ffcfb2330283fe59611ef51cf045bc2690e31f2ad3265046fedaa990b5d5060b3c38f17bbe8b2696e527fd77ead8650d329c2e0c1f3b2f5bec4dd85641022f3e0ae6f66ce98cde1a785bb52eca796ae45c33142e8264621ab447cafe988de926544e1a7036710128c42fe8b574f7ad69d830894237d95a55d1bc7f5ec\nA = 482db04e35f9fc1d87b42bc5efe25a049ed924f816e1b0f9c8ebe34bc771e67e26d6057563fd5d5320681e1207c0b0f4b7df547cd6d5be6a2e0f2bfb088f990b0303d0ef263cf45681e0e9a1147c29f2ca5251faa633ca53f6e0b109ba69bbe20c58a76a22789243d1acf128dcc936602e832a20a2bfbfedf963bc1027650f483814d7f5e6905\nB = 105aaf563d4c1d436c6a4552770a527776f40bbb844b7701313c5ada95180160e7cd4b7175ddb943e5a22c910585dfc184b52935f06b12c84b6431395f28af2eb9ccfa66b2ee8f40fd44d753c6a83d67a6f3fe3658fecc7fb2f4a8f357c5d244422e48a33d0e2971059695a59d0d39b235d5194e919facbae7623ffc92d771532b6b0cf771912c24\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = a9d204c1a497f350fa1300cbaf682c947eaeba8b3aa0450c1db9120852a2edd2a0249dedef3b3746298ee42834d869e9f765ce987a2aa4712a1f35ed10d0f7ba9cdef938b073c3a526e5bf45f3510c94ff1fb84bc77b08e2a",
-    "a50f5cc75e2f4da37a8a711f8aed5e92f7e486877229cb4ff2a4d0755029972323c0b51a14fd1e5\nA = 13fd3d7cc9d6d6821d2f2b1c40c8e070bfa85b994ee8f3e0baab544dc71328a1a57b7ee57392ab6d24bd85f9ea0f2a312148fc4f4b22c589e9a265d97e73c7a5b420bee180409ec179c438a67abf37eba61ac76197f3c9ea5edf2d4b8aab91e9bb1a432ef1f214c043664a51ceed1f2854880dd458ca253f09d6f6acafafec310774a672d07147b1\nB = -8c90ecd56d6c7cb129d1c9c26e94cf919c5747450542cab52281d11d8fbfcf9ea797b29588340d146cc40e77dce007b68c0c24356d4b75513b75eccbef6e22a5b88417cb6c516578d17d871e7d0957c09795f9a0f19b811db75d61c27e1827fa2773846857fec020f98444e307d3e52af501114b962ea705cb0cdf815109054abd00810dcc270d7bd3\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 57aef35a3f5388c810f576dbc30d4e4e5a39248b319b7766311157179d8bc1d7ef019cdd8c2c0175a8424abe7b33565afc0128724fa38f0900140b6f96bda2e78d7c803124cec8c2f2d6649afde4030c76cd33394fb386342d1ce97a4ecd180872134fd4e22667a687915bb4fda21f7e0bc9100ed8cd3a6668ed3a235d7b15a8\nA = -673bb11795d9d20a1e4ce8ae71d041705990463964505befce5949f895fa31c92d53f91fbc110df4e789b3f3f01f184c55df92927b8b680cc92864466ce5590ed2e98901cfb78b32ea79bf68b57a14cddb53209e08a7f430fee23f4a1475fd2640a515f8b609e98c760b4301747ecb61f1e6209b07455f1c8a7bb4e20c269e17937f39c6a2fb7b2990\nB = 46beea6005cf96a2acb16f37e357bc8975f4dad502fc3aefb4666344dde456c0ee7ea43ec493b6aecbc7aecc7d4cd107aa09e874ff564f5d59d7e12047b048c1da1faea36a7e2d02d0567bc4db41b54a75110626d13597db698fffd577a5810286ea8bf50625296ee8070419345fa269a354ca2eb47fa3108387f6a4b2c0ea3e779908a14469106eefc14\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 5cdb7c451b2950c9d87638857407276959142958b06241b2010a9f93625f9106f065798f79ce5c534b9e5a31fbcbfc63cd200fc1cf10217096aa0194acb9043ccf7ced30d9f0bf66e0dfe27ee2ecc40bcd8de66fe2ed6f8cb0d874ff7b5fe71951412731fe4e19c34bee64c9312577b9e7b2ac08ed15aea753a6cd3e286192ec\nA = -1eee9d5d3854db52f9b43698e05d6a0f1d1f8df5f32884a775b25110309c46ec5c7e112eb64b2d7f948868bb9670068779b0a78bfc7e17860ee02692ec6790222b4384b9bd7db5abf29c46261c10d95f503b821a4694c45553e0dbaaa977892b916cb8990ac9ec29ab5c3d63ed77138fa1e95f395b3b233d039ab5daecb0296203166e9386d1071c61cb1\nB = -34587c2bf3473a2c5d7f3399d5ba2bb09be8105a0b9f3d8737d67b03d8b91b1c869f4e223d6246abd36d99d84052ae5894e58288a614a0da8d69f1aa57428632c2b059ba99315ea2f68ee210e65a741e94125ee4a723a7828bcc410aa2dae06ea8ed6cd23f66ccca7e85d2e071055787f230ee405e50d1519377cfe0cab4e5f97b6cb893b01134813a7c2c6c\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 95d0b209654de56bd7d6f74afaabed2cbb3247f449d80511d2d3c689f84c9b79587d78abdf0eb37f1b89f1f8dc8a83f7f9fac2c8cda1fd3fd64e16f5597b7f0a1df6da6db9e828ce7be0e876012bd52f5a74ca73ff8ca4611dd9f342bf77b485305ac28a1f8ac7538169f2bf3e4ff4dc5fdb9dedb97fa743fd8ac8791b8e288a\nA = 7821d4b65d529c30b8747e184e450cefb11b5ac5dc77905e6fcd3df64336661c82ea68d588ba616d23df485ff0658fb3376d5276027a40b392f47219edc5ecbf510cf0c5b431b02c65e5f432092f941d32ac5f71ce3496e403c7637f63a23b91e3326d01d2d32e99e0ab265108dc5e7919d3983839b3c7541848dbcd420a594e850e587f1846951852ed76d\nB = 1adf5c428f2a95c27a943637758d5dcd7ca36592fcb9d52ac0b7d27adddad5804e3edef257aa51c716801ad0c731e13c5dd000f11b5ff1b69c198f236695c1b2f99c0afffb5d084f80fdc534de3b0df4597404b50c7e784c3c55dfc9753c414d145eb0ca4d07e2f65b63f3eef8d391250a5500ef64d9bf963d7250d6906694e7670f92e3d5a7930f0f85964a21a\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 46914b197b84fa99addeaf55dd803182083a7ae34d6d4d3a55d6272af40a600563cc8d9f6b48110d0521b8b99751235bd5a340b1743497ef1cc459dccf5d6da970c4c3103c978ad2d513298f1fb3e68b24a9c7b0795f47d8f7f6ca9caaab9a9d80f15982599d764f8738217f9158517806fded5f3552fef8b7dcd2e725ee04d5\nA = 1c9f5f2a0d72806dcca92dac1450a50cba05b5dd571c2b3b988d33528d90ecc83444e3ea8df80802c30fbd5a6ec2ad9969be73aba6dd27e0dd2c842b95371d7547768916c0cb036964d041284cd323c8073095b2a8cb8797add5cd80f03595de9d18af8df7dee0d250ea7048faa47ae0131ba3f350d82864dc95e5829b88eeaf2681433dd4d58b2c6f70426af3\nB = -aa1e1b3cfd5ca0facc75e46d872584d55144620f849ab05931210b4e1526f12679bbd9cf00efdbd8863970e2abe8fc9fa7bbd21afa9e364e3c9e32f51fe66844fea4bab7f3b1bd278fd803f6bdbd0d296321e67751a0b894da338ab431871adf1514269ba05e0cea5558cd5691920fbc18237914f3dbe4b253f774e5dc1dc57023c080a3b90a004b809d237658ca1\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = ada55d93c533716ebd8c16e23603071950aa714deb942ebbf77206753d2676a7aaf61673c03a4db69d67faf6273828594d85e3c8cbf38460fa2af603fe9c1b6ce104854e7281757b26589f079da80685aec153fc5fd1a223004cdf30247f8398b8e92899857dd199d5d5c32412bedbf9d55f20e52895fc1dbd04c84cabfe1264\nA = -7d22392a8da1966e6cc5ef50d7409c614f8c8f8e5791778f68a00b4a056d0002707933043d05e48347bbd4d0dc1b6ca32a1aa4bab9992e7e620263283eb68d97af13b90a29c1b7dce39ec0b8a63878e8d65aebfb3bff4e67129e3b3725f999f1ec9ae92007911f2cdf738499661c5b6c9bf27712d0f29e871b17318e95c3d14b2e472cf9e466bea91fb71a493b2d\nB = 40279eefe59f954aa8c51c9c214fa07707b1d095f697ca40edb820401a45c472d1d7bb413eeddb64c14ce6144b4863fe9337ae4ae8698db92facacd6a56f3b33129c5b608eafa29e9d92dea620113051b926b80b75f320d7ca3d2ab597168c68774e68c47670458f5ef2ffd4604f20bffcc7817eb09c9057fd9989a6786a7e067ebe6724a89e7d1580f94ee4ed502cd4\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 4dcae9def5467526b0ff071003e56f5537852cc0bde9d86eaed2c15e36e6429c68c061e12d321bad12e29626b5013c28f118ee59624ae2f35d2c53bfd89e6afdb6db79f0321ad5c55cab03e6a1a97ff7bd58c760d0e9fd7507de987ed2f94f9c79569fe7f03652cd53c67ebc6bd3c9e6c5672891a9d2ee11b300ed3b19753c0f\nA = -127f5ca6924851faa2340c4c8f425b1dcf41b313c5c2910e5eff8ef2faaeaa43305de2b3a65a75fe54c00fb30c0ce3e8007db1ea222521190ff1de6d0cf2e777ed61ce8211dc167bf115a77890d0bd1ca786e967a04f077c89939ce484bbb1c560f669aacf7756a4338d97cbd7f09a376d2dfd4d632bb451f52c03c05762f050ebbf112f8dc5acdd9b631292fd7073b\nB = -3bc5e9c352c46449a9155b7ce5478c771293599cd2dda58a962010f1f21d094aa6bee03f9311545e8dc6213f6aa73c08b55bcdf4d1d84fecb9eda35c83eae5fedee75b2d15a003f8a82b2b788ea19f7460fdd8f447d973c950b3b250a3022c19ff312ccdc86b6ab50c4ba627b15968c8a66d306bbdae8e88fe28c1853fdfb3fde92353f46b5bc448ae42306a4c91202f03d\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 62a812e35f46e04b3afa7d26c8fd4eb168b6b64cdc839ebd0a46bf2a3a712af8e97380cdf0bfa8a274f7b73e887bb4cc73c6104a176d425aaf5352f14ee51ba549a6926bd8d059b8e3826b174385d4635b0c36df75a4e7da44c34e51eb82322b34ae00e8c712eb75b3882822bce5a2f2f5fd74355319ebe1973284c690bed2af\nA = 71c57b08127a956f0c17fd3c639bd1923ba19bfdb83c0cb9dd78e62b8fe4b7e0019cd0a6b73a334c622118f96fd6d91c1e06d4dcef8a3d0d6bf8f5beb6389226c50d14d3947ce9f24f7e0e6a7befad2e4e92dc9ed8fbb9811d908c03ac074b2a5c67b67831a350c4d548ac70810bb5617d261a045e53cdc48117b9fe86d35950d0a181b73c8cfd35edd31af031178523b\nB = 1cda2a51a707f8c4d2cbff6337c3f63519705614c26a489b545b1faf366b705af1d953701b568a684856fd3186c035f878788f7e5db",
-    "ea16b5e7b6e767cf611452a4272abf2a9c5e72b7251a1ebea5098c60cc5bf649cb70980b97d48580967ffe2913309b6b78cc12d91025ae403928851902dcdaaa60f5b323a1302a5ce114cbe174e3eb3c2fb5eafc44076396c23d53b028d\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = a9213cd809d41b6bbfc2123bb84860788ce22d5b91f8e24fb616efc286a218ae9652b42912a58bf8ce596a1b48e4c72f27e52c36be1940f7d2138eb895ee36bbb917a59f73e0b6c3266bf4759ffe2ffaee3f6179492658e0778bb43c4df4bfa1a46300c9da496033142ae2c1e33333fd7e82c5a14686b255e224c51aecc2a590\nA = 1cf4e2d5924510a5fd06ff4eeb94a740e430613277149993004b8de1a2b96ada54b05365f305e896df5fdffd3d7bcb54f9a9dba9689e5ad498012f7a684d083c31d7017aaaee720bbd42382e526a35d2add21d9369f7faa41dbcfe3dae426948a402635771a977e19d5c353ec7c1abd279975f2effc0b7bc19990154b723f2f8c29e606581ab9d3966702f68d8bb8065e9d8\nB = -cdab60f9b8e1add4c54427b638ec5f76b30654d3649b500f833b2943bf6cd5d8647549657a8ff999eaffe413ed87e06267b97bfc1b77637b57f29039235548a7569fe6d4bb16ae9c6cfd38c0b8c73aa60797d0d69b03d5a98314f7f7ee25df8b896ecdfc782cf8057f038b6c3e79c99df52f839fd4eff302ddd1256e51eb31cee24585782a0439da3db2eee79a58f889d8847fe2\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 4dde3d63aeeee47441a7e733bcccbd4f2e495ca3c746468e9855177f7672d5d82e51da8e268ac24e8971d802e25d842a16a6b8d76b8e46a7724108c02d38a4830453408ca5ced7093676a1db4bf4c94b9b7a9531ab7c26f8de520bafe4431a55a5f5d8c7576427a0f5bf2081b998b82da2e8e959f2ec4d5141b55e40bf6ddeef\nA = -5770ea0a75ff451fc2c86d428f2569884b2c88cb6d9d407cc22b191849d389f57a5765b83adcea21c350b37bc6d750d4859f547da22ea8a3698a5cb6154b946331ae2ca18e7eaace951dcd49405bf8d8a716f7762eb242b8bf5e4c53a662c906c3be89e53ddf7a706ee2406c7d0ac17b54ff259c1bd5a092325938832763ac4caf0232e80a016cd1994441808d8db7e546de3f\nB = 7e4246ad4af268695a51912053ab6628969af4fcaf7f1e97dd977984a1604e8c9fe6b920f39a764c27d89f75986a4bbc122f92ccd1860f24677cf346474fd9441f572f769daf834e6a00cbc027e15d6aa7ec2030becad41e1068740cde82abed768de7e2cfd325848f6063e2186faa76982b9ca73ef22434a28bd2e3a5ac477af50f258140bff938d3fa02fb904a8ee0ef3c1f6fed7\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 3d8bde8d0625fc46dec46fc657c49c8ab12a988cec4ec1c24e6f4d8ff94514c8d8fee4a08399c6bd23fb6464a38bb5f249591456c283325e343cc289c85df0ff2c1707a6e407ff7a24383b66ab603b75e2dc3835ffe9274eafea148f20764b8ca30cbe483c1cefd51f82dfb93d7793b3ec19a57f2ba03d884f345bcc3188fe28\nA = -1680dd51d8be6069c86ae157922d55df3b58ee6f53738677bcf7332d6e7ef304ecc7ff7c5a5e1f525459d77202f3e815c68f17f9a6bf358654a92f9f9acb252ed8e9e6a849da7491f26d0e33900541ab67ce966d042607258b4382b8108729a703b429babc34496528f198a7e0f814db80fad4900fbccdfb64908febf5e09805d3a3049c0f164f0bcdaaa9bbb06df8f05309be83c\nB = -2c6c6b3c89f6e1d1cdd9abd1a9706e4f642a25738aebbc97cbd60e1f4ad79b419dd54bd14f2bd147b1d8e9bfcf92faccee61a43dbd1a2c084bf06a2ca476b3d169fa2c99794fc827b7f4dd010c0534e7cdd03d00456033ae0203b78a7ed229afcec2d1cb96892eb18898bf53584dde56b4316b3bc5186d97e3a9edcd059d7fe14561eefe4881beb8519c1cb7c3ba22cd2e13d874aab77e\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 5b4fbf0445807c8feec7efa3c2bf8dd86b1070638f3c87f1e173ee980412a28847b263a266506e70381aae919ae05d306d3a67a6c1e72c8ccf1c27d6296526e87f0f436c98fd1391f83440b58fadd4fb1905a484bfe8f516661e7176a268660387fe6a7266ef02e5fad91ffa69247bb11cfc1b5c3a88c76b7923a26f8a31ece4\nA = 65fe4d55bfcbba2bbfbdae831aef3dc8c8746e1d04cea174c1d336974d81d026f562225b4a297b1c3b044ccc5dc9c830a805a399bf26c0369b52ab0dd2c0ad19e723fcf9f5de2990ebe5a1266653195a2aefd9a392fd3da8c22c523a362f195babbbf5329018e3b454221b3e77cd0dee79f612f86332b1d104aeae7d8d84ad06b107715bb76bce20220d1340ecfc666b2bfce812814\nB = 12f775dbabf1c112523feab443f6e95d773e8220d66fd87bb7fc702588136a048e17ab6845a9c784dca275cfa445d007e8d8383740b156df7048650f89c5ef1a84148488fc405898f9e326cb8052f626c8881abeb70f3a0f52dd83e3ae0cb82d178cbfe8c393449caa2a87e7c8e2901a87e276b49b6d012f3cbb65641add3694fed3e3177777e78fe375f3a3b378091bb8d2998286562faef\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 4f0af7cb0c4e82d0e6589b24b55528818bf2164d41f58505a2b302a8f677df146f8077945dad3790c323e19b37e3379eb95de8abdadfbe4417f8bf8da643768a622ad4898513fdbc72d3b1d2791ec9ff40634678faf0e17d6e0851f08c39405907db85b74937ac403a9a3a1004013c7bd95a585728010689fcaf63b2031bc8c0\nA = 156dcadeca94985ea8bc0d1378daf1e85ecc4c7f8b6d6c7a5cb9f9ac368a97c07e381004023bc575691c082b5e9e13a02fe813a55e76196e4ad4b0f9b1e089bb71a0d5c94254b66e3e645fea25d69bbc5af266e730482a60105306d664f0ddecbd76d54e7235979aa2d806b809b3468078b5d90aa22cbd2c441198d4a52f6259972cf3d02003dc39dafdf3581638e56d08c5181d36e9e4\nB = -9a54586072d093939ad86df11fcd3337ad7e9e478dcbefb2b89d7555883fe8565abcd5b0a9c88ab135ce5327b2a326db645bc7c0e3ce24f902544675ff9d946abf30302f123aeed0f4e28edc72758ffa760277caaf4817a3ae8615784c81896d2404e2cf47c06b09085cd0ad1ec46cfc1f04d0272eac29e774b30f19939d08c036b185983c93ba15d1d27aebe4a357b9f6a298acca3940d2730\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 7c3ac09486a6fb518b98a9bc8a8b382bf2293e2c1154470ff7961212430fe2dd28697e49256b1ad8add082ee27b6ecc016b120e971665be801b720069d30c0a8c6ea4795613017e8883e5c0d0e68f982c328379d7a0afb7825c553e087b33e9d78f90e0b95a6597076b8ec2c1d375e2143bb778c318ca0680a64072cf9a4fc08\nA = -71d8e7ef13d63b4f417c01ec1241020a8ff4c9b2db531500984fd3e45d22b2bd581894c8a248ed7cc345e70a5698407df8f0e4ac71ed2c0d42122a4f92279346f463aed899253206786928a0eb7c37f2e51e1cde7f97cf9288d85c3ed7f49e62af0bf9abf062d2c6544d83b9d3438b3881e0d07b1fa0f2a4446fd43ab3b4f81fa2cdaff199c87965e298943c68cc15f2f3f3225efad68b73\nB = 64d52de221f102af62ab1e9526935b005c81658f8fefa019bc58e641023fa785798ed0dff8f7f999dbcc2ecfa47d5314ac6676c82170d6f2b18122c17c1e1ec1b9b54e333a184a46ad35b2150c8165f0de19a24b98327715e5a641c1b6d3ff9d247c89c8749e775e6fcf5f967c6eb5e73523d4f1ec12db7321b14398f26201a364e1371f0ac922781ee252c6d2b3c657ef259ab73cb7992a370598\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = cd08b388ffd41d0aa29a3dbde74106c57b18d325be8f446a2d9ae95fa4144037dbd41eccd50fa34096984cb11bce555c117c5568d76a8f79d308ce11043fe2413d37d6aa60c366af6c1da93d525e4b2d79fc82c0a53ed62fbf72c919db8a3ae11f5ff8057d7501f5f6dfc9ae461c308d21919d0de9e31b759d1d8e3526fee58\nA = -12e58708c30c93383cfe6e99ee3c5caf1900a7e610605706e77d8f428fd59db2884f5021d7a382cb18b75ed22528961cf43be1c700c581ceac3877e83eabd860583e6e94f3f2989c179ee5047c82b53d37054c9cb7ae08be60a91b10d49510e9f0b90ddf89f93790c3e18cccad5a9d223c605a6c567550e2b4950e184fd97dd68bf30681d3f9c585365de2cadf36a43f5a5305dae555396dd50\nB = -26ea5079ba7ed137a14d00d413d6f818e911cc183c88764de4d91d7a9b4cc7af3fad703142dc7905992eb8bf489f6d8231bdb25603ddf3c31fda8bd9bc4d78835f9ddc1e6445037f05125cb1ccd92eea2e927297e5eb915d5d965a25e5d58feb8d79a890e6036c80ee91e7469d9eb672d7a8db68905d06f5981fc40bf486575a067d35cf14ceee3ccb79b72871bf8f52b92e4910ab17e5e59ab3ae6f9\nM = ",
-    "b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 34714506322dccb91308c403c267f1ec75f80faf3cc4272dff4a84c13eb1e6133af6681387006c61e7e087046b64e7ae74eea8a3c0564a7c1f381e1c940d92b2c766fffdaa7318d07dbeb877943a73b50517b49e5117778b8a60212284fb92f29a9f5304f8f537e88acf8afaf01fdf64773f988cfa9551d6884baa70587ab76a\nA = 638b7c549ed14256956bad532945ef9e11a50313172965386635a2fc7db79deb0cb5c157e9854117c17f1509d505d01a0e138d2e510dfcca45b4f7ec968b5214a6699b61b8ac68adf64d5394f50d577a154c013612090e2045462160d1f552592197d7da78e03491ae284dc9faf643805f2674af8652bae93ff230fc3eaa833dc62781e5f74d0f0b90290d51d481b0a94ae6e972197c6e84ad7ae\nB = 141f62297ee88ad527fd1e0e09d9ab5dd80e17b32f34a674a27b00d719839701664ccca1b00da2613396cf633b0bdc4482ad3a0c3e209eaea7c22f33706ae44155f527c9ca4e341e651760d1c39f65d5e99e649d013730d2502b6b65adb8a73e6bc734b7d879b430798dcd53fa6c0badd57896cb566d9f1e0a7b3a9161e9808e762ca819330ce9319dbe7f49bd663a9f57ac53d65c6851dc7bc4ee66e08f\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 7adf54c77eaea2a1743bc5011ace45b7651846e77f90402297f117d8b1c0377f93f49e92a2457f3d3debec3022a96c74c166d01b2279553ef518ec0e612bd7b382529184640c55b89255b2679da9cf370913351592de39f804f1724de36db90c045fa644e8ff20627f67d6afd4546f00d7af093f668629f9a06c07fab5654ac8\nA = 19c491d5b55aa25f2e18cfb7fda18ed4b020e3f63244eb9f6c4dfa86eb8a70875cc898e305a7acdd3eee081300edb3e4c837940bbc1927f5ed9f651e46581639e133515457464e9c451390828e5e7e00a688daaea74620363706cb69e02717489ba9ad05774c424c18e295278caf4df4ced80b4cbd20cd631df43f2e16ec0334564d9dc03dfbc7111e4252504fb449d5a25cb13630b7c0c565a82ea9\nB = -c3f765349639beb80f888d9c8b7b335ab46b55064ce2a88180c80ad280c6b7314df52b7e73095dfd82896e24604854a48121353aa1de663eff07882771803010005905896357cd5a56a59f0db0045f1aa2c0b5626e132c169abc64b9893f95932f54c1d8cc25f215a9ef6e4cfdd6dba85f6faefeca81793b2258ae1d1427e81e458482aab87f6563abf435be69a05b195d1eda90146a8cc92748ca6f798b10\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 32ba5fc81a7747c3d812cf036bc0edc49f08824d53b91a65a6d41edfb1651d99c11ccb4c074d7f04e652276ae3fdc8d6eedb72c6e46cbb1f7f4070dc9d179ce3e21a3826f7dd2c27943a8d26b192d7f5c4aee9ba0647e406133e3e89c262d37cf468aa3ab8c5dd1b8900dd06cd600abc6d372d9408497d9e20c86a9a6a4ad9d1\nA = -73958019a5a52357b9c1d954c9b14f51ddaced32a4d7b7c95730697cf90029564118ea168d23a54381f7bbd6718a6b662e4c87410e48ac53b7767148582b0bd6a3d35f488e7fcf2b128e0a58b5d468dedabde4d624f4a82e808dd7b175af0d3658c6df1ac0da6495bc9a8dc012f8de55c2003da9b2d478e1a089fab776d99026684026968fc309dae46a6ef2412039a8207c3084f96b4e38e4fa01d131\nB = 4330fdf00bc6d13ffc267073b68aea7419ebef257d63f8f244accb9ee46edd04fe5481292de69d377ba6b6304804ba7ec0a063b42339e6e37867261b9945ec705d3a0029c6f499420e02a773476546993b3c5e1efc2417f51afcec7145a9c2625496865c11636e285d4c8b053ffe66887333c51a712fe9c8ea57606103fd689dc88f1fe37dbc33ae4e92067c5bf51b53e2f8205164c800e5abd677c73949b00ef\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 69b850a99b471003a56931f7856da357a2254ac50ed81dfae019c9b722b95af16047a0d5422cf7ab66ccd898e85caf0e03e74cc8a5a413661e5da483b3f0363e63a7031bb30626c8f73d6e99e290071094b7fe5bbaf4d303192e59acb5e53fc7cdee78576b51595d9f7a25ccf3c7f8889de68b9deec167778ca27ac9d4c71c3e\nA = -1976b3bbbf92acbfddbc05b5d9e7b62a7666b239c1e6270db7ec6dc2929bad1024e745b897840853d14cd815aabb01aed580e1cc66ce37f9d1cc4c9bef8ddd35d28285faa29f2003d2a4623ead7d73302ea9f380f16b3fc06b7c2b8bb4ce4c8b03bfb6056a61c620e4decc6048cdda5e2d3ed8a13b779b8829e2bbab91e9f6b0304b1c08bf8fd85e0f3cd7ee72255e5342e077ababdbb545d7f809bdf8145\nB = -2cab554f7a5d21c499a1025f61e6c81ab0fc68a874bf60470cfac57425a451365be62c380ddd31f6e202f29769e2b6106868da7c81522e03fa6f0704522a5f8bfadbd007bac65595e149f6c585d7fc022db016bab32819049e7547bf85d4232a7fe19084907c528e7eb0434f2e5a375ad9b7d463821bef2f6a721a635252576c176ba42519bfa5d97d0e47facb4426aea0d755507dac81ccf1537b1003ddbb0727f6\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 2ce33adf34f2249f8a2d2e073976cb4c78b71414e027657fcefd56fceb022a06c1969dfafd519eb9e2542662c7647102f5c528734dd005fca666be57b46234123bc3db286cfce07bcbb399eb6764daf2b9aafbc2898a5ff43ddfae849c7549289640edc4ab7c4b9fcf5e159623e5497f509ad6f0270a41fd864c9437302ce380\nA = 509f5d5b160e923b4fdd72f4d522a713d780daa4bfd10ddbd62b26497a2e7925c495afc2abf0ecfcb7980e588f96c4078bde51c7b2c19d86d15bbdad5de72fec2e0a284dd693ce0902b40e54af87ac5a5df38ae6d1d882ea6299fbe6910121ebfebd06b454ec5f855bf3e7cd544a4b0d9a764428662e824e2a6185723534f5e6ad829734347d240c48c2c0f8bd6be6ae8a495a9e383fbc7402a4096b8c2c214\nB = 1a3b7f55307031609afc974857a6cc75821e73a1a9535bd6b8e141437c3fd4a6871c904e22c5d9289df7525ac69a0341d3620bcfc5f04b38ae540e26beadbce0002a8a8bfd0f6a270007e4c52aec2fab11fb2a831b9886997256e4b7e7ad3b0ec64c0f31fb0d637869143712291f5073a5756466d7c82c31e08e09683478229bccdedc2cabb7e426af9025185d8dd5124e08afa4e981236180e0a390004adb7918de6ba\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = a81fcf9a18ce476a839c896cc5d9b639fb1d74610e2f618c25310147b57cd77806c2aab90be7be4ed10f0122baf9b862b141ee8e4be5e0c23ea776267f14c31e50b119bdd33f2b41f6a4c43d35bf6f095864593e0d8c0f1fd4656d8371af844d197308bbff14e5a28b7181eb6e6a2b31ead7361e287f3b4550ab0484bf7baaac\nA = 19f1ce60ca50bfdf8e02313f1c9a45496720a2ce467f1e8bdedbb32525d762878b61476989c7f6ae8dd29c983ea596e521bd4cbf74dba4d505dd9ea5df423474fa9725d5b65f1575d26ead95725e2a59a6c8a5397ebd6b54123e42bca44781b84c014b8e5d2c1a86cf34d764b242baaad5be285cec72ba8ace808058a0226c04f95eb2b53a828d0ac41e6b40e5a4c4092788d9f7e988752f175f075d545f421205\nB = -b115a1101d97664759538d22154de4b000c008e551e2ab10ad05f12274b10a4cbfee762d232df5188fa1161f37ba61d146e8b95fa715d98e016da8beb0600de65216cecf8b8816f6e7e73e2a2bfa7d0bac74b517b906bbc43357fca69de9cb5507bd95205515b97b3a4d6842f3d7b09606cce1c7436c462f49dd05e915d04ab6fe2748ccaf025bd5d19749cc468d228ba43452ccc479c146ac6d781717bb9966bf3835dec\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 1473f092540ae30de595666beb33e430cbec42d7a28d4f7982e62f58025cdb617cfc33f1e5ab93d2ebefd7345561b81271bdc50bfbb0db6381dc0ea023ff7c72605da26dc7da2b5664d2ad7967426ca97b3745f82528964bb68e70087e14dcf2d71d30fa0d1f7b3f10b19b357e7053fdf22bccc5188c6919eff1e5c402b750a4\nA = -68f280cecc512d51ae534f30aa198cf7b170c346c1159fa9cf158d0127d43e50a8d4704ec54b8b4295dd7f51c6771cb5767fe0c975414cbe6d2bb58ae66a095e8832d5f443498b1ade1f5bf249da58595ebd878677b34e3b4c99ba6124e2b71d86a8d99727a16746469de51b0a61d9d981459a6cebe206cd36a09f00ffce7f532e2c31999847ba000b9e01a4b84f454544b6362a5c093b9abe9d583716f4534f2de4\nB = 5b79684387f18d7de6eec3a63d737490dc2a46c0616ec16388dca2be60adcda11ae13063ede3fec177171a51dbef430f8c4b3f6d297b9d6c020fc44e3ffab891d0d751d033fda813861bc067c181118dc613335ce89c5960f952e5fd28bc72c41b7b6e374ec29b837f1e00271cab646c794579d315260921dbc3b984b86d98b8f8816aca4f16de506",
-    "57e4102f34d9e29ec3a03e0da06e70f69952339bf2ec4a7e74daca82239\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 5e4b3f4aea7115d592bde9bf7c6594fee77372ffb19f7745b4de878a4024f81e8290c77d2915424df20004a7abb64c214104a3123e7c8f230c159ccb99bd937521b433dcfb065b186a685fc40f9166bad9380a02e297ffd6a307ce8d2c8f2f1330447a9c06c327b74f3cfc2e98f3351a8b385bae855941228969d1c29e9da3e4\nA = -11c1d396693139df5bd91825c119d1241c3f57b7ce95b46472dd82081738cdeb0868d18eb7c8ee7808016b3311f982adebd5a2e5f4e201ec4a34f3037d260fe580e771222de5a1a67947a4552cc03c5c59f9e60e25063a702ad3c3aa43f061a22567f938a91f1dd697c3e3978fa11ab1d65030bf327f8049bda745658bdd4ba8f3e34b060c6a2c6c5a8be54c7cb5f6b106f54a37d2be9f674f7747744d4350b3acdf373\nB = -25a65b6acda692ba3330d70dbc3ea4dfe208c0df358c50b7872245a909c5ac19ec568b1a1340e1a094f5b8e7d1e3b7e04bb4df002558aefd4540135d62d75bd5ce959128c1300b9d98429d7369610866d98b22c345e531f2beb80b042b6ad48da077043401a82e223e9e529e7407bfa466dd2680973006d047d837c26a60cabc36a7ef538f603ba19f8e923f168ebfc3834df8f77a559c9e0342e33df245f551bb242e5a66e5904\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 47872b544fa0425981ae17bb450ea346135e6ed7a9de0572ae14a6e85e8319f27cfab778cdd8cb5f93b417d9c66ae0fb7bcc6652620f7f3f74acc2bc9f2c090129fa8315aeec9ca7adc5356484474ee803883ba4695d7bc47c87eec508d16a15150cf3f757c4713de71366e958d6af045b2d282b6ce96976692c80b1e0b6f846\nA = 7e8f55c040862f12d8cc6e506608eeca65ce38e9e8ab18ef7007e3cf0f1c9a0696795bd10f8e1e1f55bb4f4f3a35c2e0ad18289e250571ccc26a961f730346efb1e29fb143ed97cf72deaab19834fa2e98e9c12ae4cd23b9c5ecef4a04c439f7d42e110b30caedc4334372ca24cfe4171ef1430528f7b57bbc823fd606fbd30915c5817e6c57c967c4c404a0847b1455da17effeebbec3f9357358e00001239aae209228f\nB = 1cc00b95f6bd3abfa697400c98110725a7e109aa9b8cbbe9ae16327c4fc8e5bc93afc7a94da32e98e85e4fd5eb545192c73007d97a4e84ba64fe187ef61d17f0941e165c9fe64c7b8054e24dad30f92b50d1f526b4bb031e6b1b9058be24884b170a145212273c51692b71bc57ee53176d8702b975bb6ba96284b462da2ce38e12d86b342c7f4d3cd489fbce88a309c7df1121d7bbbaab6814cd1e54953e5cc46813ead98f02360372\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 5d193b085e57c3f1e825cf3b36c8bdc936c603136bb782a244b04a79fa713dc7b08436b85ca3b483d2e100a012d6430679b30c8e4101c8f08ca0f9010dc0f27fb37be842054dfdd99362e03a7f55ae58db7b47f694bd35d91a58975ae1f255c41617e773f91c2640f768bc702a213f073682dc761e056b34c57edd85585fe04\nA = 1bb1c759ea94b61a1721ef5680f42af30fa31444b27591a03b7c9bf5b90845ab965339f463a78bddedcd62fa21197c32d6850c61bae195f86e1c7a23e7a20dc618c59ce3a1c6ea6306c0b01b11a36d0fadf8214c36a133d689438021ce7c78b20c85256ec607360cce14f139513d9f3ea6eab067b1ffd0935d7c43419b93ecfadf2c5a902b7c39a69bdc023173bdad574adc77706c1a666d66f69578a5bffdc7cd6eee28ad8a\nB = -e8072c49cea603d48f20276df188fd2fb28f8721d578220cef7db1e56379c04a6b372e56a047cbe59ea84ad026adc5d0aa930011db63bf4959f15781e060e0240dfac0e2a2c26be12a21e5650d12140bb49a2a8e0f6a86e4b1eb79d9b8aab3202bfd339096529170cfe3e0c18263128686bd9305e92a3c43e1523f97d8a6a2707773e3d441da162a79089c9ea1e094cd5a23474121188013c8c287965a5e77599f6a7d64174b06cc165e\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = aa79c899c2b9518857c9e4f96523a44607c3f6a97d1f40d6474ec79deb2feadd955fe92d789df4d362c828084559fab56b5e33a971abc5449208d31671c7e220c5945886e33ed1d804c059a8e439a92524a785076f9730732bc5a152aeffb5b9ecf3a7e4b55983016355c4c29827496fd4d7e6532c270cb9ef263573e4c63074\nA = -41b326c2b86e7ac14a2050bff67bb5bf9697f02594789c4a2b3e8455df4522546278d0620f28a680f6a88ab545de5829305485422f4e70a5ebf0ad15508dfe3f16ac556436d8fe8a8cde83ead549d88e0bb24dee52ebbb49159ae71589d918d3fac8011cfc3afad613ea09173856b7b79b55a2e43e0f7cd21eb9122d5f6a1fc5408414f5aafcff863b870c67b740256d317a0c58af9a81d8025a086a1f3d79f7408d4bfa06b9dc\nB = 4730f03c389f9bdd92fd864177e06140c9dcc02d01fe7d37b51d44de140696f116d11bb67adf7db797edeb7c304386a7f5e37bfac46a5462a6d4c49b1bc034c2e0dfa56f14bbd2a4bfaf86bbad4f6d0dfa13c782fe680847d4b43373d7137f5c2ebe4ad58c695a7d4c407bfd888ce04abaaec60a3fd33db10eaba6b6acf0e16cb61d1beb9212c2b07921bfb5595ef1eb389200b356eafe8b5288d8f0e2cf252b38301de65190d56bfadf57f\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 23f9850dccd2af799f18268c3a2918a69019513c55268faf2477c50677fce277d8ce58a0cc06dfe389170faf5f0ae13ffc4954c746eebae66efc14eaef2c2ac9001f3c7ef7e32fdc31dd725b6a8093e33daa6d19808908e0c2d3e7c1c58e0fe9ed92f4d7cf3cc222393ca4f95feab5d34fe29116410a1882dff7cd92acb87590\nA = -10a75953e5fb9903411869a2949f8f04144d6e2d61f95704ff55a02f40c4f283add405353a68bf7d6acc1b8cce738f0c6f9271a538b4c688dbeface58eef0a0a1d491a9e66958750db97bd01466edfd245cef03bb6a3acb81acc63c38538e7f15deefd15afc422a8641c357c31a069258dc0ebb63f06094ed8fe7d4d420246b40302361967c81f0a9ca542fd1de01967514ff2565de7ae3b4a200d63feaa22fb99a251cad66624df4\nB = -351242b6e6d0122f7120deb8357c3bcf25d221a15f83579883bfb4dc2e6099e6b7b95fd08f6e573d93354b0676f7bc9fad563d6eb0f3567ef43efe3d874b9c7733e4fe1ef491043e1f80aab6094cc9b9c236570972233ea74e8779a6eecda23a65d08d878850cab6005159265893dc0f66920a12c26dfb421ec326a1ac09e9ab8085825c31aba488af02cd51f96b205c50e692dbf2d844ff0a989c3ba9f1c2bc7f2e7dd9458a72d310eb28d490\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 69c7fa326630d7de69249807cd8bc55c9315acac26fed3caa3c8a9c6b51ee96a7dd0b3bacd5cc13c15f199e268c5eb91d1ec36c085f83b437b9906caa6e39ed7bf09778610b621426cc8d36d96f541d0bfcc7693525d33e0c2ecd77ccfe80289a11155b37c7ea7791b5c2be3f9b954e230c19d746575afe9a1a3a9677d23c5bb\nA = 7cb78ca8e5d903096630744c85975719c16333e2e44931956d8c45b001d35ed4e184dec88c9e2167d2f338fe6f25540a144cc419590a4ac7caedea3bbbc565365d3357baa62fdccef2c5ea616614e0bff60e81916eb4abde0c9725b1bf6869e8b1e11f6d0d08fd712bc68003e55ed462ad4946f7f982e663f65d45c07c659d9620d5139d2b3332a68d33aec36e21716a3b75f44272a19f860e6ab3864f06def9a5ddeed340ac0733353\nB = 16d5b074e008fdd30e73ea95cb5fb87de806319388b3a44f33c94d38be0e6f1a92103dbdfb3d23b6e1d19bdb29ac14833003e9482cb7524d0d7b4c377f4911e3372f2cea6f84c938d84e3994e80f0d68e7e385ca29e02f70294c921dce7cd3829c5854ce51d1f4fcf7dba910b51b48a3f53cb1f187182435f21f6981cf8440f9c8287a9749c92c0304cc2bc91eef32d8e6526be802de8aa16684e8854cb0b67d9f7ea00f6f0145d14e3c251f70881\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 72192604b2f3f68b9ed3e261120ea52b06a05869f6abd21828ce8abadb3a71c360a14947bc738e5d1d530b9636d796f785bb44508477eefa80c4b77d4e8e35463e15ea2a48c682d3288c5abeb66181e4bed7d5b4e0db20fdf5ed68513aa5ae7e0978ec1c4646368f206636ec90e808817bd1d03acf9adb9ba57dc153873fec11\nA = 1112d291463b28ef45e879412e6607a3e20d50dba5044e71883bb3cdfe9bc694a577fd7d896dfb836a171f3a4d8fd025d3a979b43e41baafaf7b535d9050e47f4880828640e952435648960bbb74a3c25dd90bccb3fedd254dfc0f031d0e8a468e93bb69f771ed35f1653cffea1a763491fdf6efa21aefc287cb611f5ea0085f64cc3705c784f87ce00846901833d01a3c45ce047d822ba390b538f0a24720",
-    "155409f60ca0d90e13991aa1\nB = -d553fa2dff0265cd9d083ad097af87a99af3d8d93a9f4c07440a28a427082004ae5c81d22bda1dd2429f540de8df175c1b4d0d50f0227489ba570b28baa35055df951d05b584ae6b051a135d7eb2a501b2441f82c135a8ec0eb81d379b96ef8f2fd526ee62293bcb934c76ef8083727a4b28bbfc9f515ebcc2bb7ed9594a106e137ce94e9105b2e2f4776aa9c6abdf426a181181fece3251c3ef4f8eecb634e6bd47c5878663fd51c74a66b92713fb7\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 459e19faf105ab17ff794927aff86196b3cc3461e69cada53ab8c8c81e2b1820408421ea1af6ae10257e8cd9dc16386906410761fed62cf9ddcf0da2a92800d99563fbb9cb1ab0ba46a17cb9dee3f2b68992c2b832a5932e4533fbd5c4487d870f3fb5d7a1c358f4aef02993360915a9e9cfde234df5f51c761d84568400b618\nA = -7a964c62e38e4124cd2bad727138dd12a086a2bf01c095b078ce2f81288d3c8435ccce0c8e00229184091130989434bcd107a3a0787a2f5f4b0e8c23b1cee9a8f39ea279fb6081efb6c3df1704fae9e87d63ac6eac4c6687b3551ab7ddac5ca0541e12047d04c2fc760fda0916cd2b585a90d25880fcc1bde8f0a1a413969938d42e8b3b5f73118798e85b901c2e15860e29e2ee8b1c95336b97dc10a21f5300e0352adb60b40a8a99333380\nB = 743ff4d91ea3e0f9c4f72e5daecb4fb00b15b86e30bacebbe4384324523d14e22abe29b00573733f594d652a88d98c987f8db08b27b4dc68577784fde02dd410ebdbfaad9e9afc6a22a8cbb13a780222bd212fc61e38faf409e940fba35ed909e6938e83b0fdf5b5e3ce138604823e788efc3aa0df924554fb70fd2faf8249e17a827c5d85942005b328bed97e5ea1f1810219d77f2fe121ce66518e37c84d64aebda3c397684212384deebd520a776b95\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 183950095d9424b0ed09985aafbbd2e5d64bf541a56b68b42ea8cf9b2c051615ee7bb6c0687ca6fb0036888fbc927cb7aeb303750871442ff2c0087a95f4efad568f48b03bd2b9a9ac26af8c259a3fa97cd2af7e3d8f36148c26785489cda6c00a21e7eca219d1f41b2e82ba8e2c1cd752eb08a2fd50c6f9077f3096e2eba05e\nA = -1d2fc778cf44c6992d1f3a056860eeb12f969358cadb087dcaebf5f96bec42bc0aa98672260adf1732da057e9e0d22081e33f5fa71f248cf89dd361036ad58692637cdfff584a191279f178242ec0ad397efc52e99462f496caa0f3133c4238aaa877fa7094662f080eb284c4cbeb992a368c2d157ac5c8c9160c167716406190fa39ce0abcdac52c8020969b87a4f84bc09a51f7b2ca288c93b1aac64e19623a7d9e69976a31074f637e4c82aa\nB = -2f188f1245b75cd21d052ec76edeb5881944a143fee31c67370fab0420a748f3f1957bb8332ffefdeabd0ca806169629f130c86c99bab490a9668fd8200f4a9b1704c589e75b5c8c855f133d50b2ce06191875e2872b36c78438d6032d53004c047f49e4cb81e19fa84da16d053e6cbc7c8eec0b9129a8831eba690e0542ca3fefd204258624e92844c8b7bcdccab986475a47c8b22e89079ea6580ef8f496099cc24dc2911dcb1921d1451e2163b55bbb7db\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = a02c38d5df9ff7055ff84122342ccdf6ed7f7d54fe8227af091371f5ae62844645586adaae99c11f4ccd828103a81471bac72dc20625962e41d603e760591bb3569a21f45bf062b86b5fd1c617a4769a4d767a0ee14d104084c12ae875316a8f2be7adec0104381dc02c20b5851efdf7d4bef0d68076975e0ada3e58e101e8b4\nA = 5daf37d616da184acb278a75fda4e4fa49e544eadcf373c054b203a309ba198233f2285a1b55dc92e05d0213b26c82e261d8383a845813077b2e1b5f4553400f09410987c8dd21d4383e0f05747d0482d1a89f160a5220b22c78393873564fc5b1e4d5627ef3d4a05612709f301381df35606e99560fba07a917d7ea7413110fb5a8290e114d5200cfecb00b6c53b2ee29911bcb2fb2930eadba0ab9dfaf46443370307d9c3b61a329f0b8b8cbe7d\nB = 1d9539fdb1afabeb9be6e774dc7c7cc4bb4fd63af7abb557a5fc80a3fd23a4600de3c7fae89b91f3d441b61d3e24b2fd3d7803cd71620e7313917b4afb89ef5171a3d8a68c3c74aa3dfc8058d555eac429dfb6db40a9e0c25aacd2050418d6f32bf21cbb76981269dcd5883178d4b69a931a0338b93022a2ed0f78f3d8877989cc406f19d6d082ea344309318c56be7946412ea0867c78418ec32b9fa3a61017c10939c9345021133116933a3d1eb86a3ef16424\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 5fca287abf1f487e0ec18c230860eed4a2e550228b1500b1e33bcd6675646b5afe505b55073129f22352dc2b113c584ea1b98808214b6916933e90e036b129b61657cdea9026e1fa087ee300e055ae8f94ffca933a2d70453ed220468a5a3cf1a65d81eca11cf570d7d038722397f487af60531f24a5f069671354882c8bd2c1\nA = 1d9fe15171dce97475f4ad329fc8fb5469fb2b8086e4b01eddb6ceffe5324cfbd28d791705848569739b6758ca7e7d7d49adf0c11d891b0a5879ca870d1ca5ff475513322ff218cd26024f97623bb8a53084594e1fd64154e1db702522883fcf4c0d677a7fe90096fc76dc3800816996308d8f0be2dbf3b879f8a000c0ac534511437e2ce2d7ebcf42fd1698a829eb846b3afa581c24d5bf97abc6e247f110f4e872a2474e3acca6c8c0d518104c3375\nB = -dc0da8f7adb8e9f7b0e3f293cf623528dc8e9668317910417e52301c50c62e7d30e77ec7e38d6817d1f5a93e851f8560f642f23a0b9f836812d27b1b41c0867088a3108332b8711047560052ea30c8840f03a25c65b227a175d8f340095823788adb5bdf2b7ebb801e20f6b6435e154f78d17b8fc4373aecee56ec7b8f5686a7d22c8571797fde85cec884d45ddc4b1f2cc47ebf56a879bf286f349a0edfb531168b733d43de3b86b49eacb10b06a432c96c63440b\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 6222c1a14c6390d73944cead58eae5e7a6c19d19e4563c36cf624f5b61d99991bed7dbf6a0723abc56469eedfb1f7982987c2c7af6191178cf0933ed5f191b8117c9d726cdfa8b82a2fb25ca5436023f5860aff5fd482c611f134569ae87395dd99e5e9d400b5ab1e3064210ded096411654518110ea45899f4be2516e35a229\nA = -7f6766be6c6ca9bd1fd7ea1f80bfe68693f7ee4b5ba2946846839060d6028eabbb9079a165c1a07eb6a01239f3f14095225b8617753a1cc3d9c1e69b516d8705cfda396f4f0d05b0944a0f08b478d261e968c06918914ba87c8e7b7adef5cc2a875917d00585571542af219bd726e502b7f3f0bdf0cb1dfc6796be2e22e8ffb5b8bfac7e15e991022974e75d3a5eba214ab8a1aab2fcfcdbc6ded2abf834d1899d2e3ff94bad9c696aece045212531773f\nB = 49c6f869745983cae44d33cb7ba141234905441ca53172abd1a2dd8bfeeac4b236605cd2dc5b04ff9aa13de84872145b935b85479136065d2d57fd15fbd97480c25c6354636c17ffbca33c9319d65e82523e39fab49321380a130fc160857a451a69b1d0509d5718a9cff8b49c2d677c1f66bf77333d2511f58d3eb2fb47b3c162cc9be8b012d8df70278f0e21123a69724a1f126369a236d54da026ebe222c513f24b577707b5ab4b90ab0e22b4e38ceb4181d4ca101\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 9e9cc8c5342dc6d6daf55fc9aa9f79ec18592e8b9724a66881c379245c91f06a7df50a6ba0964603a6dac97e77a55d06efff17c93d5faf107fe65788d0f56483915f6ea0f1ccbda7656eb58fc032b5771600beafdc12c2076110a9b9670bd0754ff6a72c5d6e1a9e4e42c688e1cc96d7aecd815bdf5dcb16fcd1be1275ce7282\nA = -11635fe16dafce21efb1c599305e9a16eb5651187cbf054cd9d911c13e8eafbb738013e212f9c2b3662ea15ac9bd82b5751d43a38e4475d2310945a812262309094ae9cf59e0e9f3d02c92d8ab01f5733a20f051054a240bcbe3a7b6bb3f7c434229f631c4af239d33bd3ce30a372a480fdb49b2716091d26071aef372b8bd8ee8eb7f2965a372a836000b3737d2a833a39230e721e4844e16031ad69cd45ced60a64510c1248fd776611934d8d2a913d965e\nB = -3bb2cde9d3fda96fd7e6b24645f8e00b43affb223f2b5c3f4b7cfee905ddd6703a9d6c01f1f099ad1174da215a645ca4707d8156e762e2a253d7cfddd05ca19823ada9d33924013f677cfe4d86bde025391e0aaf91c6b776a9cf8a09dcad7cea59ee7aea1cf5f5bfe67c9d4456332d1f98e5310db9a0230381e1867a8f75b8757283f911f1a5e0d4afe5d544afa8d86637f9c9d87428fdcf8b4eb8f477e617960948253b24565b2f23081c47e211cd3c788a92732a49077f\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 30dc89bad4b449d1df9ea9b8f9d40b323c7",
-    "1d7e1133bc44d33bdb87c38cddedf83bb849e83436e4c92a06546fcf3e24ce6cc89d2e97a48aff2c7e3703da1b167a112f662a89742355e11e131e41052f1b379753cfa32cb0efa3a07465a258c585cd68c86bc9a473f5262c86c50992aeccbb9725b69ea8b3a7ebd2b6a24db52dc\nA = 60463fae1e9354559160d55a453c12d75775a53d1606d1fd16bef7e4ad1c78f9568954112f9280c46781180951534c5372dd5aaff3f33ac9c2e0ce4934d7009aad2ab5d6a5e5a141a36846e8925c7a28d116c68fb78aa9a687ec9bef173c1b69e0d7261f96eacacf237e1fe5874e5d553985b0fe7692ce8f2a5feab9ad9a2ad9c4bbf050b73b8030ebc36b94af8c6ecb67f8c94607d80cf600efd4ce4aa006f9b1832da8a1fdf8a564be0b4369149e8639e1714\nB = 15bfc50290b771ad147695a4c6701c47f2e8aec0657a4ef999eb45685200981b0ab5f8abc143d64878b85e9548651a1afd0913e3b14d11d3a26ab9793596801662a67b0062fdc8888feb029266f71d170518b6a4a040f59996bd4f257f221e830d0faaa9688aaa6afbc1f9b40d25097eab9d71d80aabc085f3a07e48bcfb37119aa00de60be55fd07d5b1281adf7b98bb589cdf2026252edf2f075ee176e23afa6b1f924c9fcf3c34c76752e833278a2e6b62017b88b77eece5\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 8b506c9bfb75ab7ab420ae6c9b371ef035fab512188d9df76f0b31831573b44cb08266186a04d20cc761d61b6df3e33ecb86c269205c2c79ae6aa4d3ebacac8ec71d9bce1d7ab146530b131c9038041c6ce8152a6f1c09b9bec8eea4462dda0f08d75edf296eacbcefd62a0c197ed30f799343268bf6edfee4995958db7e0420\nA = 11c16713fbf8bc9696782cb5a88174cddbe68a04e8fe93dd074aab33dcd85f92baa178b2f3b8817be0cecb802cfd3ebb06734c9d399a1f090e3a8a2110aebbba0e920427bcda74bf11700b945985bd532286d44a1a615cf7c501412e454edd647f8371cb8149474557a0d47cbb782f460de7a3cc28991491ea0fc510286711b882987b09341c079565414f2c930e7c3c3a3e3e0f1d786260a7f45c70e0fa20dfc63849906af61707cfdf5a9b7a4291a1c1586d16b8\nB = -cf5638af39c6da3757a09a92e0bd54f852742682dc91c71dcdc6e72f7825a0979a1ead2e158479ce5565d22472dc3853e6bf7ba43296a5e0e0a355f0703cecc02ec79da83e3e9de10a6eccb858dedf7d4c400c27486a5b8cb34d787cde6a5fd271e83a6cf66057838fe30db1f30663cdfc22ef5d002b0b5a05831228ea200f95382a58d0d8aba36523d9b5cb7506f193131916f3ab66ac9552c26cd0c2ab1c449eaeb8fde752f4f3c3f9b060cc1f8a1e37c4fe5ec306674b66158\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 347706abeb168205cef9b0b8c6b9d6449ac501af7dfbdfbd41a20a6a47872cbd7d4cd32f7b0805ecf1573d534418b7cce98181e079d5061b02639fdf0161cea5314dbbb2ef39ec841f695281f3c7de45f33664e0dd1658f645adc1dd225f781a3fb1634517c556403587b2aecd56dceca9ec19b930cead2b1d303aa056d28bc7\nA = -5e1c869e5dbcc684c245d5c69093bfeaadf388cbf928d33a8ae2148a2b5145937e4f654c5f6a36de1124bad1de8bcc9067fe1f9a44fc6ffe55ce7ed5cd0dbb6337b0e1e96bac1eb2a3606dd97b0bdb975ea59448be50191cc7ea36481ca9fc85c1c3e1c97378dbcd6b355622046888df2ab3d18d805f4d31d464f62a8e630e955beeeb5e00c70242b8f8df708705abbeb95dea3561756298b5f3f7fe16e965294eeeea4546f5e8bacf9d6b4f2136d2e206a87dad1f47\nB = 70225f0cadd328be36ece2172c836405db3fe80ef99ec74fca25406b73a537adf5073f2b550abfc4c0fcc2c2850dace0da9a266768cb4d5ff7fc6c1c248ad74f47592101b61ef96c1302924381abbd96cf49f50c44bf7e0551721a8ae85abdf9925548d13b8c5d1a27be8a40d0f43eec3136bc3035057b75aea779b4262cc66e6bc68da93c218f1920979291105d4b02117d66deb92c3e511aa588b27130202acc9f69521957f79c7e731bbd5461552b9b6b24240dd71ac449be9777\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = a2cb238f326d47f95869e2dcb295eba819a443dcc7c2785461389b58327742702f4c86e47af129f1fd4611cda93631f9333c358a29121d58286333083d13e66f30a9533b77ba3e26089e7eff7baf19bef8054af4e24735525908864ea9c4756b42a69c897003cab7b63cfd9a5927ed562e29845308eb2a55e7f8f03c87a5b7ce\nA = -1aa7ae6f56c38b654b281525b9da953ef366c2b9cffd3042105ed428dc7e5f2f2d53ef90b468bb471753606cc7a3775d86bcd2f4d5119cdde3c487cd39bf31752c5ba297e529c1b8121487e0e1de702156d0166ccaf51888a24fe7b48624eefaec855e2200929c21858676ec9bf4ceed0a832b69efd5065af544e49a3d209b85a77b0953652cbf0aa897527c52c9a98de9ae4c827f762e251478c88d410123625ea52b3478b52f6b9987d42009ae427763357ab53195772\nB = -226630b6fcdb5e274a25066ae2ca2c803549dbb935a97c0d7f6ab2c971d74cf6acd265c9d6815a6b2dd23dcb3c23b390fe8b1bed92b8c64c76c0ce62d5e7ddd7ce445bab0ca905dcfd0f128e5f4ffe966f3903d7ff1c61fe174e373cfe35a6d83249ec40b4a354d46fa1c90682efe468e895ea3da710838c262e8a47752dc6e7a79fe20051f51180173b58e0aa37b22eb8efee5b6dc264459ce4d135f430cb15afbf8c53f0de894bd2aca1f7ea32b4209a22a075f7b3b18e86f778a9e47\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 9ea62ef634\nA = 55cc58c9d8\nB = 6b49179821\nM = f753311ac9\n\nModMul = e9ab3a2aa60edd30108\nA = 5134a36c2bad180dd5bf\nB = 2ba6485656d041690666\nM = 9b9cc4409e86c8b0fbbf\n\nModMul = 621f9b797e866028b7bd1ff828bf29\nA = a202338dffe171c99434d84f3\nB = fb71eee7045b3e3ab5dd809dd\nM = b3e6e8d53b7249df670e3c59c55d33\n\nModMul = 808d463d06b7b7f98e3cb2783e2196c349d62672\nA = c669426a92d3cb5b316e2b5b9\nB = ccaea3874008dcc92450d8b2f\nM = b04dd2bb325baed1940cd000e8cb2d786009ccd5\n\nModMul = 872164b92b9426b237858c4cdafe1694f96b0e0e4c19e894a0\nA = c3255cb24a813e27c3dc410f0\nB = b144f39e7c2d33605ba7bee16\nM = f3639f4dfb782f3107eb402fabb5fc878903acb5e02e129077\n\nModMul = 6124d7d171\nA = 235b938139\nB = 3a56a22a28\nM = 83eb4af4e5\n\nModMul = 9c006f56095d442ba98c\nA = 207e14237c42e3764e5e\nB = 8a495a26872432fa8e33\nM = d0cf2b8ae5c67d6736b9\n\nModMul = 97387cfaef652932a230c82de59cac\nA = 82ae0fc5e943af5bb8c4adebb\nB = db1279be12d59ba3a9c036a61\nM = aa36dc1d13390169cd54d711eb511b\n\nModMul = 32ee73c98da657464c6fed4274df20b099689e00\nA = 9baf08248ee24bcb17714e420\nB = a7f0428147bfe098666180749\nM = ce0bc198331c9ed1d21f0d498326e8185d3d602d\n\nModMul = a8b3fc0b53df3b92753edecd6fbcc5f4840dad3a44da704e34\nA = b36249e259b303e453757721c\nB = f0c1db50670d92abd93bdc84b\nM = b05cf978bf2dc7e093d7d164e46d547219c480382df32b33d9\n\nModMul = 2663b741ff\nA = 58c8e7f7f6\nB = c84681fc87\nM = e0a50dcb45\n\nModMul = 21af3c0b42328f41b81e\nA = 1f79f5b5bf78c9700d\nB = 5bd1734ba0f0e59c2a25\nM = 9ff3fdfb5c089244f327\n\nModMul = cbc280b5106c2c36cb31ad7e7c986c\nA = cadf6482b769e83ce7f7277dd\nB = f9862a06da1a9c89547b76c61\nM = cc36144c88139ce921d2fd1740bc4b\n\nModMul = 3813f2fabe016e19fd8e70687ff473651a5fbb4b\nA = 9c51a5bacb5d9f055a9ac2962\nB = bfed5625b21b4e82d1f105a0b\nM = a47977acad7c5deeb683ccd265cb30cb193f22a9\n\nModMul = 76ff291a02715fc87ebfb3e99153c04e53358dbd7beae43478\nA = 997c4a7b537d9500d73a205a4\nB = c679ce666af284a459ae5a26e\nM = d0d0fd4922953941acad8beb65c00603b19eb44fb8ca51e3c9\n\nModMul = 1a90c92fdb\nA = 94fa7bb475\nB = 564b0a3339\nM = a1501bdc75\n\nModMul = 5e7ae5470686bad7996a\nA = c725797912c6c5f30d94\nB = 3a7f4c99ee3f5fa9582c\nM = cc50c8b7408f09a74973\n\nModMul = 72a15b13bcd1b63747342a6be8f0f2\nA = c33357af48a2df569e3c11ce6\nB = a4b4c5c14d7796adab54b6cae\nM = e22a0fdca62a37f4c8a61c96a429b9\n\nModMul = 31e179bfbf65b0695dde36a4fb72d131830dcdd6\nA = ce8d3adab8cbf15c332c0b289\nB = 9333f94eeb7d7a86b82becc51\nM = a532a76bd5cff409b580d54d12ef75ad8179b381\n\nModMul = 8f4b8a585415adff3a7bc35fa88891ba31e4a82672c664fb14\nA = 9a2b56a54bd0727ab4be57ff2\nB = edf1781b4296567990773005a\nM = c5a7c3b97ba00d6f174a019c6d37eda52036c528f351bef0f1\n\nModMul = 917bcdb402\nA = 55c7dbd314\nB = 997b29ef79\nM = af5b4cbd0f\n\nModMul = 660c4bb2b771f523a4fd\nA = 43fe52461d5139620a11\nB = 1f8ec4b67de1db54ddda\nM = d0458e215b7e6903d96f\n\nModMul = 7aeff02c143e4426fcbcf32bd1277b\nA = a2671586369a990dde7829f36\nB = c7ff67937c900daccc0ab1d8c\nM = 8ad9c1d4d3cce681d1ae27c27982df\n\nModMul = 4b153d57433f0f7276674d3484e9bd0d25227d07\nA = aea36cf51dd2ce06c66b7a407\nB = 80c9fe5bb0afd2bf8b3644f96\nM = 8cc22a67ed7e5a7a2322aaa09ec2be94998494f9\n\nModMul = 7f8447dd983b113f04c6288f9539e53a2e9cddbca8b2fefcc0\nA = f67636b03821c8f13f21217a5\nB = 8473a29f4ae33f",
-    "36a0d2c6dc0\nM = b829af37b557c3ddbb5257c8b19144b90708a45a274d6655f5\n\nModMul = 17fe4644a2\nA = 912611576f\nB = 7a10d36b80\nM = c5fa605133\n\nModMul = 8159b23d4fd697b4fd35\nA = be2d646e76494439e60\nB = 60fa770d05ebc69772b2\nM = a6e7c940cd749925a85b\n\nModMul = 7c412dad5c9fff91357bf181caf2bf\nA = 80f476ed5acae75b34ed54c52\nB = fb818e2bdab3b5f4bd84db3d0\nM = d0339f7ee41337d8462d1a9c207d1d\n\nModMul = 70432c749da4ade2c38237545ebfe6c4c6a92f6b\nA = ee9c92de52210e61adaa6eb4a\nB = 8ab55a85b1abab62d33e75fe3\nM = cd3faa6de4cb62fece4c3f94492d457834a6a041\n\nModMul = 9fef1c18778a8691c5e71c0b5208e82778e9bfb632da0b7e28\nA = bd162c90bed25e84dd5b6b77c\nB = d887ee03020c5df356f091db6\nM = a2c2d45fe9decd93a0ca3edab8fee46d27ba23fad9b5294d5f\n\nModMul = 958951bd0f\nA = 12bd0d3375\nB = 668bb65b4e\nM = 9c617dfaad\n\nModMul = 8a109ebc9cbf86613e43\nA = a3e7019f1bbc35689a77\nB = 3189ecd3fd4ffd0229ef\nM = ddadc50600dff2abc1af\n\nModMul = 2b4d9f85a398c852b3a0cc82524619\nA = c244fd157267f707319ba6c6d\nB = 8a07018a748992429bbdbf326\nM = bf3813fb54f749ea5627f59ce30e07\n\nModMul = 28cab7d574e6dc56a6a622f8a7523cbb8dcc5e0f\nA = c9909dcfd3a59a3cfa538b267\nB = 8bbf89cd5a4e24adc2d8c646b\nM = c8f02682b9d480ea98faaca53b747ced33ed0419\n\nModMul = 69b2dfb3f1d8dbb13e9e479f38edcc427d5968acb7751a226a\nA = 8019266c548982a520ab48eff\nB = d33c3e3b13576dcdb3ffaa796\nM = e6255103732475604df7c6f7ef7e6b49a8ef9e2b0c717925a1\n\nModMul = 3eaa4c99fd\nA = 6fc42faa85\nB = dd0b4e318e\nM = fd7f22301b\n\nModMul = 56b6b811ced3433755cb\nA = 145573d17cb0c996c69\nB = 9d3297d5ccc184896822\nM = dcfb3b383506239e83e1\n\nModMul = 34315b6bc6d3690c28060485ae331f\nA = b963a26973894cfb42fcb2d22\nB = e8523304bbcdff1a0ed4141bb\nM = d7a379aeac7d8cf94f19e7924d35d1\n\nModMul = 2ec9466e8b3357496f07e37ba24d36a237883846\nA = a75f3904e564997695b6707eb\nB = f9f47bd779834dc1f5fba0654\nM = b3ae5abed45d09c4dc5abcadc3ac9abebe1949ed\n\nModMul = 88b4d86b2c1e1bd780e8d2499c2221e05fab4f9b7047c2a044\nA = a38eceb9c551f0e69a544072c\nB = d5f8e7c2d534b2b8985bfd213\nM = ff81809b84fb8eed3508ad891d3d8208249d8a902a12d6acf7\n\nModMul = 172f2e2e22\nA = 1584ff1055\nB = 2e0aee014d\nM = b904cb0bc9\n\nModMul = 122c10d3200270b9eaa1\nA = 86fd189e62a6dc1e4ba0\nB = 5235635f7b0336f5f235\nM = c93da97d0e95fb63dc4d\n\nModMul = 3e461e10ac4eb749512097fbf76616\nA = cf4ce10cbca07164f3812f89c\nB = b7e4639c233fbb0f923fb5104\nM = 949647857e1406871593fad5c30101\n\nModMul = 88117b59d9fed79dd6aaf083ee938215a995a221\nA = 94c888795567d434123d441a7\nB = c60ca79e61a352e34e0f78bee\nM = d2553a7c5dccd639a3927697a2e1af03845f2f25\n\nModMul = bc5f0076a8c2f6cc8f4e61540d2d6f6d6b13b775b363dcd71c\nA = c170eaddca5295d6ec6272dc2\nB = f94a5685ced7661df2efbd34e\nM = fa6bc46aa05033af72aa42793e9174af2e3ba38992f33572fd\n\nModMul = 1110cdbe5b\nA = 5db02b38f3\nB = 3369537903\nM = a8863f7979\n\nModMul = 90fcc5f3a346d3d4ea4c\nA = b93373680ea0feeb31d8\nB = 37f9dfaf0e180be64bd5\nM = d595cc29237d1c19e2db\n\nModMul = 8623a9997e514cf3c1d06c33c14053\nA = b396f5ede6212f1fdfc7e7b77\nB = 81a1ddc18306f2d2e84030148\nM = a6be32a91b34857842255ef8b1aafd\n\nModMul = 63f8f0254df06356f5cab8941b77619ad58025ed\nA = 806b2627b08d987438f920bae\nB = 83297039f4aa8efc1a185fea3\nM = bb8a7e7c19be02c25cf5682a0eee655fcd5b69a5\n\nModMul = 697238dbe3d395e81f20c9fcc8db30c234a1f75f3b2bc27438\nA = 930b04224bc097ac1d8bae8be\nB = b79496a80e45212c4663e5b64\nM = 8ff7e19d967d317c255380411898d73e3786269f09079f19f1\n\nModMul = cd93b5b8b1\nA = 47a51b2d5a\nB = 86d6ba5155\nM = efb0ad3643\n\nModMul = 2037821ea789118bde0a\nA = a92215dcae19be637ff\nB = 93b9a3664a406737958f\nM = 9df360b69ed26f610253\n\nModMul = 3bf11785d28ceb668dc55b870faf7b\nA = bc8758854dc48e057cb6210de\nB = f03ca689620a77ecd8a6f0de3\nM = f3ff0747d6e5f34a0ba4200f579259\n\nModMul = 7b30b44f75ed12f54136858ce4fe77d00e0952cf\nA = 993cd09f3e46423a8ba2053df\nB = feabee384158032dd013dc08d\nM = cd0b21388cb2033b1e792ec4078334df70b6c8f9\n\nModMul = 8ce1e17972f1a9d2e9437d0c5219354728a5f31337808d7650\nA = 90e5d18b017118177ffb080da\nB = f8e7e09032574f6c66e623ec8\nM = da795e6ef63ff7dc4baef5c327022ccf65d44e3c4e24823f11\n\nModMul = 8fcd412054\nA = 2e7f9b1a\nB = 6283de2c9a\nM = 9bff560ae7\n\nModMul = 57d0d3b79f1e2f3632fc\nA = 2f8cc403de5af54cfa39\nB = 3b798c3ead52878dfb2f\nM = 805e6cbde400d4b4bc9b\n\nModMul = 23331614e88633af879201f568c359\nA = f21f19da4b20980979a645dac\nB = ea752050b79883dcd69222536\nM = aed3faf4c88f7c4afe257c5ed90599\n\nModMul = 56dcf9ae1c787e773774df3c8762babb4675a212\nA = 9accf901fa599da05fa6ab5ff\nB = f7f6b9b1d7bae06237532e39f\nM = b5bcd776bb2eb0805ade3c8b47e883962d3cbdf5\n\nModMul = 61d0ee0786963906a028a1df01f836841ab6d39d88ca2717c0\nA = 8e57680f213d088ff1a1e7db3\nB = afebecc9943b0093f87022940\nM = b6201f68a45265d7e9183c3255feb4c110c05dadbcb13881bb\n\nModMul = 143ae78a29\nA = 334abb952a\nB = 74203e7a50\nM = c9535a9505\n\nModMul = 897a2b57e69f5a1469ea\nA = 1ec8ca0ea4fed52bdbbf\nB = 3a6273cab05e478a57b8\nM = dcb33163a8ea42c1ae6d\n\nModMul = 4a2c10e90e2d37111db79a44d3e31b\nA = a90e7bbd63fc4af6de83029ee\nB = cf09c3dd50b41afc7045e057b\nM = 8ab85d47e4270116a64f97dc4f0f15\n\nModMul = 70f94276c9d85fd3f71edfaad6051456f754da85\nA = fa3e9ff6e1aa1fb78e51711cb\nB = b115ed197c50b7ec4040ca255\nM = ad63f69ef1346e7549ba71c13b24b279f53bc9bd\n\nModMul = 861e7ef401866f815b983ba18a612913ecc20a67016d79cfac\nA = fc41a9ce06e882942f751be7a\nB = 881c05a51d1ba8134d126a48e\nM = b12200b39526c33b70e8aa23ebc400dea0d4d8fe42be103d5f\n\nModMul = 4e0051898a\nA = 2a06523f70\nB = 651b5044f0\nM = 9da4eb09b5\n\nModMul = cc8274c88d6affc3742f\nA = 9ccf0133f9628532f4f6\nB = c1d80907057be7a67b01\nM = d6e76e362da831f32685\n\nModMul = 568f15bed5c4405be9dd04673a9c46\nA = dd6029c3196feb6da7f0f4a48\nB = a5f6745f2cb64913d1d3236d8\nM = f62f02c9b9ca8993e3be9a02b444bf\n\nModMul = a629452d5ed19df040eca26eaca37d82c0fb1d8f\nA = 963c51a9415b03e85ccb09f25\nB = b1cffe333afe44311cb968ffe\nM = ab2128698d498e8d75455033cfbbf4487535773f\n\nModMul = 814030123025d287aaa8b826792999d72f2d589e0c7f7f3dbf\nA = c3b33f391e78bee97ceddf313\nB = a9136f3af450fdeb245eff425\nM = b6aa9c517eaecb70781e597b907583bbb569e970d229235a35\n\nModMul = 8735bd486d\nA = 563e15c52a\nB = 31293264e1\nM = 92f4b193df\n\nModMul = a541f69ca163b288dd0e\nA = a608b48c1dcaa18424b2\nB = 891b0b296e911068b00c\nM = d4140921f4b2c84f1eb1\n\nModMul = adc1b7cf65967b013d046866b4ed9d\nA = e97941448f65060cf63ecd486\nB = ca68936f76cb87a8fbdd37311\nM = ebbca2482fb82eeca2866057cf1179\n\nModMul = 44aa9f0dd58d4510a7364e130698b34eda23a632\nA = c11f83f01bb964ffac93a2e30\nB = e05ee40eea39f4538d735193d\nM = b5e8b511738979dc740a6a1f7291cf4561787be7\n\nModMul = 8b16b82f064f471983c7154abc9f9ba355111bacb90400372a\nA = acff8da571e1c96810bf95707\nB = cdd23e5504cc26d0c34a62b06\nM = f38902a99190ae0b5ef26849a6e943d651925666fea271fee7\n\nModMul = 193f453197\nA = 8cb3078675\nB = a8fb003a87\nM = b60ff22f4b\n\nModMul = 849c26c8cf5cae426a80\nA = 5d1e3d2b4d038a0a34be\nB = 34f70325565bf0523314\nM = cbc189f9a732cad8f425\n\nModMul = 9a4e64ff530c53a4c6c5b6b5021920\nA = f53b81723cf74f520a61e614e\nB = 9d8ac2e6b839143fdd079a2ff\nM = a115375435151798f3644bede9d863\n\nModMul = aac303a4623e80158af1cb3331965cc8e3184edd\nA = cce0a88606ff962fdc37e72c9\nB = 9840a500a2051625c517104db\nM = b99dafdbd91ec3c05791031df5e193c03d6a441d\n\nModMul = a31401dfa761bbe82b66b5f094151865b18a4ba75bb9b3dedf\nA = e6f48c027284856aaf3b96425\nB = b4c326f72a6a22fd4b93ba5b3\nM = e57d9608ac6e5b129b2c014958bfc59137f63838b1ba88a4ab\n\nModMul = 8b0929adbf\nA = 61fdf77ac0\nB = 8892f05400\nM = f12b3766eb\n\nModMul = 91b57f353307b173679d\nA = 33f8e73752072b4b5cfa\nB = b4c730f79f4f2c07945d\nM = d41be1d8d2e5753e3ae9\n\nModMul = af04c564adfeb120bc4770bc8c650c\nA = af151333b3d4cd1d29fd801db\nB = 9ccaac44ff91be11b30bdcdd0\nM = e0bd6e70d5f5ce08fbbfd48d43101f\n\nModMul = 1b8d623796a5065d9e993a53a9587a0fdbea1bbd\nA = a2fd08df2d4eab0cd6d29e213\nB = 92c9d26ae7c215b52199ee28b\nM = cd529f4cfa46f3bd3e7fadf167fdc02f6f881da3\n\nModMul = 4a8573dd8dc50a4fa39f3579d3869745eb8c1153ca508deefd\nA = 855f941d085305725da617f5d\nB = 8f09b7d2c36e0340523da5421\nM = fd8caa05edeaa81beefa01957eed97a981ab34bdeb6d8c704b\n\nModMul = 2d278e089\nA = 59d20a1716\nB = 8e2a58bc75\nM = b3d61ef699\n\nModMul = 2f937ce359d0f6cedd1\nA = 1019d11d26040ffd5b1d\nB = 7cdb6252087423d43e08\nM = e8f537323004447e669f\n\nModMul = 6567332e25af83089f7458786ab0ca\nA = bf9565e9f8a098894447b58fb\nB = fc867626f268c24cc0ab7bf8b\nM = 930f39183353363dcd822933a438ef\n\nModMul = 3692e73ad1d91ddc19cad3808eba2c5fc88e2bf9\nA = d0a42ce512629f0ffd233a9aa\nB = 97f6d3c4c655c7353a62d6ac4\nM = eac2ea84851f880214b8f40f881a2",
-    "e56a6ba6f2d\n\nModMul = 81df390c9e51b30bd639db15adb464c7cb1d011cb5e260be58\nA = c237eb242c40960861c938c08\nB = ab2f481f0d768eebd90d2574b\nM = 8697d7a28a5f42c9a7b31949b8b568f861142f44fe66c6cd3f\n\nModMul = c952f9aef\nA = 81973bbcb3\nB = 28ddee3bf7\nM = c4a40993c9\n\nModMul = 241dd53d93f7bdbbb2ee\nA = 2136eda4495c45c9f96c\nB = e74c4baa8ca3f6b7cd5b\nM = fff4594e7a5f0a1d3e15\n\nModMul = 5f861ed8b0aa835761613e6c869cfd\nA = bfc5c1572086079f5f5d18d1b\nB = 95902e14923c8010b7e905178\nM = a819c6c109d623f9b845aa23712c9b\n\nModMul = 5b8ab089c4e4c6804e48a2bc1d218718b3a32598\nA = fbe65d3852224a812c432672a\nB = d57a3f38da966d2471d70a048\nM = b9e6a626d3ad026d14248fc90c882bedd64a1f13\n\nModMul = 761438baf5b02dc095b7040e082da7b167c2b9ace956284ed\nA = fd91701ed2151f8e994bf4ee1\nB = 88b66e735b76972bccd9db182\nM = 8008b2d1274456aa68dc627b1ec3e1762c6ed2d660c64a1a55\n\nModMul = cb743c97a1\nA = 9c69ca9b60\nB = 7488f48f5\nM = d67040ed0d\n\nModMul = 931b2bee1bc30725a31\nA = 650f567b544ce02303d4\nB = 5858da30dd1fae88a675\nM = 91ce30234bb29fb9e833\n\nModMul = 5b4f262cec958a20390b5e568ccdaf\nA = f7e240e8a077e8e87506db2f1\nB = f8653fe64e3bd414782f51634\nM = fdb8225eefc1620648737d31dfe1f7\n\nModMul = 4c011d1ddfa30c901793cc6ce74db47584cebbd1\nA = eda8e9a9ea3cdae17bd50b1b4\nB = 992e8ef4a45593e4ceff67876\nM = 95e2f120cfcefbada1058af6c8853cbebedd5763\n\nModMul = 6e99aa5b8107399848cf24fbd88ed6350efb68d737e505b466\nA = ca6c51ba2f410d09bf71d60fe\nB = 8bdfa8fe5ef3b2ad02bc63c4d\nM = 84daecf412b8c50ad6dfdb546c3eb783dcc6f32003eda914bb\n\nModMul = 536175913582e73c1002083cb0cfce5471d4193a5b717881e60abfe927c829d\nA = 9b474b6f7d7f11dfbeb7a0724694f2daf9ccbaf2ec13269b5ae3329e8df95f7833baa68324509dcddfb5afa1d14f2dafc55e2c225475f16fb396beecc7a66dee\nB = d74a5081f00af2361c3537642c06cd47aae7e366741c9b4785e185af8b328acf3e2ed71e3b9a4b6fd49d956eef76740b3c6ec5850a90e7e444dfeaa7214c5eca\nM = 5efaeebe212752b28b5441a5d0b2600190504467c6359e9ab26320ee72cffcb\n\nModMul = 6161cceee2b74e7965a926fdf5344ddf8cc41994d72154a8b6014c18cf71634\nA = e7d6b74a1af0834aaf93e09a6488340b661449ba2bbc73d775e7d828163813ddbcd82719351879a6d67ab6b518011e1db43a3d620d1f24403917691d15ed6f90\nB = 3ecc8fd3103fe52a7e73ec4be4e60b69584bd886a030f017b482bde9d4b0b964ba8471cb32b3e9bd49864d9028a22d6b6b46be0451bb4222c3987b74a509f8fc\nM = 7c3e3b8b1a6110da82674aaf88c288cef4cfddf22e7c9b75640fd67fa5fad59\n\nModMul = 2acd55bdcccd55882eff0bb262bb62f78bff8e932aefc9d32f54d5d4e9b8bd76\nA = c221d1f0d1b7efe7e078dd01bed773f8876fa324b3fe91985d47d343e7f3878b457dae2f9ae68971245278a1d23cb541c56b94dd9ac43a9fbe28a46efc627651\nB = 49f94c19ff7ce990637c3d2019ed66f7e6dbb1442b04a4593cc480521b991cb1b878f8c31903240f89e34336d9e6785433617e729b71adcbef622a683357e035\nM = 43760c71742e9cf22cae6fc262c008b7f1b97a78c8063957b74aa4cd370c1eeb\n\nModMul = 504c11e38284a30e3647c1ddfaed94503d833bcecdff05e749422ad1d9442540\nA = 3fbabe2d65f443e7db0a6f332330ecc4d1d40e14fcb510499552020405cafcf10a50a5ee47cf60fd8c22a22b3f753b4167c213851f32109babe4b5c298d6c4cf\nB = 62e5b0f887dcb1f1794bae7dad46a066f810cf5f82a1eea99207b5f0fb0ae9084c5e62cc97b2672b1cf4cc1400a19bdcb093c97404876b584a6482931e7ba9b7\nM = d79fab3eb31189268b2a0689cafdaa0826f07d432591e8aa8bd3c7cdce1470a7\n\nModMul = 13a6431c57ddf0ed3979412ba8454a0dd9a2694a0dd76453aae63366c46e41db\nA = 7e1fd0bd9ab0aa75b264475604aea09f24239f94847ce2549d43b71890c0549938d167adebc7890d3c492b5874da7bf18d895ccaf1803b9776820598928b407c\nB = 5e54e5185bc86f16177f1354a57d36ac2980def141b389e4bfda134fae7c158009ccc61ef66281905128b6297f876662104ead2315024f129c56eaa387f80b4d\nM = 182572149b860615dd853f37f7d51a35e85f5e4a4249a60fde58dc68e0dd7401\n\nModMul = 145a44566bd75103083b7556a822ea6008ed3a6a1bf135b68fcf87a294c09b4\nA = a195e4315caa8cc0707063c7359c28139d4dfffb57eb726156336e13227ad9766ea1fc99152893ebb194fecfc153d47cb927a633217328f05e4d8782aeb89d04\nB = a97ae97dc7e9a224cab94ecedc08d0cbf7a012dc5209b1e1e8b5b843fcf61e65db3457d6085545a633be47b742e8237cc716357ff5bce9b00e23671ec1d049a8\nM = 29b060ee2aef7e43e02163d279ce49259127198adf462d13aa195c7dccf573a1\n\nModMul = b00740cef7791692d45f5a7110f3eeb260638f19f87c9245436fc0422de90658\nA = e6b97c11ad44fd451d168d65d1691d2220db8c3b6c8436d59f4c1366aac52558d0d6b61f5d6966460a4a31085fac711e5a09af5563d938963555d4730982eb0\nB = 6805eab5a4da534f07def6d2c320a6cbdfe4831fc2163dfcef740607b3181d8647bfae8f8c16237c1c1c5d14b9e3417132f81b3a7db4b7fc11927aab30dca590\nM = f975a94fa62b4c0e68df5c3ac5917d18927c0a6d9cf39c26f6ed97a81cedf227\n\nModMul = dc04b6ba2eb1e34ea8942a50d1d0c5479dd22109895796ffdc9cd32b53d4764\nA = 7fd3310af09a67e0684dcd8e3b4b651c7c13c2f6a0a47b59a7f5cd8bd80854d1d4fe02eaa61843d6bb2b87f99d8ec4842864681eaf056538ffff610c231e1d\nB = 15f1661c59ee9f93400073e18a91503a93d47537d2da5cf5e4bc69ccc87b07bed171a95f1c5eaa9c7d7ab207ab3f1f7634c5d16e706969e869364207f61d84bf\nM = 22e2856f4c2b6c01448d4aef74aaaee3a14e9660b5b277200f2e67464ecadfab\n\nModMul = 19299c9e960ce15087e9fbd66f95cafe82546431b92d70db1de87c3425c1bef2\nA = 8e3abb1f24e1f91496db99be9409f57f67cfb6e0e33d603a2a31e1309f1d0bbdc413c3e4fbb5e3d923f683afa9942b9b9fad6a6e558b2297889fff47ccef7d23\nB = dbdf5940dcd68127d476badbd5a2f3018aa4d8db79f81337ddfcb108637110b934e946d3284ec09d5255605ad72424f1894238ee4f7964dffc27fad838532321\nM = ab6b4e3d3909512f5d1d62a30c1ab8dd5e584cadbce9dffd12fe203f8936ee93\n\nModMul = 4f88ad4e30e6e8e38cba0452d98d4a3547c680f16308692e33e5577772658764\nA = 5137697bf48982edd869e4a42f3cb858bf65ad5b25d1c0e8b75d054460d0944ecb5a6924721c5728964d84231c7ae808f556837aefb23fe3ad36aec9f5f60f20\nB = c79554304620f8116b9a8bb56f6a23620e9fd504f7163f732e1e6367d25c6ff98cb01d16faf3e018dec6a067d1204a6aa95470598ce757bcfbc3ab4f5d8ec88\nM = 9ba20dd78923d8ef82897ac46a509cf22c9b7986a4facf42e5416bfe3576a735\n\nModMul = 985a4d2a7431e09fcad03e6a3f926582dbc0aedc588f17aa5db40c2d3566233\nA = 908bff40440aaeee6c90b6312dc017c3bdae884a9074e02b26f01be1f018390e01f0d111f99a06c16e20538df8000d4066cd4bb3628da88a3a5cc240cfac719f\nB = 6ebfe9fe53909876784f9d6e5dcca4cfa9463fbd8426c5bb8890ae84c2fad119615fe1e1f2ee5fa544a5ac713ed1da8c1e04f282f1f1b9fba4b4c4bd9db20538\nM = c66842e0a11ed6ad1e8f192ea97f5f244536cfc5234c7fdae1ff905123c72793\n\nModMul = 133d7b31537b627da2c042217cd28625437c28c3e06258427d9a4384046a1f4\nA = afb695e3e40347f60a500e01fba4df1c1f2fd4ed79e3f65913d82369f79d80db6b3978e6351c70c148f572b9c0c2b1efeefa605251b3156d9b66d240467e550f\nB = 8855046dcf50f80f278227d5260b9be53ca2e4a1cfe1afce4d35b11d0fa17a36a8bee8126e13bbb318d476becad5a935e9d160fa481e1437b292bdc169dc7d45\nM = 3eae4f0d6c7e1fb9de1a4c160404a8767783c7f839fe27a543f5c389c679d47\n\nModMul = 7f4576a315bad5c7fbb1616e8b26c5b34ca6f701b9b1adf0485fec181c41dee9\nA = bc2baf0153a4598f6b5f488c43b2546cadfaca2c1931b919f98ba71835a8fe78886da1fea25b194e60ed6f9e0ad23c988b64af9278155c1722dcf4983a1566c2\nB = d8374d91fd3c523ecdd6bdd265c9a8958dd222f9f0e25454fd683bd86d7900a273b56f1f47e033c46527e32c721094ce6bc927d25fac05d7fa6db4d7a6773c94\nM = 9975d8e7f2a4d9d1ff8d442b93ff269a83fee43a18bbfa8c2ccd7ca5fac3a8d3\n\nModMul = 57ebfb39605d4fa6ef5fd03bd8e4fd685664297c29b7ad75a40b133e15fc5ae9\nA = efed8e442154b1eb6c75775cc23e01fa65c9c361e222da123d07daad3039f305e7102edff23b65c333f0caae4f7929857c3169f4ae47c9f0fd920c38eb42bf2f\nB = db05415ea90269a74b0919ff772c148c0eeb2ff9dea76a6e73e82eb86bc76fb42308b55ef83a769a91d23b7840d5d2f5129f15279dfab7cd8d63778acf202f26\nM = 7704390c4b1da86d51ff817003e5451d601a5352296e339e5da219ec5a330479\n\nModMul = 40b6b0d44cf8a5ca7f4fd03dd6e1e2a11f74f3911dcd8727e57db8d65cd490d\nA = 6500f3cf686eec4e1f243616ac0ea8e8d11ddbade490b86baf231e7b2fd55968ee14b6bb7badf8c898874099831976af46bcbfbfaea10d49aa803c6e51238e2\nB = 1fac744fa1e26e789639e049679d0e2eb57336279f09555e10210e7143199a3df5fbf5294edc386ac762fa3a3b0b4bc28945adf21a8af747a29018bf76d3710a\nM = 5c0781a87b84ecb4362b09c623d511de53c085671dd4f08e9a551685b55ddfd1\n\nModMul = 6b778ae9822221e6a8376379e0032d7edb14d7b5e32a7310897b54d1d5626113\nA = c4a5737a9496129a136753f8c2e52bbd2660f2d3fafe4ed702900b01c14e506d13e3bbeab19b357e5ba9fce8a4fc3dcc469406a16248d6fb53862781fd9d55e4\nB = 444e5a673eeb37fd3b4f6b6f5133b0f46c2ea532e1953da4a0e144407a8e2534c5ff40cc9af7756e5aff9df57d938fcedaffb868dcf4e458b36f506ed7fe0ce5\nM = 7f5978c0c066132a9bdcb00727bb802b72777b9e8e4265f76b80cfdc3a788817\n\nModMul = 5c717e5dd25abe60f761d6f9326ed056416add4c1384682d87b7ff12e112f855\nA = 4351965a421c75c5b4c251861e53316a300ed7983e27e17f9308420f0d2cb11e9c476294fcd9042a525bc1a044bb442d1d9f853c",
-    "9e07245170e0e2711010cd1c\nB = 4e1046647c362c8f9c414be54075b4e9d151c6fa0c3da40d90e6042625947ca2c9f20cfbcfdab8666dac5a15f6cda9d47b09f654131fc5addc07e382c9639323\nM = a6c789884c66c7f028099e0367b3ed86871277bf070c541ee12fc02fcb6181d7\n\nModMul = 4452688244f542125168853f1d444f96ab0f82903bb12a97e59f0db633edfd6\nA = 9fd1cc81981bff977244c044146918057ad06d3cc26edfb8fb4118ee02b959d45555f9507ffeb23c3688e29ccdfe5f583fa3761f6727573542bee8ab5f5b600d\nB = 856e6a03b5c93fc19deea51b3bfe42c810c5bcf9ffbd08e2625eb209baf6a4e24943a3c090d89c1f70aea9f0128e511fe92e03715d917168c1e1ca77a3a8731f\nM = 2c245d407a78903ef2b279ddbe32106e6333b6f44cabf87b8641b047c79ea06b\n\nModMul = 375f8474ee47df6b9a038512002e56cddd374d69c69719d8d369232c64a839e2\nA = add40f1dd6d4a2414b17f0c628eed9a8f082f3ad1f34ec41935fa86b34d4505b22ea80c062386a9ed63f95c67e55c686f837bddf8f4da791f98b08c02f32d4b2\nB = dab1caaa11d5a208b7a6b7a1d6482a4859daaba5e3a77b1b1020e8ae62a664953dfddd0b47d40526e7a3c6a5363c6d41dd9f529fd8b58d5d31bb67e745cb71b3\nM = 4f506313a4f49873a405f2e5a6e9cfae9cd5e9f67b5ef900153366570e28a955\n\nModMul = 36fb0733a26902f0f8f11625305a3c94fcdfffe294eb6ccba110aa628a314df\nA = 52ee1498bd6a1677db801ae2eab4951345a1fcf8fe7d38e3f28dbc27fae508d87c9958e02a375ff4891b88ee916b96331e7cc082615faa028f6d541b5ce37876\nB = 9343cfa074f50c20e8472f8f7c4a7d330aa30ee417ed8027a4c956e84cc5cb31d5411c14796d9325fceef79a51b5d8a4c89182ca273ab633e6a7b22a27352300\nM = 9d7c334aa33634f9f313b71b42476a3b627a6c5bb8ac1d07a8d732d5c087bd9\n\nModMul = 4a377267508eb045e00cea66a417112dac07545304bbeac6315625275b7cbfad\nA = 19616a82b75b08499d4b1f869df2db8f71398672f3f97ffc6177a4a5aa913605ce8a6ab5f778cac508f0b3f2aa680b01ccdc57c0fdd6cd678a2ff2dcd7f01f3c\nB = a5643a9a9fe3be4134082daae4ee7dfd85d9452beee856fd939d3be9788b6bebcf3571c67ec481ff9b20f70d23e82e2171b1d0ddf0a9435b40115d32aedb6811\nM = ea0477e7f1a02cb6c21171066f3dab69d4e24429043b0f049de660fc80e51937\n\nModMul = 7952dfdb91252658430e365adeefd9093740de92cfc9dd3d92294f2dab6ca0b6\nA = 8e6cd7639b7c134b53e6ae6ac5f51268da83ed09e8e96d65e4bb130dcdbbab9e48226ddba6efe93faa510bde8ee92f2a641774c4272b5a2f88024b77a2cfa110\nB = fe4e8109a49b16b96871e384564cc096277dad4e1bbca8e5feb33f140a4fb800c8f3096b1bc7042bccf249aede88e6055c0db609f94e214b1251eda494be724b\nM = aa46853682af960824140c35d145a6dcff6283b2c59994b30ecf9b8def41a025\n\nModMul = 1aacec7f7e66b0cf4eb2dfda9d8d3fbf4eb8e928cbbc967d13e3e38612f0346d\nA = b0fd7a936b0908ba6fa797e4b855d673ff85d665ef3a345e560e2c0049becf5c25b6c0068dd617ab47a8fd151939ea0631f86806ddd40e557933c0e880fcdd0b\nB = 105c87fe2b1bf0be5405ca0d530beda1780f0045e892d7810f8a8abbe890f0a19de66497cba55bf38e190c52992467c22a320c38a4bd167f774ed812f1271d5a\nM = ac4f0a2b22df691331ded955a5d0e7d1910d7920a59d4a87636b2635397b7335\n\nModMul = 2c25d180156fa7d2fc20c9bd6d9ff0b111c9ad76ada0784e2f8fa0bd06413f66\nA = 2aa4a0a73df11f4e60956619d0b35eaef45730d619f9b920298e6d369b9861f6411de28a34af038f288d7a3d6a35b10c8082b8ad0fb275a8f67c6832ac46ba9\nB = fae1d50b72feb25da2581829409391bf289cd9f730c99d265b5b2d63889381cde4adbf85c3998c2478f2866526b8f64605d75765edd09b78ea45337207d173\nM = 65c9d79a09a820adbc9beb152bef387c1439147ed50cef872d36a69f1c7d5fe1\n\nModMul = 56ec8624fc199e7b4e68358f88f1a99f1d4d02577b8c6f7e28e4ccfdd981f995\nA = b0a0f9d05d144d2ef257c1e63a7127a3b8e0d8b64ff8f6447618560593574b5c5da6258b274efc28da0defd988bef1efca0f481f809665a78954b36741d668bd\nB = 10901b9dbf0016cbcc671da75a75b7a6ec6a66dd17b53a97344864b08f037098537380bfb0137b6becfc36a75206686d16bc4eb8fd54299494374e3f383d9b10\nM = 73882376ca850c125ce9f20c291e550ee48f0eb0d571109ab08c22d6719496e9\n\nModMul = acceebe131aa34ff21b3235f045bccc8a8f762dca20c1dd1ef6eb461ea971c6c\nA = a7714b249eb0f0cbe3e6fa0b04e895fcf14c404876197defafc6b57026ae7e5e993fc47c1819581adc03860ce07f2b7877a3f6d0912c0cbc659f5f6170a1cb2b\nB = b7278ecd154ef5243ad973ead291ea186acb63e09977e644a6a9fde195d1a33993fc47c1819581adc03860ce07f2b7877a3f6d0912c0cbc659f5f6170a1cb2b\nM = c52ae49e1a4b21ec392b76844ad559653b7b9f67a58b3bba6c2ce250017eab09\n\nModMul = 62b5b04dc84bb4ee04934c03ef361bc6e59b42144dc117b9f7771525c67c3688\nA = 2b65f491caf0b5cd9c66c859fbcadaec7213e6b848884638791b1620d6e4bc9dde087af0e7329d3b15a45df2d43ebde61b053ad7f63917aa922d58b4f3222620\nB = c1bfcdb34b0766be980540dc3256b9ee4158310fad2c43cf24bfafca08ee185647043f5842a9d9eda224449259341b7c50998086434528d47661bf5762a7ab5f\nM = f73398c32191b436d14a0b76c6069b1d61395568753c832dd0c707780a232dc9\n\nModMul = 5613c8fb0721bd3f605089def48fb2c38a4862bb387886c1edc1bc37d10f0e15\nA = a3d8b12a2c8f4021ca045a4e4903687dea63ee7e88893b1911aea77efbff00f8f5c7884cbafc71f59fa2636195c2ebee61edbf642923f34d87ba5eb49b06a7ee\nB = 3231829c81b26dcac432b502ce22e126ab564922b1e9818cd3da46edc5ce7df026d0e515809c97bcfdb9666581efbfd364437ba9959dfad099f90472f97c69ec\nM = df8344fa848d1066afe4f8d985cff65441751677dcf3a4e99b40365fc3c978e9\n\nModMul = 30325f7ccbc2c69e11d739ad7132a947c53377aa902ec70b152f3a75e050c244\nA = e4ba620125f58a63fe12fbd3eccdea477d56b120c76d5d1421bebd74e8686b4093f8169070453ccc04b63b173568385313a1d9c841a4aa82a61cb84d4286a941\nB = e87aaa990307855f8e5f2e5509d2ce31dd4b13bb7199cf5fa0593e350326e222efc33a26c69245565d6ebb5a484cfef7d2558f22dea8054d07831d536803d0dd\nM = 43d57108eb0ab9bebaa8ce137628ea825951c6accb9acb7f1e991c93b8563897\n\nModMul = 1975db7b72434ad32c9aee412645f6670b7f4af1f8a424a5031c559d3e18dce6\nA = bd64b1db27fa7da4c92a4ee092f58a2a53ed0f12d009fe13b36d5fd585defe778fafea4a60e8fe567d03e9ba3b72b189e22504ae8ca6aad7c2ac0f44abca2f6\nB = b487d8116198560d6c5b08c7ce63b0acc0c98e6f2a8d709cf4e3a409edd55f64d72fc27a70dc341e280ff5a1b09fe131773d466cb31991d2db23a2a86d225c80\nM = 39d57af763eabe569dac1a103e169e6e3b4375168e41e5c3b961b6e743915923\n\nModMul = 3bbb5bde9e3e240694326571360090e1fc0a4ea7b2311c1e0bd3961f6c159385\nA = 4181ee3bf9a98bcd49eaea243a179cddbf160981efc720685c7be1dfeb5aa552685a2cd46f340e1e1da893b3b460692fa2eaf6c100f24a14f239e45123242d53\nB = 77cd04d86dd5da322af78be54246dd6b7af490d903db1db03cbccde535570b81c6053a84110c07f097540ffe7510320024b7bafb77e9e239761def76092e1d59\nM = f3b9833a303eb540cf8b6cbc3cf16394b1634ef517be57684e42d364d8bec3e5\n\nModMul = 2d8174211f0367233b3a8df7c5bf0066d6aa792be7cdc5e850a477454d5c829f\nA = 1c08cec52d96136fbd9078b7b8db36ab63b86e19dd3dba7b2e3190ff566180e89dfee9423fa4e99be2187eda6aedfa86b9a45eb1e4655257315ae6a280f0a6ee\nB = a8b4bc9647d8df9b7c76cc6d0f2248cdbc41f5da9c061f9864aa8415c9557582cada456cf23cc32d47d1fc1caf19d36b398019aac4734e10f55ce3cad419e5e7\nM = 7eacffe21f88413af94155a2a8e37f70a431a59653738afda04a1bec72d0d9ed\n\n# Regression tests for CVE-2016-7055.\n\nModMul = ccd6f75b5f24b7c5ce2ce755fa89c2450c6a7d96ce8c8791e659eab84577a7695e3b2caa7c980fb23f60634233e9798499c28b0338c1f1a326d0ca89fd41f2fd88b759f317889832966b551a950043ec7a4b6152d3e2cbfb40e88458e70ab783b96f12d271f828d5b39e198ccaf8665411d85026282dbead5d24cd01b6c8a8e9\nA = 7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878\nB = 095d72c08c097ba488c5e439c655a192eafb6380073d8c2664668eddb4060744e16e57fb4edb9ae10a0cefcdc28a894f689a128379db279d48a2e20849d685939b7803bcf46cebf5c533fb0dd35b080593de5472e3fe5db951b8bff9b4cb8f039cc638a5ee8cdd703719f8000e6a9f63beed5f2fcd52ff293ea05a251bb4ab81\nM = d78af684e71db0c39cff4e64fb9db567132cb9c50cc98009feb820b26f2ded9b91b9b5e2b83ae0ae4eb4e0523ca726bfbe969b89fd754f674ce99118c3f2d1c5d81fdc7c54e02b60262b241d53c040e99e45826eca37a804668e690e1afc1ca42c9a15d84d4954425f0b7642fc0bd9d7b24e2618d2dcc9b729d944badacfddaf\n\nModMul = ccd6f75b5f24b7c5ce2ce755fa89c2450c6a7d96ce8c8791e659eab84577a7695e3b2caa7c980fb23f60634233e9798499c28b0338c1f1a326d0ca89fd41f2fd88b759f317889832966b551a950043ec7a4b6152d3e2cbfb40e88458e70ab783b96f12d271f828d5b39e198ccaf8665411d85026282dbead5d24cd01b6c8a8e9\nA = 095d72c08c097ba488c5e439c655a192eafb6380073d8c2664668eddb4060744e16e57fb4edb9ae10a0cefcdc28a894f689a128379db279d48a2e20849d685939b7803bcf46cebf5c533fb0dd35b080593de5472e3fe5db951b8bff9b4cb8f039cc638a5ee8cdd703719f8000e6a9f63beed5f2fcd52ff293ea05a251bb4ab81\nB = 7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878",
-    "787878787878787878787878787878787878787878787878787878\nM = d78af684e71db0c39cff4e64fb9db567132cb9c50cc98009feb820b26f2ded9b91b9b5e2b83ae0ae4eb4e0523ca726bfbe969b89fd754f674ce99118c3f2d1c5d81fdc7c54e02b60262b241d53c040e99e45826eca37a804668e690e1afc1ca42c9a15d84d4954425f0b7642fc0bd9d7b24e2618d2dcc9b729d944badacfddaf\n\n\n# ModSquare tests.\n#\n# These test vectors satisfy A * A = ModSquare (mod M) and 0 <= ModSquare < M.\n\n# Regression test for CVE-2017-3732.\nModSquare = fffffffdfffffd01000009000002f6fffdf403000312000402f3fff5f602fe080a0005fdfafffa00010001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000002000002fefffff7fffffd07000109fdfffef3fffdfd06000405ff00fdfbfffe00010001\nA = ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff00000000\nM = ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff\n\n\n# ModExp tests.\n#\n# These test vectors satisfy A ^ E = ModExp (mod M) and 0 <= ModExp < M.\n\nModExp = 00\nA = -01\nE = 01\nM = 01\n\nModExp = 01\nA = -02\nE = 01\nM = 03\n\nModExp = 01\nA = -01\nE = 02\nM = 03\n\nModExp = 01\nA = -02\nE = 02\nM = 03\n\nModExp = 00\nA = -03\nE = 02\nM = 03\n\nModExp = 02\nA = -04\nE = 01\nM = 03\n\nModExp = 01\nA = -04\nE = 02\nM = 03\n\n# Regression test for carry propagation bug in sqr8x_reduction.\nModExp = 19324b647d967d644b3219\nA = 050505050505\nE = 02\nM = 414141414141414141414127414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001\n\nModExp = 208f8aa0\nA = 86b49\nE = 2\nM = 30d26ecb\n\nModExp = 27308229\nA = 17591bb\nE = 6\nM = 30d26ecb\n\nModExp = 2bdf498f\nA = 21292626\nE = d\nM = 30d26ecb\n\nModExp = 11317167\nA = 4a655df24\nE = 10\nM = 30d26ecb\n\nModExp = 2e1b88e\nA = da6b761a86\nE = 35\nM = 30d26ecb\n\nModExp = 20a12ec3\nA = ea811\nE = 2\nM = 23bc042f\n\nModExp = c42ced\nA = 1011a6a\nE = 4\nM = 23bc042f\n\nModExp = 4637d79\nA = 28d9a601\nE = 8\nM = 23bc042f\n\nModExp = 20e5669b\nA = 72fe6bc20\nE = 11\nM = 23bc042f\n\nModExp = 142ab9e3\nA = 9a07b9363c\nE = 29\nM = 23bc042f\n\nModExp = 14c64646\nA = 822df\nE = 3\nM = 30915765\n\nModExp = 160e35a2\nA = 15ea542\nE = 5\nM = 30915765\n\nModExp = 2f23a488\nA = 34d2e02e\nE = e\nM = 30915765\n\nModExp = 28e67f93\nA = 636a32703\nE = 14\nM = 30915765\n\nModExp = 29bfeaa5\nA = c8646998e6\nE = 2c\nM = 30915765\n\nModExp = 30959e22\nA = 81dad\nE = 3\nM = 326dd68d\n\nModExp = 1a1da4fa\nA = 116adb9\nE = 5\nM = 326dd68d\n\nModExp = 272bf0d8\nA = 2d21ef08\nE = 8\nM = 326dd68d\n\nModExp = 29f5054b\nA = 76989850a\nE = 16\nM = 326dd68d\n\nModExp = e6c7b77\nA = b88ee70d2a\nE = 3e\nM = 326dd68d\n\nModExp = 369605e1\nA = cf26f\nE = 2\nM = 3ce082eb\n\nModExp = 168a3c5d\nA = 1f82caf\nE = 5\nM = 3ce082eb\n\nModExp = 125c4bb8\nA = 2e9c4c07\nE = 9\nM = 3ce082eb\n\nModExp = 1c5fe761\nA = 523ab37f1\nE = 14\nM = 3ce082eb\n\nModExp = 21703009\nA = dc832165e8\nE = 20\nM = 3ce082eb\n\nModExp = 1228d1e\nA = a5555\nE = 3\nM = 24665b27\n\nModExp = 5226af4\nA = 1077bd6\nE = 4\nM = 24665b27\n\nModExp = 1b14eac1\nA = 2db3a834\nE = f\nM = 24665b27\n\nModExp = 161727bc\nA = 6bd962cb6\nE = 19\nM = 24665b27\n\nModExp = 10d61d0d\nA = c10caed407\nE = 28\nM = 24665b27\n\nModExp = 233da406\nA = b125f\nE = 3\nM = 33509981\n\nModExp = 24032799\nA = 1656b7c\nE = 6\nM = 33509981\n\nModExp = 129ecebe\nA = 2e671504\nE = a\nM = 33509981\n\nModExp = 20c20bac\nA = 4d7a2de44\nE = 1f\nM = 33509981\n\nModExp = 2e3ce9d3\nA = c53b3def4d\nE = 31\nM = 33509981\n\nModExp = 12fadfd6\nA = b4cf8\nE = 2\nM = 36e9d4ae\n\nModExp = 457ac85\nA = 1b1c7e9\nE = 7\nM = 36e9d4ae\n\nModExp = 31debef4\nA = 3a973028\nE = d\nM = 36e9d4ae\n\nModExp = 2333ad93\nA = 552b97c45\nE = 11\nM = 36e9d4ae\n\nModExp = 99ba1fb\nA = 8bfb949cbb\nE = 28\nM = 36e9d4ae\n\nModExp = 27b691de\nA = 93492\nE = 3\nM = 298fdb16\n\nModExp = 3c2b70f\nA = 14e7b0d\nE = 4\nM = 298fdb16\n\nModExp = 1486cda7\nA = 29acff81\nE = c\nM = 298fdb16\n\nModExp = 11725275\nA = 507489205\nE = 13\nM = 298fdb16\n\nModExp = 24d14627\nA = e71c55606d\nE = 35\nM = 298fdb16\n\nModExp = 222b8d14\nA = 9b1a0\nE = 3\nM = 3db59d12\n\nModExp = 3b8bd47d\nA = 13f4e8d\nE = 7\nM = 3db59d12\n\nModExp = 17e72356\nA = 334774ce\nE = a\nM = 3db59d12\n\nModExp = 306447ca\nA = 47079ddd2\nE = 12\nM = 3db59d12\n\nModExp = 90bef3b\nA = a75d62616d\nE = 37\nM = 3db59d12\n\nModExp = 1\nA = cddd44f47e84b3276cc36a5c0d742cc703e61c4756168601fbb1b6eb598c161019562344dd56ab6f603d920a12c360b285e6496a3605a2f8d691c3598233ee9366b5f2692554893bdeb67b7bdaf35ab7273ac593145e26bed82c70ba5793bf4bc5cac4c80b01785d1496beede493806e4f4aa89fd8d41de80dd6d0a3e2742678\nE = 0\nM = c95943186c7567fe8cd1bb4f07e7c659475fd9f38217571af20dfe7e4666d86286bc5b2bb013197f9b1c452c69a95bb7e450cf6e45d46e452282d5d2826978e06c52c7ca204869e8d1b1fac4911e3aef92c7b2d7551ebd8c6fe0365fad49e275cc2949a124385cadc4ace24671c4fe86a849de07c6fafacb312f55e9f3c79dcb\n\nModExp = 0\nA = 0\nE = 8de689aef79eba6b20d7debb8d146541348df2f259dff6c3bfabf5517c8caf0473866a03ddbd03fc354bb00beda35e67f342d684896bf8dbb79238a6929692b1a87f58a2dcba596fe1a0514e3019baffe1b580fc810bd9774c00ab0f37af78619b30f273e3bfb95daac34e74566f84bb8809be7650dec75a20be61b4f904ed4e\nM = c95943186c7567fe8cd1bb4f07e7c659475fd9f38217571af20dfe7e4666d86286bc5b2bb013197f9b1c452c69a95bb7e450cf6e45d46e452282d5d2826978e06c52c7ca204869e8d1b1fac4911e3aef92c7b2d7551ebd8c6fe0365fad49e275cc2949a124385cadc4ace24671c4fe86a849de07c6fafacb312f55e9f3c79dcb\n\nModExp = 5150fb769d5c5d341aaf56639a7bcc77c415fe46439938a2190283409692f29cd080bfe3433005d98d24718a03a3553c8560c5e9c8ed0f53b8945eb18290e1c1a83d919302510f66dd89b58acc2de79ad54b8a30d3e1019d4d222556beefca0821b094ecf104b5e4cfce69d2d520d2abf54f3e393d25ed3d27e8c2e3ca2e5ff9\nA = ead8c5a451541c50cab74de530c89376d9a55c723e0cac3c84b25f0093c08a2961e49ab48966361c42c9f99111587252d98395b76788400d75c66ef208ea2767a28d6f8dc3a859f39c95765d57f139e7fc14f47c908c62df051e7216d379f52028843b4d82ef49133cce8fe671ae179423ac8da5be43b01caaf425cd969300cd\nE = 8de689aef79eba6b20d7debb8d146541348df2f259dff6c3bfabf5517c8caf",
-    "0473866a03ddbd03fc354bb00beda35e67f342d684896bf8dbb79238a6929692b1a87f58a2dcba596fe1a0514e3019baffe1b580fc810bd9774c00ab0f37af78619b30f273e3bfb95daac34e74566f84bb8809be7650dec75a20be61b4f904ed4e\nM = c95943186c7567fe8cd1bb4f07e7c659475fd9f38217571af20dfe7e4666d86286bc5b2bb013197f9b1c452c69a95bb7e450cf6e45d46e452282d5d2826978e06c52c7ca204869e8d1b1fac4911e3aef92c7b2d7551ebd8c6fe0365fad49e275cc2949a124385cadc4ace24671c4fe86a849de07c6fafacb312f55e9f3c79dcb\n\nModExp = 1\nA = 935561297d1d90255aef891e2e30aa09935409de3d4a5abc340ac9a9b7dce33e9f5ce407f3a67ec30e0dc30481070823f8542463e46828d9cafb672a506d6753688cbad3d2761079f770c726c0b957071a30876c4d448e884b647833befbcd6b582787bf769d63cf55e68c7b869a0b86374f8920516cf5d528f348b6057450a1\nE = 0\nM = dcc24236a1bb94c71d9ec162a6aa4697b932717e82b667cad08b6bd1bbcbddf7cd167b7458de2b0b780486b39574e749d6405f9ede774a021d6b547271523e9e84a6fdd3a98315607ccf93356f54daa9c75e1e311e1672d0dc163be13f9ed6762f7dd301f5b0a1bb2398b608f40ac357ae34fc8a87d4fef3b961cbdb806d9061\n\nModExp = 0\nA = 0\nE = bb552be12c02ae8b9e90c8beb5689ffefe3378d2c30f12a6d14496250ecce30317c642857535a741642c3df689a8d71a276d247ed482b07b50135357da6143ac2f5c74f6c739c5ff6ada21e1ab35439f6445a1019d6b607950bffb0357c6009a2bfc88cd7f4f883dc591d4eb45b1d787e85aba5c10ee4fe05ea47bf556aec94d\nM = dcc24236a1bb94c71d9ec162a6aa4697b932717e82b667cad08b6bd1bbcbddf7cd167b7458de2b0b780486b39574e749d6405f9ede774a021d6b547271523e9e84a6fdd3a98315607ccf93356f54daa9c75e1e311e1672d0dc163be13f9ed6762f7dd301f5b0a1bb2398b608f40ac357ae34fc8a87d4fef3b961cbdb806d9061\n\nModExp = bbad67352704a6321809f742826bf3d1c31c0ad057bf81432abeb30dc9913c896c03e69eb1cde6b78ffcb320c4625bd38ef23a08d6c64dc86aec951b72d74b097e209ce63092959894614e3865a6153ec0ff6fda639e44071a33763f6b18edc1c22094c3f844f04a86d414c4cb618e9812991c61289360c7ba60f190f75038d0\nA = 855144760f2be2f2038d8ff628f03a902ae2e07736f2695ec980f84a1781665ab65e2b4e53d31856f431a32fd58d8a7727acee54cc54a62161b035c0293714ca294e2161ea4a48660bf084b885f504ad23ea338030460310bd19186be9030ab5136f09fe6a9223962bce385aaaf9c39fe6ed6d005fa96163fe15cdfa08fc914d\nE = bb552be12c02ae8b9e90c8beb5689ffefe3378d2c30f12a6d14496250ecce30317c642857535a741642c3df689a8d71a276d247ed482b07b50135357da6143ac2f5c74f6c739c5ff6ada21e1ab35439f6445a1019d6b607950bffb0357c6009a2bfc88cd7f4f883dc591d4eb45b1d787e85aba5c10ee4fe05ea47bf556aec94d\nM = dcc24236a1bb94c71d9ec162a6aa4697b932717e82b667cad08b6bd1bbcbddf7cd167b7458de2b0b780486b39574e749d6405f9ede774a021d6b547271523e9e84a6fdd3a98315607ccf93356f54daa9c75e1e311e1672d0dc163be13f9ed6762f7dd301f5b0a1bb2398b608f40ac357ae34fc8a87d4fef3b961cbdb806d9061\n\nModExp = 1\nA = 9d92629c1ab181c50c31619e8acd0d235a1f5fc7a0bef4d4fd54b4f1968d45921f8522efe88e69c6c14c576c564592b9feb00d1554b88b038934eaf4a8ce81a2582732387490181ef158360c8b2d9ccb326ffe043f776a50cb8202837f08ca743b562eefa007150ab7012c341b16248478d4775c02ad71ea13d5e82b71e2d600\nE = 0\nM = cd607549668469b792f495c141e500871880b0611c8004293a561ec7f9ab6561f8a9b90872742386adafb5cd1890e8204ae12aec529cca0a9e382c96439137f09de9973b12c8492c62847e107deabb7dd946ffbb9d0ac73b462c481092bd65326a17f21d8d6527c47a5dba50aaa20c7048b8788a49eb3ea5f29bd5cfce24eb3b\n\nModExp = 0\nA = 0\nE = 9f43dcb641f3ecf4dbc97450f2bdf3b7ec6a2f3e8e96bb1df2bf34b8d2d78e1a9018d04d960ffd0e932cfc60d3b9b923e3f9f29b3f3d61cae3a9f7245078143475c7fcb896ff200f7d94c4f2708bb42750e37c185a31c876814e4f06a00771707654e1da2fb69c16b6500b16385e3b933e2276ad3569977473f699b1c7926c3b\nM = cd607549668469b792f495c141e500871880b0611c8004293a561ec7f9ab6561f8a9b90872742386adafb5cd1890e8204ae12aec529cca0a9e382c96439137f09de9973b12c8492c62847e107deabb7dd946ffbb9d0ac73b462c481092bd65326a17f21d8d6527c47a5dba50aaa20c7048b8788a49eb3ea5f29bd5cfce24eb3b\n\nModExp = 24eaead5b57883c2f454928f8edd470a344bfe07a953194f7d635d705ef13ddfc64140c8ad6f363d4c828e7c7891a6b6d4df37335de4552c319dafd1c06d1f743240082a3535df4da1475d3eea3fead20e40815fd5a0876c881c162ab65a1eda494280c258901ca953d1d039a998bf0e9aa09273bbef4865f3054663b72d75ff\nA = a31618b4532f53729ba22efb2221432fab1dbb70853d6a1159b42fd19fc949965c709b209de106a652aa422d88922ce51dae47f7f6deaf0055202e13db79ee84fc3d3c6f4c003ef96597c49d6895fa53c22ac9e4819f7048146b5272f6279424fdb389819a0b251c823c76f4bebf4f1246de455aafe82a0d34454f5039e90839\nE = 9f43dcb641f3ecf4dbc97450f2bdf3b7ec6a2f3e8e96bb1df2bf34b8d2d78e1a9018d04d960ffd0e932cfc60d3b9b923e3f9f29b3f3d61cae3a9f7245078143475c7fcb896ff200f7d94c4f2708bb42750e37c185a31c876814e4f06a00771707654e1da2fb69c16b6500b16385e3b933e2276ad3569977473f699b1c7926c3b\nM = cd607549668469b792f495c141e500871880b0611c8004293a561ec7f9ab6561f8a9b90872742386adafb5cd1890e8204ae12aec529cca0a9e382c96439137f09de9973b12c8492c62847e107deabb7dd946ffbb9d0ac73b462c481092bd65326a17f21d8d6527c47a5dba50aaa20c7048b8788a49eb3ea5f29bd5cfce24eb3b\n\nModExp = 1\nA = a8558e7f455b27c0c46d7d0862eb409cdefbeca945e0284b5bf425b7ac0f3d316bc365594cc1639decffc621214d61479bc75135120d4ac09ea8b742ad7ec1822091b62b1c6f564fe5e2f4f5b7def92cbaaa9a898549207ab01b91c2324fbd306a87f7d6379b6fb6493c5fca76729767f136120da9c90bdc7d364f7d242d5acc\nE = 0\nM = 88f3c87ac5e3272a21b8a858da640d6939fb8113a95412c38663a0f352686d69a5d7927e60b484b9fcb8ef12978fe25ff2ebc9b61c5450e04222ef20ba3cbbdc5ec45581ce0f58e10be7bb9de7fa08752303a7a1db23b2ac9c6692ec63bf09ecd6639e06c5491ba568ea886620d71da32d329615f0e1443a75d09ae35b8a2d7f\n\nModExp = 0\nA = 0\nE = a5524b41dfc6b570df1d8f6633ac7777c1131abe3a99c6166b0d29d3b8883c41b00a0c53cdd6f42820bf05c810b6ec53e77a8c1b9344ea0c91d4f410a2f204c369f3db33bf8c88217fc2cf802a9d9bce8119242d8e781875b85431be170076498c0963574ee423551aec9557e2fc672ab1ab5d0cbb1c400535df9481e7934d8f\nM = 88f3c87ac5e3272a21b8a858da640d6939fb8113a95412c38663a0f352686d69a5d7927e60b484b9fcb8ef12978fe25ff2ebc9b61c5450e04222ef20ba3cbbdc5ec45581ce0f58e10be7bb9de7fa08752303a7a1db23b2ac9c6692ec63bf09ecd6639e06c5491ba568ea886620d71da32d329615f0e1443a75d09ae35b8a2d7f\n\nModExp = 292f0b39ca0f1c850b1a00cffd2d54924fcd5fc7e7504c9d593e6c0ff74760b1f4bdd81679fe06c50248336f3108c593fa111072ee87d0fcc89a63243a1dc89044503663eee9bc18f51c3e0193d9108303e12ac90ff78f6ec752a4386af09c42db524a7cbe9a3d4fcccd56c34d283bcc9debc17158b5fe8df0c1888a9841bf8f\nA = b4fde2908745ff92cc5826a27dcfdda09e8fffee681844fa4c7f1354d946d5d84e0e0c7a4a4cb20943d9c73dd707ca47d796945d6f6b55933b615e2c522f5dfc33e0652917b4809bab86f4fa56b32b746c177764895492d0a6a699812b2827fe701d40ef7effd78ea8efe1cac15ff74a295a09614bf04cae1a5017872ba22efe\nE = a5524b41dfc6b570df1d8f6633ac7777c1131abe3a99c6166b0d29d3b8883c41b00a0c53cdd6f42820bf05c810b6ec53e77a8c1b9344ea0c91d4f410a2f204c369f3db33bf8c88217fc2cf802a9d9bce8119242d8e781875b85431be170076498c0963574ee423551aec9557e2fc672ab1ab5d0cbb1c400535df9481e7934d8f\nM = 88f3c87ac5e3272a21b8a858da640d6939fb8113a95412c38663a0f352686d69a5d7927e60b484b9fcb8ef12978fe25ff2ebc9b61c5450e04222ef20ba3cbbdc5ec45581ce0f58e10be7bb9de7fa08752303a7a1db23b2ac9c6692ec63bf09ecd6639e06c5491ba568ea886620d71da32d329615f0e1443a75d09ae35b8a2d7f\n\nModExp = 1\nA = e2845c572b46496ac158a731f612fd40ef626fa7134755c25b1b7614f4d7b29164e6142ddb7985e4c7ebc575855ff901e95927fe98a5aea2ad3a4720c75782323bea1518b2c57790f44efd9411be4e95b3896bad1e73c59658290b309e5a7eb5ef8be08125063e57336b80f17eacee88966d12bbaaa15a25929c82e027cf696f\nE = 0\nM = cf0dee80177869a532f0c6c3a0bda3aad79bdb6b70b6c227b32d75c26e394a90c1f2a6c2bb841ba9f6556b15654a79d8b1dd0c90709a093497bf40be0807cdbb378a74de5893c25067224d3ea8d37387ed6c4a981138853cb89caa9ce6cd0f6a1e95de24d558e90960f93844db4d01e372650350d45a9d34a36042b4d4b9e78d\n\nModExp = 0\nA = 0\nE = a55703a72ca3f6074b939ed3d748196a684a3c8e411c2b39a9beb98993b6eb7ea3fa16f41bc5b5c3710b91c0fc74a8072793052f872f61695db3a2df872eaa427a110f1a8d568c85d58bd350d0df8eced7a10be80f7567360c1a8047b9c44aa2967cd0d9dd2caea2c1492358c2db4f0214da343fdf2e34272865dc5c63be2ae4\nM = cf0dee80177869a532f0c6c3a0bda3aad79bdb6b70b6c227b32d75c26e394a90c1f2a6c2bb841ba9f6556b15654a79d8b1dd0c90709a093497bf40be0807cdbb378a74de5893c25067224d3ea8d37387ed6c4a981138853cb89caa9ce6cd0f6a1e95de24d558e90960f93844db4d01e372650350d45a9d34a36042b4d4b9e78d\n\nModExp = c90e4c69df92e26549b016950b59080947f5403430698e128477782480dd70be96bed2b9042dd8c708eb432e02710555b97af11ce6fa9b53395022851c32d1f53f04237fb0763563b440ca6e81a50d909d907d9c26b7d3c420dbf88f7dadd488666848135f8cdc608dcfb0691989289fb54379c2e84c262f9765f68c012ca1b9",
-    "\nA = 882ea1b9b6c79a3b1bdfd284658cb6227ad825e0178cab713c7413c2ec34f03cfaec470c4f5c521f5e9899a2123878ff0f5b36a4196c08ad1b04d03746c4bfb5d126f5eefbfe172627d6732710a8ac8890cedbd4fdef69a19f2b3253a5aa0e5dd5484f72d59b17bdd1dad3db209a3ab839368ed3975069685911d7b35e41a9e6\nE = a55703a72ca3f6074b939ed3d748196a684a3c8e411c2b39a9beb98993b6eb7ea3fa16f41bc5b5c3710b91c0fc74a8072793052f872f61695db3a2df872eaa427a110f1a8d568c85d58bd350d0df8eced7a10be80f7567360c1a8047b9c44aa2967cd0d9dd2caea2c1492358c2db4f0214da343fdf2e34272865dc5c63be2ae4\nM = cf0dee80177869a532f0c6c3a0bda3aad79bdb6b70b6c227b32d75c26e394a90c1f2a6c2bb841ba9f6556b15654a79d8b1dd0c90709a093497bf40be0807cdbb378a74de5893c25067224d3ea8d37387ed6c4a981138853cb89caa9ce6cd0f6a1e95de24d558e90960f93844db4d01e372650350d45a9d34a36042b4d4b9e78d\n\nModExp = 1\nA = d7a99e65b8af86b1c51d851f0447e43cd4f343cb0ada7236283e69aa7ebd383826acc9809e5dbc4002d0f2430022cb026458189db3805ce2de1142a31ba71a6c064ab51f0059eb4b931b8bcbaef023c38d57aa5f3e14f5df77e547fc028702071b58bd57338be1e1e4f98d3553484e4de359cefa29c5f58d3fa5d823f389dbef\nE = 0\nM = 8315dacf124bd473c578946347e83d1b20c750a7d9533d6215591be40bc78bcca77821f8c8f95375bbd6372515ada63d22bed2fa49bd6fabb0040c538d08db25b09d2fda02a93ab086cd1c27df93c37ee9c6a0527d089179b8f92b5dc3acf5ef1c75906fb80b03f5c2442a7a4088640f66376575ecfa4c697c1a571397ee5a0d\n\nModExp = 0\nA = 0\nE = 95793fe33696f53e37498b2b65aaf27079e27acf1da97dda2c3e0803e8a02139f574e04ee03f7d1ddd029f528e3f3644515ad6f10f0beac2767f23d9cd8a8b9b6c6e376e36b64a0ae2711d7d31a5a75011641935b503110edbefe9f0ff2da27b5c5f6bb8cc151fdc86f67191bb99160c6cacc86ca368d5bdfafd3f3ff5161b1e\nM = 8315dacf124bd473c578946347e83d1b20c750a7d9533d6215591be40bc78bcca77821f8c8f95375bbd6372515ada63d22bed2fa49bd6fabb0040c538d08db25b09d2fda02a93ab086cd1c27df93c37ee9c6a0527d089179b8f92b5dc3acf5ef1c75906fb80b03f5c2442a7a4088640f66376575ecfa4c697c1a571397ee5a0d\n\nModExp = 186c50ae259aa0fd31859cbcfea534e626a254de33956d5d719334bb32e7cf37cf199a21f079a5b90497228994d05efe19ccd8c769cd81f896286e8ae557cacd1630a928c629ecdfece29ab3697794aa707734e007318fa7029b050bb09ebbe6986187c6ca843f55266d275620b3f0fec0ad5f847ce8b314d929d128b33a249e\nA = 9d5e345793faddca9867f23eeddf6816c1e837f7a2cf96fa077212514acb6be87ac01a237d8f2f1d07d27a8ddd1b0ae0d97e1bda4f205a89435017284cdedea3e407b1b940d6f52112b6359b3e86e4c83074b17c210ae2c8856b42b169b4a7a6dfa65b368a7959496cf9bb1ee93d019dbd79101830e3f5ed08604ab90890b914\nE = 95793fe33696f53e37498b2b65aaf27079e27acf1da97dda2c3e0803e8a02139f574e04ee03f7d1ddd029f528e3f3644515ad6f10f0beac2767f23d9cd8a8b9b6c6e376e36b64a0ae2711d7d31a5a75011641935b503110edbefe9f0ff2da27b5c5f6bb8cc151fdc86f67191bb99160c6cacc86ca368d5bdfafd3f3ff5161b1e\nM = 8315dacf124bd473c578946347e83d1b20c750a7d9533d6215591be40bc78bcca77821f8c8f95375bbd6372515ada63d22bed2fa49bd6fabb0040c538d08db25b09d2fda02a93ab086cd1c27df93c37ee9c6a0527d089179b8f92b5dc3acf5ef1c75906fb80b03f5c2442a7a4088640f66376575ecfa4c697c1a571397ee5a0d\n\nModExp = 1\nA = e6a079bdf7b0638d50b183475e9ddfd5cbdebfb29f5fae8e9be402a0bd36085737b556492ea7fb4b1000ae9ce59db66098129b757cfb29224275fdaa46b8b7eb18a93ca7d3e446dc38c734b683d7ba7927b008d993aab01f44239d3c76be76d1503908e9b5e73b36c43ae0771368b01f39c042693bd92c4fc50810f059e1b332\nE = 0\nM = 81dd561d5d5327fc5ed7c9236b5fb21ef713c6d5e36264ba65ccc801b8eb107b714aad65bb503bb1f4721c0a6f97e5ab89300f049f42a4616ae43d29c089c286687484d18629c1be1b5befbdd0b3cfc86b1d28add89df4cc5e68dac3f56f2490a9068ca9c634ec258c030ec5023baa9133fd2af32fd1112895f9da549d410247\n\nModExp = 0\nA = 0\nE = f0460c5ca9b3a5c2d1b93c201d020dc43e1c81d1daba432e2cd310902da23eb81a5172b0b357484eb8fa2c04c270893b8198c8ad35453405dadaf05195b3aeb5ec0ccacecb4b6227ca43b27b97e240a4148a472670ed60f304302f757495fd4a91af0fe09800db0c3043a6ae213bee6703ad80523ca433d99ca0eab1e0b7c929\nM = 81dd561d5d5327fc5ed7c9236b5fb21ef713c6d5e36264ba65ccc801b8eb107b714aad65bb503bb1f4721c0a6f97e5ab89300f049f42a4616ae43d29c089c286687484d18629c1be1b5befbdd0b3cfc86b1d28add89df4cc5e68dac3f56f2490a9068ca9c634ec258c030ec5023baa9133fd2af32fd1112895f9da549d410247\n\nModExp = 60719701a2dc0bcde281a93ce0b8421d1a718adee43c1b5d9fe9e697a48ab3db4f9f33c73cff305ab6b6c300c149b05c6b289dce4580860dc56bc59de81ac074ecebdc65aa3ca040b44e5b3c80ddba1658d78b9abbc4c77e5f171f5582e70ab4438a8e1e2f062d618c4ad09c70c73b5b5fbc9f8f0bbdf1d530a933b705f85af8\nA = e1b400cd3b1f2f1c6b437adfdb970d2c8108f1b39bdbb13582179552011c6c97cba6bff2c463212b7f62776aa3e3aff9f175990e79395e819c144350b0a23d61638d500ecc97726b098e1af334aece23a851c718612442c04eb7b3805a24cc8f5b90042145eb5e5d6a408092832b6bbeb8a621419a9282fb5c075f41c7f1fdc1\nE = f0460c5ca9b3a5c2d1b93c201d020dc43e1c81d1daba432e2cd310902da23eb81a5172b0b357484eb8fa2c04c270893b8198c8ad35453405dadaf05195b3aeb5ec0ccacecb4b6227ca43b27b97e240a4148a472670ed60f304302f757495fd4a91af0fe09800db0c3043a6ae213bee6703ad80523ca433d99ca0eab1e0b7c929\nM = 81dd561d5d5327fc5ed7c9236b5fb21ef713c6d5e36264ba65ccc801b8eb107b714aad65bb503bb1f4721c0a6f97e5ab89300f049f42a4616ae43d29c089c286687484d18629c1be1b5befbdd0b3cfc86b1d28add89df4cc5e68dac3f56f2490a9068ca9c634ec258c030ec5023baa9133fd2af32fd1112895f9da549d410247\n\nModExp = 1\nA = 9dd1e6f2d3ff24096b54e0ebf0f10e283e484a1cbafc0431adda1296ed97692f3ba99440fd4f67c96dd8bab850e1123361c99362df9ea205ff8e90d1b329459f54730992d5a360e46fcc5f5a909e691abb9a06613d6991bd7c2aa609f0d7b441d7ded0c07b8c394327672d38a905efb2d76aa3be5bb14d0c002aa37e287aee79\nE = 0\nM = fda6f9d8588e3614f5a68ce867a5619f6ddbb8d64450ff402e1c4f1a08b518f79dca21e5983c207c5b7324c16895a1e9f1282fc6cf60b0645f6b02b652ed5b129e67c939e854ab492dec30ea878c3edde10a4b7d1d14c57100c6cbcc5fc085a0d7308715ed132fb917251919c727487fedb66500d5610b0014a43419acfbb92f\n\nModExp = 0\nA = 0\nE = 8622c37631e428402343dccf8ed09d47b3f4201e95058910289a62707c3ce0b7113c390056cc4796cc9893e471b12cb3f63f900f3356ffd25c8b2fed6f6a7fba2c684eb241ca706c76cecbf72473d8a58c02338e40714b5610465cc319f0a529a7aa3898d9e638b247abd1380c6e8f7fa210c9f1a1a2164db6db83a6bba79436\nM = fda6f9d8588e3614f5a68ce867a5619f6ddbb8d64450ff402e1c4f1a08b518f79dca21e5983c207c5b7324c16895a1e9f1282fc6cf60b0645f6b02b652ed5b129e67c939e854ab492dec30ea878c3edde10a4b7d1d14c57100c6cbcc5fc085a0d7308715ed132fb917251919c727487fedb66500d5610b0014a43419acfbb92f\n\nModExp = 86fb0b8dc161c41de2adb0f3ddcc8ad49c1efd729a52793a3ac987d4011c9c1dadb18657dca718df75c8ddcc49d60f152c46ab85ae9076ee7bfd405679a7da3a5195a1bbfd7d2b998c7b135ea91f8c445cbafe1276fa502c2a85477716829a2e0d24ba02623405a3654bed8f355bc7ccdb67c3f9a01e249e358b60d7699498a9\nA = 816610e6018ca47074d55750dd16a281019dbf95dc752605794cbb8ea8d75775317ce685737859728320b529fb3b4414b40bf3a93d08d8994a21ae54682cc1c357eb529837a7b0129a0843eebd9341c9bee3a8ae30475bdbff517e885a0c9f2b6a680643bd981efb53bf9dd49f3dc3cb757e117895fb34b1b4336d9bf8384558\nE = 8622c37631e428402343dccf8ed09d47b3f4201e95058910289a62707c3ce0b7113c390056cc4796cc9893e471b12cb3f63f900f3356ffd25c8b2fed6f6a7fba2c684eb241ca706c76cecbf72473d8a58c02338e40714b5610465cc319f0a529a7aa3898d9e638b247abd1380c6e8f7fa210c9f1a1a2164db6db83a6bba79436\nM = fda6f9d8588e3614f5a68ce867a5619f6ddbb8d64450ff402e1c4f1a08b518f79dca21e5983c207c5b7324c16895a1e9f1282fc6cf60b0645f6b02b652ed5b129e67c939e854ab492dec30ea878c3edde10a4b7d1d14c57100c6cbcc5fc085a0d7308715ed132fb917251919c727487fedb66500d5610b0014a43419acfbb92f\n\nModExp = 1\nA = 9edfce4691f46eadaa2043c7b1092b831ed50f3429f0bca02f985c0b77c686d951be84d772ae4b55f08935bed6e3206c8441574f215736b5c1c1b7595b3b789b55cf56db83741b10144d6767ba2b97b23a5e83504c60e06ab22834b0145655aa0463108317a379cbfc8a93de8a66925a999b8b02bf88dd85fb9898cefe9c95c8\nE = 0\nM = dcb68f6aa530ae9b31d078e2e82670adcc98228e7cf1aa59f81e66426ef14b1591b833d889463564c75b5fd5551ea295a0da581dd80f62c7008ff0f26a1c9f4f756431d48198af157149be8698336b306b0a8b8635d3fc2c4c2194ecc4d2af31ca1892917cc2e621d702eaaeed0d9a0c3dca575451eb8bc5487e313988cae745\n\nModExp = 0\nA = 0\nE = a3be10ef04535fca6784e5dbf3733d677dedd50fabbc3a860496628950b4747a328c2ce0d903cbe1e700f0af30f59fb917202257815097a2b516df5d0a82642faeffdfc3b7883766c78fc4be5901ebef891a9ca27f3bcf00960729e659bb3fddd54a19ce628e95ab86e4c7a168588bc9f67b05dd21a583acd8dc36e615945648\nM = dcb68f6aa530ae9b31d078e2e82670adcc98228e7cf1aa59f81e66426ef14b1591b833d889463564c75b5fd5551ea295a0da581dd80f62c7008ff0f26a1c9f4f756431d48198af157149be8698336b306b0a8b8635d3fc2c4c2194ecc4d2af31ca1",
-    "892917cc2e621d702eaaeed0d9a0c3dca575451eb8bc5487e313988cae745\n\nModExp = 442866609915aa6f1bae9dfb59e721e1b63f42c0f75fbf0a88344120fbbd7aacf15208fb7c9d8bb8477d553cbd826d7e685ad764a8423e81c2131c040ee83a03cab8d5ce50866a941b48c78e9f1330794d908562d4141cfbf26e8c80c69551339eec41e37e2b37b54330f7bd75748f8d26d56ab9eb3b0c127540484c6445a7fa\nA = 8ff65e2cbcbcd8697cc3ce9a26855d6422ac7eb4e66500648c08be697e005cc3c854a54cfab91d43489cd60be8b516a9b3c9688e5e009a1689c6b164a133859a5464ef422c86344fef42cc477c9df27768377c126a066d1b62f593b7f6d6e906feaee16addb7cfbfc043d741b7dc81a87c17f167b7b8ef1b1fb3dfd1eb14102d\nE = a3be10ef04535fca6784e5dbf3733d677dedd50fabbc3a860496628950b4747a328c2ce0d903cbe1e700f0af30f59fb917202257815097a2b516df5d0a82642faeffdfc3b7883766c78fc4be5901ebef891a9ca27f3bcf00960729e659bb3fddd54a19ce628e95ab86e4c7a168588bc9f67b05dd21a583acd8dc36e615945648\nM = dcb68f6aa530ae9b31d078e2e82670adcc98228e7cf1aa59f81e66426ef14b1591b833d889463564c75b5fd5551ea295a0da581dd80f62c7008ff0f26a1c9f4f756431d48198af157149be8698336b306b0a8b8635d3fc2c4c2194ecc4d2af31ca1892917cc2e621d702eaaeed0d9a0c3dca575451eb8bc5487e313988cae745\n\nModExp = 1\nA = fe9f77f7d0475e00ec964c0effb9b8e079c32e376ce77a9c40ce4018c3df44a77b4f294d9565502b2b79accb30cb58dda6d15e1543b6d4a53296543ed11c7f51baab60283ef03fae37dfeacb431392487ec2839551a933895c4dbf18844f7b375d3e6f558d3c39993cea1bbf7fb743a6a07bd3753c03eb7298811476d7f3ff1d\nE = 0\nM = e7a96cf6fa930f73c8bdc2726bbba246001a9d27f39cc2b978c99dc6f15af0e8aaf26b565302f1112e607e2df4066948baba931b89cd9bbdea2072e05b9a4968fdf282c43d997987c3a3a0434e925a679ac81f316b7a7b724b79be3d6888b66f4512759bf66cfaaa88b9513dd27a44aaea75437268a014c4eb50ba2e50093511\n\nModExp = 0\nA = 0\nE = a0bc148ed50a9b54036bb8fa1f214979052ebd47db8b347af3bb03b806bb457b468ba34781f8a25f289a7a90af4903dc14809a166df2f4c3527de2ea6911cb1afb9071a4afbb522a7d50634d66fd584c73f32d05217dc9f7f16394c68a692a953492ca85f89cc11da95fd8cac6231647923ced48a1b3b0ee68c010286d452836\nM = e7a96cf6fa930f73c8bdc2726bbba246001a9d27f39cc2b978c99dc6f15af0e8aaf26b565302f1112e607e2df4066948baba931b89cd9bbdea2072e05b9a4968fdf282c43d997987c3a3a0434e925a679ac81f316b7a7b724b79be3d6888b66f4512759bf66cfaaa88b9513dd27a44aaea75437268a014c4eb50ba2e50093511\n\nModExp = 91fd879d02f95a9f40fcd1037726f73892caf84e9b43b4aa4126d9062a0d22c464e7af2fbd91aa849612d99d9519b724a7fb1cb018fffdcff321d883ab2519953c9f174f09dd8f13ac87339887385966eb4a94842276637b2c36c0a5036b1d3bbea438bc6efd4b4851c7ec06879d60694df894717569bcd31c4b13d80df6cbca\nA = cdec5edc1cb3ea974342b85aabc0f9385cf877ca328747d40dd4d297623ad69ab6582653faeed5aef225208305135cfbee32e066cb43e18afacea3a32acc8aabbc49617ac33e741651924ae56dd6aa044a12a1ea50fef573b5befb2f4b21b9cf83ab2aaa6fd153580a0761666ade8fb94f202a3c3dc4f33297eabb4564374168\nE = a0bc148ed50a9b54036bb8fa1f214979052ebd47db8b347af3bb03b806bb457b468ba34781f8a25f289a7a90af4903dc14809a166df2f4c3527de2ea6911cb1afb9071a4afbb522a7d50634d66fd584c73f32d05217dc9f7f16394c68a692a953492ca85f89cc11da95fd8cac6231647923ced48a1b3b0ee68c010286d452836\nM = e7a96cf6fa930f73c8bdc2726bbba246001a9d27f39cc2b978c99dc6f15af0e8aaf26b565302f1112e607e2df4066948baba931b89cd9bbdea2072e05b9a4968fdf282c43d997987c3a3a0434e925a679ac81f316b7a7b724b79be3d6888b66f4512759bf66cfaaa88b9513dd27a44aaea75437268a014c4eb50ba2e50093511\n\n# Craft inputs whose Montgomery representation is 1, i.e., shorter than M, in\n# order to test the const time precomputation scattering/gathering.\n\nModExp = 9442d2eca2905ad796383947b14ddfcc341f5be8fec079135c36f6f0d9b8b2212f43e08bf29c46167ff0fe16b247cd365df4417d96cc31c94db1cf44b73b0ee3ebcc4920d9b0d003b68e49c1df91e61bc7758a8a1d2d6192ff4e1590b1a792f8be3a1b83db3ad9667d14398d873faf5d885ec3a2bef955026fae6dbf64daea2b\nA = 3a4b4c57e62c5e9d1a9065191f8268fed9d5f6f424d071acef66f0662b8210f4c029ed991512e40c9c912043c816d2c4c5b53fa0e5c253e16808aad4225130dafbbb89fd4f30cdfc1c2f2179b636a7ddc4be579795820b4b9377637bd8a21a0ef5a90d0e0f865321eee23d9be2a3b7320b4012d02941b892df2c40bdc85c1898\nE = a2c56ea1362511cac0301918e15a9afe7d37edd438a5c3538d258ea01f0a6df758de07111e868b3ad8fc89b629b4955d78a1b3af902be1806410ddde25ccc6a196ba5949395c1ad5d8725b18815dc1cd5ac1c7dd17773f571e3f2e628255af14476e0494be23a4a4dfd18e23142f33d7a59c236fec61660e360d9676a747c69f\nM = ede35a3a7afac817d413373a2032abbc067b1493f709ae6e1282ee5469743391d891b904938857168802b7872d3cd7ac18ab249a9e540a86f970b1d0f310a4cc29df1cc9d4063d98c554f1a32f4ca5eba3523cdfb142e0fc609907c7a92bb0187009d97ec471db3545f42dd5fd29c07b7816085d09477ba31fcf90084660116d\n\nModExp = a7f5844fa9e7202d4b70ee252c9846e63d3d091b0387768ded872cec53458e19df0d9b4960226e269b8ca5dd4c4eda423a67b6dbb48235c08c12c6c7c78db47287756d3ed9cecb9232f7d18d5d80b9676cb68ba4a290c97e220beb1a069976b5e6022a4c1e5ddbeec86b62dda24ffea1deda37695c9f61a8817218e6370c0679\nA = 7d6d0cc947ceb949cdc4e9e1044f5deca5bb05a491041e0d85bc4b92a0944a57c72845fad91e59010c61ad1712bd2f612d53a846a044632262a9f2e3373b062fde2484e0c165ff947f2469f743ab6e2e5e13c640fc4029b1c9213eb8473c674e7f9e95a4a5c5636d4656c1e696962340d77b322daba47d6fc894f2a2cd9e0afc\nE = b78012afe806e2344d004c739c97324256850980ac97d88c4ed9a838517639ca112e235978d21a176c33f5a68703aba0f2a05501bbe3fc8d49a000fbf530cdb431581dfaf8683cb15a2aee5e239cbc542827100da3b47babf4a16ca7c588aff9912e674abb449e0b767a15e415f4e7f2bbd6380d7131da3df8d49b13bfd35ce3\nM = b72d5c55bd2998472f1965e75a51be6155c1ba04656da8f66bcb34db36a7b1db66a89d1d05b1bde10206acf85be7b474ab689220faf1bb52ab39d8dc00512dd4e26df1179c11b973e1274db85a88c7cc2a17113abdffe58cb930ddc5f3ccc4d68b4e65c913730509f7ce5656e8bbaba9b1be177ab9f766678f018fea05da9cdf\n\nModExp = 465ff295786a88496828fdc763e9292d557957544e9322b7996807b87fdbfa7a11614bffeec557ca831c4824c8e4ca3b1a1c7f3f4f95ec3fd6a86b73bb13d78b73af2b3c7e76954d0cc03bcb0cd606867ebb3765a8b3d0108cbe4f343a14016be9c33f6d200f0dc547e7d6b02bfab1e79dcdf9c9835a814cc6c855a12ebeb66d\nA = 89ad02bea3e9ab839a6e23f20122409daba52c68e1e893034b30d321c0305434a6af940015e3fa5ca9c35230da34beeb1ed4fbce6c1da3a8bfe3f3ae172276c1d1723b47ee61e6f8fcfdafad102d6f7ee2a79f510c7edb93096205a40a6c9e665b88b18f39a979e2e61286d939952a6f02fe8148b7515bb25f4252337cb6e60d\nE = cbd6ac628cc7afa3c61bee9c22a06a395087ec1811fe9681b55216700c435996c815e7cec8aaa90016dd2382d0306a5414630124e14f3d396a4ba02ee17851bf720f1607ff813e4bbddf01338983db12f59bd6371a738eee3eeb716f21051d6174d2d6c77602942b9edaac18d4b3a723096c0d00dd23a8a605c585022f311560\nM = fa7a3e40364c8a8d0f14f0213a3f3e035222ca0ea19d46d10ba41580e5dd2805c8a133f3856d7d5d97f922ea540e5eb0d10ad04dfdbb74f518f58da0099a6fc2b3f3def92985176e07fc78aff2faebccca10a429794e5f15ff92f75fe90f527c60ddea8093a9078c703c372ca09f7aeb27ade02f3595308c61dd9c44e62fd101\n\nModExp = cf08bf00261402102e9fe03f3074471dcf0e9b3c96d4d1503f099f24ec85e1901b023e9e048c1ad042244f5f70b38b25a99f4c0a7b57d5844bb0d0137367f45f4ce2cc7746105b77414768cb97648dc5721149aed2d4c682408cc0d50d26dd0bd77e848911f8625c727cac5f32e63bcb548f41a57d718d772f23983a42f603bd\nA = a419646a6631c2c69b18f7aa65011825eb31692eecaee9d74f92d92203811b68e9764bda31a1585bdf69b6273fc6f9f508c395ac081336506525dad88473512f08a205621ac8b16e9864c7a7c5a4f17435de00d0b32badec6ce4897e3e1076c562b6d9523f63d0b2079eaa416cb090471657763f24931d955d1fa2720c80a9c9\nE = d5a6f4a1842aaee39805356dc8d0d678ee03b2c81277345beccb2742f899132feb43271f95968a01ae68aa8277201851992dc0aa7a71c90aae71b124d873ee264ea400fb131be0fc6c4ce8c04c45f6bdaca89ac743635caf6158983d257e21cef6800d7f990e912ba21bbfb8fb779afa4abd19e07e7e07eee9908493d1ca502c\nM = e739689b6cc6def1d45fb1a2ab551643beeb303f4aaa4da47ee5e4948510f8445b4c40e99ae8354dede60b2ba6694e93bc4d573b7e8adf871b7a9a9636eb7d70f2e49328e2d7978143b177cee8374ef01bd1ee2d95862765883f5e7971668b53ef0ff41b6539faf63c397522b0bdce916388e72e26c8d3d2e58dadeb9eb5d479\n\nModExp = 827e6312ec3b14600203bb83f5b277ded197b2967363630ef673240df05edd3ba8ab2b11c86251a612206569c6c33952b31e264f129909bfe723bd0ee1624b36cfcfaa893a6ec8b5a1f7de79f83e79b459a3350f89f412ad1cfd6bc4c2a7a29272c783d6ecceeb1398fa17041835643f4debef9b5e87b098d104bb8912dddf7c\nA = b8e49c637829021d32db3a39a0c1e58cdd4c6e4eda7e8e9293be379e9c2e2d184f929d278598a81ae231cfedcf69cce4a6e31cda3c8ac14d753a7311f2436e29795f0dfb60259a0f61a997918ff984aa2284b43a9d64c974059e9682adfffd018305835f74eda8c75fe4877d811c1620f654ec9f7f32d1af5ce59115e2f41785\nE = 80e0febf369d234bf1aaad4f82df2e2ff02882c3184781f6ccdf4f7cd93b6887af86830",
-    "077c84dfb02109ada05b40970b1c65228b0c19030bd6361c3537fee22a8155c03b4e7007ca006c6daa3659518d05bb81ea0079456d0ef6116df248dffdb0c935f321f5a1034deefd5a9414a0652aa6548de33325b474b9e5a8507a082\nM = d5eb1d14af842a9973274f7463d90cf0ccff19c47d710edbae184478d4f29b02693ed7958bd487054327b9e6d8879e24c9af7730b92f323eeac05558da6c1b952e5dbf13de236050a77628bb5325fe0d14cc5773bf73338759d5ab43c212b414581280f1cee250007e53791b800b61c90de0328acd7bc43fbdda48158939392d\n\nModExp = 4a1efd29c7e78549f5cd4deed1454b37462c7810ee6a8a2493b764dfa479be13b314cf9ff98259517d61865567ef499a511630c0038c97914625df181c6fe07892f329f98b344a78d751e9471483eebaa7977371bf97bb25187ae7e93a9227d6c124ccb4644423c961a11ae59c4354f89d5a95164c23d9aa256e289e9cc0858e\nA = bd86c9211fa6a47a06e5016c46cb8a99e34a043a29e22f8c3196fa7197c26b38927b8d9bc0ddc11a5fa4bcc44deb69dbf37cbe7ebc9a2fad6c74e09ab5a9dd929fa04ab4319b6caad1035739be78ba631fb0748d9e53944836d37ccda6e6a62823c696d8f31139ccd7f2f86b22fa026ecf433cfb1271a3539ac4f1c83aaac059\nE = c40b9972006d28a84c2769a86e526a2b274f73afc7c5c6a2742166757f61b5f5fdbb228afa157af62af989ffe966f232bba9e6beef5403d1690ade31a6410f7f349a35bc4267a129afd647993df7d45cc0e1a1ba4678d7f1b6e8a344d8ff7037679e1f4db25a454e4246f6b55c416567fcfa188e8a3865115851d9edf0aa8902\nM = cf424d7af75ce7eef90cad75ae55ca8810cc7b4703fdb5bce701e7bac07e0c371cae06df2aa8facb55a0faa6793e4d2bd9d7969703743b9be170be82792aeea55e2bc0f7ab7617b276486bf474dee2f4556aab595ff3ef115139cfe5e21ccd4ee05c0e1cf901bd85df86cc17195a783b0be836d00bee82ce064077f9191188f9\n\nModExp = 3137a3049fd4ad2e26d870f5c998cf11bfe82101884a82e85e43facd0928cd7434a2e346ca124619769fa141bbe92ad6f36b99231032ddaec3b349a410f82b5ca36f45e56e5fb85dc63d32053dc90805d3f1854ab385281a71a57726bf97158494e7476057214ca7379ab8b70f5bdc15f70bdad3adf33c3a1f9cd1b6bbbad556\nA = 39a1dc6a4c3f14d9c350ee968d5ce139ef725952c967a2d1bedf48ace22091283525be03807e2e263d2640be77f0525247bcd07149bba50568cec5a082c87d72962cf9e43bcb5cdb1e7e9a650fb53e0ec2fad37f09a9f036c0d7dfa528fef846769f80a9a60854910ca1b4ee05dba82ed2ee018348d6b3e52a764b8ffae61e0\nE = deaee3a3f80c9f684ed7110c0653847ccc7be5ff6d982fd4b49f59b5dd35f7210b1077babbcedbc127df35cd469dc6e569a0f84e58149b5605c94b09fd7f0b098d02b4a04631328b3fae39e6c2fce25334225cab71829abdb9507cb903701559660f2c08c3b743336119d1260a0db27054cad3f28bc1b04b2289baa58fb33965\nM = 938388927d06ed3bb1286c0f06d3054cb0ee16dc7a0bbbf13a45293c09a5f40f1d611b2e1a1b0ec2ef109b508e27af4274954905cae52034f8740a744153b4d22059f0dd262ea51785522098ecacced6da07709ee6b5acc8c4e99331379a7c3de7f4e2d1431e43b19570140955b7bcba118dfbaa552cbfa2be531e8f781166ed\n\nModExp = c15ae334455d9f4d1030cd33e734726a27c63624c2afc576238cce5e0498298a4a0c93090a0d19568b41290303c4b558f3d9dd74f9cde8798710f68569ea0d6fd971ce67ec5b54495031de3d8842b8b49288725bee5c9f72b99054d64986ccd4e18d70d5f33943f08cd694eff538f84438ea993ebaba0910c95b3a694f213510\nA = def633b955a917569df3ba8517455eef0655e7a35985edda27097a063e0d82c7c3a76dc36c5d8a71ba9d540790ddd0ea514aaed98925f9a1808eb288d387aaf9605a9ef8a333ebee7ad7057bca012efd619d5867f02266f65976ef4b16da17468426ac4f99b3e8921707e01b4de20f6f9a068e6a19d872079a27f3a44449db83\nE = a465c47b0d15d48e01bb8b1d8e3b3253e11515f6874dbed6c25818adf1a8fd927124d5593beb367f685c11e46f18415be73ccdf16fa2e93a600b728163d21d232849e5278c3749d903edad3f1c4535a2f55a2ab65e7ebc64888bd2a0527e876ecf38cec3ab1980d08138709fad8eb88ae65d960adc3f0f8e92f784fe96fcb693\nM = e43cb9ac1446154356cdc31ec771c79b0e461e22d95185bbe1a279c0945e3af07903a0cb54d553380716fcdcafb4b7cf5dc6da481dc74a8c583d75ff6c1f8e429182d200246ebc473bb56e173787987c1b7fb2dd23f5b2e438a97bc4a1df628bc044fdd1e80c0cf37030adb7b04784dab827d0dcd64f0dbf37c980612570ce11\n\nModExp = 75c3f79ab7c991b98e65505342a8a563cfb08b5d3ccf8664c7db1de50256b1d17ebf7096dc98c7bb5d7f027a894ae5cbb14dee04d5d445e775ad7e239acc82673b0ac2d819a69c83864f34e73d9a636f05de8279619a067b4c90ad038db5910447e03841d2034635018f08cbcd21efa00994247763a249082594128112f95232\nA = 34def7d76f6f158a359fd12759fb889cdf6af0a24830dc3e84283a1ab4e9b2647a6a36b86482f829b2cdf3e3d6028f9a884b1f64f7262315446bea8b0231828e2f3d990fb103c17f820b39e4b8427c85643ceeca8f5dc8f191d1255768300e859bd7d88c770319ef38269660d221cb3bc061389b6fc0783485ef042b1c7d6fef\nE = c6c46453dd5aac6b37277a446b1d0c69cbe476eeff55b3ac35edb89ba97116b0e7783660f2c7b31b2a2d6c4709d0ab45d01a838100694b0777c9c9c14c959b07c437c73a5eabb7402f1001e802d797a2e7707285834fb6440a1c2f727f7bb84ddb2a49312d32fa0ce620c43872655cb5c394749c9e75d7fa25be00efe50d47d6\nM = fbbab6698a9142095c46b38a732592e4366c1838b84bf40f8c8fc7b630f73380a0d09765562365798f8c8030ed1b6728329d8bb06e882c35a1d59bfe84146a9db2afe42a414014e247390281c782fce806d62adb54778d2bcb49555459429d6ed446af5359657667f6aa19e8e3e0e24ab2bc312b2d90b5cb1ce6f2f15af15d9d\n\nModExp = ba16d7f3f6e162ce248490d164a13c00e7720d8a667e2d3ebeb13f1663e15ef5408d5b56cbc7bc793a8ca787cc50f8e15e0e9d4ee764531d04a9114eea556bb3e206ed7d85267151a056b6e68fbf35e03f2cf829708ffe1de13e95ecfe365aff1eea36340ffcd3892dee659fb1ecbe50f5080e54737c10f9c1ba638b14ef537e\nA = 9025e6183706105e948b1b0edf922f9011b9e11887d70adb00b26f272b9e76a38f3099084d9cccf12d04b1a99c0f654f8b9ed90c6dff9478c60bf05d58d734ab60eaefa14a22230ec60c90dc1f0704b61eef0bef345785ae0e6a9af7db069cf6bd2b4e0fe58a0ade83c7e46a04b9fe1d24cb9b65c6f80de713e61d70eae5b286\nE = d7e6df5d755284929b986cd9b61c9c2c8843f24c711fbdbae1a468edcae159400943725570726cdc92b3ea94f9f206729516fdda83e31d815b0c7720e7598a91d992273e3bd8ac413b441d8f1dfe5aa7c3bf3ef573adc38292676217467731e6cf440a59611b8110af88d3e62f60209b513b01fbb69a097458ad02096b5e38f0\nM = e4e784aa1fa88625a43ba0185a153a929663920be7fe674a4d33c943d3b898cff051482e7050a070cede53be5e89f31515772c7aea637576f99f82708f89d9e244f6ad3a24a02cbe5c0ff7bcf2dad5491f53db7c3f2698a7c41b44f086652f17bb05fe4c5c0a92433c34086b49d7e1825b28bab6c5a9bd0bc95b53d659afa0d7\n\n\n# RSAZ 512-bit.\n#\n# These are regression tests for code which historically reached the RSAZ-512\n# code. That has since been removed, but the test vectors remain. Note that the\n# lengths of the inputs, especially the *bit* length of |M|, matter a lot.\n\n# Control: No relationship between A and M except that A < M and they're the same number of limbs.\nModExp = 7f34c1cd63377bc3abf2bb5b2d1bf5f06454e1e8040fe19a72245ce9731cbee1bf9e84532300776c8021ed4f3a8de508d85b4cf320bd82065a013754857b50c4\nA = 8e4e67da6ff890643d0599387955996ef6f0c2045eb9944576ddb965ca64cdb6247727ce128ef178d4a84e5a56d2e67eb0fe389ecbf691f9244ae80f4c11b364\nE =  be99d8f0650e540b9b191e9cf96f74881b902e32ed169ffd8a1776c3f3e80f0ac765aa14615713e1549f250a20fe4ee48c4e0c6176162fc7842a0dd64d640d1\nM = f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725491\n\n# Same as above except A is negative.\nModExp = 71fa6a4c8ae75368eda8cc6282c26afa69e2af12a97fb9444f16b7dd6c99e0a5d6034cab4248cae4357346b211039f4a2bc4c5a20a297372094162417af703cd\nA = -8e4e67da6ff890643d0599387955996ef6f0c2045eb9944576ddb965ca64cdb6247727ce128ef178d4a84e5a56d2e67eb0fe389ecbf691f9244ae80f4c11b364\nE =   be99d8f0650e540b9b191e9cf96f74881b902e32ed169ffd8a1776c3f3e80f0ac765aa14615713e1549f250a20fe4ee48c4e0c6176162fc7842a0dd64d640d1\nM =  f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725491\n\n# A == M - 1 == -1 (mod M) and the exponent is odd so A ^ E (mod M) == A.\nModExp = f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725490\nA = f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725490\nE =  be99d8f0650e540b9b191e9cf96f74881b902e32ed169ffd8a1776c3f3e80f0ac765aa14615713e1549f250a20fe4ee48c4e0c6176162fc7842a0dd64d640d1\nM = f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725491\n\n# Same inputs as above except A is negative. Note that A mod M with a \"correct top\" isn't the right length for RSAZ.\nModExp = 1\nA = -f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725490\nE =   be99d8f0650e540b9b191e9cf96f74881b902e32ed169ffd8a1776c3f3e80f0ac765aa14615713e1549f250a20fe4ee48c4e0c6176162fc7842a0dd64d640d1\nM =  f12f2c19ee1ec",
-    "f2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725491\n\n# A == M, so A == 0 (mod M) so A ^ E (mod M) == 0. Note that A mod M with a \"correct top\" isn't the right length for RSAZ.\nModExp = 0\nA = f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725491\nE =  be99d8f0650e540b9b191e9cf96f74881b902e32ed169ffd8a1776c3f3e80f0ac765aa14615713e1549f250a20fe4ee48c4e0c6176162fc7842a0dd64d640d1\nM = f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725491\n\n# A is negative, and A (mod M) is the right length for RSAZ.\nModExp = 8d76eb0f8c7bc3160cc8bb0e0c3590fbed26c5932f5f525b48045c0bd46dda287ba5483f97c851fb7c12c2e858ee7a4a4d1af745cbfb3eb311fa54bea12cde25\nA = -80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\nE =   be99d8f0650e540b9b191e9cf96f74881b902e32ed169ffd8a1776c3f3e80f0ac765aa14615713e1549f250a20fe4ee48c4e0c6176162fc7842a0dd64d640d1\nM =  f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725491\n\n\n# RSAZ 1024-bit.\n# Note that the lengths of the inputs, especially the *bit* length of |M|, matter a lot.\n\n# Control: No relationship between A and M except that A < M and they're the same number of limbs.\nModExp = 8984f8c16044f9c0ad7bd72347af90f58e6e003acda92b76e3c7c4a56ea8e918409d8e9b34884d4c89d0b17cb40fe898f2627c084a0f1698e46beccbf6f48eecc281e11ea9e5135adba460ddae157f2c655b5f589ce29b254d43a960a71cede8a08dbb86be4dac22458da232fb1ec2470856827302ed772c9ddafa408c931aa7\nA = 21158da5fe20356825e72b3f5384ec57720d22f727b27ce2f945c8ee311db781add73bf8fae96b775c909bd22fca75c44c2b0584284a5bb1c07f8eefcd6b0a44047a02b185df34f897f11d4fb9a86c9eb841b4cb8d0383441fdc5af3ef385b5e8380f605d73ed41bb42eb2c2a5704d6034b3ad058dafffce83dbbfb6295daaf8\nE = ecdebd112b3b5788669449dcddbd479a203ee9ab72a9bb9c406b97623513bf0ab9a22f1f23634d269e16bfd6d3b64202b71fc355057411967b6ac70f8d9cef0a4e06819a9a18cc06bbe438243fa9759303d98be8a65dc1cb13595ee9b99f138554425d50f6fbc025d8ffa3eaea828d6f3b82a3584146bafde34da257995f0575\nM = ff3a3e023db3bba929ca4ededbace13d0d1264387b5ef62734e177eaf47a78af56b58aacc8ac5d46f5b066bafb95d93d4442bb948653613eec76837b4ffb7991cb080b6c8b403fb09bc817d026e283ee47ab2fc9af274b12f626eda2fe02004a8e27b9ed7d3b614e8955c7e7c2c0700edd079455237c4475fbd41857e206e4b7\n\n# Same as above except A is negative.\nModExp = 75b54540dd6ec1e87c4e77bb93fd50477ea463fdadb5cab05119b34585d18f971617fc1194240ffa6bdfb53e4785f0a451e03f8c3c444aa6080a96af5906eaa508862a4de15b2c55c023b6f278cd04c1e24fd0711244afeda8e3444256e51261ed99fe66beedb52c43c825b4c7a1adc7d4b111e2208ecd495df91e175573ca10\nA = -21158da5fe20356825e72b3f5384ec57720d22f727b27ce2f945c8ee311db781add73bf8fae96b775c909bd22fca75c44c2b0584284a5bb1c07f8eefcd6b0a44047a02b185df34f897f11d4fb9a86c9eb841b4cb8d0383441fdc5af3ef385b5e8380f605d73ed41bb42eb2c2a5704d6034b3ad058dafffce83dbbfb6295daaf8\nE = ecdebd112b3b5788669449dcddbd479a203ee9ab72a9bb9c406b97623513bf0ab9a22f1f23634d269e16bfd6d3b64202b71fc355057411967b6ac70f8d9cef0a4e06819a9a18cc06bbe438243fa9759303d98be8a65dc1cb13595ee9b99f138554425d50f6fbc025d8ffa3eaea828d6f3b82a3584146bafde34da257995f0575\nM = ff3a3e023db3bba929ca4ededbace13d0d1264387b5ef62734e177eaf47a78af56b58aacc8ac5d46f5b066bafb95d93d4442bb948653613eec76837b4ffb7991cb080b6c8b403fb09bc817d026e283ee47ab2fc9af274b12f626eda2fe02004a8e27b9ed7d3b614e8955c7e7c2c0700edd079455237c4475fbd41857e206e4b7\n\n# A == M - 1 == -1 (mod M) and the exponent is odd so A ^ E (mod M) == A.\nModExp = b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d964\nA =  b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d964\nE = 61803d4973ae68cfb2ba6770dbed70d36760fa42c01a16d1482eacf0d01adf7a917bc86ece58a73b920295c1291b90f49167ef856ecad149330e1fd49ec71392fb62d47270b53e6d4f3c8f044b80a5736753364896932abc6d872c4c5e135d1edb200597a93ceb262ff6c99079177cd10808b9ed20c8cd7352d80ac7f6963103\nM =  b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d965\n\n# Same inputs as above except A is negative. Note that A mod M with a \"correct top\" isn't the right length for RSAZ.\nModExp = 1\nA =  -b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d964\nE = 61803d4973ae68cfb2ba6770dbed70d36760fa42c01a16d1482eacf0d01adf7a917bc86ece58a73b920295c1291b90f49167ef856ecad149330e1fd49ec71392fb62d47270b53e6d4f3c8f044b80a5736753364896932abc6d872c4c5e135d1edb200597a93ceb262ff6c99079177cd10808b9ed20c8cd7352d80ac7f6963103\nM =  b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d965\n\n# A == M, so A == 0 (mod M) so A ^ E (mod M) == 0. Note that A mod M with a \"correct top\" isn't the right length for RSAZ.\nModExp = 0\nA =  b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d965\nE = 61803d4973ae68cfb2ba6770dbed70d36760fa42c01a16d1482eacf0d01adf7a917bc86ece58a73b920295c1291b90f49167ef856ecad149330e1fd49ec71392fb62d47270b53e6d4f3c8f044b80a5736753364896932abc6d872c4c5e135d1edb200597a93ceb262ff6c99079177cd10808b9ed20c8cd7352d80ac7f6963103\nM =  b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d965\n\n# A is negative, and A (mod M) is the right length for RSAZ.\nModExp = 9cf810b9e89d5cbc4b79ae64e123ea06d92965e2bab077df97a1b906dc2e1ddcf96a9c4ed14e2cd96309b829ea9cc2a74a7d4b43c5f34d792a7c583201427754b8f78b783608070a84b61f18913e3ced7f7f530972de7764667c54e29d756eea38a93cd1703c676a4587231b0ebfeadddf908e2877a7a84b5bfc370ecf0d158d\nA =  -8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\nE = 61803d4973ae68cfb2ba6770dbed70d36760fa42c01a16d1482eacf0d01adf7a917bc86ece58a73b920295c1291b90f49167ef856ecad149330e1fd49ec71392fb62d47270b53e6d4f3c8f044b80a5736753364896932abc6d872c4c5e135d1edb200597a93ceb262ff6c99079177cd10808b9ed20c8cd7352d80ac7f6963103\nM =  b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d965\n\n# Regression test for CVE-2017-3738.\nModExp = d360792bd8210786607817c3dda64cc38c8d0f25569597cb1f363c7919a0c3587baff01a2283edaeb04fc288ac0ab3f279b2a89ffcb452d8bdf72422a9f9780f4aa702dc964cf033149d3a339883062cab8564aebdbfac0bf68985e522c6fe545b346044690c525ca85d3f4eb3e3c25cdf541545afc84a309e9b1d7807003461\nA = fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
-    "fffffffffffffffffffffffffffffffff2020202020df\nE = 2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020FF2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020\nM = ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2020202020ff\n\n\n# Exp tests.\n#\n# These test vectors satisfy A ^ E = Exp.\n\nExp = aa6d7ac431\nA = d0e07\nE = 2\n\nExp = 12d416b110dbb4e467ff0c89a22122f4da8240\nA = 1a18cf6\nE = 6\n\nExp = 49a3b33e23d84f1ce0d5d83f5dcb651d50cf3920f0143da2310d0512a90a06cd8f38977df8a756c30883de38df092000\nA = 2a3acbd2\nE = d\n\nExp = 5b4a0d5a956f885f275712b194459980f24708bfb6393d71bd37dce852ce455724f5ee5030775fb86b4295edc98afaafc097e4d82a97c0078ec0eac763db16549c5145c4cf2d3124f88cf9a5c71da0625afb99b26801786fe49a778415dc025954021753d08691947a208b613f0be5c1\nA = 54b3ae461\nE = 1a\n\nExp = a0ea5f6a4de49beb8fb7f0dab280d6a32c5a3814c9a5153a7944cec0a9028497846a8a89044348721a0bb5f0c3ded3e980574ea321b0cdb0ead4f4e93841ea7478a7f15d9729b646a8165813a0750e8124f5465dda9b105e1bbeff18fd09c09a2e26610d9176d253b877c3a8908a6be521cbe1e472a7a1b7820e4e890f8f28aacd34609c686e76e15b01bd9324a71290812724ea564d11c874a6765b262c3e57d479da0287a76026a1e8fe53da0b02405da1d379eaa30fc65f\nA = fccec0f6df\nE = 25\n\n\n# ModSqrt tests.\n#\n# These test vectors satisfy ModSqrt * ModSqrt = A (mod P) with P a prime.\n# ModSqrt is in [0, (P-1)/2].\n\nModSqrt = 1\nA = 1\nP = 2\n\nModSqrt = 1\nA = 1\nP = 2\n\nModSqrt = 1\nA = 1\nP = 2\n\nModSqrt = 1\nA = -1\nP = 2\n\nModSqrt = 1\nA = -1\nP = 2\n\nModSqrt = 0\nA = 0\nP = 3\n\nModSqrt = 0\nA = -3\nP = 3\n\nModSqrt = 0\nA = -3\nP = 3\n\nModSqrt = 0\nA = 0\nP = 3\n\nModSqrt = 0\nA = 0\nP = 3\n\nModSqrt = 0\nA = 0\nP = 5\n\nModSqrt = 1\nA = -4\nP = 5\n\nModSqrt = 0\nA = -5\nP = 5\n\nModSqrt = 2\nA = 4\nP = 5\n\nModSqrt = 0\nA = -5\nP = 5\n\nModSqrt = 3\nA = -5\nP = 7\n\nModSqrt = 0\nA = 0\nP = 7\n\nModSqrt = 0\nA = 0\nP = 7\n\nModSqrt = 2\nA = 4\nP = 7\n\nModSqrt = 3\nA = -5\nP = 7\n\nModSqrt = 4\nA = 10\nP = b\n\nModSqrt = 0\nA = 0\nP = b\n\nModSqrt = 3\nA = -2\nP = b\n\nModSqrt = 3\nA = -2\nP = b\n\nModSqrt = 2\nA = 4\nP = b\n\nModSqrt = 2\nA = 1e\nP = d\n\nModSqrt = 2\nA = 1e\nP = d\n\nModSqrt = 0\nA = -d\nP = d\n\nModSqrt = 0\nA = -d\nP = d\n\nModSqrt = 3\nA = 9\nP = d\n\nModSqrt = 8\nA = d\nP = 11\n\nModSqrt = 6\nA = df\nP = 11\n\nModSqrt = 4\nA = 10\nP = 11\n\nModSqrt = 5\nA = 90\nP = 11\n\nModSqrt = 3\nA = 80\nP = 11\n\nModSqrt = 9\nA = -e\nP = 13\n\nModSqrt = 7\nA = 7d\nP = 13\n\nModSqrt = 6\nA = 37\nP = 13\n\nModSqrt = 1\nA = 1\nP = 13\n\nModSqrt = 8\nA = 1a\nP = 13\n\nModSqrt = 54d4cf0fafe265056a29016778cea6b712bc66a132fb5e6b6865e9b49e4c97ec\nA = 599c10484b22d0b5a115268c7538ca99b3253a311a4ab1ca11c3665b0bec393a1167d1ad94fb84cb2c7ad7e2c933e8f613bdd08fe1f1aa4a9b0b9de0c8a7c9d4\nP = cfc4ccae35458ab5be1a1bc0664188253301f8702af4f8fb19fed12de0c653b1\n\nModSqrt = 38a7365a15365e911286c1be2a7afe76ef390234d76269e04dee17313f6ea54d\nA = 1c4aabb4d8369710131c664ecf2849e963c1bc31d66e0b939bacf99a870c71f24ed71bdddcf566f3908271fee43fc1ebb51eac7e3153efae641b49d2e796a12a\nP = cfc4ccae35458ab5be1a1bc0664188253301f8702af4f8fb19fed12de0c653b1\n\nModSqrt = 35ab18a560dece04725667f640ca61d1d59f14d191f94c79f58531acd097d444\nA = 685168ae855d60eba220d803f5296459b30a289580668db9ed51bca51cc2d453a937e13819ae34f7a9a143ac96d17420c53919167e46279b562b550be1cd9abc\nP = cfc4ccae35458ab5be1a1bc0664188253301f8702af4f8fb19fed12de0c653b1\n\nModSqrt = 288370029e87024175e5bec0eab0929179f42e16995e7f6194eefc61061e54f4\nA = 2a14ab77c045bdc48220ba9c463e1a4b4049cb01edb53be0937767eb2ec19b7d719855052281250a36a0b76d9a5d967d0756e1ded7a052f7056191ad66bcfc9\nP = cfc4ccae35458ab5be1a1bc0664188253301f8702af4f8fb19fed12de0c653b1\n\nModSqrt = 32255cf01dc943577ec2bcb221b98491d7a1130d046d6c68e95fedff643ce3a4\nA = e26f6dd46a513a1dd3fb14b71be1d4c9e9d79eda1cde10ea4d1eb8abfd4d5857572205e247184dd0cbefa37b5c0bf680ba2bd28c5741f725cfe2aae37419baf\nP = cfc4ccae35458ab5be1a1bc0664188253301f8702af4f8fb19fed12de0c653b1\n\nModSqrt = 5172345e801ada63fbc4782e32583cc3b4fea88b9e6dfd542f3542f8538ade66\nA = 40dafa8342b302bb04b1f3ddb3b9015a8fc1b597857c115b40631c7be9e22de89358fca23b331596ee5ff304dad7811e6d8e8822f7aa533c9e7c882634ea550\nP = a6813d316f9aca30f98b4f864b8b4b8f51493af930bd4d3a1b205a710e99add3\n\nModSqrt = 4dcf63c423bf0e39aca2293d57f6792d023db649d6719fe936446904b9f7e60d\nA = 5bcdb514bbe84261e169203e8017909b60c9bb330400c766ee01b0189378e70e61867a164a12643ddc9e94b61e09e5b158cbe85be228a3cc48f95a552958b8f2\nP = a6813d316f9aca30f98b4f864b8b4b8f51493af930bd4d3a1b205a710e99add3\n\nModSqrt = cf77c5c2d12a500b75cbfb1f3e66ee75d886b9365cf4f8b4d1bd18a6be0f387\nA = 4652ddc2ea7b460d8ec3c9059b8f9b5dae6cac55b51f2ad86fcb336b25235737965cc515e2ff0b54835015b7ebeeda6fadd986471d8cb424d309fc353d1e269\nP = a6813d316f9aca30f98b4f864b8b4b8f51493af930bd4d3a1b205a710e99add3\n\nModSqrt = 1e0549e4c5a26023e9d24fd8c67419960746f82b1ecd113bdac66f570a475d87\nA = 5f4a6d450ab1390d96ab1deaa0ba18f897cb63daf0c9e1ef6c08e804c26b5e842f6c08f13db5d4a6e88f07af2a3cb04fa06fc3e59c410b9356f025ed81acc74\nP = a6813d316f9aca30f98b4f864b8b4b8f51493af930bd4d3a1b205a710e99add3\n\nModSqrt = 144481a781d831c1ca046ca9e322d79ad4d2c6dd9f780bea9d1ced9cd20b7b23\nA = 4c254fabca441017132b9eacd4ca40a336db3e5c09715773fa07af095989a91cc968ff07a9ff56ed06b0ce0c5269f7b2ab68564ecab9f4467a7e96b6cc6b21b7\nP = a6813d316f9aca30f98b4f864b8b4b8f51493af930bd4d3a1b205a710e99add3\n\nModSqrt = 216fecc7667f488a3d2d102a38b46b4860ab858300b8638af4f34e1103fd73ba\nA = 17878f8048227573a9d70f53c0e76ff13fe9f56e9c984c92514d3d13dec23c816661f0618d21371b80dfd885cb59551bdf80046f65f22ea9b89c78645a6e455a\nP = bd37c850cf7d702bac879f3c21a51a5a4df2b8eb0935861e0753a6eb62261a95\n\nModSqrt = 458e5e789ccd2417174f7e30bb31914b9656bd8cf2b9f5a9752a8737a67707bc\nA = 5c7d39a4bb04e69201aa519f80ee7e62ea14ca55e13656d1da3f45367e2fb2d061aa2940708d02ac67d35cd2ccf54a1bf95bcbc759779e692cfdcbb3aa1a05b\nP = bd37c850cf7d702bac879f3c21a51a5a4df2b8eb0935861e0753a6eb62261a95\n\nModSqrt = 543125a16c2bb8b8f8a2c39c497e5224ec77533602d7dbe24002e32dcbd2ef1a\nA = 3413afae333b2ad9ff45c7f3c7e5934b3127e8b1a55225958ee6ccf42423e81559bf070ad3f3353b78c0ffd41475af49f59d268ef78bdae879f5155e8d1cc07\nP = bd37c850cf7d702bac879f3c21a51a5a4df2b8eb0935861e0753a6eb62261a95\n\nModSqrt = 10e16859c67bdb2eaab52a7c847dbf37162eda258a9f6262ebacfe4cbbbc1080\nA = 21ce7905894faf220bdf4a82a2d855994ca2dc9feaecaa53c7f146e1f49934215695e9bb46ba370b7005a90c399674caa8969eb442e7914d90f749774d7fd194\nP = bd37c850cf7d702bac879f3c21a51a5a4df2b8eb0935861e0753a6eb62261a95\n\nModSqrt = 32a00586adc6f6cc2b1a04e1be0ab569fde235e1436c38b6af92bc5ebd60bc1c\nA = 350da4fd8cf03c12f7dd6ac6d3ab801a3413964083e374662aaf878d6838b97d4feb9e52cd307a25b113e101661a865463ee2480c626aa4e2ec437d72e7bae4c\nP = bd37c850cf7d702bac879f3c21a51a5a4df2b8eb0935861e0753a6eb62261a95\n\nModSqrt = 971f75bc7afa8b4b50f1d4b05e52deac7d4836a08d30546f29649bf1ca6a247\nA = 655ed4c5d8d0afb4f9360372ee1ef1303898d2423e585108a3303faedb55064d2ef25666ed4c4d71fe6063fea1f3142b435714b0e30b339dd791d347c884654\nP = 9810151ad4bc9c5d68fc326395b509f2625bfebca1c3801ad4da7539fdbaa6f7\n\nModSqrt = 48fa882b7cb6a29de9e3769f72eb67f1efd4d2af56f0c7e410c610efcbce2065\nA = 14f3503f33b243800eac1defaab33e04c01e80163fb3efd03860970cc016832431ca4fc6d1b760f4f40166b0b8b3c40dbebc81460cc10890172243770338f090\nP = 9810151ad4bc9c5d68fc326395b509f2625bfebca1c3801ad4da7539fdbaa6f7\n\nModSqrt = 236fd7e397ea7f8bc2a288eb7236ca41936fa702b7dccca56c8852e147511f7d\nA = 1bbd0980feac854782813bcde4da85e8a054549a1b515e065da4236528035e756882e29e762cf60453e375cca9dc6ff637f9558bf86646e3b928f68f82af7efe\nP = 9810151ad4bc9c5d68fc326395b509f2625bfebca1c3801ad4da7539fdbaa6f7\n\nModSqrt = 693f0cbe8c81b0afde0cd2f83e53795dcae6b0cc4ba930ab5c752400d787f14\nA = 7b20f9664b23907e152ab8c9a907f72e8670c1c38ab4cd1411ea7c2159c09aa131afe068929b8e6ad1409b74c04975180d1cd0a9fa74e923c3fd451e8da2c34\nP = 9810151ad4bc9c5d68fc326395b509f2625bfebca1c3801ad4da7539fdbaa6f7\n\nModSqrt = 4a086c50b0bad576501ddb6280743b2c9d247841eb7f14d90561432ff7dca6f0\nA = 4367431ec0cd0d7626538b93a090c30fe0c97c18ca03b97ddae304b619112b5b4d02bf0f041fa3fd673f9ef2ceb07eb2079d11c56dd903b1a87e8252a97b8079\nP = 9810151ad4bc9c5d68fc326395b509f2625bfebca1c3801a",
-    "d4da7539fdbaa6f7\n\nModSqrt = 18f8433fa468d8065157708f1f1e53b8e31d39c6011fbc2bad93de1b5548e19c\nA = 739c032bb4139c199c40f548d37234298772e4ccb9d3ba28412b60ad23b4c465b0787e2382f1c5a4a87af2d20eb978b7dcbe73f2112249477d15c8a85e54a79\nP = adcd56924f73836ebe4dccfe006ad3b1e5076562cd11b161642cab7af2284659\n\nModSqrt = 49e3c8eef5e067cabd51a7c01384ce05ab8f4342f655559d8a689eb7b20e0106\nA = 18400c2cc3e06b99b4e39c77b9af5ff0e9c683f1708321afa4cd5b6988d13b36b1d9eb4379b7902d9ceb40c03f814b2b6a01b90509bbb4532f13ab1571c4d04a\nP = adcd56924f73836ebe4dccfe006ad3b1e5076562cd11b161642cab7af2284659\n\nModSqrt = 35548c530745f440329325cc8a5fbd90c16a7f0788879a4869bc4d4f73acda0e\nA = 181a3c5ab02566e7166c4d6d2f2bd4a8ecc25991a98d270bde80cf4332766a7068b14240bf5f5dcd45e90ef252596da3eb05b11d68b2063f7b3a825742593ca9\nP = adcd56924f73836ebe4dccfe006ad3b1e5076562cd11b161642cab7af2284659\n\nModSqrt = 1ab7046e6af061ade5f9719008fa4d989007e2a579a134a5b9f19ec410984096\nA = 1008a03e211fab0d45856377079bc96b0776c2d4c0175661f3493246cea2ab0a02a706c85314fb707ad9906bedb2cfd577d62092ae08ff21d7b949373ea954c7\nP = adcd56924f73836ebe4dccfe006ad3b1e5076562cd11b161642cab7af2284659\n\nModSqrt = 2be9e3e7515960d90f115b89f60dedc173a73ce163b4036e85b7b6a76fd90852\nA = 392053a9f0100540a8e1a0c353e922068a84dad3a4a8e8962fbc0bee2b6a06e20d08ade16eb1409a16acfcac3db5c43c421505e07035ca308b15c4a6db0864c0\nP = adcd56924f73836ebe4dccfe006ad3b1e5076562cd11b161642cab7af2284659\n\nModSqrt = 5b301bb93bdcf050183107e36258b53b4805918114ea1c2227b0911d5b4dc077\nA = 55e55e5f94dc3d7aabc921f6469d85fa2e1e92a87347c57afad5872306ae69f9fb99297d1e3e793dd9e8632244208154de5da7114fd876383bf1422f7ece024\nP = d43280ac150f725f4a2a1dceb1c79bcac57855a4eba72ae93762d09bcb2444fb\n\nModSqrt = 2df9609e2f5a5156c3260461b2ee52eacdef00bd8b091479813143a6c5283f71\nA = 2099325b7f12fe77353ddf3f2b2c5ef77b49671b150af954cf84e9675e3ecde3e057084641a633d19533b4712ab49924c8b5c31d591abcc88291f51253fa2a7\nP = d43280ac150f725f4a2a1dceb1c79bcac57855a4eba72ae93762d09bcb2444fb\n\nModSqrt = dfab751710e9008e25e422d1199d6fbec4dc7fba35b4da9d225a746eb4126a0\nA = c006af53d4737fb293584df6ffe2e4cb3fd8dc77fb7c1f13b97bb9c249e3ee5fb9feff7488265b3093906c08a4946f142ac7b491937d24bfba6413366ce371d\nP = d43280ac150f725f4a2a1dceb1c79bcac57855a4eba72ae93762d09bcb2444fb\n\nModSqrt = 26bc030008d6c60a09fb0e16093a649fcb40c6c21a8e2da2353ba4b07c4f85d5\nA = 1eaabcfad2ed349ac9356e6f4da0b301266ddde811cb0f817aba8f5c10fb8b8ba9d0ef2dd386b668f16eac296118fdb8cb7afe1b865648c81c2fa3cf21f2711b\nP = d43280ac150f725f4a2a1dceb1c79bcac57855a4eba72ae93762d09bcb2444fb\n\nModSqrt = 35051b1482ec2578f3dc0000a422cb5111e43c37f1ac20b1844d3de2128c4556\nA = 315ff9de178681116f2a5fa78eebf4818e1d680435eacdfaf9d0e5c4fc01fc034b352c82fd52c81ca30d68864952dacc99d08269c9dd7ca99ccf22da98c3840\nP = d43280ac150f725f4a2a1dceb1c79bcac57855a4eba72ae93762d09bcb2444fb\n\nModSqrt = a5474252885cacf004c460a7793ff0b0a2187bb1a9ed700ae3470199faef71f\nA = 19856fc1351c4b02abf573bb2fc6ff92355fa369d62bb8f2260fa772fb1693f509a56cad661930abcac049dd70f4b16bed4a4c172e73e772504c9990ce7f92f\nP = dc315fd52684fba79e577a204de9053b11a5d7a414263fec9eff6ff62188829d\n\nModSqrt = 12daf4722387ecf47de1b0b6b110a062dc5ea2685bc9dbde66b8d15622985029\nA = fb8479787069116abc42abfd7dc0c24d2ad04fe0c04b42a6dff714af715d17e0fd77855f950f264542b06d48e8818de813ddb7975798b7debefcdaa5ff86beb\nP = dc315fd52684fba79e577a204de9053b11a5d7a414263fec9eff6ff62188829d\n\nModSqrt = 397996ed5c0ac6ad32e43c337e9de421b87774cc162bf7ac7bbedf4a9029255e\nA = 5aa04353321bd2de92481be740357f979da464b53aa39111fdbb734cf7af6b3857d1baa08d3a126a3dd34a2fbae2bf2b84e900686c1d31505b390185acef5fe5\nP = dc315fd52684fba79e577a204de9053b11a5d7a414263fec9eff6ff62188829d\n\nModSqrt = 2cf4b844a54ba359dc592ef1b49f43fcfeae84d1087edfefdd0b9174b43c0a3c\nA = 365a8650510bcfd8fa87432f167cf487234c215857403b9270b5eebeafa48cd6da47fd60dc311b94d1d72baad0447c31f0b212d755f46c256e16e5e015e6546e\nP = dc315fd52684fba79e577a204de9053b11a5d7a414263fec9eff6ff62188829d\n\nModSqrt = 9277c73043ff767c3fa606f0cd66b9d854a600c8c18287f191ce277758c3f31\nA = 62cec3901626d03e8df66299a87c54b1f7a55cafc99f0b6bba1b5d51a3d2b7d2171c9135a9d8a5346d436e0136b12e515e703e3cd84ecfe154eb94c6772a6d72\nP = dc315fd52684fba79e577a204de9053b11a5d7a414263fec9eff6ff62188829d\n\nModSqrt = 4189e5a90c1b1abdc1c7c05b3587e6f362e06f927b6cf5f0d271aab3d6f90765\nA = 336b8d0f9dac842c696bc020f49c6aa023842c16f2052eb02f17959006554ca0012042c80c72590f21c6bf5a3714c9cb552aa69730e33db93a56a909b273f39\nP = 9df9d6cc20b8540411af4e5357ef2b0353cb1f2ab5ffc3e246b41c32f71e951f\n\nModSqrt = 36ccd38cb5a6bd8a73bca55936a2227c503664422c2296faf7e2b1c6a375a43a\nA = fecfd60a376befbe48d2c4f6d070d716d2f403cd5daefbce62b720df44deb605162c8f20f49fd7ec30d4f8e70d803d45b3a44b5d912baa3410d991165d7c507\nP = 9df9d6cc20b8540411af4e5357ef2b0353cb1f2ab5ffc3e246b41c32f71e951f\n\nModSqrt = 198fc8569be172dc9b71023ed3d42d2ba94bae4099643f6517ab03f540527fdb\nA = 65bebdb00a96fc814ec44b81f98b59fba3c30203928fa5214c51e0a97091645280c947b005847f239758482b9bfc45b066fde340d1fe32fc9c1bf02e1b2d0ec\nP = 9df9d6cc20b8540411af4e5357ef2b0353cb1f2ab5ffc3e246b41c32f71e951f\n\nModSqrt = 21b7f74c30ded681d6138cf8e6fd798f32a049e94138e982f1845df3dc9e686f\nA = 9a30b791c1ba4f394b4e3dcd5837e474237f4fe8987b255c098a47b2c14c598ec69d2beae444dd4fe9c4ede8173d2b187677cc706a3c28f3b81627d8a5fb6fd\nP = 9df9d6cc20b8540411af4e5357ef2b0353cb1f2ab5ffc3e246b41c32f71e951f\n\nModSqrt = a1d52989f12f204d3d2167d9b1e6c8a6174c0c786a979a5952383b7b8bd186\nA = 2eee37cf06228a387788188e650bc6d8a2ff402931443f69156a29155eca07dcb45f3aac238d92943c0c25c896098716baa433f25bd696a142f5a69d5d937e81\nP = 9df9d6cc20b8540411af4e5357ef2b0353cb1f2ab5ffc3e246b41c32f71e951f\n\n\n# NotModSquare tests.\n#\n# These test vectors are such that NotModSquare is not a square modulo P.\n\nNotModSquare = 03\nP = 07\n\nNotModSquare = 05\nP = 07\n\nNotModSquare = 06\nP = 07\n\nNotModSquare = 9df9d6cc20b8540411af4e5357ef2b0353cb1f2ab5ffc3e246b41c32f71e951e\nP = 9df9d6cc20b8540411af4e5357ef2b0353cb1f2ab5ffc3e246b41c32f71e951f\n\n\n# ModInv tests.\n#\n# These test vectors satisfy ModInv * A = 1 (mod M) and 0 <= ModInv < M.\n\nModInv = 00\nA = 00\nM = 01\n\nModInv = 00\nA = 01\nM = 01\n\nModInv = 00\nA = 02\nM = 01\n\nModInv = 00\nA = 03\nM = 01\n",
+    "def8105ac28f2ecc8598ec0c4bfc9c1c80222fffc776722eb0621cdd8a0d55f08767fc2922282a76e529d81e4d6e21a2542b8c9a403709ed1132e3b52786b81e684591438fdddb5df2f0b72e6b39cd2db6c0cc55c759c2dc1b6ccc20a5cfd10c6fd345fc766035c7478570d4ac534db3fdb718e2bdad3d096b137bfc09a562043800957e2afe4fdcfe292881f6189edfce52370c0438c2822ce3b14d73b3eff32f7e5ca97e989326b4e3a8fa35544193f8590bbb0ddb1f914894ab87998090771a0be1fd23917cd792be86ea0b98e6eb24\nA = -ec953f1b7ba7d561edaaa23076987daf86f50e9a66c36f0993290549a9006dd9d424885c0fa77295cfe34fc81c5edce9e2371b3039ea18d8f998d1956196284e6d81eb1c62ecaa8cf3fcaca28ca7e64342803c8dc3c139080bdd4a1ff30d7288b085a579d9e90903bd363b48f2072bb6fbfbd9ba2cab30a8a63784d246\n\nSquare = b33f4f3ae453058f4e865ec78f0844bab7af66a97dc2f265ca73ae2232777474bfdda39e10652d7386c16f145272192af728893c3d8a8e92c60d77722b924c30269ff5a399a2449ce15e50320c528c22655ad06227ac4efe5a993179ec61c2fc9115f89d75b53961fd16f7797657f6fbf55662b019608a1d30f64a2c0838e0018b7526921fdd34fd462bfcb2462b7065e2bc7abd57d71371e45dfd8fcfcc00a71f7e45430820747c9a060b72e4f6d2919cbffd00beb0c31a2bdc32afe2cc540b38dd04a2b73ae5ba481a6e535f37a757bbd6aaa972986213afadfa47cb7a15a6f1d443f93cb0ed824a10b4b7d82cae524a096b65ccb39be3c37c07f59\nA = 358da59ef65f62f633675764e292e5a68879df24a4727eca1fc4d232b3a6d936976c92eeb11456b5e8c11319838c145c6529d2f3acc828e55b8274bfe9afb5db241b102715f8e8164e454ef39f13ff1b37cf367a5a66c4f743c750896b7c3c29026e448bb36c6c06b0d9a3d048086ef0c3cd922a02e794223f388b5d646db\n\nSquare = cd4246489f6f221f920acbd8bdcdd17f47d2b77268f72254de4190685c123e8c5eab8517fded1852e8316c9e549d3fa355142d91b2921a3c94aafd8862cd2235429340da38a2af131b8d002f17662354f5805f6a7af7afb6dbd2f641036600614cea42bd8b24d86a5109eed29c0865a5f30c5291b1d1ef3223f9b9826dee773d98ce972da92daa19e843f84ca5f1cd77925a3c1117242ab0fb509b94a83f8de4fc8d21f856f37a4d025b3024bd0dbb6d8acfda4ab2993fd6eb7a7448d4f66ec725d37f0eb14eb242c0ff3f0c4572ba6b98a4ce905fe1b7ca3daca56c225171428c56af938fb66b37e99e54139157bbf41f536989ef813af738837afcd62290\nA = -e53ad05c88568f09f616797f0b7f2756fb543d691ec2a5b645c1e5892a247302826419a35b1348cfd2c1c569c23c31b4c46d6c57d4a488c29ab5beb77904d4adfcd0a01ea0a26bb0cc8790441cc2c8c900f030d7315b4319f1a3cf5685a140e03abe6b94730ad79e8de1f4a0cded86a3d6cfe2db267fa7dc9b2bb32872a90cc\n\nSquare = eea8028b26e0df090504d54da714a6f5f2695202e53cff479c78aedd47a8dc676243ec586740fde53b3eca9ca02b91031ce766242184109503fbe25b1b6d318e3cd5970fabd16dfa22984dd2e9f1e0f14c189170fc69c031d66663703e6235a942d51a4545bd7b0769d01d302ce2b00b83f01568a1e378f61fd0ca6201b0490330580cd9de85719e174a71915d7efbf65cd73d8f4e66f27e0dd3144d58ec09ed0f7ed7d1238ee596922807100fb7a11127944ddcdec6a9ca3bbf6df7301e354f3f049bfb7c275b43c3d8cda5907a932fba507c9145ea3166081c1b48fcc710ee32cd931f936c796b14f8a78a592e67753a7c9e428a01719c8ba82652f3a89fae110\nA = -3dcb44be1e54c5a5d7db48055ca9afa1ebe2ae648aa6e16ac497502a7deee09ffa124720fad0ab163ce8b3ea6a90f110ea52b67dbc424d0cf1e8c9726dfd9e45bebcefaa5cd5706edeed27896525f31c6bbea3d67ee97badefabf3e2532470b66e3ae3100f66ddf50cf02fc3a8e3f44c304251d3b6a7ca3a6e4bd5d16a41bd97a4\n\nSquare = 0\nA = 0\n\nSquare = 1\nA = 1\n\n\n# Product tests.\n#\n# These test vectors satisfy A * B = Product.\n\nProduct = 5befab3320f8f90542f3120235abd926aac3805a19e343f690\nA = b057af553afb120db6b7764f8\nB = 857734c4c27a1d17f7cf59dee\n\nProduct = -ab1ce167f4b2945c55ae3f87df50ad07d4be87cf9f8aa07b0c\nA = ae7a6a87ea8981a567d0b3ecc\nB = -fb0fed5f8c737bcacef4d6cb1\n\nProduct = -c2606cd48e6b075c8da79eb4668e7157f1f175c2860fd4c475\nA = -c28dc31984d4583e9d45424c3\nB = ffc4581a5c3f885cf42767e67\n\nProduct = aa6805b5408aff7f914472756da07830dcad902834dbdd6944\nA = -ffa07ff9f503511954e5dd3f9\nB = -aaa7af472ad8957763f5a7c64\n\nProduct = 58ca2569173389df29b5ce4b784086055dee821a7243db7210\nA = af417d936f4690008811a1ae8\nB = 81b26b80b43aa65aa55ded52a\n\nProduct = -a043d31dfce8bd01724d31c863d0a64f1bf013509d77737c42\nA = fb5fae5edefb6997d44a1ecd6\nB = -a336e50c6f7845a1686cc88a3\n\nProduct = -b5d6a45ffce851b201239d938ba551bab7dcb59fc11fc35fce\nA = -f918faa58bb57a2ffb8b01f05\nB = bae08c3006fade695029a1df6\n\nProduct = 6f2fde7d1a18625d727c6345ed85e597d546d9228bf7f0564a\nA = -8d108d7a16f0696d4ceb24445\nB = -c9c764cae465207097ef8d2c2\n\nProduct = 93808b1140841dc9735cd61c6f855ddbbb83066689b0d7e1a0\nA = b386d08daf3fa2154e9c768d6\nB = d2557dceb2d02d04d9c578670\n\nProduct = -ad04212ca8cadb1f7861c5130ba3a747046a2a7e4a0c72b69a\nA = e4e5f7d1311e0c5f2e404d55b\nB = -c18057a328d8c7375afdfd4ee\n\nProduct = -685e75c232f2b4a0e455fe5ee8aea52f292ad8b8178320e692\nA = -a683312f132b2320632e74ef6\nB = a0758f12791453b4af354730b\n\nProduct = 6f588c53185c503dc5b0dc3002d3817ca2e7eb2370b3e9a647\nA = -d70c9b93170261091f0c53f27\nB = -848c86c51a186ac4c9080d3e1\n\nProduct = 5e3bc5a04e054a9a244bf7c86cae215072fdb70e9199989427\nA = 898b64ef09d7cf63966e1a3b5\nB = af638b12f26aa5d12e97439eb\n\nProduct = -8d8372b235b16108285203c03a8aef6fdd3c0e1a9fd31d4f68\nA = f6003dc83818c14fbe36c9998\nB = -9343f6cbcc81fa4c9399dce5f\n\nProduct = -5ee6509abeeb7af7fc5caef40d1822ad3150c8d74f522dc7c8\nA = -875ff6f56ca72cbdf614bb9ca\nB = b375a68a21dfb1f159c22fa14\n\nProduct = ada25be404a17385af5a330da799e5909da81bfa0715baa6f4\nA = -c9b8df392e76abc3eb7d5ce04\nB = -dc5ab818c70594dd917b4243d\n\nProduct = bb24422ee4656ddfcd50ec38201b15baf679d3b75e5cb878ca\nA = f8e12cf4defe388b78510f687\nB = c07ee817b4ae95c2915b88966\n\nProduct = -93da296ba164c7220a17330647aef0980c94eddd2cfa2a3b2d\nA = bc5dc74ddf7a1363d1c2b1f25\nB = -c8f069bad7f93cbfe6df51169\n\nProduct = -6b2e1d132c4e0b0dc9b7e7de7d424fda5180480cb5ff47c755\nA = -a8048acb66a8bb88df39266e7\nB = a34e0b265d71435ae8c92a463\n\nProduct = 6ccb2cd93783576a8602ae43f41c786008b6623a4cca0a010a\nA = -b071f1f54790c951c1dd2a1cf\nB = -9dd89bb4d9b546207e282e2d6\n\nProduct = 5c742ba47d0d64bd97509927ce957deedb855766cc24c60016\nA = b44f3f252c368096fa62747f2\nB = 83439b97dbac579fa4f7b7d23\n\nProduct = -7347ba65691c913286c2fb55e45b177f031c1d86ae0e9f654f\nA = 937cf0643ffa53cdea24d642f\nB = -c81881f78243dd5737a7d28e1\n\nProduct = -9bc0649a703674e59f83ff9b8a560e5cbf51f65ca310f80f95\nA = -b536f8d9769be6f62da941ae5\nB = dc0746fb101881ae0cacde6f1\n\nProduct = bf4992fc3a124de350f9fb90ea825cf663b1fa051282ef22e2\nA = -ff7eacc7de1bb01d668c693aa\nB = -bfaa6627f9fc7ba68ae41bb2d\n\nProduct = 7c8992d34cc0b63f1c953f68d4e12a99d3f3a34d16bd76caa9\nA = 9e0d5a850d078890a983c0ec9\nB = c9b72c118b3e1f1023a696ce1\n\nProduct = -a75840c95082b9a0ae0d6e0a4eb5e09288e4e2a66e9697d9cd\nA = b2b042a21045a74ef1a5091d9\nB = -efbf8b120b384e869692a1b15\n\nProduct = -a510b333bdb4ed7479c142e8fbe2b12f7671a42acbe16c0998\nA = -e7fd5e0bb5496b9d876c27f65\nB = b6262653b2be44501af1d85b8\n\nProduct = a1c1e90afc4684754155526e307fc6ed798746f347bae2c880\nA = -b84674832b26ded0a690a8ff0\nB = -e0b7bdf2fd05a038ed3640b78\n\nProduct = 5588e0c33bffbefcc5695ca0615abd383343f21a8a0d22b222\nA = 80cad81ad9a66ab6a1c2e5669\nB = aa0453a77c8af1584f54750d2\n\nProduct = -6460c2fcd6cf3304ab163ea883ac48e2031cd10f2e9014c0ab\nA = c49ad3d7c8848d4fbf913b10b\nB = -82b3dedbe3cc7cd532ad632e1\n\nProduct = -a18717330b711669e85abde8c4dce426529aa621ba3da2a477\nA = -cab4a9c0a331a5a5e826dda1f\nB = cbfee5041c13075dfe3399aa9\n\nProduct = 8ab6282ee892b53c083d319a9dcab48af97a1ac8493c0bfcad\nA = -f7d13e47f9aaac8c25f9bf75b\nB = -8f4aa95231c1e2336aa092297\n\nProduct = 8f2d1c23c78777ed371f13155445ca3c88cbc0a9b299bdf9d3\nA = 9d8248d00defce1ad081337c3\nB = e8b479295ecd9cef7301f24b1\n\nProduct = -86d5e0c5b581fe59819730b4b71e33d1f85f9ab504c7dbe2d6\nA = b21b45e88acff48562a19729a\nB = -c1cdfebccc763beeac394b997\n\nProduct = -484ca05aefa113bdfcb1bc623f730c9f9555b462a8ab4c9606\nA = -8c12b406c02c4417163c0956b\nB = 8422b15c80c1c087b17eedd92\n\nProduct = 614c3c91f60050c785fd229a3ad74674577a90cacb654e0a5c\nA = -93d45bce155a23a397506d96a\nB = -a87e339c3fd5aebede5fb1b36\n\nProduct = 9683285f194a7e4feeab196a36bdfc4f828035fd184b9cc692\nA = f196d8fe760fdcae7eb60e2f7\nB = 9f7d88a2163ad818bf3a6377e\n\nProduct = -988a64599c19cc64f3cadc1a83fea6550185f6cc3ab82af822\nA = d0584b2a306671e4d2c9d0c7b\nB = -bb6e7559df199c68d6df3a3c6\n\nProduct = -68456814cb0edd951196d04c853172afdd5787a5bd69a57876\nA = -cefce1b0a1fb22862418bb597\nB = 80f614139947aea5e76cd55fa\n\nProduct = b4b1cbf5d6566e7a57aee0cc5c9c8ec4ad885e8766aa7662a4\nA = -d68ed1bea046c6cad057e21db\nB = -d7988b9be54f6e332d019032c\n\nProduct = 6b09212675ff5257a1384371e17b37dcc268bbb141577902e4\nA = a8208053adc20a609d5d01404\nB = a2fa927c5458c4fe662d7a3b9\n\nProdu",
+    "ct = -8361bc26f9bcf55f677e047d822d3004027da0d0455b244d10\nA = e82b6410b29020c2d6810a977\nB = -90ddfe0e7f0d6b9cdc0815f70\n\nProduct = -f1b6da00923fd513a83e32040a515649fbd362f69ebc016d9f\nA = -f9b697d9ec774a8d1ee5ea905\nB = f7ccb46a8869cb028492bed53\n\nProduct = d06206963f2e150bacdb32c823c3a47f013d5a267c3c0d0c88\nA = -ea8e63afa99c719897ad7f2ab\nB = -e36f11f55b6148d1b4f46e598\n\nProduct = af774a5eae6084df5ca499ef005642730adabf6a4f9533e2fd\nA = e4c7af7eea3ec9cc2443b7319\nB = c457bc264c8461789931baf85\n\nProduct = -76350f428bfbb95e6c253ec0f457aa84cebe8c7cb1af2a2120\nA = 8fd1ff97465775d44dee58ae0\nB = -d268a7d328f44baf80e35119f\n\nProduct = -787ae3f114f9a8dd4d249d5d3f3b0897b02564b9469416cefe\nA = -bc0b398bd0ec045b0cf147b7e\nB = a4050955c234e473257d0c641\n\nProduct = 9d6320b3d4aabac097a079b9bd2aca7f1898bcab0f23409fd0\nA = -9d7a4ebac630cc0662b816fb5\nB = -ffda517d3eb3214986b04e290\n\nProduct = 80bab8bd800ac8c9dc3bb57dca306f10af6fd88c5d8314833c\nA = 834bc50140d6c6ab938dc58b6\nB = fafee47793cbc533b3c66af3a\n\nProduct = -b08920f5922226b1dec87151ae087d8a7e5c1aea8c9be148b6\nA = bfd5b1ad323c79428cb2db36a\nB = -eb956a10edebdd658e6810fcf\n\nProduct = -6d428e08e8350bb4b0fae3b662c82df2aef7beadaa17430dbb\nA = -a57da276998c548101f514e9f\nB = a9040c1909712e1149d295765\n\nProduct = a57da276998c548101f514e9f\nA = -a57da276998c548101f514e9f\nB = -1\n\nProduct = 14afb44ed3318a90203ea29d3e\nA = a57da276998c548101f514e9f\nB = 2\n\nProduct = -295f689da6631520407d453a7c\nA = a57da276998c548101f514e9f\nB = -4\n\nProduct = -867614005cc204a8d19720fe13\nA = -a57da276998c548101f514e9f\nB = d\n\nProduct = 12bf3b676f64e5929d38c35e803\nA = -a57da276998c548101f514e9f\nB = -1d\n\nProduct = 24d8f92c68303ed0b96f91a8167\nA = a57da276998c548101f514e9f\nB = 39\n\nProduct = -49b1f258d0607da172df23502ce\nA = a57da276998c548101f514e9f\nB = -72\n\nProduct = -6fd5e6ca25c3d51b2e529f22173\nA = -a57da276998c548101f514e9f\nB = ad\n\nProduct = 1276d4705b81b82da4c7e82559d7\nA = -a57da276998c548101f514e9f\nB = -1c9\n\nProduct = 1ddb9abfc5d4017f068a67b5f4fd\nA = a57da276998c548101f514e9f\nB = 2e3\n\nProduct = -3a8b41c914b1b4a4e341433601f7\nA = a57da276998c548101f514e9f\nB = -5a9\n\nProduct = -97c0f4ba414d6e7d4c8b7ced84d4\nA = -a57da276998c548101f514e9f\nB = eac\n\nProduct = 1198739e0c23639c176d46d13f7c8\nA = -a57da276998c548101f514e9f\nB = -1b38\n\nProduct = 159150954ee0dedf541e4dbac0ec3\nA = a57da276998c548101f514e9f\nB = 215d\n\nProduct = -441d4bc44c86f02ff12c3d91a1562\nA = a57da276998c548101f514e9f\nB = -695e\n\nProduct = -64726b76005ebee27592237ba5dde\nA = -a57da276998c548101f514e9f\nB = 9b62\n\nProduct = bbe4ec7cf7c5bbd198e0ea86bb658\nA = -a57da276998c548101f514e9f\nB = -122a8\n\nProduct = 21f717d05681fd2eb1796776a69ef7\nA = a57da276998c548101f514e9f\nB = 348a9\n\nProduct = -396ac788a1748bc6955f99be4d2c64\nA = a57da276998c548101f514e9f\nB = -58d1c\n\nProduct = -54a213eb083aed1a04f3d1b2da62e7\nA = -a57da276998c548101f514e9f\nB = 82eb9\n\nProduct = 1366fb9c20fb14b8b9a9be4b3e3dde1\nA = -a57da276998c548101f514e9f\nB = -1e037f\n\nProduct = 238d65fd26da4733e5d93ab2485d40b\nA = a57da276998c548101f514e9f\nB = 36ff15\n\nProduct = -38272a99be154d531e922be405aee9a\nA = a57da276998c548101f514e9f\nB = -56dd26\n\nProduct = -64651b62b6a454c08951632c7f2c398\nA = -a57da276998c548101f514e9f\nB = 9b4d68\n\nProduct = fb272e3597b816144f8b945ae6130e0\nA = -a57da276998c548101f514e9f\nB = -1848320\n\nProduct = 280d9f5ed7243712ecb9a7c6358bcb8b\nA = a57da276998c548101f514e9f\nB = 3df5795\n\nProduct = -2fbb6bb8e1ba78cefc47fbbc20e188ee\nA = a57da276998c548101f514e9f\nB = -49d6652\n\nProduct = -57f29c13691ffa1642d2860dab9d288e\nA = -a57da276998c548101f514e9f\nB = 880c2b2\n\nProduct = 139c19d7668e6aabf2d7206cb0723ed34\nA = -a57da276998c548101f514e9f\nB = -1e55aa4c\n\nProduct = 2950ce04bf0cf836d4fe94b88fb757d0a\nA = a57da276998c548101f514e9f\nB = 3fe968b6\n\nProduct = -5175239488dad05a58414251496d2a06c\nA = a57da276998c548101f514e9f\nB = -7e020414\n\nProduct = -945ff0ed38bc6020cf679cbd3e0758c6d\nA = -a57da276998c548101f514e9f\nB = e585e573\n\nProduct = 11c69ae98f6b27e95477986f796bc67c8c\nA = -a57da276998c548101f514e9f\nB = -1b7f653f4\n\nProduct = 209afe75e8fb5ac76d13c06b545f5d4d73\nA = a57da276998c548101f514e9f\nB = 3270154ad\n\nProduct = -386d64b215e41506514f4988ed237e4da2\nA = a57da276998c548101f514e9f\nB = -5749c891e\n\nProduct = -6c13cccdb1d140d0babd52707ea72fa278\nA = -a57da276998c548101f514e9f\nB = a72fb6288\n\nProduct = 136228a8a45540372b9b3cd7f82021f6546\nA = -a57da276998c548101f514e9f\nB = -1dfc08a2fa\n\nProduct = 1f0ad3babf9d132eaa08cf5cdb8f19dbf01\nA = a57da276998c548101f514e9f\nB = 30050f2e5f\n\nProduct = -50d615ce183258e95af77319b766fac81e2\nA = a57da276998c548101f514e9f\nB = -7d0bf92cde\n\nProduct = -817d358293b86a56a4e881e50257c549471\nA = -a57da276998c548101f514e9f\nB = c84efb12ef\n\nProduct = f09b9e80be251de474d726b16e25a6865fc\nA = -a57da276998c548101f514e9f\nB = -1743322a484\n\nProduct = 22996cb0f9c60e35dce49f3825f8a479db26\nA = a57da276998c548101f514e9f\nB = 3585acec11a\n\nProduct = -2b307a37c91791a61c0691858f5f783e4678\nA = a57da276998c548101f514e9f\nB = -42cf6be3e88\n\nProduct = -8826698fcba6c30d755fc523de1cc25301ae\nA = -a57da276998c548101f514e9f\nB = d29cc8af592\n\nProduct = ae37fc99fd419809310782714530d7428d77\nA = -a57da276998c548101f514e9f\nB = -10d8059d4a29\n\nProduct = 1d544a20f9bc7d95ab67d1f65743979f23bba\nA = a57da276998c548101f514e9f\nB = 2d5eadef1c06\n\nProduct = -367897184e9929a0294d320f10278889fbeb7\nA = a57da276998c548101f514e9f\nB = -54431582d0e9\n\nProduct = -943a509076a00060a2e7fa1cddb7468d734a1\nA = -a57da276998c548101f514e9f\nB = e54bb102f4bf\n\nProduct = fcce6e42879af5ad13545c0bcaab85b690cea\nA = -a57da276998c548101f514e9f\nB = -18711db522cd6\n\nProduct = 258c49f86d0cbb14ae9edbd3456be8cede2022\nA = a57da276998c548101f514e9f\nB = 3a1562c7c269e\n\nProduct = -4a8bbce59ad7daa51136d557f7fa16e9a2faad\nA = a57da276998c548101f514e9f\nB = -7350e780b0f33\n\nProduct = -82f53ec9333275d5cc271876a7db936db49280\nA = -a57da276998c548101f514e9f\nB = ca94ad312dd80\n\nProduct = 11daee4fcc713db5b2806e47fa5dff3b5b770eb\nA = -a57da276998c548101f514e9f\nB = -1b9ed6758f9635\n\nProduct = 17038cac4f0c94dc24985ea108ae6682e175752\nA = a57da276998c548101f514e9f\nB = 2399b8a9b1116e\n\nProduct = -37e5f14394bf347a3ed061769fe8e6424af4348\nA = a57da276998c548101f514e9f\nB = -567840a7569fb8\n\nProduct = -9253d4a32a88d8f725984514d969012ead7cc9a\nA = -a57da276998c548101f514e9f\nB = e25b246f733f26\n\nProduct = ace3648371c16a931d29004e79f5b9678391da5\nA = -a57da276998c548101f514e9f\nB = -10b717b27b6a13b\n\nProduct = 1faa5b45d04c143c339b09d3aad94d39b94ef960\nA = a57da276998c548101f514e9f\nB = 30fbd672e106aa0\n\nProduct = -3fdfe246d27aae0d08d63b2bc501461d2bff3b8d\nA = a57da276998c548101f514e9f\nB = -62cef5f078a8253\n\nProduct = -5b792bfaeff04ee3d948cb343a249d49eb344f57\nA = -a57da276998c548101f514e9f\nB = 8d805ac65649c49\n\nProduct = c5f824406161eec321da5a58e3e00d393b55abe9\nA = -a57da276998c548101f514e9f\nB = -1323dd41d2e1e077\n\nProduct = 2226dec8a57be8e84e42559007e2d101ccbe67f8d\nA = a57da276998c548101f514e9f\nB = 34d47842b5d0be53\n\nProduct = -340f50f812c7420b502000940788a700f6769788a\nA = a57da276998c548101f514e9f\nB = -508836d8e1193d36\n\nProduct = -a00f1d96e19c590479625c5329a87774b5964cc78\nA = -a57da276998c548101f514e9f\nB = f798fc858657f888\n\nProduct = cb94f830cba8997331912a6a31c34f1bef826d121\nA = -a57da276998c548101f514e9f\nB = -13aec7a5c52a0883f\n\nProduct = 16b45140b048d6dc0b9fc811df7ce7dd88357fff04\nA = a57da276998c548101f514e9f\nB = 231f27f3e347bd67c\n\nProduct = -2aa94179351b4e87de5849ab619d94f47450640199\nA = a57da276998c548101f514e9f\nB = -41fe3ec2189599cc7\n\nProduct = -5489401d3da93158d4284e557d74016c0a7cfd935a\nA = -a57da276998c548101f514e9f\nB = 82c5281df41bfc066\n\nProduct = ae04d5b212ecfc9a6d7df07794d565df52991fb70e\nA = -a57da276998c548101f514e9f\nB = -10d3139229f5d02432\n\nProduct = 27821bc811f45d63089790b41d307be978d4b19564c\nA = a57da276998c548101f514e9f\nB = 3d1da85cc012b3e234\n\nProduct = -3de3c9e9d7fa3020a578706339314890dccf63096c2\nA = a57da276998c548101f514e9f\nB = -5fbcfb28bfc9044bfe\n\nProduct = -627dcb299a6720044abcf11469bdfd3f951edbb5bf7\nA = -a57da276998c548101f514e9f\nB = 985b930517b78e6ba9\n\nProduct = cc0622441497a37fddf1856d5e2c99df52b99ea4573\nA = -a57da276998c548101f514e9f\nB = -13b9b88948fb7e95cad\n\nProduct = 1a5168e1a492210591ad1ed660adde9110390e4caf32\nA = a57da276998c548101f514e9f\nB = 28b631c6e04b6ab0d8e\n\nProduct = -4d8ec27b7460ce616421b9f5cae708c2ac241daa59b4\nA = a57da276998c548101f514e9f\nB = ",
+    "-77f99bdf1eb09da6dcc\n\nProduct = -55afd796db7bce822a00073fc8926d3bd0c79772f036\nA = -a57da276998c548101f514e9f\nB = 848cdd6212b9bb3620a\n\nProduct = dc494b0d73e8ec07cd2bb6dd8191d2b4d48e7700cc34\nA = -a57da276998c548101f514e9f\nB = -154c39567bd8be5f6b4c\n\nProduct = 240e9301b4345b914ecd91a49a0e651524dcecb6fdc6c\nA = a57da276998c548101f514e9f\nB = 37c6e7ee89cf87674814\n\nProduct = -39002ecfd6d96661b336157ccef6536756ad2e9219be3\nA = a57da276998c548101f514e9f\nB = -582cdab09915a652203d\n\nProduct = -695f49fc891d53f396f0593efae3973082b76d4f9e944\nA = -a57da276998c548101f514e9f\nB = a30074dbce2246af043c\n\nProduct = bba2b7b45b97cb0d7fb30fed95089870742ad69e7aed7\nA = -a57da276998c548101f514e9f\nB = -1224195afc7b394ae8cc9\n\nProduct = 1910edc278515ab7d4cc09b496dc3c06c32c75bc7368af\nA = a57da276998c548101f514e9f\nB = 26c6701c39334169e7bf1\n\nProduct = -3670b7f9b661aba35ce50984d83173c84c8fa60e04d100\nA = a57da276998c548101f514e9f\nB = -5436e84b4a29858a68f00\n\nProduct = -7fa0d3e0082b37475342b7e22e5dbad7b8d4cb5d64f871\nA = -a57da276998c548101f514e9f\nB = c56e0f44fc63bca242eef\n\nProduct = da7fe3367ce640fa5941c033ac1874312f10ba5950da75\nA = -a57da276998c548101f514e9f\nB = -15200043166ff309f0426b\n\nProduct = 1871d72481f66b1d413100edd6b339cbbaa67b3b2b3cd57\nA = a57da276998c548101f514e9f\nB = 25d057879db26fa29a5e49\n\nProduct = -3cf1dd1e2df3456757d72f35353c3c7a659b2ef844ad857\nA = a57da276998c548101f514e9f\nB = -5e46be70de21949df67349\n\nProduct = -5e861cbe47aefab2a7ea59292aab1258932b9a322f66e63\nA = -a57da276998c548101f514e9f\nB = 9238670897685a6c9cbdbd\n\nProduct = f623344788efb857db55c924e95a437effa4dc8bb2bcd24\nA = -a57da276998c548101f514e9f\nB = -17cc0ec84c228225a7cf45c\n\nProduct = 15514c916b0ae7cde6add16c629d3e19ba52a101d75dff72\nA = a57da276998c548101f514e9f\nB = 20f9f925b3ed307edbb154e\n\nProduct = -460cf5b14f9d0b547c3084bf44207bf881745c409b08d07f\nA = a57da276998c548101f514e9f\nB = -6c5cbfd29f3dae1dce99221\n\nProduct = -5ddf7fb91d765af97dfda5333d8779e80837c2b51cfb4f43\nA = -a57da276998c548101f514e9f\nB = 9136aa79080defd1bcf90dd\n\nProduct = 12c1a0edfb6ab6a0caae2553fb3743827e1470a8954e0a3fd\nA = -a57da276998c548101f514e9f\nB = -1d03b512470dc3052779f3e3\n\nProduct = 28388a244214abf046488a8d95308d95f021eae4b994a5a52\nA = a57da276998c548101f514e9f\nB = 3e37dce784274962ff862e6e\n\nProduct = -4da476e76119deef291c0f56934a912a0877278a19a561ee0\nA = a57da276998c548101f514e9f\nB = -781b2f2dc40094a7f8fed520\n\nProduct = -5792496d33dd45e225f9dfca17419a04e075ffc0c90b37b82\nA = -a57da276998c548101f514e9f\nB = 87772a4fb582acafd3e4ef3e\n\nProduct = dd3a3506a7d748de16fb43d666928a87de0354d8e8a1bcaaa\nA = -a57da276998c548101f514e9f\nB = -1563841bf7851ff158a395716\n\nProduct = 24e8fb09a9ab0808ff643122479dea5ed41060c6c5b74e8752\nA = a57da276998c548101f514e9f\nB = 3918c30b5568318a58e9be16e\n\nProduct = -366c125f96b38b58d01c939c27c4100af3377eabb792b5491a\nA = a57da276998c548101f514e9f\nB = -542fb814f45924aa09a16f2a6\n\nProduct = 0\nA = 0\nB = 542fb814f45924aa09a16f2a6\n\nProduct = 0\nA = 542fb814f45924aa09a16f2a6\nB = 0\n\nProduct = 542fb814f45924aa09a16f2a6\nA = 1\nB = 542fb814f45924aa09a16f2a6\n\nProduct = 542fb814f45924aa09a16f2a6\nA = 542fb814f45924aa09a16f2a6\nB = 1\n\n\n# Quotient tests.\n#\n# These test vectors satisfy Quotient = A / B, rounded towards zero, and\n# Remainder = A - B * Quotient.\n\nQuotient = 1\nRemainder = 0\nA = 8cdaaa7c422f3c2bb0ace2da7d7ff151e5bdefb23e6426cf3e6b21491e6e80e977bfa6c65931a8dee31fc7992c0c801d5d7c\nB = 8cdaaa7c422f3c2bb0ace2da7d7ff151e5bdefb23e6426cf3e6b21491e6e80e977bfa6c65931a8dee31fc7992c0c801d5d7c\n\nQuotient = -2\nRemainder = 1\nA = 107f0e6cebfe22ac11294a06fed2b994d01c9b3610d50bdd254adafd08c93be8ebdd1e85e1286fe9c9e682a90cbbd6351681b\nB = -83f873675ff11560894a5037f695cca680e4d9b086a85ee92a56d7e84649df475ee8f42f09437f4e4f34154865deb1a8b40d\n\nQuotient = -4\nRemainder = -2\nA = -3d8746ae2123c2d3f1d35910b42af1f86f5e81f8e98986cea20b2a1bdb8af6cf111f1258f112c837accdf4868463fe9eba536\nB = f61d1ab8848f0b4fc74d6442d0abc7e1bd7a07e3a6261b3a882ca86f6e2bdb3c447c4963c44b20deb337d21a118ffa7ae94d\n\nQuotient = 8\nRemainder = -3\nA = -5645d65662eaac73050de06f8f982a9b2ae680467712284be3e2b0e58ef4bf4d72b5be5e12ee1fd803b47f161759662ff5c4b\nB = -ac8bacacc5d558e60a1bc0df1f30553655cd008cee245097c7c561cb1de97e9ae56b7cbc25dc3fb00768fe2c2eb2cc5feb89\n\nQuotient = 10\nRemainder = 4\nA = 813bc46ee19ffeab364073a89f96913f340d43ee72129ea9edac1beb4ebe1336450d2eabc7b26e51c400cec60d6ee459033b4\nB = 813bc46ee19ffeab364073a89f96913f340d43ee72129ea9edac1beb4ebe1336450d2eabc7b26e51c400cec60d6ee459033b\n\nQuotient = -20\nRemainder = 5\nA = 12805392c55ffa0e27e85e15f2b339872793664e9ed3074cd2600aa52459a57197130d1ea46775ef43115c9413248cc7b34805\nB = -94029c962affd0713f42f0af9599cc393c9b3274f6983a669300552922cd2b8cb89868f5233baf7a188ae4a09924663d9a40\n\nQuotient = -40\nRemainder = -6\nA = -3579fc4d6083394c691b060cf9e20318fe17da0487337f76710bd11512578830ba94ac7b587a2d5ab7cb4afe611e349cdcfb86\nB = d5e7f135820ce531a46c1833e7880c63f85f68121ccdfdd9c42f4454495e20c2ea52b1ed61e8b56adf2d2bf98478d27373ee\n\nQuotient = 80\nRemainder = -7\nA = -74ebad4b39ebaaff82cd91082408c979527907c363d8f0f75db410523f8477c074c45ff85851b6275b1ebc5279029818e78d87\nB = -e9d75a9673d755ff059b2210481192f2a4f20f86c7b1e1eebb6820a47f08ef80e988bff0b0a36c4eb63d78a4f2053031cf1b\n\nQuotient = 100\nRemainder = 8\nA = d2d8a4419fb3b1c22bfca04ca08c2ee066ccbc9fce2f41861b5eef91efd3c13eeb7eae5abea0ef1849662cfdfef7bbff892c08\nB = d2d8a4419fb3b1c22bfca04ca08c2ee066ccbc9fce2f41861b5eef91efd3c13eeb7eae5abea0ef1849662cfdfef7bbff892c\n\nQuotient = -200\nRemainder = 9\nA = 1bf534da2f4365c96fc5dd4928e73ac24b157b5136ead90cf6596033ec387a2c14bca828000ae1725f3a5ace8ad67a8c07a0a09\nB = -dfa9a6d17a1b2e4b7e2eea494739d61258abda89b756c867b2cb019f61c3d160a5e5414000570b92f9d2d67456b3d4603d05\n\nQuotient = -400\nRemainder = -a\nA = -3a172cc9483774544311a1366659d9e61cc9fac7dc11c68e36aa991ef4d5e96becf5bac3e0967c904d926617ea11bb9551b980a\nB = e85cb32520ddd1510c4684d9996767987327eb1f70471a38daaa647bd357a5afb3d6eb0f8259f2413649985fa846ee5546e6\n\nQuotient = 800\nRemainder = -b\nA = -5ecff3a3e47fa615b6e3ce2dedfdeefbfe1d437c394631820968a9650b59dc3a2dd1c9a0b06537e4e5c408a59e580921503580b\nB = -bd9fe747c8ff4c2b6dc79c5bdbfbddf7fc3a86f8728c630412d152ca16b3b8745ba3934160ca6fc9cb88114b3cb01242a06b\n\nQuotient = 1000\nRemainder = c\nA = d3ef80fca0ab3ac3432b22e2b485131d816810c39d02a9c82dcc05ec5e6406bc216026de3abe53ab103ea3b2ddbc2ea377ae00c\nB = d3ef80fca0ab3ac3432b22e2b485131d816810c39d02a9c82dcc05ec5e6406bc216026de3abe53ab103ea3b2ddbc2ea377ae\n\nQuotient = -2000\nRemainder = d\nA = 163956bc32325f28f48d41d32bb08d2a9c4ccbb0d818368fb13941e82b27da21d04094f7e897ce79c2d0ff8470505f1ef63fc00d\nB = -b1cab5e19192f947a46a0e995d846954e2665d86c0c1b47d89ca0f41593ed10e8204a7bf44be73ce1687fc238282f8f7b1fe\n\nQuotient = -4000\nRemainder = -e\nA = -3763f8e43bd05e6ffeec6d509bbe6ff9a9022ced8cb191c9abaf5fd0e0b75a53e2ad581455e3af09e702a77b164ed3fb54ae000e\nB = dd8fe390ef4179bffbb1b5426ef9bfe6a408b3b632c64726aebd7f4382dd694f8ab56051578ebc279c0a9dec593b4fed52b8\n\nQuotient = 8000\nRemainder = -f\nA = -531dd44dfa9e79a5aec8fa7c84bd3b753c146770d22d2c14a6d2125f7ab95e9b320e84c31cf3e0d883e1295a220f2a546550800f\nB = -a63ba89bf53cf34b5d91f4f9097a76ea7828cee1a45a58294da424bef572bd36641d098639e7c1b107c252b4441e54a8caa1\n\nQuotient = 10000\nRemainder = 10\nA = 900996b61f58713f0755e68bbdfa4e0bb47f034bb0304f77829847923d14715def1771f43b526c41b9667438b434d2b966c20010\nB = 900996b61f58713f0755e68bbdfa4e0bb47f034bb0304f77829847923d14715def1771f43b526c41b9667438b434d2b966c2\n\nQuotient = -20000\nRemainder = 11\nA = 179d7ede3db0c105525286551331d5b9e1f97a7883f0c13cf250afe9765bb5aaa527af7945c19cdd4596565cbc8532a3cfa5c0011\nB = -bcebf6f1ed86082a929432a8998eadcf0fcbd3c41f8609e792857f4bb2ddad55293d7bca2e0ce6ea2cb2b2e5e429951e7d2e\n\nQuotient = -40000\nRemainder = -12\nA = -293dc443c294c6a6c53dd49e84f58305d59a432afb6c7ea2039cd02a513231239571ae07f29b5427e869b9faa485511ca45980012\nB = a4f7110f0a531a9b14f7527a13d60c1756690cabedb1fa880e7340a944c8c48e55c6b81fca6d509fa1a6e7ea921544729166\n\nQuotient = 80000\nRemainder = -13\nA = -5b637eb8aa51ef15a18d9b144031c9756527fc0fb96c84b6df03700e5079ae1b3e96940a2c1e07f3b47ad8a9b2b8ca99171a00013\nB = -b6c6fd7154a3de2b431b3628806392eaca4ff81f72d9096dbe06e01ca0f35c367d2d2814583c0fe768f5b153657195322e34\n\nQuotient = 100000\nRemainder = 14\nA = 87c846f5469d4c5819aed0c7e77797209b2c",
+    "1b83a7a0e2be70280b9f30946b5db9bd0f25a06cf4bdba1c7183a1b9eb75c19400014\nB = 87c846f5469d4c5819aed0c7e77797209b2c1b83a7a0e2be70280b9f30946b5db9bd0f25a06cf4bdba1c7183a1b9eb75c194\n\nQuotient = -200000\nRemainder = 15\nA = 11c2a4509f419aa977c3d37fa446fcf21b4b3b9f983fbaddeba4f51c285ac4032200711a54cc6edf24297b1f3d46ad020131a00015\nB = -8e152284fa0cd54bbe1e9bfd2237e790da59dcfcc1fdd6ef5d27a8e142d62019100388d2a66376f9214bd8f9ea356810098d\n\nQuotient = -400000\nRemainder = -16\nA = -39e37ae0edd92b957e84682358039f5e432c42492a44f3de01cdf74d643760260f2837946608663e12291e9b0695449c1153800016\nB = e78deb83b764ae55fa11a08d600e7d790cb10924a913cf780737dd3590dd80983ca0de51982198f848a47a6c1a551270454e\n\nQuotient = 800000\nRemainder = -17\nA = -72f725edd5a3dd6f20b5e9ca7da08a99f8ec9214c80588182c0d42e03bcff34b488b28c03cdf41813a6193c10672a8ee68f6000017\nB = -e5ee4bdbab47bade416bd394fb411533f1d92429900b1030581a85c0779fe6969116518079be830274c327820ce551dcd1ec\n\nQuotient = 1000000\nRemainder = 18\nA = 966df62c26acab2d3d1dbe729e48d0181c68e9f5eba45f6caefa38d60e34057d09fe620abb8640cec8cac755957aaad7c6fd000018\nB = 966df62c26acab2d3d1dbe729e48d0181c68e9f5eba45f6caefa38d60e34057d09fe620abb8640cec8cac755957aaad7c6fd\n\nQuotient = -2000000\nRemainder = 19\nA = 190790727c1514b4ef83a1c6aa07493c0af7087fbc8a675bfd9a1e97b8ef80ef684219d6c6f1a5fb5b919f105fd7717cdd5aa000019\nB = -c83c8393e0a8a5a77c1d0e35503a49e057b843fde4533adfecd0f4bdc77c077b4210ceb6378d2fdadc8cf882febb8be6ead5\n\nQuotient = -4000000\nRemainder = -1a\nA = -22d115ab02f8663d8c009960086a0275d301d358cd3b250bb9e7c16cc6ebed4a8fbe43bbced856d93be64a17377d95f5f9c8800001a\nB = 8b4456ac0be198f63002658021a809d74c074d6334ec942ee79f05b31bafb52a3ef90eef3b615b64ef99285cddf657d7e722\n\nQuotient = 8000000\nRemainder = -1b\nA = -41f2e708ba47494a13607223b08e6d99c0b4247436632961d873804e83446dc97139ffaef3e25969950bd4b5bb4ff73b1a25000001b\nB = -83e5ce11748e929426c0e447611cdb33816848e86cc652c3b0e7009d0688db92e273ff5de7c4b2d32a17a96b769fee76344a\n\nQuotient = 10000000\nRemainder = 1c\nA = e4b52f78179039499c2f6b500840f41103fbd60eac0d7082297236f25189c18a8301a92f533945047fbb83427dcade334336000001c\nB = e4b52f78179039499c2f6b500840f41103fbd60eac0d7082297236f25189c18a8301a92f533945047fbb83427dcade334336\n\nQuotient = -20000000\nRemainder = 1d\nA = 10888959278661bc36089519a215bda60f9ce24ff7c0ac1f543b6e652f94dbff1f32aa40cad2b4b4d676f16948551501c29f2000001d\nB = -84444ac93c330de1b044a8cd10aded307ce7127fbe0560faa1db73297ca6dff8f99552065695a5a6b3b78b4a42a8a80e14f9\n\nQuotient = -40000000\nRemainder = -1e\nA = -3ada453530a180fda58533ab8c62beb4f693a134f512e4d23e487dac3b575e5390c0a90992400e402bb47aac93d46ded55f54000001e\nB = eb6914d4c28603f69614ceae318afad3da4e84d3d44b9348f921f6b0ed5d794e4302a42649003900aed1eab24f51b7b557d5\n\nQuotient = 80000000\nRemainder = -1f\nA = -57879eb5d92d565daac3ac5173639bfe44b6ecc69ff770af57bd79c9b93841c5677042cb362b794f3d8b24b0d3b73ed1cba58000001f\nB = -af0f3d6bb25aacbb558758a2e6c737fc896dd98d3feee15eaf7af3937270838acee085966c56f29e7b164961a76e7da3974b\n\nQuotient = 100000000\nRemainder = 20\nA = 89a2f1792afc54467955839eddc9ef2e37d391ce7a1a4a205291220c1f49f59ee31fc7a7a7f7706c199bf5c8c951a0d0743d00000020\nB = 89a2f1792afc54467955839eddc9ef2e37d391ce7a1a4a205291220c1f49f59ee31fc7a7a7f7706c199bf5c8c951a0d0743d\n\nQuotient = -200000000\nRemainder = 21\nA = 1c267719338a4562e934bc57fabe6da86ca534a34244bd38c15032f01f47c2fd498c83f644b345c5c661ada0e586a096bb63000000021\nB = -e133b8c99c522b1749a5e2bfd5f36d436529a51a1225e9c60a819780fa3e17ea4c641fb2259a2e2e330d6d072c3504b5db18\n\nQuotient = -400000000\nRemainder = -22\nA = -250249f2185d4b428fa9534f03ef3cbed535bd31c56c0b273e6c3d35e0266f7777a6e59a99da5738b8e3af8ac60061d6716ac00000022\nB = 940927c861752d0a3ea54d3c0fbcf2fb54d6f4c715b02c9cf9b0f4d78099bdddde9b966a67695ce2e38ebe2b18018759c5ab\n\nQuotient = 800000000\nRemainder = -23\nA = -710b30c23c3c4e646ba90da33d2ce35af2ff181c40b02e3ffa607966730c6b6e274dd4c3c78e578e0b10f431f2d832274bf6800000023\nB = -e216618478789cc8d7521b467a59c6b5e5fe303881605c7ff4c0f2cce618d6dc4e9ba9878f1caf1c1621e863e5b0644e97ed\n\nQuotient = 1000000000\nRemainder = 24\nA = 877f1caf75e7166ef18484d0718947893fd1ec016984387debc55c19e378a487a5ddbb03a80a88316f6fca16ae148933e719000000024\nB = 877f1caf75e7166ef18484d0718947893fd1ec016984387debc55c19e378a487a5ddbb03a80a88316f6fca16ae148933e719\n\nQuotient = -2000000000\nRemainder = 25\nA = 1ed1b7d9e4cf3d44ee98ef69850e61a39f54cc407c6795c07c887374441fd9ec258c21193f8a8c55802fb8f8c579cf94cb0ce000000025\nB = -f68dbecf2679ea2774c77b4c28730d1cfaa66203e33cae03e4439ba220fecf612c6108c9fc5462ac017dc7c62bce7ca65867\n\nQuotient = -4000000000\nRemainder = -26\nA = -35d324ba37d2000f960ca1c9e1ab96e341a2ae6a5ea5cef014c73a39dde000d8ad9606b817ad67e4e4593cc5894d354854898000000026\nB = d74c92e8df48003e5832872786ae5b8d068ab9a97a973bc0531ce8e777800362b6581ae05eb59f939164f3162534d5215226\n\nQuotient = 8000000000\nRemainder = -27\nA = -7039477c3e0a6f415e25e9f9b1dab1edcd8a23f984e7e3bc149c206a3b756b1be001450af4049cd4535e4243d7032afcf6790000000027\nB = -e0728ef87c14de82bc4bd3f363b563db9b1447f309cfc778293840d476ead637c0028a15e80939a8a6bc8487ae0655f9ecf2\n\nQuotient = 10000000000\nRemainder = 28\nA = d6c59dd07409da98f7bbc7ee471b6e06c4d9e832e9f4d04ed9da63564d37d3072a950564cf549bb5d6e7dc85565d3cc8ba340000000028\nB = d6c59dd07409da98f7bbc7ee471b6e06c4d9e832e9f4d04ed9da63564d37d3072a950564cf549bb5d6e7dc85565d3cc8ba34\n\nQuotient = -20000000000\nRemainder = 29\nA = 14d27a16a9cf2fdbc85b88a604dd8f0e57b5b34a27089d75d805e05fbb367dfa61c085aa98b896e3e53b85ef774a3fa52417a0000000029\nB = -a693d0b54e797ede42dc453026ec7872bdad9a513844ebaec02f02fdd9b3efd30e042d54c5c4b71f29dc2f7bba51fd2920bd\n\nQuotient = -40000000000\nRemainder = -2a\nA = -3bd0119619fbb5b260c44050d61e6b1925a49713d754ceb06bafb1d730a93f199df654b153c40e75096ebbaf5a6ce3c801820000000002a\nB = ef40465867eed6c9831101435879ac6496925c4f5d533ac1aebec75cc2a4fc6677d952c54f1039d425baeebd69b38f200608\n\nQuotient = 80000000000\nRemainder = -2b\nA = -61a283fe41d965ee770704bb453f689cb82a81089422d6d904a91776a06d32857220286e6ef6327807b724062dda143b46890000000002b\nB = -c34507fc83b2cbdcee0e09768a7ed139705502112845adb209522eed40da650ae44050dcddec64f00f6e480c5bb428768d12\n\nQuotient = 100000000000\nRemainder = 2c\nA = 87bd03a64d9c56fe340137065ba36bd07b556119546dd1fc3ae087ead32bc79ca7efb5c7230ea7bfb00ad419096d9279fbe10000000002c\nB = 87bd03a64d9c56fe340137065ba36bd07b556119546dd1fc3ae087ead32bc79ca7efb5c7230ea7bfb00ad419096d9279fbe1\n\nQuotient = -200000000000\nRemainder = 2d\nA = 1eb7cfb197d19f56ad994eca52d1af6466fd09da07d68d63067602046b2d42d3063ef5eda6b58afd69fd92b0b727a0ecde1420000000002d\nB = -f5be7d8cbe8cfab56cca7652968d7b2337e84ed03eb46b1833b01023596a169831f7af6d35ac57eb4fec9585b93d0766f0a1\n\nQuotient = -400000000000\nRemainder = -2e\nA = -3ab858b3329e5bd0469118be52a867b2febbe2894d962cedeb3a5be1738db1cea106cd0710c9f6937348c2c63b109ae623d500000000002e\nB = eae162ccca796f411a4462f94aa19ecbfaef8a253658b3b7ace96f85ce36c73a841b341c4327da4dcd230b18ec426b988f54\n\nQuotient = 800000000000\nRemainder = -2f\nA = -6137bae6cf7573afcbb6fd5c066ba37648cba8db0ecafe9dbc66959b19deabf42f3083719a2268b7602bafa2140a1ee8ce7d80000000002f\nB = -c26f75cd9eeae75f976dfab80cd746ec919751b61d95fd3b78cd2b3633bd57e85e6106e33444d16ec0575f4428143dd19cfb\n\nQuotient = 1000000000000\nRemainder = 30\nA = d00fec043edadc093673e5f5abef0c6bacdf1f3faa49a831a645bf80db7539d657f69403b122a5c6f879eb8e63be54d35ed7000000000030\nB = d00fec043edadc093673e5f5abef0c6bacdf1f3faa49a831a645bf80db7539d657f69403b122a5c6f879eb8e63be54d35ed7\n\nQuotient = -2000000000000\nRemainder = 31\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -940693131e2ba7b2af531803794983337dd526f0d84d08d58723edf002a388d55c8502d88c2a2a6e78233a2a1b1c8d339a13\n\nQuotient = -611b743a0e2acb1043bb33de50a59eaa0405b37bf6b622075dd69291fe5b53305dbfcc377d1f3082319c153d0c1ffb3b3346\nRemainder = -16e346b6a4297\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 30c77f3380ccf\n\nQuotient = b9e34073d5e6e5b9e5d2d7250150f8ad86870faeb88d5aed5029fb25c176de216e2388e0f5d33f7c3b56102873eb40b06f2\nRemainder = -16ebc86eb88339\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a67",
+    "3426000000000031\nB = -197b6f6ad5b75c\n\nQuotient = 141bc8752e846cd63743e6fce4a22efc3eb5f0ce46ba81b8f578c94c516288ec3610fc9923f45d4af2b94c0b0a20b48ed0a\nRemainder = 9bab19f12d81c3\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = eb90162ecae18b\n\nQuotient = -381bd85c951e1dd775b0d7fab344aadf06b1b592c643b5852fa44aa55159eedf3b3e47fe0d9f399ad92da85ab2bfd18240\nRemainder = 1e4f817a2f52b71\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -546c109fa8a9d7b\n\nQuotient = -5e385a83b56830626cf8306acc232f955178080e86384bbcf92eec3a8961360223c4cfc1d8d118022972e61866cbfc46b\nRemainder = -292e149300fdd1ad\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 3246242094394c8c\n\nQuotient = 9af0246f4b49316df43f61ae3795a764fe9b1d071ce227982ebda7988a7a7a98129c94a76635c6913cb15e4f75ea1608\nRemainder = -dd3b3e32ddc79cb9\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1e928618913898b2f\n\nQuotient = 1fe40099811c648aa4e84e4fbb8cbc19706774a11391fc03a9667d8dc72dd0b26c4a46d0bae56ba90fe4bfac1517d241\nRemainder = 16e021603d30dde2\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 948887c1634f4b08f\n\nQuotient = -3f4fa4c179dab02ad461bbea8f890292c934496db560f72878323a4463d77ae261363f4dc8f53eab145fcc3815d3253\nRemainder = 407ccb4f0b814dc5c5\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -4ad17434071e1ce664\n\nQuotient = -4d17d19f7f6861189a520776339a1e425876808111c303e391118714370111151ef4ad2e6e84250f59b0fe09ab3293\nRemainder = -36f745b0f421d16db7\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 3d71635bcc25183cdde\n\nQuotient = b976d544af44e711351c6618106d3a002c42ebbe22fe939a2457d24e8dcc35c95dde5c7c77af6b4545344a198be82\nRemainder = -107334ab98e5099fec5f\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -198a54e35fa0cfa328a9\n\nQuotient = 1307bb8e89aaff7466bc238d32672fbbde7be19d15423bcfa14f9a23fe85af9739b72807fd4bc420ad0b0fac37a42\nRemainder = 170ebe9b83d4c43b79ab\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = f8e923a8bbc0242eafe3\n\nQuotient = -3925a167c1c4d2fae265f277302b989466e309a7211e0b7173031cbbb91ab7fac8dfe43c9d832764e222e9d8581d\nRemainder = 4d404e93edb435dbd60af\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -52e36cee22274556059ea\n\nQuotient = -4d5a6ef346a872142b999ff9a5429198b3c2a97e968f55aa2c01583efe30e9687c57e2bca2372db4d3d443052b6\nRemainder = -3a2ea5f9d204dc31f21833\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 3d3c79a115d9071b573d2d\n\nQuotient = a49dee54430f1737a04543d5f549efafab25f0f28f5e304f1bbca191f99521c2c4be1b9927bde19e1ec2060bb2\nRemainder = -17d02758f8fcadca911a95f\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1cc65a75211f2826c9d0811\n\nQuotient = 1808ab7c0ccac2ff8f7cb61248bf4624fb60352a356fdd1408904f8c6fb0cc52b7642ec59183bcaf5dd89ca0ac\nRemainder = 5c95323f3b8861261dc31ed\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = c516e6e3fa6e3dc52cf5933\n\nQuotient = -437e04d7076794850aada0cb4ca7a1055df103e74e00766be6a2fdb2631bf294cdbf2695d0a2f8f9eb5587aa5\nRemainder = 1fc63797594c56160536faa9\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -462ee529b488d1db2b6c60e8\n\nQuotient = -5dde5497accc4575a412e7232ce75bdf7905936e09e382d5c9f133faf82a05ad9dcc94ad858aed34cc14c714\nRemainder = -15e79293d5e055f906381a899\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 32765b0a34c88864d39bedaae\n\nQuotient = 11ac52a9287472e1d3b8577b3d50c95076e190714796761322b3ce869d96b44387e190e824849ee345d0a22b\nRemainder = -a158ccc7c055d64e7df3fbcf0\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -10c061a37f6cbd11bf0c327643\n\nQuotient = 1ff5cda1551867577c5ca72c86516a82fb8fc5f59ce967b73c6bcc1b85168389872c9a747ddf044d6dba174\nRemainder = 21e766a0020ba429b330a325d5\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 9435cd2dc2a92c950bb9e69b83\n\nQuotient = -2719c892fa3f4dbc9951b2095056a16159adaf32dff902e20a800a0cc2e858ccae408f2161aae25d3e1f6d\nRemainder = cafbe9caa1f83fd0dd3d5a6881\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -7924e4dcf8f96da61f54bf83870\n\nQuotient = -5080dc99dba295f4a2d9a474c2ddfa3b232a82fe629fe62177514988983eff8195b37d3fee3afa343b497\nRemainder = -94ae72f78982ac1ff83f300cfe8\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 3ad70d4b6b9b5f5b2eb65da67e1f\n\nQuotient = e475eebcfc53d49ffad2e0c2a4ba48fe7ce02c42ff107e01ab3fe5b26eee45c83c4f58c181d77c259155\nRemainder = -c83ac7582a02b47ee734e0f24dc5\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -14bbcff5423a260b21895327b18bc\n\nQuotient = 201308a421b85291d23465d648ad2a8d6f3393efc16fb675a42ea7bbca635ddd8c2449b1b34e5db30a03\nRemainder = 8e07efb8ae4c9df39533042362081\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 93aebb72a81ba68e8881fd1a56a90\n\nQuotient = -2584cc534f88f091fe471c652ac66a695906a7cde1fc1cde9be3ee09026b690c1a899378ff31f6acb90\nRemainder = 794801d9d5770a60e312b99d6b9f91\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -7e408caf387a0ce9bbf4309c80755a\n\nQuotient = -63f7bfc0fe5a5421bc0a19fa6c87713a72eeb2a33e5eadee8c2f32c20d14f403ab8bdc424b9e8e0c68\nRemainder = -24227c242afedee2473c1a66a5cc29\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 2f622c665af7f8126eabfd90df8e9c5\n\nQuotient = e557e6d2180aeeee5d2cef453fbdf38e84cc148f4608ade8836045498be2d318520ffadcea6319432\nRemainder = -dd290149e0e159f9ba6bb9f5a4b003d\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -14a7623d1d9dfc177e913d3119d0d30a\n\nQuotient = 1651d852316d472b41ba0460566e43fabb9257861859ad0fb6ea5a6433a4164299e078f4d50c58afb\nRemainder = fb60aff5fdd2a2b794b0d973ac4d92a\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = d439da27b5e70342aa5cb365ece15665\n\nQuotient = -3ae357761a8ff43d3b1bc53eb336260342a39d22f8fac44eeeac96c2f6de32580dd6a688faa9c515\nRemainder = 4fa6f7ee4faf2f6be99c5ce4b65cd642f\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -50700f9c0da59482165a47a3eda2bf07a\n\nQuotient = -543b4390e4e254226683aa0b83b2ca176ec27a373969fb88f766ac72adc9125ff83b2652e46afd3\nRemainder = -12ff398d9a7d9e97a7f63a0bb293c8fb0\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 383c5a4f1767e83fc382ad4f1c7c2b7ddb\n\nQuotient = ecb72c14c59d49287fb6b2cacdf04619ee617d5f3f0f1b2890fd4e79746a4fbd848613cf5eb437\nRemainder = -1035512a2717a89062d48f1bfd213333ed0\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1402b751a1e5f3fc46e22b43240d6ce9b27\n\nQuotient = 1e800ddc5d5126f322298383f32fd593623eb88a91b2d68c5d9f56e20c16ffe2cefabe87357",
+    "0ab\nRemainder = 72935d534bed5ba557b91ea023601f50b1d\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 9b4df766c608ff3efe5ea1f65cc850fa73c\n\nQuotient = -2c2dc2378abceb983904cdf6728f361d279b4c821710ae785724a7251c43fe4f705f023afa7e2\nRemainder = 249f6433af4e8e224eb570fd438197af62f3\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -6b382f812816c77d65c94c0c660b31a69b8f\n\nQuotient = -5f3ced1e42fbd3c6b2c6f1e16953e0c1bb6efb4e49566f974a968f69a1a66a3d7558f5a802a8\nRemainder = -317a7fb1af65982fe4641fbb1e5837e6ea3e1\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 31bc97372d17038fd842b72eaba2abb26df62\n\nQuotient = af3fef8111c449b9e0858e7e53e1d00b764232f7a077d75043249c387ece30af351c8a40335\nRemainder = -a1493bcbf57a8480461d62796aa8f8541ece4\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1b076b2f7b78b4a0f0e24ba3a05d6c697efab9\n\nQuotient = 196734cefb08f09cb32ffefc07da8d9545d3451d5a08736757184bad94c73be71311cf1e01c\nRemainder = 273e33521f4d74840a96b3fffe169f79d32855\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = ba7746f4400f812919a3dc86b00642e1487691\n\nQuotient = -3c5989cf33145057a9c8e904435d12939db519cc6b9ca1c0a11934399cb139a73613950f2f\nRemainder = 456ebf56c636d54e37709b9e799e83b7a08cb93\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -4e7d4f389423f42e980eda55b4a6a45f6f4bdc2\n\nQuotient = -8432cf3338bce1d12586f83025aea50cff3864af3eb2103a36bbb0aba10b0ba4831641633\nRemainder = -4f62c678137df301c4bef216e6aa910104e76ff\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 23d4c57b5a8162aae8d937be12efbcfd7b96ec06\n\nQuotient = 9f94c4399eef16dfc65a1e015e0786c86470299865932c4d564b71c9b1551a9c0308af38\nRemainder = -168b74a6073b4a5b54fa14aacb5c3bb7897ed0fe1\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1daecf01ec633610373b79e04c22cd7499012bc66\n\nQuotient = 1d5b838dce6c0324f157ad125adefde6e1045dce9ff97cf8d1d39b79bce02128e3433ffe\nRemainder = 3aa816216d55fc3c910a030fd10fbda1e12f2ac2d\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = a1598a12a84e9cba42ea0e200e88d4599c9f615fe\n\nQuotient = -3edb182b53890ca8762f3039d2d71a8a27c36cc884d0879e0635e6326af0182bc47cad7\nRemainder = 4610b2b1305220bc0de584dd3f87d90109012a8077\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -4b5c2f1ba3a82047c9de61d47cbf1bec86b6ef90d6\n\nQuotient = -7571ed4c509630886483f6ca0923859e644063acb38cfb338bf3a681fe449501262516\nRemainder = -21c579846594fc3e5efc53ab01576a7b32d69faf41f\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 28550e1f7c6492f4cb682c37b105f92b049c13fc03b\n\nQuotient = 9ed8fb31327a110ef4377258681c5287de8ef9dbe62aa4fe84a7f2a94bb69607cbdb2\nRemainder = -1b7bb759dd0ebc346cbe216e56be8063f063490c17c5\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1dd1e61caed1efc07d21ce05d889de1ad65808cae026\n\nQuotient = 1aa716227d1ca6af68286062b2d6dafd7ade16abbd5d6fa4ada0365832fe18f73bf35\nRemainder = 32e714b0c4ecefb38735cb88cd5e07c21c81be858cae\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = b1b959a7b3262d7f4dff488315903aeaffd982b726d7\n\nQuotient = -2a9979a530046939e0b43a25edfbea6775784eb5cf346a9fc3a2d22e1aad473cdada\nRemainder = 4edeb91a2472e80068b1883cf2cc45d68ff9bbed1756b\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -6f31bbe097587a68fdf01d0bf93830bd03a23920ccc0f\n\nQuotient = -566ff76814e1c7d31ad53bfb9f3c0607ef1f7d1cf9bdee6e1cfb78b3ad7018f8bbd\nRemainder = -1eac095d6d84021c33aa9b219d191bd0637f20b5920eed\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 36ccf5bdece624b4f54c729a8cde13325d8dd764f44894\n\nQuotient = aee4f377611179d8b6315811dd94639aaaee63e99bddcfa8eee297ce1dc04daf8e\nRemainder = -59cb3ba7efa1637c46b21795872e8deaff90f13402cfaf\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1b157ad838684b45065aa77ca3238a4d8c5427f719cdfb7\n\nQuotient = 1c72d32cb83cf4a9043d3bb5002f61b03e29c34e44a9fc5cc4d613726f5e618546\nRemainder = 7312d11fb5828c7f1a0060a5152a7644fc1e6a59de28d03\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = a681444c4d47d829f7b629b561ffaa0c3be1232346c907d\n\nQuotient = -2702afc4095a0396215e3ca36e2a59725f743b30de0dd8d4ec4d943fef6c37162\nRemainder = 223dd3080ede3a64744b14df8742cedd71388b0df99073bd\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -796c9ea38ccf516a2054a1e584c18b64b996c9679960585a\n\nQuotient = -805585c6a7badc933bced6f8373ffdfe9796e963d3fc90e85b1a22c38f842062\nRemainder = -a6ebff3f651644915d5c466cc2915d104f0f85a44e08fd6f\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 24e8fb7a6a3057ddcafff92916c46f7e4038b98c3104ae831\n\nQuotient = 10383ff8feeb180d4fde925b534be97ec3d5f1f1dab5d8cd9ab5d8ea646cfcdf\nRemainder = -a7efdd0401c74a69cf74442fe3da907acf92e8edc51668828\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1240a71ed8d81e86fd9b16e1d64f438b35d6f8eff672494017\n\nQuotient = 195d95a520fd22317492117dc756ff97806c48c1aac67a41ae56fe503a60cec\nRemainder = 8b8692bee56f8a1ada9ffd8b3583eae33a0df9b73a7d8585f1\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = babe02063b61cb90634ac0493174073d2419e00728d46ad2b0\n\nQuotient = -37791adae674b866e4791c107a697363847dee4a58a37806391426ea48b8c9\nRemainder = 33986fc6a5f5c4f4e31458fc7de55e08a4e9320509d90299b93\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -5563bb852e7338c65aa21c516eecf47f498e5788c608ed46cae\n\nQuotient = -68a30494eceff55e4f54a556dd9b30025ccfa22c0952fd746adfd13d31d00\nRemainder = -1b511d0ab81d528d00a1058850bef48df2e9ae9357e779bb9231\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 2d44e919fd27bb3fd2093062d11830c30fa77febafe0a2082cc6\n\nQuotient = bd30999592dbeabb8871b76aa04cc1c6c3794a83f0178c2ad505d8189485\nRemainder = -b0dbce286df5faccf0bdb40ca60f508d436f9410c5e49c3f1360\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1909930e2d16fc877c15895a3ec8b2125858bfa1c5a1b8776bedd\n\nQuotient = 2171694ef4a9d57b83b09357a511d4e11cecbab5e9387928b480d686a0e9\nRemainder = 29abc8898d5ef85f87323c2a6fa36ab6e1bdbcc0ca742b1a2347e\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 8da37bc9c7c9bdc62f49cadcd40e156e776b7f4c8f7ad543f463b\n\nQuotient = -267d470f32911150d9944e684c14e1834734b15475bee968748dd5f6502\nRemainder = 53a2ffef61709bd7143c4c876e021f20a99ba481f2b11abcd45da3\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -7b117ddccee97816c2ca2f1a612cc0d94ac67f5a79ed41744c8fc7\n\nQuotient = -5a21a3bdd3a3d4f1361a978706ba1cec409c296a5b3c369e91fc8317bb\nRemainder = -2cdc818f1e445fb3772d2a56833aefb2f5565a5fca80662e6fc1845\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031",
+    "\nB = 348dfba3c793f0018d7d3a70c4060c3148b4a3163ba60af9d6f8b04\n\nQuotient = b301b4050fdf4ede8f9c746b26d968110e1eb119ca42cd9c9bd8d4fab\nRemainder = -17993daf81711fe59204ec82e363d2b91971129af9206ff9506d3cb1\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1a76328184b9bea8770c91cfccf8ab98e75b2224d666af58022aca80\n\nQuotient = 19c401336dd43c221a61264f8b91791d250e6c99c61850efe6d1e3532\nRemainder = 6c9e547a77c98eaba1b021777dbd98ea88f7fd37c95a2b182f2b9067\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = b7d7b1f95f4fe2f267af88b81af88fbdf603e54ab6de73ccd000c32d\n\nQuotient = -38a77853de88a8db14612884b515e3cd7c673175779d4ab71ba58f83\nRemainder = 51851549cfa00dbfae388cc3b46fd4824268e00e12fba288acceab339\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -539c0171f48e4160e5c308ee9e74f35d8b6d032e946dbcf748b1335a8\n\nQuotient = -79a7eab82e5b65f4f6734e8803fa7c30852ea3ae56e801c5dd11778\nRemainder = -f89592eedcbcc68d5df80663b3cdc638d9d779707d4ae5a552d97d009\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 26efac15401a945ffd37066bc5af23191292765164a0f1e4fd537fd64b\n\nQuotient = d33afb58753a21581c5b2351a74f3d220599ed56ebeacf1d43eeb2\nRemainder = -f699437f44af44b3ddc080f5b74f753d35f70baf3866040ba3c64b30f\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -166cc6a3c60facfa0d8d318f26c6514c7eb9113f6b625c1de804ad379f9\n\nQuotient = 19e55bdaaa5a375c36e6869700f8677db563e5cf985be2a8d1b012\nRemainder = 7bccc3a653f29f3f45b52b8de2449c868c64d976666c01bff2dca03a8d\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = b6eae7a82b5dd1554795573cbf558d7cfed813eec270c326bf290adccc2\n\nQuotient = -297530094c3e4270ab5cf67e60fa5af6a32eb41b18b050fa6d46d\nRemainder = 62d8b502e172da7bce53fbb7c1ae376b6c21b3a3a47523aa0023406e353d\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -7241ae5f1aaee9340d437ad2dab94b70dd29fc6fff7fe31b100aa5001644\n\nQuotient = -640f3c38230962c6d6fca459afe0e46137525e8d62dd9b84da73\nRemainder = -16fcadd5155910764ecf0b4bd0afc3707e2ce49cedcbd5414f1c7d860e95c\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 2f570d2da7a4e62097eb494ca43f7bde33e36525308dc864ffbaeb5d48f97\n\nQuotient = b3895ebba13c8f383ac0482be02e1f5518511420cb4513426bb\nRemainder = -21bc847fdfd48c7a4c36c778681ea20481081cbb7af6b281c8b8ebf2b2c3b\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1a6233954b3480af5f911a6bb8ad33967d5e0446c3e56f521e892c986b6b82\n\nQuotient = 243f3fbefbf842c79c5e96162fc42fe4f177a59d27681c54b3a\nRemainder = bbfaf15a90e744dc4a1caceda3cb339e5491e4507a1118613c5e9739f976b\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 82ae783b8a13e2e65d52dd3a6d6b057163347872f4d72245ff364dbf2421ff\n\nQuotient = -30f7cef2948c9ebed8fa3c5ea9a9bfa96ee4e9729c9b18e9d3\nRemainder = 1feb3fd887629cca60c664e385dddf538d9bf7fff2d34ca9e0e7614946d807f\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -60bba60d69093c0134fcb90aefdb9c190e7bf037ecc13dab3cc7915d7893046\n\nQuotient = -6b6f0183c1f598a68683ba7435c05d700d74681fe472669a1\nRemainder = -1f4d58f81a8c18523918d31791a00ea9aafbbb87792d90a5392273ec4e405da2\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 2c17372a5128d7c403a3b94838072ecf9aff88d164764b12bfbf6261df957e2f\n\nQuotient = c4347fe42b2a7d9d5a650b72724369c5c1f59262a7be3fc2\nRemainder = -1103ec9c4a15373949cae4e34b7b42e242da41edbf5ad8362ce5e5426d3154a1b\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1824671758069b7660bad819f06c86fc76a9344ea38412058380363e5c5b4086b\n\nQuotient = 15e8c8d6847dfe974cefeef5fee93da9e58b74d640c6c413\nRemainder = 61dac240f2b39832903d5ecad9cfda5162bf8ebb0610545f259b75c3dc6ab8771\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = d83386fb9682576cc70cf84520c53169e391b414f5421cddca6e257bd77753c40\n\nQuotient = -3572711bf994e6ad48535cc4d65ac323ef1ccff530b4337\nRemainder = b5899d4cb879e37022c539962959339d055900cca16153da09b54c658753cf50e\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -58a05faf5c61f85ac5a090b6bb045c851ea17332d9bfad4309ce2b7a79ad3cc575\n\nQuotient = -6931ebfc6e34305e5d7cba5284829d088d1ec0abdde508\nRemainder = -1b09eafde481064bab3a5c7fd895edceca40b1e62a9cf953eae1061dfbe00936391\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 2d0769f392ca9ec629ef1bfbdf08cd8cc9219330ffe3c05343df792dd94b1147714\n\nQuotient = 9a4800f0cb2bfbe8d234410deb510103b7da30cbac7d9\nRemainder = -971e4a529e439a1b96b942001631027ff2fbe40b8939e224adb7f2ed30faff64d1c\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1eb3d7971125a036c3a67d9f5ce580a4ef4c469a492be53a55bafd2eafd4032b5b9d\n\nQuotient = 23116704b7a1a86cfa2ee5707ee46268634db5d50dc0f\nRemainder = 467c6b64c8121e4f250492191ea36a27119a0a6d19af519bf7ccdc2436c885c99d85\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 87134e98f73470e23a96c6a9139af3d4d21574de8aa9ea1d720df8940bcbda343694\n\nQuotient = -3b7f72ecf4f55c02366c52f38a827f5773b7cdebb9ba\nRemainder = 194b334b2046a66be3ddd7c6df01c88967fcb11e97b8206d000bcf6043c6e9ccb13f5\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -4f9d0341cadfb1f0bc38184d93503faa196fb8170f8ba2b5d3b512c09d39b7f79a5b6\n\nQuotient = -6db1d69019dd4cb26fd65d5b88a31bb6413b30278a1\nRemainder = -2042a060391e181882dc0c8d91c3b03c1ea35e2eff01babb3ae876ba1e57a505d44856\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 2b2e8f445c0c3aaef0285945e4ca37a700310e003086f34d02c891b94b117f3d3032fb\n\nQuotient = c0e5b9a5853bb21b5e2e37f469764579d5cb2bf984\nRemainder = -154669d4bce7914cdc8d79f2b8d1faa43e8cc3b20fb0767e1c9a47c9e1daed4b665cfdd\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -188e619dbb719381e701363de874fe168529c10f30d3ff184e4356991fdec1649f72235\n\nQuotient = 180054f8c36833d44cab9dd61e6d89d28605c564af\nRemainder = 59192ec5c6fbd9773b8b7dd7d8ab1800dfecc8eb01c29997d15ad75b79575d9e26e1fc9\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = c55b5eb165c63ac2794bfac21980ebacadb93f1e059309fd2b855621572e8d9b3f29018\n\nQuotient = -31412e97045c19ec38951b0e3884c66d1d7479437\nRemainder = 56f1425227bfc6eb1ecda7bfae0e5cb59e92a2cc5306b28465c8739e40893dc5c1e94cbc\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -602b8c25ded1ab3877f58cb048c733649c7dcadf87b2652e35c4e5544d2306107ebff7b3\n\nQuotient = -8da1489ccf7203ecead94c67a5750884122b6e75\nRemainder = -15162026586a1e55dda72785f31c9e6140d166a1fd34c87a7d8c78f8d8f87bbdcf8f75b1e\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 2171ee4a6f7f67d5a33d0a08c367184d70ffe39da28562655e75f6b66c866b1c2ac93e467\n\nQuotient = e635f8bdbf80e99723aa5718d3fade4e573be2c\nRemainder = -ffbd73bfe05f95bc2b135f12682288c620215eac3d6d56503d93a90e06f236e597d1df975\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB =",
+    " -149375d478a096e724b84faf795c589ef0d772c4623f5be38da99006cd833dc5b28363faed\n\nQuotient = 20f76f5c6d0c8284764a10f6936c22bfba5f851\nRemainder = 82e3fb3f7252dd87b5370d26d9e8b9e98c7d333701f0ce8a05c337054c7aeb343d04d7e342\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 8faf8c0a3ef94ab1069394998e5412a7d84f44aff97edf63abc46d96f897172c38faa0b13f\n\nQuotient = -382586dfe93872abbe3a504fc62a8973913f96\nRemainder = 4d407323ef56093eea2f3993334215950f4e1a85ba18cdcd77d819d92b8b292c3ec8edea425\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -545d81ed25602b158bc79aadf98a8f655fc399fb8652ae94333bf54c8c9ffaf8c6b3f2a9d52\n\nQuotient = -7d179efc493eaceaf46572a1f3a62bdfc4a38\nRemainder = -3de3d817a9cf7d529b5229a503e8ebbbd2c53215ac3c584c010947f780198dee16ffbf47791\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 25dddb00f65d6a1ba8caf7815a8063c5da656d775eae9e0108c68ce11dc925183810888dd04c\n\nQuotient = a9f7e5f235bae0e3e29393ac5c99d510b009\nRemainder = -150478b4a0df3eb20dcd1be8da283a00636c021c5c6337e7732aae9c4b49853b95f6d2475ea7\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1bde6cae7f5ced9006c0b1a61fb50982a433e4e2050aa486298f456556d8e909e96933e2ba3ba\n\nQuotient = 16de125df5936181981b4c2d0051a8b4d211\nRemainder = 29ac7c8a11f9beb9ad649257994216146b663bf4f237c561bf315d95778fcdb1010283475ebf1\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = cf24735a60ff5906410be5c4d98e3c9247919b57e404aeabc7eaefbf07bd64762bc61b96c9040\n\nQuotient = -268a52cd10ab4814268f66d9f44f71a98eb\nRemainder = 20293699f12fbfef2e391963866fc082a7884cd13b1c9bd8d5d203558feed2b889720be936451a\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -7ae7d548212830013b7d653072c33f0dd54a6ebd8792bf75809d29a8c798dbc67c3edd99a69b85\n\nQuotient = -8f051067ccb82b6a3dffedd0ff2ee97c46\nRemainder = -100dac0d3bf5aacc5fade281c071eb2399560a65349566567ce1c0c34e43f175a575ed1eeeb3b07\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 211ebb5dc59a051fdfa3b18ac491971e863f2086cdc099672c1215af4ec877e29950efa4f487be7\n\nQuotient = 9b7ee4c499386f922432fcb1a453ee2ec\nRemainder = -f410122a74386d724cdd45b2e548645ac5ee4a44cbfecb82aad34ae470526674da44ebbf557bb75\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -1e76750814dec1ecbb1af0fa2281ab3185e94e47fc16a77fed312f23f261ad7709ad7c9f85862c1d\n\nQuotient = 23efb26228d7bcf281cd45f54572e2b3a\nRemainder = 65bf2ef1c2f8e94d98060aa305f85e6cb869c74eabad99877010d30654aa2e578ef6aa3c5f1122e3\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 83cfc25e90a61cf8686e3d5857b2f958674d478622c54cf8427275ca5e9312ed24e44ed4a1b5e413\n\nQuotient = -2cfcae0e922f2d884bfa0a3346dc9812\nRemainder = 14de2725b11a9c6784d9608c52770d29b9fbf824ecd4890bf28f3ec0dc6c52e4df9be540332b8882d\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -694b057ff381badb37c7c15c81e74cbd6774e8d61c9e7d450811c36262ea834fc1287fa59708ee072\n\nQuotient = -4c0238ff3c18d4d58e543f020002802\nRemainder = -2ddef796c50817e82ea6f64a02a8c6b30ab40070ff5401c2d39ca14b9c4d99de33834bfe566a0c2efb\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 3e51c9ab14f522b55e8f9d3ba995c0846a864dfa2d568ea211b0cac1463ce6a1da72d0a15746fdcc9b\n\nQuotient = d41f9102a7785ce64f76b7d7b870b0\nRemainder = -106eaafdd518c658bd371164ee43ccd915a01b513fc7d220900039ff840ba36450e16ce9987e08e7141\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -16549c5d57b531528dd4d781f03cf275b66cb94eba038b782b739c3ab30b8631c8706abac06004a942d\n\nQuotient = 1616b432b3277e774aad92b0cf544c\nRemainder = 2c89373720b834d718ff3df985ae47c3a7cde0e0309f682f5fd48dc97a1ff3d69fa0dcaa1245e956445\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = d6721300e877a8145d05f4f3d8085697c2ca5f34a5357fed0bdb7169f83b6f8d855232eeea594846b79\n\nQuotient = -320fd6a7375a42a3961362ae196d1\nRemainder = 5336711bf81237ea3449f4e9f4e6358dc250f8ebd86082cab92a8079f2c8f835bc783082efb0ed7e3f66\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -5e9e8e1d446fdd314d487cac1226088696e33161d923acb67d3c75e87e428bdbc193e02f53200610fcdb\n\nQuotient = -4bd06daed3f30345d269f51e4381\nRemainder = -1f3513bdefa40662f0f50a04b418a833aa2f85522dc6c399298b1b147662ef2164ddbfb7247ba9511b8ec\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = 3e7ab7ffe5f63a6c1e109b95b83af470ff820cdedbb3c90c398ec42e44a45e1ca894870a7fa51f17ad5c5\n\nQuotient = d6fd01a0c5b55fbe36e58bbe77b\nRemainder = -c51af3e8b430870388357cb366ea888bd7b4ccde09ad3a1d2ee1426af060245c6d6b5980ae87fb66c4642\nA = -1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -16086df3dd5e665f2631a294563c68931faa19ee67d6a2153d262940a648ae71bb3c1745daca5ea977331d\n\nQuotient = 18bd9a8f5678d28cefd955cf99d\nRemainder = e193f2fece67b7abe16373c3f84f18dfedcf654d951bf47585fccfaf67ee04f5037354d057c9f5eaa8eef\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = bf758acacd11f3f3e6665cd740517c9ab2384266f3c7ff9afd0888cdad2f6c9401c24d6c11fc3949aabbaa\n\nQuotient = -371239db55c79521206c9e60c0\nRemainder = 93773085af7582dd298b09d7098835787978d820289ea6850f27d0d77eecce8614785e32b228f46ca4b371\nA = 1280d26263c574f655ea63006f2930666fbaa4de1b09a11ab0e47dbe0054711aab90a05b1185454dcf046745436391a673426000000000031\nB = -56033fd85be464301f10177b58d895fbb6df6154da5c2a2a7cfc3a24d83a96f5295fb17a08148a4e51dde91\n\nQuotient = 696d8e378d12221e2d970c53bf63a20ef381db8566701972c22fe067cdba99c57b68706a5c6e52f21bb3de861e49ed2141b3036f07d1fd0ee\nRemainder = 9f0e50ca76031b\nA = b2668f5fbcf4170820ed3fc9b12a61862acf8e3cb17175482efe23c5cfd3556e77634d407b6d1f98a73437a8d6066319a7a860afcab2338a1b1313037e30f4d9\nB = 1b1313037e30f4d9\n\nQuotient = babe271ea266bc7bc16d193097903037819f82366c7e9ff8f2cb14157b40433c6ee327038d5dcc44140b070d823befaefbee5e13419f6f17\nRemainder = 93d7c547a9ba0a4a\nA = 74b1a591f449377836f378e05d2902b29964df59c6926e5a9182cc09ce3111783cb7021a185340b4880d56635de268d6f3855c4d9997373b9ff8df899ee3b3f1\nB = 9ff8df899ee3b3f1\n\nQuotient = 890139fef28aa3b77814e1122b9c7f26e746ee3c507e6082b508fcbe380de83b06a01f735239c6847c30eae44749fc8c5e3bd97eb40ba297\nRemainder = 6c97aace900389d0\nA = 7e89adea82b4cb6feb41297b6dc8d948e72c3d5554a987900e7fae48cfb38fb5282b13d9a1f5793cf7cbf1ef551865041c3ffe0e287714a6ec7123556af55a48\nB = ec7123556af55a48\n\nQuotient = 1fdeead441e2d7a6ce3cce2389b2a22248ddca7970ae3f7e7d8453052fd08534ff7c46f6a4537fb6f28df6c5fc8a7d384336e679b74205315\nRemainder = 2903c7cc2651bfa8\nA = 9ca66de3d83f0a747fe986464522bde5e42aeac20e8ace1ea13fa6bc9514c58517479a4281d4128c6d775489b85dfd114ad184613f308f6c4ea484a22ab0ad1e\nB = 4ea484a22ab0ad1e\n\nQuotient = 12f16c8f9f898a08853982e2ac5a906d784c5ab8d74007ba3ab311e861d7c1ac115efe694cab7583f75a4a59ceff2887dab53b2f1022aa452\nRemainder = 4bdaf1f352e87aa5\nA = 6e6a97b358b591b78db43772378dc084a11836ddc9dd4607f263ce620714e8fdf6bf67387c163b6f2999f84270802b4bd5c0f0377e949fbd5d42fe145e66ffeb\nB = 5d42fe145e66ffeb\n\nQuotient = 14e0c06c8cff1f9f5dd8afb6fa6c340f0953a18ba7d2b26b22d8e7f946ef20fd5ac277ceb59cbd4ce3e8213803c3b5b0452ed449e22bf2c29\nRemainder = 55422f1caf4a9a00\nA = bc9c054ff568af73e301e0751bc1ee055e82826cdc53449f2d9f45feda2ba227bedd6df9b74fb58a85917d60b087bef04a156a571716e9bc908ae83784ee35c0\nB = 908ae83784ee35c0\n\nQuotient = a457ea94da3237c0dd15ee30e9c13e7b4ca1dc90fcd67951b8737872",
+    "06babaed837a3eb17e298d74cae92d1059636f9aefe11aef9ffa31053\nRemainder = 124768541b600598\nA = ea6dc82b1906c277526ed867fe8b0fbe32feecfb935dbab860aef59a7d72799fd4e952e70b4c9304c7b2a06af8badcd6cfa12d0b6c9db38d16d2c4a24099ca14\nB = 16d2c4a24099ca14\n\nQuotient = da0a37eece8972a0e2e8817c54e67c4d9f92373340488539d5051984bce0ae3300ef6ca9d0902daa4d485dec3b4db6c8b1ffd2c5d08b18ae\nRemainder = 1ba15c46023500b9\nA = 36ca8763e20e6ebf07a55cdfdd83892bef0bab68ac092093bfdac1a49c1da015541196a24249bb2262e70f7ed53e0fbae61f02ebac4b61f740548136ce50f243\nB = 40548136ce50f243\n\nQuotient = 3d8c433daedfbf681b528f88d610204d33bbe74d0b13978c34a617ae94177e07a757519b5a8f1a93a73d0751c7b5b72b4bdf475a9708fecac\nRemainder = 4cdfd72349c6110\nA = e0dd7e73b2a64dc017da65992176e2535c43b6fc14f2f7b0a7d894d768bbc77507eac0112b2dc3ca83d70989a1b949ccf374be6a012d80a23a74bba39671fcd0\nB = 3a74bba39671fcd0\n\nQuotient = 39d084b444e39c32f2883e9968301151802da15141f65893f37b8b834eb01c074aa1e1a978c5c99732c87ae106bf8db09e1728c8bf2aae88\nRemainder = 2950443357cd7477\nA = 16df31dc290559c3b6a3d192cf15d825cfe79f8dbd5c9848eac7fa90eea5d87f8b430cccf9baab3e8e4dc33467a4234d8551ff25e33af175654686ff1368e96f\nB = 654686ff1368e96f\n\nQuotient = bbead8f70c8e61114f22d36e97861f16037efabe1347613e78c51d7f539065421a66c907faddaed13ad2a0f0b00f8fd594e917799cd937e5\nRemainder = 3013136f5f728b68\nA = ba5e688ab4f8ab5c25592bc4334b6dc2b7a06d491d0f919b716bf1cf109b62a30d9dd59dd4bdf870dd2687894edab303277a5f3e3a537cc8fde3ee3bb61767d6\nB = fde3ee3bb61767d6\n\nQuotient = 42aefe467ff2a5614efef1edce25a1acba9c476b3abbcd680140a3aecf8f51c1ebaab8912de217451bfaca2842c0bae717b8a030b6318c0\nRemainder = 1f130dd2ead0d35e\nA = 17bd50b5322c51ac883852ad2a4446c039dbc210ca3aa0313065fc88cce6819b324e93b036bd0c71be58586cd2b243d01a4a918c10ea0cc5b22f9d795df09de\nB = 5b22f9d795df09de\n\nQuotient = 13de73dcd72a3638fe2a907fd7f6574bbb228698fa60e4ecffb082911c5f09c74bb4f50564d3d4035d07eedea38b634a3e3acc26c8e9aeff8\nRemainder = acb8702f0113e0c4\nA = e0327b2e59236a3f91ccf960490cc69b2afc854de9299ad2edff9618f9fe24251886afc65f5c581a9bc86013f356d599e98b8b10f5236a51b48a6b29025983a4\nB = b48a6b29025983a4\n\nQuotient = 27d11481f00519b786eaee96220afd45bc51700f7366fb5e7da35bbc84891aac3d9d2b709dddae371a6b78439fef810c68eef586e1d68350d\nRemainder = 3d1890c5e1555d74\nA = f3504d5d96c9e27a1527725ced337f1cd0a183531642051e166507432c01e8d44c4e8918701c2a05eb8a9d7e26bf04993f9adeef2826ae4e61c602477f849121\nB = 61c602477f849121\n\nQuotient = 10bdeac209c67b023044186704735c7291423054bcddc24b731ad601b49372f4d5ce6e9d85002f8dddf0411efce943f81a5e42cee2d0c9fe5\nRemainder = a93a0c5bd51004e4\nA = fa29e37b0d0410d19fd180149b14f94ec2edccd347da65f6832850aa06a61b7b78c96faf64dcb347893c93c560b8043466419864a382c6f2ef1412873b2d8cbf\nB = ef1412873b2d8cbf\n\nQuotient = 1c9b6cffe44241292320c0660b89f2f77aaadc8d36e33f5ac3da0f12b3c114a156870a92079f7192d237f8bf49aeee6282531c929cc56d75\nRemainder = 1ce3e5eb13ac7958\nA = 144325a641463ed6bddfcbd73e50620a44c606d71fac38efb1c9d2747b4903f7b51fdedacfb66db022aea09b43c7c2ad7b851035165ebe59b552d4f7eee617b2\nB = b552d4f7eee617b2\n\nQuotient = 1b4ad18dc0e634053beb3cf840b53e35117ea06309ea8ca22e37123fd7e1d391c96c792e5125e322c27daa73301024080d73ba3491484b659\nRemainder = 3286bdce6dc3a828\nA = e3a2b90d3ef446f6bde30d3e726cf3e78212324054b40deb0b18fe00645568fb0a6234b6bded6240977373731bb30d1349e25cefd54b7a9985735e9b78002691\nB = 85735e9b78002691\n\nQuotient = 28f5e8da6733240cc2f18e3cf4d42a50d92816062af33a9e1871fa89bdb39a0d905c49faf51cc1c1378741bea34d25ac2c8e522881a6f6087\nRemainder = 135784870eb40c68\nA = 593206f9367b72f9cc59b3e37d2eb23b2061422859162ee53656899c2471017474f500c6e23efe1f6b1e57852cd4229329dc182ba01a257122d76a26aaf9b844\nB = 22d76a26aaf9b844\n\nQuotient = 1ab276448d16c533b6e90b5b5ca266e13ec27b5a58c80b7657df963ec2d1fe4eb1c1d24873eff6408bcb3d0cf97c31e85240eedf0efcc1e5a\nRemainder = 27b105741264f875\nA = d84fde3d851b52ed3b2a1268e9b765ec6c09c5768bba709b3b799802fadac30a6c3184185e6d57249b1c34619f3c9d2b90bc0c348b22537281a39fcadf738083\nB = 81a39fcadf738083\n\nQuotient = 84a87678485b3e60ee1cae3701ebdf0a29ee44115a492c34a0c8e84090e14070eb2ad0abfe2c339f26b5099327515104fe3d1c5546feea98ed\nRemainder = 95f7434941f9d8\nA = f79a0643bcd9c28cc22cc7b4178b3340e4685dd2672792516d6fc08567d2de2d3e25d43f100a58826edb146ac94acac4213bb09bdf8a258001ddd0ab110b89fe\nB = 1ddd0ab110b89fe\n\nQuotient = 516a2ac26e5b3afa502c7f3c6f15376f7a380e5842c229443343b5b74dc3de84db3ae99a0c57043e32a504ded19943c0310cababb3e92cf8\nRemainder = 327cf78eed336523\nA = 17c0d5814e1020d5d69674bdf6b9df193a16c0c8567a589d014e8eb7f6c9c36560791f7acbbbacee7c456eb51a4cdd7ca88011e9d8d9f2d64ab08ad74f7be5cb\nB = 4ab08ad74f7be5cb\n\nQuotient = f0da0beebcfaa716f494cf3fc81fe65117c90adde3b3942e8e66986fe8050fd5c9ebe1c88c5db04cea4c4c14779555d70cafb53870671f95\nRemainder = 3b2f844440d7be00\nA = ebba8c393c2a22b094d824ed95b4acf6875719fc165f73ee6d359e1134949169fdacbb42d5deb8cea96e11e3aac985635b5bcc6c02a6778cfa8e03d9ce6fc680\nB = fa8e03d9ce6fc680\n\nQuotient = 56527f07593774f0fa642241400985d0bb9b41d3dc9e025ca069130d93afc972d75e3fe0f798e127c3e1b4e925000459a3a5a83b15186e516\nRemainder = b620b7a3b752b78\nA = 5d6cad9e26267abb480b2b9ac5ea323bc4c3c53e0de8ce40c89c85accf0499aea5b11703a04296519047585ff12f8795f98da0546c20016a115100eddabfb468\nB = 115100eddabfb468\n\nQuotient = 294dca3b56ce9529aed2c132a9bd6c0c61de7a58ac50582f396b4fadcf7873b502bb869f801a9ab1f12384631cefee72b3e6050a7f69eba4\nRemainder = 53a0fcf5486c7a6f\nA = 24aa73803f270185d23310df2cf3ef67b18d7800bc41aad2ca13f372a27ef0a9217194f3f512e79f545a903895def195a5eb9a1a1b6b3f4de340e9da9b305d3b\nB = e340e9da9b305d3b\n\nQuotient = 16bf4dab1c29bd284c9b6649de65a4ee58f21d6a8b51627ca133fa817872b1a4a9956662db0aead5898ed0eda08511be7c47449638f2fab95d\nRemainder = e7751deb047d98\nA = 77b04d93272491322ed2fe651044e28cadb2ae7825f02b55aeb0f73b8b8a8b336802416fe08c718ab681581ac04d87116323f61f50bfd2180542fcd4a46dcff6\nB = 542fcd4a46dcff6\n\nQuotient = 388ae1c243bc9111e663c0c80495c36e8767bafe188b532b7ac84b5160d902af1b638aec6e4c66955d16bd8ce94ce6027a7bf95910f705ad0\nRemainder = 7c667ea307017c2\nA = 52f357e9a57722a867d8199242e100f06e8df810ee913d6992bfd9dc03ed78bcf44d692aaa7be806df0c9e0802851d7ae8405f76114e6322177907198f85cb62\nB = 177907198f85cb62\n\nQuotient = 33dc2fcceef7dce92e3a9df58566c6e28d03b58ff6ecbbb31e43936cda6380a56788285d37b5e8f11487afd78c39cb2150cc98d9d78a0c6cb\nRemainder = 429a380c9f8eeeba\nA = d99cf9a0bfc347c9631ae8c69defe1f1509c3ecaeeee5dbc61317bb73fa5cc6e704f64c865cf4d898f8a2f63214dbd511f61aa6e09856222432376698f8d2f67\nB = 432376698f8d2f67\n\nQuotient = 18ecac9e5539a014cffd8310ceb1170577cb23aa9cb3c523d57ad83069d1609ff743cd3c275b67097a038b85afcd7105ad21672f9ecbbc7df\nRemainder = 37924fea665f5c92\nA = f87aa8b6e62b09291e0e9b832ad71d8f85d60501a8d89d2638dccd4022e89bc4932c186a198557282527dfa86dfacc2f90fe0656695b61429f8220509f5106b9\nB = 9f8220509f5106b9\n\nQuotient = 37c0649a53c8cab91a7458702870bf64cb1de9fc1c6b9a3b92444119d368501b62d3a5138af72bdb7752eab8af6bf4e3bdb9e3beb1805b88\nRemainder = de179463e3e91ad\nA = 995c04c1f24c4efe88393bab7a7545e39193662d5db7c8e557d6c554ed4367f5af82c463d0ba6bc3148620481140add5677937989e03fb52c0323980d8841d5\nB = 2c0323980d8841d5\n\nQuotient = a6d193cfe7d8983768ff29908ee6e07fee99927a4bc4ef41d01f63f3b4a2e7029630b7d925d0979458cdaa903771286af672253cd99593b3\nRemainder = 6bf69921db298b3e\nA = 55c856daa8110599cc4fde0a44acbd69a68eb177e0438f7d843ba0fb74caab2a7e0c8a6f176f5555779e65c555e9157a16a1497edf36ccb583a458f0372a57c9\nB = 83a458f0372a57c9\n\nQuotient = 63f379bef9866b59f8bfd6bb0120a75dc03506b0034e7440764afc8ec14d8d735aa6f03a568ea98d0a74ab9bbe9c6e11b288467e5f79a2539\nRemainder = 11c077beb8667d88\nA = ff1fc3ea60fb37ff23e2f2f4e207a86e055cca41eebcc5bd6376904b51fb3d233cb04666fdc92be33239b5ee552870e45717890e35fdbe3728d6ff55d5662419\nB = 28d6ff55d5662419\n\nQuotient = 285ba8cdfbf00b112e496ce65cdba2271c82a273b3d30bed82ef2d360790c5deb97f3311bd5eb9876a61e33b3a37782d00c2d5ffbeec752ca\nRemainder = 1672a8aa119c3a1d\nA = d614352268930d301aa4046cd38e2eda4dcfcc52eac984943f2c863de5c4f8a44473a8ecebf12cb8f4da4722d305e5c9c3eddc0109d416e854df334dbfcfdd4b\nB = 54df334dbfcfdd4b\n\nQuotient = 358178128648fa9ea28dcfe68b4cecc7071e129e3ce4d113f5d1e387f7e5a412e9d2dfe5ff16d9987a544004d213ade9c134cc240eeb6871\nRemainder = 44c3fdb374bc0c30\nA = 18b973dd011969e29a1f4a5b8f118313f715c2e31dfebd9fe0957cf23cf36eded89c38637a8d3512bb23324ff",
+    "2a3627d5b942300200c823d764b7a6c12d1c91b\nB = 764b7a6c12d1c91b\n\nQuotient = 19ea7212f6604d423b308fe3f2f4986f31aea9d6a117a3e207e38ce5bbd8d7a866285ac60433630de547fc84e364c451457fbf864a82c6613\nRemainder = 2718de2dd0796f08\nA = 83577f755a448d5586e19486b04de7836818223ea920465c4eee979a9ce5696ad8e2fd5253b5d5dcfdf355465e8c0819658ccc5580fd29b351169b54c62b779c\nB = 51169b54c62b779c\n\nQuotient = 13e0c5b9905770b60a6f978d1c983cbc84dccfaed0f4222f534df80c7d3d129f5e8f74f19581332a7f6d383915424c71db4ca19bde2591fcd\nRemainder = abf5f6c8ab6ed4f4\nA = e2bf43c91cdbb244790eb165cc13feafea36f5187cc9bf8aa8cf202042efd5441e3822a1164992da5be750aaac0bb11f09375bdfbd4a39e3b682c7ee6ab5f5f1\nB = b682c7ee6ab5f5f1\n\nQuotient = 3919f31521e87f90df3a4463d0c83fa31e3f569449009d307962d26f07d854e8d3f0badbf55311c206bf34e6227949327a93b1a5ada7a930\nRemainder = 6c3802d44dd4668f\nA = 2546880cc6f97fb379afbc4a2664115ba7909414f35a5bf88be2ed5187bd1a24afaf82eeceb0b438d4999ebf9b7ec752236669425bd3cce6a71d9ad67ff2ff5f\nB = a71d9ad67ff2ff5f\n\nQuotient = 121d5ad4115c2768b962e51d09f426d61624e0f203ac6c923289b4e7964e165b34f3dc1ff938a7cf37478d407de251c64db71d3ee629c1035\nRemainder = 660a35e1c1245910\nA = a36d3250c123697adbbbdf489e6cb40be57febaff654ca951c9fa0b396b1714c55ed6e05e468153ac443dabca29de9b43cc0cc4e62cdf24690593662c86fb5ac\nB = 90593662c86fb5ac\n\nQuotient = ad81debaa02f6e60da58b46e76ce041fc4da64138634ea7b3c165b8fbda027eb64b6b5339e70babbb83430d60383c2cfe22029e617fd03a7\nRemainder = 2e4aeafa2ad76832\nA = 8992cd131757ba5cbe54aa58be115723ea3438ddc782a4d1996980b7b312fa76e4483584df744b10340e5fc9e468690cef538920a732a8f0cafb4e30846cad1d\nB = cafb4e30846cad1d\n\nQuotient = 67a71b9ebaec91121a8cf6bc2932b6be01af7954eca69c5202d771c2c2d13683cdf90ec942a3445771ccfe484f947f078de825ea88b3c05a\nRemainder = 8395953f744cfb31\nA = 4f8ada84096198175174896167405b85cbc03fe0642f6b263a70f9a22f19ad6c9aef38da8ac036d409e6fd925023c95312cebe04eb653e0ec473dc8dfed98967\nB = c473dc8dfed98967\n\nQuotient = 9416326e2347a541b777a0fa1b0c35d8fe76c940d24c6f6806d6ae8ac1e280c16e480786478bda3f780ee92f3f3c361574efc2ed5ca98e26\nRemainder = b8ff45f31bdb58d8\nA = 902f5e48b96b9b1fd16c3b21292ed495987ddac4e1d92b2ab10378f2966c4399d6a41eef622a4991ccd1f647531dcd145de4ac99b3036779f9414ed2f4ba7e08\nB = f9414ed2f4ba7e08\n\nQuotient = 403c651b4e571e8301c4158fc185396554bf61d900708d2af5c2bdf495b3cb539b0b9b5acd0d71654b3aa68024961d5a7bc9e2788e6c822b6\nRemainder = 7856ec047cec8dc\nA = bdd6d846983fbf140173a26d2b709b9f31b4fee1eac9d25fdf0ef3523be0e6afb372acab470cfe1806b36d84017ec99302eb9eb5eb2862222f4916d8b6201d14\nB = 2f4916d8b6201d14\n\nQuotient = 1b6d967173f9777cb6194c8f69289b91da731456fe5a1515a49e4463cd906c84f97381cabdf9f358d97fad5d3cb140e3a3de397e7f9f683157\nRemainder = 83649246ade8bb4\nA = e3da80658acd53ada7c2dc57178e697f2907c5b0c64f4a87a794ca7521105a0568a32874207646df3768ee60964b7d1d2e29ea6bf7fbaa7e084eabd4ea553a72\nB = 84eabd4ea553a72\n\nQuotient = 27b8f1e49e404455cc68217a20766590e749507976a3a6de25a7cf2c32593aaabb04d84deba1ec6bbe048a2959ffd747243c396dc53c9c811\nRemainder = 3daa032278ce53d0\nA = ff3ead7c7b27f607d16f1ef4ffa91b6cc28301b9256cfcb0c22b6818371ce648ae8812dc50a86e4bdc0d0b1e5b0d55c6ba07b240886a6d5766cfb3ed0937a543\nB = 66cfb3ed0937a543\n\nQuotient = bf987f58700508356fb6274f64a9f78d455e4c436fc6fcc980ec0800287ab3789b91c29a8a72b16645ecfeec926b6f8242f3c7dc3adb40cd\nRemainder = c007da44faa80584\nA = 971aa67c9af10f70977f600e10f9278b8e66d2471956da38e5f4b3fedce9a5fc7ff42b800bb4a78314c70bb59394d0880383f5182b6c1960c9e5b47ef8e63be5\nB = c9e5b47ef8e63be5\n\nQuotient = 7332104442474715d7c4cdac15fc1731240f8b4dd0e6ff3284a15a62a8f9a071dedb87f2220efcc5839cb7e6933a8f65d767819db26e134dd\nRemainder = ef65a7789f54174\nA = bcea2ae4b1edfebf905a5820f0481b6c58d76a69df9dbe84764add3f49496a5d7005d645eaee3754e0ed105c13a114e6a0eae5cc4efab6aa1a3d3a0050fa86f5\nB = 1a3d3a0050fa86f5\n\nQuotient = 3f6182804a7ff12fe7ed3c8521b55564559b1a47a78e1fd56597b9470e7e0f6e7e48c58bc8841c9d118718ccd5e0c0bf9a08d8e244ae60da5\nRemainder = 398e30aff5bd284\nA = 2b877181a960c5e29ab1b2672ee22539256a82369e8f6cb5bcfb69e5e4a41f782e89b58fc0ef6ca336469ff929729f8492b44f12199f0e1c0afd12b2c999e787\nB = afd12b2c999e787\n\nQuotient = 1a80a681d2c42edbcbde552323dac3a1c03b43251a99b5549da6cb39ec6947daa0d574f0df68512984fa8e269b0b27a5576b3aaccb76ebc23\nRemainder = 378e44fdc7a5ec4c\nA = d37e62f44de27a1418f348139eac5ab9fcc1ada21ea6d7695273daf638b4d7eee6745f54b99a9678cf742d304736ee356f66d16d874f8cc67fae9be5dfd41a3a\nB = 7fae9be5dfd41a3a\n\nQuotient = ee982a63816d56758c29d284c19b9b984908cf0a9ae3f1f926e162a2cae4f88703aa477c5c14042247635c103494d11593c2c3839baf4d93\nRemainder = 39afe3275c01aae6\nA = 9a0b0476cd33861d2fc3137df292728e1f636f6fcba5105f384533723231a3104e7c77df46f7f34a4bdc63d5c67b418cafcf106b26ad020ea547d34edac1d3a5\nB = a547d34edac1d3a5\n\nQuotient = fb3f4a39a661e5c31228a6b7b4c27e6e52d1954e8ce262b98b61650efffd762cf2a1aec228bec5d5787683cad6b2e6e49a0de91c15c81874\nRemainder = 63e5ed36ff73a42\nA = 4453712f56467328401a69d4d749a0771732734a760a74094e50a62a030cb604e735bfe0bf0641754edff94ac0e0549e8c10941255f0f21f459e52a6cfe4d9ca\nB = 459e52a6cfe4d9ca\n\nQuotient = 7af60a7c0f995178be76c070cf49eee311e6d1e3afaf50c8c93ff200c1b3fe742b23259b4fc0b9ed0947be4fc9a6c212d86de9a0f7dbb5279\nRemainder = 19657d8ce516a138\nA = c9c92a31ad0f3cfb56a294c42a26eaecb77edf33ed40a7e6797927a0c996a7c0a701b484741163df388bb082e3daebf4e1b7a99002632d6f1a41c1d517238557\nB = 1a41c1d517238557\n\nQuotient = c890c55a8e2a3105b9bf9344a57a9b9fab5fa1fd57083d52431b695553bfbe7a44a9b6cd1f83958224f351f8511b14215d1648e88e938573\nRemainder = 1bab5b03c372daee\nA = 88341550e470016c7ab600b9f6cb410071a77f907a58cb6da4ce3e955d1e859534c2c1098fcfd91b9fa66926e51896733c36a824c3a20844add94e27f30ca651\nB = add94e27f30ca651\n\nQuotient = 34c240c42da400317f66f5151630493a2f200ee418d5ca3300cab10dfb429c2acd7280bf066fe19115f86db83d8f5b93cda714533b16abfdc\nRemainder = 18cd326996ccebc1\nA = 7e96d7b90ff09b114dd4393e9bdfb13d8ff517681126c566e18dd6369d87d248734d94bd02a1f19cca90be7642822b636369c51dee441a9d2663ec896e1d6c6d\nB = 2663ec896e1d6c6d\n\nQuotient = 10d18159e75efa8204e325e6be830b4ee8d2c07419e8276edeac6cc286488fc0c888300db3ebb5f935aa82654d3b932540f0093d1880e1d6d\nRemainder = fe9b6b8ba7c30f8\nA = 731aa6e2fb2ad1e1f80d7668c7b0642203af24af382abd207a5ffb588209e8b5caf953e9a96b478f39ec03a397d1433998e3c95e382d93376d80cf0c957788e6\nB = 6d80cf0c957788e6\n\nQuotient = 450d1f4a105ff8d1a3efbb12165ca98c67ae70404472e4862db479e03313b08783ecc42104780c9d57df0ddf19c5b4547ee9ba52ea82dd0c7\nRemainder = 169e15b4d5aa180a\nA = 902bcb1904b80183656dcbd51879e2982e2b46a547c9ae3119ffc12c6a003e4321b519289b7f22fad19d16480182d1d797c3045b2d29dcc12167f9ce5e233d89\nB = 2167f9ce5e233d89\n\nQuotient = a426f71cb3d75365cd076a6c35c10765bbc3f4bd317fb83a70083b0f7dc43a4e0b95508e60dc1dedb780e9b485f4f7a8870960de669b73af2\nRemainder = da381ae5c97a506\nA = bd59dcdefcbaecd9292c4c3685fb87d3a94c0f0ed01e43e63e1f36fb65d6c5eab3b584f3d1f76d31458c9f6b4c69869d96e943c61df102771274c5b4d821469a\nB = 1274c5b4d821469a\n\nQuotient = 26ccd4b7be090af22221729b0ca51a5e66435c2d33f8d88f94405f6c0123ccbbbbc8080cd8448a977946019ccbf5d267ac3f151ebe686720\nRemainder = c41f9e7bf20b376c\nA = 212dbeff03f14b5825f0d7cf8a7501db21b60581a01a26d522ee44e7fe69545cfcaaac64dbc76c7e3027ac39ddc2d80af6f3fca1824c6ff6dae90967d9ab48ec\nB = dae90967d9ab48ec\n\nQuotient = 801df28f4fd987b4e980760f4f2625276a2a7191d453095c82aa98a2253324ad2873abae70cd98c28ef3ce102fdd53469b9f01889f3ba8b0\nRemainder = 8e435da582e59809\nA = 48341b28138dd04807e522e341f74ac46b0449fa45f96d7fc586997c056a21eb3c399752a6a6c023509f042cf9e879f397a34af9aa2ec2e8904674f2ea3ff739\nB = 904674f2ea3ff739\n\nQuotient = d3857b72b70adff9b5dec3cbc63de7c90ccd7aab6595339b2de39bd6b9789045141d224aa4e6bf9a06e017aa3edd00e716a771b3f5b97771\nRemainder = 14135c686d2e9f70\nA = c1cea45dd46409d5e24fb7ed7d849dbb079247af2d312e01083754ed07f65f090e4dd50d23a973488702ef00936c5d78af603ec0fdf03dceea8f939c922b1e7f\nB = ea8f939c922b1e7f\n\nQuotient = abe20c90896e261e7d31bf40e7f3136d36b0b78006d12225a4dbef6aaf2062b609379eefe7e5af5bcec17126286f196f1330da8477096763\nRemainder = 230307c44cd55896\nA = 19a637e4f3051be0f7c4d35513bca4a91ca9b8082fe3c73899b70b6805a7aa0458512495cb6ee1ade55ecd5851be1dba96d65202f06bc7122633a0d905017545\nB = 2633a0d905017545\n\nQuotient = 5ed3765c4a777a903e182f7c9ce39d19c01460f389b904c3ce1d3525edf25ffe7dc0f4d9e24f0bc8b7e01bef19c83e74f17884bd7",
+    "bfabb2c\nRemainder = 40f5346f8775e20\nA = 546578393e914be30581e24508a33f6560a5805dfb1c675d1ff1d6f5eaa7ee638b9e0265f543413e04e3f1f3b0895dec271c9897a48d9ce9e3d7df32c15b75a0\nB = e3d7df32c15b75a0\n\nQuotient = ed73a67932746985465fb0606fb0e81595514f1647c911c303d4d31eb0306e3b2aece07320f6fea57a7071d73150591ab2a82a7d53968a81\nRemainder = 2e495a881876da00\nA = 8976445bc318921f7e12c8d4e8e50596849a1503b5efb65e939c291de136597c05a1fd16137f0bbbd7197df943cd612118d1e55a50ee097c94331c1cfb1e941c\nB = 94331c1cfb1e941c\n\nQuotient = 5dce24b7a16d847b0c43cf365ea20bee9679fa0e8732813e827cf6ef3c9bdb7fd8846b5689ce8b80a7dc0dd05721cb06d2700aeeb7ff04d6\nRemainder = d8ead1ae3126aded\nA = 59b99e5d028e6771d27004bc19830a5fcb347f7ae04c0ba7c49130bfb198c5b16821e425c979e6d2dddc14889ae58475bb52c6cdefecf2a8f4dd6e462bbc8f47\nB = f4dd6e462bbc8f47\n\nQuotient = 170e10b399a4c5fe354b536fe59d53602102f215d5107493680ab6e181f67d75ffd45bf49ffb23cf9269b856156b5ac6b1c5def4ab1abb18a\nRemainder = 57131776937c5df9\nA = aeb35966e2a616762768b7f63ce3aee5e81561080617bbabd7846b3ca03fafaaef83dd05b8d16cef40db0a56f3b0ef6eca5e236681cb57c8793dc0907d9aa30f\nB = 793dc0907d9aa30f\n\nQuotient = 1acdb88f047f9bf679c50ed67ba01dd24dca92103f8ea2677215b6142083b64f9fd2a365499dc8f2bc61e29fa176f7d76b55557fa58e34f9\nRemainder = 5065b726dc6b3758\nA = 15a6292c9fb66c6770a8dbc6fd431d2a4b57338581f78d0860fda90182cca563eb2272a79fb4f5a6fc72c90dc23e8a95713b65988b5b3f9bcec4f0466c1c47cb\nB = cec4f0466c1c47cb\n\nQuotient = add8127c0a27c961203ea0351aed5b3c75aa816e9c2684574e55f55c7140adcbf69d2cff843e5f53c157bd60b43c45c8b6658de72062fbba\nRemainder = 67f48d3584cf4fe5\nA = 4e8938c8cc46d34e3369c5d8536b18c963dbde56020678f77cebac5f8777e0afc62ca2ba4f533cf6cf7561bdce77b6f495bc1b05f1416d1173a6a288012c7c73\nB = 73a6a288012c7c73\n\nQuotient = 688ddf883a0bcc1ff9bd582119c2fea7c059e19aded8c048390a1d8fd7d769666987418bbe0d4cf4b67009a342958928769375c1c0d558acf\nRemainder = a5356d04b64ee12\nA = e0c9e32056977aeca72e229d83f0d320fbaf5cd8bf3e033289f46101c75ef59a854982f33bcbcfd200034e8ff439d669a03fa404e7dbfea822664967d67dd5f1\nB = 22664967d67dd5f1\n\nQuotient = 39d4d94587fd1445f31457c275fd6294fcb69ba155e7da3e6cfef38ed1272d6c95755bca49007ca62cc101b038d264876f18594b8fd4c329\nRemainder = a34980d5046e2ed0\nA = 2efcb12fb55c923f5c6ca7ae076765059e15d9e75240a6e5fc3db92de184143fab1934c7450c3a380a9851846c9f43d67bc199a314e82e72cffee795d695f82e\nB = cffee795d695f82e\n\nQuotient = 145ea82eff186b7db4b11fa1514674fb9d41c698efb33227eb1abbc4eb78bdb2a280c0c4c47adaf4e010a4336cbb5650becd1ef544e223e53\nRemainder = 36052bba2867f5f4\nA = f6a6c7e33fd4c664652d696c495df387b85b132cfdfe34bbd35759477b4a3c052f610df57e49e85720489e4bb8dc923696400a4a28dd000cc1bd491446a50b96\nB = c1bd491446a50b96\n\nQuotient = 35d0c9d870348b113868282aaba22b21ec87cf421519a23b288b150604729356f924090ba038d7400c0ccd4932836c65902b4d3c46a202a0\nRemainder = dc8c7d087bf24b0\nA = 22228c8a5966ebdec64007704a373b0596ae702d62e29e468653b21a890ace2f02c27f26b043f48495687ce8c2ca8092ead21aa250ce0f6ca26129615a2432b0\nB = a26129615a2432b0\n\nQuotient = 52fc995a486c4bfd17ed9722948e9ede1c4ac2fe80e6bd7482fc47944c4337a185a506a9ca473d49073e1b813ad742f19b13d57914888d5f\nRemainder = 75c703f654ad630a\nA = 3473041ae301dd2806da30dcf06b9c09600086d6873cf3ee9d5a0be638849afb56bce2664f797de4123f6f8fe3e12acd32e33a285bb7f493a1cc13a7108327f5\nB = a1cc13a7108327f5\n\nQuotient = 1744946730b2789977620f2e7439641125dd338d1b31fc50813b34dea70b83d209330bd17fd527db9a402ad9752c26b8823082ec9971f4ae65\nRemainder = 453a3d59303ec3c\nA = c0f592d83649bcafb7e2de1a8a71fa863c1f51b595bfa638c8fe30731c6fca36da975b6f19c657e3ca29efff6febfb311c003ec68189998c084afe4979b5bb19\nB = 84afe4979b5bb19\n\nQuotient = 468f3eece20aa9d6473f3c559760793e702758a3d9cc19d7817216392c7cc7c3968778cf2fe0c3f0c1424d7512cee19ac0717952f18aa287\nRemainder = 5904e71034e3a02\nA = 1f0c99a128c757d76ae6dfcd01012f0453c8f89b00476ec46321ecb872f99a48b4da29a4abffd0bbff2b727dfa182652ca85350b4ce100fb70a6a40ab6c41d95\nB = 70a6a40ab6c41d95\n\nQuotient = 12198913ef16c1cfc7c1be13f1cc5991a61ff74935e09f0c46d26456b7cf2825403b9851d07d27e0197c1fa2ac5e32e836979a184f14cd94a\nRemainder = 33431c3df719f946\nA = fbfbf5494a9c5384c7ae3df6c02a5e1f9f32dc31cd7f437832696bba164bae1a9d95daefb8bc08e0e8e637436fb747084460697b5ef5ac9ddec06757dbe61aea\nB = dec06757dbe61aea\n\nQuotient = 376c2f902566d83c21eb7c3aa3a6fa0482ed52c253f67f00d5b915d0183c2d9a2891c2ff837fcb426a4c990c48bda4f90e0bf69d13558696\nRemainder = 31540f5e05e8b4df\nA = 2527f8cafaf7e8319ca53104229199188ab1ca5fe592bde8ecf605e17ca6446414e06898a85e177d6985b5cc6d4eeabd6b222b5f44b4fc1baba050665c090b5d\nB = aba050665c090b5d\n\nQuotient = b8fdd5cd7b2d9295258bd99e2780921cb2ea70627a79088039fc3ab1c62bcfc6307e86db4a7803f18e5339f152063f9e41d370e97b1ba2f5\nRemainder = 4ed4f2d12e4f4ba0\nA = a25bd113c5a8c67ef65aa80f1512de43c9441fec0c41250048d29c406fbdae80912eb3970457d621c552e3af7ef2d6bc1b5448e7df5be724e0adf6f71df7eef8\nB = e0adf6f71df7eef8\n\nQuotient = 5421daac8cdeb6acc2b8b0dd85b592f255ee4fedb3a9e90f2a5bedfb0f9f033d7c562c96958346bcdda4664c67848b9d9fa7d3892bc4e9af\nRemainder = 7e5661558c345eea\nA = 490aef65c81b32f5df76dd58decdec3e3f73bc1fcbdb6aee0c93cd98725056153b572509e75d2cc4b042bbeb0a77d27fbca1e39efbc765adde41a7dfc5c3576d\nB = de41a7dfc5c3576d\n\nQuotient = 156a8a24e7804c5f576cd1757dba44cb4185bc13cb56603b54ee3b70fa35cd98db1992904d4f7d99a63b3a486e6fb31141a9d39cc0301f897\nRemainder = 29e9c1627537e5a4\nA = 5e4a10e772de8dd2c96acd714f7d3880ae8ab460095a01038f3aa9b8ac8165889403b42019a1e70e0e7f32e77fb388eae3579dbcb690729c4671868b0526aeca\nB = 4671868b0526aeca\n\nQuotient = 1b0eff2ff0aeb2c02ee3cc9e0bff808f4d616eb290293b13a6b58a84127972bb417d55e1d001a9720ec72562ef3ea688e64c4f32c7e26cc87\nRemainder = 664d57c57d4952e\nA = 806b8504abfbeec4d5923f83ddc071be88e11c4394168854448df96160b95adb1fd9c288852e2f3df3e36916ba5118815ca2e83a6a7d9e074bef9c961e2958e3\nB = 4bef9c961e2958e3\n\nQuotient = 2e363b13b0457a0e9effc2d7e297df78f35e5d24d0f8ad4525b573fb2f66f374871291ee8a8ee3d15a823b560156d474c678f79ee480bbe4\nRemainder = 5ba8f49e0ca36ab4\nA = 2e1bb261d98ec405dbb068daac5efeb0a51f08149181864e9dd6bf6cfcb617b76d8facaee2ef468807e0403bc550d58e8ad9e5cc0f094b02ff6d0277fe642f44\nB = ff6d0277fe642f44\n\nQuotient = 149a5b1a81b9e47ed36be76252055bb202dc25f8fe7beaa1ce59c279b32941cfbaf8fe4555867850b2fba43b10b74534db82398320f9786d25\nRemainder = 1ef621737e81780\nA = 63de892cf5df40c98de78c755c99e94e0e76cd5dc0b49b8856fe69dd0abcdc535bb1416f0d02b4eeb54e8a939cf7ad4edfb7de4dac87523e04d8ea8637e50920\nB = 4d8ea8637e50920\n\nQuotient = dea8a9211974758752d89965eeeb93cc616f88ce757ec2809f829cbb8d99b4ffdc3f0f643779fc5e0bb53b5273a5b15965f4a364863592f\nRemainder = 9ae7de3edb6c7edc\nA = acd5cebd069f7febc38c318867ba3a562bbf8ea9b19a6b33538ba107e49439f8ac6e880c6267c29b39141dbe2273d93062464de307efdb7c6b738c0bb282c3e\nB = c6b738c0bb282c3e\n\nQuotient = e9149b347cdea84d740be70060b239af000c4336ddf36fd5159083b795c4763588c87a959df0104212a04cc928baf60b0ea72e8cccc6d477\nRemainder = 3ef5c6ee67e6f5da\nA = 6ccf1b8b406e6a106160e73ac4122a04c0814ef5a47708a6776eb52002d52772d3fce3fc05398172bba191390aba925bb23aa1eee626410877822f27d1e3cb09\nB = 77822f27d1e3cb09\n\nQuotient = 1606c2fe44cd0b780ee474a9c7daf0b2bebf62db0ba8ef5a99fe22036019890a4c7dff73e678965bb0e2a6e61d00a74a1d33dc1106842115a\nRemainder = 7cf920ba2897f714\nA = ef9a3983f26237576311a871e4a3df0538593dd0cfda58ab90b889fdb35c700f7d158abafad127605057ca0532e846992c41ec06902ce58cae0c1fe238c726cc\nB = ae0c1fe238c726cc\n\nQuotient = 8ccf17de5068451fef1c2808c62e19997c7f920d5cc0fde1f5a247cc57c6d730df553cf33094b786597a343a0ce9e4bffef568247e904343\nRemainder = 2689c40a54df34bc\nA = 8435babd279b7a3833d01988c58005d4557f7689ea9b7168ef42ce2b31a1a3c32a982aff654f271a651085335496dd826ee4b3bc27f58920f05dc6676e51c662\nB = f05dc6676e51c662\n\nQuotient = a9e78c48c779140b1d15843089765ce9ece3855537ce88cad3eb7aa7bd6ec72df65adacba2bdf6c491066406bdc3dd3dd734a70e93eed958\nRemainder = 53da0b15ac079ccd\nA = 78550cb7b58b58d6878b615dfa25a5b90a1ff631740e631c7f8829962446903c686c810c46a1551b6c1f7a89ae898435bb8e36d1bae24a80b54edbf4bbc9af85\nB = b54edbf4bbc9af85\n\nQuotient = 1e3b41304ee07f6baf1ca061e0e28a3740991c6ca2749eba70d3ea1f9cba8adec45cb69a31cbff22784a9e056e884713c0812e8c7981e49328\nRemainder = 3d051148ec43a72\nA = 76b9453d315e7a9c592e1f2640f5b6b90a65e7f2ff8ac24b9b47e35abb76fa5d303be6d501b341a882bdd9d2a1c81a9280724673f87fbe9803ed5a2e7edaeec2\nB = 3ed5a2e7e",
+    "daeec2\n\nQuotient = 1921410e1a538a71d33d9c5de95593fada116200c399fa7590ebc374282570477f5f4abdd5166784ccee9671a1a23b96378df62168049f6b8\nRemainder = 1a1f4aeb882d7546\nA = e4aa84f782a65d376b10e7789a7d56695885aae274db6cb37e0a34414397a57b4a5f76dced11376af5fd11d31828203e685861a6dea239789196fe73d0e46116\nB = 9196fe73d0e46116\n\nQuotient = ed2afbd2e63617a651911017d9d02224d521e99275ab642ad1a941827983b17ef0f2067b5405b20e8e97f2ae6099150a1989df94276aadee\nRemainder = 4578107045b9cb81\nA = b547cd987638ff7e3c30fec9b728bc10c3b8cf16e7040bfe0fe9a26e44d2898c4c4d28ef525cde2b4007b2ffb3aa80fc4514a99b9aa2e112c3acc56b72ddbe9b\nB = c3acc56b72ddbe9b\n\nQuotient = 56181509251931afca3bb9dca21eedd6ed4226be67497d8d1bd0ec052af146993e7358f132e842f9b6c4934cf1b4501f5d6c5912e65c8d3ce\nRemainder = 1b9861df51429a6\nA = 32988a4e0769a5aca200f6f6f1498512e13b4904a9a311cd8a962fdd688de0c6e50b04f42cdd2cf8bf9b0a6922657f9ad195773e1250f85509672452618da9c2\nB = 9672452618da9c2\n\nQuotient = 1fa45bb973dd1d2df0002772afba55284a1e41f6aa4b0d1a6c6a4beb8ae00b52e88a9889037b8bfa9b7ee38036c57b713b48af156c3f9e8d8\nRemainder = 2525d52ecdec8814\nA = bda657ddeabe24c82c883e85822941bf64448b7cbb368468078101289b6fca36680b3884e35edc1fce5a5cdbdfc11359a1ba8ac0785c09ba5fe5cdbd30726df4\nB = 5fe5cdbd30726df4\n\nQuotient = 63e21f5568d07976aa81a2690b9e81b76fc3291cdeb010d1693d0e80191186815c7b2f83551a5f1b172640425d4733f06f4df1b2c8a7e6ed7\nRemainder = 14781a368471ecae\nA = 9f3dad0b3b56de15ac46cde1d79aba6a2f3b34d685cc810e9fa3f2d865bea4afb480d58653630319a258e9e8ded9be93cda3bc52b80a9359198221221724cc3b\nB = 198221221724cc3b\n\nQuotient = aae37878db016dd758003b85ef52acc7288b7b74c4723e3876a710baed4751d3be2ae49123b248f2b2c55a5be702c4428b1dba9b8a6ae8a9\nRemainder = 6c754d5c167e1228\nA = 4b93a98eb7b92cea0a4f5c2223e77abdfbd332b39f295b4ac40f71625d88e4add7e482adf3010082d8dd8854cf714a54fba0887de87946e97137cf7eabda038f\nB = 7137cf7eabda038f\n\nQuotient = 9881f551c4b7e67611f37df29e77cbe4e2d9fd5e17b7da3d013d6f3d4312e53dd26dfe3a2a12525cfef1ef81e6ebeeb7ef8fb4f918bf15ee\nRemainder = b14595005716bfe3\nA = 7737f8e7337160c14cfa8411236ca0354d8aeabf389b9fc4b14bb2ec3bb68286f3d82eb394dbd8062862b955e9fc8e86eb646317d1315d09c81ef51b30288cf1\nB = c81ef51b30288cf1\n\nQuotient = 4c8519d4d85ccf845fc5b8f31c27c60f0893ffda29ba86e8a3fd5fe67de5d29cb29362679abde996039b8febda2ecf71f6b9e1c1874361464\nRemainder = 10fae644af084f8a\nA = 900f7846e927760d9986894de6489e53cbbcdd59f7707917e7581422508f2ce79b77bd2c56d964a41e60baa927ca679faedcd9cd8102dde91e1f583ae834b092\nB = 1e1f583ae834b092\n\nQuotient = 16ef17b40bb73063f3cd0929cfe2405ca0ff2d3d426ac05f8a8dfadc85659105f7f728e113baab59247c4c7936ab975c08d6f1c72c12c532\nRemainder = baff11e6961c72e3\nA = 130b212cb6f3d854e4f17524953fd8592f5e59dfe92fc7d955e2899d1dde1ae4aa20d749caa349ca8d1bda7eeec2310532a7af54660e2a1fd4929335a1623bad\nB = d4929335a1623bad\n\nQuotient = 1cdd7ee2eff733b83beda5b862673177e2f2151ee0fd9ac0bf0ec5b7e05516f1d1b59ea754b0483d0e4bfb7668bb99117907a58a8ceb78028\nRemainder = 29e33e0c2a515780\nA = b0131ec2c1ffe9a523591a9453d2fc740bf885e7efc1a0158905da1e646745ef1bbf39b406564cb3da2f842bee307b36219bdee5991c969d6199279c25d4e380\nB = 6199279c25d4e380\n\nQuotient = 20bfcd06f9c54c537ae563e33dab31047aa30a6bc4e7eb0902bfbab3bbb7e65df442c46625c39e08c88310116348e9ebca2450ab463727f90\nRemainder = 11d8f2f6d4c1f55c\nA = cefafbaa2990eaa88184162ecb118d20e5999e5a8fdd25ae7f6248650ea74a8cfb92c58efecdd5d31eceb618f1596d7a6bfd31d092cf86da651f629975faf91c\nB = 651f629975faf91c\n\nQuotient = 37204c5735e4ba5e47e845d8b652cfc2b1dc715abf21ea0ecf5b1c6c8b9e596591fd7a7f41787be1a028c147a721ebb891b0abe3bd079b589\nRemainder = 1ee700ffb0ea02d8\nA = ce22d36b3cb913b32bd0e25cc14c7270d3f7b8e600a9b6732377f846adafd7fbd8a09d12fb7011f2283d988fc29aa25948dd4a0f24512b4a3bd460ee19887d35\nB = 3bd460ee19887d35\n\nQuotient = 191051194e4362bb201f5471d4bfaf92f79b6fbd119ca3dc1afffba334869ed9f8acd14fc42a2d8f616d652610a483ad90f5140e9a5ca4172\nRemainder = 74785b6874d8fa37\nA = f3c79f9a6af1c5bec72218d969620149afe8bf068cf7a7aceda977076665bb5a2c30729ac3aa976c9be379c6a5458f1501db8802652ef69d9b9f4f097027ddd9\nB = 9b9f4f097027ddd9\n\nQuotient = 6c46c17fdb03d192f75d636e1e2ab4e858d55f0f205cffd75550c4347726b5cfe036c6c901782cbe5a04f1985d9fd1dd39d747d25a6a7a88\nRemainder = 9a836be71a24e72e\nA = 4f6cf6e357b4985442a25b5c84e2cc0a5e685e2f5ff71ceba439b81f4123e16db2296dd4333fff23eea92bdbb812daf1d27c721412fa9847bbc9a0bf08879b1e\nB = bbc9a0bf08879b1e\n\nQuotient = -4984390f93e11c9a77880cfbe157dc41d43fe901c8895ac5091c5367a77370b16d42e8cc260058adf4d3fc8ee8cc6c0099804f4c319f15561b0a2b1caa7d703db82a726c9eab569c\nRemainder = -19374dcf21822188d720d6ec892bda2c084e8af84f38012da7029a3c3660c7e813fd4f7644ca80373575ff98ab6d743e939269c51bf62e04f\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 330af318ce0ffdaa92448777ed117de9c104e0f975651322c8e01b1c470f3cfb7a78b11f7daeea57614cec37d18b89155f19babeda0016171\n\nQuotient = 1a56f7d6c06a316a9a466319cbd558a99f06843782673a54775d859768a61933de3fc410068d00d5f6ab13fafc9228fd40ad41434501f8827bd7461441140eb6977f18d102d446\nRemainder = -3c3d566cd48a909292be2ce30f88ebb68e9122a3359f52d1d7b0189c467b829a9f226c0b64845715020dee12d179913ddb7f17da2db86d854bd\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -8e770450768d07ce20ff8f5f6af464b1ee5f1d0e8faaf927a19d3ff801f6089378133e822b8e63cf29c4c9ed721adfc91d3355a3c7bbde77bdd\n\nQuotient = 42131cf8f52a6a3f189697ce402a8c9439bf05cb3dc1cf8bc49dc2f07cef15b3bf0102c941b5b3bde6440abc6eacfbf77ea8da06ce932fffb226b33dedf001e9657464b0f06\nRemainder = 4cd483574fce075404dd22072abe61200fc455c15b382c7f2962ffd82c38ec1e2c60f71267cbc35fcf77fe1f9301d6b5f884f1c416304aa9f4d4b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 38caa64e74b29a7e9bbf341edbab112a730b17103831a9ecb70ef077e9660b2dd1fbf71d7f6bb4cdae2ed7cdbe9070ec9fde996c91b9bca5b83450\n\nQuotient = -11d6883fcd705ac97cae5bb7f8a2929d6f636f4f232ae9a4af9769183dfce9a9296fa0714c3f4fa1eea467a5c96a484a59d0cdd87496b9398e7a818daf89a58add3a39e80\nRemainder = a6b7984fd80d719ffe2e6eb756e4e3bd7ab51f6088e04ac8fecdc744b0385294dd23b5007910109abf40cfca814c10addcb5330e422b6f5eab6efa2b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -d25d50f53c694cddd56aadda2654ae5888603b39cdbace93d19c117af5505750aa24e615f95446862bd693f5b444e2a876eb2cf49f6c7acd007eae02\n\nQuotient = -3fa898b02c621915f44b213ba4e80b8e85c7a2f4c78df2bda7d99494bbca3eb2d9354965d83e1c9001f10aad9b3f3ed837a630b329f5a4b28935158fbd9d291a120b08\nRemainder = -320d41a3875da2e83ea9a83947f5abb1a7026c84020e983381722bf7aa87d5987ab088cb2c37fc3781c82c81bef3263fec560023e236a747030618e9d2b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 3af2721aad4b18db27842b5e539d8cada9dcd7ac4c5b885065dd2496a6f76fa73c8a51b239b5c068ea6feffda22d8ea806fb488ad5a94210264597edb40\n\nQuotient = 179307c3e14de14a744d082825ed723b996a4e15f156ac473960583138c43f4275b4436c50ef8f21a7b450a969819b81c15bc355fbc5fb55cdd8e124d931d142851a\nRemainder = -9c8eabd36a25e995c1811b79a2a0357f6aeef4477cac0ffdd130046cb2a647f928a34d91d9b489d394965719cd58604b957c693a93145328e5568d33d88a9\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba46638",
+    "1056a3b92c35d9b8b71372b\nB = -9f2d3da1da77914df66bc889a40847a0d705d4648a11f282e09173d170e96d84b5a45092d995318fe7a954b54b88b784423402519a38bb521e84a4f6c5485\n\nQuotient = 6c0f316406afb4cc2aebe34f7948422de0b612a02dc47f4ae59419c579fc465ceae1980a3e524fdfdbdfad4862f168a9851664688c9ba01a8bc1ac156a6276643\nRemainder = bf52a2fb6493eac22fc8b334ccd8e8fa347620539d9189d535373f94503310a027c5423197c7279bb51ab8c459e27f548d57b55740320e80b753290d077aa7f\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 22b9e55639ad3ff4f071a49c8bba6bd9047e162fb31882421db8ec5ce46f28fbc35040bbc74ead5a948c47c43e9c7adc32fa52046b53f12b07b5224e0d8e93e4\n\nQuotient = -1008fcb6894d8c411905136fb3e05b38ec5d8df35db06379fc2d6d3e3579bcb34fa6e021b98b899d9d082c111b1a6ac8e50418fcd5968ade6aff8828d8e4777\nRemainder = 3d7dca387b00c677d855fc4af4d86d86331fe4309929039e828765f0937990bffa964d3ffc5d4f2f4b8bea978329e7cedb847c7cc341ee52217f903ddcf9446ce4\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -ea045323f406bd7ce25b3ab4993b5f6dd92ca80e3a02607a862deb13470ccef229fad67ae958cd87fecf4f08d9609595077d0d1360d9fe48c4566e237aa877e7b1\n\nQuotient = -42a50301031962754ebf9c4b1e125e6df3dd40ffbe09c044b1cf4b62ffb4f92d298b05933a450bcef65e86398da80740a610ba45928000a5c12d26e9f6a4\nRemainder = -c5485b82cfefb3f980e0fc7c6cd89b1345a8fb942299bdc36ed4ff8916016315a0da84ca0ee2824dce3c7e5ed49d517c45173c9c8e30b224940af6cf828c73db8db7\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 384e523d5a687bd1a90101e43334894b6a27e8c6809a8bf5bffabc34d558a8309997dd6f2a3b7c1a63100dcc0b6647b444ef7e5aa4a9c52c7caba1ebd096c3fae6f95\n\nQuotient = 1054439945ccb5bc5461fed04e364c7a36d5dd2c0428872676debe07654b2ce31e435a90c81f2bac1032143acb0c49ad101398feee8426bf270bdc0229\nRemainder = -7bf919e14b2559ab82b3c1bf428d083a4c851a7a1fea44718377e9e945caa5cf48e0b1ad727e251bbb330292402a75ecd96a56db4ad07146533a3ab5a717d0a25a3a7c9\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -e5cd83a644ec86b94f5e33d4dc307a2f14ee8653288145dabb2b5f894560c164470197fb9e37749656f47df343c245258627aeea17965fea10a57336bdc6b4a47443492\n\nQuotient = 62675274798218da426a54ed7158f8f737b7b3c328a9c351371f0cf61f41712f9b28741f187eb635ce45866762fb5fc5051776151d202e2556c5845\nRemainder = 1aeb5d1fde3c259917e430e6790b00484d0d9508391ba6ebab0f6299190d4b34f5f7d8ea2174974471a1e28ee2c15e05da645db971f699d5d0e80569b7eba7908ae579f5ed\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2622350611b486e6be7a7c1c073c230d604d782c2696038a3233ebcc3f01c6a711969094e47f49e294f2c5bcd04fb1b7c0934f19bf6e7aa519a8d4ec2c172ac59cc1a57b26\n\nQuotient = -12970cdd96b92c37787971cd8dd166999ff241be881eb9543ff29165a9c1a3beeb38b1910a5724ffe2b73ab95ac1ca88d3989aa531374d4ec6122\nRemainder = 627455cb555398150e5b4c1c53ee16dac8d80d9616ed1ef40031424287f8028a9cad1a10bdd8430f6f65368cfd00390c8d4355aa5ecdbd1ff0266a1ade235f33cb5309446961\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -c9dac93cfb7abaa3fcde359e09a92ab0b5c06359bc09ae9bade3c6783064dba90b233b4c8d5c6236a13ef96c7a223e37bbdd931eae61e845e5a10088f75b3ff5f1158e833b15\n\nQuotient = -6742b3871dece5986d4e219bf5f43c101da8896f247521fa286fde696e0b71ffeb3b6a3e4f33710c9ab150b7a1f747cee76839c5e7f2509f62\nRemainder = -203b2d6eec9d485f7b439fe9d4c640bb31170af38418faf4daad577c30e44ca06efda55ceea4fbd959b3809fa2002b6e2cb891decb09334ed89ac66ff05502036b2155ff62f8aeb\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2457088096865cd052e9cd9349c6e5e34e46c89d6e860a36f8e2a0bb1e5d983e07d05e6f6b31edc67e4793cb4d40979c029c80a13e654b66c8acf6b894f615a3ac800bbd09ce020\n\nQuotient = 15eafc416460d757d0abbda8d094eb535262a71dd033c25e704a6df54265b6123247e5625da476e0c220ba88582a1ed94265135bf8bf1fb1\nRemainder = -64ccd9a0ae0b0abcb5507d51b2e6c8e52e67907474605c439796febda06eabd8a3185fdfc0bd088cc49fdf564b5b45890b07269c15b1aa2f993cd9872b97aa6cc37dea2f03444b3ed\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -ab34d3906d8a2b806b22c73d44948d703c1e05a9337f75cb0b5df5205c5e2d23f8a92d8381372f9398c9ac2f7b9302b83e48b26512ccd0b06e6b8ef1b930ec2678d71e2eddbf7349e\n\nQuotient = 3b22916d9fe3145fcc3b8872bebf5aee4e14235f618e0aed09199852c6bed80df39256d8407d334c06f4479f230913370b7d451fad99d\nRemainder = 1b02a7b97f9ac1f6306aa00fff0e59f55fce463ffdc640364a950df29474e08b67cdfcec0628e973d42fa1e4f98e988ec4c47e4915651a1731b71d5e36a10a0d1b3420427dbb79ba7d52\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 3f74cafe9ab0c1b307cd7571fd442665fa3205fb2f45b3811b92d1d38b096a2025b8170663a29c52ca84da102e62048e583fba96a594c0b23952fec587814857c25221ff2cd0533cba6d\n\nQuotient = -12ffa4b6fc369404968911c17358012b993c18c2ff34122e06f450d3d441926b5f5638b40efb012d76d8bcd3c0012d0a0ce5d55c596\nRemainder = 64548684fd5f6c816bd296234740a4eed772570bd4a48852462f9cddf14f1350ce7c7c6a58aee8f66ad7df87927458db09e3af08eb5376de08444f35e5171cfa0992fb27f70b81574f6e8f\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -c58383afca9e1c480ee75d3cb6b0b99ea42e827d39fc96bab6b0dddc97e3eaaaec02a74847f9f7d49937f5ade3580bfcd491990737d172d4079437067251ab403c36a9826e974b113e2d2a\n\nQuotient = -4964410c2b038573107b0151b36177cdd62495e0dbef536b59c8aacb8836bb45e7bb014e5022360621e8e82a273d0d462b8eb6fc\nRemainder = -1250c42f8c9b129a5c477be446b86356edd1b19409d362c3a5fb5d59c30f1c3fdc1424a88a0d6ce20bae885905d98c8a5a6495931f73edf4c60112ed78834e3bff6de3ed54c867fbf16a1cd53\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 33212ef4a8e80daf1049ac6f639f8e1990142ac32f7ebc97675ec90f8eb1a2814dfdd295ae67317253d0187ad33f3932a3a7efb056d0a3c87d28e64e23e9f1de751ee6f0f61c6f39d08d72f0a\n\nQuotient = 17f77efddeed52ef2e423bc2c10d2ae15c97384b766f4108474964c2a44789e61249103d9f5fe00b4d612772dc6ea12a42e395\nRemainder = -1ec95323b7b95169d5ec0667f3cbf683e98c15dd0fe44df4ed9de9586e43f1f69337e41a6d11d889452665dc0b03cf8d9ef2effe0b350eeb9f6468751b8a2c42608ba2a33192b770cb62381a966\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded49",
+    "9ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -9c91fdf2dd1827ed103a102db254630c278bf8b47bb12a342a92f081acbdd8ae5f5476ae194e24b187011ac25b19fd09e6e690777f9d3efb6b3a32c8f5905e1478a27fe4b1adf17a70abb4e7571\n\nQuotient = 4f5dec525ffc737094f40d27446ca0be5b7a2aff02d51d99609165c4cea0dbbc1d92bc0a8680782b616c149bbef7f5ca912\nRemainder = 1bc84ce56a9a0c74962681c02ac927051c81f3824d9f3f0f91465df333ecdb449473d9c26ae3abb9509add5795e89ba5eba6ec7c89b114c86e6991ca0c185b34d6e66925a14fd82809dbc4936d273\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2f47be01e6dc6a86097676fbd472c2af0c83a2f743fcaa885e44fda7e9f350e9fb7a8cd07fda59ccb7963f1e95e6a1236f5f94939decdc85afc0e523c711b24641c844cd3113c17fe35ca988ba407c\n\nQuotient = -163cafed5bcfdeda88555f30bd4cc2da2cefe2bcec9a7c19c36ccd04a45121a5a0dc28d0bf6ab7fa4b78933c47a5d5286\nRemainder = 93f856077f5b2907cefcddc4d767ffeb0acb7af64bb9dd8a15dcfdda6c244c24fb8404ff9ea2fe1dc337faa05930d33cac4f61e171d0236e222374cb3da76396ae1329a407fb4ac652fcbdc568d0fafb\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -a8bfcac452a5e48fee9132b73bc2fef771450143ab80aabd8690ce54c9b52c2b5a669076a7a35fa6d926268077bec6d90b722b5d074f28ce3843fb0147e567c45f4e91a11416c082762e71b5c6129c08\n\nQuotient = -617dbaeb8c6f9d584e8eae923c872048f9f9bf039ec6b50cf8f09c061bf79acc3311b37c2502e560848c05ab316fe8\nRemainder = -1ab4613767c4f1f7d127e848f2bb7c72a3a9e1dd6173b63198b80d3bbebce6a31494f19b53ad9e3a77248e6f9b26fc59060e2759a20dcdbe785297bbd912da9a1819527fac550d64bfd20ed1f96450c30f3\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 267d9397138fd0374a7a58593d41627ba1203a646ec2c04997acf607e9d217b8f40183d2f9304447d6f7e727a476e636ded4697a5ff30a9ae3d249baf97969658209c1b32ddc0edf920b0b278e9b5464313\n\nQuotient = 10ad85703fd51870306c5e36b51512341d6d39e0bac47a03732787b2f62e49c76666f7f49b2596de6cb5c5b2f31b\nRemainder = -846b4479713bb19ebb8c1f1b75d2be0f39fc1095a3d2ca149b5565146bc19382b86e5ab0d098ab1fca1ce701d582400190fee34b602845c3c0c498925710f0b9e3af2412ed5ead1fe03d77e9b2b407ac83823\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -e0ffa4e120f2f46fd1430b6022fd03f71a22f9b120f8d40e901279be235b32d94760fb8c2403d23cdeb728ae73e2b16af7322d6ebd5f5673187668c99805e700f1e997423886bbcb851448dc1ed4cd66d6598\n\nQuotient = 41567bbf616ab41da51108d7edcb5a8a4877c5a8663b3aed7559421b1fcf4b535a54989efedfcc935b3917fcd\nRemainder = fc026e554a0821e0d36b796fe6a676fcd7383a55fd6158d78ace4edfc3d8aa87c65f0eb41baa2aafadc51218b0562ff4b5c9b17bbe84afc491d9e309217a5138ad48dd51e1b1a9aa51d69963b608ec47d63fcd3\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 396e9b45ce43d3f89386cfad8ddef4b483ecb5173234530c67447ab74629d246c18b9da09522c77f598957e3fd2a1c0c9417399912fd547fb1023ba6b90d63d223bcbf3e7ba155e51bba7e8635aa5c39d2b9dbb8\n\nQuotient = -18f1f395347ce8df530d9330c61c0e30ac9531b50a0af2ae7809db1258285c15ba7a436121287990fcdbda2\nRemainder = 51417b9e9995de34316a66a2f70c146df8e36952fe64124819607bd8691a465f4fde98e590dcd56f0faeb95d1b67751081c2393626713c27ec2a2123aec2a4ec3761e5ace4aaeb612d46e52e16d72a186d2ec8a7ff\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -966dfc779cbf9c388a84e947d1128e2392399ff45d9491259c7cb19589154f82f41e852e0c6bb5a728f6e87ff4ff95abcb9b2b57af1b6b7fc125497775ecc1338e4bbcb5315f7afde4e283347184b908545211afb6\n\nQuotient = -3fd962e88dc1d501fe9335fff8b6b2d50eea967c3035a3dcbcdc9599b81f9a445ed5a6ae7413b8865fd4\nRemainder = -97f06f6155f8d0ee6850728192e0b4fcf55fbd9ba982c5f1d598ddcbc4e1c4be0e209fefa6ab3b7eb2b4c645e4dc40217202285ab0a7270d085dd9d4fd24e5293faf6797b4c3c79bbf3ec63fd82942549f9e8f862297\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 3ac566d6b2d18572360fbdc626ec488aa316a74f33d71a17a2d0e1d2bf26395623eb91dc4abebf2f944e9bc3d669fae2e4332088e9ff9d9f43927a7888b1390ef60f05efd6e63ec606ecb3e164ed6dbdc9d088586aa71\n\nQuotient = fb5ce21bcf28490afb64e6746a1a81792c90eae17407c0b4c5ebf2464eeea43e516be2c615f84901d\nRemainder = -3d255bf94c3d610c32266fd472d070c0f5e7dddb88d32723b2e1a20709aed2faf28701e0d0227c2b33ecfa9e708e5ac354a97be732b786210d86f1f05d191513386c580b1ad1f4ac6890f87fd0d4270f23cc5c2064502c6\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -eedb64a6e204ee3d6df508830704f1d5b2d2e627698d38a114c07458ea0befd593a80dfd2e08fcb1893adf57061ec4fbcd3130692de7c46f5ca51361e9b79bb7a91963618b8e5b7591392a5f0e3be954e8b9978c97f12e9\n\nQuotient = 6933a3123d0b32693351a834751345300c49324b861a663e8700bdb3b70ad996747b284a8ea5c02\nRemainder = 13849ef93cbc77460c3c496e8f31f7e01a98c21cdfcd6877547161f9601680665b394933d3a0824f0d32854508c89f0e4a0873280c779c7ca636cd89cf6ee5d42a917b4f382be3b9654039f623c11b43164827f870fa0f0781\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 23ab6042240a7709d43de7ee17332a9710bd0d913c42b3591341527bf48d5bc30abb962482292d45a15cb03c9457cc8d78d1e00aaa63358427b000e59e4260bfe1e2cc603e175d7fcf02bd9f61fae3740cb8e10a510ea3d1d5\n\nQuotient = -10e67cbb33dc6e24765893a047252766c2bfad8385150689dd4fec9ef495dff63ede1fdf78bb6\nRemainder = 9dabe2cbc734b910fa1bd25616daee5657d25b6e4dbc2cd93cf8549715c87974a8336fc5070d86c11f6b670d4b3bd5ee8ae3af2bb321fbb4f8fade3f5c6c2d6c366b4d800dd13ce897f13b0d3fb79f1d9ca525b4e7286c56ff29\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -de093dba98747499f2876c8b6b7a6b9587284835ae35f0716dd594c826cdf5b9179f2c6b08d800a77a6936602ff2b64ee0b7c94493bd5009633f5bbe423454b7f018ae96c21230510ab4bf5db394ff153b0e9eda3ef90eb4c253\n\nQuotient = -521f5e35300b9ec2742ff472cf61235dfe2e449772afa638b1adb812cccf269afd164b7602\nRemainder = -2ad10e8758e1d358d4744ad344ce319617027107c0b8db195d1b58c6e6035450c9b377f026fdf9e5737750af5615cff2ac3ccee623c060d779373136d48a735b353d64bcc5f2e6ea1e46083fd799b5f57dd5ad0ff3e6df9764af977\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2db1990ba1e353a1a62de1b914ccb691380b6ea937c13621a29f0a40ecef460cea52cfbc77d98706fb3c9939ceaaf962fb8003b0cfb40535e0dee22e8e7d04b5648fce2e58803242c199421cc4b26cae776d3603f2ce410d",
+    "dd1e0da\n\nQuotient = 1d45aa6fe6837a1b7ac95efd55d1690b66487202949a286fc85da7ac0b50b860215e44fb\nRemainder = -7984639b596f1d4e6efea9d8b4719215588620ac959034b303584679a44fa84a4be0c89fd2e29f54e62959f9b7a858c06b0cc051176af82d4b85e7334555ba11c39e6cfa1829995c383ba81dbc220e527e90a1d440c1d069703cc1370\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -80316fdc405bb002990d3ef7d0e98defcd1f0e370d1e51db2d21ecbd96230baf69d00b168afcb7b8da9edc3ef7f6621ae5c5a0d7797e5c92283342e42468dba1036fcb2ffef1f493ff97826477364f6b5a41dc56d6389a01b83eee041\n\nQuotient = 3c0c3f7a777e611d1bd0d17d669a1ef7920b72ea8de06d4b415a73b836e37d6cf0780\nRemainder = d8c77134a75584ecd5ab29e97a909ec139464901f9cfcb1d3d9e29a63d204615b6845d466c8710873980f107c40ab54eca9f8933ef6d726f9bd0f3e9e97eade5eb1a9bcaa7b01b6ad51ff3ecf67d6e4d345f128e990494a2db434fcd3ab\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 3e7dd961be36c0c286eb9e78bf3b33e6f9bdf2c2137a0c660f1d21dea31ac9a044e526bf47ec8190e137a60f1f55e947046b9cd04a2485679e48cac80a1bb064a915208889289d63a6e338cf7069ad799861c31ec6eafe02a4ef2c2641c9\n\nQuotient = -178d749de2dae3a2ea4898c59aaba98ad9f340762040f5aea13cad45a793f1256ef\nRemainder = 6c5d9b19aed9f099255b6e3d251aa50d1e534e6c86d82eebe097dc8dd0748201e48ac62eec070a999c21f5c7684e5a700212e9079b5fb731321dd1e16ca82ce80c1f5c17fd1720f1353bb90997f47f5fce335a43a6f59facff0b3724423393\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -9f52ead13916f9807d0cf0c6699578af52c54816828f22de62328fbd7b4fd6c3740ffc82af4e24892092c7ecac44b5e775944445e6615fce25610984030a345731f944128f5734e6e315a0ea97aafd7563105695d026880d065761687b75e8\n\nQuotient = -4fe43bfa9417839ee408b254603c3dd176653b6915a89de5b781b400162fbed6\nRemainder = -1c15816e03751a203ae23c48965c8541849b09996bc81d28e28d7871fa87d1c3b2d383c056d3084d7d01d853bebe270fe2c0839e71851e169d417c47caacab2aff8a8e05f65dfb20eb17ed8f67475702fa83087bd868246cbb885d52639797b85\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2ef8419306ebfd215d9079c7a2b959a53ca2f4553845e3cd32caab2635c0e77fee8c5c016c121e3cbedfac57f810c132486ba78df9e719a976e0112516893f14cf9b89f95a89aaabf31cce509ac8e7e62ec3833f0be4336afe6d7d73518141d39\n\nQuotient = 127e8c06e12943017f9dd57ca24dca0ead230092811d307386c81b6efe009c\nRemainder = -24f3431858d5aee412443feab243b465b849f5dc97e4de4db88c7adf774d9bdda65fa0a28cf6b18eac6078b00cbeed2ac406f8426aef868d4b59ab045825d4b0a18af6c9105e32abc72fadef55b221278d329ff6fb9019630411bec143c4156df7f\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -cae6399216401dec0f8ff5eaca884ab061469082ee3a18e49e0b4d5f9cfc98a598c373249a8ad2374e0b3de71370e93a98650684fbb931aa5d8b4482cb0be142492bb71743c251346df66896806f926a4a5dd4c16ca3294f01bb998835e6583d29d\n\nQuotient = 3f180694e59df85f48ac02b6d4faa26278af9641db18d79f198da5d802f\nRemainder = 36cf82dcf8c7ec783b4de68e0627a4a4b2a508637c176de09feef62dcf382bfa5d8b88539b5ca2cab6cbbdbbd0e54c092f00ee13f4a352cb570034cb0a012cc0fbdb6ed32967f3b81d146f352139bd3d9a5c27789468b7d79b84d6a8f6085f859532f7\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 3b7983bfaf565c5ca444367654a07b8bc2bf7fdc04ef12128c392bef2f6b67d9475b4d2f0ce1c380913aa98616fbe1d74dc5c9d64df15f5c9b87a8bfbcadf335a6e8f863c7a01ac175a7d79645ababa5f961fad7d1b9926f7284e254fed33765339e0c\n\nQuotient = -11f635baf7b7d613e84dc38978a21ade2f4cd741d0c4f6ae592d93af9\nRemainder = 4317c686dfd56216bc4865f8dcb6a3446e13d8b33861e74d6c4a3223c387ffb8caeea0141049898609ed1abfc2adbd21756cf64a72272aab6c0b8f2177419abcbf9086635dfbea80a7b884181f2f2ec9a402cb0505e8208909fe062d5e6dc7094d66af62\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -d0ea50558197566f22704e66a70328cacd6f4b7ca9b00c16b7c4b4e7dcbd47c9b2526b3858ebb4de7a571ac570872f3b44ba1fec655c0778a8a87ca24851f6072c5c0b7591b5e67a8cdaca78fa46f201e02379fcb9a8470e4a4971acde36cf501d369751\n\nQuotient = -64a078497f85588d3402355bf3e83d25ca1f0ed2c24a395ef6de6b\nRemainder = -87fc31ac66a24ebd629a26209ccac1b2c85e52dc83c5240269ae5a27333f33d31152c9470efd41472af034e8536bbe94b0a49e892b1d23db3c13fd84b7395d7e3f19d7d4cb4a4c07dd1860826696cf7202483446452aed2b4980388e7eda0ccac792d77a33\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 254a85bf512d9159b00a70678239902ee7e15ac2790ce5747c4a4743c6a0851e6a179b64c75acf312dd37a7b82a729246f79196b8a399ff476c48a05f89c29fb106bb06ef0300c4b330a7b2bcd4ea1e82584c7a96b99ec2131c885c5851343cfa6ae4d384e8\n\nQuotient = 116a06b1d38067cef9f55875fee1254c8ce39b42c19fb232a287\nRemainder = -c15a797fed3810e4f536e9509564b2142ffbfc0c961ee5aa923d43a824765c05d2a99fef79bfcb6310c77a91d9bc6d0762bd687493865de270c99989e891fbf6da7ea5c7c7a1032449457eb73222a011bb755ff44e4bdce8e86f8aa9f687840c0832f7fd8ce48\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -d77c14100d19fbaff6334ca6aa504001a1d56f274632dc89d48e1d517935503c26b60c047cab9e186a55b72439761c884f63fdd2a38ca1acc653f6ccbb4b7262e6215e6d00c8829b448b7ac8716fe0bfdbf8088c8c61eee8f8db43b7b5551f6278081ac2eb1c5\n\nQuotient = 6fc9533f6d0e6c55494cb1b319ec47bde8e621aa92d91155e\nRemainder = a1a70f674cb141a896c4adace0dc58cdcbe2503fd0ad36ce348dc5b8afc96d0f2f8c65bbbadabf2920012798b7ccaedbe8d896dd2674082ad3cc75b54c5c190ad56ff34e8cb5dd29c031656497d48571295d6da396d5f4cdb652732d874a79a674d06a1d7b979f5\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 21917f48bb8e65646c618068fd9069c06e22ce8c679a845f9c4ec843849010abeee12e2d3c61fb963297abca30813c446f2ae82e909ca6ac7839fb58974fa65f3b5d91fb8b3f99d948519ed56653d50026d694060208cf48e3c757f64885b4ed4328c6f071e9f5d5\n\nQuotient = -1abc689fd19523d2e295f260d248041bd00ad3009cc7581\nRemainder = 1ab5af1478fe7373d012befb319b53ff9e36899c1749ea763fb74f7d24624e70ee78faf3115c2a423629528f45295e4adec7b122b993b5c29260558be4831df06468bb1c63e8afcfb1b9b533ec6acf754563d2ae25e2adb4cfe5ee3024611e03a156484a130ee01f3c\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -8c5a7b6bc8ed6ac015ec24efff607b0446c1b736dc8b409e2f433e69d0ca015d70c64b4c924175d0e0102ebc3e1dd96dd4d5bb01cccad229e699f9d8f9ad0e04339d70cd113e93d50c10c03083a81264396",
+    "f5db2d979d272798ed30efa15d52289d0c72f42582ea56f\n\nQuotient = -4aa210fbc0457fa7366a8aa9a3acb3f9fce812303ec9\nRemainder = -737bc4fdd3d5496fc7f936ccf14bfc3d93f5b7caf4718c444db7a3228b41015c67aed304fec7704ea8238ba6cccb1e94cac3bcf4764a44bafb49e5fcb0339ae44c0114cc304b9c4370363657cd2bec09bf962ccb21f6091b081e71d2bff8556600576e18d4f78fc68b12\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 324774e49bb429553c10156e8db122670d6dcaf6ef5291f515c517d7ffaee36ec5ec5ccb4d12dff71ae7a05bdfbb03ebaf4dc6c4e8bfdc165b77cae20153c27d53bf27d92ff25643b4888cb586e773955a1c02ecbf0fa6958a8ec0b832332eab2e449be6e72c48d2f1ad1\n\nQuotient = 1c8631a18d189f1fb689f896005f2dd2098e0dae9e\nRemainder = -1a1ac9612fc3354056a5378de5b315f12591ee71f0fa9d8a6b2ea2b1c4eca9947e5c4f5ed3d4b78e69ef7a1f5a9894b9c7d85f6e2244ae76881eb06584eaa98c78b60b46084b517f4882758691f91d9e2acfd580d5e901dae14ff4a4fd6b0d7c73450e4928fc6f02fb5463\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -838df2a27bbb033fa0e581073b879d6e8747fff38539801a1870f2e52d91bc84cf10f2560e93784650fba080304244dbfe9da679f207b6920be46b0214a1e490537e56d99beef3f58b30f311a12283501ad79a5407ff209d19a6efd0421aa144e0cd427380d89bfae5d1f5c\n\nQuotient = 4213d04b9f0b30026bd355404bee887b22b2cf9\nRemainder = c2bc097d1c20f050e88912f066b658446cacc7a4d510343a8d88ed007a8c0cfd5d44fe5f067a0e81536d121b39f2d0feb8dd053bb5632e3f9c04be5f6bf4091d646860cd38c96271cdba466ef8b7e2377a51d5669117e664269fe3c08a51b10e1e019ac063d670a3c7db12563\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 38ca0c2f03a5c56676a2f95cd7a69d4aa2085343af6b1d2a71e0d1c54157ec0e8f9125df2a499cdd484c04feb23b1e0042ca908db74744584036c79f21c25c40401d551a65afed0ef35f1ea000fa1a99cb29e6307f6ca0304145f7e483d008cf9efb028ebb654115a8c6b87a08\n\nQuotient = -134e043b3b88b31f89ff4bc709cfa1bd2c1a8\nRemainder = 99c1c846cbce5e9a26c5afcc0186bb1e43b2501ab3205d13fdf01dccb9b1a935bc1cf8adf74d58f1c316381577366b6d126da49991a0d5e02acaa678085f335ff8b8e975e5bf2e52a05488ebfc21a3e0d0bc5bbe67442f77bfc3c1f0c03b7f7ce42bd0fedd8a498f018d8cbea47b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -c261a6c562fcdd56e67fbd2b91027f17c95da43175eaca6e4069c16d240ebbd240582dcde953eea739a4668fbfcdc6af8ff3ab58674c95de90fdb43f64a61108b030d644a44b0319b912bb563f61e520dca9c88f411b32e99c872cf00a01f5badad584636352913b7429b99ecfbe\n\nQuotient = -448c4922b7a7d5e1efec2c3f41d0264b76\nRemainder = -2599e928027d10d3a11056eb719768e5edb1a625fc0b8a1dd4439ebd30a82bfdf89e617ac7c71622058cc64ba32dc242d96fe3ecb856f1b146f831334af562cf88139a99410dcb869b9ad6ac4826563b400b59f55d8fff262dc920fe525b12b2fa167ec237028a098c9117cb77bc3f3\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 36be11eb72832f8ae7b6bdf689f794f62cc1c885e64706d14a77a11df9761c2e9cd81d8f6a0ad0cb1696c69afd80c8bb992cda5100cf1162d600515568b9dc9c81a518da9d240888d4984df65c129ac0b4c557b4e63ee5be79a27473ff5bca58e559cb04c4ac93b61545e7351bb6514\n\nQuotient = 152474a1a76700598c18d9301866ec00\nRemainder = -274a2f9e2bc5f9d75f9897b28f840b71bb10a3e4e7a35ee1dc1150be61130b4e0e987e8742c5edb75a1ce3158eb8bdb7d657b8ba39436d7c88fbff160c7488ddff2f13b3b95ffe149a3d0d2d406b1737a7671f69c0e5d7074a151cb2776b2d13ca24bec261662f2967fd22339ed6c3f2b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -b17c79a31d5085b49793b6a6d628109a6047e3b1afc947e5212d0a9ae32b1955cfd6fed07fc60634ad15f32a9e402d7d5f750fb6d1ad958211f9e8ecda8990689e5212cf72b24e9b51bd07a6e0477dd4c02381d0ab6c0ad3cac1f620f723ab004880800736804751349f6bb19d3db48da\n\nQuotient = 5665f53d5a7405c83a5ff382ec376\nRemainder = 252d055186ec896cb3142c9e4e49c441e2ddad365b86ad21ae4ef1c522d3306c2834d6993a5e1f8c64a1ed582bad8ab746f7e773fc004b1c47814f73560db72f7237ef6e2f671d3b19a8777be2e4c662a76db87ea64f32c48ea371b1ffb15df26726854a417e18afcf49054c6d2e0e337e71\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2b6eb2caa3ca650be02fa199e9ea6c48646a76434e268713753a547e49571f9817ad396f2cb7b16d307801fc8892f0af3e7f93ce08f7955a8acfbc0b56add4b4c7ef7351f60e402b9a8ef7fe02ccdcb4b00b7ffe78c7009268dbcf1d606c3a1b5307d9a8ee6121c6a635a742b8bf36b56cc7\n\nQuotient = -eeda035247bb13860f228d8f2c\nRemainder = 3976edf710ab42bf069e5829de7e16962d1b765f6ae6ad0ffabe723e21ab01cb9f3f5f4edb1d8c13cafc0556c0aa93d72dbcff754ae9260abd294647b71785bb049bbb865a26bba22defc458a14af019a796e942e77d03484028aac2b3798fa730ae0193d89728bf80a8728715a0807b3c497b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -fb5e55f261aa96f54983869d58b3e9f0757d363b9c43aca5580b7c0380096f396ec79d1b30037702c19be5889fc6376793cad51975100f33ebf43e0897dfabcb9adf3adf8d845aa7589ba1f6d155b25f73dae3b2f835595ad6050401fd4e6392012d06194af415b810b0c10a53bc56350bfcc4\n\nQuotient = -5b37eb0c3e3f8f8d9ac6f4e4\nRemainder = -28fde388257b9a11441c592580cd38caf2d69e2ba57d43151c77d26535226e05e08a9e6d8ed470d4354e9f46b7626e5f2b22b652a2d78f817bb51598c727a765941fba63510b58fb3dd5f30717f237da43b42d20bc260b06d488c9c912bfcea1e7808544c58960a3e1355c50c889cefe75d4d9937\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 29232a3fb059242cae6e0b419ff13c479048cfe46a9063188706c6a3842674b16a1aeaf771c5b0ef401d2dc8a57f6fb4fe1b3c7bb545c18ae763e39421e6a07c4469d234f9fc737ac21ca67a5553c7ed693eede4325dbd132dbd9889d815c02f426801eff1f46e7a52f72845234acc6c153f34065\n\nQuotient = 1c7ac058af2e7bfbda9484\nRemainder = -54d7aa6dace87e61e24d87053b9d094bd160916b720d7cf4f740a4fc5a7f03909773d0456c530ea0204427146fd44d3ecec51d8627b5768de1494bf42081a8a4fa97163b0b93b59e70e533f3257723e441cafa4aab471ec4086601021c4462e1f74bebf298ef45fec98fa8e6ea97415f84c93c12633\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -83c2cdca7577b32c20e9e20fb498a2bceb7174ea9aca09d4dd2fc7a1d3b922797b4e9640c7eb9dbdb4d93c7fb9daadd680c1c7645d8102d77e9c877a9f65b13239f9a650dceefc1fd41ea9bd2b38a622bbec99cfddbc6e88f377cd51cc29fd17a27f3d0d970403a2aeeac6ff9fd69c3bbc5c2b0fe7e\n\nQuotient = 472df5f4393f33cc382\nRemainder = 16579a289cc776a47611353e158c43dadf0a78833396f8419fcbbe47d90c7e840e2c90e73e563e6c505bfcf691120ab0f1e9ef9c31db608cade70eb8e487b1113a46e2b5c7f4a172ad99b502eacdc0f91c295fe608389e61d030607a94d09d349fe1a0cc46d1e07c8db533cedebcb4a3b89afd8b924993\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932",
+    "725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 34b7f6780620246f5a0a92a768072185f02e57a52db1d865c21c952f4386ddb7e2dc1df076316cb4f2f394397cbcde1af0197fcf33e6428e6f5d42a9ccf623f75fae5940873097d4591d9b1a4cbd00074d134272700ab06d901742da695c3ca9d4f917a808113336f883e769fa8051cdcb0cad7cabd1cc\n\nQuotient = -12b4e74d76bd306d9\nRemainder = 8768fbe8ddbf60b548938d8b4a74c4a326ef335257e5f513e65a7d2cfbe9d456425ceb719407bde3cbc74c9c978970597b5663a0ec61962e77eb351adaee2d2d37f1fb55b5d2ceccf282ea3a0d398be1dd1b166d55dce04a39ef434fa392893618003adcfa61401276ce4e599051ad93152e3477ff524f0c\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -c898a753745f0fc178227a7004d917557cf3dcae2e85e95aee51e137b29c895755853ce2d61f214b80070174cad8ebc2795a7d070790acd335b383f9dc88c01227eeab85f1f29d76c1136ffcc7b9fdc073a3a03d8812c7c561b32d8e69754fff64acfd64994b7e9574d2a7cae6bfd5a6fd61dee7ee993bb7\n\nQuotient = -548c97fd02eca7\nRemainder = -939e90e281f97a433eb1c6510668d0fc448f03d737d92693b6362c692167add7e4442105d60ff3db29c03ed06c3121aa4a53c4625906519a4092e4821c918d2264ed0cf088b7da43a222877f3ad9a9fe8ec06fc66b9cfbb44e0fdca1dbe4e461dda9b85231b5b9733e0c78852da83bae557755de3680ab61d4\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2c61dce04200e725ab0ecc5016f66044218391bdf650bc0bd31f3749ac06c24707e79526ee459ccfd4bc22834f8d23f391f2e99135f92b5abd0b04079ab75a263c0e98e46edfb440cd865269ed7872e8c1ada312df1bfd6a5fcd2ebf548d7b7d1d75bc36f62e5e9d15262bb8652a8041e5c8f4d673eecb777d1\n\nQuotient = 14622572f311\nRemainder = -6d197a84d2ed486327790059adb5c073218c56345f48c15caf6892734fff0aa7af4782738bebf24d984bc8adb3056f67e57f9960001a67fa462afd8c57ac9d60ae6517d58ffb4773b637ebe6bf2473a5490511fcdc576a4c40ed03b3afcb2fd27c57b66a26f6d3f9b2bb101502b1117ba3ce7214c9db6302fe20b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -b818674faf69bc92085b7230d9335d7bead0413f2905539a54e8d1233843ef13f07cb5538e0787097cb24f152cf54a92e62ef143e31cfbbaf3c09650b14229a4f61a783eead26430949c88a87f1618788abab9728aa52dd8419f5d568e6a109f278b2afdea91cdedca43e562d4bb8fb7f1b7aef13992fa7edc320\n\nQuotient = 5cdbb03ee\nRemainder = 1cfa68d5da7a600a7ac598b9ca1a0759f972fd9a46ba62e5e96d8f6f00fbccd0ab26ca03d14470b43793411ea9803c9409908625fd74ef8f9b2d7c2064b2e3439adcb684e6f01432a1feb0f492fcdd2b8b5a6cdbd0bf460272218bcf763974be8784e5306c219ee535baf5541b8580952e3690b585fd99f77c46d69f\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2869338cd16322409d3efbd328b27e2ba53cbf71816ff5c093849b1d866b8cdecbd6bd8ffea0b7787251acb760f85c277ded21e56acef05d29bc728cf44f55be87cb4c8913408a01a1ad53461058a1cf94538f05ec14a6d3eba804264df957de7eb1a61b794a1141218966463dd42402c260c229241ec46afdb5a06a\n\nQuotient = -f16da1\nRemainder = d8b66b622b5a54963c2c84aa186bfde5b67a3562e07a23a5f6843bdb615a3c5d4f007ad8b275ad7e4c5b1436252efe35699cff2e0546e6dd8c7230d6ad560c51cd54db6d312be32ae4c708e9047c3a25c211e2566c58d6b9291de31612006d4e847c6916702be99b3f7ce40e1ac842908acb7f03dc120aa8998c60737\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -f8af8fb7002a9d2218dcd0f0c139b8e3dbbd48e25a5c910f6d0b6684bca224f62768b64955580306bac6bfd45b99ad77483563fc7dbe015edc06bee3ff93b0afa8f5866c23c7a7570b366550490c97ad84062c2495cff30717aaa965a8e15e270b504dbd4fa943be4f97a7fd1f3b589bc9fcf4f907a7690d99c978a374\n\nQuotient = -71bc\nRemainder = -13316e9b053a06520526f579718c326402d2a9686d51a340375cb53d7cebba99c8d1ae93388db0a41cf55d5753dd1174014ff3305fcdbd5b02de9e90c45ec0d2900ebf6ef847c2a045eab7f80f07f01c81b9fff093a779a280ae42239df79de8d2ec4bff6723788c86786fe276ae6a4dc1472442b552258e1e5b597305187\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 20fe256859a2e4c4f77db6adef78b2aa4758b29ad0787ce7e277bc68391d5949bb4dd07a9b1a79fe890c8a760871d81adfd3858e27d1bd6de33fd31b8aa6131fef9130a50f995c3be1d615d1bfb9878804b7f6494237d8ad78ac219488f17335ae54b494532f03a3fc8e9576cab6facd90c662658878fec86db66bacda3a7\n\nQuotient = 10\nRemainder = -23e09736f469c83f280052ff01071b1bdb52b7e2b061e8a1a8c6a4e091fcd7ca0b33ade885d928a11a3375599aedfe554d1c2289795daba08f07327a19a8adfc219592bcdf9fc5aee5961a48b3b1b5fc380eff5ed2ba7d7e564462397fb6c6187254ee41c74602b141d7adba99205d2e0b35da57efa96397b3a5d112751cf7b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -e849bc0bfd9560cb90e42c8e4e88df175133c14466e530716d89ad0326b660b0e617b4efe8df6b000f517d3cc24d9dd4cafa2773dafd4c6bace0aba54e43c17e8e3ff9497a97ed83e6408aa0aee0e6485dd1d89d52520d1acf4d587422b0c5cd2d5e7e81fdcf842d6331779e800f96628206e8be020ad4021789008a641f67b\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 22004040a65f9b6f120bb7243c638cf3a4cf6fc58c230da932c79568f68e31af7a7b8569aae77af671f8335ae68d6dc1698baa9d6ba9cd633a662101b45bde51d55098b50fabde8546f317ecc2ae7a39521bc075942e3751a349f51ca3c371f3b8a6cbbea3e11a334d677c07612bcdca767194c07fca78ea8a06cc3b0dc6dcb8ba\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -cad46f410062dc33ad4d712c3b743ae2b7613576b2bd7c346a8479ed679a08e3644c7ee4f23b95f1cc9111905714b170abc37ee1003956f64f0a7e876b38d524fbb2436ed56069479d8d2e4029770f7801a7278fff99b3dc76280f35c7d43ee594073f725554a92eaf4f785c18a7cf6669dce5adb0995233241f3294cfb5bd8f4741\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2fef69f9745646aa13e0c38d77951161a1f881a7ceef",
+    "032698da3fce00764959f11140bec7d7f53d6777c3622453d4525fb068da48047609d18d463a8fbacde1d21035963b668ca11d5b9ae66db13de7a7a5b66a40608dfb56d9f9f0c8880426641083a05b5ff9e6ba0d6da3a04af1af01dc218e9b4f6ad7b1d3a4d1d26a5c906093b2c\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -c50a24e5ddafb768f64677233c5cf09da1b4f06894bd68e194b23feb5c5d6844320a12a02d13ad012f13b1438eedd6313bac9c1f9bb4548fcd314988d8fe0ce6458306735307afe08a96a0c2bcd9cf126f529e48b7ff4b8266caa28c40b5c3d2a473ab8805c860d27d7ee9c032423148d96fad019490ea019d40679de7a2a3323e80979f9\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 3a8682d0e5a4efa985dfa8bbddc2c0d72a4400b8b070a8cf7450aa8f831d8a91c9ae3542641b7a4ad793e232a0d301b82664fe2c7f20bd9bf8275828a2a20027d6056b211638b9b0220fa4252d058bb485dd3c4622b1eac97d54b9634b558ff1bd5bd11085d4f3d288f7965af52beaa922b23ac0207d5763c24c085076128e0ef7370eeaa19d\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -f00fb238bc9383079c7ecad9b9f6efc622d58a76f2d5d40ec7cd7c3c083c459fbcf3d128df4d20ead5f585505515aab11c36584ca622d28e0cf037419a649d598346063a07e29c61b7a8e76d1949dbce3720d45576763aa0d391b39dd6b694c7cc60a1b4f4f107d87130402985695e1847e82cce39b8d0fb5c88bcf3b37d6dbb90baf5a8553c3a\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2b809f6baacecf61198856d9edbb768ca2df2abe9b7b8ce1669fd9259732c8569c0cafde2e32d253094480ed281a8db230f84e780c6e8bbf3657c0b0baaf19ea973fd8daa2870c9d79f3695d78e063f9130fe07ce806a088ca267fd2820f10dac34b5b32aebec20e4362dce26eee0c29d2fedc1e020d452bc2499234d07a2a6e54314e3fd6dd85fe5\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -90ed75629073df816ec1d6dfedd1cdbed9239661e362db706288dc4d774d806bfacfd4b32c3013ec67d8c2af133b46989f12f809fe202d33d5ba53659bd2a9a85d3fa542de4a5c656aacbbf8899aa66ba816b809f2629f37b0444cd3a6dfc99103bcf2a5ee87790b8401be806b5d7fb7064ff0a6fc8ec769d0ccbddbc3d35f7dc4d388d8d28021c95b6\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 3f60052c9dfe0bac797a674ca7f11377a24c28a1396ffa0f46acab7909543086aee1995cf51852ea4a21ff4bbf6e7309cba9848a7b2e3b33dbe660bdc58d513d16bc709f1f2253648b46daa7aa037332552db1da81b4ab9850ac4ec66621648fc856a71eee3cedc6617071600ecbc5ac8636233f288ec249b7ae0bac942a5fd539d03990c4fb28a46653aa\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -c12fc156d9345cdfcff94bdd324429530ad8caf8afaaa1a82297eb3a8aecf2ac021384036749e489fae05e8776da0deca7e4325436bc8f383bed579c2d67a456c4e23871489780d760d63d0bc0d1d0ab41f06a091b44f602bcdc0bd4e817202e39ca6a934c0c9405adb5a14d24da895c58a81d1c7ce52734183e00d80a414ddd8869998822364e029b3f42cc\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 205dc6227dbd3adf8ee49dffd43f835882822b1c94f92cf38f5efc62f943075d80b33588973a0e0a8ff5e800ede21d394736ba98d4eedc53a9122f8c262cd09fe9e91cedfd0237003b0124d757797ee13cd03e7a3a257bd8df756940a4d22face9287edca00ca23e7d5e629966ef710b07e54241dbace041aa6d9f82687c3ecba818203adb376ec0b201894a500\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -82c30a9ef6a83d81b77825c71ddc563939b8508f1b7e44c725ae0f61006646ba9b86507ec9a4dfd3755ecd8bfb451c2d43a61599732b8aaeedff7a304ce0a9327e2333f75e9a010556ecbc3abaed02214f25e1c8373bfafc2c288ea36b8d5f848b76295a141d8f633609a6656c07f3d98177f5fa83833476dcd111aad179001f81d6013ca3a54cddcd8dc0ce7eb24\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71",
+    "372b\nB = 33aeafda3cfc20710f0b4a3d9ace4817eed80ca57ce6c82dc2e7946058a40983c9204ac95a1399fa633bc96cb10af3ddeee3ad2337c64391a42dc7794fca629e3e1e4e03a2ae24a000e7113b91c1b6230cce9592e45b6ee7984680b45aa0aabd7f56cab1a64ec310cefe5211821a75deef2e0c8e43eb467dea79dc8c03d2d523734498d079d5493c904a2ebfd8a3a9bd\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -b897bc87a40211ef8f93645b1f6c981fa00ab3b12e117a89375400ab5f4c64bfbba01d265c7bc6f5e3a8e26de5de9df3b8f70f4a39c0eba577db5e4b7a68f751b4a69ff4a38915983cbf70dd7e066779405d572f5bbe0719c978b6865ea1a72d90d3ec8a8c146f20d98595036b3de88a7500d7b476644913e4b63e85c4e2632048e9600d553e560759770a902cca680b17\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 20604e080549e1c503049ebf4a56cf9447d90fe699a9773915b0a65588890e15bd58f55ad7b52bd7b7992a8b24704f1dfd5fd07c70aae4ccba5646405ff8a9cbf542dc334cc0c27a790c05420b552539fbf0a155861bec0e4d9e3fbf045720ea3aed58307d5738b64252a963f3fd5ecd0587cb4d7e159b4980dcb112e26c9c34f10a192e090ade157eac1d7a6f970871eaa69\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -f11fc9682601cab97c25533b2599f50edb1ac65d46f1969bd9c3cb3717461627621c8cd401a0a0b91f3645b8804e095aecab31c1bab0c26df556adafdd7e7f4f0510e0bceefa3619e26b8c9a1bc613db03857f53e9eb5d4b8f75a8cd1429feb81edc705e5a779d5f95373d2243368ce17ef22da79a6a2672496bdf629171b7973fc4659c8eae9ae867cf38d6d7617029bf59d2e\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 3cb0ffbd9ad21d0e86e4e4dab4d237e2a17d97356bdd305fda772fdd99acefcfb8309d813643c852f66e1c6c7fa41ffd44f8335ef7333b2b3e846139fa9be2c4ea762afba4e11263c0b5fab18c5efff2a18d83ee89844f5f4db2c1325f0f55e066a9e01030c07a85e2c9bbd37b5e767ebcc9b95f474ecff24df9ae52a19edeb66546a3a28980f616eb5a351cd399e5f8436f17faf6\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -b8aaffe779855c6ae51807f8cba780aa64bc22e8fa5e33f7f1dcb084fc476791565bc33eb37b4f791ef5cf46d64576f48b5fadc9f096f20c798355861ce5d24a7be1450bb871f9821099f98213d74a5e5cf83b895ae65e0e0fd096698463906a112e6e169a1cc0769df7a5ba6812300fdd33611761b6339385e1a70f8f8b2be7679ca216f5b183140e69586a27aaa9f2fac118118875\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2b7ee3ee34347dd89ba4a81415aa1269d0390346597b07444f0febb71d490a01b6fee174634bd88e8aa180409549b2726d044b4690353de2fb2294c8f69c612485aa066f68fdb89466760a85901cbc7312bfe5a6f656e67dfd2d4ee099ff97694b01d6d5b8626ab1650eac5267be53f5f3ced5dda1aa86bf42ae132a28fddb94902a515da40e0fd0586dc8b17a34af8eb03d06f70ab89df\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -bf8213944ba785e01b8d37a12de77b2ce1492f34bf6f67406cb51da89675b4f70f4d4f314f30ca8d65cbc48ee2fa1f0a3e4ac0de3a87d2c4c589b6812e850623d78ef2e46fbb555f6d3c69b211892c11a4a2dc3d8a9a19e96a07952602ed5ffc0232c140c3e828acf990e5425d8dd9ce0c1107ad1c6f96c8fbc90ffa457abab0d843094dca3c8a45ddad81b7850190625613a4851485f38fd\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 3083421e375f0722b9397e156de47f77635d62ba1d51794469371b473b71c02e3722841bca2ca06b5d1cf1492bbacfa0abfe394dfdaa7bb8787550ddbd953540e9c97631d9a1efe0c8f8e14f395c82d20245cec6d8021f8564b4d66e7779c3245734c56fb74481172f4e349d9a113cd0ee5263c69ebf746c5285cd4c0fa91d9531f769fea3610c2972ccfe9a22c00aa62ebf52b3a4c6135f3069\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -d736bce537f47ae4797faad797af8cfeaf8a4fd42df1f7e61febf8ebf6e47dabc48252ff7948f3dbf8cc369b6952dc58f64cf09b4c53447d135c7a753c21b6052a9726a47a61e13628edf0f2bdb357f2e780ac1ae1f28f211296c8961c2955b773d7dc2904dfea96780b2877af133c9591a0dd54cb20884f014f363862478ee7ec45236bfdcf0321af0692e68f744af28fbcca827ebdc7b210da38\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774",
+    "ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2cf1708f1e675ba688c0d19eb61a05d2c8642528ea6b1512375faa732acc59ec04ea0aa55e0049144be09eae1292b6cba6db7a9823f1e912df6a5032bb9674f4f26c0c8244ea0dde7acfda566574956cdc33e4a27bcdea25fe255c19f218cc4316ae8428ea61d1bf865197a066b959c5fcbd7c9596207997d05fc38e32322aa189ea06cf5139522571661745c0d72b740dc6d842f1dd8481e318b5792\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -a9180e44a284b5bbe72fff46e55869f749b626ac33c8cb17be1fc260d7c6f460f24a89e1367112e00d0da4d213a821d09f103f35bc4eade5605bef23c5d048b1cfb45dace8b9c637af626a85fc773cf51e6602a7a5999a030030cf114ed6a4ed7583465b9303a72e7f60824c12329517c6763b0f64abd8ba2b9b26cebe882a51f05ef8076e527d53a213db910a5f42be5fb78729a3dcd08d69a709920a2\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2f26e156b3b1117f7cec542b20fcc06ca66cec03a19b6f5eeebf22b4c0fc265df5ff06fc9dcac569735135bdc142b526b295225711efb71577b10aacda2fa446f5208487c725407c2188b3185237740c813e4455a6f1dde4f62916237f23164a3471aac0fcfe24ad1ce1dd81a6144f5861ad0cf22dc337abe10fc4a88b36116dc4929602ab48eb971fdd7a5ff747d6b9e0b2bff75c59621550991966a0a19f\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -9fe18ae697576dd36ebdb621d14cac1cfdfd1f5cbb7cfa8962c5a7dace96f9f54fb4f4cf2e650dbec5d1ba89ba53d251ecef7dcc1cab8c2ff3d77903f5fb5f29a4e8e3a2a3c05c105d5733b5132f2f8d88f99d17de86ca1191c32ad8ed469bb649ef188306f69f183bd0fcc32759e4f855170f88c0a3f6745aa98f6225536821bfa056a42b37535a622f42b009859c974cabf2e14f75c749d0fe5a01fb3ab0c0\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 33ab185854b20a8126884eed85181b14e75d4ee452958cc1043b099bc16c24b9c2f3e0b792744f230013907844496e600389800e45fd55133fff0cf19c9c152b9d031039eb90da568f9c5212a3ba283f4d1353ff8ff9dd04d292c265bdcb77c3e411716f471930bccbb8ddb819ebb0e0036dc1a18457cd97f4f5909a725baabbd15e8ce33875895aa8dce77a4dbedeb0271a2a4a17f77f5920c3776caa4a75ac650\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -e7ca0c037bf8bad5f8d9c5a2737e044d9f7284c616156d142612a53eb217f57f4aa00b6daa424e6c0d9163939e1ad0510a1cd64fbd576f3e54c59d7aa6228fb3caaba7cdcc951e00ed141ac3a68abb9780bf46bf544fe0e347f677288e962fb69782741df49b27cbbe8720c6f8f2e769147d89df6e17e3c592bede2e696d384b9f01b99b31c505d67eb6193a8844f8c4cdadc9fe45dd446a0dc572c9da6e58ed303f2\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 22b76d6973e37aff4a09216e57662f186c0a0748c4375d6bed370ea61d1f6fac2d9bbe04487a629118b6b0b0c8cc4179fff7bedcf048cc529498bbd9cc81ef3a103d6cac49d58bc41c83f961b6df7f00c7171fb7d9359e03c76e4364cffae5f67321ce646e9b05f9c04aa16ea65389e940022eda6dc740ddc070bfc7e589b86fd1559dc320701c39de20d54d0483fdeef6c4fd012850630b982c2e243ac1ff918377ceb4\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -e6e4d69a82b83e26ef8ac0f4c3a211153ea6655b7ca12840e7b866510d114693049c5b8b22c3a097eac832bbd1986e60564298e54dba3316807ad64bd6c18903a0f22660c9e8d5dac180f57cbb90b176b842d5b58d6dd9f47499a037833a92a18f397238a8bcdc4afd129382fd6d200d3d267ca1e6bcc2cc65950831cb8e30bcc01665c8149b874c9f11168153c187341afdc43e4d8652ce4fbed9f9eac75db40d64344ade\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 319a81f052db21ee213c536db2cb8a71e0dcd0a9b2ce780a9588c38b717c5e487a337f82b5223f638fb552e92b826192e6a1c27771d1e86584bc6c7cbc5d9a6ce6edf2ea2ccf6939485959ccbf3183b40e410768c4665adf90a0ae2792fb4b5d8aaa06c6294e31893620decc3bc72fb4eb68f1e56b48e39c59abe869d07509b7564268d0b7f178ef09ef5dcde6e7dbd2a20fd1d4fcd707943dd63adf590a117ead1ad10ff85cb\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -eced809145e696ceaa0",
+    "ee8f831eca67049509b31a1b15e7fc86cdd97a73a2ca05bfea5f4b283d287e49906463ef36f2f8ea23c2aa12d5534c08e9769055e04822be0f8ac85f404f5c025a6833b4115f78da9470451c852ba0f24062397d20385f58c5aca10f3f09072b2592e5672ffb989a390abf86cbce74268aef1f4ffde730b3b962df1088bf8745105a7462379ce142f819c2538d9bba99e094ffbc4478625bc54df16c5e1a\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2c1ffbbb30e71d5fa77b5473392f95297b489c85f83013262abbe948842473154e00c86b2e354278844083f960fd746a3b7cb9baecb9c66932774b3a28f678d50dd8fe52fbeead43d8c8adad7c0fcdbe5e02664b0feb0ce214c5fa007c5fa2d08c5fe96787b95639311cc4b7eb2a7217c9c38c6d93444fa60c1f52ddae9bb2ec1a49a593e210e47377d3623cd2c4994ad9343863443911062e12233176f4a65ec715b3c9731c4a0cec\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -c3bf056b905c0392a7b5fa57446ed350f325eb67d59f1784c744b04c7f4d8f5397db913407aa8a7f1dd0225c1a9673828db0d8bf3d4908ef53307131bf5b5c4c6068ad73b874aab98e8db33b0a758532172acd8b2c830d0679a8226537090166317b8eea91e8ee4a7282c0ab0ab6f2b7b63d728d22b534fdc88294c376a8d036ba9a644c2489bcc84f6aec83afbac08067a7b93f3897f8dadfb68c327b751841927a728faba47dc44ec4\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 23fcf9510caa531a304eee8d0b2d49050fca83abbf287b6b6dea06501c5afc6d87d2924df1d45b1bf6c4bf77b563a3013cfb4ad9094f8ee9892d33f6ee1c70131cd5721c5af804a9da7654510e8591aa185ee723f8caa78046d9e6fbb891e6024d2ec70110ae61c3969995e35941d2c7f3779d5bb71ce5b693bc9ce4b087068adbb554acc4ab23624e060f7cea169ab512a06ff3d2a36c2b6e3bd9a75f1a9ad30a6a16b0256c42eaff2c3f4\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -c32d5e643b12db6616554116299c1da672efff1eee394378c5e9e5f702ea4ad64f0dac8904bd2751d2cef91adcb283599f6c661967dbab27059e94dd50025489cf74c6897a22e95013669aa3063fcdd4b73aa6a9a1ba5cad3956bb26346e22df6741cd0ba1c0ab87fbe74035618a394383823216df47b910cae495b8fe7ac5feb3b2cf0d0ef6c75db477160b75324db8eeac48a0fce72b9abbd7079ce6f529a89025a03a3777cc7d1deaf3e4a\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2a8f2c530342bb6ce683a760540e956a1155c0fe065476e400caec59861ca97ca71e51a11b3213b2baea1a41a29449998778e0f533fcc181698d293f05e28bff2750ef4095170de98a19a36ddcf59a65f3789a3808ead51680245070262c9544e446f23652eba47065a2bc4701c55378bd49733619ed2c213f8ed12a4a317c465f37efe07ff2df8e88fc33d3eb42cde9408dda28215702bfa607030839285a8bbf89b5e8842fa7d7f50d83fd4ab5\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -bcd2b2362aa146cd120b729e81c98ae598804006d046a7ed0f9782baa10a85e37c7c22288dc61c24830a1b42b123d63779e88d7555028292fed5ada1793264b35e961b608bdd7398e421c5474c33a65059ef13787e0cedf4f8f032beac48c4b5e5a67417109142a43b198ab617d1de1a38d6fb4922c6ef70a5aad3faf6f8d5da3af9679c94cf61ee760ba792d2972376425e2ec9c4109e969e3d9c3dd90cdbaeaeb7382cb7bd024b75a1fd6d621c13\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 3940430ace4b5b87bf4baa2673582db3d27307ca4cd8e55e976ea3e10da72b6deb7de932253bc9228c85cd4ae7766cd0264004c658a66d81e60bb9bf4dd66e2afe11057b7f7b53a1ec222510748be53a93970fb056e8082631b2b77413fccb6e61cdc6f224b7903d75345afed8a4f194b4bcedfee1f16dc256c2bb9f4a129fab6a9fe752895a93937a3d087ab7ca212991ff34f1bf1c55987a574674af43986312bbc3bad3280bbddf4ab0217440f851b\n\nQuotient = 0\nRemainder = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = -ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -f0dc20b88450f45381791e85d080e4f2cf38837391e16e608b8cb5e0ac0ca75e9f72cc04bf2f56f130d46aff31efbabc0ab14f0c0ad680d6899797297152be85ac012644c8d0927b5b6c70dc3e5a8d79ef92a0873ec22af3d9683bb5db1ffd5ebfb698c5ea64cbe2b6a8b9f14d4c18624be1b78b19eca14942ae9542012692cd0d5289ebf75fcf5486596f92659143e9f952af3622137e633376fb95e628055e0fb1ba3a37ccdf0af69a4c0d6b0793078e0\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = 2f2135850715f623909e41a745eaf7b37593567fa8be2d1ccf76d10b93a096e244b91d8700cca37a2ec1bff7c3d21cc3211ea8b03a3594921dec32faa185e7f3d9d17e98cbf8d881fd2abb9",
+    "44181659242ede21df7e5e8784f541cad678df1ef6ca4a5fa91f7856c62fe593c4d24436810cf4fbd11125bcb571f6975d82afeb81bd0c7700e053fc175fb5fc7b329c438479a863b8d5fbe6b4436b67355c51d0306e8847a27a30c9e61f0e08232673cdf0ba4e0\n\nQuotient = 0\nRemainder = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nA = ea87c57f6cdbfd4f836431be3e9950c90ee8ecc291eb4efb881617512fd62e2d86caefce713cfd8a20f4b4925bfc7dba1fcbe99c72932725b5d11eccefde4c5e505952754891e9ded499ec453a1c01a82152c8933f7db4f2b4b19e97baac322eb483cd661a43e458774ef27a29a19c3562ba466381056a3b92c35d9b8b71372b\nB = -cf429f101a2e19a65af1e238f6745215cf476ff2609c846f10289f1ef21b89af2aec53def3f4ec07ea42041f8b5862dc37fd03b2df12adaa8c9f1933cc69b526d47797b40f49545fd093b8ceddee3c55721d1fa19b336218de0cac56d410cc6cff4e620578cf820f5cdaadc367dc4d6372aab1e0ae3831a6d153c14920b1dcf09e7629b7442a06385420d79742e409677e3b82ec58bcbfa668ca072e981e20728a983d84a432605389c855a6668e0ee0d2b67449\n\n\n# ModMul tests.\n#\n# These test vectors satisfy A * B = ModMul (mod M) and 0 <= ModMul < M.\n\nModMul = ae2ca2ce7addaee2e2b7752e286b2bb6a58b51cfbed5c924f00398e59ec36fe6341cd83da43a33a12410f45f6228079c4aeb3912be87e2e81fa1799151bfa0fea29873097475b2c3efa312145d0bf7e51b2a7c9bc961a4f4dcf0c883ff90b919b87c21099fba40257645be31f95a3a277\nA = 6b18497fed9befdf22a01d988d34213f6687d8a96e86c188dea4172e7c6095a0d18d3c86c0f5a1af9c6e3aaeb6baac2a510930b3ed06ec78ec2e12b\nB = 1a058d99397db0d209f01212dd4023ae01b15da04fe62d1f76f21622b2695558c67d706c535ca7f19b36f8ef2d508ffd6cf6fcf25e5\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = c462c7cdd79b7604246a0cd97b40ea5a9a77408f13cbb548b56ee713c690dac0507fd988bf28e77462832f4307b08564a51510d4a951c1ad7564316dbead2b53540090827a8ade8092a6133af0e5fac7310f787dc1472836178ed6992b9f71224da3e884bef8e8379a58e6d4be0fbaf59bc520f786631857213305e23fd5ca65\nA = 16c92f77c139706430f396f72ec7adb045745cd9f5899b0074d9955bd32de66f57c05c7929b575312a7f1c04f19e724d64744bff7b31ad0e6171437763\nB = -8734c4a2361fc530f60b28a5f1c7e93136c5ff6bfc7553965eaca54c61e6befb3c0f8cef4280e780cc5940d21a740debba31f863ded75\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = c462c7cdd79b76042469eb41a7a83115eb84103da4ba438c3e33227631dc185054ba4e607141d1e60990d8aad4e0bb0ceb645ce9ccdfe72d4738cbe1f6a73ed3e070194fa4feca6001c4a853940a227d15c1f1cc153d8c96e90e24805929fb11e0665e0c41c77d5a97fc5903a8b215360e26f6a19922d650f460f7056274ee92\nA = -6715098ab2ba3ea1e6341e89936e3ae913cdd450dc831c8534071f3c362841e47d88f2cd29c0d1239aa0949f3685f12f8519625bbf10b2c7a515e6d00942\nB = 536d4b3e4815ae5ed55bae6950f5a8a61d52439d2800ef1b5ba2285b85ed0f6ec4af9fa0e364a6b14f6f6b8bebce9200467804e787f9f3e9\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 309b3e30f74c58beca8b2c23f64fe1203830db8a7e306e1fa2e2022f0d6d422851da509d1b2936f088f0e35effe12a7463f47ca369bee2f2980bc48dd8e696b2d8c6f35cf55fb8baafc2e613b4c684de26129cf196741aab873f81e498b1e03018a539b5eadffeb5953029f31f8579df7ec0ff3f752491910\nA = -11fec955948e007b59fc50e729941ee9d43d552b9411510b73f6b4faafc0465f261f8381d96f647267f72175883172918b5c866cf1f1ffc43c55f3c96a60c01\nB = -2b3792f39499767e0a8b7a6a406e470a78f97ebb36765beab5fe52e95abf7582736db72a2ebfdb2405e3954c968b350a459ff84ef815dbc5910\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 9143ec3e9f74a8eec476cab17ad8636eaa7c60e108e89ae0702dbdb2b255a217ba2530c6fd52658cd931b962054a9c20c8713976ef3b7989c40611cd25b0a9ad0635d61f6dc95dba6e0c4a7d53ff539b623b97ba3d66344fa324f905abb861c6b1e830c4b0fd5f6a4b01f09c8e1408941291b2285c4625267a108c\nA = 7713413d87f1e50840255927ff27bad79e5de5898725a876e4647913158cda9f5fa031dd7fc11d2e8130a0ba99e8706341c1a98d5fee3218763ceb1d131e9cdcc\nB = 1384e60753dd4bc20cdabf398525e7c4aa40065255c5058cae0b2ec90a3821bea8de672a712431aef5864eab719ba621cbbd8b46fe86fb31286091\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = c462b3b4a0432890d141c0f46a28190a2e30ebb2e4ba90ed132169cd72316b290dbf5c261984d98e63eea6525fa890bf52185ad7f164cf49f67ca91c2f35511f3bef6eb7f3da31a602a78e4752e326d79dea729f4ca6438f2aa65eff44bc60979b42e44f6a301cb5de8fb42abb47bce5633c6ae9479d39c9e8b507d96161e0fc\nA = 17d806d7c76aa8acb051fd9c0c782443f1b1b6387455f7cfb737c41658d0459bda5d13587055eafb87ad8d209bccac1fdc392aeca0774ea48799511c1fb9141cad2f\nB = -d7c9b6574354e131de4b8643d766641e98554a03238ebfce1112c3da5f049d6c410a7f05758571aa2625f7190b936a214797570539317b32fb94cfd8\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 16c84ed15ec6352a8ce6d5c2bdc0d9f13b333072fc7041146e944a29391f83e346b8ac0bee6dde98a420ba4f8852801d7c5bea6f1177a6cbf799edf2146f8297013e0e796917cc967786788ff12d9c1d07d9ce4b897bd22a1b8a391d3b4ecaa5b5c85d0a03aea5145db6350c42a964a41ee5f83e7d35e14cf442e5d99ccd0ac8\nA = -6d84cdf18a2f53fe496248fafef183914d55c42267af3dd42a39515e80cf29211fd58454986f5fb6afb56170dd9865d3158249090270bb9af341c830522a4dcabfd494\nB = 6f6f3f74187b7d74dee92f79be864d0a2c56d4bca3283742e9cdf15112c8f4208e3ac8ecc98b44b4ad74b0671afa4aa9e48dc31d34224a1f66bb2b4658a\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 8fb782e4883ccf3aaa2d3e020b08993d580c69ec8fe66ecac152c5babc8aeffafe406736cea492450fe6adc25dfa2e12723a3f9baeb02fc0f785b3db760ed28048e1710a78a2ae0c96b67c109c5034375a512b6fc7906847253f66316baa0ef90facc9ab992235153684d49d6939ab9e91086529494d7386f604ed69aca2f53\nA = -1f745c8f0c8fe6ce3f893d77fb274c61b72b2d9f9c5a2eb2467bc00d1f496d0ad469d76bce318bd64ff1107ee5fcad4469f84d658586a5789c068b0cb9b866d8fdcbcac5f\nB = -3a2347b491813252e8ebef1bd181534b074a368d076b8c80bde2e54ec3b4ec99001f43080c7857427e069d99b1b65cff998a141ca6963aa5fad1ee632986ad\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 7c0c1c05ae1d6420bd93596a01aa0153000ecce660a8a14d6fde7d4740719cc495fe6681a9a08163b2dfd51659b3ae7db0fbe09504370bfc695457d7b32665a4df53e879ac817bf715d5bd6ca0e242b1ebacb1ffd6698ec90c442910a92b35ec103b345f9a9e5c7b005f8028da4dde80f36f6f6e5675040d19e46aef06040eb3\nA = 4c09264420a9452c6f0b55baee42c076aae5a73697cc6bbb88b7c922f236ee4c18e477f88e2c40cee03f0bbe87d3ac8dffd75f635315f856a3881c6373e8b9a286c813325d3\nB = 10474ece7ddae5c53c4df5b594439124370932dd94aa5d5b4ddaa233b1a55634fb7d72e33bf1b02965fa9d1538f97e1cdb5ec0477cec8ebaf202aff8533211169\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5",
+    "f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 481543f1556df756ae2e422ffe35aae020c9bde9e9b1f760b43043a4654de363dc67f381c0df1c3c1b90edb4343c47ffb8345a1aaf5dae56f446fee08a0b9ee8c42fff57143e10846610a9925be96418c4c957b4e92af734b96fd6f21974877dba52a0db1fec4aa97640e357434f95ba74b6b8323cbe17118dc489552844602c\nA = 11bccd165d9fa2d8b01a48c0ec549a6e600396cd2023f0240056193ad27e971c604eda8aaed6ff6be8be1001f3dbdc8655f1ae84eceb963938ae7bf428eb5c968f584798c1bd8b\nB = -cfb6629ddfc98a242e3290959f4d0726c0b1770b52393bc7488a471a90f7f0951362c03e67f443c9ecf4987f5303a789bf65e0fd59cc5eeb9f5d4f40d3e4a14080c\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 2a770ccfbcb2bad207d0e2dfaeed04b6e7509daef00a1df88e57509451739a8a0f15106ce8b53d280a4b4e09900420714cb6961ebb0e00e88567c5df50d2f2908b4bf8e0a9a5a8b3c6120503c14f16a99297459543c467dcb67915e0a10e19f72ed5b6891a6121b66abaa602818801d3306630bb04ea57e6b31b2c05e368d398\nA = -442c80289bfbf00db06eafbf06109b55f99786a323fc2c6db5686f99094cc24aef50475841243ec3ade2a1e0ff28b4032fd8afb8bb5e28f3b2863bdb9fc8f033adbaeb5f2ab16fe9\nB = 6d43e3c46f4a55d49e78f40d34033a7f5fcbe50873930e7c5452b6b3b176534e6e70033868c85b4d63052964093214dfd0bda6a84e893b1aae3cc72aa83d039e51c014\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = ba0e8c91a86af1001b13deb115c77609a1e7a3736a6b807255aee898e3100f469ef6222be532dedb1b8d3db4b3b55aa4b5da5629c83e9b2bde76bf2f2a4119a5378b5cde000980b3e58595d988ff776f0388fe025625ccf368e20914fa90dc771c826e4a836b2890e82ac2274471d586b4de5dab3278f0e70207562ac6e6493b\nA = -14be403d28c8451cac4dc83fbf895a9d2b74f730c39b0fcb33d7258f99211dde31a78f182ad1d27a559031d67d6f2f94a741f141bab80fc692afb452ee2d502099ebd5760ccec7f7ebf\nB = -2742dfd02134594edc6d3025aba5ca4a34dfeb43821ad84164510b43be4fb95748f8d0eed7bbcbeca14efe843fb676882784bb36c889be29bdad9270e0956286552119561\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 20c691d6544912fadfd9894cbfd42745991f39a29cbe3a1cdd302bd0487bf70c0179b9579b77f8481bee13ddbe42f32d734b6118af92884c946ea8576f6dec867c1c251c73777cad7c7c76e90da00ae07f96c8d6a751e5b18157dac4468c05d32eb86e74e0e8312bef85905af8193a3f5c799c5875badbc9eb7ead1258e56d7c\nA = 7ae9b4d5151b11bb7bd4d1569a6f4804f3b4d77948e0c6300e4f28d51c9a0afed2ae7503e53489edca5359e2b3d0c82a9cef316cd7e1c1275c31fc9c51a8c1e5fdf23935484e467d6460d\nB = 1f46f88d39fbedffa8501fa1268bdf3460aa98e12b629da59676e61852a4d3f8c59f72a2fd717fe2faa09639bc651ba516cd39297e0cac67444ec57c0db47c2a4e250033d02c\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = bf21b3cd55c0df8d4d568d00f757b10ef3de782ae71b289cb2b59d36df1341382bdc1825ba13199f2cf279a72968b3bbf5f7e3d13ea9adeb96d81132788231fd988eef04828119dcca21ec1fe844998909cc95a8d01720e883df27f07ef4dc3f09081015dbbdf019b96707c18b0b1db6e689e8f86466a2afea4a9cafc576e10c\nA = 1243b14aa3d16a55935f6f8ca49295e35e7f75b03de7192e1e8a479abc0a430e0d340acc05eb9a61a5dcbfe3ce3a4c5c940699f5043e924f282bd21e341edf8b7a6741c6ac72d7587a9e7a60\nB = -bcf08b2153e8ca911096189e35dbdb21b77ce89685484f574c89f1747612f39340bf1b204a23530abb36b2c5e195940b86ef1252d6729393c25d4c73dd434b6dbc3057b05d3f15\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 460539d96c07e72acba5b59c88fe904bf7f1e1648612908444b0b08172d05968b31b43456918b4287dbe01afc3cb4860d9c2fe549a580c989b6507094f6c241eadff910d2603f747f8e289e7a8176ca4a978bba89288a4cf875bf3e03939af966c54e77c28119a39d34a2b7055465f58ef2efe7c82ac547fb675653198e4b504\nA = -5a44cb669c055ba7c28d49f84bf8d12179aa30bbb9db2a48d7a6b09e44dc0e0f7471e3629cd2fb51e5a53346ae025fb49f9591ed1d71bc79daeb3f1254342d8a2b091ae07a758c1555efe59e78\nB = 646cc0f766346aaecbc5147a4488ce157a6d844045b80884eaee9d419087285fa71108b5ab4a05689aacc8d2e3dd0e6714c55eb8f77487a3fc5e56c3c2df0c4acf28a457051118560\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 79b536f4f30f9f7483f90e65e6456ef8072d9a7430405cf8c9377ceea2c676afc338837643436d55ac6af2326ebb362684bccc5092367209822581700d641cb8d331432b761e4c6e22639a27335f45a25ec019d180fc53dfb53d69216d7cfaeaa07db8288adc35b7bbccf2829631c1eebb821e4d3299015c3d462dc17aee5024\nA = -167529b1e8668938ec02a68bf4d76c22dd018c41e19be25e2f821f63c2046085d0af30d8b4212ea0f3f9943be1c14fb2d2a944551107cd2bbf8dda5bf258957325f06277036282977db4575b0deaa\nB = -378e1be10a57e03b197bc2b1287d643ba6d89da4bf6a6170816691fb6529c602eced237863ee39659be3729825f032a57eb5de0a87b0894d1a1244523e85b6f50a3d9976dbb038490e46\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 658169197ddd0bfae101c10c3e6a2b10dbb456048e81160b47b197fef439b1e0ed710399cfc80ead8e436f1c0399064f92da50afc335847515686e055fc7bcc0ca721184435955b896b0af4f4d96672ebed2f154538d49fa507b945c0a6ae926793751231980274213c80046666c28ada213a2f87509d1466b8d1b2122e93f8\nA = 49136d37ae8f3da71a6114327833e8aaf3dc8b5a9a27e9d04c953988456e525263f86ba94397321c2093803b789f8db3ed7cdba19c4b796500b979e02952e1625246f8e977e01fccc133f94cb22832c\nB = 1dca005663385fc00b4fd58c73adc7589d15ddbcb8cb2fba03a737a320c447a2b21e576ceda73811a31d8277883fd31e22f776bff3261a098ecf8f40f2855b0c723d1265eeafb43f85323e3\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = a49fc8084f3e780537b4038bb769b8db3653a3315298a99c2ede6739a1732a636e9787f2e8b09d0b9bea08fac43cccca71a315e6f4a7d6417d171b4693dbdbee8cd9f95be0847ffd40ff027267125d67b89737e1d0365bef6c4429504d13cd8ddc7810f456d6293c0c57c14a307b94010d79d5c13b92a907f923966fd3c5c8ea\nA = 1e7d8de2061cca59d1cc19b356a8fcdf2ccf917e0d81598f014167c5a8de027ccfc8f2cb8c37c396ebaac83ba862c146bb2d551d10ce03de9528f97725804e8a6de57b9d9da811200604c2a032462b6ac1\nB = -e38592f3acd75b575f64ced439d5ef2377d21c61bc70625639b01bf755fa2c6de803ce155744993493debcd4de40860bbfcee86d0b117d7f8c3f8ace68b67cb6fe7a81a145535553896424f7a\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 5a99c8a6afaa97d8e7d84f4899803c7786b1bfd2ecabdbfbb3bbb92247ff91ac213a72f6d23c24699d60babe91a7d9cea751e686c027fa1c954474fa5680f0059118426c71299462b11de5f2817d190599cc4b352df4d2e80605f9ad1e32eb13712d3027a2b6a19d52151e37e7fa057d8fe59dfc8a943a42a1756a38f103a75c\nA = -7df29221e6a102e32757c18f87927cdc90ecb012ab0557e0ab855daba832d76ddf595b9c5a62988ca968b64fd5bba2a147a5991810c17cae7edfde38bdbb7e13a1fe5206724c05a9fc9276c8d4e503a860c7\nB = 5c586d1aff7dafea3b8ee42e0e8854712c95385374b5bd1fc8ec41a72b296e070940c4160509a4a1699a678533ff3d12299338fc441b0f01e29a48677bfc5aebc644555285756e97c74e1af6aaa8\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ec",
+    "fa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 21fd2d881b6a52332dceea42664aeae1ca110512c13bb33e25ba4ec0f39f80eb73b1fa0834c998c23a2453dbff971eadb183c51a30ba78d593f23be9cb6b2b33a554ef31e4a36e0314fc2ec889f18debb956b89d1bf8172553271bd56d89ed0b30abb70e68abaa2c76f73cd5a3de93433747d09c845b5f8843f9fdf9f6c975c8\nA = -19fe3bdddcf08190a037768b77666de803ca4f7f0d7dbe6aaaf334a486dd0da7ca024d1b3df11e0406b0326595a171be30b04574c1a7d04f4d2ccd334663690fd20e4fd168386280510a00a70c1a11e99483048\nB = -33b2400173c057980b0e0cfabbda1a5cb5b83b7ae80708c199f28142237f04b071c6eeb63d42e80eec04b76152250c9e4d4c4f19a048cb9815dce6e66710fad1d27494db5c31d9af37d2aa779d12d7f\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 1c45cfacf30682a876cfe253f05b393a2cd4dc065ce73126508ce897a99a723cf5145187643ee62d746f6edf70269ddce3c348a1432316286a648ee9ac31ef87feb14f25c42f2dfc2e84bb5bdb4ec0124e249c526c55ff2cd0ae938555c5f86d856eb181572ed01dc045f1ababa52d249e56aba0ecccda905d7d1e64bf89bfe8\nA = 6a40d948eac2fe5bf6db15d7f6b89fdc0712e32d39a881c21859e8f7722391ce05973efc7c40e2c0d7f56c217d8a986bfdb08bf87bc0435873cfe4d01967c46f7d39464bec411d0369f6f5d1d83f42596fa47451d\nB = 12529775e8253ba220d890d4912fb95f91e4edb59610e889431208b6bb42b089cf2aaa12ff9ff98c2482e7f4cbf35b22d15fa28aa288217bf766e937a706fe1e600143087b0a67f668cb7b762c9b9f38c0\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 3b3b08e8eda8be3918bf648227eb0d569dd898729d9cd54deb32b1a1dc69cf7b2c4184c8ae9641f0f75950df263a5e236f428ca86244e617b14a04edd0f31c02bd4d84f25bacfcd4a2786825f0361251475eb6c7e99020dfee4298a1f1bc260d4e364a332bc6f651dde7ce5026dbeb0e5aa75ee98874da54c7930108ad28e3a0\nA = 149d36918fffa682cf90c4d3f3d48e6408e7ddcbeb44e78b9cc7fbb08108f65215761a61d79f37ec8f67cc51e0a9b4bcb3834b0ebcf6734985153f29a2778473b80147eddc813b4fbeb98843f5c1ae6cea68f88dbb4c\nB = -ca87f66182e271a69c0964eda92a009d438078b584c3eede28ce1a501838c5f497186d305c09922f32ba858fb55f2a0dbfc9cd0f93b789c1f800cf092726d6d33db19e4f26c7dfca69b83925db14544ebfe2\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = b199655160d88b6b4157ada0e5675f82b33b5592408bb57c46e2f7d8791bfccaa51436dc3b772b83e907c20ce7edc2835ce96595b78c0647d244e9bad6f4184e0003eb0899e7a47ba0be888b9bf795eba95e5073a85c4d20416fcd4a8d4e1e16b403deb38845fb8bf9e9264d68807acf02d579e8cd104cf2bd555e6cf73d0450\nA = -70ccbb73e33a7cec30ef2071f3b1f2e008e70fd6d00fe8b7aa4b9146fc6d0549c57d984cd014c7e0a4ed6d33376998b7c2c9778fb9580d8ca4ba795c88612721c153c186740c58df3fa63b6cf7a4de76e049217218c05c\nB = 6cf4168d44a8da8e8446b4420466fefbdeeaf9623a40e10b77547687b25f36916f2c18cf6060c03b3b40e0959479f6aad5e44dcff0ba799262ef53e280f4a7f667d262d472b2e573265774deb5ff8f25dc1822b\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 6ff91af444c61d2e2fe8ad73bdc5377d5becd55074eb60f0f98eca3d8f4be8c02f196b3afea12c36f78b78ae6a5ab677ffb7d9c0bd58987cca816affe468c7fb4b56055f5d2326532d6ed1c00ca2d052ecd103994e8929bce04e067082b4ded7e1973566f99c514b4e0d95b9a8a931ef4f6355066940990fead70208a63841f8\nA = -1c924bea12ad6f8b65abd1796e381fee2cfbec15138191bc22d57165928794bb080c83878fa5fd19a5d657b2fa91165459966f50aabf19440f7d75f027b32e999ff4d3f7a7ce878fe0f33a847d644d86ca19713ca9968d97c\nB = -3abd4b281b8f25f5957d1f2fde904457d49a3a7eeceada26b454ceb4ae0e879135d376571f08b5038b7b3d73a9a9fecbe265b72375756a715a523ba66737085e5ef7a4ad988155adc93eadd5d95a0faea56914983b\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = b9076229b1a1241e8b4da3fe143ac31d060785be6ac1e841c2fa9683d2bacff2e2b5dbac33f58b0b1718ad2053c37ee55ea54a9d258ddd8930d2784852844d85db24e4721762839a5c73cfe588efedc8932ccfa585e1b5975083919be9e32a86dbdf5cef84d3d4b2ccaf7a006c0cadca1e35fff2da9da7d7e779494d8f85bf4c\nA = 75eb0fe6c07559c2b0c7b2acd7d29b5798f6c4cda64a504ebabdf54bdc773ab28b218f0defc040016178958d5561796230b71edf49bbdcbd3f14494859843c8ca7a0f777cb05827f2839f3982832f4f3e3c5e50af17ecebbbc3\nB = 1b8aa718d61447003fdbaa748a9d86befdd2675a677cf34a1be7c81e4577f665d71135a8a243976a4f6ffa1636695567bde522f8fb1948033a7e0941f833d827e957781cb4349a08c6be418befc8959960fd5fc1b288c\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 9df82b7c34ca97a3a5d4efa28d5ed4f35484914dd73af9090c4bb31ea3496ece8ec650f4e7b07dc779c97e597e76e43cdadbfc6e72b61ea718c073be1cd204f8ad2bad0df1e530e75705f3d3dc285e9d793c8d42f04dc20773d3fcda8ef3ac1cb10d33d20a91add0358ab8658f49d2fe51d0d2d72684e31c0eef85e5695bb4b4\nA = 1fc2a171445ee6add5c2e4d29e50b91d83338f8d63c111e4d3e95f16d2a33be02bef24dcc3d6ce6bb8f1ef980dbf8fed409a0232c0566153014eef840aff58ed8c33e8d463d408f93e2f5381a26fdea63676c4e5397eba1d39f928\nB = -bdac7a177c77451104852bb99004ce8e617036906667258d85adcbe8cda21ab7d03aa7dcf62cb210a9db8fc750c7e1ad290b35473be0fd607fcdc686de0b78fd9f258f5b25e2ed43c2ad1a38859f882b9f6b293dc258659\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = bd9f3d2e8a1086b177698f87a9860e3a5f030e04a0bf4ee9436ac55e005bda01ff4ac662cb85d39e98a41c723ae542a83a936c3bd0280c6801ffda080ec0aa4230b45dcd0bc5eb41cfcf272028bce3572847637a92d1543bb2b8408e880f5b776e1cf14fa28d15cfb584f025596ff10c9f091c837a3aa622d9e5c856db8ac207\nA = -7fd5357cbee7c5e31fb62ad03bd47b705b574d915200fc7f1013d836b9cb683db020b152ae9464de6aeb8baf14999ac7025dde6173fae6ade325c60ec310eff6dc4130a8efffb15ddae90d760cb7f76a27d0368175d4a44a22f7f223\nB = 5894a0223e4aafe4efd4572752fbde4952c8b09cdfc35137e7e6ed650f8fdcfce9de673853dbf73730b159b2656047e69377d7c5025a6b346fb08831e64bc8bc34b75765012460d8135a4f7a0f41d768fb85abf17f5e2f5c3f\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 2c61867bca70e8662c7e5435a5aec020faae86fb079b992bf49d8497fc5f96abbd38a6f04f6ca8510e0160e546b3f68b7baef4ef0f404e881771cc12ec5ed3e3787c2d2ad6bb957cc59f8d56f0afb4bea49cb671cb42f4e8a0ee1dfadb6fa14f84a5b3269dd33e20d658ea4cc39499c7a39a4b5650ad7018d32f97954610f676\nA = -1bf5ae15f24c7c14eb59605136a3f679f303cd5b81e4a27465281d17715afdc2c231d7ccbc59f80ad176f4e0326eb757b52e3695e27c6776d7936da47e3a8a904f735b151422029535045ef489e61ec93f02e6d588491c8dad1cc311f52\nB = -3238dcafb85ce557036d19e42e7e7e473de9f9da6f920e18845dd010546868d2652decc94596cd2c36bd16b02c02559892b9f573bf21ab18c3c75591413d046b385d08aa66d849ab8adc9fbf788e837b047a7ce2b9c63f7fbd263\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = c1d04b831b71",
+    "2d0619db462c3f3fb5973f5984e9a48493ff273a5abe17a548e185d751628899e2851e425a7d4b2c72d4d908dc813cd122b8f497e08e299dca9166f19752ff8cd9840a70155ed9e8c063a3840838b3679f96f1cd5f1cbf0e037d222029e02769dce7fdaea0bbb5417f85497d77c76a387c6b970eac15dcd128ba\nA = 7aeb60c134e84f289e419b74f99a5ce5b4aed5fc630d5d591ac7643251ad32d6ca7f052fdf8857f67138262d221de644140e9018f7b84879d74883f8f251303f65e06bb52246ec6a912772cb698b47de41c1826ddd065359f6b9f1ccb0cdf\nB = 17f81e53d9fa6201e4d3eeebb32267929cd5258d10f053e7c021c4afd17094f8ecf433b1ca752f8740f6d6bd84f801b1b9fd64bc4787b9ae5e5aba0b4318a63dfe27e92d5a3ade192af7563c74c9d6006ae7701240efdd6021a83cf6\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = aef89874854ed34deae1b77286f9cb0e3017e3ae77fe050bb244acf4f30dc03504c73c1a4d44b769709bdb53811a5d0f8a76a08e6a66fc2cc4e98537ad6a8049f02494305b89a49a55e71fcc3f5fc42d6b478456ada9b19ec0a03f5ccfac5538c0040092771660312be5e51996073ff1a506d7460c57d54e10dc2991c028606a\nA = 18d3af14bbffbfcabdaabe44074b407d69abdd80a6eaa5954f0e45fac85af7ced1715c78da872f7a8fabaad3207e31f12b7195cdb25abef0a1e54d3b13349d997f207fe130d7985e2033cfec899a0af310c9827749cd22bd062eb0b1faa254de\nB = -85a7d9f08a60031e689b0e611d7f7f46e1178eaa2e6459602e738990c77f4d3783ac43fc04d53504cf67fccbeb02f9846756f8e32fa4a9316b6d3b45f644254077bef096a72bcff17ffa17070a4355121cc5daa2f782fc0d0bb48101db\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 14a85edc6297763547702c212b1a8274b8f85d53ef35cd1b01ed51039bbe030d0a1b9626ae2f571a43f1224d723847a1c6708f2238f6f6fd75db6656e6c703a5acb57f69717efe8ed58a3713ba2720d8c001d026d83de0ce5e24b67c41daacedaadfe404aaa9b672f00562e6901fbd0710c4303fec41ee3338100beb36c9b1ed\nA = -44414ec207060d105f599b9a66aafecc5b232b55214c1a5e1922f6b59439b3ff77cd3a327bce4f7406871196b90350e6dca9aae147ce03027dc4de7563c734f111d95171f489105de5ca80047cfa43f7e932917b816ba7d41fb95b4106745d700f\nB = 45f2cea1b9b75880ac3ec206740cfe0ecceb488c9155cfacf5885a8cb49be78af8cf221ff8de2328f4880479c031f830a3c9eaebfd83f7de501b7c5cde03c4720c56a676d331b2a13c4689a2e34a43fc11f62825b8776e75d31225ca7ff65\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 7670c1e2e141d8f8f5466de8ae2e0ba2eb3eb7634699eab8415d3a37f8df291d00def88361e9fb64a2f116433dac3ac2764fd62f3201dce4e48a3b7019e5465f82241ffda29d5eb0462fde74dea3168f8993ccd4d090b9c31a5a6cd7e05f725bbc89479836b89379b422250ab049f31c860110df5ed69089716877fb0ad7b0dc\nA = -15b4a2f808a85a5bd466a342c4853c04ac0ab73f8e53a4a0477f73dfeb8d7a911ab2eb5d3d192b9b084d0e38db491148947c66f838aa5f460c37341b129137614259efa531c0e6ffdf163ec6851737037a5299060418d96da035e6f583e6ba79d0414\nB = -3e94fdf22004384f7881875b1d8f58019ed8afb1b6a31f5d591e77b0998f3100b34174d6f3466da44b4c7fc8b92ccc5679c26c146b704198a65a88554d24291adcf897bd758a035361f671a82972b5962002c6a828792980f86a64547165327f\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 35b49beccd8d2010a8d777c1ff69e28e01a1bb78c6466e717f0a934bb62f9bbcec5ed29f9cd2c14d240a6c33b28c986eb9c8912a4927605532483dcfd31a50876e1819f3d7a0f49bd276ced5c4110470244fca52d2611ed7e31cd8b73e749aa70743b39e92810b3b52320342a65cad3180f6e2966059d15f79e5574348f5f66c\nA = 6fd078e3cbcda6a71a710e99204da640edc71a65974fc765999a74ab50a0e4b090d57ed0ee869c8da2cf694b6fab56e87c4af62fbe73eb8890bc066ec3460beba04dac3b8fae7e4f316e8f954c6e8d934e946dfdc9f4cde0f26bb3d40d5c444b03bfc65\nB = 14d8041a3b83468d2f44f150ad8d8d0a1a22035d630f2a17b70d5c3d557d3abc7e4d753e1ebfb3a3ba465520b84746073d211a67e079ec7f47c2cff9c06da69bb5cbafcb6cabe7e0018867c42e07931d6797d4499463e3cf786c6d5d6c8cbd600d8\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 2f6e0fed8a9720fbd83ce950d7545d2c6d5b271582194570424f90309227a51777cac974bca0ad3c1289ceb91cf75af73b0645cc20d71e7789144876b8c1bdd550328d9907accc316189e8ad81310848cddd2dbe362c9398d814a048f93f9368fdbec0f19ab87ad2a59d4066d738c3da3cb71d4716f2cd2336ad35ea1438276c\nA = 14bda9e4aac85b0ab7abece728f61450b7779d3b5fb83be813758e742d2ad76597f132aed91e20a75c554f0d61ec4dd118eb733d04942b2548b1efdb4dd22fdb543d9bc1e4bf0574ae2cb2c46fb98cc4835b6a074d6df1a3bc5443beabdc784d542e3349ad\nB = -efd765f8ffd72d041ac3244078b8dc4482233e9411b289cbc2cfc26fed2cf28e286835010438ddc9e7021ceb098b10c68bcc4732608ec1f4052df9362176ee14812bbf09ccf7c2882714ecbbf92bbff61c06e9dc35a368208a05dde949fa2cd091ce0\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 1f0c436379f6dff55a59093ff2a0626a9b959e3e3e59365afc33c7a7893f04bca863ec910c446957baa8de4e35a1f4e9c4a776ef41b053f03b775f327eb7e5fbe68bbb478aa4339ae703ee4b573d6931e47e09271d40239d527fe77098a7fbe519f5eda1f26dd6a7d0ee6833efe37187d8a85844690fecf9fdc3a4d80b921130\nA = -51eb34de29ba24d2b1fbeb0a1c324f4ebc69cda2dff971a315c0c2775d988b03ca29891ed0790f3dd507a1d26ead461dade9284613e45df338dd83aebfb66050465d8aee554970b43f7d4e0428e1512289fa1f9b23867b67095c455b66d536b91207b749189c\nB = 55259a1122eb7eb611a69118d3d42c2f05dd228d71c0e1e42ae3a8d3d180a95b74150d844e916ac85105805126e4b995f2ed1cd3fcdf28e1fd241dbe3125dfb3e4d90556256eb513a2f7c9b596719c83b26931d92bfd3573560e8bf054138f5d6b9cde72\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = ac321a272d2206df4dcd6ed8ca194a1049c1e3a20bf325fa44809d302170f850721c077bb5d792f86f7ab03ca259567397cc2fa1429771190bb632ac2c92d3fccf6e05e13cd33149994cda5f9c57da155439663f6a13c66f9da553f5038fb92fdba186ed9ca04b8ec87cba4c5a68c8edeedb94e38a6dbe293340dee1a4ecc768\nA = -19ac99d7d51456b00a193b3b04693c7e5436e05763f0154768db078ea5111cfe9eda3451091af213b9c8cc649d341de66c12ab2803ea39655d3d7de182a77355ca444c5d2778f791d39952a7a11839e497f5dfd8a703df49ec4d7628bfc25a992e94a6477e6be39\nB = -286d1d436f113308be594f0f43d7a05120639152b7e2f93058cf602cbdbc016512bfd23f7aa937fb358b7b602d15998ecc150f2b9224c58527c0c1267739e065e24236771e2c683957871637468181e6e896b513569bd004b9845f0f0e4c26a5ca123365e1c\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 3466804a1b7d1af8b6060aa93a4c325d9cadb33ebcc8bd991f9e44cc2cca8918411efeed0f005790d649382ec40278c8cff903cf3db177d24466c58cf6a56ffc14e595c36bfefaa2327d37f616b1466eb702f5c49170598bc361d892e18051b8233dbc5b3fd6832befd9a995bcef3b0f3beda6efaf09f7306ec203172e78264f\nA = 6710c19330d3f974fc377e28039e0c0ee0a558621fd67fe724c326537c18c66dc5eec60980e07d401ad5556a05688d2dbe7b271f9d5eda3032bf7cb7c420e7b5d65a195bc037090b6fe83064ac3731624ce2baaaa62a6eb07156ca12ee51d4321988026cff573ede9\nB = 137ca18f47a151363a3e8c52dcf024262ba525ec8852e8e406f460fffc2cf88f1999b17a5821849317fcd84d09c88ebb6eb0340120f113d7ca5fbd91c6a40cd790bce7b422552cc0cfd2a6417add2501db1667f2802e5d0f4df824adbd033a90a155cebfbe0b53\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304ed",
+    "d566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 6f248a70b2cddd9627b32fbd130f05a604866799365f94d97f1eb582b28192959692a870be7c2614536a8de84cd8c1364a75a3927ef9dddbb8c6c87dbf526f2d3a7916384f2daed96002831173fa4a51863c28b4378f99b1b201010581d5eabd66ad1e328cc4e647bf5e0588bb775e130b4a4d029eeeeb5852c5742862ddbc3e\nA = 1f014cdd87cb33ffee623cf454edf2c476e91df279b4f0879637eb6e8e5ccab305186de67585595d34ebc195fb150408c4620cf6c7a0b0d9695ba0e0e1d7552ca7d0be3dd678b1cce2beedd11939891a6804770f1c843e16dc2ea6aa8e4043940c37fd3d950caa122845\nB = -8d8d9dedc80994fc5db04d8c935301e47054250fea9020bde8d5fef01f2307cbf458d5afef5210a369c396287c5eb453637a2d721085af3de0d75a5dfb5dfd22fde3b229d438439af7b296b9e68ffc982efc6c825556c52a735f8be12a214a06c4270824d5268fb6\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = a35ff7e232f047e575b200b9fc4c9253de6ac04c612b8a82c275a951075eace5e7d6664fe8f78301d554cebe7b996c1f4ec3ca59d8d12d7196eb3909223de94c220f0445d24233534af1c93433b05c5924799d2c781fdb88c4537bb8d442e6bf76b2d966827bfb4f40378a3f135103513da056bc0d375b1339561700d15a0227\nA = -58346cc8a9a1e5b8babaed8e7f59415388e0db654ea7cd465d96781c57faae7a8af8e7578e46f3a8de7bd1027188e1cc32fd1c0d60be24fa3289a12cd822a6c9a77dcf8799624856c27ba88fbdb047473274e651760581b44457ed048cf76c166d38bb9b2afd3416ac7e45\nB = 61951a16dc6466a9fabae99df29b7229f1ab96b476092dca1e4f8fc8e7404e2fba56ee66486d1f27f89bb3f86f271307228d7d6cbcff943961e177300b6acec1eeb46af1c5725f745a2d2af0fd9642f57a09c9ce6742114be0aa6e939e638bd5c7a92a7c206b2d36e35\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 90b441d8277eb1ed454964acf567067925881b5db0b446a7d554dc61ae87ff979bfb0e58ca1706123453e62ce31284a5a2db1228d259e27abc7fb5cc5848dbeb9a6808fa1b4afa844ab39b652abc41423c2833e1209a1674db518b6df7ebae315dd7f416df54e73088762ef64cc2cd0a08b1cb01c49d9299d149cbe84145a55c\nA = -1ebb693ea7d18e0ff4a9a51124ebb78bfa3a4635b75a6387e9fc745a2325409f927324d1289be8a4f5cf2d5c04adc7ead20564f97e453287f03e5ab59a6133584f970446652d05a131d7d382c47b7cb97580ef6710a532dd4f5a0369dd3db500ae5a3c5efb587cf0cd2638382\nB = -3916ebc4653e7d6e0a4f1e234d765d41e9e948b5acd7ebc73cb595559c1b20b037a3c8da0a7aebfa5fd327bdcc922551cdb8db3fb0a581fa0620ca2d2559ccde3ebc44542b4d80926d061e2a35c08c09547e0cd587c396ff2959ee93ea64b1e6b7e2b624cdf445988e1f42\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 3ac61c3a028f4a2df6645acbd36818a2f76a3229d229ce22471760807585a909727411e8b68bfa4e76adc459409a101a1ce83900d46918e8d0903a163de87c07bbafbd60c7f536a62c59370ea53b6cea4384345343146bbf529334b4201ebdc7585b6e5eee42696400c9be9f496406a4eb51d2fd1b40466224f1752b181774ad\nA = 5a16d5fb9047949684b80805e5d962bdb939d0d0368b48517a2a826679c37ee0ded4fa83e657192d9ae84294e450f7e2f2773d1f13395169582cbf95860891b9fdf8f3240a16aadd1198e884f22b2718219d478e2410fd4bb98ea534a3626201959af099fa55488f5390791bcc7\nB = 1f67066dd06ed4a49cb556dc2fce22814754885a7cf6c13915d974b46b0e6269c0fafd688f45ed2deeb026a7cbb772c080dfd577d21ed2c81e50e7537a70dd550eb94fcdf626500040da88c43dabce13c82a93769a9e0ef66a471661292dfd3b3af07169e2dc909e43678400b\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 7087dd62eed6ccffc7e1370cca9444dccc4ff160458941aa9f49dec1a2e9ecce4cf50ac2daf06994c5010cf225cc92238cd60e1aed9edb2befb0fb354ffdde94ef5e8ad0415bc95851d59095a5c4850ec52a74c78eab58309f395d3078dc481feb9d30bcd9f113af7a01611b94d085e32193dec738a64c5fe9bdfbf5dbc98cda\nA = 13596eeefbf06e9ead8d883113d8ae6cc3da8b6fa13ab66681db5a9c083ef9e49d905ec19c39b149cc09452eea0446b29cc92d4e865e6f681827336945282fa6b276ef552363229a976c503b822e6e4a9862d3fb30dd0c3627ccb97a7046a6a679050a39166388a9daad5ec5555dbf\nB = -a4e574363f2e5982cc087b38110d257019962fc166c2d6e6d396220bb308a8a0dc7d90c5cb2ab85faa19b07ed7dc11eae9bf2abde0a5fed279e77a717b43d35e70fec4e18445e37741262d0b0c20dc4375371d87d839d39934f1dc41122e815f3f37352d04d0cf514738b351f02\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 8495eeee238164082240ae1db1e3c1e36fb6621e6b714c9de914f9de8a587d7106b8dc5214f7c60c0ee231d7441e03cc26462e71adf8e29772ac95d0395722d2756f9f64daa8ed41d7ce824a572d7f9fd419112ae823b5b48b8aaae09fe093e9ed05918c4ec88ab159890910837ad0691849b44be95993682b2da2b124de39ec\nA = -403f21e1a7911806747bb78a4f20c4e6572d49c6c4ce071db0c8c91ee985e68a16e60093e4628414b2673d25c9f13c4c43600633af95017e3846512197c9515aaf9953570ce5861620716b3d80eae7de0f033772fba82652484cb3ce7cc189d1fafb14e044e07a88da302547f2e623d8\nB = 689d1b4a968b7c00082ae3a29c8571f826c4630c947a7767fe4a71af43a5de84db9b5baec0980eafd0019e09de1b5c56173ede68c9a6acf260bef3d9a03f4c83a33106c94ca7e1a8615b3553088d1d05a62ddab0f1e5a126df5d960f67e3b92981022e1f0358c7970bb2fd5dce7a7c\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 397df584bcd3b2e1ec7ed89de624e9d104bd6812901e38c5740755ce91bd54155c0b624c590ded199590be5d98bd1ad4acee56a62d05d6b5fdd1ade12f7db8e3eb08c4a5996450cc1204be7ba61b768af0efd563ea478033324731e24fedada1ad6e564238c891494e85ded4feb2165fda22f75bf120856034a9206511885fd5\nA = -19cc480d1e07523bac502872a971d78bb26955c5453386f5d51767150e229daad3ab2dc85e0fa0cf6e72389391fe627fd2d9f263f105508642eae5a095ec4d88545dc9d0a2c436907460e1ea7db174673000eb2e0b60d57163ced261bd0f6cd8ce54133cfa10591f1fd27996353110060cf\nB = -39c45512fc7c9620194fb7ad22abea8f6dbff4a137dc4523115ad7e262934143cf1f320892f8c097a400d4099e787ea7041d0d69b6269d191fcdc8ea28340ecacab71058cb39a9c7362c848826b35ab560c27113fe53c497ca452397891c81365b6e7f07f916d47961e50b8c7c5cab38f\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 263ab04c98efac12210beb66b13fec7c260c5b1cbc20cd732a511fb3786b917a617d6622847f4eed70f25982ef5d0b0d13848c62dcf447e3a1d491f4c80e69cec03cd318f6f93134d582210bfa81c1790562053a71091333348c6624d4d793fd6ef971d284a4ebf0be0771efad302015abfaf3edba017907f10ea14a46d9fdc4\nA = 7a354753e39b9ad1c0ad6b65575fc7247487f3ea320fa82d1d333ba8dd5d0ff925331994a6961c9c603be5775ef1842159551f0bfb34920b93d90ca60e6abd514650f77ee8ffff2bac0eecd0fe8ea0fffc6ed0285c9f3c3cfaacf338043975457d62f9c8dda8cce1e99f34529435016fe2ed4\nB = 1a4384f9620567c698ced05870b4dae983d8f0df6aec888353f9dd6ac8ad54340c3ba8346bfa47bac38897f3963fce972f6d55f3407ae03f5c7637be1a34e483e50dcc27148b76ef079f117104162beb191d146ec828ad5c5bde5ee1683a031d554c276d837bf1f2f622cd11baabce10212e\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 91cf4d1899e170bf75dda0d51a6481f79eb94c333b876382c9d04681073e949191223926523f6531f0a45765d7f382221eaa080d7bd05a3c19220ebe18802b15d8009714e8e4e9872223049622ca02040eb041707c7e525f698cc",
+    "361847c66fe3673a72e4d701466bc374f55fa5437216eb59375c0e2c4f7020149d0118ea72a\nA = 12f35c48024e8271e8f9a60a48b5a214bfb6595a837c041b230e6ac87a4c1d4b3f93a2d3a193c750c9857c8627d0f7c454d6c4f224dbf14a865eb83e990b1d9b8bfb729b8d3dedbbe9c95032e4d60676c2baa2aabafa698392590add3b83b521a7a5e7d6f8af207e44ebecd735374acd01ef5822\nB = -8fc18f92c0613d085cf3ee6f586b39b99ecca864bcbe60fffc63c585e5613df68f3534ad46e244916b1f9188507a3692526c9e403b8e93480b0a5a6297f65215f1a5d8e20631a9d559fa1acc15a98c9397761ce18903f393b10444ba51bc92ac44df90d4cf0852da9d75902230c6de6f26dfdb\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 9af562a7b61c6c84c91bf979f32ba5d246d2ee2050f07ec2dd5cb3f9496bd37c3922ecb2b5b17085a13e93ab2dac6022077cc18c621cce3a2d2247e5e89de8692a36f596e5dc7a6969a4f3ff0d1580eed380e6550c6218c1938caa2b7ab401ae6f520063c811088504d60a19da3b5018d640ab8d340f35d1337a2ede8bc64bf0\nA = -63bc10b8fbcb391dea305fe61b404d3bebd035514a812d0e1d38daa3d67f9f1bb8f02d2979270cb9147aa51d66ca73d4b5787e472456a13fbe0d568e92b622439d33ad3c357a56dd26806ebda7b3bb592385ca5dba7e5eb5d85eed0a1746441e8d56e22decdbf8f4296e30d222da5af17c427e832b\nB = 57a602bbdefcdd00f42ed1e2cbde2ba858d171804da56b0ac87081424ad1569df1308fee7c9ed349eb496d5409c4c46921f09ff0830bc9f57e920e17df16523598fd90314141955ddb84a1522ff3ebfa812cfeb6670525123476a739f64ebe6a5f1fc805a880f8e5a71b908c483a121b38d05cc2c\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = b395c9f264172a3653af6637e72c4c8e564d1ce68032a5d761bf546e0c4b51b33cb026bb4256fa639ae98e54e5ff7d8921ae411497272b53d97c2c44b5b9ecc5aba43dde201f64f1d033056f19ceb0cbd04decb486a1d07ab1c64fd213d7eb6db9cd11efd743462e137f368acc4ca0b49a7f85587bbb5ede4be1616889e2699d\nA = -1e71df5f04001f6468c3a192086bda948aedd19c5da9a5286856f30524238d95b0ae71940f2af123315ab5d2fc61964d3e970d5858b7c1a78d0f2cfd10cba7ba4830a8c19a09b59794ca5d7da32cd8376b5ab06079b51cd9819c0021ea41a9e43aee147befdbb17a92cac7c7767705fdd908bcd291fbb\nB = -394c187308320ba1b14d91d75b8ff993dfd57f9c84e8185f12bf9924e046629ffcd7174879f9925bb643988259cbe9dc9277fa83a25012f91159b012f1964aefddd5a94ac6c2a55a22bbae93085dee079f84cea1d53dc4771901db9a3db5a14eb17c25aaf5377e2beaff6276cbce7cee97a9b8f32737\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 6602ce0fb5002eca37e85b60cc871b7b2eed13d38c20a37a6e0886ee4814f3ce2515f8714c67ad81e8c3abf6a00464e6a51b15e55b6c11296ada43cf459e15915026d3260cce8fb796241fc2b0bdd2b65ec04bee3b7ab6626e10597f3b13b43d16c34afd5b43a219917626c88b24c6f8392bde1b2e65a50b7f1a8dc5eb096702\nA = 4855ce75a3d7dbb72a257f6291e9f6ccc158647aeb2f8beb3e8fb32f6f59af1a46617b77440798562d6f58bfe826d3ea7dd28daee8f5162d7d24ae6c24c2deb2669b15898689ca789e2005903f3a94e991e7d3c8f3ae6181029d959bb15e71d7ba94d2dfd3ddd10f6fc49a65798b5f6ffd64682c78b5d91\nB = 15b3e9992aa3f042fd58ff97a8c04aaebf46b75fdc38caa9224394a1805cc26e4311bfb498d5a04d19396e98d11c8810620979362df82b23a115fc1711b57c7a56b8408e2682a2edca36cf9311addfedd2d0889a78cc1ab170d1379245de6f1f6f4db815fea9130463dfe5283f195e6e81486a1d39634aa\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 6a81ccd82f00d829bac186fb38b85097d52afa3ca83a026856bb83f94d6af6f6c6f3141d433f8fc159d11397df8d2f44c769f255cf8148249d8e9fc4f59ec3bc8e804d7d5189e71e20b8d0e540b59a2854ddd7feeebda5a95f17605e8bd5f311a63cc2e4ce23a51229d0a49ca04982c1bff79c201de6cc6150b690c98106a39c\nA = 1f1589c9b5ad9d878631cb03c23ea7e94680220856285668838452a63b726e01709588b38e578da8a4845aa5cc2e4723beafa4f81a1a2e463f67d9a3e432de7064ba8bfcb943cd9efb0e5a136649cdcf5e85a667917075804991b997f318752304f4946d69abf161625ed0c03bf9abeb4ef28034f818e2a643\nB = -909dc7fcbd27d0bf7d6a3d0e2937ce725b5cca0acf78c103d633206cb431e2e2c785aea4bfe2042df32417143de76b71d21587112f36d067f878e556b94ef63d59a07d19647593efdba7f3f5324d64c55f93a283a0dafe080167f6576053f9beb326994f4a1d53e18e3f3e770e69450bb70f276d128e48ecc\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 69139f2e10726f83300505d15dcbad5b5f284d1c06789181683b7b8caf35dff063dfa4968c35facf32a3628dcfc19b3fa4c30ba0e030b06773832a2631529fe0c0c402e05a0c4e9446a8b6c22754c70ef540f90d903d83a2e3592169ce6b5edf939ac5ff25b8bd48aa2425321602a9571661a1109e275a3b3039ff0c2f430b18\nA = -5d02cf3969bff8789850ac898c00fcb3ff1fc49a22cb243ad18703bb8fae25f83502bcdd885417fe46e8237fd0b444712c4fdb8f4972dbf9278a83eb305efc7a8210ce55167c069d1c4136a9b66d0c4dfadbf036c079d12aa082fbb42bfb0098006136a61f3da43aba3d3bcf2f5ac2d7884caddd0cfc28681d33\nB = 50b369234d993721288662d83298d99b9052a0a66336a5a31b76dfb20ec2b5be3aa76f78b2c17c63d78402a15aacb585be5c8d2e7083145e316e71e111fd34f5c79363c4591c247b1a94b20ee042d840c42a3001d6c8dc7cc1e1348e0e3ea8c6551f9d24af2dc2d0c38a54ef065ff048b148ce4f11ed2b549c50\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 87de406a6c957e85c759f8ff684023a0f98e93ad4ffcbc6fb0038c7a7ceed2486f15f36555d286338aab3283aef677118f7cc3f88a7ff0ac9fed31da6786ce895c3c08d3edb652bbc9ac2b44c4cd24ad281ca3a8e8e6e4d730f4f0c25487cfc1b2afe222934eca8b1e1572780dcc149422a88eeb1bf31065c929685a0a97ac3a\nA = -1878e0497aa1c2942a2e6956957c876dac73c4bdbf42bc92498f29a006bc92f788c24a4624b87324a7c8aedc6b2c0c8a1a442aa91557aed9bf2c02b6664979e8a9a21330dd839f4ba8f84515fa6f7db9287f7c20f31732b98fc09ee7796dc524870dc35851814bc57e1a8ac49d8935fea04bb08b8760df33a98149b\nB = -32f4e94bd073cf3f70810d9af7a873996a0510109bc6fdebb855f27dcd012c59507491152d30849d75f95dd868992c6fbbf29b1d899cfd401e9e7f4e0436732cb4cc9e6a6d6b0cb63fb0bee21e422b7f7b7b14dc5d2b6d10447fc4add390fd3c8e7b06f1d9b181adfa8d04459ed051bbdc9666623b00e3871e597be\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = b456ccf9d066dcf4247a21c7f3820e324ac9cf004cecf8dd1f6c3aa40c2a33e24c423e97190fc71bb9fec21d36c5a687065a7877237a2a05e64cabfb3b20bfff0b1f5ef2e9adb7edcd7140d1047b0919a2c770579ab44a08e5ad9f63a06f90ec7d5885b91de5e524b2e187937609b4b81d40a0b33e31a48d7b9868add75286a6\nA = 6c484e3c6b530dcd3644b19fee66c41c7c2c1dbcde574d87ee13cabef9dccbe5b41e25c32c6a56df23f2e87176afd28249e5fcb918723707fca94d7e2c9623a3493d395db802a1b49d550f52c29666f785652fe81afcab00a60a5b50cbf523cd13dfa06d5a5b0809c68ff7264a2cb35b8d52284172c62ee658e8417e6\nB = 1b4fc753d0530bd07094bae09a02b1ea684fb4e8519086b1e2ed9d59af011f61d1b94ffca6f354a5b428417b328bb1e8af3f6c7ac9121dae58de9f1dcbaa9c73a357f408b870e62b0c7db1a72c4c440f2e6fe90b199b9dab29fc23927190d3f2bf8a7ee926a152e64474283695614ad696c85ea547f5f51d02d1b823e3\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 5e7c63276f350f04816a6ed9f98507a78314f1d99081fcd906affa3b8395fb58d029ec657af82e77ef45611bc988095bba9c26f25f8fd404432fecd02398e69635f3315a824d6a98b33eaf6a91f12957a5e80cb48d5b086c795eb3b1e04da5432a7e8be3d683addc586a44b62",
+    "43ffbb7a979bf9664cc7ec41e75f267d58a7127\nA = 18efe267d4c62576294f4ba44c67a058cdc0bb44c48f4035682b2d6b8a63106081af43d99098ce133f8d7f9cd04d4dd7414f704e32871d43d6e5d73fa9f447873168b43b32d6ad19378d74a967f92ec7629a690d29a62a5a6e734e9ccf5b84857a00d97b9db846b057004b03d88b827dde717fc30e6a5246c752d65dd625\nB = -ebaa580d3eef5361547c692e107439c8391ac0a2d1cec0cd275d0be69133eba8a94bd186ff9a129af3f5a015d5ebd30215643554d7064635dc11ec7a8ed2200fd637b099e534237f0495d2b629abd4c8f84aa1d925d53e98490d02f9fe51bdda08b043f67f0903c0195fcb886c04397d3612e4501ab8c7b7db69f781e169\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 76fcb39f94dd2756e8266c025cebe8e801524a757b976e35ed45e3da3db720061cee9037fdb34776c704ad2059ad8920e400bfbf10eca9bb157eca7750cc31fda06473bd22d4def80189c47ba32e2824c721425f225563df2a2ea1edd090e01c0bf980677db5a5dcad37d21a68e2832d1012586f506480e929b2fd9bb4aaddf0\nA = -75f903ed9bb0b6db8e3be16e797258f6c18f6cb7b16f835f04e3045f7e4974d7a86a63f2ec351c88fadc0635b6dc83a797cdcb5cce1a1674f89e44190991e0930575b19e2aa1512bbbf2ef6f8c3e707b17516756fadb635d8c6bf9caddeba14834b5950a4d1e98bca79a4d15e5fa5fa3c1727d7a49b33d481d32fb14ae4164\nB = 4ccc582c8460f7def2d26167b68788a681c41bdf6dc805dca83127a18bff6f5ebea6db75cd959beb859637b200ccb5c7644d571f436e46a357d027edc9769da226278f7ab947963f7caed1e7e70e572980e960e9764a40c6db67bb526694b084976142471270b2331da563a10427cbbb38e76203d7da5d67487eff701d75188\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 5adef30c67aefea4da3884b8a1d0ce6724492bc76b477f1053621e7d19f3cac15448e9401d34e05ac4b508b9d1db9a8d323cf43722e0af6e3c3b6d463c6007449c3bc3236d156cdf988dfc308a1b4911554ecace52938a7b10f463d14f917ec3d9fddcf6d33081745009c59b58aa22bcd7dd8c3bbd489997d4e0bff5473ab9d5\nA = -174e8e057a1d66e22eff88de26f43fde1c8efe5611f6ba4f318f027f5a5818df02ec3f014dfedcdfc8c143c5005c3c5098d409710967c93474f5854c1113fe4030e6682bd56d389ca8b9a4587b8b9262d146bc92fcd81d75c3bfa4281898f394f45d5dd11cd4c7344ee7a933ee346bdaeb6f5188967c388b919a0ce6730c0bbdb\nB = -22702bcc4f9d5bc6f803af6af8072780ff7de7a346d6b9293ca751d6ee3a81493fa86738c44cf2b7be4bf14a55a4f8179c35c09dcb1485f4c08ec5e9f9b1efa91f4b5f15a31a46e1ed71cd934ba6bd271bb22bb5703aa468d297f360ecbb48f9fd6c572683e83ebc3d432203347dc62e19fa06f93e087283347950829d4256bf5f\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 5c2f67b1607776c10fe2c30b112e541c4d8229f5f99f615fa02cf715d3f20556a28eff5c233c58994e9c6c1fcc37b3416b0875b9a62fa5a09a4b8f9e216487203b387ff97fad1f39f674ab19c5e34cb2f162e6b0b0b0084f0618e64928423b73b189c744e3de9fa50d66f45975f68b14866cc16c8c6c722a54420adf027880aa\nA = 67056e93b69e8a7b789f1f8b835d9c6ecb7762f844d656b26df9844a60bfbe0d55684f61debeed31a24ef4246485e8a1d43d49eaf97ed9e7b9f2d2916a8d85b8c9e8ad5575cf5a3fea42392e5d1dfb23f7ad41a7b56a4f21e2828aab38a602d560c99783a4f807120292ceae366b1fbfb4be8e5d4561bc8944e7f17ebbcb0fb6296\nB = 1f874f244ed6cff9f910ba9a58db0dc0a7435e8d99ba6412e976b8f64d4106d3c5c57ba079384fced1c261aaa538e131734451fe84fd3cc5cc8b3ab46b2031f888d95084cd3a35a61092672a9118eee4ed1a0df0409e3613b3ef45a8b16b71ec892755dc3f83c5492b67fb9a143ee6102d053078f4875636b20b536d5cf851768cf73\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 7850019c6712f18eab877faa8489daba23cf34b512a3193852508185b13cd5a2e9f503fe8d61b74b5d3930021a5b8c38322aae9b9b1b4814fa4c2c5bc409b58f11fc8fd7854b17baa94a6bff5f234832f9468d90d148fa2bfed774ac03f2dab6a506a70db4ce363f932adcae202f04fdcae968f632dd674416c23d4e21345ef2\nA = 1e378a0f27e6259763890d29e112e3d8d2bdeb9994c49fb67ab680b6e71a52fa0a7db886d3baf52f36d943b5430ae8bcd82e229f4197239c35678eed254c5816722b995e9c311be942f8124e2f80c1e59658433a57f346adfcdb83202e55457308161d2f928b60efc39538a6469f90f1a868cf6077568c8241623896ddc2705cf04e4f\nB = -f4ee37e39d4cadb692bab5483ceaf0258b068f2c0354c540438803780c983469ea28324ce7e209c3bf55b91f0a2f4544bf318585e4514333eafb9b8c2f02170c620e9b5280a828ce1d8dfc64ae9c28577e15071825a85a59656c5b47d9a382af6b78a5b3dab1078dd647e0b473174b8415d401543d30a4018cc3eddbfa546d0fad9cbb2\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 4c8f8b671443a3af5ef5749885ce5de8e2afeadef9051bc49c0d7e72922d049b1accdb79d82288e472b07578e8b6d2176d6cbdd7f0caab593dc0fd9224a94920235410501fddd6001b62a7f7d8eceaa7a8e4c0de52029fae68656e8120972b5cc1c2e909c2742e836f2fecfa51e12e4f8a2ec7e69eab061c81785374ac607fbe\nA = -5769eae759dd6bf94468eae94189d3396886d4569b0ce264c22d39b623be3abb01bd5008b9fc86701a3373f7764118becadcc69481cbb134c20f669cefeb376dfc489dd4ee91cb333d06afa391dd322abe2b3b715d11ee372666473a473e29dd90fcc97e939049b455be52b3f288db306999019c1177ab5820d94859a9d2f050b7ee1d4a\nB = 44adcaf1e2afbfddae19b23cfc0f0ba1f940d32945d0b541db23f3a0a9d06fb1f67ade9a8e620bd96f4005ced99430c7a55eb7e93a701c829fd5b9e55dbb4d3833afbcaa0d9c946916b1a86af4a6393b1155c6439b8b82260e09ccf0ce5d1c4856f4d524983e4b0fa123267694a1c6118beb8be26113a02721a02d7b0ccb01ec6e9c0f9e19\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 51e25767b8d4d7b2b0c2652d9ca6bfdbfea06acba543b1bc8d3d25b2fe5f2998febe1a6e742abc3f482b4267854c2223a5918a9b5c84e0864278283bcb5bace0c046db1d0240443404fb62d70ebff3ccc655e5f5977958df4c878d9859a69731744f3d33978ac31551487270bb4fb56ccbf59402ef9fee42cbc329420180de08\nA = -1966812979042198f70b3f1238c93ac5c6e5749f1108c2bba869b1dac7680f910e56318c9b59be9212e713a348767ba6e75917fb599e929ea2144880d18d4fbda4f4663c7abb49b02245169f385e09098a4e01b56dadfca8c803acb7cc244f3c98bc17440ab2afce318476b80e1d0b4ed9a8d6f2a0be64633f8faad5eb48de2681a38a633ec\nB = -2e4f5eb92fc34c753c61dcc826abab6fc4f427c6ac7e73ffdf65b1037464b2a9a0b0290e713d81ab57c0e1dc30e76fdf96046fe10a34cc4511398319ee34bcaf73763a9042fcacf59a100c43d3333ffb3743048e8df0dc61fd0da3f935fadf882ffdfa9f0f42980c1af6edfdf161c4b16087e2b14277f655abe54582de79c51193e13169b55e6\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 33539b5f38a9943b15801d449adabe02da6e21651d96acd9aa40e866bf65015fa40178399254e8af6bb082d021e2a05da0f45b699d193b70112e114f0d25287476dc0c733c5cf9df57667ad0d3ffc4ea2f85b43cd10459cdca9465b0974e578c00a6e275e0b97ef2a4c9886aab7b5947b78a88f84a3f1d8c5f26bd07bcc59886\nA = 531b891fe9e8db322cec59a2115574c7a304c423e6b11516906b840542b2c608785e2c18033262ab9cf68f63edb40ad4f073ce8841db602cf8fae0a6771d741c6392976c9b333ecfcd0c8e9997da40616ae2a9e0c6be93fdc7af0dc0668ded1e42a9f729c70f74500ee76a91d3d993c075c2f645b35792a20edf17c157459e35c0a48da6c4c6f\nB = 1a6fdbfed1054a0c5758f92f72db7e5737b0740c4d8c3ae4713366ef6709b21eaecb6b74c92541a9a0c99ae18ac6ef7de79d4c84ce39ad59cea9c203734a99bbb895916275e8778cfcf7fbb7b7d081a677769e4ab96bc7bcf23303100e629fa8e07f5b8fc2e39c7b5724c72907eaad09d3088783b3118e57c9c8ad1799b43a13f73864c5602c478a\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b92982304",
+    "9d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 2eab6018361f557ab06725ad90f6886d4b468ab1a193f8fdcfb4ad15fff781c8681329a27aeb5f03a81d7c404b8017b12fe23165e941ea767c733513a07e921aedf20596763f6f977316e37bed70f6a617e5c2757c229c59b3d7b1fe8755b5f65f7f407f13634aca7c8a267e661ae2f77fc5a95f56cd6c8458119df587478b1b\nA = 1cc779145b2b7bf9ef4c9692845e162329940f96eb43e04db8728bfe736698082aae6b6a1b3c32867c293b08547a0941cf4059d2d567840ab6ea526e3724ad59e715a3782ca656cbb739dfdf0c113a18f0dd62423d4edb60057fcaedbb852178d38f1b5a232842b4fc645cbfd97a8cac0b094b870064302dcdf23df2c9e9f736d93409cbb8ce9ab3\nB = -cbba16086b51bd83d3460e51cf193ebc79b826e4f30978274eac3b2dcb04e9d7b56a1449b7cb128bbfeff5c4720bae45271fcc64085d3ee501f0f21fe73cb7db5f275d88be55c339f9180ea21a8cf3755a875331931b75d23f57c2030c89c6f9c1ead431cb4dbd4480564c83f8470610e5673c7eb6c0fe7351ffd7ee460df5db7872c67041aff0227f\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 96fd93535728b961b4167be8b304e570cc34e787c12a9a5d76e099b336ed6b837cfc246c5bceb04b0f4744c5da7071fc01d70e342509473e5bd7c60d6046c9b4f21c5ee71c4e678447f837db3a7694fc3936ca733efdb7d387f0f6e263b3ac0b89054a826da9716691c9d580ad38d701d08ca090b6c59be466e1b9833e75d820\nA = -6791fd686f46c3773fc8d7f4753d178a93f6fa4941f4305d9689c2a305bc67840bbef80ff05c7bc6de3a595f73846609327d28540cd705f5aa94a3ae5915ef55304c37c4c43a4b46906889331ee16585629bb303673d439de9c0236f708fd19a977e6e1032e0576a921853f7dd328979ad1f1aa945905dae93a82b3af9451a541f544c18ed2546b66e\nB = 6ae062b39c77bebc2fef05743e6d35e14a31c6fe1fdc42d8de2db94ce70a6d60d66263c7414b1081ef2fa6ab511b361b8baa9c71ec628dba5bfd772c440baefc2fbed68d40897878232d9715c4b7e7c9bdd41cfe7b6986d825f68be8cc16d04afb0cf593f3028f3dcd91bc94923f3d7211aa5f0f12d3270e8df8bc191808f0e266c4fce2af97ac7ce06b0\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 949ea5f645ffe5d0d03359d51a663c7dd6e6013812a47be309575e036503126f48677c68c4ef6e7b3f72d76657fa282ad5881263e649b5297da82e24298300d032af3f5e8309ac7eb597b16e257a6f7af3476a264415aa7783433e83be57ffb3fdb404a9ddc3527d6a9c297f8cb7b6674961b3af837ebb65f218147a46c39cba\nA = -10f59ba073126d92a201529a5374500612bc59a9e66322c6706b422d35a4f82d97e668b268f5527b4641c6099c80bcea504234f3c1e3fd29eba0f161da97c50aea542becba499f29d4ba5571873d4dd9eb3f48cb26fa6c929a704fe8e49791b2ca3293c2428d9cb453263935c9c90a4a2b39d23a0baa12535845f907d42b729033a0a1e74d18da30a88ed\nB = -34fdf9ae6760d4f434d09ce2a7760ca2dda14bc256015809745524dc49d841b07102aefe5a1d0182e3e09d4d45b415e46f653185742b9b8ea6960160752080e5c9577a12182ccf1a293407b534ea8ddd33ad16cd19ba537d8db5b542f86a2a292423d452bf18d82361240a7efa831518184572c5a8b73b108a81d5036b3b530d98bd47c7fb2123418f12e05e\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 9ab739ddae55a0d71b39974628d4601122ba6c5035c3ad0439691317f23dc33c0014f3e870a105e4dc1432ec79693bac658433b21cfc218ed411e003990b94ebfa87767f3614ec19f5bc30704adcaf85a9d3d15ea764c8f0bbd52ff388659637746d39859398c79016ace8c6f97d3a5616711a235b85f334fb889b9280ccbea1\nA = 76b15a0aa0f59ec804a5e9a627e1fed524320b29120b6789f8e71b1ac4e00a9a8c826919035b84f87d291e2f35460bee181342136dd9eaeb99ed00c6328b8e44c49ede3921d6275f6e7f03de179fb2374ae2fa6c58852fbb2649e214691daef945ead6c8bd5a53ad2b130e9eab6ad046ddd6b80874ca6515322bc171ee32749333669de0d9c883058423579\nB = 1fe2171056ed4585a143b6b2bb5f44047664f64d710dfc05c18be5840ef9426ef05b6e92e4ecb5544ee4622e9030153dd9827f2f01ef38e62b88ecd6c46b4457d16644ef6d863c226acfd6928a40de614a5853137124fe69127a7f05463eaa49bc742d8f7be300d06b302dfb0ba86801119bcdc01b516afa360aa8b22b7c6c1839cff859ca1bf26e3f7e030512d\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 5631048ffdb2767aa04d59d8a5750016b38b983a2d53743ba4de5d93bcfc8ec30183a84bb1e290ef9c72c7ad357728acecfc613a6f9b3d712456d545ed54a337930937f4589fe41e66ee930db3dc10a4fe41481008c69eced65b9d1c46b8574c5ac8f7d94025d8fff00ced17a5e17508527681bf94c2dedd51502a2c4652538c\nA = 1aca12b1933f25ea081e12ff4a4f6f9ce379f96d976da2ff7b8eb8ad791fabe31c1148fdec22dfd67828e540c955a1e13f40c5b125e1c7e6bd839bfa84e5bfb58bfed76058c6db77af7a34ffd25fabd60e19f65e1faeeea6371d7785f2e5bddc8650a7492e06691d61f997483661eeff54a30656f1daacf31182486bc40647975151fc05d2f64b50e632f5d5c4\nB = -88ed894287043e7e5cd2eda3c1e5c97f85809f7a246b0c20891fa9a024f3aba4ec1f3d112580fe6ba6b0bdcaa1325ac7ec9508aa88c187af08e4f37631eb6cc97e4481b18f747ce6d35ff355e425a4833834ffb8d34a818bdb015fb818ac9f58feb87020234243aff912da5590ea3f6cba74f1a9fc3ffa2b4aeea25479c55a3b572621e75d86d8c8f6ee4f587e0f5\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 6ce341aa4a571cd5bc110dd436acaa09f409661967de0bd096c77c60db58b2b0ec95cda50acd7fa20ea4266b2c579eeb6ac214a75d40abbb70845db74c4d6c93f8c545add269d45fb15d985e7e630d0425565d06dad4a3ff9835411e51fdd9780c24f466dbf29244cd1b8c3445af181d0928db399bbc8632f7ebcb9d48c0b754\nA = -52c53999b02a92d6254557203cb31a21dcb896495d1f29f3277d19129ee43e521ab9d5a297204a844a9537d63b74686eceba72ea2e7b98ee8895513395cf7c44c99348f5c4eb657874a8115f0027d6a416b8a04a1ec0e6809b7701ee7d41e99996e307bee9c295ab3df1faf674e0067d0ab3bec4da998580203e33760870ae472a3045bbd66e352b8f4d284efc00\nB = 4329d110504caeb71ce0453b0706ff675f646e70a6bd9575791a38f672eff226f4958f8b1fe4123c0001d8f8595d8030d0e9798232942725a9b9d654ecf50546adfba7103fed796b455ffbb4c153e70f941bef7953c8a210d6f2f4ddf5d9a79d9938503ae8f24d69d5d7df1c988630ed960e12dd877bb80a1ab0bcf6db67e0c0578fc0c40408f72b19052534da8d31ed\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 4b9fc1e0eb4be199427c48bbe1b53948d0135bc1965b8aa5421a4ec704b13cf934c650405ba02ad611b0f29d46d82d4a1fc5a84651a29364524e37be2fc7001cbd3c792aa477802999841ff19620cf66dd2453c9b05aac349b9094d43b40e358f32805d87cea3cfa98e05240ff95ec57d88e0a12917628ebd34946eb1ad6799a\nA = -15a223b691d8b3696306b0ccdb52c1d62c7c2d1ac71e5f07cd8fba960417b42fb5ebed5eb9469be67f231b5254bb0fcfadf5ac5d2906769e8bf8292f0442986cabd88805a162c0c1f60f9ff0bcc2029ce33452d05f754375c0bd147fba745bf8a0008792d4f90d0e0f2cf391f2d7865705544f4a220ded44732321473c0ae7870394d4e625df11bd0923340cb70b995\nB = -340e5ccd644849d982bdd455ddb3b9a23ca14e168bb87256bcc370ffb6b7fe78fd062b3bcc1ad3c8c3b8cb549f2baaf1b7f0f6522aba02fd35b651f7de52b3aa2e0e40352bfd6ed0f84a2bbc3b3a396dc8512ca1db01cc69611925f1037794c82a418f10e0d994f458d1f19051e8bea32b90ce744d46718f42e711c094ad0a1ee96c88920188078f1b044ccf307e4cad7de\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 31c090e5160faff9a136a7a482b42a43ae3c7d00c215cbdad28804be0e7b12b0b3af820c1350b1622a22c8875f24d48ff16231c826d1a946c66f70aef92d4e6582e3ce9213d907267251ac74fa3cca9f1c8fd53fe9898aec19936a2b797fc345d68f0791cc740199be39c05053d5591d874b415e62653b04a3f41e263d00f230\nA = 5419e87e50b28b6d24927934b541d8de548a8f4ec7e9b00aadb6d23f2d33406177d3fc72d29ad2c2e141ab2916adfd30ec4791c626af61d8d192276d632aaf3b54e2ffe83b44f",
+    "6f1ac441e6823b6b58cc08fd7a0af945a02eabb5aebb2c7ff0622a17b38077cd0cba906ce23e71ac7f4da40ef6066565b4cb3a62ebda28f3629eaa251dbd9979b123a5447ea20331723e\nB = 184782ba4daf429cbd13ac13fe93fe5833f09915cbbc707feca3293e505ce9cf0b4b12ffc8b178e0a4617f809be53d4895a4182e7a8a65043361e654befe8b01429ba4b7420193d1d7d90930ee19cee0316f33a5795335f5fa517e1ffbc99b95101b0f936353afd3bcfec34851ebff1ef02fea991a01b587d28640c935ec91496d1aa3ab8d38a6ac75b3a4198ed27b9019bb3e\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 5eb9f3ca660de481968a3c7321281f22fb9273b16fc10d8eff1fe34842364dabcfaee4993c1c8ddb7c8d6e509a8d2afc005075d5fd3c4471f0622753c7797aea900e785ceef905e2606f64f34e47239c40b74f07e2ca70bd5a18cb0a88780489f3e98232221f65ac9c5ce703a256b7b75eb1dd38778d8bc05a37ac9ad8d36b35\nA = 1c73d8e3d5db127a81477a5c4c6d61ac62af446981773ca15a9a01fd5175a2826a8763f91d68df28ee606e8ffc203305875a238d2095345556f12f3b5e10c5bb6ce3f90342ac74b9ac057195c863c4b9d28ca1d958a98649c7f8897bc6abbc39becae963f61b33bab4fd20d9d0e5464f21c2cdf06d00f597dfde45dc5919f5124f26888b12d72cbd2f57de3f2de7c014f891\nB = -e406fb60e35f0abdd313b8431f4cc89fbb034daf71fae0cc727e9a93cdfde53566fc74e48f4cc2111fad158c63293bca0b21b98416381b81d2443d0e91647679481cd6b6869b37112d3b6e575eea7fbb5bdea422558d817b49ac36a829926553202cf9dcef09423c085d26176a89be741ae20a434ea461def090dbffaf2e2ef97bbd4ec779041ed69ec07d125c7b85a2d215bb0f\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = acf9d363fc9b76ecf7e61c33270031340e66595e559dd1c9dd4d2243819b660183521a4124558fd4b216dcf5c52c4127fe517c48cef428b9ee0f1bebabab487c968a80b9815e82c12e807c096974ea3893a8d5597f745365c352a6bc6ce92479176092f02907538c5e784bf26dcde7672338f402753b08de8aa21b9480df6955\nA = -7c03ba6e3939ebbeabd35cca277eecaec31f326ab75f1a29e05af50c4e62e0175d4d6a57acab87cf1fa3a51791e9a2b2d4d5db570ec3941263902b0c74544c323c106557cd5139d2a25f3c3ef81ca009d4e3c16f1abf6e2b5196df1b30def46d61eccdcb3741a6dfc8e8c5e6db68ec29c82b0adf6e35ce7aacef8da806b3b58bfa489d319869b20768f8eebb604a9624d048f9\nB = 4e021959da96ebeaad17f9896ed53010d80ed3fd4c3a826a266e82b80ad81b3032303e7c0e58034a652b8aac00c08d42a530039de60d74ad349438f5ecca1256342ded6f30e3bd2aad5bf2b49124cb27f45f697e157550dbbb37f5aef0f04839aaf1ba43bf1e77a1529818d0fa91d940904eda6b748e5c86cd1b37592542c43b7b4afe2b8926fef6dc01784fa431d43900edef27f8b\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 24124c69aaabec7a7b4e7a82245f6cb14b199852a8b314a7b8d9049cb66096d5ac93ac75eb58a2004de8b0fc8375638c0878fb6a45be8bfbcc292e3571df1bb8d6e346d5595fa395fef983a365e4e868154fb3e337d47771419e7f1dd5e4220900c564d7cbe8e7792ab288f99d265aeb296c5ebfdaf08b88d9b30ac660cc3ff8\nA = -167c959417e9566c93e7e05d2a410f4850e3a313e516ec958c3d2fbdecbf58072d05691c68981e176a867d7467091dfeca11f695f750c8c44ebc4d08e39e679d96c4791ceb1ea3b89fa3ce26f7ef214c5368c03ba694f7ae592bcd8ae53a66cb3eb1e0cd3c105faae6eb7e7a8fbc88248be722406f2d35e46c751b5ceabd992091eeba15191ccf6dd61a7ee0c624d43b188c42b6a\nB = -343940f3b2a5f73a51d6f609e8af306f44ce7b5c2e79edf6f4dfc07866dc5c4b2e0ba48099b5503af87762a44ae451d166f8914ba25b3cc41a766583bf73d27e40784064582fd9fe952fc00e9aa2d4e4f1ef35818978e725e69c1bcf267fda4d635d1d292d54d3ad10bae9763dc5d7f7226f371184465695f2d384d749fe07967a1bb64df22f294ed88b13600c7068d881f713cb8e3ce6\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 50cac148215963e58cf6d2ebc36fa518c63a0ab8fb136ab84c9657fee459043ee9f42aafec89e8ba5fd1cc5c4495a41e80590ce197e12c087ff7e6ea88ed798735f55a1634562b82f8514488ada526e5dc10700058980885000e266cad55948d1e080f6343f84b12a3698d9ad5427fad4017d931df77ed2e45e2fb8380b7fa39\nA = 6a9833d768a22ea46aab1a1619f30283a1ec254a2de5652981d73146aabe31041ed04d271c6f2e5e2d090cd615518a06563a94ee2b12cf9f142de3f15599998a712974d0ce9b122a2aa65bf8750f54c6324f12e321a888154330f0f9e1e5b7999acd70d4e6da95c2df1da2d19544b7abd2bd3041e3228c7cdba44f7d1cbfbcf968f8fe87fab523eede0485efaf5cc9e56095cec8983\nB = 11e782e2b3f469b1e3d14ccd1b8301ffcde7e371f6e9afc99af5809110c6d70e1cca5c0bbfeb95fc3ef8352581c11ba75c0f8c445ce2aea903769a24289581c95ae5ebd9553fee61a30d155bf6011278807833eb2ce7ee2a98fececa23fabaaa259409e88e3c4f4eb1e04176d44878ad3f6961e0615ade2fe86b6eb02adeaa7c9019d63231a28f84b7dcc8bb0e71e2a717db09301e1dca20f\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 7cd49d72bcf5ff4fa2c686f21e1f0146c4f24b9ad2e900dca1c0a5d2fac5047509064e65ac582946b251a3f04850c9abd8b80c92af0fb11ac13debdae8b94927f1de0e4bb217e78f5d04897c6a0762667d3d883cb754dc610442c9dbd44228a7ae4f14fca145550d813655befe3bfeb52f1c76f989ea8a1dd9c10fbc7e9d6574\nA = 109fe33568598972063279b71ba0efdc2e03f770cdec331428fb8ca084c9b20d0fdb5cf9ad7ce90c8cb8f0fef10d219d7dfcc6b4599440db8cff9971da7852880bf004266886eced8763b3569720df3a1fb0dde2717ce0183f2250034871146628430f206c12f5fd87574c206b203d90c0f2c705cad3484c73da8bf4e9f7e1bd433a6f7fd27df63079d30c490aed7161bc594eefad4bc0\nB = -b95da952cabdebe0194b7fba519768e1b56149353cd12023b97397b59e0d7f4dd1d27b65b833948f58e66d3f6928cc3140cced835dbd612cc82a7e9fae1621986f71ddb6707ad57926b03e87e165d30fb145795a70627975bbf9d9ac9bce07492de5227c666663cc28b3e70b19dbaba7f16849535ce5fd61e91cd2875e0a534a10c60d21f919d566a3469d108a35ec3f023210efd5d318c7210\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 98a89cb3c9602fe503c32c44609bd4487b6c8323737b3376dafacc3eff96efcce7a31f1b61ee6799dc9561e77ac058fe5195cc013e72a2864f7e492d9f35244b321d46270a582f6f14f15fa8203d392e81b183a1d64d48b51d70e38d49c93869ffb9d7509f15ccde547d2d9c4dccd50eba49190b6e831a9f4f9000a95dc83f3c\nA = -67d7fc8f1766c40bd476cdb65d4dd161c3d4c2c5860a0c559f0e87ada213c9ed33308c36bb1c7d615fa69ec53656bbae6b57181a0134af23ea2a75f8fed3290a2f483392a3745fb57adf2121738c84f6d34325121a702c8ccac0090ea27fe9a5ebb6ba9d4f397e4a7e3151850b3d7d25643398bd3e4c1da081471389799245d986cab825a2e6ca72b38ff978a2753c835299ab4597bc65fc\nB = 676ddc4d18960817ff8fd2adffaa68c87d234d62d445d6ba3847ded849356d929d9e4ff01f517d7b1c0778bf90f475923517d855956f17ece1e032e2fd474d2133d6b8a591995454d8b587cb4f6fdd0fa29305f146d340cbe6b6efd28a926c73735621be0c5decb792083b3f063a43dd9f635e03f78c1bb56389a5cc993c8f36134d755a324d4fccc2ac3bafa270df67db0a4ee6ea4497aa33b5a8\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 76c31404854006a7d55554762094df6e11e0393f5b0451d85de2e5b104432df72023a35f44da10dbde01cebf77b8f9d3ad582373c5d32232564729af0d03c5450e439045d96a2f0a38871c922af2bd38c545d219adce0ec80fccd121d6a733bac09253604a8a0b1ecf0f24e44b818ab9e9974181cef10e9eb17684c57d72257c\nA = -134e8784878a8f3cf49ccb952075f9f9bcd24a20f8883955f262867045c11a9c566abee00638927e5de924872fb98f6376e321ebf3f567db6cfeede62e04f839617d78b7c9d3487b60a0d3897b3fa49b14c12511d04854bde4a9dbe5f31424a3d05cb75d23b46f6c0819536020880afa5a2c173f6881754b56f82a2864c99c820156f96b5cc4665d603597331d98d90a52f4a30c6215ee5eaa2\nB = -3c5c0d35de5fb21c84d2db228829f43b31132b582556b92b495f59df5",
+    "02a6d00584bb5bacd9b8c1a8c7eab91db0ea24b40f07e62a712842d5c2e1d208a6412a068cd5c6394d715260b67fbc03e3ae7eb4862f74f4d7484f747774fff03830c65fe022d579adb6737f6dfe297db750e6a58d1004e7e2716838befc2ea97179ecd53b7f36e3540e1c3a0f3e044bfe2d0efa9b89d2d308cbd0bd88ab3706\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 5b704b3181e5d0494937b4d6aa8172eea82919fd1d884493197a6a85ff047a7bcd5dcf072bdcef0287be20d4ac49918d1df550d184f86d7220f0a84fc4da3ad05e131c443fb529df01fec9fe4fa6fa2f36e791f9e16b4092759016d2f9b1ae7c3d071c57edf26386aaead767a3109c12a5004c7b9fa595e6d592daaa2dd1df04\nA = 48a0ccd2d14e14e2aa862d306501efe5de239e8ef36ff6251c861a0aee9f739411f402491bd99aebacdc26c4f30306f9137ffe4579c2f13efa81b979ddfffcd23675ac6307c0aa3ba8ee77a2e3a3c8e241bd2ade6484e6ead32ce8d752fb3584d14688f223758c5cb8705cea9c56136b219d87f9904bb56be2ea1c9a035df33455206e6b7972cba32ca4c3db41991117d88da3521780fe65c4023\nB = 160120a35ae3edac3edbede9ff1c6f317d95481227d87785b7ee46cfb80fac9973e418244884caca3211a3f6cd3bb419cf70fbc22d82ba5ab98ad80e1f6c2cda753aaf7be78613ef25577107a47ad1ee3c3645db85c4d29bd77900e99e1f439cb23c6c68662c05322f94feffcd9e37d8665cde984387093a043447de590e7874e6acfa37ed302040df4d5c3dcdf9fed91b3d17ab5c141d4494d0f301b508\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 448c3a64958b82ccaaed3c74706ce0a48c5e059c3610cc03a6b5a03a7de5d4f1d1e4b08a31478fa8edd58401f0171697f0662146ce2b371e335d695f9e4a671255f29fc0b9b7d1b2eca4cc7f8357aa0920b5942e31bcfae84e909828fbe5d02251ddf10dbe4c15351f675e96e2eae6d044da1f0858ce8ba9b7aa146850b85d93\nA = 1b2a52aefe44170376df29d17ae2dc1501c9c296f72f271c21f53db71247e72c3eb2b780190c45343bcc8f548507559ced3bd4a6fb13f9174dbddf965b9c4a56c3d88727736d78be9db2268cd02382e50c6fa28ddaf8eab9f44ad45d5882a5100b3027c150a7f3bb36f29d24a76e40f3820ba116d645800459f06c20679321cf5be72450879462f0eac99ab6ff8d26b464cd0e6d78621c9263394c15\nB = -b7d9bd08d7d8e0e9596851b7e03c78973a502afcc7b5fe5b0db6034ebb8a11df1ef7ed0ae1371eb4111cefd61c61935d768be3e3755e481daced219874cdf0d07a76e7144be626cf1fc21c8a0e9db4389ee213193775e95d4d86741d8d8fc820c239b7a90937000dc3e89b2fcd61b44e1c38c655bb3d31aa7e422b4406c9e4a88e6a2c18ec7c048f4a6b5b270c90d9fb378f64be3b5b351621db48a6c18625\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 2192157490ae044a26c23eea6da51d3a3dd08c7fb67a9beb76d37ee24ac0089863aa7f00849b81bab8259f3a0e1bc744d841e07aa413c286e4bef2ff3356bdbecee756026915894584b4fcef7e49da4012cd9fcb5dbe3f3b867cb6a7ee959a328b0fd56a9eac1f4e40a22bf0a30073cd2d48f99245ac03c373810c54eaf3306c\nA = -598eef47b40d1fa1ce260edc561bd1c1ab286a7e068af412ec2baaecd07c5b9cd596505ea1bf0370ea961c4ceeb9be76baec74e6952cb846f20e5da406bd01368b85d59569b403b7a305cd7448f331f10a34def43c738fd633df9a3eb194c32d53aeb567889927271d71d3929d43fb9338248b64f7d23cd1b053239e09cc2ccf5fe9c9ce240f1a10fb151a8583e4b4cbc70ec3082dd20a9962d564544e\nB = 559fc917de34bd7dd7a23a432142ed79e3ac4a6caa357eea21e423eb9af7fd94f1eca735d2588ec4c2ff013520c3a0e209627217cc69bd5a07ca46a43ec1f1bdbee5f09ceb1b2c18bd388d3852e51070943f16152a73da624be680c671057677356c6f281a4ba1f7c60609125d7fd9086c907ca5c191820d80e483886b70c1074e2963c49996ee92577334881edafd88270bb967da795aa4fefb739e4367390ae\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 3488bf00f67b852592922fbae64fa56d2e4e7081678e789bbb3b4f48df62576d537da2e99c9bdd721c725b9a828194662bbd51ee20ba73d4ed5562482540880686d9fb1e8ae62d08e39fdbbab1d18e399ebf07b3a6559dda8b043fc25a8152858d39b10ff64776e00a839950e7a9ed5ea95b594b6e9e9d4348ceae08071ec5d9\nA = -1b135d8cec9969561be396323e2f8be0c60903ca59b6c418cb19876e9e3cdcb9ce4f5251eadea11fd6e785476c70822aebdc94617063d161ebe55584a8a774ab230b8228a2b65bd5a6c873bb6b261429eefdc7d0c64c7e78133e739efe57f835ad03ef8f84601e1a2310659db5e0ee706f23e3c5c38c9f8c36e5b15b654d1cc528f1dd392f1b08921af8be6fe4e4e6db774392441883ef867bc729338943b\nB = -34fb63435c90018e5843098e379c76ef3ba0615b6b500854b3dda3e77fc5646228fcf3a6e1cd87a506e4959ab05e24474990ad98ad0865942737734c03dc289307f1b1f424b9a8c2264350943449b3d2b0f71f989039131e23095d122ae98c0089a184dc530669e804140134e5b602861a5e61c030fc3d3b3eef0a59f8c0579fc9b0afceaf16698de3fa07c43231312254c04ab11ad7a29efc4597780c2cd1b64b43\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 8ea5fcf7fd41803606c95729d2d910941e43b222f9b0c93a1a803b197fababbd653a92ee34e805906fde29b307a962a294aa4dabebf0d181c046653ad0fe6da1295eef817f3289dcc6579cee8869198c39a9f79992cf6894162d35d812df327a64470c935994aca4985d0e6a783b853ad762338dabd575ca71034e29d768d014\nA = 6858d029a62b0f75e4c59f3ec067e3990b2304c90a097daccaf554abec49a9d297ca14648471dba08f22ebbf8e238c89ea06f188203599aba56611eb3d4df09ea795a7e28f91f4a9a582c6b949c6ffc584a076de653446aff9b24e87202037974aede37aa9a121b5b70a3e9b5ca376c9056c2c91f5d5484baebb64cccb6a09b4f40529afad1ed64b4cc4aca586892693fb5f92edb6b4d5f678f7a2441e51410\nB = 197d6deff7adc30b025e7e418cca0a641e1a1b35f78fb56b9d8847f0690313475e6fbc6f73c3a718b10bf37434dd9fb1eca33a99bbba674195b20d35e3b34ba9d7c8438eede24ebb48e6d39eecd93fcd7dac44235ad32f208919f57b261da70ca378f9b03ae5e5a733f97f0b3f4102d971272015bf50b6f3e50c7b36cdaa14a8a580366c9cb0118ceec6e627827b0b8f614656292675ddb66e1c55355d5a1d78e69ed31\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = a25db977e7a8fa4578fc530995335411432ced67e131fee2cd7ff56970df64a6f0f4a7d225d2f4ccec8e98273ec9a0f1aef01dc0b866e425d64e09cafb9ebe3f80bc0ad71c769f1ecd5efdb4a990ebd3a94303f52f4a97e3a1d615918f8b2df5321c4aa9339b4453d7a710a803106dd0ab49c6cd9aea431f97fea9fcae0bbd90\nA = 13f97ba15ce46ae32147a0aa4c1639b6b555f4d8a1af15ede4f1103f7a0b06b4625bf456d667720adca0c4e26e858f008b012fae63cd89322b33fe51e87714519e7dc3cceea27d968b46ebc04024d063b17901a7ae978591ca6ca41afffd81769f04b714134cfaa6700cf23bfda6ce67313988bba5fd3782bc62f76cf551d140c978dc002a779ae37400d34cbea013a5d1338b203ff267861edd88ab8ee1e4c4d8\nB = -88d8a4c8c680fb01f493f73753c70ee753951d4734627da14962e36449db5490b8c575729fafbd203a125b500b96364e6799d9cfcf0efb4ec877e86865eea5e99e2fe5e7655c1ee0eac641e73b71c66d7a72c2934d1ccfefcf59781035b2c7b89e5de3f7d1e9128cac57947d22e7577832ba374492a2f53be37e17733d8bc625fa77fa5cf093975049a5c477f792fe75e85da26cceec820c8b255df0292824b4c3a8ed455\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = c1f2165a402fe9becea284dae60453965ce327f540bb8969562485fd1bb60372b8689d9c9c97c91bcfd699dc370117ea8b704f06cae3d972dc6e5eaac971597c69d4dc24a68b256f97229e643706aa6d2d844078a5fee2d08270820055ea58155d7bc754f09d0c6f804e55ebe53e3ec418747d4130cec68533f6f0c2f8fd2409\nA = -626a1580e52ba52a877cdcd62b34cbc7f949148671d4a61201e03e98985d704b2975b9a2d9c4557deae065becd662ce8448171ac582894bfa2c59d4ed20c6d0471fcad1d0fed1291df5e4556aba72f3645486580c8bfd0e3c8f6cb34fe17ccdd75fad4d4a2db4e00bb8c2a23ed17a31e95631320590f40416c153efdaf897e3b278a1faf1917554d9292f90c4edd5992748b58492289eecde1af34976ea8ff507fb9\nB = 44c336d77391",
+    "18340048939d6c198f73f90e13030b69be286ef920902391d87a58df3632091d0ef25340eab395203e8dcf3389e95debb7432165147e145735d2e3226637b4b8cb7d85d68308be07f217f57fe439b31fddf3fd469869a20f1f852e1645b0d4903432ecd1fb6397db4c11f6b6b9c0fd25778b0ff00bab9ff576b16538a6b7da40f01fa7b987af8ead41ecb66b8940c0e8a1208d0026773e711153d99348e92303\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 98eaf476f11168bb63fddf7dbf3347e619f9b580ea6804ab893214e94ebc089cb652e307f1f37ea7ab9052a352e260ff7d1e8c17461bae68c52a8a8f1a57a84c79b2c8fcc2d504ac4f553d2534f2a776ca129ec1942d83c8ae24c772f6a8429bd61949ca1aa714cc3881ed731497b84415c88ad4b9be34197a549737edcfeac8\nA = -15897a5a986641fc2cda42d185d72aa1552eb92f788bb71cc74c0e424bd038e02c620d0686ff88ebdf0bc1632093c0d89e724e7d5b526b0ddc4c7e145aa90b36be0d8574901fdf286df84a6b52674a78cf21ae4865618b4347bd905461d878537b33cc41710ddb290964c48e44d4d2ce2ed82847de75938d23ed418bb9ff1caa03b5c1ac5d65692dd1defbc6013b3270c4314a45dc67883762fda5509b915e8277c1924\nB = -3a7141f54a0bcef68cbc3006166f7e15a5c2394892a428fa417a485981316a537cb3ec757d4a2473fdec2cd61010a9ff865852af8f43afc79a97d394bb6c58643858e2b4dc5cb958c33781b5c35aced7882e8b8d7b4e4249c2b82150adfb0c8f2bbb1cff3d2ea27ed24eae030ef468ae4d6b7462f0b072cd2a2f02426b3290b87b14d14b34e91a94c5bd69e9eda53335cdfa7df90a57f97f3d023ff85537fe0a8bc5d8fd7901722\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 34464b7a50713d17b01b5940b5acfaa7006aa6b9b083bc17e0535b08783761391eaca8703af2edbe13dd0fe9036d38aecfd9faae08c0861042ea1a25b41fa8a15b7721909783de3aca127e955e177987518dd010306a795bb66466fccd55bd9e2bde17470cbd36b1e8f8b63805229754387a5fb40f3ee9a8afb2e51e25c8bea\nA = 701ae8c5bafab7f41c999e492f04a7626b2b1054e6dce1b83002b2d3de46717225b018733b0fa8fe3f973202da8a090ae3fd14f48b27097513ecd4ceb1b9729e7783c17fee9be5221fce4ed3860275b3b36b7416594d2b65e198ff564e82301cae23756c878494e57b5ea8fd22ad800a582cae32fbc985d122cbc6e0eac77c1000d3ede45ae7aa087534adfdea8e9f924efa1b19c43dfd3b7bc83d7c40df7c6578a320a19\nB = 18e0256543619a750384d30b6a7afbbcbdcd9a2ce644dbfc97a8ff699e118032558f706502c9b956695cb25a46d7526596b3d0b67b69611009265838bec533a9488d24583e7d7f2284e23c3cc4ccc5920fc57e24f60da0d479d41f5b9c6ad9152903a4f37842176c6257fb1e3e0681d6d583e704c1d1b24cf616fe638106638fe9d79a0c74f0df67cb2df9d99185324ebb037d01ba0066ba947d5345cd3201b19769d438c43292f572\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = bc57cbb3e1051d3a3035f77c2e375c7e3221dd472edb1a5ccaa7521849fc0ccc7568238aea9335a733d839e89ace6f2b66ef238267e0050c065c3d9553cf50cc5cd93d34fb43c3ea1c31b8ebf0b751f595a7e5e3e860b366229de4286b9d3f0267f78c6888ab3f208c55d9292079116ea0eb9f4ec2934c97149aa132c03336ea\nA = 1ffb0aac11f6d1d257ef7aa997a030e2a12b0615fb11ff04f344f6ecd550e8e77e9883c246e009af33a51204e4066ed4249950e022a61337848dae17c88317e15ade5b5499c0d7597a69a02b6c18db0f975c19c16d2167c583571e947676ae9c15be60e69d76e78329aed5fa57dc5e616795b5487f3d52bfe74b54bbf93ceda093c2e14104a6d2f017f0d200a9fc89deaa283e04b0bd9015ec67598425312868eeefeae9c996\nB = -9de2d82e25b449b8ca4b02b2d2fc0a023fc5804ea553aa84674a815bd74193a2e549070e2cfa0b90a53070646875282fdf855940905f834f5a07f073093c658cd1813fc5cd7092af592092d789ab5481bfb14b6683139646cff8eb1c5dcdb6a33113d1c97d4b587f15f972c06046730b7e712a8e3dd5f4bfd07cfae289047de31776f222d11510ab6b70a200ceeb6802d6c33f913c509b31b96e2b8dba9e25b0d2250c3b102d814683f1\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 9f7f4e010370ec1d76fa83f73c80825c3b71521855fca5db06d7ed830c910d0430375bf319671f6a83bf6b57d9d53cfaaed5bc5d615c5690df0067b18791c33cb9f0ac9fa5f0473e4f4eb7840b0b660962097606b3de5744089ffb37d9c0df1123a91a5896d4deeab8aebec469b099a3a9a4f6d822030ec2fc4d11636706fd0d\nA = -7f56093243ec2399548ed95df79363e6ff09de211dfffc314b7cee526535def0f9a8eb9aa6f1736528ee7aae8be55c06645708d576111766ea33e0564c12103edd61ede3128a7a642f968eefd0d7f3768b1325c2dd910d459b15e54145a234225fd29932234e59d3ff5099ec4d5b5c6075f56382ade1101115c7b94e1e2a7bf075dec210fdaf2357c735416dd5d616335002d1cde6056bf7c478f810b78c661a3dbe6e54084bc9\nB = 4df1a6296428d06f51f31a1b0f66d0b77a04db3bb8e1b80d64da649899a1a55d4041bf0bb47d3e3936ee0f3740e1e8c2b235e1b8944d28c7d617d1f968abcde9dce10d6e3c27b2e3607d8df815f5a39da9b5569e95eee1fe5532c0a80011e7415800d8a9ec175fb1d13dad959becf04964b70dabde6d37072dc9f6d914309b850cda33a565515dd6c0181fc48bc7033b314ae0bd5872480e02ffc08dac4e3030d83b33488cf149e19b0021b\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 6da5fcea305cc6eb47fb17190889e6a39c339da1bea2d7c95e997fc538b4aeec8b0edf7c109faad7fb6c656420f4afa104ada7a0d3d14d3ef0fc6774b59aa2687c0b4efe7c3fc83194a89c832f7168346cadc2b1fa6fa9a23a67c91ad731b4cfb9943738c7f9951945b2eabb3743473d9c0444ade756291f53fc7641501597a2\nA = -19dfb98f9f7d20fd331ea749d2019d8367935fb75ecde45d6dabc815ab9e593e51178a72816f85aa678304e6ff3a2c24079a59aca253d76c4ac633fea1070753ce770765bce47428f8f5ae40c26a3ac91ddb551b3d575bad9a3b6fc7954acc93aad2131b78fd212fb0db7cca4195b41651a5311bbd4d8c64f1c93e6520eef8e6308e98caa1cd0d3c9b4041182cbfa131c4948257f1200b1c5351bee77ac8bc8e44680ce64ed0648f3\nB = -2736d5038c60553927f389c0650bb1355b0ce745a7dc5f52c9909039465344af910a5f6a9cc4ec130b9877c1cbb52fc08b20d672e42b853d26a02bc07eabb9e3f91399db8465b6a8b1c9f4a4b9eeeec6e9b6180f1a770c139c8f29ceced61cc7ba182884ae01d14dd85bc924391333e8ef039b586b6a0ae18db3570aa560c2b0226d5e23e7e753873637c25aeb19e74997da4f5d0755571785bebbc7dade57446e0df4cdb8df23c1003533f60a\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = c0265805aa8ab52da5aec06ef7cad2026fa0b18edb27b4903e3c068ca6464465e34d3f3bdb4bcc10a19441040deaf5569645f7e09b36c56631b3a6144d6206d39c9bcac53b54210db6d484cd6a2780bc68c07272de03a9bba7e51c9d86cc8883cd2e1864a2ed711d505930143c883c57545e9c40851c6df8b3314a8c9a0d201c\nA = 5622f906b077d243521325be82a43fce321412bdab1f15e4ff0c11a7066a288b7939afc01d30243c8a4150e74286611ac1ca4daf457aa23508a7af869d2d55f54f2746afaec477cd7df0d5711dd636802ae7f673b3f730236ac3899330f89cb71d48c2838322fe856d9d8b4053d9c1e66acdb5e43614ecff954dbe37c5269d7ffe00b34e682c0be3d7cf653ef212daa3d55dff92b329126636e440b0bab55f4810a2849f77c39ebb93e\nB = 1ebe0d1800b1fcfb67d7d54568e45dc604450c1dbe103ee21d48dda300c1d9b9415dcd9f5a56cf12c2ede3c862e895efb83621435377387b29b882b2acac78386895c7daa90810092bd3062a3a4867f92d54622d7f0b89b40fabc4709fd507d4002ca80de231596630c234fa418611ede0ae4a9616d570232c1b03329bad02220ef64e455c164aadc16190ce35b78060a6b117b4b0641fa64dd8e8cddb5914e7657573804e63dc7b216b1a9aa175c\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 606d2b6f756548568013bdaba6e811dbae88fb01f5f36d30d15dc1e099d86bdca9fc1eb3a785034ea14cb7f4776586327d57ca5a52ea1b30f26e2a76140bbb0e930c7780673770fe22c5ed443c349510e1494ebe402f2621b1e6bde39b8691edbe5c7242efaa6634553e6af146dd40666edf4a3db5d1e7f9347fa1189c1e5168\nA = 14ea5e6fd612945c71fdb17ec44d95015773edc908a85a6645a8eb823",
+    "d11226545d05b81791401cefc81ce9765eacea7a619cb482f29d38988d355ce731bc9009969b7487a3acca2d2065c1faadc5d6dd8ca1dcd3f3d4ff61d0a75ef75272e62193618f6b802f70795041de26d6ce367ba996dfb91167cb1fa16c8977f982e1718de7d60275a7f66e4ad72ee55ea06267cc4e8b08f488579825cc674b0bdfd34a01bed08b62004fda15b7c\nB = -8a542280f6c8bf4d9fbc96d5bfa6ee0d16a09dffdcbfeaa2dfa1097a760dec7bc540a0b5b2020bab1eaa594117a40a9bb99c3f16fc340c262b29909608740b8e77fe4706a88dc0fc3bcd47998e88fa02f617062393978ac1bfe14235d43f3d5edbdfb9f140412f4fc2dfc05a700f47b1f0f90da7ae07ae781d9ccdbb951f19a8b8a9a7dd8a65942842cf207f3baed3a0b2f08a06ad0d9ab7ad0110346293d51ec53ff8165b925c0e7906be8b7303252\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 512220042f151479a6a8b7c743ba83366cb7733caf37164e9c823422ccbf78b0b83f426a7230f559d50bb0ed3d9486c6a6e25f4cf96c4fdcb2c861566c6a73215b6d08995a14569710cf9e54abded1d77fc7722d06fda4557a3a99862e5ce963e1be25336fb42a4629391cde3aacd47ea5f5426e7185c5df27d9136a6df26f54\nA = -4d108217b778694931088bc255d1f69cf8f5a14252156163f948ae58d58f2ed54f518177d668e795474952c930052c1bcfcae11bcd15af168ec2e881e6ddc8de257d0cff90ff3ad409bb3a080d30fdfda99078cc3ad8302a4bdd77de66ac082b40fddb3cb36c75a86bacaf60984a74a0fd575d751ed2830650d85844aba9e3f781b2dc6b515bdb8d9459b083e1aa653ef177de76282e86c99e97dae9c0b050c9e6456a051e7d99adad7be4e4\nB = 7b9079504c635655a588ac360955fceb10cdea5f3de548ca2db681da38c17a70df5798f72cf18691d14a5f400ac69fbb47e64115cf071466c54bc7077a228249209542683ba57791352ef3409f6a947865d8f234ea9d39491b5c001685487b32130bce9aeade97d9537afe3f2f87e8f3315619ef7f215a73cb724f1adca99b90912aeecdc81485c0d00a74387ea99c965118fc6a9af1163e60d1ee6a1eeb12d7c2bb9a54f747a415beb5873d616fa0eafa\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = e36899d83a143c82e19e11494ba18478c0a9497fc89fd83df38adcb6b33918645a416626409a156899c6583ab9a4426438d9c32cac54b78df579cb7b6b1feb3f39ca4a6183743a4b823082896a89f9f1722be842cb2d2ceb605f84a9f9b61cdc7e184593fc2f9ff2994fe6cc4860d255809d04ab47e154eaec9ecc807ceb298\nA = -1422272d9e91a14b38b3e81cbd9411a0cafca23addf4f33c94a1bca70603db879dd8a9c0b95f5986bcb447731219c4f9b32a1e3253b027b7963ce40279dbf4008e526adc0bd7bcb2b533392a105c6e8e1bddfdd2bde7dfa0d2e3b1c6ffa07fea07ecdb9fc828283e93b0ce4861945562478b1a56de32251b7d31f9a2309488f7cbdcc38cd6b1c951570675ef0d61e1df69fed78979dc755f160d93ab5a3e65dc2944d3333cb85aaf87a153a90fa\nB = -2424fc1e71286ce3be684a10dd885e4891b52e9009c3021d90ebcaf68b6db81130bdbb74869cbf142e0f44ae72684fc12c85abb5157987428c7812889beecfd7bb43fcac2eb6298ebf1dbcd2e70e4274841c2703b8685df18f6e5bbaa1422004797defc6ba843e77f891bbb46699a863bc1d77c5e3cab809c247e2975e8170da00fd9c8b232abc3fc6b16951ac4e6c96f9503c1ff2d6832ff9c35b2c8aa408645849c577d2b8599ef520da57fe2a9eccfcba6\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 4e8a59476d47ee2cd0217bae2981cf25a2c38e5f5d5c30c2d8bf95856a6e8f42429e565f1836365e550d85207246514624e7ed932d6f5802a50ff9f15d500dd84b27729c1717a3df0f2d6dfd40f0094208445193ba6500ba03fa3f4bdeaf9251aace8729b32ec3215bcfa170575e26265fe523cf44a071470e3b1547901e9227\nA = 452cfc78cb9597e67aacd4ec83e5b473ab8b7a1dcb6097fab37e25d5a6e25c69c73a6c20de0e2a744375bbfe7f612036e69c7a503255d9e17c6ec1dc6cc6f634d4c79bed4764496e5c7c026fdf9408242d3b234195e67a5681e7d7b861f58eb631ddb9aeeb0e5b3ff7a7657a7fde5975b8a9e1f643893bac47debf7918c7ef8f6d7439320dccaf63b80ec9761559078baa8e35d98fb9dc242ba83536eef7ba9901395ef02b19990d8312203df7dc1\nB = 1dc222e7a737e6d97a703fa232defc6c0a4fb2bafd247c8e547b9c474421cacb7692ec98f94be19a5e40269e1f5713d06a6d081a943dbc667bc867e481b99c55e437061cd44c4482649faf870d9347e0252ba9dbe116fb4992dc2c2a0583c1351e9e01e71e9324f5fa942322485bca93c2d95cf304028e68224fed446966073ec7326c93ae326a7a533a36e053437910418bf1761abd9c4c5ab7e6f538e9bf963903e6c80f21a0a38a683e8166e4626a8d8b743f\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = a4d5e9fb7f0d75ce41ffecacd2ee1e4d15f82dfd4decf5ab1bee75fb97792d0d574fee60a30b15af80bd38e6a25b1821e61628dbe456e39fea3f8a9ee6ef3d2332412be1500fada0c1728a1457656eb3e9d94c64fb2d0ac89f10f2b9ff57d73207274ae7e8c7538936cb7241615b830cc9011d4363ef88f51c7b3ed503c25179\nA = 13eeef030b3110451fcb1a258434aeb51d3dc805b38c72ef7c79d4b0e18d600e5dd28b552b59f3dda1898367ec7da5dc6d9089a585cf52002eaf8f9ec64b8d3ec50d0bef7dc3faf203c48583ec89757cfeaf888ec4a91470a6b8ec9f26a6b07f3311b4fe972cac2f2ffe47f5c11d2dca87c62680e2229120cba4de9cfce9f7f5c33af8398c07ffabac1675de1845e05a32536329647214e54e5d9216fc0cbf2730898eae19e425688bf184d16bd1d655\nB = -ea324da99252edb03f40100e528d9a5080c43be97fe4b7e03d9563ba48040d328e57d0defd4b7ffa9bef3ca0d2682aefd2a0ffca8566e755b11f2e3c6c1b707f1b9465592aba6181e583babd5c70588e7123361a8ae77d8c398e33f894ee288babea1d7eb63e2f3de469e502b5048417043c5a9a9a3eb921cea1533162e3ce9c79e6caf62bbe7e17b180b72c59b9ef5fe1a001b733d909a8278029fb4a63077ef9b3545f1159ad73dd75030aad599ea4884677e01f\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 2f096fb8fe2156c41ab695956f13f0fd9a084f87ea5f5b1acb6b60c62617b8d7079f4b072223ba18cde474af3942599fe070ddb0ac1a99f42b9506a2648e1b8f6106015aba0bf7a824842403bd3f4ac8b6fc4a9861bf0e8ac59be0322f0495e4b515fd579dfef273160ddf96e453f4ab663e703609c709fb1f016ca919fb26c\nA = -4212bf679cc00adb2ca502604b71dd5dab99cdfaf55ae92aee6bcf8b3b6354a384656c09eec6175a95c8cb4591ce118e783d6344525c25e5b356e45802ea3ce1fe764833132e6b7bec434e4481c9cc2986904988bd8da7dc2e31cdc481fd0e359674bbff524124bab1ba4379885a6cfc1b73d953e6d1aa1b938129d74fac9dc597c31383f2f7e02fd995f7065290a9812ba8e205316ad5bac6fc65c6c7310f1a6b033503ebfe85bf6d3851bea1b65b9c15\nB = 7ad83f97f40d5be508cb394c128764532f0aee9a108eb02840ca1c635860b6d751d5f676e8670e2f61466397e1bc68f97ea52d64b335d07aed22f20bb1ed19e3e42e4205d650e6d37714c2f80d39b111577725e3bc7ce75bd7ed5e44f8377d5fc2b97f05c3c1ed5ca1ec90ba3ff7935a25a8acbcb15fe1fc7aeaa1e444cc2f06c1e6711721d24b8969d465e4958cb87924b3e0fe99ccb371009b5b15747bf6dd5d0fb73b8fdf58d955c8773a55424a34c741406f6f904\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 909626a69c803e9acdca97c56781eb672d6fb31430a53b853f467ca26d4ae96c182d71c0212894b776c88e773acbe9602e3ca56584c39b5947724290def7dbf04c6853a108c1282def95dbd5bdc015b68daeea0ee959b35bc5af98a4ae4cc7486e627bc9432bd009b21ee9af3085f074a3ae1bca879e321018e991e7898f2897\nA = -14eb8e28dd04a159c576eb10578c24fad9eedd3d8b7560b681002a54a4bce2167de05cd061338f63c50b86327a79595a2dbfc1d3f4e76aabaf88cfedb69faf5148c61f8cfb2130511a3bf4a17d846ededd4c08f3b635182dff1854e8c4c48007af028e06f01235fc2becdb32adcb9e2058dcf8f8655624bed9915faa06be972282cfbf8530bc0cf2de5b2057df32e4a6cbc3c772feea0a511cfe3408a6dab0e2714fc4cf15602ba0da03bf0016f1f3f5ddfe1\nB = -388da160568aef9f82fc16f48a22e8d7aeac99121cfac9b748c815e5d3a823b673ddcd20c1168f98ba204df5e52535f61b224fc0374092f8c834321949fa0a812b5e65c492fd9fe8246b74143a943bcdbeba16024e311d673357a3dd3eaef9ae3a72bb06e03e34e091cbe5b6a9eb9fa3d7f36c03baa5c3e242f2c186b58db5dddbd73f6aa54aae027529b8f8f0a536b9b283ab08247b9977a2ac2d0d9f162ad03a2fe247d2c589b1a2d14b5f90d5b9c0a95918ea956e261b\nM = c462c7cdd79b7604246a0cd97c017700feb25908656",
+    "b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 128e8844a2f04704a4a60cd33e85cb7ad373ff683abd167894a35a1daf947f504c0abd7a614e293ce10797a5330147c88c4d5e1dad1bdbeaf74095e3f5a515f2af68b7bc11ee1f53b493133905b654318dcfe73118ef1931eac47deb6c4958406b704ce027d9b027803eb8e639b52d5983094b8ff4b54e86a7dc6ea169ff1af4\nA = 75e6b045aa44dd9b8f4b434dd4bb1346fcf558a5e96b00fef9b6cfaca72fe8b1672edc2a64beee8b959683b1861138b297629b44a0caec6bad2ac05665728379cffaf66a129f0ba40aab7c6b1c3fbdabaabc87ed3dd580ba80ec7ee765e9a8fbe845c0d207eee7a1a3a0c39650c75ccb6bcdae2e0d5149991dc3bf899ae9b7626a2baa17b168b260d82fba84a12f10e09234035e08b730cfc230f0d2651c03e34d4952fca6409b5c6ea5d8791c90466bdc4adf2\nB = 102fc193633b0e60a48dcc17aa76f3e52cbbd1012f179736a0ba7a102f8dfadaf434063b0ed1b1528a018b349eaf192fe62f868b538cddd7e8e6fd98b93147727d58561517b2836e4a373bb31fc8d5e42d16126ed80b880c1a37940c138fc1f7255ee0b7fd39b1b799c34e5178580cdc076ef3fbff65fdff7497398fb1cac75e5c09cc7df1168a20f88a16e7b3ac78091a90f1169bccd48c0d06b4707ab79b741a168deae5ced5d48bb5f5dd3f465e43c82b9db7edab24569b2\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 9aa9699d1e5d2c6acb21e31890c1899f30a925b834adb5b8bc8cce83a1718944a2c90faa71b34379a21340457478c0c43121dbd65d62e290eda2ba6230bce4e6f18555a1380c7c95c1700793157f7c1cbabeb09460ca28dc596bb17851ab2ba6dc6bf311ea69bdb7fa8eb78df74adf171d4677a154b8536f8104d919bdd58648\nA = 157fb9e1b38f288db78a1a0e22fdd9f48a59779487a9ada2774a094d34536b85993e7b9ab6e24f081c4cdfb64a82271100a054169e4f1c24e3957ae9aa8300e85eb2a45a6d5987eed4f0fba6fe8557cbf6128e018c5f9df028131bbba6c544b2c6312aeddc71405f0e4ce648fbab9e5d51685949408e4ccbe06fe501a36fc13ee65c31f062313135054b7679eef45964c77f5a1556ac09b11c496d0ba8c6057e283bdaebb4e6d9e5c557d975745f9f98a288d5bbe4\nB = -82cb6334479bd997c771e894cac1ead87dcbaf8f5006be5c70ad48ef94303137bdc45f261af91a201b276a17d884a56ff27af7dc06cc5b7b9c94f7c4d4a36f68f8d309c477b4969a6e7cd1b2afab9deec06555cb753d8a0eb00965359ef865a84bfa87b815a42b2050e1635d5ae5e3743c007bd79e820aa37a968702a960fafbddecebe63f022553cadd7a4d4fb27b4dcb981e8b490e80bbbf13af8c4412d158775db71f5fbc9986e7b8a8f9299574abf7bdf9ce7544e8c4e85bc\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 46e401989fbcde9d830dc6e3c42768999f153d44d270d4805c5beefb470bc1e82706aa7173b359763c5e15d146eca91a32a36f0a80802871933cc7f2ed15a5472988849a2d2f57543345b531538db57ab9bcbfbe787efb0a82e61baa505aad628df5f9e881dababb35bc2decff267eaed3d3671757ae1764ec5163b792b4db3a\nA = -590c16ea2cf7fa7f63b5cf74804333f22fd2d0e1da7d226da8425abad2b39a4672fcebcf5cc15d220b0ecfeec09665e682fff0140f16889f7a6ade9ec11aae3fa3a369b3fc133babe52e42b7a8bb9a24777521f4d9e0efe7d7977dced9e40784c24d2c6056b3b668ada7856da71af73d2dd33d2e481ddf40999d86a6e236d0d73f31a67c52cc8b38203bb2840c0b92c2612ffe5fdb6be87f9a787d70b3dd506f9a63d144db3417495f0a48523c812d14a89710d95bc6\nB = 5a2865cf2254710a1a51ee3056b0c1f6c5f77d22d7aa8f939e6f48ecec529a169e630c554bbe682a8c4de9ce4daca77a278d7e752cb678141ddefa75ba42e661885a82ab55d699414ffeb75802cb8f4e7583bec8a7ab58803b378bb60fd46f476ea490c9aaba568ec17f3a6afdd6f20ec54a512f7aaf62d2f941e35b4b72dea77095e863dcb38bcaf8777707c1dd437ef2ac6b6a8b2b832f80ad2a6d6f279c053d02058b1a657a1cf5b6b269e15d29087b0cfc0c2d4c3fbf32a167a3\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 1c9649f4540556ae82ffd71b2c71ea8588aeb845c50dab595db9f8faa01a26c809d30d8433b6c0add465e164cda2b6723c942ee87241eb7baf9944cae08babd8e22a0eaf35c09e9efdfb9f8bfa65d53ee6eb23fcbe1d12a66ae05e7592ed788b231b000f895d098a24febcfa4372d249575926a5faf966072f29a62a401ec51c\nA = -1bc9ae5fc2f6a3f1274584bac1e145f02c5e8c4779f4df15e98dd34344c988c1437ee4428485a09090d81b18606a6ea5c1b9136872ab5b37373fbffbb5b3fa8fbeca1e112b9f1643658c2f38b9548cd8f0f271779ce0acad403177057ea0a2af2e7435109879941fbf463488a2522b831b95c1cff21d2d816d70c25156369dbcf04a0e28e1d746afb8a77713703fefa512816fe73e203bb4c3428efe09b946b750199bd7a03d30feb90230c219a103ad4528cbe0de1e5f6\nB = -39cae179d955049f830867d4115d3bae25127c945b1fa0c16fa850e8fd77c1b3b9b7916b9983c1659b7cee77b7dc72abfff1c56681b7931c5e58cfe4f1bf0168ae32df0df8f652223885717a98f858a497b1a4be62a2215c39316c34451b0d957791f49139921d9ac8041899b8fdd5d3d443547a26ddf5748147e4c3e93f5043ede42f38a9baa628df65d3d6148ac2ce182056700f0f94029be05d3ea3a218b40f65a87b4baf097fce107c080de24880259f1046175db1297016af76d94\nM = c462c7cdd79b7604246a0cd97c017700feb25908656b4733353af8119ecfa0212e4bd24304edd566adb5c1e9daa40894290a9e2e20d523bfdb5a2603409b312cba43d567a27118c15d4bb2f3867a7ba7594e02859850b77b929823049d43573a881948d674e95c7427e2d04d4ed81b5f4de21e0d5904c8e0359c99d4bdc901a4\n\nModMul = 9fcf6a47addfa336557749821a88ccd2573a5ce2c3094a17d9a29b33e043bea165499e89fd2c939f17a670694aff05e9af46836b62c96e597c83681092d63ab9d6e22751aa8fd4b9ea94a90a373876ef0f6514304a495edb5ca1795c9ade7965c70f9aa92f8ea460ccb670e9a62c81e9c\nA = 71b93fbad39b1c2755f2051ff7d532d59c985756410d58aed3947d6ae737ace5aadc35e7e0d29c684b9d4bec9c0fa277996bb30230f70431cb7b905\nB = 167be8381a3392dd4df62e150025e13b388bf366922ba8632614928922cc290772135857d1b5234d51c27862cb1a055c1b86260b6ec\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 8e2ba940fc5165c6c5f7f4cb55cd89d1d5f59e90e78730bd66fb120a814514784879dc43ad4f355030ddb3486a59bc34b601474978a94ddbceafdc0ee23cb18708bdbd824d37cc32577802ac6057fef29a71f168e816309fc80cc46f251e7289c6a57fd222d5868263360af63dd73e7c8b1dd6b3f3b6939849580b9231940a4d\nA = 1220ac4bde4feca135268550ddc79d8b05ff72f483b39f77436f348c4f5360c22c598f7dfb76697bf6d2ae86c68e90748b8b729b25f932b2e5fd33f3b5\nB = -bfee56cd412318cd62e7b6cc49217345d3a94e7fbf6fa19053fa685efbc0f8b320b7e43883189396781c49371dffe7d126c032d1ae4b6\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 8e2ba940fc5165c6c5f7bcac0e449b64801e75134a390f120acc58cbee43888f50d07f7aa6dc2b33643c025cf745434d20eb1aeda8fcee5fa3fa5baf10d67c21390297857aa50bbcc4a29a6b10885f97fea60f1b88fc72512c111b938142ee8d67545efe386622162e8fd50418b09769b8c22efe54fdacd652580d609f0528bf\nA = -7bc53f6f2e78628678ebc8e35ae4905caeec61acca5c64fdf595689cf005bde2265cd43172802fc133dafd933d7b48def44256868d202727a4aa6c0cde66\nB = 74147c93e729707111d0d531b1c135453f3e59f63a7e082b43dceb8b16cc5debdb6d7c0ce0c00ec9b5ca51e7673e411c3cab34938124db6a\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 43c47d7e319c32a758360dd726a1d91e2cf5c57f73cdf9ad2040e61a9c282a2962d96d300e04288461eb1ed37df19e6b88f104a250f9885898740f6487b081515314e0a217df2d4345d3cf81eabb2bfb346b634b9c251624748f6e9407cb677aff4c53fcf42cc027de267e6ec011e14bc7f3bc6666f693d21\nA = -1e6ce0b44105047d0da0eca7b936980267db41d41319dd5315889fe8fa2329023d7cf54f71ee179b5bfedf442cdad1920d311966f7175cbb953bb42ee105393\nB = -23a330c7e06cdef4b6b121d15a9c0bc774eb5e432e72d04c5f03a0c588e55e010b61f57c03c51edb1211685d8dfd2a35393091fd0e3ad2304fb\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed45",
+    "2d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 768293c84c431b9c8dc6e538ca3f856c60ae5e1aaf42325865418b7bed16c7fc2589968319cf41cb370657c8edc7b969de10e0566b64ec796470b630e22477e7aafb38e99b6012f100c9d23d5517d486e3cab1fc60c1568c0228c9b55d2d77d23b1351fe37ad4fbf9c07f29330a539de4a32709d043dfc9e21aa1a\nA = 6bbaeec78b6a41818b7eec42fa3be7d639dfd86fbace2bc14e0369dba6dd3f04ede8b808743d809f43f70f1146dfdb1d649546441919e27f1f7a9760da4a3b152\nB = 1199dc2f52868a0cf440f6666b576541c7aec1e9cee14c1d22010ab0f53fe8bbf3029c639ff78d89dce82de85fd8eda4e67395d435df60158623c5\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 8e2b90afbdafa02ce68d537ae807b4e7f3e05a66b20b84cff309941fc3150f99d083841ddaf6f19f5a76886ad5d853c73051a0457e95eeb0fe3776a084a027ee77d14f3825713a59622ea163a679cff904db33bf6ab23b06eb4b31f4e34fb122c8c170321164439db783e7bec1c265eed33f33bd9cb6d1611c00aa18a9b4b90d\nA = 1c4821515167f7073d4b7cfa318ead1da1131499c12497447846caa84176a9d4af576fe549fd8b0f77bf8dbebf6c395f84dffd40400101bf28b1dda0bbdcc5da255e\nB = -de60cd639044e863c6a49c73213dbc2ca84e4225aefa5f880e829f2d9cb48ae92e3f2680c462ac697dc34da38f65fcdc1b4d8c3c99e8cbe29660b539\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 33e8e8e193b4b99d8bb382c29c1fc5403190d7654f43cd77e28d1bf77bc3a728dde9de9a89c6522ebc7222d25f46833fd1753a44275b04485c77b675d816090280b3541ca61bfa33921a79f7286830131d6eba13acc46cc2c449b3a359f1cb49d67a4d0cc1245f3f8b59b1684aa0c3ff1c928b8e880a3375ed811dffc991fd1d\nA = -50ff3e00feeb2efc6df6387d6409a622b7a8297a717b8d94d0dc41c6ec6f29a8455c3580019349660b31dea1e4f66b74147de93535e671c853b604ba06a9b62d34646c\nB = 49ff858c7081392defc3ba12ea8869fd61188ff15d9339be72657b00530b851de53b1fcbe16034816e73251fe1ec97bcecd8bccc470373974287ca328af\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2c88dc40414969e8b614bf8db05fbc38fb2b7ce144d7e707f9f8eca40ae2309c1fc67e713a8da5fbb20e808ad20aeb369cb72a77fd285e38a7895ec0fc795ade4ef1f1680f3a3b3cee4569cc9d5e699984daab3385815d2e515ba5d67d21dd1defc12ca81bc8ea645f8f8d103b4a0a9cdc92eb50690c07a037df274bbd5217e4\nA = -167ee0fa8e5d8b569d7848b068df06f6baed80f6fa6a442f9d11d9712622b512249b92c7ccb821ac751fe4ec0a7a47e04ea5571c7cb45a7985749ecdd87f0c0faea01d232\nB = -2207fd8dbf2b8e9a5e3cc515479cde241dd3671803f9fbf7859459ac66705be055fa759c85631ed2a61139657eee7eb08fd963b49e33666e60b7e75dd26b5d\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 674885ca3ef617a53eaedb9564cf96bcde131760ac541a81f4b25c174a6fe1444c2c206f7171e343e1bb43f81610162994c497419e75aaa25b664c122ed2b27640b45bf646fc5da1703fbf1cc66e10a3c306eb69ae5f937081a1a18dfc8db376ea18f4c1c499109b0cf8806eb32cb1f28985da790047bd7b32c1f67bffb9761\nA = 413cbcbbb5851a4ae12555801f7f80ccd888bb82ef1b5c31b99e1901d7e0ab91ee489c84044bc21fa2010f11aac21d0531fac09feb482fda579cb9f224c3149dd6249b0225a\nB = 1b6bfea70f1d80350eeb45f9a5cebda954d72cf5cd27a299ef5a42e1ed0b50a541d1657b70e50b0cab69b22e31d0944fd735957b1ff764865d9385af302bb802b\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 8d74ba5fdc67733ced4d468f6eb6ec4c1ebd79c97682c1d4daa06105788ed9c5144992e555d903804d7ed0dd9b29ef2648568ab7ff462a03e0bceb5482485afc3b91448fcfeba435dc587db6f3a022428d37fa0e85392d0e48e7d4ed6b21253084e653da8175587b3b709e28426cddfec8d9dc582d4ac2f3d540305c0fe17327\nA = 17c0b7f0e2cdf316e4d32f040e26d41dbde1e6689d98f0652da1c380daf5dfeb6a511b72d82f1b32d3852e9aa2f594be10776a8fc89a8a35c160e8e41b42a06a342fa1c309fd82\nB = -d7b7701340c5a358455ca5fa314ad83860d9f765978ff652d7f542de2e123bb976930b8fe84b9608648324450d8ed2bac4e44f2fc71711ae813cd8793af8d3796e8\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 57e60f79b4e156ccec4c253e70df8d86e4aef326150d612a5ac4dc285761e88ede412d28d9dfa5a6f5c073d3c91a65ba9c86067d81f296935f0d0ebd2af82e7f6b5b336422429cc3b8427fd8d3f5a6fe936f4208362632093bdd3cec1aa8f4b176d260f605caf4a12cc011f3d1b76135ac2507346674e41673eb16c0f55d8010\nA = -4f1568c207a9ec970b5c26f068f3cc8019e8cb483525d251cd2919b368d072ac8f40017a19fc7437cf88e927c9e7d6f539ee84865f0af24be0d6d98fb33d74e3e0d28020c00bcd61\nB = 723db98a78f42aa45496f31cf78695583526d25e167da48ec310e447ad3540be2636813a2c2f7b8c622795ac451992e91bb8e43e5737f0dd95623282e729d815b08ed8\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 237eb5726e2c628a515104bafd44348dbf099569815784eca5d6a415d3c12421c8c70fee23d6d82f7b5b136b70ffed3b6d9e98cb47854e79239d96c26f2ec955e4ea8dabc29a1b0765c9b7af6ef09ca673d1ee21c680e4b8cfebf47bbc74c993d017ead6cb6f3319ce4de9e9765cdb3ed8fcc57a1b153327e1a6a965e5dfa89\nA = -1fd1f634685eb1470dd9080529a891253a28a0b31e15c662733e20d43fc4cd71f4cfe83c3774adf8293a0fc3bd806d0b31b61c6ed0b4414ccdb91e2994e22797e5771c63defcc0887f1\nB = -3ec0478afdf54c949a097ca411be41f931acb750ef4f0ce97d0f0fc77cf15970cfbe24b170aa332de04836b7a0e6c5d456814182d27c8310d5fb662a818bc421587d95fc5\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2f1d500443fc4f4b86e7ec93e4d0dfd3faabda35a6dd31445021928373be14c37fec369ce80ebcb77aff2151b7ea94d21592da1823ebfa0af196f286d7a69ea54799573bdcd4d09ca4f33b8a3a93b35de5ff7f65099d59367914f1c79440b471ced6773b0802bd8ca99cf531b62892eb1e78d67f8210592208859b0aa1754b14\nA = 572de2984fe2ed0d5ebb5bc3f62b197fd592795d91cb16b48a0c898991ee3e884e5870b92405f248036ef9b3898c5ee6100a09ede5a48bf7edf3a067e4fc77e7e6bf6a6e3d4f538e3d66f\nB = 12c379402b18a34dc8b80c0dcd25be16c99d6f76d5d64b6050b90910cce594bc022794640735710c7ded857ebd44fe5b2e51574a2296f7d7a61b59c0123051bf2ba4a168cf8f\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 4001c734e1391a88640007893f167eb79ef61e4717d5eb14b8d80c25ed59c753be63fc8e54bdaded22c9c7d3e49753eb49efa010439807dba0d90ec4f9b498aa97f109af542bb41922936223213ddedac4d0fad8f1446498f4228b758aafdf1d9692f59029c76ca2832125ba50e811cb95f2b982a7a4d87b4726e6dd8b1963fe\nA = 16792909716b581a936287d0a8550a1f3e840935f0f3ddca75aa32e3489269b078fd19a16f8d6b2326eebaf46da76e90890c0ead3b35689bfda8c1ead17a4f672588f982cfd3da2c2b9bdad9\nB = -95ab2c47f85001aa852d6999f29644a6a55f9e4e12bf905f911f90d29cd1e4fa4fc9d1a2aa6c215bcb5c5643561499aab8f2678fdc5fa9c6ec138aeb2d62f635c45f239e46b0fa\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d1",
+    "5896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 1bfad44b58d3f8bc987116d4cc7ac98f89f838a8712d81d726189e9e1469cf46fe04675dc0b82e6e556b02c350ef4e30ec6203c7f1df937ea80f435af7c10f48538fe7755ba78993f304e64ca0d783b0f46f61bd14fd3fd30768f233c59018ce911a94b495f58eb96438e416ca3c7eba5b1bca9dea5a770c1d2d9f2f62f821e5\nA = -78a6a6ef40e443c52036e75f0b35938d632bd45aebf45a1fff5c2e1b6f601a57382b9a82c3e8b2984e643eb1570cd83f3a6be6daac567ddf9f37bd96785662bc3cfee6f47503d239c77781a8df\nB = 4920f870cf9f371050e64a419ebe07ac92dd3525b41e8ecf6939a267e1ba853d54862dfc95dd21b3526eb0a0a7a7f8fb67df2e9472dbec81e15cb13266257177c5f2b92fced4cea5d\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 6b0b84505907a5ca37abeff9a5ba169975792c69b5751d9845c0f09dea833fb679c8dfbf3895bc470529e0cc736c9b4a0d08b75d709a1d04525ae583c5ba082d3bca1355055c7bb674aa1b92689cfdec4dbac84a96e81c855280e417f60e7e4931ef4f428420c0b85d2cd11c1030a47788d6ee6af0a76b5364fcf23b270e9d4f\nA = -143d843e3b12431fa0d873815a757a214cf731c298db61ab13cb87fe78b0a6184bd1fdcfec0c7661b10775b4ee2c815dede0ed497977c9ec5154f7b24a8a786501ddb8dd257bea51b9fd9401ff760\nB = -25d4da7b64f439987eacbde66abadf0da7c1653c1c1c6d9b2092351fbc714a20d2d7ad8093209da371150b69b3602480595533ecc1f3c5005a8ead10732272246d8cdfbab87c49e65223\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 6bce40524278ce242b0b5292d27751a3dc414f962d9c1cacb45fa3ee693ac6890d2ff1647abe578c40ea8d4b326a2e0e2fa7cdec28fe2da089338b5fed91c4277cc5be37537eec2f17edbf48a45fbe38f15c58c3e733d408d001262dbd40c9d246c323e7978df4fb7207aa9270a12921743cee2a483e7e71b221b09a6b2c667a\nA = 402671b0cfe14655bc650bd35dd0c36ce7f65de274a0cc4b708c6f6c3e84c2125ab2430e702421904950b29aa8a03b049910305127890457cd0cc97a3e05df67f29d28b0452969986959df02f59d207\nB = 1648c29205f19fe4c646eb62e8ae9b65260c2cb8424a526423c6bc04ed55870cefef9b8ba808f8ed2e1ab170e2e411f68b934abb1a22776969f79f9420f8bcbef28417582942e26646af60a\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 40db38dcdc201648da555f1062bbbb92c632c29b66902eabf90d98dec69ab3f3b28e60cad1571e7246f4c9e6aa62ad26a6d0bc08598c7a8571fa830cae4c2875c5c95a59f3295f998681edba7749b7e38cbece8887a7823b4752165e1a897e638836d408f439f009d0fb6c196e83e83ca3289d2bd0f0eb36b721331e4f9f80fd\nA = 14361ace8ec5223bf0165b78913b77ef921b7089bb5e28891d120bd3db6513ddc90404a4e6cd027f9b51fbc02e80d376d59e1f2b043954199ef8218bf26cacdc5e749f668ad3b4ab35cd796f94c06307e6\nB = -851a39d8b0101fdb22ea9e367286e572dd132b8a77a6a14dd0e995131467aee898230f37dc6224e35bed2eaf459aae579181a161450bd7ebe6b62ea7154a8a0ab590ca4a6c2f05531c4e24650\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 4b085796665458b798f824d1c1a88c23ecca456fb88713b433228ca8735141a616633ccec4bc53ea4f6e0c74e4aab6fece2e4cc4c4efb479638cf54caf55d4addf75908076f5fb487ed00d540e5b984acb8f81cae3ef51db926a06382a288092b352793de721c23c371fd0ce7a789486b2e8b867d35f47b5daac2d339d22dbde\nA = -511565611538828ff7dbc45c273fe46f4f5105d41ccf5dd343b41e9dc579429e56a9cefc54657ef0422960d1375b72411a5cc93ffa323455e006e242580358d6cfb641f46b9c36fa777a613b17dd4a187454\nB = 4f22597947638b9a9e9b9b7c2a8d37f77259f1bb1c7db65003b6e1a1c807469c84c89a75b80bbe0324fc3aeefaedc6ad9c0d9e470dac9c30bc48f6abbbdce9547ad7624f0ce9ff3cb6be23e47bc7\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2b90a57349ea94ea818207fe15c164f9d3530c7cdffcae178557274552f79c4ab56acd78033a570bd6c3e45789704ef0b0ef586594fe4cae3ccfbf9ceef46e769589b084adcee3ef8345375b7103232465b991273df724964248737d5eccbac558e35e4190112571d3e7c291baa7aa8b1800121bd573b8419f627c0091e1bba8\nA = -170cc62ad57094d307ce1b317ae5e825c2f2e317ad6060437afa105501caea00dc9a86af8729e2f3c3a854387dc3ba368c0a84aab1a527ab34fe27b0a69bc71c728cca87be728457c65eea7d7538ef3aa282615\nB = -3d9da1377a88f647de57ade46dc7caf71b4f42bbfaa5e77f16cfcc90f00b5d3e9e9d82355104c7cd0db4c1dac0496be3aa35706cfc0a30a1329755faa439694e8e9b41fba8f1ebb46140818c7008e27\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 4cd4da762c7576d582572d3427abc4b4297f740705fc14a32b46347541b152d0d1e3a11f27213badcea1e2009e34a63350c7a59e4d43654b28298d2757d6b54c4d82f580e98de4230cd119ba350416452cd4b8adff29b9f35ae0c533f666cfed716838e2b91941dfbea8d6a978a369d5f27554ef411f15e5a89850655d7f3f5a\nA = 4f4a28af27b926d8ac347503d6ac0bfec388a6c0b38a577501c3ca4aa709c69601824ddeb5eba4d9e437a97f3e4477e1487d5ce7b4a35b90fb863657a5b2d901bb8c3c838db40b89b495ee9875e8eee607d7b8013\nB = 13ca192603bc8b2da29dae67159e4f8d32f351a503434ed9e4e24f74abb5908ef7da80781c71b1a5ce64fefd13a16cc1eab05a370bfba2a97e6cf90cfe98d3a487ba72dde0762c36c10e1da175f1c1b5fc\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 3812e9e835ae355fdf328b29ed8b86dc3f6895e379b8b5d65a5de41eab5fb20ad3e2290c8ca69f9500248ff883d9715f59d0db6257d13c5cd612211bb1fb99867161daffc77968bdffc1fe48bcde0fcce02ca93975b3cd9e93b56974ab4beb59582c3d0ef2a65957f701549f8bf858de0c5bc98af3e5722f1450de391876a2d9\nA = 14ca6101af00d67139b985ac9f149accc260336237dd2dee802b5cc6e506e217b74c1a007ec10c20012f071ddad34e7407012669109ec1f385566ff04cf1a1ab7562353c0af1ba1be0baaef920a188c60db27970f64d\nB = -94b683326e9de19e414f653aeb2cb4bd7b17e76a23de6a4d91c43d717a35e08f2155b444a9549dfd01a8aec4dc901ea9f629f16bafd2c84828b12d2f63dc154323eb2d54938895ec4c9efbcaaede274fd4ab\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 5ad7411cef0581b2e675d03b0ecb9969102a283eba5e779bdcbb7646d94e843083a07269c932d18b973b57abe54eaaad0aa76cf7b61f30505a263bc95aa063efb264ae829eb1d1d5f7d380a0b4db59839de9ae6230ba51901e71b3e3d59e8c34a79678e751c8b7ab139123bdb2f04d90a18ed81d2046ae86da1a73c8dae4fc4f\nA = -469f61cbff01f0e4124ba69a860ec6dbc75cd758dd8ac7cbfed97645b16488a329adee62d1a66e90ee4212569d56d58b61676262f49dcb68296bbe5d8e23853e3fefe8a304710cea568ca65c183531a992ec5b4d82e226\nB = 4a0d48e31cb8c24a3b2c9c95fd19edbe46823032ef4c97fe65d0a30d5c2cad7a4fbbe89e0ebc9940ed9f9ccb8ab18bac269759a9740a7985809d0f38259e680f0703febe7fa012d1ded47f0cace4a133f59a721\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2b2953981db406ebc544c39dfeb08a8b089064533221536c7fa2bf2a7a0d3a1192859b7dc0ea5036eeab5aa371e3e0070c3980433adb3e3a5202ff257bb546bcb9550423201a35501fd717ed4c0016eb3a675ed399340bac7f058a04e69c1774590fe747ffb9c27e78ba50fcee30ce533a1659fc49dc080a60f21357a6265d24\nA = -122621d97f42b65b060c84df3f0c0da097b5e240731b77a37bb9471e7e398b242db6f1b5e25062a9bed702860ccf6aaf386c1d6fcf60fc31b8c190d348",
+    "6949c5772b9e621b863a7cbf29449ddd68b7e0c21e669492e58e94a\nB = -33978406dd30ec2b192c416e422428683deac210017cac9e4355e8446d6969295b0fbaa8cabc92c1fc0068da70efa047f938a419bac160ed6f794a9f69f53a88648c9725610d5f309b652f5462bd3011cf68ea859b\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2104dfef151526e072c09a4a277eb981a035379de3b1a55a88cb060681706f26131c388f5572c5646826b119c85ed450207f32733487e3c4e1e9d701a65058c4b4ef0cd1db090495643038229ed177b54695ac32110619038f1c1cece14faa693d88476e3d70329b0084d0ba5d547bbaa5b59ba1ce1fad5aa2f1c11a75bc7c0\nA = 7b79e6f1330fefffaf8521089c3348593e40ab7e8d4da3d4346571b43b12740958336580afd13619be3dc2d42eefd9e30599405da3e32e7f3a5655ece8b77a367059668021aa092460de75e627526da08e6206b0f8f539ef40e\nB = 156e234931907c0c0970c1fe6bd4b24225ed94d5f5b1be4693c8e141e9a6032425b4a47b6eac6265afbeb9d796eb230efa707d5ac4a73808225181cf814b319142e9d175ac461c75e6d479bb6bea53954bb981062eb16\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2a392c5fc96c29df2f5ae9eaf76e7d981dc1e2f3b47b43a98eaf556a9465ae8727c622188123c64658053ec50c25e54ac5c6c8bc279b134d326e911f14c873357647866eccb4f9038ed0cef5082c2058ebd71e1619f7c8f8f2fb80871ebbca3fbfb7845bd855d307d2efd853f1bfd467fbe030862f165e53a9cfa633d0d3fa23\nA = 1e0430e7cf15173d00592037e83e717c90d7dab4f54a5b2f0f5772762fb5f56bc0b2a53ec1bc3b960afc35e7b043f9d85d0af6c29288486af3e186e52bae6300b58917647231b40a12648cc8c020a797683a9bd7ff34eb6d41b928\nB = -e08372fc766eba6e0ef55a9149d700b503e2e3f978c8a397912e2735d5bcff69c461561ac0822c44160c7c1bbf722df421b74beada57462ac54a9bdcdb42d6a27b86413036ed2282abf62800fb2518a32a4a135bc948053\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2608f68632ef14dc3979725c8cf1a0db10a1651f17d91247edfae9935b53f6364d233b030eb99871a87b7bd876ab2cfd5a643387a7af9d337e81770db04a14f4f8dbda2cff604838c9af9a31e8dccf9277d453176589ba33abf77855b9501e63370b2e6cd22831e1e70ff1815302c0a026c70042957d08e74dfaff940a91a7b9\nA = -5d3568858c05a15bc9777af949eb01d33dfdba58439fb3f7af2ba792efe8e78b16d7fbc2a303a4c4c4be7c9d43f57405e88be54d6ab55268a4739945ef582921d2877019659dadbc76e0939f4b2cfbc91e5356ba2ed531526ed5b9b3\nB = 47f81f65ea1af04f702757c02a175a299b23cd8ad551fdb67020c50cbb4110b5371dc5790b12484e9ce647eeb24c0220a5e62aaec3461a9dcdaf1a22814b6f22d66372cc5ee31944bef33469f905458c172ec7871d9dc9c301\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 5735109bd21d31b5f54e9221bbed78c54cf387e39c13d31557e8173e173f786b2d2f1acf3966c3bf4552fe9bc802d0868a5a7632404cb91609a7a45fe0fb83fea8d83b0319666c1b0ac520169c15be708343359447f2fd37960c1e96d32799ac9394e839b391f59dd347acfb79bcc4e34e76490880d163ac97ee69e3a0a6e68f\nA = -175011349a0a1ceba11756bd528f2bd631c106e709aab223032d08d52d7d6724e8c5b055b6f97b48261f4860eae297badc1214cdae9b2500a7a47b4b777dd7b8f1006757754ff1143b637d2a3adc555f38eafbd5478cde0b04e5f46d3f0\nB = -2aa7f75d6801b04ea9f690aa0c5448906595fd28b53775059c01efe54b463f1d87c9fb4b39cb038e770f99bb995a2118b86ff8d004bd964e958c2af82becf362fb0b927c671cc3bd7185990419d26a827a2d81bbc0126e1029556\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 3b4ad19b75e1301d19b57ba9b68e0666c28c7c5c99df1d5fbbe0685dc1d3489ff39c919222719c5d8b7ce2d7ff967730d776a02b36a86064ed66a02011bab82eb575390f85f0104715f6e4954a1bb28518450182a8ef58af35d00e2fe417f07ba25dd9c85e00c3451082becd22e3aa0c9bcedaa96e6423c7df6c375b4c799c65\nA = 58e1ce4a9b512eb0632b02cf1207936d6707b802140540fbcbbdd712e5ac1426b4f36e74a9a9ddc812e572855d4fe4fca8a0de6644226f5698fb46a5f2a479dfc8b588aa8e02ddb15acdc79ed3d17143e290f1317274f425b869df54a4807\nB = 14e341cbb5f5a7f3b4dd864172b82ceed2887fcf20aae7d0598b3d8afafd2f10c27bc7456c1488abb570be3df04f43d892dc6a8dbe7621f55bccb0ee3acb1ade989a510b4e0cbe29b6b93968f323f0016d87944c908824d249769f8b\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 7fe0bbbccad6032069b1a335b3f2dac16089051cd9321f903181fad23be6853e2d209958e8c48e008be94a62c6206b34b4e994ca08b8f24a2df0e6394ea65b3b7aadb3bc43d04dc9d35a77e673c4476dedefd4568b4ade5d16f9d89486f3d5ed0566b1eb428cb0b688f10fe3901037744f278385754fca481f937cb630f60308\nA = 1cc0e3ed58090db55063c9ba11401636f89262d6ec096d361f448496e05181c5f7f2604333f26d511c13534618e90637adc807d622097f7eabfc03266135cb626e1bad20997e72da71bf2b3f65a4973dc27d2a594b1fd96b7bf7ec14b9e4b983\nB = -87871b2058d33cb67d83b6a56ab27839c6a6c771bd94e55f200a1257f2c737e39c4a0403fa410ea64e8f442d300df1c19c2f03d07fb74d94f86d26814fca23d4cd2cd3718252cf0cd8a0e36726f6e68827a1dab6bbb1d23b884381c702\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 35d7ac5cbc7e6c262ffa41be168b02a3bde9e112c512d1f68421d705ea34461ce3e0dafde67f44d44cf31d91b38d4d5f2fbf8c6c6a44ec3ed0298dd58f3d45c04346c11e57229dc3d2cdfea02c802732d9a811d7be5e81094d72172cd04caaa3c9d55a951c09f454f42add6e89e2d8a98e124aac86379df377606e7af9bc6baa\nA = -4ee01518f6581c560a186fa05c6f4bc26809c4822cc74a0bb74d5a6b0a368aa9bd0108f26113443422b8c589084ad49f919a9e7821d99127bb210670e732b7cdf610e464e300a39d3dfa7c82f90cf00ce329bc6763d7b1d4224a020095112fefa7\nB = 72dc8973f7af7122a05c90df190bbf1e39abca908c197590dc7ac41fd0712f48f838ca62a72a177a293ee6b2afa7a10c21e7993347c3df4f161a5641ff62ba123999bf1eabef29ec0d33ed0919818f4b7c35b5f41e654759fc9abdc0f80e7\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 5d83a9b34631dd6c63c05a0c012adf97b4d0f20f61907e1c2145330211e9a7e38128517b058e0a85e993c385068d1cec768deb814bea1323dbd333de091ad2cad72431f20c1e70ff7e1b119768ba44e14292c38b88dae7e55ac9e10ff98e9bcd5f0ac05af499196b4be0c6222d1a63227ee895fa6a8221a4a182a1323183cd7f\nA = -17b3e0c9288be15fda58c8fd228216bc466731d631218a7ddf1d2c9cc858c0219cb0757d3b680bca1b1964eb15031b5b9d761a8bcbd160db89be339067a2ea35e1ac3cfed701912a17ef9ea03999d92e3592e893183ddc05cbb98a656983b54590c72\nB = -269f96a4634eb37cf8a6608408128587ba45958405a29827d0d03d34816fcb1a2297f1319485439d3e8594532545086efbe4d21d31d30e2daf09b74fa8cb27df54e8f9f993630cd9a292c977eee70887158bd3fa3cfef321ef900a0598ac8cea\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 7fc1c65eade94d9de7440eb8dfaecf1004905135efd4f98257c3295b1e76ccf1e2ab6808d158d360b7419c6210c50efe960610973d9ae855c72ec0e81d423e5863c80b542ad455700d2d0dee5fc403dc01eab460c24687401cf6a3179642e59f2a30268df95fa80dcdac230702352bbf6b60acb9ff5d45c5b09a3403b954d173\nA = 7906bd8d3bebb1303c1df1fea0b2503b0abe9c69b4f4f5bd01eec9e314788cb7d44b93428adbcef570477e8ecac2a64822e481bdf520fc381e1bb0b2cdae2fe94e484cef5236dd524e4dc364b72",
+    "f4c06d57f29dd3c5079e532b1ab1e71dd6a65b3362df\nB = 1479ef2807b9c23c094d0416f513894cc92e023b134f44a5333360dbbe98b8161ab899302f4fa11b470b97dca0c4e8ab7ae47e5fd0962834e6cc1763618193f4ee027f667368da580c623080de137b5869c3081128e6081b9d5e2dbafd791773242\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 730c04094b1ce944588e8291f7e6cf763c70b79cf362dc8a1bc63bb8790cd4cfe4eb51cf15a45a8464d69ddc3e1b9383cfbfd643f317108cd9ca6a6eaaea177c5c8b6747bbf40108cbc0437eb8f11bd2a0939da59b70c0c6129e2c249823897f2ee536b0427bc45035f121d2cbe7441c175899b97c490e6c3ca01539bcd05848\nA = 102cf23cc3b81785c73ac3613c816de47fd585c7d5f175185818dbb4bf0bd47d0dda9702bce97b29d66e48bfaae0fd07b47b40be2b48ed702ef21c54b10bb927f9d6b43604bec4f4b2796b44aa6b4e83f8bcd00f2fa3871dd901570e1a32888d8691454c40\nB = -cc5349a9c5280a933e87ca38ce458a711c71ffebb40bb1f7612b42b4684afc495e99c4a5f32eef1c9564c2b7612ea4cda7a0f5df6b3ec9026447dc565ca08563d46aec7ced9fc4cc5645960210d44cdc3944149051d569c9295dc50862f8f6d1f6cd1\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 1cfe1842a53d00e4619265e2fce7cb566ffbd912c9213925d01408a956af304eacb85e29fb6edb812a95e90769bf1c3d62b0cf6cd5bb8f8992391d2ad70f38a14fb9d1d1eb522aa7b7fd9f1b52790beebfc887193882377b7ce567d317d8432e1d9a908d6ccfe8d2de7de497d77b023b3959cc042ae30aefcc0229617fd2a146\nA = -5c3d24fdb193ed83f5f6a825c1716f98e3cde6b32e09659f253ca3fd2a39402b5bc3a6497ed7bc908838e93422559a13cf59156254bd3fe1e3b8600b2a777943cdb39b9d42c58043f1d587424425d3ef5f5538ea157112970ce3e09a87fbb5f7c96f1b5e65fa\nB = 675d9d2a05288b438ddcb330acbd59e4639375f3f14ac2d0e9e8b72de6ffc1d217ce62f997577f7eaddbe4603541b132cd41f2f2740363d9c331ef22df92029d143fc8495ed0152b918aed7ff22f564c7cd94fd3fe4178c90365ace43def8fe30ab05c0e\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 83ed1948276d689bb7fde814e67fcea72c4e3509c48873c3e7349a8fa1c08ae11ea4d814d8deb1021eb8b8ceec342cba5002a2ca45d5f340ae1aa500af4c7db120d0402c6cc8a840404be7221bbc46ffa10236043e5ce4415d3ef1355bde26d2d26eb7127326d4b8d671bb96a08e38a2c1dcc281830ac77202903a5e4777ff02\nA = -1be86e7c87827922d2e8a06e3cd6b64ac9a280c525749bcdbfac4856916321a964c9346d17465378251e6eada42dadf38bc9d7d87367bec94ebdc21af6b1302e520db08a64ba6b39920683725ef02b011a3e4ba46ef0eefadb98582cb911d0cbeae9c231b5e432c\nB = -352059faf97b433089a688c702b97adefd0c91d51a0395647f822c6762fee3287693e302fc5a5584a12c048dea1a320cb96fa70b5daff7c2ea21d249467d14c6bbee15a1e94c030e908342a939fbe8ae0de58cb6d6eae7758485e392ff6d5d64465b701692c\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 402525e19b6b68942253d1a51fd9b2ca36fc84cf938d80b3d52fd4302de142b9d93d1663e89340fff10c2b5efc8cd47fc3b5cc5ccd49a6ea3038ead6454bf190b7f88f52c56bcf00c6ad5b0f5dfb7615915ee8af137dd99cd3d21172ab772f36d291a6856a8e7912750139c09aa024b930a0a6b9eccc83c2c5c0ee2473ea32c\nA = 65e5db532ecae639bd56dd63045bca39b33b4d70b2db82ca3d0ee8ca436e671828cde80217b48eae7487fe110830589ab1be889f1e1463f3b0757d529b2f0cdd2ac92c35e8ec141885bbefb6040a3b5e00e64a541913a38fe05824a929f8c5a2c46568c61989c3ca7\nB = 1d9c73eef8373cbb1e8393feb26d55c33a245c33d7031c234abffb2f06a1601f7f3a79ef1e8664c51ce5dba5f5aaf3b9a9e42470d381219b4616ae93c7f6e64792d23bae523b6a224c1f714ebc82a11f9be42618922b8d2eb7b55e4d45572e68a19fb0ba72228b\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 7a9cdb5dcdfb6e04351057d731fddb9e85f41eb432f01c0d980673d294d05ba9b0180133a89930e74cfce78ed54991b494a19e7f80f310b85904784cebc5639bbc631e80751807868e7fe16719e8ffcd1f2cbd1b9f303c3ed488b647670be3080668b5fa0e53b6342c33c87f0ca1efe1ddb1c877bfe2556aeb61805b06f41343\nA = 1e412c3d66aea2c503f3aa5dbad368a61d969a2951c0094f9da32d2794e47f3bf4c481ae23636baabdebdcf0753d431426b1865e62de8eae7238a9245d62820ad7f17b5380d701f5db776cd4e1ddbdfd542901731ffcea5bcdc247fa9c83f7e08a9389e5a76d38be21bd\nB = -afd61df72361260484fade8b432713eb740df83a401d73492883a5139c918d5c911ff5dc00140637da1c6acfbab4b0bc8fc1f337243d90beeb1c2a083ad8069494c73a99372bd38712a5b5393c779ec1915e878600e0b48157bea44ca8e97c6099c4ab07fbda57d1\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 712580a1ffde78c8cf98ba71843c8130e835fee3afbb45e372d04c04cc388e403c9efac742611d7974bbae982c3aadfd1893f5da280afe0c1db1d81a9ed73b6ed9b7f05a20ce828316103259112d7754560d66733041e9470ae0d4dc95fd0484bfd56d66739f38ead7efa4051187ea41f7bea8fe5d958a29af41328246e2bc35\nA = -47c5755ca61ca8b7ea927f6fbe347f1362915548ab38c40f0418f4c9ba4ad520c3b2469d9ba3976669dec0b278461bae80eda53e9d11447512963e797f45460f74678acdd69fb9efe3897913b6568f8e03a6d90b4cb5bfb06af132bf118574b70e6bd2f6d6cb4d0089379d\nB = 5bda68c0a64218d3609d75eb4832d5468298f19498507d7d515f4c410f04dee535947571a5e75f1af7f94a5b3b05fb742fde23e7cf3f8b3dbee0a569e5a36d7a3d31a26c4a48a299044fd72339d2cee1a68966c851e76b93ae34130b75f4abe4f2260207d2254d23f56\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 4a1a514aa4d1ada84fa841d0b668930c904783fac521377a7d622201867d773ad23dbb667e0d4181616358f3cb088cd157c8e72bcd03db64647b37aa1813f870cbb0318ae0a3667f8e6c19f6e0706217646ce633f0cc8bf4e8f0f4d7329a8647252ca6d376416d545e73cb9a3cba40f8f9465d85d57c2481b84b6d95dd42d50a\nA = -1d68bddd8c3e6b78daa0acfc63a6f39e97f19527a43f6cdec47568d57b47f4e4b7ee88e4a28d683b569e406ecd2510351dba25f10b9f7c82d6da16d848bb970cedf7675e67937921bd334eec4bc8fde83d67aca57eec804ce22bb342167602fbff452d5f0f2a7f38b576e1e50\nB = -34d219765916a4c8ec843ebee9a7aa1162974d41cb4d6b60532513608452da9993749455d9701af6b7b6c7454d7f2fd5c344cc938baa5259301d4b56ae8d25b6f6510ae6bca114cae6791fa5a9551e8a405f5b1c0bbfc27138563b2d64f9a4d7a8f42a23bfacc3f1ec9393\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 3fe24e66e381eca525b24cf767215837019f44ed4fac6ab118d02cdbd658066505ee5b0feb7af51859992ecb97d727121e38873f748a61d70201cc43228a7732156a80dbe399e05764be19e37dc1b93222bcdcbc45b1a4817460f7021dcf1d70e632bc6a306628790201222bb522f4cc80adcc907463a539b02f74004d42adff\nA = 773454a43f495959dd55b8a064d70b1b1ffe45c084f5f9553582e24fb402b564de68e5379a8d9d02af101594e717a6c6db2e7173e557a64d2f28fd45c4e06041deda040705d99acacf8086830af19c7ab5e27f91738ffbd937dc27e5b7869bb6caa12c2d7930366ff75eadc570a\nB = 13d884a2396268f1a8186748a15722156a172a56dd3d8c77b9cb7001b6ee06720653507eba9bb9918f2f699cb37f3b5ae514f5180108a704647f19b0fc075826153edda66dc1105c1008ea8ec6f8c10057f8e8e479e1a1274edfed9ef719b30827a30f26da78820c3696d01aa\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 715bab8708e53f76d2ef2afbb",
+    "845bdaaf978b54ce25f84dbbf9074f16d30a18733a02a4ba5d7b092fa6c25d3b9b0d8243c743910f1b7b785d9cb02343fc6d59eb0817bcff05646030ce4fbb2b9ff76781cb1af66b46553d365d02c61e677ae97defe92d057d4378dadf8cba9824b0022c086e0d78b5442bf3d3263ba22c643f7\nA = 168186208c734383d472374fbedc2d5d430e85690a4881b740008623120a4f7f83b2cdf85dc28bfaae5870abcd7ff1bc782ef11c78a75c99d41f8aacb52fceeb5f10266dc65eb00b0868937340146d8850887686d54218badb97647a6d82c0c6650ca1f9078d73fc6222aab95c2967\nB = -9711e5b3965654bd9427f79c89a0b3f3cdec1c857f4451eec236c1f221bb6773e5dcc30e7381a18a813ac2b03ff4a4ba679aad41e0e5d7181d4627f682ca2dc8af9a8b4f878771446fb225a979ef9c7e641cac819c307c8dc50d9c1ebadf912ec7c844e416f95b546cf09391f9f\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2714b99dcde70d6c3be8b671d78abc155793f13105fd4b7c5d760a4c68ae89987311dabf2a9238d18299f983b8aca69a9ce398fdf2c9775d90b11b3dba17bcd8edf661efb6e9c50b4e37553cbecb54eb214fed1d0847287732810e550a4c86b51d4e5da1cb7722ce4317e69644620ad806d6d1c94e1e3fb4d87de6178a997453\nA = -75231ed37f1dfa4487c9fc79a6f7b36929fdca086e42ed41f79430b2dff521919236fe415ccce590e1d3b986e16dda866f3f0d29ac1adcf55d87fa5cb67dbf4693293188516e360bac513303769c42181483fbef7abcbc4fea1310c916396d29f37d9058a62aead94511aded7c4b8de8\nB = 5aadfe65df0e5b877fe45d42d7ca02882cb6c686d486374da5ece6f87771675153c84d74b6f40df1db567b7e1e3c60c41d21816f958f5576fd2ce2f84a8c3be4749dfc7e5561266b7c9698c7581292d0d813cb77955458d63bf94ce87472924c4ca79504d1ae9d5f025c7a2504156f\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 6613b1c8ccac0cb8fe2f59e76fef4dd05acf1f1b2bfc20aa3f193622ce3e9d4c7824ad544477553bc68f05f0b546e7c1ee87301e111af7929d1f40525291b88e211db7175f4e5c0953141914fcb4fb951dbf77442e7cb28fde495704f1b5141de1e50fbd0e359d0d86ad709c8f564c84dac81c7602717c269219ab1cf12e809c\nA = -1bc03897b02d1edb633e2c019e40c20c1d89a210b0733412aab675563fae8bd75dd7e65988cd8df4d9b343586e27f548becdde274f62dd421679554ed9eb127e527a69d69fa8b17aac0424dfa2a7692d1e63617ea45564b55f01a70325bca050862d583cdad96c4a2e123d0ed827348a745\nB = -3d5239dbe7bb3dcfd8027204eccf5e9444e68d322a0b0c535a203a1d0c054e7dc1e588bacb891388241462a5d2b43e6cce34ce46a23e6ef29670603d31001374dfa347dfcc794988e58945d0d2d17da6565cfea559203dec119fc357d396f65b296deb07686b0ad2d25a13fd4fad88d2c\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 3a7fc5680aae875b9241200b9f4112a82cd624ffd9044138ae3cd65200631ee9d7b918fbffadcad7e598791a9f0bef3e23005d6bc0048ba92461283492df3bce74c66e417b082ee052fd8f808d71f3ab18f9ffc40f8fb51ebbb936d09c26a3514bf868141f7cf238c1abb3d88e5d50dfc188902254f07d63fb8cb611ef8e4149\nA = 4a30f32d467b29dc83b40bca2fc4ccee5f08a64069cb87f20e63387b2219b12aa312400c4ca59608f50a71d2535cde40a6d248290793fe01693ca40b93a5cded2dcfbc9aeb36e187c9d650782d12bea917daadbc6525f266e074037803e4b2f300778ca8dcb304658cdb502c93c94a16c6261\nB = 1ca5e5218dade077fecb81d579e1c9290431b34df5ec84aefaaf233d68f17dcf60ee010db26320685af13a821b6daa9d73d8f3a30826c3ae7b2bc5e219cadcff826283cd7dddd04cea7a5e0585d6e7c9f23b27f14ff815fe53bcd75fe700b1b91671bddaba737fb43bfecd2a77e5b752a206\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 768d312175ce7d2601f30bb38339f046e4c2ba5c19ae5f7ca5a562cc2462c579fce9985e9e8afe2578db542c8d9e7693e0c74ba161334b249ce720d568e9c18f09c87cd701e6f2080b752362f2fe6252a1d0caaaf1fa18199776e4c6078d89d520b9c63db159d5fba7e0838811e68794b1413c248f3f7173ef29eff28f15b656\nA = 149353e91bdb70cdca8f06648388508511a64d05221305cad7187ea40d9ccef91fe17ceb1e79667bf66e8e6b7a57faa90a83bad119c02984a8f860bc1f23ffd33d4ad84896610301cd2e8e80a5ca7e8d3ee63e7dfa459793c9dbaef3569eb4f8a021c6a3d032a9c94d3f6b8278274d0088a98228\nB = -a7cbbb6a434e4b022d312ecd4a45fc7fc4d3aaca038cca0fc56e529fe7119ccdddc8e76d51a2fb862ad3d27a16ec8a51e5f66b9c7fdfbddcd05a0ddea14172339cee340c8c651eb653c6aab6551c99ae94f26116e15dc62f2c2e63305bbf84590fba1327ee721150d46464d7e22d45d53ffd44\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 763912f4b16549e6ccd60eaf7a0a1f64d9c3bc83e4a9b87e209a3959ba3cf609cf47183bc543f08e346b6e12b8bdd5d1c07c603f74b286ad432d58d7001299ec7a4dcdb56ca875dfc7ee5c75bcfe2aaba14959bf3facaebf8df92bc12937cfd4a4865b3dd74b243ff62ba256d110b01b4089730cf48efdc66fe272f9241014e\nA = -4df3899b40d51c83dacb442fb143835bcdb550136921df78800f0515a6cee77fe3236dadd2a0800b79ebdaaf8cf4aba5ebb60cdff3e4b4531ecd0903c1674a4559339123e9f09158080fc53c4c6ae72c961c8da2f357b7c05368157b4956e592c41b25642457651abfecb4fed5d9fc1fc3825b772d\nB = 450eff382e73f2f38bc3a4abecd5f8de478f80a6b99fb6252173c90d7099629afe859442bb1f796855ee9a2940f21d1f9dc44f462edd74b479e1f2926ff6faefeb55adbc6152b5c97967b1dc8c44dfb85b5e02e870d2920b75422c8a427e99e35e2a4be92cb0ddc04cb7f4044f716be97b36f045a\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 56ef57d56c6d1b94cf0fcdedd3611a8ee444c2e25522b9ad175587619598da341916b183be03b1e73be300f9969120d8f3a23750cd8c4ffdb87124a2139e8ff2c15d8dc944bc3c3a066aa16dbe6dba4a74925e16acdb2b2e83cd7fd5cedade6a7f7409a509c00dadc182b2860609cc9a375cb8bbdcc350bcb2c0df9b3bff882e\nA = -143caf995b7783b1316b5551978727f06512fe114b419c735b3381ec351275fb7fbd6ca88b848c3e8c9faedebd6d084cb8a231636f68f6803d14bafd90534609d4a4ac0fb953417be7fee4e4cfefa452c5ee5d1e1b97ee75f83cca8691a0efeaa8bcc1f1e0f18c0c5d6c7684c9da6c9495d31a32f40a5\nB = -3025fa05c55826c40089b12741b7d406f748cabf692bb0227519a124653160142633700e3c0676000943556f97551171d231c1a35f7b7d8f96b0366eb74942466ceb4660f09aecb2fb2ac050ef699eb05bd8834a2ba959ac71550b5c026b9093c8cbbb7c5fb9390a7818db682b7c11e58996c9d0add5\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 42f363c34c20c443c1ea7a1c54f98c6977b6671164a80308000533b2404a7f280adb1f3b98101cba25249131288f7ac68b0ae2572c7777e7381c1f4d05fd82188c4b1ed5636652e0bfca4d096bbf4189a9358b79f6b6333b99e5c4b7a940c2f7d1413bf9f47a2ef66b620b5e220b2c3dd7267452eb1b9d8d9cfb17bbfcdb6abb\nA = 499d05de867bda3118a8cb82b80ac91fc505e0fbc6c7dac5fb61713cb6e715f56a31ae8af4b400461d7ad1687a2631faecd90d7829f67d1b9e36ed7d55704b3f2aea65eac061172d698384daea710ed92cf1140cd4da427174bebd173c2ff1675b2407a84649b0a318602f33105006fe4d5ed8d0e015b99\nB = 17a426a12a0175bb46bf7a7e727eb5238af383cee6f4d5e2bd82b0d29b9fed35f3d8ec95cfdfcac49bee47b25d3b5f375a3340fa83f8dd9330a593a974d208debb7e567e59dbb7251b54e42dab2cd50fc63aab050a41bd88282373f8195c94c35f61bb48aa921f574cb4ff0984ccedc070efea8c46e5cf8\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2f03374e9596cb56cbbd89794090ca7a4b437f4c05fa38a09db60e5ca900b208fb85b52f71c29fd35e62c9f9529d7ffe46fcc54607ccb07f6f8e13fdd4ff1185033ba4fcefb1ed4bfc42c3ea9f05276767d8dc9b7b4aea4c8bc0ce84951d1f590cec0751f73667db19060e2bff64da30fc048a",
+    "1f5700fe3f489920675cc3540a\nA = 1073531f678877ba854fd1e7f857659614c526847ffbe8ed131dc9f2ccf69e1f1e917bb44a7b905f7ff758f61c06dd59ee09567d9f0df2550fcb98b776ed1381ce052988aa08fc5153e31c621c6a51ca61b386e3a9163a5cd69608b3e200476a8ada35d906c41d044bafe71ef5c6f732935f15b53bf36f7ef8\nB = -de3563925474e5408e245184b57f328e265b6cb62eedcaba809d8f257eccc0a457eeb82c451f93af93ce9f36dd1aab386e7c02b356f31c2d170169dbe15e70cf5bb9073b35fe0e7c7fd7faa91c5b2b0740734f12eb741a9d9ac6dcf7cff59f6e16324ea39e1e07dc5b9daea27ac674dfe5d0a5790abaebde9\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 1aa22f9013bc1cdebbdfecedf710c1bcaa41c696a3d7dfc1c8c601fcfcc1c85c8cc24be7df2cf3c7311b3b17a4ef2dbce545dc467d2a92d371e02a196a9977cb9042b236acf99d8c0d34a1c4dd8792d3497cffbc87c397ccee5d01fc2c89ef051324a7061e423720d0a3821a36739797393bdf7a45b5fc600824a17043312bc\nA = -4fb2e3fde2a0c653104c077cc6459c9234f86cc2d7b317329b68289826d3e2b975f1a69bed1a53418a0dd86e1b2723f4c4c5a29d003161e667c2315ec24a36f8bb5f2eb0a94f261e791bb829db685cd0ec9e1e301dc140ea57cac1da228124ae029e2b8ab1fa3ab99c55a9ca94dc7b767162c0a24af851fbb984\nB = 63702537a07971e399aa9a1a0795db052d6c8185c79107216babe11d6d8d472b61e604cecf9eaa6d44a2fcdd1ef0b6b52226ea0c6902d929b09e16576e6d1a6921765b2134c5d23c69ed61f36ea9a5552e5819350366240693558fac7a9d09ecd3702076c8c758a4bf6843fa843dfd688bef3f73515db31bfc26\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 6acb23ea695d4b60cce53079390da3cb3a4bc3a6486c238c421f3bf6c93c027a0475f656c3e5435f0211e90458ae81772aa956ef284093020f7b58ccd9373f3fdd39fdf4adb8dd64590f4a7fc05238ba20017bdad07f5f9a6f076b71554a7741bdd8c98ec68f8fee88396cb1f47c64d6da4c228caa3dfc7a9a1c032a9ba4fedc\nA = -1b2496ef929bc673042996ae80f27c6bbd33fa7c20580240ef8fba985d1a6117d6e746989924e34f281e7d2509175d0773dd999bde16662e88fcef52978d19cc45fbae3997fa580a66171d398f4f0e7605d9f4aa4f728902cb886e6b6dc9f0161e7cf1ebac05a09c5a1bd69a92273280758173fd2c14550ec221275\nB = -28399206ae2820d26a5aa0bddc4903776611d08fc4cb34a22a8bdc2a19e9f8cdab94217f346a8070a4145f989e1dfb49cfd100267635af0e062872cc879c534ff138fca603b5d45a6860ea85b6de37cfca000c81fcda3d14ffe81da919b2a25214209b085bab9cb511889665fc845acbcd038711533da171d8308aa\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = c012c4d17ea4c95a360218adfc3363f6d89f5aa524aec70049ef94c2c05e59a66ce01e25588e164bf2412f9517b7740de53d037e71ec3a1d426f05b18b128c41a878da75421e8c8ef3ebd5effd40735c00818eeb1ec63182b44e817403c9f1f6c1a0155334be63a3a15109be6d45ac0d1b1ef5cc99e9b284b00c487d91e5472\nA = 796fba6276fb7129eef2d1572b305f63d7b8c49371cfb3b2c67b141071e66ccdb5e321fa2c1bcf624c77317e2aa135e1137dfa46a34c3ffefa2fa3e316be81f45614d422bf86fe4518c2fdb7e416bec199de033cb5fef7f193a80c0f0e6ee924a12c8f705f5ed3793ab770914924b45cf2578bdd09c701169f0a881e6\nB = 12cf934763127284e642ddc232b1c889cd86617307b6ad72a9fe0d48befd7c5c5370a0062dfbde2add256dc0af850813b22320ceeaeed347eb9319bf22320b2fcadeb51c4bb26a160f7459fc172c27a91d367d5a232d00cf7bb778fba83afb744177bf1ddf45446baa035fcd0065f9b493d92eda37e9138f4fecf3ec55\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 3de123bbd50c35805b943e76e97b7e664eb9feb99860750bf97e275029e836217375cc1910c13269ffbd0bd72bb82ca445ccc4b693742a96d19d3dc23f78e5ccbba46d9ff5975f239551c36403ad5fe86997536456c4a5ce54807c24e3b5317b1c7b2a1661aad85b63859d427f0703b460cf72b9acd3f87e2e69d7f8f15e972d\nA = 1d0433d84f1de082d2058475e0168ceb369013a67aa9417f066c29c28272a0b3f8be5ac7190ab78591ae72a1dc8ce628c683281a9ad563e134387b9258b9c96d2df288fc118a8cff068ee49d635343772c2fcc252facdfc93112358414e1734d6948b909b53e46263e9a0cbffa141ef77bc98e7fae8ae2bd85bd875aa7c1\nB = -a31a574d105305e47f4fc00ccea0cdf854556886b524901c22e6f3b59a42915932ab209a8d5da29ab70d1472dd5378d9c79a7447d17665f9d1f1edc1e545e417cb65415cb8a368075c16264f42555d26e83adc704b5c126c6129318a8f394af8bdbb32c8114470d11b2acfe806acdc7b96e1e348a32ff96a988de76d4623\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 770f0c3104c0f3395fabeb75ddfa2c21a111d23438463941239f7c63e4b6e6832b84508ebf3cde1d90cff0a2801beee05cd5118f9a726a987eb58def6780be899b473ea71c697557ff63a4c6db894e9438595acdd98abfb529d75bdf3c1d619d6165a9edb6aaab8ada50b61a3a84de654706a9aedb7321b0523558e8f18116fd\nA = -5fafbd498d610e9f29c38a5c6c262b71672fe9e9c84f0f071b549390353e4fd0101a059b7c547007e27df97761767302458f1936395142ce5776b0959fc5ea039429d64ac5d50c2ae0ee45d60c0c50b7ceb4ff9853d57c6e883f588017ffcaddf5a1aa3e23ab068877a114d9a2cf742f01f5f5d611424c8ec0d082f5c165b1\nB = 552155ef110c126afcb87dd20251220c7a43bd0215ecd22249a21c93583e120ba6f046c6fe03086ef3c97311c4d520110a450470a473d8633e3560d2cb44c25559af07516aff50d6d176e8782c06cd9aadd3354cc695c4ea8dbf85e01dad479c8e8438154351fd5fcc6fc7e9d2162ce2f0179247f756f0b9b34b54be74821c5\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2e9ed66317734668c4c354d720a011fc65bb67439b2ac9203dca65a8f567682be40cbad4f55a83e836f1fc135596b624e4327acb085a61b6398237fef5a6e6560b488d4a673b5ae7d734b896d9647d71087621cc81e94d58e01fc2cc2dc775f9ab1b6031840a672fb715b77bd636e3d87b4949ec7bd60721bec8f9907b7c072f\nA = -1a6b046d691830d33eecf2c53953676ed3f6fdd20c2252f6e915052ec28ad1fbf7a5f264acf87ef8ecd515ed921ce6b85017f3d8a8f1d14f269f31e3307c6f935ad468cf012a912b0650a15106fb949cbae7b36c9cd496538bb0646a7a28989dfadc719424519bfa43cd8833d3a748c758f813881d83c98f7cb2a63c2a4d06b8e\nB = -34f87db0f839af6e4c4bf146789db36b3d0bcebb9bad81db690ccc3a35070d8830c9745b2fe730a1f3a252612e7026bf9889169b57b8984a5479cc4cdd6844ee3e150a2e7bf7680eebbef30e0591c895cc8b2ca488d489554f2339e2f55598717ddd8ce444a060cc95cad9eb478491ee8d3b8358c3762a970224abdc1068af0bde\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 6455ff7c12bf3bc37120fe3f1302a9916a6ffdae6ee6a37fc23ca2f3a7ad910dc0e1027d4dc304a8eb4eccbcf3c87cf52a13dde472c07e2df2420c1d36bdd5e88c3d76e774ccd2ecaf6a0ef55b8c60231b1348a738f812a4fd9d0c158fd5a9fb19cc7cf9f000860d4cb6509271c8e43ae4193843324db02a029beb58ec2955ad\nA = 54ec203e2ababdb0348135c0679eca2a8e778ed46e53f195331a48d3828e5e40da804ecf95eed819ecefaeb9c5377cc1afb1fb220175990d347981353e7d90637adf8cbb16812af8a3783dd312d967a490f8efe3f23746929cf2a5a8df58e0b878367f6c5e4d3c086f947fc2bf70bfc3a0008a8bb1d7d83f002930640b6ed94c334\nB = 1311b88a05224e15f1465c8da26784dbaeae84f818e029301ea39a982f714c64312f9f02d094c401abb6a89e8537d64c178637364bd261f4a27beeaaa901cc7b3d4e36ebcd9453cda33d47a53c6dd1d121dfb83a222cfd16158eac23482c8abbfaca59e765f6c1fe871d884d281793eb19f6409dd6bbe4083bf762ef24c24f0127613\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 64104f6c06e563ec66de4442d35d88117f2535edf9e012897f44daab5a1b8a8696f84db7a68d64ae24a394debb993bf6734c",
+    "9df542c7e473b2e497396ce39a064789d5d7b339b65766b002a18096e7fb9f312ea5997c2a85463fbd6fc18f25769ac2a2123ccb0e72f14b0608c4c22add72bda138b83f986e78d5c9da31b15b9d\nA = 145f580c2ebc6c0354ebdfdbb1d3d7fa17f0b55493b0b9a11b71001c840a967dc77f0206c3dde161b5a773a6b5fd9471fa08b205cb6f728e3afba440b55268d6a9542e234ec313d53583c580a391d8da5943f4a900b279ec9d8933f2cfbb260b74ab714a8b9a1af3190d914b6e42212df84f933a237728a5fd5473ce2e272eb82bc83e\nB = -c67f9b9295dd5844307b8fe3cb9c1875257258e4be6229ab097e148c0175ecd0de4d84fe03c8da6e27153c709c2526092b1abc73b5fb40f1d4da9e0f3d8d2fd5f8a4e6f3c30befd80e189b73fbd77e8547b34010d2aa57072db0f00537cf3ced95eb517b23e0c854b4becce128a575a31037c3a9e106a476d8b0277d26dcee435cebedc\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 11913c40d577f70a5346ff1cfdca492ff52b640eaf257510d311872c8df7ba9756973da5b9206c6e5254bcbbb4bcfdad5fc4594e41ee44e77f168e2d20a4b228480a9908b102dafddd039ba7f7619eed7057e8af3a72ee491a61dd049bd947e5b09a94ef94d5f336945f47104fddb8493ef22fb648ff5376b68e96c0555d74ca\nA = -5537630b7cfb8daf76d14e617f7b69f7b75b472801a9a818179d83ef2984d0abc8ea4214ed3d3d2bd785060e9c2819e861d0df760fc1daca8340e8a2c997c9ad201d6d2f12a82ae3883cf9f5c51ff1c25277c28175859a7b8e5b6cdec7cb3875071cbe415bb698b85cb19f617162587516f93c728ba8b2cfc19f238e2cfda115b8ec0431\nB = 597296cb27080f33a24241c1e98fdec32f7a4013a7340d367e4cf2a521cd462a2803109c27fcec353a30dd20053a1f744394fed75829e8396f8de434399bafd6cdb6e0ee81343f0cb99ef3087a7c69bd43bd722745a46cdff0c2c837fd87543c3c63df3896ac101a145b478dc224644996fc72460a89beb5741b91a42f2fbaf0d62c099b32\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 42f420adf5c6b32ce53fe23af4e392517e37013b8c3a7d035a93f6ff45142b0b0bd5525cde85f9b7bd9ce219bd3514617e89ef4d9279cb9a3e89e44f1994d72febd23ffbdb0a4f19cb76448199b31c5cc6d7ec1e46fdb67be1211c0ccd93c123d56ac0d9cd2ad11f0c58c713165003495b75b60665047ef80f6a393474cb727f\nA = -1c6ac9565d1950ae6c55025f76e0a040eed0462218e97aea87208ba879acedf413ffd5e63a92dd8658cf5f49d633ce7b126091a55701168ee4932db004dfe8c35c939887fae3a892b0b04d8eb74191bf8fdcf5566b4d3796a5d2596b1e750f64201057ae60aa705edd58aba4b48f6a2e511bf5007a6c44a27e3efd5bf2708f7046c1fff7864\nB = -244f2a90a57e5d066fe22f4d52f91b44882b8ef76d1dafc3387abcb224eda4a2100239e729bbc745237f8129d457e98eafb2ede2f3afb81e63520493da2a5730f1170b31fcac21259e90c894f8bc488c5e5dab2c2635bc7b1ff56c3685607f6fead73a09f83a7a168c4245729ce5b06e482d7d3d72eff33d14cfe2f32f72175484ffa292a9af6\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2239459025b257fd0b6659f54b8874f93f07f4d6240f8ad761c9da288cf1537d8bd001eced284bddf78edd611c7f28f1393c6fb879aab6e7df8eefd347d63628b1ae086148f488b01272f67ca19db71a2b284eb17e17aaf1e3e8f23ea253595de474d5cf47c16aecfae360eab7855868b8af361491f6ad96f893f9d3eb66d07d\nA = 558613de283911aea1ee21d6b926f531f778c5226e978ce329860682b5375fe5e5328ae27b00f504f2a2d24470d16c1edcb8e76b4d1a740e55538e79ac7da4b45c5299993513ec3bba7e7395dc829a00d4e228618dd348fbf838eaf0bd50f6c70253fb1c1c734a07d0813915be25d3163df13511f3675022cb85af7646c14ba5d13f615ded8e5\nB = 1f3c3c468146c29408d9207e15b25186d3b06b3fbf9556eff7ed7ef7788032d87ae1a4d2a0983902d4c70936c615d8c9ee26c89af8b58d60231ede54e859763237d5ac59af686300a3e92f456484ce77700557ddc0f93bb40e5d2e5117f2356ac7ffca26dcafb3ce7a5573e07ee97515b6b082fe75fcc9dccd76b4fd416e69a247fab2b30965d9be\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 7650985e7c6e5461268867dfa9782cd8154bd6a4bb5857d6555e9d9746ee79b37e44638940bf8d5e974911327f0e53bbcfda0739056bae2248015c35839f35e7e359e93d3a339e7af38c0cb43eac5b41e1406e34cdd4afd458a5d126f70b5d683415b490e0ad61269ffe7ea8972eda6addd447d97e60891e5099ee920e18f233\nA = 184845d3762ad1a9c925c51fabc7b9e15570a84a06ecef994910845d56869264273d75fbb84a31c97c27eb9779e8b39f6829638a78b266326b60546507f65128caaaf36d4e7f85939b75cfb3145e2b1bd8372531cda579f59efa0da9c95a8efc72faf326d35c660b4444627d328bedf50a919029dd164de051a4c0c924103e365cd640b9637d8244\nB = -977390f52af784b52c1d54e82131b072a1c308406e9b82587102e67c6f7145f0020952231a5f0ce9d130677bb5a7a37d5a06dc570a13a29673c8a9068f06242ac438806c37ec46136e7c1c1487ca2d330fc1f3c1f42ea51ba2805b74c44a61fb2fac109710dc3dae78a07057a753898d4e849b910f035bfd807178f0108812778345b256c7b59f8883\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 35d48c3e43070a10dac0e256afb83b219aacc0036f554bd998b9092ce3bf87bb5d3b00947f2c86fd4e7ab830502d15fb2d4e47ead087f5c779a9ba56e272ea86116e2c81345d379dda6b581e9c8f4df8ea56c78f04d4f7412d245e00ac645847af6ae97d5d2ab27e48cc878d8b510c2dc753f6ceb1b9e7bdd923e0e065a6c11e\nA = -76e575cc79d7f0c313a489b255e85d114f3933383cdfe75cfef649f639921eefb9b3b3184351fd0ad252c6e477e153ee586a0ff6da1e1b2bfd7e953e6dd778c849843fa5cc355b31f5529ca45aec81ba67a1e364d5a74a4656d266f7decdd47b2fc2d81d6c298afa2d1c39b5e8eed519a9997a14513537cdcddde0b5b41314476264d59b7d3f0e9a65\nB = 6b7faa437b4e8db8fba56c62eddb8a81e9090d1b6655a2185d656b2db0e85225992297381d653e707aa15f3017880b0f07abf3dc455cb09c4e551b3df3516c6db4ead79b88339fc33dda96bba76ff7c388363c36b67fd5dd0ee63f92f67549dd77e37e9902ae51cb58057579f03286fc48e3b7fba763fc5844c222e6a1eed9e1634d0bd034cff222bf147\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 445039f359b55eec647296fbff4f22beac09cad32cae79c13d591e314fafc2b77839816aa4f641250938865b0a2c30a10e23da71a6dff5985ebf3df4429fe64c327557b12d987ad9e9971f7c7b1e4ad01c94e1e5322dbcbc4707a959a401624619029558fd6f5b14564469b13146f9a2555916491e4d77caa70f51716b299135\nA = -18ddf976fec2090f7d1f4d41b8f875e56c813c04338f595d6e591b3eabf9e105be792f45354ee9beff997e6c0e8ec3fdc714c07b3466ad1a949b9d30da0115f5484c3b9e00c7cf0c117db57c3c6cd7434371c6d9ac7a5da1a0e2d705bacfc22f62785222d59bb5bcd3e3bf2df8e845953c6ddf1b546cb75b1698dc8e20bc611294ff288056723f1e46ec9\nB = -2cbaff39103570df7d85a5673b50fb8818434bbc19ab4e33bcc8289a4047d85de1b7029a5cda3976ab12e1d891b7efe3d5576bcb3713c597771f93532853290068761bea04200fcaf9b05d8553b960ef5e28064de89d9e5097d12b26af0b64beb40b33ff82a55af7c5838b44282917fd4342e2065942c724f3cca515d9142fb8e46652242e8f0ee5ae07b6cb\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 6727c0d0ecb4a375d0fd1bc52146da1242099d445ed9e87b1fad4daf8369fbeeec49027d88bd98efb425c1e3f73e412fb327680068ae57d4a53992f3759af0ac1b96a92f56c2cf552e6682d1fa90c3910bbc5c0b1754862ee13c5ebd62d5b98bfe8dbbf9bf53bf9ed0b967f3c9da24d4334b9f3f75314b429b05b8e27142623c\nA = 5cb6c49efc6767cf956885690ef740337aa71b90c1d4b9b0a9e4734de0c0c50f2358fd45aeedaca6e1dd0fb510bf097bf46513ee09f3343bbd1c11f507eb61d51ada40c5d6b730561756480063f60caf05141bec9a769c241d367cb92fa8e229ba2e471fc73f48812a25bfc7553c395ca77b80443ccaa82fbb7198f8c35c3b5a2fff977d8b2a29cf9358ee1\nB = 16ff229a0e67a410555dbd4b687f1470ec854ef67db73a902f2d19953c55071c4a26dc320baa8571586f1fd54fa490b0d87dc83e5bf20b78956084275518b307ce69aa4ca1079e3aa753d97fa1cff62e0b5f3b99d96a24e411fc3a3e375",
+    "ea21b7b35a578a72df68d28286fd9a324c06930905f696424780083715f77961532bad061f3901ed276a9eb6e81ad4b4\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 6e9947beae4d934253e481d27e854a59c4047eeee4fdc7df7e174a8f045776109c148ba3721685195b8fb59263def88891c5953b5a0ae85fcdbf02abc76f4d3c0f5d9496327d063ce8b3ba875b4f119dcd8beefb3ac884c25955af61c35a69d0670c3c349564e5b84f7df4252d6d3b29d9a75f09e9ef79f0fa9f797bf75b8ccb\nA = 188785951a3befcab56128cb6fb9576bee2412e6cdd7dd1bf5643babae83c8011af99aada405e119c3be33653862440005be994bf37d3802cb6c73cc312824c56841004c8e871ffb560e93a1d222c93d63684e90a91394b9c8ba8cac27b414bf818ee0de7217bc2faf099783800485ce2e93612ce39fc7e2f1db708bf9bb032d92b66159073fecdb2e0257058f\nB = -8dddf094f30284c213577ceb7f1b2efb1e4213a548e6aa840f801cd6382fb6d4995908b7827078dc3f46fccdb9e071bb8531ea8971de0ddbb714d678bb71ba9d961e58cdd5f41b8472146ff9b814a5d1d6368bd94812f8d38f235f39aeb2421a57499fe7102c1ab167df7d33b32a6dc7c8eb8f4babdd6b6c929d1ebd9bf4774aa40cefbf136feda7b6e10ba4dbef1\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 3f4a8d90017dbe8e77205e65fa7a0875a1ace6f3f215c2974e47dbac779804143da3dbce92db391c2614c078997c7d1a15439ffb51a5787f5bbaf98a4dcef576a6317b9b92dd8141a8fadc05d3be7c150630668e620a4e07b4b00519f34e422610a160de112f1ab8adf09a9169ba95b60242c89196ac6e155021dd84b3054511\nA = -65ff4322f8e46e03aa6c1fd10a207a5e51db6991bdca232c0dbc9d73ba77fc485d881868be7b14c25b05bb59b7f5bb6c4b2a7d53f35d2d7af282a0423285c5de656429ab7d3af7d92837e41ca701f527845e98c2bfcb51647512e6abc6675cec2a7d34ce55ea4dcfe9e7a8397d45a7a3e73bdff06e303a8f04ab6285eeb1bb78b1455931cae203078eaae826a6e5\nB = 4d936b603eba3aeec3d3f1f9acff02a0ecc28a8ec64b6bfd9b153b1bbacf4f1e186d3deda8c1c81e759237921cec53251250e3e838f5063c4a1eb6cc93637f35aca10b965533d18b713617a312e74c446d63eccee93cc97e3723ab27357ae9b3cbfcb3e2bfc589a1bd582480e776198df047c3ad85f611ca6fa480c70aeb98af02f57d56dc9659b2a6bee222dc3e0566\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 8a7f3cde3230af1f1fc25e0c0e9ebeb69161d3864fa5a03e5d7f8c82d9940ded285df35c008f61cc151b4578e2677b2f2cff3236935de5bb1d113597eee448496fe29bb18343687f6e9f1c783863e949a0954de2993d47a03607423b458bfd18c844ab57e9e2a43930df159ce8564edb5a2a37a06425626502e3ff9363b73c79\nA = -100f2984dc1451fd7b71e5d290e4b7de2d26175a47b9bed524fae02bd5abf96faba06e955107329559bff3805689633a4a57275732bc42183acdc792cbf7b6b24dbdc8921b73c0308d0c0ce5d8aad75f7eb16352e67116e859b323deccfe5d9ffdd1f0265297bc9eede073146a06acc3c330458b07b8fd0bb652c7325cafdcfa165f69cd0de8b145d49ddd576fdde15\nB = -21ac4953e54347a56800d75f6feb6ad660b0442174cf3c5dcbcf6528e2b5da95a614d3a8399da14507df4b8eacaddcddd627b10ec2dc5fb8c43d96a38e6dff37189ba275afb9484df800587f4953e327af71dbd58780bd5885b4cdab15ea0f2864f961bbfa9bba6b2d9448443af87c0cf178990254c1ae6e19003b1621f3240a6e5d0a3be2deb5dd253f5e1f88dbb60b522\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 76f8b44df8d8547f8b3d8537393d2805c699eb37d19bd115bd5539adb6b6a00d004def3b7793d5c71e0ccd2b7e9fb87103c1a5f56a8f18ede1bfe1607a346297166596aa78dc584c7c32832e11b72fb4f2d40ae1591f341919bc0157080ee8febb7fee5461a918d2178fa407c37a8243e24206ce2c19c3addcc2b7c3c1912b6e\nA = 56f4d397530f5c90203df1ec799f82a0096888fd370d543e33b5a2c8042108bb75a86265204c40fa5a9a44965ad2fb41896b134ea56c79699a230f38c0e3fa4e5d346cda70e0253b9993c9da5642f4e645a0d96cb732f8f04c99a83d1f1360a385c6e1a972b89915489245ce58830788ce23b9e62d6b48a7ff9a486614d6979033f7914a0735d201c6f29e512374088db\nB = 10fe818f6af7a95cfefb0ea0726f9a3e0e7c30dc9785b1fdf6e2b810515448386c7efc656479794d389e109ef3efe37fa6124c5a7db3164268da0d98538606c57bd2f7df9482860e81f272a27c727d7d81a66fc1a9bc8c385cf02b7ca6bc7ec2d8d6ba1dc992caa216d02c9bf0fba8ee754af77567c6e275ac1b6b1b36b065760761300d156e40da8445712b8fb206c0df346a\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = f580f9d2438b22700c3ebb23d1dc296f3d33deae2d32dea51c7ed3a0ce7b06af11046bc1cc279bb744bc31e7f822c17ffcc5dcbbdabe213bf97bb85c7e19ee71a513bf59b25b3b5787e42e9f3ef6aa1acb8705d69924a107b4f88e0cf9276c2c7c47fa4bf56c4900b557aa5587418f0ddd899630ad3ff678b5b907c07247b2b\nA = 1017a4fdce8bf41ce804b7c9c836d85ff6ee899807e1736bf0357b015b701b9675297e5ebf588ac6c295feed3c6a367987e192be0d89523ac7d64b0b9576f311b5b2705c5398276a52f06085027480c2ca72884ad7be34967bcc6c8cb4ec4fb761e88c16866a2e284b40180eb14536810eeeb180ab701ec47ece62af65a0753f95ca657e7d04ebf3c3a7db02993da9089840\nB = -aeb03379fcd4e87cfd18957a72fce42e016951a72b673a9e81f666b3cb20d2bba81400ecc2b38601bc3270eac46a633a1a6b55c50f00e9d7fc8a20176b93e971cfaa4f41573b17b8ccc498f8a3230825afd0d7f102daee347a9d59cc0914ac8689c1d8b39ccef1f3def44054307a7cb7706535f0cf4007231ba21696424c3d5b42c8e85c278f7c2e8b7d1787effa601ad357eeff\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = be05efeee19cc91e30a9277a6551aaea63aa3861b63f6061efbb0b92296e09f4709529eb849d9f40406fc59c526a4697144cef9661b556040458940ffd6a87ed56cb073d2ee0e6d1f05936fddd1b9a8974a3088577847ddde6bbdfb3d69158d5b3899c13ec78fb5cb6aa7204efe308bbe0b52f18381fe838536707a8a27ba0d\nA = -669660e75eae9930dcbdb99c477c980869417ec9c0e8c4053f0bd8ae62d496daf7539f37af96fd1cfcf3149bc02b8182a46b413e3397b49d4b4d204491440eea65505cf5d33a8e797af08f3da41f5a0804214846bd95d730260c6545d51126278181719ddd396c55f119e84da71f0683eb6db8393b098b3a0c5999862644e073b4918b5c8aff17efe860744d85bc94b582d45c\nB = 6045f903a750b69b709cfd6a1c8ec9fc0d7da9c53a9d26fdb0ce9a17c6a0ed5ba633d6fc01f004f4a48cf247d61f7df609008ca5bdc8eafe06dcfa06bb67efa6a584b5a2f02768718a908978edd475a2d2926af2a6e523549a5cbecedc78323c5c295bc0b8d3e14053078492e82e339ea2c6301412a5dd7efc20da0aad0577a37d853eed820776e672bc6d23dc821b5855eabcceb18\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 705bf20b7d92e68a69019cfd721b27373c7ff22f911066907f556321371fba70dbcb9774d3a26ca43e44ab20c586a3c1546fc3152ce011be66e04a59c6631bc8bde18efb7bf1743b9ed75a7a6c5bf5a4117368b81b112a3cd4e1c44a621f534a11c426451ea5fde880939ee5bb28d9843730e284520a976cd9f60c94751050ec\nA = -17c1dbc1ad1d2d33dfe1af7b4cdc7b69fefec5a92656957e111aac292e44719c7c752ace33dc74a6568be38b576a5ba174bcba77a034af5fe101699c99ca39f8a3b0a20679e6d0180868a232fd8fc775089e185e5eb81585403f32619a2f4d857bb091a824a89de2e84529e5b0702b45771a5816c5a823d81ddc89f8a70cc3d3a0c6bd6d85e9d72b69d2713b61c46161f7f4700bf\nB = -2252b54c602456c5deb86a0f249f3982c3836b70a946f636b22fe00c6e3b91b94e19200a33087fe734ce9a3f92a6099ad03a95ca523b7edb9e1ed3464d38fb96c470464e1c54790cd48769677efc5e1d22f5be4c15288bc5ea1dc184a05fddd5e576b3b4962f37437b4f9709dcec374377db44c8ba1d8611c0c3ec35f9bba213eac59a047e78195ebbbeff941c7f862e8c80eafb72b1e8\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee",
+    "199bc20d30af280fb\n\nModMul = 7306e3172929c00c29ca1db360eb4ce82066f237e9cf6aae368d1f531620e9b61eb64f5b3e2b735a3b565587d7e955d052df94a20e4aaabe493dba2c18e85fcfb65df166cc48733632d165129b112598bf5e4c58dff662e558e5f71b25f36708d3ab6536b1cbdb5aa2ee56d9e019a9c3629185b188af909831629ffceab634fc\nA = 6b31ef80767a7693e7d0a9ecce54beaf5848120f036923d80b7a0245aa6a46135e32314f3b227268e0bfa1f45b4dce83bea890526c7ac3efdc8e485189ce2c51597c2864c2d3664584be23559c03670622a53edc2c17b3f1a92640078ec35189dd7953e55e4da0290ff1e2996d164d69f1bbe6f5285ae89209d611a7d760e413e23285066eab8e126c320bb6130a91d67ef26d4dabd\nB = 183f06828033287497322b05ac08f62dcc5fa67b7a10c6c5a319c9a1e642754230c6d9809dcfd2de4bb9e360d6e6e1180f6ec6e0d4c6185e34ed299b6171e653521d0f7b8975ed5e7d2c51d27f9784a4b6f9b5e97379fcdb42e4df981462cd5bb9d0501f93f217d954f6baf70343ec710065eacbd2b778430ddc36a7ef0515f29d5fe78d8708d8ffb6c3391c6f632cb1bacb4ec52972ce0a5\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 361ce44d153f4d251952c0b90681a19b7d2d8df7a6c5d459691a80c06107b2e818f93f30f8dad352d2dd87b01530d51fd1c67cede9b1a6167697098e41bdc5dc5e7a3c310116aed0c7b5fd99dfcdb3517c13daaba6ad10879f600eab846cdc110d392d9bdc0e8ab34b317840a725a7a12ceb48c75e8dfeffe2947aa85b2a5158\nA = 1e1f2e44bc7c79a00afc3b2570d5cd27ad5ec9f45aa94f63f2ec3fa6b69077480212a1cbde25ded7ab1c6cb1ec26d5905948e5c1d6d109bd5047b1e038666054606b42e880b609f6f00a219dcfb504d481d6fe709f4362940f6c4b6f2e05d243722cb32bee5508ec94eeebb53b5befa551d3ab5dff9cba3daebdbc97179e56cb778aefdda6a0c24265728ff9e59ca3c2d615398d97e66d\nB = -e018708df037aa2918850fabcad82731487fb812213b1c067d0688462a4d518e5ec7c4c84f2cb2017aa6bc960e2faabbe361ad8f66355366cae869d366f06d7cc32ea08dc51631e7f36a4c775611095d8aed06a0086d0a471749246d7157947a1eb5d5503f207723a7062382b3e45bb84c6f555e48f6d63aaa1c04fe13c0108507c0ced669a5296bcc16debf18e03c32eefd177bbc1dd2f19cd\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 3aeb3ff6e797d271fd2271499a740a91569f300d7392a7b5898084012a3c5ad379a57d5169e43089cd58fc7210314758d5368dabca2f0ec5cf6786801bc99b45cd60403c732d9f98936aed76da724bd3e7d4b622dc690778f11fb0310fd4cd980b220627f7a864e107f93a6259081c6581e5dddba4890508af8057c1af29a745\nA = -75e06b47f60edd23148c3736c9c125a617beea7c8fd47e662c9d9be883ae925b7801a0030df3f4bdd3c9fc386f18c4e002e5daf4a6f7fa27b2f71252c83d5f1695e50d62a10b99e1900987b342290decf681a064f789e11bc3fd75d64e2e78ace56e7491fbe0eddd6f9958a5f95775c920ad6c051ebe7750fa76891ab00f42c910550a42bbc1c1e5aea0ae13b7e6f916a5d228bd57e854f7\nB = 434c8e4767d0d7df2125def75a978bb1509a26bf8305cd03df748c6c12b6dc580a2c1ca9a4526eaf3936fbc4ec797d0733217a54ffc9e1d7c6ca04fb39679859d5bd3fa64cd0a09cf1a056094b9c20ddf1f00e134533ba9892c2ca7346ac8d0655250eb45df9f0b7983bbf71102c6f1a2d9497e7a45eea7b3095cac037b7aa755beeea8a6191da268780179a652d94a732a2a5c7b626c0de3145f4\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 734a429c91f5b0f06fd47725ded06222c0193dd407e9daf136696f203e153c9bf6df59016849284cef93fbd35edef2cd31c9b956fbe562d2a22100f177254144718ac7d22c99783fd523b642984794bd7beb0d0b363e28d3f3469ee332ee364faaafef25c1d4a11b5e517e44a412ba717a113ea9e1e8f2d6db8fad6f10d06950\nA = -18dcd213e9938fe4b6a64abee3b9867f65e47e5b0365d45a8dee14ddf787f34072ce32f38d4d48ccad236005a23c5fcdc02b72cf27001495663fc56f428072d3f1bf5e33ab2c5f9dd9facf122f7225ea03c2f67321530a642803f65a2e9428f32d0d974e68a25f705e4f8140568f7e4b132942b49f9ff53f04f241feaa29aa353925fcade33a0cc192fee2628c2111da1e652cace9d304d0f1d\nB = -2e5397658a5e6db9d30f09e93e67a30dc84b1e17c25786e041fca48ab710e1d0497ce615264f1abcb23d5aae8412b58430bd801775acdce06cd362438898697940712062b611c92ae6ad10da31784207c5e7b9362b20d7254da0df8caafe0736002dd466d76b1a03e91a8dbe8a71107abd5f07b00fcdca2017391c7c3263881a3d02a89b0e16a2a765a32d24ae6584cf44a88975c539402db9a301dca\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 427609751f28edb62c717bd98ddf999cfcf65128b652be1b5aac0dfe1bc0f7687c580ec70c8290455a9448c69dcb550c0cfdd109af561ece2ec8707c1d02e8097e780f32ddd932e706f81f68711acda0e7610f4dd0fd55f6ac7ca3a3184f655b0b29d2d62974739b43ded96b413b9e3f0033ca1edace24b6bb610bf06b5d940a\nA = 6576c31d48daaf7d6bc3658952c4ba18095f1a0d73726f6fe59381af45a2a6b592adc79fbc3b597e1eea711ab295cd991441fb5fc4ce5f047e571a7d949c709e0d31156184be4b8a6a49691ef93d7d3b120193f6ee82246aeb896b8b7b4c74c27c02cb39fe0335883a3f088a71ab42b947a0cd59dd2155c65a0274ec0836bb8c2fe394500724ef84d869bee40291363389e7012d672b1eab6696b\nB = 1ba2888f30be283b588cddf00eb3ae3c641e35fc0bb3a9fc85d7fac1e81052129f499afd3e8458d4cf893d51fe4a2bcddf70f28c8edef16c7bbfb791daedf1a8248faebe36953560498af652d1f1c7aa0e9a5a667d9c94f7d9525cbd5a82147d58b738dfbba5aa162858c2c66d0dd7d8db38d41a2261e6efc7d0c8b2dd2d6962be0fc796705cec8e87a13092e4a3febdda3d4dbed9d11a1d5f92d7dafcd6\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 533d6d8d7384e6e65569ba0daae0a8cffbec1d20e417a6edb42d401a59de0a91a7e6854db081ce33b76faa63f6d866993c245e69ddbe6c86d339f7107a4807856cbca23cee2bf5496388ae8fd8d7c78767d0775acd7bd6202dd75451b424034e2766185969b5663b638d539f718e50a9f752f406c224c000bf1ae1fdd60a2a82\nA = 111940235b144a42a13201a41a3f9e4ff02948f8e9127d9a3007906988a50b36d7622d1221155f2516812074a7888b1d8334a01c02ee33b3164d761d02b36729c299ce2455a462bf18471fca42e5b01615d53723c3fefa5aaf4a039a6caad35c348a0a4dd3f0204f084f35c0b93ab233c4066dc50c5fd3897a769a7c5bf309f7a9c30e905466c8394d509b79d62a69b58c73d8d3f1665ecd9a8a4dd5\nB = -e2633e43c38c0b4b8713c20bf4e2b8ccba680ecfc1139954fc42724277beadea438596942fea1094091671c2060dfccd0351b2fba8cbed35dc963cc18f8e8835052da884799d88ec1887712000a0726b17cbc4302421011d5be8d234440eecc363f09e2c04bc9cded3cbbac9a5bdf0b6d418822fdd90dead20e5bbbb3566ca94ab85f3a00d32842eee6521edd18b9aa6872340b2f47deb961f58bf231e01f9\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 33960d7ceac73f342d46275e04fed56563decf2fa4c0e9307c90288e911ac8782f8e1354fb051a9da8e2db83d7c710b5d2b611495e72ed42259ce783a7e7a8f601c07061ec749481d39a082f29dda1f9c7f444a33ae1c1055d37a677b848af371cd3bd41c851d31a07e144d7add66df39576b8200a8b918201630b3da8e664c3\nA = -402034484e499a8efd610200790d443c5d3be35d19d8808da85954d42dca3f24177de48f55fa2efd7e4f7f624d806a8d461c3bbe0b626fa1f3cad2145746464108b367b13f3537ff395262256bfccce5f0414e1f98b59ed29940171d46ebc4bfa1a27802cc30d9221cfbceeb92abdfa6e84ab4a54965568aa10ea631e82067ae358a1a93a3a3fe3a5ed5636a0c4cb373b4d49f46f8fbbaa665a19200b7\nB = 78ec7dbfa2b28e268619ba6db34a23adab25e7f8690aa9464a7d8fb7c6b87d5dd9d33d4c023bb665f2d96febf2638fc087ed30796fe7517fd58e4120c0d319688e67a32bbeaf62a987a9764be75384bd499b0e00a850f27e303f615031299c631844d10abc571f9f2a0f742cc0e8df2fe3c244bd825bf1d9134b2f1059e2a1b61985ae8daf9bfbd9eb24ba268ca58553891945ff1a314a78fdebb5444677ac081\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 3a1ea3fccd6f336e6d444d68af1753b83145131954c20f1e3c433a8",
+    "9eeb7e267425a34d91f67fd65191dce85769ece2fc7ab12d032f3e30f8509095ecc05148e47a85391b21a18257c338a6a3ca9816987abc8143fe443342b34afd8a52fff00dda2e42b1b39322bd38c6a1f711051f791d6cad2a47ebd423a9b933485fd5861\nA = -1869c53f86755aa350115a9f49d6248cedd42a339506b8ff59cb878b7745956f142fc4387322c41f369773ed375b72665026771d4ed1b9ece08f84e4782d4c3b0177853cf9ac3a55f7e52f39c1b82aa42b30628a4fa6a838754ec6ff9809308f675e455bca6f44e298394888d85fee29d8a0c8e9cdb9aa08d68cd70e13a243b5804a3ec199f52ccd462ba6594d856602cf1d5efa509047633923d31f78da3\nB = -2023c544b6cdd8d971bbb345300f7a101f6dd44dede6bfb5f4e6b4eafb7a40728a3063f6d4bdd0f606ddecf062828cf889b2f632d0c9254c28f36dd974aef116b73cabeb2bba98635841c2b4d2aea833e35eb1db9fa9a9d33bf7b51c49a14907dbc6036b027a039192b47406bcc56bccf375fbdf40b82ac4b3c660a43d5a6eb656868d383cebd099d2a73506f675cf29649617fe06097a46de93c13d1e590ef2cc71\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 4331f18a94c169cf0253136bc4eb7480c9fa4401c18db1194371dd53e5f7b75f07ec2e1e1c4116a5d2a8b2cded4b22925b67a88af9b8479c6e821d58cec7ed9f780a4c41e729982cb33f69b87d01c11cb9a8f7952db1920b6eb2124fd5d820555a99327117d7e8e26d18e748fea3ebc17e1d07161fda57a21a70c7f4e251612c\nA = 5e7d4ef7d6ace6cb106e38d96085d3f3505983fd952498af3c1d9b2af61e4ba10e14961b339c6e64e11ac758d5fa18c3222138290866970d67d0a4f4e19f453503eb8dfb85b44d1050c86943e7c5d6faf7851bedf7d0cb6b13d2acee25372243591d37dd230907457fb440f83b62395f80f59a2d02b87134887406a78efd77614f3193e517f234434ab3be084f1484d3f2c1f68c67c0d6e863585a8a5ddd0be\nB = 114b6e6726433ea88a2ba965f0881beb3ff4d377526e4e099741f069abfaf29e129a1f5fd243c6599f725a389728f755f9cad767ca1d6ae5c8b3a32102e47af211e86d67574bddfa42b2cb466d968f38b47333b1b55211fd9a315acd5ef62cfd3e83c13ee9d3fa20a06b2292177961dddc7dc39abad9ea31ead1fedd3d699f651b656edceebb0bace11bebd0cfa581dad577b8b42f0a844bcd8c8227880876dd7b0aad1\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2468cdb1a26eaee34db3d2724e37f023c8a1788526b3dca99321b574685cc8303c609c85401a58fe6da181daf4111fe8c6d4b7428b1cd301cdb9bf8cb6f33140756c8b490d3b2e538ff294fd6471c4d17b9d9e4adeae0df088cb9daee18e825a368be57af4a096056b9e76b94c8d3b911b6a074ed41082926773a585007752ce\nA = 1e6a59efe0b14fa017c32ffd0962700fa9752242b06ffd0b604b9bfd125114d4e0909534ede704cdf1c9e88a6567f4a2989df752510d087d7b7afb515ad594627ece54b8a8e539074386121c9a3e1c12eb2641ded8719e56d42ef50e2f3b5d7d59f8a6f897174cc00a7449d2b91f33e9df07902a95479731a44fc4ebe8048c449bd515ef6cffed70ae78c832cd43491203a247fcfe0a403862266777947fc2542a\nB = -8a9d3646831dcc852fecc8e2335549e8baa2e2d82fcb90846ee82bcc715c716d4a9f62be29d5e1531db73c2186a4d2f118266de33d966b78f989600d772ffc55b1364117d6750cef67f4bae851e7e3f8fbdae7b79de7eab54cc1fee56e25d0632b2929e352c882ce78fd64dd0a1473e80b6572f0d4eb67f6bd6e45c7617314219d6f7de5e505a9b395096cd36650d23e8d57d6abfa9faaf0ddbff90d32865bf5ddddcaf28\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2909d3aef7a21244efc9b5b16626e260907ac11f3d00647f2170ba37197e47b9767030195c2f6d5eda717a83a152141bffed2e26777417ecd8e27aed8666698c2e85a414dddd52b07b52b0da7e08b3217fa6a331f84820d21086a4424974e1e8cfed3501eb054242a9f8bf0803a94981b7b81776eca6d07cd50c050dddf81d68\nA = -73ecc8a6a1507fb5dad40677dc6ec75f0d130ea704d1e87b00d2bd56a6be21714bb30202739170b8dd3605f0553ff57439051efea2a97def70a6d2cc3fa2b9ec27a00c1338bbd588513f0f320272b8933fdf6635e585d1e79203efb5c95a454fcd7f33aa2aeac08902107e9bfb29587ce8610d50cdb7f2033c5b726742fa9f7f20b4780cf9244e6abf6b812171a64b870c3ca4c9e898d4c15e9f5b0194ae736c3783\nB = 4049ae926bb52e862606842bbcb4a5148bd1063b6a56f331cf10000c524b4aaa80b3bd914cd697ebc98d68bd3c2bd5c87fac4ec68606c264c56e25b19d118dc9f2eca19bebca07269714f2955e107b3fbf85530b1fe99c42d33031958280b8e8abea5a918a41cc7e6980149ad68fbf1c0041798d2046d7f88a395348b295858c61c2f33d8512b6fe75aa8fbad62e2f9b0b7876ef95af8a7b7338a2d6b25ec6355c276fc6ce23\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 22407e4fe280ff5a10eaf46d8e1f5a1e77a07410cba4106466d703b11764c60124fa355733b47327e952a12869476306926cabbd797fc80b4a6dedfbec0b7718ee754d447825cc405a98b85f1e09ebb9294c4a4636aebfc61af4545b921cbe759d3f389beece3f29c2c7c07691a4c46a1a72ce418a239fdec80df48732627866\nA = -1e165ca7e1eabd2ad1264d5ed9c3d2b687f2db5b507a0e4d21d9e042cd46e93c2444c6aea8491b5caba2d8146bac656b7754b7b1ae0f6216029c7167fd3b1c3ba2e20469d386d8566ebbc05cb51bf1f1eb2cad9dc4fa454b07cc1bcdb9b8f5a43e354c4e0f4e62d52798f667080a0e0a15414391269fe8c92f06da74f6209a3b215adafa1eb6866f8b3e419468e2e5b4db0d0ada80514249320cecf034477977bcceb91\nB = -3f314681eaa4cb41a3feae8467f7d76b8b05939731fdfc943235aa4d67bdca30e64de541d17a8971e829bc0159384643672bdffbc93b3eaded7844d824604f46aa58b1f1b9d788106aff53438954af015a0387268266a6ba262e2fe7a4c51b5af6ff7f918674b7407ce8282f66e84fd2582edd809b465e4401c67e5faaa9e5748c06e3bb8ddb23fa649ccaf9657dbf79b937eb8959aae8d5bd9513c1e601c0e536cf60c4fc3802d\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 385ba217033463cd9cb882fe30373c2d8e8475dee54aba1ca9713a709f40844905c2544ad792784cc8eafbb412dd68de6f98522dfca1c3de8e3bf4cbd09bee4656c4341153b17c98f9ac09411d16ec9880835cae772bdd8eee51eaba7c02ca6a1034c2c5d2d48e7ae3eb0e22f59bf69537ab6f1e49e58a71c64b8934113eb069\nA = 5137226623f4ce4dc9b80a783777ef4e53ad3c2ec648264db472c517a96383ba1173e52c2659a97ce36341a11e832f4ad293b89696f91a051c35bb1db6182260d4a276d1a9b4be848c206899f87a361d318d38b4073a7470c5743b816cbbc3bc1b20dfd7971b11ad4e20d947e352d42760104a5a3cc590b985ee3b5e98c779e38d2581413a2208d31873f9644ec979602671c9da72fa6f66c603c1bb6d8e690dba8bf4933\nB = 13b45d4105e3f5e8e0ba36c812faeafccea2f1a30e2ce8ffad57ffe0dadeae3a23e813758f270423ecda3da083b42432eead7f04842db8865f9f1e2226a3d298ec1895ae69adc55d1d338c3fb787f0676664564eefe46ca95206e81678cf1a2f173c52d809b1e06641a9b467f191ea09fcdc597271eb43da1a9a856784972ce0eeedd49ad363dee882438f09863ba5af063925871c525c6c0ffdca428054e039e149a424c6d1b5b2b4\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 7865f718cb30026837ca006f5cd997c5b917726ac6d9bd8c3fb9eabda0854d528d6cfc10e4cd3f93f6848582690c6a83955072daefc6959d33192fcf42a111650e50776ba9ae43d3d26e0ef2c6b60c3871aec33eda8c56353903e7ae96592fbf350b88d2f56e03f7f327022a2aa9b7c484a000135b85bbaba6f8836cbfc81901\nA = 16978c06a03276fa2e0bea45740a98d55fccc9d27321fd0a5b8522298a2a90d391c06c5c59e7eca85efeb9b4c91d4a1e9178adf816d597311f004ef98d209b59a2d4b901fa14c57b7297861ee58b89c9b2e931e4ce5818dd4006f3c40168bb4d3dbbd059c1f1cc24ecdc64d37df16b8e8d0529247c06f905ca88a5d283ca1b9e6856fbe8115a326061905b369791772a47900974339722d19b3aac16a0bedd93e1e4e4289bb8\nB = -de6dad276dcc0a9e271ad523620ec570fe6e3b350b934932ebbe36dd571edcde968b6590be14326e0f6394c0a2172052ff8dbc3ff15d94fb6e36a098286333768a84fd0404dfa354173d01f98484fb20897c439c48952b7f1791209fed94e9e72bfb3df5f368d420d587ae8bf036db6700f77b130459e9de2a541ed885c69c5641defa9436a4f7a69d2848d0e5d1074f77fa688b6dcc4d4c7de25a3b1b040546ef7f418112127cff173b\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd99",
+    "13b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2d3dfd14e7ec60f842d1db83e29a0f6b052990fe8900887dc44476ed3948870c57e72e91e1941c476baa6aa86f76dd8ab6e6ea41707242c46d39b54215bebdb1f28e59d719fde18bea9994610214ea68ad9f2da24e1ad8a06f8bc698f8e76379ff332a2745af472d52a4b8e57d60280e19f93d5be669e0832824321e9ad8e76b\nA = -5144d5ca834f7bbb35d3fb95818c1f89ebe08efdffd35993a7691c05aa1b67f6a28e219b27fdcb66e516097c9ef5f00e4257c561b1f94c52c577471cfcd7a55314d3b0fa308b59449a36adc884c48ef5f34753bea746bd6fab2f20b86814c9fe50e8abaab742916313a50e3c390c67fda8e3729ee3329dc5e4b7d3107083aa3a07daf7952ebbcfea15fae7338cd0b114e9ab2f81dc2e80f90abff7a7ac59e3aecf76fab87633ec\nB = 48b927a46dbc4e23d714b256084fdc7cb9d4c96a988a71c956e0bf98785ebc9bf22b9d5c6ba0c419e60afbef7b96cc0c4a13e397aa2d2dd7995875d2ccb127169423455d138131199a263151f28d232ff4ae24e316907ace1fedd02a02cb5ff9c831de33e6702010fee2232bbe3c1c193ce792eadcad0c81e7d7c17e49168377b68690bc61f22dfddb17d82a3b993804726037cfac8aabe8548befc52a3c6c6baaec89a392133cd9c45b1b5\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 3f66970f600a9d09d73fd1ff813e977f539d69fe1784b8a2f99506d868418e4b47338ee0cbceed555f88824f98ffed39befb69e8907a5822ef7cd2a9950a070aec8fe4db9d68e1c0620f9eab4ab529c7e69466e325fe1c6c011bf7ab62bfd1a136597d7d5c47e8eb161ea048477bedc88fa30e4f7ddab2cfeec3fd0bb3fb61a3\nA = -1343c391be3f2b72c4b79d8d6091389c9602e97774b18eabeaae81fc0539336cd8c899341cf75fa758421c7f32eba9df474c934642003408b32db66cfa92e6e414b42b1d49c7e655ffb4c80f5bbff8d2774ee4f7198839680175e1ffec0428939653c6697eb3681d0f92634cab1cabc63f423d5a71d65fc7150aaeea74f9e0153923a1c65dee4a165e6a01a88655fbecd2db7697f4d2b49fca2508e2b8f84129785d36d88bcf59f4e\nB = -225a0a4afdde6f6450f28736c3ef6e67d67ec6206a63b11763bc6e69b03f1494b275ac504868caa6d56d684a12dc1098ab0d030583e73a2f45a42b8607c0f19031b9c5f07fb71919868911806d210d43aaaced5894e844881e89bab85a203af9ec3adb105e50b4250343ca50c26df14c46d73a22c2e4804d26d44ff0bbcc13d0dc7e326c9e4eb441f493c9743ae0eea0de045e05d19ac32d2379196a165e63ba640ca42e4861caa24c29cbfabc\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 54e95e86e87bc220c8f53f8485402327885be34e34063a1b81e52a23fc3056758cea1c039ac4e513f70ed9d394f5806fb771dca8e342368184e674e6296b9a705c6380bdaf11550cffc73f9f55b9385c85fb648f105f11138a3e1f9dc0a39a0f9755f8328701484d45784e3e4b2ebddb32c9d9132867c6513201116428b791cf\nA = 5f1239e0b5dbfefaba906bfd9003336489ffdf634333cec2484c582dbc19b66782ba40942d047c3749597ec4d89ef61b7803d33a9842f0c903461be37c679ca213aea894d36c1e12bbcaa1c679599d2adda9bd23e712dd0d0bd3f91d146e7a04f3e7ddec8b0db7e12377ab32ba241ed1e01da070c1f3ec85efd8387a7b9421453969ecba8cbdeeeaae6ddb098084bcd250601af780960c32f0a1ad7d7e61fb19f40dff1060c5f332830\nB = 1113f145de014bb6dd6ca05de159b97e9736c45bd3bbd8477f739daf79615fe329ce948cab9787838d7daf797218af5ba7925685ea341b802690bc9588ba3e916145cd3ae9d0c4a149637b890cf50fdfa8f89a62e508eec68f9332787733aacdd57ec1f359ff7fde76138d5b33d32e64cf7d252f2bcff14be3adb1afd8da9dc930f5261e6d715ac75752b29f083bb1de7b0b89ddba633b8137f3fd299a7f77abf79781a10d897e7bf2c958a097227\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 6e0160eaac8e1c31cd3cb6c5fb91ba086d033b4b69e41dfffce7569e61770f6629f23e12f0074c47c46653bbba94701ca798e1a242f7c4e25708d3acb5af6ea307b95cfa220f8879cb4cfff96b843d6eeed2b15c8f1bb21bb2b511cefbad0618d49d9ba33cade6da6ab3b846a6a24e35fb36d41201d3b85be831522b9bf509e0\nA = 14f4e24627c773527ed2243c0d1947395aba5c9cf95ae62a48827ffc1477614ad9c7aaea4b4fdd97e3272d3e220601565aebf87928c301656e9edb08d6e680de845615bb3a81c61ed043adb9d708ec1447f057087211673fa6ad8977166a2b4a8079a4f29d48e7fdd6875ccad05d2c219922b814589996cd9642ea2b798197407acd274da30d3ca008fefb40a25b38cb6042a581393283d6448cc69df9a5dc2b0777052566a8608a1010d7\nB = -b4188ebc5bf3ba31cf7c5e100e79806e92ff6f863c3d68a66aeb3ae8385f596dabe6f627f3812d0f2baea319d93ae00de41ab65e42eae7d396cc8fd0a2dfd35f303117fde4db5e8438df0c2b3b680dca538b42a7c844a9bf0d3697fc89ad0a73594627578dabdc214e0f4aa06b40987aed473e7f42d318bebf7392d9c898b4b8d73a94726aef65807b2ff746d4a9aa76303ed7b4fefbab34f5c87c2df82d20457f68289f7b96dbeab581294974e322c\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 8dd91f390c1f85f153f332de17e5de82979755d835398cdf3dbda1ee73c68f8e7565a964ae33fd5b1f1060572bb3af67eec79c4c3e2eb4de118d471f74351b80a5dcafc682bc3cfde642e611ac1d5bc2c49b308c30985b1161c4d78cf7621b503e2dfaceed886befc004f3a729b4a9bcbb8f13791d973bf38fb8101d6b7a4d4d\nA = -70e99398673324ee83495aa0aadfffd7bb9c94ee5251fff365124fabc50175d794fa84509f034c2b86d83607789338b0eebdbbf709a129a0ed0afd21c130d94b279c56f1c7c1eacfc6cd13f724a9352b2b37412242a47b23ec61ef0040a8855371aaf238003c45ab9d18a66cc7dab9653b93c323815e5404762d3f964d4654a6995af507bb2db2149eea59acd72af4d034217eaec0be5ba1d23890081a6a234e125572e3bcf68a6ea52d9437\nB = 661d8832671a4974b493e5d71e547cd46b36730f4017e50c5d1a7520fbb75f0314cbc2ac948744dd494d566ba580a2108106b120a797cfeb1fbfdefdab6bd6b2e073f90c77e814cafd0b7f79afeecd59778b1dfee3446fb32139b2311011576674f96f151f896b477c631237995e11e61e715dd8dd38e802af93124c66eee735c472972000cb4788b26752a630ba63b45e8ebbd979f0a4da5b359abd2905f0b7f3a21b1d381cd02ac08e284218ce41c907\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2b591d2c57f6a5484b43cd7ca247c48a1b38319e843257331c8807d499c7763de4eefed529e70d4c144e5e843ac00ee8d106d0d82163cfb7afe528a7daad8e7ed105942d1128a67e38d59325cffc0c3dab9185247e0082e3ccca82a900d917c9bd0f892d4b518a752f8e9d38eab2acaf3b3b59f15b0fe4cb9a3dabe6e0191493\nA = -1896f67485a740720e23e1642ef02742ce5f10a92e51af19e112cc99c0fbddb60d7190086c942d293d076b474d056e74ec9f0c42055d745a57ba370c51ab2b761d889b766cec909811e2b2fd11d6916b753ae00622f038a4bc55b813a5d06e6ac136e81689407de721ee852cd21ea989ea7c8cbd00b64614caf0974a62097b2eb865f46fdb0c1a2e4f2d839066b797e51392e5ebd14dd92630c070acb546dc7438631fef01594878643a4cf77f6\nB = -3a8e2f3b8378a2605f5affa21c4fadcc655f2f8357a3427d2cec0118e55fc2bbc25931259e294d91bde8dcbacd39e6cbc125683da7d0dcbbc67d7c5866f08e7c4732cd4384d9366868370ea40a75beb23b81306303da4a3e26ad357c5c743d0a4ae775a472afddf8f21cb4a1a3350bb6aa71037607c334a0c79468668d3e727cf1d0610e49f27780901c68aecf1d145953e45f5b090855be714cb39aba2efb0f7db2786b331dd9bb8843de8c73c95ab13b6b1\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2f53bdd643b5b22445e2af3667a93de52f8bc7bc151e196c0ab0bf3b4e4dc0e5dae9e507508711a9e3de52e2aeece6aff7fc8a1db65588de3272839390a35a847e29204d3b9b70e10352c88a10c86cd33e067fb530d20a3a5ffe67938c5a7a9218f1164f36a73324adef64da64d5fa5540d29a76a87ce010fb7d73a59b109280\nA = 75e31ab221c08b3bd73bed03f878bf7742f9b36a89bbfa7e90f9b05ec11edeb0140dcff6e9ad1d62cd7af34bb4284b3a52bf1b48a40f744b561d9ece056a9405ab15f508700b14914e4f427ea1df3093497410a0108066e9b259c1a26ea72082b3cf0e3a99ad054804da7bfa0200d93d65354b75e605b47a4e1e17ef851a37c59a95e1b5172801e6ecabf70f1e6e382740998fcfd8a297aaaba7d04b668e3d6eed40358247767323a8393ec359628\nB = 107aca18938a9cb244ad646a37a212859b3dda7518a5827aa2146b47bfb3bd08d772eb7a866e1f",
+    "674aab7a1c74cfdc2bc6e9ad1a365686213655b2c7b1977855bcd42ccecb804bc01d92bd7d2667069d853f18a0f0661f028955e39f71ee82b9ce6a81dfb2951b33b123e71264e819bba4d0a8c53a1d99964ad9ffb58b7cb5cfcd3e30b1baf5aa5b3cbd20a0df7ec37563e2b32b4cba91bbf3bb6fd1cbfb2fe0f84d720efdf36e9645c7e9ec70442ea5174528bb\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 32d16f7ae2632b5cec2e90c34d191599acd9a1b5f97845595988c1d0d4ceb9acfafbc4aeee9924ce55e109ec88c57610fddc664316e0f9a5e3ed56ea447111c0383ecdf117ab42351b80e72720a4b1d98d4c73f5235507c5b4f7849d5e9b527d054858c0436ac3d2de2704c4bc25de4cc702f5880d5ae34094766938bee555c8\nA = 133a439cf006c753c132a8559ea13c64f598c5f8bd5043b89d04d7ecbf0ec58b225551c8df8dcb341198fb0b487774867e5b68f9058f58b3cc98168fbed0d0ffa86bf74b4fb0d4235976fa86d52b8dc7e82df176d70892954223cc484ae58b6a60459a9a0803ab856ff9699789172b163615e322e193bd758016f634c83cf50403e416ae241d9b1e44add17c2a663771ac88cf8b9dd94622d80d879ae41f0f4e7a1a32a1ab164f981900fc159aa85d82\nB = -fef33e21c07dc26a47d692c3094205bf4efae6af32f1c0f46ee579c1a22746a3663d66f2919f46f973fe558c61264157d531e66bb9ea10b4b49d9f6ad3ad8762a6ea8169a9cfe01d3dd65518c2e6e58e8c88d1b2f42d207399d7326752560cd45d0ff571309301683770793fe3765c1337d14021d39ea6980934c5fefadb93047ef07c807d0ea5625ae0cefd098988d6eb7af993c062ba313e23176e7abdebcc6e566304a5f9e03da05bc1cc58dfbbc898a67a5941\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 20877c7f53fca97f8e484ba31f23dcf51ac0f4fe4c5121eec576e043c6ec5492725f1b9f9ecfa64195f71909500a69fab2e591377cc2120bd5f60d3fb3812f9e80b2f6c787e0081c1439dbea76b819ab44bf6bffe87dffd771a870e4f5502609249c5260f91175fb217a9eece4166540be877d564049389306e0d6b313706297\nA = -534042b0811c9afca04d20d83898e7653f91a73de1e4b516f3228c6d6d9b963c7f8f4c36e05383da90f4edd072a7eda382c47b84b46b4dfa16f269c2d9ad0fc53ed2ce51cd31e4e32d0c1ee21604d3c7eed2deb35cf8df6fe1c0740a1515e4c702a2074ad6c0fcd403603b4a4e2195d19b265958ae854ccb0b41cf22480389a053f71544cf594f6833f3e4d91fd3d9091df0978d04d3922ed72a4fa3579c5fff50eee812dfb2a334148227a0f5739f8ac6\nB = 6935a3444434b0b03d27545721e253e4281884da027246e46ddefb01fa7cf7a9a030581dfe618431a68ef6d79b03b34f3ed598e7c8ac030e2b4cc887dd31664604fb8afe4e71fbc3135d6d3b4e596044d6b615de7184ebf8dae8fd58506286ae4d3b797aea911eb59ada39dac756d0e9eb6a6c767ab77b9348929a00f8e311f639d19ed88c86eb91f0d4cfddd34e98130eb520fcd2b77507c24b6804d3d65d1b21e6f6d55d1f6e92bba0544829687a096be79eaad7d88\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 24823628d4fe9540103ce5f611f8a6ccf18788120280179a40c2636f30a13e5076503e8a4b6b6ffca21da5b0f9f0d85feb2ce10b51292ed069f35289ebf5130972d720d20dfb8e6ee80c3ac598570d38e57ba33dbd75f1b03eab7847d865c3e8e471ccaf302461a6136dd13b8d31c9f163799a3c24c7284b8826608a9543816d\nA = -1d476cc98529efe5b926aba3160b261723b009e9b880bdea04e9b5b03f173040ffafd1627b38be8e00840e85d7acd3abbae2f7a60b305256b920c2b25a8a4373ebbf1a0c69f6e74792cb0d849872500519b6d1c190da30c572e26b44590b7ffdb464a900fc38db013feecf909b43bea549e05f1b7e70d6ad879c613293cf61f0cecdba1a6565eff1bfcdf740bf553ffd5bb7d74f7e9537897184c527b990dea20387bab0dec3e32727786bb14975b23ff09f8\nB = -2b6e12c87ad91a2fa878b9245875209cbfef400e637b557c868ccbd6e94dae65f1ef8caab61f292d739b139e384137a747210c09ee6f3b2ceb6dd212e14525852b8c54215191e116b7097f6729f6426a8bebdff86cdc16effa08d932ab512d7265cc0f57303aa5e6fd2afe0a45180557935c230558d02c3030b38ca88de5fc75c1240d25a22fe32c4e5096aad0078d50989812d7dd0cbb02c736fa563efd32d14109c44297cdb3d4fa3b93a2e15bbb6eb678e93e943979c2\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 2c4bc23d0b4b1f79141be9149ee20cc9f1b58ee0a76d5f4205e0862492c18daa20171285d6ff0b600c358be487e78cb5450d151efcff8d53004eece94c5a37f49a15fb2b5f62a79568382cf0a4232407b139e1ec5a9595bee8435b4f138dd72fdc2946b03817e49864812b7b61f179bdd8389791178a95bb6311df0a5c60db2\nA = 5b0a181f07068af6e1e4b715d92c1b8391949a1e3cf0fe0aa49f3333c826f5582615d39ec28b1367804c1ef54f15fb83b3c578ef3ae957fc89ef22a343175df3ef2fd425f724ec1c3363aa000ef624d64c6d678a4cbd90b41cf7d69a7e03dd60c5d3470dbb75228b34d35469847772ff3d74b1a89a2c492c082d3ddb45ba4df6e3f228de6c64913b79679cbbbc36a2924e722c2c640d0c5a0e90ae86b5364dfbfae80df3d75823aa58ac6c1da78e988a11831bf\nB = 19567bbcf615b777b35fa7030db7da18126cd695ca7dda67f5146c97beeb20df24ba0fda4a4f03523a0d9b9f85d9acbdb5793ecf9c1f4ceac81299a1aa34417779175a4bddc0e95ac68309da51e4f115dad6fec33a75d0c5520692a38df64e8d684c9304f9e2e6ac6a66d2e16a03c19a30efcac712aed2b9ee774ea28af4f37c45609464289de3f9be379c733d711875216bc223f2f468a0c9b4a8277bfe49c590ebce2e027102537bddbf2856c3b6e9389c4d1f5390cb0f346\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 36e1e0b44e5afc35d1e19e88e75f030569eb99d326721ced9bd7416ea7367a98305354eeafd204f1f8a652a8442eb0823d2e6644e6320933ac481a3709777381dce8a7c165b23aebf31b2ea2745ce5b352acdf0707234c824da9e1af98bbedf80e940fba00c229539f310838bd625f1fc103f267265ac1243855622c5df72c17\nA = 1dba8bd9d1e6cdc117a5a01b5046353084946fdddf2696f831a942d9db4637a5ee76b84d4ba63156b8cbc72e40559a2fe9b8e2682d8ba1db0cea042bb86f8ed71f6609df52526c42e7494f6114bb62263d36784dd55d396018b8fa47fa49ca6e5c76ebb0b00e6c764e36cb3ec75e3af6a2c14dee01fab78070239638521743d04f184dae79d49a2bf209ddeb4cc72e0c94a93a47c107f5369070ad95ffce034c554fe2a8391e67f817c6cab5b88ae9748072da5c9c\nB = -849602ea3b79b33af2bd3ef9d1250c507d332e759d428902dbee054fdbcdcdc0a357a51d00aaafdacd696a15a64cbbdb7e1fdb347be5ddb1f609a4390a6f29f79ccdb51bd1f0547d0d9a2780517f8753a906428fd236f8ee1b433e57f2810d0ad51846304a5729f53a871d8b0e14355d24d3f092e50de4f044e2b8aa14cd8a51fbb2ff36b0b37defa7be768c56fbd4f5169d9d4698fb9072cbb0a037c219552728587d7c35f27456c02020f5f9374b6c53bcf8eeaa14be51899d3\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 77eb3cb5277ced02b72368e41f04a35796c2c6cc1273f109336fdfa745aba7c755b6ff3833e9b124d9c78584f6bfda1c94273522f020371107870c288592b7c23964320729d2308bac8813586e72078119852e1d7706d8e15c195486b8d94358736869b15d59c037ba4dc8032ceaa31eac3a9e3dc51ee17706a6956cff8537b8\nA = -6a0753edddef8b74f762bf802d7fe9b38638923ee2d81bfdda354d40df4422e6ac43724de1715c4088da2e68b63c10c90b236d7dcab39b9a0ecbce57628f4c2950c79cc88a89daa20d7a8679232c8ce5fa30525c56011570107697222e0eaee6871adced52ba01a3aea0ccc9901cb3a09eb4db2f93aba0083180bb41f3f9eaae00fb458381213dad01997e9b88f21b0a79ada1ec3837ac2b63611455fab6839363b796b105c3be6106ff284544bda2a32352bbce6ef8\nB = 542c5fde65111ec8a38d76d8c5735cee17329dc41cfd0f13bf47e6d0e0093a129f3449db380ee9a70ec1e44640839ff18b950c8fd89346cb4701ef753e6ef49dfd9bd27d9987e572bf8e68df399cf945813582fa1d33e07be938a7729efd9a5e7d730bf61c537770a0727f6bb9ea6add5aac9267bf910eac1b7d92ab4184734ef8b1d184c292b2b4295ec1bfd17b8a2a2e4d315a8b37b8ff9bf6a1e94a4772267195c5a7ea6f0a0c267337fb97a023f1b50ad697ea31451192cebcbb\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = 660a1f378a23fc3b47f693a347d90640fef43add97",
+    "29d74546933f4b78a26968cc9a70ad6fe8d85bf28164881bf7a99e8b96683c6f4fb54162c144f99a27e3feb736f0d382d7e5b934cfa835c723191e5692b7672cf6918c4a7a93b24af00b1beaf1b80320b14cf2d1539e3376779872542406a5df961f765e59f3480e1cd40b\nA = -1cd74c052e62ee8156ba5d97f28aada75211979b1c5925ed015ea75f693a04c4dd0a705f6a723ae7b79958884c96fc07f81fca064ce2affc70768923bfbca6049952eea3ae048425b7c6ad1611ed4b8b77f7605629b9d198a77a27f25eff2f82867845cc868edee4ae31afc5d022b2ffbf43c14fa01bef8d7cd9d0e58362a0ff9abbf250e43ea5065512cd707791ea4868e95d8fd2357b3b3aec1a06888ae940751ceab01cf9e49015d42371fac30d48ef5853b6894ca83\nB = -2ac904d3632e25a4d536097d80a157791a6aca6eb10246ea21f4cae07aafe907c6e4c726694e14ce12e376c02d326f4bfc02ed539a5b4615a3cf5c838ffa52124f9b843598a3821cf9f1fe94e7206d6a525fad1ef77e7e77162e8c6d3d860d4f568e8f81153dc47f167860cd52c1ca59b15f1eaac6b9023c8b375bb63b6adf6972af8ca62b39f044378b11c4a969f3939d9fed5cbe18c06749956c7acbf963f640a1e1ceab73fc4c77463ee8d1575d018f49bf0f08161ce4f88aaab5a70\nM = 8e2ba940fc5165c6c5f7f4cb56a6fde2fab687651099c880d38f6eff2889f6a3b2a3a186d1fee05ed452d11ac712cfd30340d22da763af7b2ff65a3f6e202e8b4f42cf5652c625fd9913b4a032ea9448591b9a839b8c25d2323cc2d0d3bf7a6d15896aa85237b6ac4c9c9a854a23449e30e6a2b7c4a2aee199bc20d30af280fb\n\nModMul = cbbeda9c467ca801ec66fce801c6765a20148787dc6becb199a15c58fae8d20c1d391a1d9d57e1c74bb412e1b8f271dc2cc53c3355c83f3e2f00f15eaf0df735160a48e2273fd1bd75533cf94c5175ce67e79fa6c1422996fae36ba288a658a7a5422a59d39dd81ddea50979e933efc02\nA = 7ea551efeccda23622a1a5029e5525f46d5ccb83c28ec9adb7a3e97c2b7d936238c483a4a9bc92fe0e21208d5703611e2795b91fd5019272d255eeb\nB = 19bd92c534f56dc4235dfb7efff6d941112d66acf81b079382c86fb10dc5473bb8adebfa53ea3fe6e4df8412e7807aed029694ca786\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = b18a9cd6a0a89578ea773fbfbf642e05935a995a38bbd54480ea3ecea1751370ef95ff5ad0e3203613f0ef6833237d549676a95b720848c5e9897cda82642a2f373951d5746b559bae2d98ac00fae26e5957c61ac1de95318b1b1aa6d5c64a6ceb6575f1b807060f9e2a241e378e6ebd72ade7d2df18d5353db7737caf52f888\nA = 13c68e450e9e091ae45863f6c1faed25906dcd90a43620b1a40e7a506e7a954256bab0225f3678e7ce6c4ba6e3a83c8f04a3491d9bf097adbd98fa6e78\nB = -ddef76382342178fa6636e62887fce6e19590065c766b047073329ea15fbba96f2cf088fa5a989f6ee3f6a513fbf66f621c6ea6ef2fe8\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = b18a9cd6a0a89578ea772021f58ce74cbdd8c44a09b3937b198adbd8e95e8e35541eca26438351bfdcd8600b4f9b71616e1f16cee707c712d40da9a440681f8c8647bc90ba4c68b08ce4cbca458bebd5110222f06b2ca980a2e9419e71064324e8c36289eff9c67f6d5d011e6db8538a54aeff8c20800b0949fa42c38fbabfa1\nA = -6d7e88715e9854b435876fc9bb2d25218a1451efb73ad9cc5f52b2bee929530e6618a858000b3f24fa5f47b5f461c84eca971e38cda6e1f475f6612ec32f\nB = 49eb76e4614ac7b0ed3f534811a4ea6da5ea24be925ffeaa38bb228fa117ed56ae976b590d6c9d9a7a8546d8a6ebe4bba771d6587ac44f09\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 44f8596fc06afdb72a6e4f876b70b8d5d734589f41089c510b0da60ade642fd79cf8e705f09910912624fa1f646da596c137f124ec1a327beccba62a44f228f3c0977fda2af631e249b2a4de17d170df07bd812c233a96d17e1e93910267682d24c5c485f99aeeddceb658a7db258a2fdf73eb0266d26b92e\nA = -122231b14c249820f0dae625342415f0c6e7f93787b4206b79e9ecaeb09623636730810c7936e17a1eece68edc7c97218efb17c069bc59bdb9681a79c910c4a\nB = -3cdaed858523fd55553ef85d018c1097d7b88f6c30060d1e77b84821ca20b5625723c7d4331ccad1a70371eacc7f7aa11220f83f1bf3595650b\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 6de7efcfbc1e8d2cb14cbe4465c4ef71f0d1d7e80a1d80d9ac2d0b161d45fc9d915c54e33131591e8daeaa11ce02404c9b8494added1bd83e344ad4de7c04f626315caa56fcc5ca2ddd4e1ff064a2957afeb5d280477bf1f1195c7294d89049024fe821dceb53c7d270a8b4653e2fc0a4d8a3863a854bc3794753a\nA = 47423c4fec1eb6779fd23e3d4070d0a7bf9a946f5610eb469876797a39c58577242daef8c34926f6974089fc595508d9c573d0a275cbeaf37172f10b8c849a493\nB = 18ad789cf09e9ea182eaf43b28b4f2540e533f0fccad325430b73101c00e440bb64b70ce0f2680184aa8caea2f6f6517e9b80285fea8b61887a41e\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = b18a906994d3247bf8a00f20e4b349a500159d086aa863772e71a68f91af9d19e4c021843f8bb6eeed1df708d55047dc8faf219e00d559517632dbd1cbf4bda61651b9644481d052903be1970f04bb4ee8faab9adbbf858324e6cf5aa9384ceba655a1a107210a9497552ba8a56d5e0e70b0c757baa71d1613683707357827f0\nA = 122773509ee608cd9ab3ff6763629a18eae41be64bcfb05122e0b3e112db48c64d2a5a515d96a042850c1c848ae5fd5f0ccc57b273d25bd8d68568cb00bb17b1589c\nB = -af398208c01ec9700e332f3e694894c7cc412a73bde8a79e08764ded92f0d58db8056883972c79a0c9e0ce810786cdaa3629baeb9e5c370a5a59d3ba\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 64ef5e7063a1d95226569a27218e35e93d870a19a43fba9889a2ca98ca5c573fa56ebd77f1403b3bcad17c1351803a809c245a97bbe32b45e21768f28c5b11ad542f5e687a17f7811df6c8735e1778e94d9313c19fa32a6703af7ccbd88b489c96632d10eebb580cde3b905f6345a2a2b86a871b4fab36fa4b0dab9a6c1c5096\nA = -7dbdc37a51b601417efdda2516aba15827a40ffc304c523a47c544d5c0bba6c1367a20d8a6268a5c3f723b1b68de57eceabbb00d44185ec4ba7ecdce5d80456f8cfe7e\nB = 641cf85fcb5fbacd6214be4b7b06fda1b80f4683c21c1d08311f6e23a15434b42d30a51912898a1c46b46c00aef7ab7663ecba683897825a4b07d2b7dd7\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 370f20360ac844bf4275f78b7fe71ba5db6f0bbabfbac3384c04b256eddaf04725d2d57b31afa48f047aade156c34441b4a41c0b2146790a2e15d13b584021ad55965588c6e55ed3b5cf5c36b780a27c5dfb72678d57528ab17ca2ac696aed3d9abb0ca448d9d5789fe37e632fa9709f3bb924c4ce34244d239a940dcddd9c77\nA = -1a0cc5b07271098a23f01b3c0d47cab8b294794b74a8b162ff3b313fcf85ea81fc99433cdf4450970311e1d5ff81e9ba27eb867073ed250aaa7795e44ba8d4000e879bf31\nB = -308f93984acb78c5dac2426d9bccc2e3ac361143807c7d34c24ef8f8db5e68a904ac8bfed1edf3cc90d21c87ae4d224b8c46fa42eea77797f94aa848160fef\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 4c8f466d1d9829aaca1a22fb6ca5bdba885606b9264933ac2b4c18e3afc0c406aa71ee7ff490fcaa804f457096e44576ff8096fb1d2b3c68450a8bc36d1a2797ab8b621ddc91d75e7d6ba01d86e959171fa428a5bb1f26766f94a553c94f6dcc2e0af90d7776ed3d9fb67e842e88f7d7342afd86e2f5d159db7304ae4d204a3f\nA = 57e894e37159cf3c161be9c97a946454e43bf09a7ae8e1437570a86c6b06f84005c1463d27d726afd2e25aebb1657eb78957a9a12c8749049d12007a81d766dbe008aad6d83\nB = 16dba5cf077403ff4af47438f5840f65fa4e058c5cab3cb730154ae0fcc982ea097c6d0e75bbd635e97314f33ec7e31f0e41cf285ecfafaf36382b33d5e83cd55\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee6",
+    "5c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 29d13ec304f26247a45ab6869720720fe019d6cf370b9e2df9a65828214aeb4f8b17969b8dd54339d08eb99bbc66720ed78ef79033fdce6da33501fa8588af86ec18be4c4ecfe01781f9d1379865100dbbc020b892e77027d1f04f8171ca51fb73129dd9a96568904eb44e19f56f842b223724a9ffe28826803185e4208f0ff0\nA = 135ebb133a0beb909101da896e3aad7e26ea72b23e60802e54cc6c58a07b1205e2ba1fef6eb86c420f011b70e3f725aaf9fd1873b6e1c1cc7005c7c09e55550414875cfe846357\nB = -e8cbf3feb7be7fd12b01d5bd024e47538f434b496613320ad71f48a8972f687992f97e4b69b5842d2d6a4176a5701327c40325e98b27e4c0f8fee5a457d92181e40\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 4309b728306535bafa6787dd79e58324b3f86eb5409d772018cce2159f75832b87909a672b8b4b14342b352e76ec5a6dd66737cb0a20b81c5ce222133bfddfea878b132b6f9fd557133973a0b44aa41a01d54ab565d6b9c62da67378a4058255047a95923daf5f0f7adff2a3f06074ab1facd986d7d26cb475ee818199a390b6\nA = -7a63e108bc9790ab687e0fb8a1cbe1e9ff876e7b5eccfbc136ba05fed93412dbc2ffb1ec49518e9fb867429cea1d7f82e2b159b75bd40eb8370e8a54bf0e0ac0ff24aa3662774bae\nB = 51ee025b2ee8abf9dc5ebf1a4600131c00ae4b6bff966dae5c49ab5b9017e6b1abd6434736df6daabb2bde254022783764c94e66743dc752c9040563df7016a1581fe7\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = b9ddcb9ab858d2229cbfab87d87236e8206cf5e1a042eb5ddde201d56e2695a3d0b2a42bda6a284fbd2a5b2c2b80446ce88c024137780c277ec80bfa6e9d15397cc5bac98e58c9130756ed0fde58d475a033fd94b1fe0ecc6fd91a8b42177abf3f77e87c0847a4244b9fd4980f3b42c7c955836bc994f2babfdf9c5b43315ca\nA = -1f971ee9a7c966d1e82166503681afc280fab255665b850645321f67da8934baba1226e9efb59e0ac4483c8724f63556a213f2224b993e4e082eefff0056f7aa8a3cf5b655e0f72ddd6\nB = -39309313b04bda1103ca6f56514026538b4a29ae258a2a66424abe2c652b959f5c1dc4755ea37ebbfe404839505c2807ebe069c9abb9150205fe35bc286ca12b64ac46133\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 47555924c31f040619681d4a12064790e981db2c7853efa17e4d20f741f33c56d80862caf86bfe0730870b6c0afa9caf66e15047e60256fec29469d1760d5e9b77d79a84fcf7a1dcd0168a59f870f1635eb033e0ae0ac17bdb73da803206d48cfc1da48507cb812bea540daa2393321ccb0d88b57abdbf3a3bb765692a2c2ebe\nA = 754d78d5608fe8c7ed8e26a174fa27833a24c48d23f0e702454b7eb578cb107da537dda11027dd6b41daad329e036794de562d7623bed8d9b0e909cb3fa38d4d21a95c5f4246e0b030a32\nB = 1839baa8b8fb6575832136f1d4632f72f36cdbbdcbd00f197fff3cdb88b851cbd74910ef6d43cfae9d3248e9c85662d7fb596ae45a460feaf308823f06345bc5fae8823230af\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 9b2f026b11d0674e9ec060fdb24b45fceade3070db4405b363d53df1219a02a664882819fe602f430636fc0bda935b14c55c8a0bbcc9b6683417e3ffe7f5d58fae229122ac6e42e76899254295dc5a08ed43c79120a5e5e4124b8fa6048ee90836bd2de51bbd2c6b9b53212e913cde871f11bf32f91b3a78575a006da36627f0\nA = 11402b3b1a45d67cde9730062e38aafe1d04fb1f8bb1975f25cd9098813efa2727cb229adf9490267bd437220d9ffa05bb993e45d2f889f140faed3ac3c7b53216455a830d6edceb02e8db92\nB = -d8e011f18bde068badedce8106f6602429fbcac4766334a0101b57fe94603203a4a8975fa499d8a68198aefd9e68f28e68914f920eea1083e37c67d59476bca9819a8bd628b89c\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 3a74066e7eebd9b63a1dd28548be60573c95f29816f3b3ceef68a5f6bb797d7eb0b0f4ee612dca794ff82f5d7461d995b9dcc09649e2587639ea017865328bb5deef17b5283691724e8aa331d75c635d5e19ebfd268fe5471714aaca8b48aeb846f241c1675e18d35f029b132f81128f19028b0a471b3f75a530321135e35fbc\nA = -6c5dca3fb7b85573d1c8899868940794e428171e207b5f9f89fce4b7159236c0755e2959d870754e902e9c40dc1fddeeff6364f898ec0dd669283e6d26a612d9af3c3ab04468707bb8a7827756\nB = 5446269bbeb613e69286f1012ff62ea767965533624542f3b5c866cfb569d6193aa603061701992cb4873ea8b766606da1b57d7b37cf52f52bf85b58309387200b0ed36164f30d52e\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 2a4e727ac67451ca9dcba648050a085196460e4aa4836c5652de863c3e2a76213e0f590de3aee8639304c54a9dcd5f7d5d3592f647e3d07d322708e1e26329f4a31d66c7f2e9d482f22cd9823074dd57d14040a4f00ac2af9677a2c98d58ee1e094b1a8c40092e77eae454638bc3655e77441d4f218c637f95c147776f5bdac1\nA = -19fa688008a12cae228c6ac4982ecbc88da248d7ec785bf2289dc9103bfa3a91eb1e5fd6afe9e0cc035d3312e9ba64028fa6a229db6d0eaf8af43d8c410be7c689c3e557137ebd60d3fa04edb60cf\nB = -3e8c87fba4a41c3a84874c987acee9f560b9f027338b584a775c1fcabb766700f758c4d451077a9427257334a569037b0bd006375f71223add62eca19b1e26b86dde0cc251e48d3b60ef\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 52e4a3f6892b425b935c6f9d1396d2034eb0331cbc5241e1d745a9619fa0cf0fc521585cb9d6b1034c5fbbbbecdc81c757f768c7a82f6ca291cf5afc98500c579f82ccf0be233066730f738c205c3c188f94b878c11268871ba42a5d950dc8a399887997cef2b6b68badec1ca641b88d1455e6d97a2841da49df7eeb766b7be6\nA = 67df01e34a26e8239c8edc7ddfccc3850f39864ed237d4dd67588efbeaaed1f884105508f69e20ff6a5cfae1516f6179ae6fb515a66ef0a7d633ba4218c30875287ecd0cfeb5bafafc492619942f97a\nB = 19f5076405b3c81519c0863d0c963d545b2834343e42bb3c779788cbb46d89be3f775b62f4114268a0ca0e6af6c0dd659607d40071dfe7f1ad0df9a5c53b741c04612158de396e9c96f7523\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 8ac1d96abd2cbcaa8f7e3267b716f675aebd23694d24c112d202653979636d4d47e27cc36f850355cfc5ca16b78cd1848944f8759fbf6b03fbb7eb347536a9328a5cbb778a6bcd983081374a3f543b1380add14a9468358009ec2baa7ecdf13e7260968eea74083459406e8889936b2fb98c8b9a3597e5f9ca10b76e1dd0337f\nA = 1c9ab23ea37f324544280d176cc02762db7a39935f1ede9695b53a3ee2db49d0485c6a3742a3b5cfb51f3c21711bf89ed05afd0886bbf61cbd57b23439a8a165484ee8e4c0e1c0ca2b6478776aa2897d87\nB = -e30d28dd01655b7a419d939e3e7530258a667420fc759bad585802c63fe5efbb309cb502babdad0afb208aff5ce5830071c5a974604c69ee47f76fd87e2460a5b03a57ef0185881502625886f\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 5df0700adbd880a5730d8c0637a362a9d42c64503c3b9784046b946c2459a619b5bf804a41c92ed6370bba730c7d39fb2e01558f7ec38511b0449d6e9db8df2cece4ed348782ff1582396ca8b3196474e7e5817f8c197c44d771923b6e286e41e7e23c33fcd8765e06793169999544a310f2e080ffe13640b85f21a18fa11928\nA = -5c01fc52e86f3a344180bac284d2376d1bd693f20a46479c77fa57077df62f83b1e81c94e577d1d6733d276f9cf70555b20e3afcb97534e4e0108a6cce87e9292d78b2d7367ff15fb33d2c3289d2a2913b58\nB = 6bbc39283be06382ea91ad6b1630b38f32385ec90019d2ded7ca6fdaa39defbe22585be0df9c0cf613f6f146c71f901adf525336f6573f7f43e661c44b7097f110d4551e8c75449da8fd39201ca0\nM = b18a9cd6a0a89578ea773fbfc0767c8ab81",
+    "7cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 2a01005f1f387c4d8d24a365708e2506b044f86dfc011262d3577f7313a8f51ab943037361bed1858e021f8a46491a5c73284c666eb65cea1392a780219f13d7188721d7d4b975272293a5eef63480f30cc9618aa74bc51f4175246301a46fdbd34a6ec72d5974aa920be5f321a97b8f19c0ec56ba10eaf2e61f2b45f134b304\nA = -108bbd8824e8c16b81dfdd4dfee691e012e578cb9cc80cf050c0ec4cebf71a968732da36552979ffaccce6667e46c29144dab75132cb087681d5549dc5508f3719e129553fdc97f545d7ddb7d3a4fc575ea67c5\nB = -2ad4d4078c47a3c8f5f9b48e10d52d72349ecf0f54abc60bad63bbbf4d8efb185de90e5e1a686859e1c429e30977fca492aedbf084019e9ceb4490aa471776ed2e8a09151b37c5caed9ede66922b7ec\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = a1b1b2d33cb610f1b398e03f274ef39a583d13af14b79e6766859b9ca748237b481a3cfd5d490a073e82e3c53d3ff5cb6219b2b2f71927f27ab6f567547a22dd35fb5919e1ed2b6dfae4d536d6d44fa6216d94d26b33f52db06c4ecb29702588b73ebce87569639f786df4fcf569bb07d5379bf8b83743327248c2d71b5dec6a\nA = 5bc53b3895cff2bf7bf10e24fbdc43d17d277a982d5d92f17b9b5a2b9ed8b6104229292ef3997591e2e6a116fca21ad5d061ce438f33b7f7110293770f8313077152c7546cd522ef4054147edbe1878072b1043e6\nB = 1599b541c9809779df3ef40971e7a83f21564bd5d6596d51a3d96defa4dff41e83ca6247969a3dd9a746ab72ce21137f2d7ea015ac6b2ffa8a32997e8b821064d35afde3435b23e47cccafa74d5192535b\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 4fe8897417446c493725521c0ea5b2110f91a1b5ba236cbb6ff3f52b0036a49fc82274ca949ac2b592fa4bcc792114bf2f2a78a2cb44cb22c6fe7e4bee7981604de47f6da2ed1fc6a8eb32cd9b8aaca0f2feec76a2438126ae6f409645d897769a6d340308f82dbc6a98ac059fca6f903c5aecd668fa838b67300c654d4013e3\nA = 1717c6503d069103f10bb4b36427fbdd2371b30793e492e4161fe185b2e27469fef6a25566d6b46f6a7f97446315a22d1f1f662f912b17e71feb2c82411ed7eebb84d4f594deffee14934b75a845d83761f36141ecb7\nB = -8808f540521c20eefaa037fc5da782c891fdfc668b955eaa2e4edb592e027a964b4cfbc94c548d785d92992abe282d90dd137c4d76419926740ce138d567da7350d89f2e56772d8f5bcc9ca8d7076540fab3\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 8b9311808bef497d8a5d14f7d851567a196a051610246964917a1f9d4f4449357d2411ba9fd93983f6edd76b8a8e1501146b08b6e1fcdd97b6a41cf637b6ff0cff7a2d6351aa1ded93f8fc1cedc81879eef751bebfbd1559d5d0320595c79e3eb1db0951d7c67c663bc57a672faed9e14c7da6be6b0c6bcab3d4d515e51a0b5d\nA = -511312fce1849c3d177d42088e55d534f9f7096282916e16b041f66ea90e2cccddab5cec0ba8ebf0b047ccce72da349f420cc28ab19bc156c1cccdcf5216f19ea922698127f090e97444751dd58fe7a2c90197a9ab3d35\nB = 6a5cab5e322d5f651f798aebf43a62af772fa2cc379905e72d253c49be8193a07ae6164f21cf08baff906ef800e361e1cdf1604f454483e10c8b2bfdcce77c12b0320dea63f9ac0afbb86115b656d0198aa883f\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 665e16ba6cba87c646637a233ae04805a302ef4a10d79c5b65b146cbab8c9ccd491faa32937d0ee955dff7dd0ea3f79fa43c133021c8680490b91d9c1d8a8102ab709ada7508bd59042940b2bd3a4f8c195f781313e45fa8d3abda1f8e13b35811b638b2ab101d1caaa92188d2b75b2b10d596ab159583135b0d4d15fcd3d882\nA = -1375af024e9974cf8170801f4a709b4e5862ab7d18464077727bfc2581e557cada991e9484a1acf80182458158c44871e67e783f7573f214ee4ea1f1821a65068f2bbbed7575f03a4bba36b0fa8cb6dc58c73b100a6c4a6ce\nB = -2d64b6bd987d496a3c121e89f4b0c88b6ebc6e30fa9d47981b52862551f3b7251a3fc376db0f2d6daab6e6fc5ea8fa10b040d0dce334ee91d8cfa6db9648df907b199bb11b2b5c41c67d72b760c404b0451f70fccf\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 49e9709810d9f3fef159e5cb45211453e7a94878dfdece19af839b89c0e43b226d7cfd46859963c7ccc753350e74c2501131474e3b8e0edcda18583b0392ee15f1dedcb7144000fc7fa7eabcbc83d12983d2ade477b4687d75b723c1a98a951d21b2e8ed95735aaec77e00de288d16422fd259c665a08a34331cb99299ac11e2\nA = 4e550ba2fc2a44452f068860ce2a59230738a7a15f5de0aeb4d15bda8c61ee3003568dc5971e48343d402112d7a86860a7f08f5cdc0de21fb1aa064ee5df26fa23839b5ff6adaf64a4a18c07efb3582c2fc9612d2208fe99f8a\nB = 16f31365545772f276d8ac952506bf4033a884edf1ce583a63d8d9f6809e29d9cce3b3d227f839e6c09b459951465ab4570d2d36127c0f677fc0a63975801896f2fd17887ca16ff7f265e2e7adab1516ce56ee1ee9de1\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 89ca20a3fa109a65b9449edcc729fe97ed45a9bd69eeb31d4a566ec1787b24cb7a2c25b3f89b36fef1cb3645b17c69ac8ae243cdba35e17f5738b35278478bcc391add0b5ec42db9ec1eeffa63a3ecd2ac0338db57cde9d2eb9ca4bb1df84f1a62245c4e585c4f20f26c98fa1957df34409a99a18bb442ac14f0bd309266a35a\nA = 1fd8a096be30e4435ce8cc604ded337a3d9d2fbc9666d1893c38546c4e155315b536d1bc323c1e7be162bb0fcd58440915b053ca0d0896e99265241f2afd46605a2a7486e1394a07b23f3382cd190e943e596c747b6529b04bdb13\nB = -a3960a51af5ecaaa70146ce55d639005e9b6b9b58592441d5876fa71470ade6d1e2cdde17bb80532551bee0dbbb71a0cb24dc8a129c1f6e28920055d87e9c66be27fc4b425737f36add7d72e39bc83aabee5534637e2e22\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 654d9c55d4a62976670a5ecac3a6165734a65f1edcc1ca81a8c444dbc98c3409ac8c4f6fbb92f122045fef8b7971a276c7dc4eaba21f7be7495394053d4f9bb14b63fc02c8a55ad8fa9bb9aa26aca5c47968ea1b7646ec606f53606d5529ded83639984683b8a020e8ded4b2d9f668ceadeaa8160245b36a819db14e58cf2bf1\nA = -67abdbc70db183b8c25b0664805ada269922556bf15aa80a47d31f215e216673b8d59edfa10a74f3f09d066055c3b9abd5434ce95eba91dd51576adcfbc7e2556df95fd6642a3b7e0486a635ed5699eb7fb285589c887c8659a2b7db\nB = 6ad3e854ea57aafb8980f1e99ab9cda24f183dbbc513e1fc92d4e239077816843f47927bac28e41d3f31c9ef134b72c09dcf14e2e9677a430d43002ae70c577d9958341243030fe58a800a068d6b01fd377e61844f0d434dfd\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 74bb23f7b0cde7924ee52e58bc0680f151e6898cc1bd4a2eaaa05faf218b419a19ebf85b0219f924a26002f9251b83506684af659e5b680e05138432ba227977f38a479ad9d1f3cf68a86ea214645fc4bd1a032f995307e9c9ee432e816fd852655ef20214e24522c17799ef41d1eebc6e097b9792757f7fc43124c609ef9696\nA = -19d3e6fd6de9092cbea55d65154208a0c93ae409c3ee35569cf774b8c8b7b1c9dfdd52e9f408e14ea3153073ed8d92746474e524a903a45a882fe46af92b033f2c41eacdd7e3c1ff661dcc5349ed6bd1aa845eb1762f27593708aa185c7\nB = -3d466d29e8c0008ee6f402551e3d62fe044787bc9f243db9252ea97da9bb75f5be416def97f13cbb008fee77f2eeda672bccce1f36fbcd26e1f1299619535da0a3fa3ffa0c6fee82a494efd7407cc770cf46ed1b8b143f42790a2\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d4",
+    "8\n\nModMul = 197eaeb8221b431d5fed3d701a175abc146a9fedf8060e8e611a54f8da2fb27d2fee4539ddce1f3481e6a64435f09a2d5012540d6069900a332461471b22192fb87b63221c7822d3f2fcc35cc38feb6b3e49b5b0fceb52b0ccbdb4e1fd7b0f3eef3d582a6ae194c249ebc52f215b568712b3e50bb8e01c64b114955ebac2da48\nA = 7bd216d0acd4ee392258a7341cd56bfb0968492fe75da0c9d935713a6ac883525a4a520b5b7940b05e3f5e0c40372cb11b7ca193e93f0d3883fe5840e66346aff0f38829322bbc1f0a0e63ce5e528ba5b13596ad7ca19d20b2a7c9bea4214\nB = 1ed4805e53630b886cd733e5281f6d2699b3c79da615f4056120165cc63858ed2ddfcfd0af0c5fc54662aad90f26c55dcf70a30d04ce05bdf61028730b900587716e690dc0c6e02419622ab8c115078b92315e7c7a5ffe38c4a404a2\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 40f69f2d1660eeb6e1840164817621dc95eb930875333bc3f62a644ca5910c1080505de0d54fc9fb6404a61bb2c03b3981e558abf9e86f2047c3928599b529ef3d91c7ccd13c1d69431fb9ea3f02b001427cf519d9fd8182219ad904f47b3785fa05ed24cb0ceafd537311633a2e26c27e61be92eefb28a49d7f583cb6e072c2\nA = 155fb75044fc54a6ba6c46972e2f97531861b8d6afbc358db456bac33a44bb0545deea2fc83023c08b7be473eb68accf5b65b3c5d6af88bc6d8ce722c80d5d1527e475905226b01ab9d7b5a6557250cf8be935339db330df2dff92f2e88e80da\nB = -8c6016966a2cdea4b2d8625aa367e1d079638870f1b61e6b3c3a1e6281ece41018d2ce93684d1f0088d021107fb595390664c11435c6c0a7b93c2c6895217a89c469a37d3250dfa457b928ba6119b5c9ca5f2d47b36e60e4325bcb4383\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 9b9e6e1727326fea099eeb008a36539f3d47e3882b77d6089032b99c6cd36ad79fa75b7c19d1509b3ff022ef781b6a8c16fa6881f9ee2c4e00a4dbc93a49829622f4ce6ba9c55639656102d81167ab8a5e1fcf14d71caa60be732f1fbc71250256520c7c5a4579c3fdafc39356a2bbf2c7ecc526dacc0293c7578424c939ab6e\nA = -54cc11ea9806ef27911ba721f19e2ccb111045711d301863792f0cfac798758f0a29111e3a0f84d294a79721067f50858767abf507cc10ec9ea3eb27a91f06e7f6b7b4be7001b548cb7fb734166bad6739935081bdf6d35d58ef56180d377e5fda\nB = 7263e8b9a6f5387f44c55af64b64160efe97ec8a8159e723ca8977bc17c861e22041ea227c9c9bb467faaacfe352b03cc620eceecabb6db2db108b49c69752bd0cc61a5e998ac2f404ad052a51286ccbcfaa214ea8ec14cd9a2a6db56c3d9\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = a18a7498ac9194f600cea3d66615595c27a3efa7ea196ba12a80b5f608f85fa72afc366d23f5ca98452dd190b8f86031a9dc097f94a217b29fa676a6042a3aed2355cc8e767d464a8adb888491c8cb82dbec8f117f57c4a07b41e7e6f6cbd7dc25418603b1d1d865dd2140a649c9d52019ef39dbb6809d1b28b3c1ae64fc6813\nA = -1b663403c73e4a9003467ed12766f16354f79073ce89b66066857d19f3b42791eb360004d23e02874254bc6db54662717739eced153944c4776f334576746c5c4145b21a23caa2b2a137498554c7b749efcaf3393c5457b2bb87ee2ca3bef5f191107\nB = -21d12aad97a5c6e639a2ea0a82b1292aebd418567718014465a22b9ac5c8c927963a2a4530c41d5a7a6c14805e56a7092c8716e4767b54a393d8552c5d3c366b39fb3b8667c60e6075e9293bc938e407c53afdd1174843b76aed187f56bb4be5\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 1983576ed73d4d87d8b94cd3f70c149c0273e966176b85fbbbb7b3202e2c843bf1f8f4546ad7a4916ea4c731a22bd337b6177fcd2da8bd301f3af9bdcad800449b57986e7cbcbc7eb313d6512b2894c0cbb6cd753a870860a49d6a682c20b5e883b8c4839b3321aede51bfc42bca163a924191feaf05e196d8dcb7fdd9941a60\nA = 576759af0f02406e8dafa330babe9473d9d970bf371ceab30d2f98f4470f669e042e1708e2677d52cb9f99deb9b53f30727d16c389bb63e71e923475314b615762c7612269b5ad7bcb5108068bb5159cb8dbb8d08de2bd4fa4d9db6cf6e3f5997b9b416\nB = 1a4e34794747cf4aa626e964b839ac497b1357090ff63088f9fd4399312df894e41b395d17b8ca1806baec6115b1476912ca9c4309f00a46d5f7a52c8f640075422af06d6d6d796359132f4955072ce90e61b40c992a155b2bc31c262e753aa7d00\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 3448648ff9f7425937b6faa54551ce14dd15566e5d41b2bdb1a8db62037459235a5b9546d289cc2295b0ed584fab2e1a798bc25a0c114238f61ad3381a5b441cb67f92cbf66007c980db3351adb9cfd2cfc769b5b9b0bd1701425ce1ee8d4b9f438ce1207fa850aaa1d3d1f970aef874c2b2499a150d29c2ceb7bac375009b77\nA = 1fb54cec882c274b98913e76342a9b8e631bf1d381fd8a4f7e0eaef475642ab3f5da70ca2e38741bd0182a959e5e985f1e0e7d737beb8c725c9b5ea22f7ec25b6e564809601e8405a5b1362e7792791f55ab64a57c03a99a8518d7f65feb0e21be619a6a95\nB = -8180d172d3afe00e0423245f47591d5f750f20d2cedd8ba6ab6f9aa24f74498a96c9001a0124c4f98dbd402b63e71eaa3a7af8b0d2fa417fb1d45f64e10030232b9155169153496aa202745a432e547002954eedda7cc9c1ca76811bd902b192f1a1d\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = ae0fd585408a99643271eef575285a6261a4c4a92c1956b1ab436d3cacc8d4cffc07044e57b357ffa43bfa9aaea57824319579c5c3e2fe4dd48bc818178beb5fc1ed60afa08828657d00bb88894c975378b1dfb452a5b88fc3c1d81099644a998a47a497c8a2b12c444fd2a088f47576b7f4fa40f34a208fbc3348ce33e59150\nA = -7dc7dfb753c0bc3ab4d07d5aa78664a7f57d64be4d4780ea81e3efc967fbf1bd1390248bbe259da32108ad96bd8b39f2c9f118bfdc96bd06147f812af831288bb687e4e1742dcd1dbf2b7adc41afa28d07dfb8df8bb2da5359e66330f5c65964096a96b31dd8\nB = 756f3e407a3ae698f103fa37759e90554f38378a9b8eb38581e0970ec8f9c00f8392612c61aca5fd37d1063b78c19e3109f35c0684ce523c634190b3164ef06959cc42e2b77e1bb2fd50eb59c3dccdb6090beb809ecb0ca30457a5c5948328eb218e219d\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = a2aa4550e855623a8ed488bb63db8fa4ac374c1ae953781aac590f78a364fc33380ca2806445fca5bb9ca2fc7ec4db5819dcd5769e3b746286c49a7c80149e7fe276d095929e2cac6ae57e8102f7d4c96261ca44cb6f1601f429528495b6c3169e15f9babc5be696074d45559d5abdac42393094c450d6a4a45bbf60ed7847da\nA = -16d0aea9c752b2e6e4e13f7ab1f0a2c1776874967b0dfeeef7e00f8d9edd1e11d2aa702be45fffc284c47811c51dcee184a134b8f6d1874026eb51e2ec80c94837af4602cac3efde556ebfff578fcc56c00de99a43638ab68387ec087ee269ca64233eb5b1762ae\nB = -3c6b60b0ce4b13a5d6d9ccd67c76ec6b71b94ea7205e408eea099c7ced2f3a462954741d353d0af850b10ffede8ce0bf80b6893288413674504829793d7ae0cba53b163e3f26cd99beb0a9ad540f6d2cd5097beac604b1694a9a2f4c48b28338f9d6a63e75b\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 8a1a8fcb68c53846b3edae33ec070ef5cdcc1346ab3a98a116344e6d2810e2e3f60f0fe435fe7ff257c7ef4c122b3c34c776f4912a9621b6949308e2cfe2e0827536c7464371ce804bd7cac1d76c5bf8b4a6fd4ed56b65434c3fcf0ac7be543fe2d09ac01c564d7b9b463740dcdfa9068d4d8e33f29297ab452e6ec55c263de\nA = 7c4878334ccd9e20cb11a643b206626ea5d0b20973f18535cd8f0fc2f0325a67d3558e4cc9cceed0d88c6d2215c220b8d0ce230fd701502b02081e3f6548e58e02bc2e79e4991f8ef188a84b0a367758b4e534b72cd87de7f82a26de14fafd162a50b359574812cda\nB = 117d8b1d2a3e2049e6edbb9494c68a97145ac3e658aeaa05e8ecec4b090d5f467cde34e05fa7f5fbfa32f1d9dad70955f22130c358468eb371555fdf57a40e1df398c166a22a9df2e1f4e18590b00856b4f880f6629f1a4296056dc66a29b6f0f25490c6a8209b\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600",
+    "540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 2cd3de06953acb87b773b8bb28172b24adb283d6adada676f5f4548990827635c51506c85670767828dc5b4b91b45a7ab89a700d70bdba4e0355da32b52c173305767721d18dd2cb6c55f890611e7abc854277a453c7500efc4cd4fb8e6c9bb7a73fe5c77045e715fd35d415b3496f7463ec902cbdc18f9f6f67c33fd78c3210\nA = 1a20ad042f46330df937b879c72ef00dcf39fb85b59186b8e7a9d40723288677ff6ab2b9bce95f34f2de37887c8a9cdcaf231254bd00c7e25b6042695d7dfc05a11765120d1dbce29dc74f35aa1492ba0c5ee65114d9a246b57dcc2eb2ea4a310be98383fb934121db20\nB = -f8ec67323cff9d53499ceb3afd44b28f0538c39dae8c965ea27d645b430c2f8a4965eadc8ed864f2549eb636ec558419be71f986f4c5783d0dd5253738b876d9034735bd13b18fc670438387f84848308d9357ec2aa4f6a453bdd36ff08d54a6800bb41df416b17d\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 1aebe2bc35eb2e449bda63513b1bfb55988cc8e6ec8b3c8fed5ce4dcf53b95f1b438c41e3b2348412b35e1f734edba30273935b03d16efaede429960442a01849c352349e23b4af88de4d01e9ddb53ae900418d49a84b7fadd2669261a574557c4fbd782f8e8f400895f6a6c9679b72983ce01bcfdb641f5067c94694e9eb80\nA = -5f97994c39265b5389526e3847876a10aa3699e3c3762a127d1a9f892180cce68ca6139a6f71b235da26c287bd3e1aaa1436746d983c23c3105c33ed2e06baa1e880f1744d81a80b98ee1f16220940d721a92118a9b949d4da7d1477db8f5b357b3ceb7df34eb5f62078cf\nB = 4bb4f8f4f4c8e63238e8774ed61a7eeafb3fe9a6e19cffa648defe82f4846e3378c892d223957564fcce79596151658a726031a6921cdca0adf0f5325d858c048a6b94312ebfd19b803eefcb93bbfaaddef120ec3b8c366b6d978524d5c74218da77e4c3b5ebbc66cf8\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 5d64678a32c163874d1c81824d628a1051bce3b55c37055acc47a8630d3fee648df5d319e50b4c56f465bbf696433409b89c07e442425d3018a059ec757d77b3a40d516ca3148010036b003721ec9c999665915a3c442d95ec3c01c232feb201be08c88fa3c6b0769e3da30f1d73b66f98e31f4306bf4e23de78e74743b224ab\nA = -178d81e419f0473c426e24428caf25d61b648bbf963f7fb753ae15e5ea3706b53b00bfc8fe917ac9fd6c7096518584566ff71e6d35197f9aa25107a235678cf9ff8ae1501c1d5a15d2a27d39d066e169745e1e8c808209bcede0d732423d0c9cfbea322ba3201ebefc5315c0d\nB = -27ed464895b65d9518923fde5caaac0c72aad0d1b38fcb7827d6ad4e0c8dc09e119b8b98183f0ef8d5d1133f3f108e951caee035bed0d48bbeee6d1ddbff5864bc192b84eb8a500cefd223972ed51c7f720d1736646825f95f2f10ce6ad47a267bdd8c80f65d644df158d7\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 52dfb6bcbbc5cff46942d76ba45301cbff76e9b894703a6a7fd1af29d615336372d147c3932589affe5c6533f28d3e6a57ce2d3cd7448bbd81e09a13266ea31630cf044f654b87ec3fa3294eb65873964110fd42d86e78d128bead5f117cac98145051552cc3a86c193d738b973f866d068a8994a49df3fc7c7314fbd9805e80\nA = 797c67ebdc083f3c8b3ddf9847b7f3c2a39e35ce2119f746ec87fd5d86671d8fcf2b4f6d440c43e93f45019032e629879799eb58adea729d43d2e40ede6485143bd35979609a12faae7e4393879c40c0511c886c66a24454e4f9912bea944eaa417c9942f09ddfb227feb14e4b4\nB = 1a599d1cd0ab3614f50b71b93c999942bd3d4cbfe7900122d5083151c71d9e0c299bd927095c5c3291418424a7c12947389bd4e0a3c2fdf67b3f512094ec0ce5b52695e527de2b3804dca2edaeb1ea4b487911053272ea926cf2fb3386dc4b1dc268b808bbcf4eaedd21168ca\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 99bb9082e4537426c61f3b813f8c97675c44ba9ca418960ca6e2464cf61ad4eabb01ba00798463567ed3d829d3f14201c740f19fca623b1e9b57b534a65df0f070a2130489afae89b91003cee432fab11426c4d13b7721e6f9db1bbaf0adc0064b33e4b9f4b795511a0744b52f93e3db7bc9c0a991e4e122c463ff344fe14cba\nA = 187a8144a0045a92dcad94f0bae7285309ec8fac7dc864b08914e5a4dc3b1a6bb9212161a18c22682ace16a4bf3c03dbaef088b09844902a3255fd6adc0b7c6397dda86d6ab67204d8061c36ca20fd4bb348202037b249f6c110c31580148db46dc5b1bfffa38a683a27054c35326b\nB = -e93ff16817b725016279a32dac247961ae9bb00af890fb49c4fd8cf5e815cf98b58cfa1e3735095e6034c9a2f2b5d8030ab30e2271abb45b347d755cd9ab5ab5ce37950380cb306bbec42b6b8056793a0955bcaeb23e2d6a9548684030566eca2d34c458f224c8e337cb8e3c252\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 631f53d02c031f592b3dfaeed106160488c08e0672083ff195b22a2c0b006f11165a245acad6f35dfb15a871a9a2b45c544111f71f86c920b42fdb6551e56c55199e6173c00e27c9f47256349a80236bcfd3acd1730f823031ff9ef594725cb9429ea183a7fb2e03124ebdd98d435313e43819d995c4fe81fdd4ba718aeade94\nA = -72e20f1aa2b5f2c4218fb9e11ced3f45a218f4c83a2017d97d0cfbbf227c9082cd43f939c8909e52c8795cfaa75d80392d3649dd85ddc35bf1cc54ba389bed9e9dcf867da1c05eda080274beb6b868b54fc85e12ae127dcbfffeb043f9d59333d0ab3374c24971e1bc7269450b418c8b\nB = 61cb021a3a957703d14061c21d3b0fc19598e19a17df9d6f2418c76d4d37b3f62bd4037aeeb1eda37f83df44c440f5e49924cc72ec5b153856c6b621350ec89d98859d9d1ec7ac4f0c418c6599674322e7d618c5ca588d5a873d5af356d4771c6cd375f5dbbbc69f50b982b8c4d1ec\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 4654a62d9491f28599a976288cd2068d8e3228da12f645413a92f482efc66d1737495cd4a4c733f147eb5414a2ef6266a116ce264491a3463c9df1b030d83b315f76f3bef8cbccb5c538478a65092547b91e991e6be91ce4549c3a6e34aa7b466e63eb3b88054f6714083695c616a078ed54e1ae46e00f3593af845fcd0ff51a\nA = -1a342c154aad619e567fd32e7053aef8d98335a4fa0e35bf06acd7998c43d821de1076dc1fb67dfa1156d7ff30203ec736384a9aa7f5f08cfb302eb3a2a7179b2664094c2cc0df73fa05bf2af24a62b8e394fc76014dd83b434df26f8a67a624884a0b9b4f08f33e9828ae64f5d0c8cdc2b\nB = -2c57e15889c3dc9c94361c17585d506933a72fa954ce44dda9f5e33408552ebf49cae87bd0be35197f887fc6c7deca1452a4345eb67d19bd2e7d3dcf651667a8900388e4d5ec71e9433e3b01d2b3d91bb94d0fc3c51c70793f978e4b5ef93a9c6356c0b2f7accb9e4eb457a2174b50dc6\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 6124d9ce4de2880ae3811836235d6d89a1a4b710f1d5a517153ed7729dfb5b56b0ac10a4bbc811db9b26465f03cda355701f9f28c5257fe288743cc0789cc54a8661f46e36eec357580b00a84f1d4c8e3d689bbc18242f1cac30a87cb7a47ea06f80d7c5633cde4c8cd8a1a7e27acdc3a2aacd608cce9e2efe7864d41a56ceb8\nA = 7b48a9663d914e0225d7275e965d866ee6649d7267474d5336d28d54027ffe8572f4aa26230dc7abe9957d211e6c2c8f3185cae962b878cfdfaaf6cfe32058c299247f372ae170a1f7cf71380787f6e90995da9ca5a4be8ab1ddfa8e6e5dc65b6f168b9b8e29e0257e0eec853a6e1911b1afa\nB = 1fc4dc77f4a18d4406a4ba536e500aff68d133c6e7725717ae6537b527c6f40f93202a2292522fe7d04e0ef804d1a7013b04cd3d88462fba31534770b56d2e5672e8a6ec7a723186024c40b4717defd1433b9967bd692ef81d5d4e39ba10a3223d250ab6e71d5d253dd0a732ed386ad57e54\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 6443de73e1c826c90aa36fd7ec5d0c3324c42058b1c35d3adeda1685470d363732d23cceb08c3f973034c24fe65506bd33dc45d7d617a53048dcc103d3d1b4fd0534586c2fb7489ff5ffb98303bb068",
+    "fc14b1bb6bb43f763dca2c891095e613bb7b6920163aa6cbce8cd93d9d39f4512b6e0b28d361ae11cf76037eab4cbc819\nA = 13f739846ed2c3aa0a1923168cbb46f4f0a2f3942ba57bfa5c426cb4d4b3d80d9530405a31bda329a1814c560d54defa3e03fc4f808606a598607783d539dbb1338d5bc0c2e272a7ff6ee6f93e1665d6f5a0ade30308fa047db086646c763106cb875e014e2c18ff8837e4d4d86861b85a5b7197\nB = -ba019333046f76325fa9f258006a7c10d27e89f6d482b95c79296c07a65b8e3bff4a9c9fa7e5d0038da129390ac851f8c0651dcf655a3d4164a731cd20a701895c12a906c732906038a8e459aaeb293fda21346964a6d53fa3e370ebf43c7ec8f66229405095c6a509d0fa15dcf45de8d0e901\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = d3a6fdf4a26993edd175de9a0f012e1eb15a5a1c4dd2741dfc6d0f9177cd5645508b8ab09c7fb34066ba893c38144c7f2ecadfc2b0d15728b407e5db4fcbbaf1871580426400433f14dceac43d28f03376e791b7ad01a112981f29ff4b66102305f0ecc4fd134c2cdc79a5e9d9f085bfcb7e6c187980e68b6c7639c12e8d200\nA = -464cb16fdd395e32fdc613c63ab4768f8cf72a5b74a0a5b0cc581ee4aad1972cd97db7966d3124e30c9a1c80d85c46da2d36eecd7c3bba5866f9eab4d0fa55b2d440a311654466432c681372a80a7896c9163c12314ac51f652aad68fd9012dc63fae6c7673c5da8faafcfa1b4ed5550f2baede5cc\nB = 40389ba4d2f5fc152308c9e8a8c36258c770fb2d03e6189b96c4f8dee97ccbe426cc14595c8482e9e22486b61fc570f0e7aeddad2f4e3a480d4b75d14294a3b912928da5692043bd98ab88ece87a9bbd973ec82f990c0ae6091245318c2810187d69c38fa80e835300ed06c0723fe475f3fb22de6\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 8a0f9eff3a210912828fd7b5f2d72479cc9ccdcfd3e8d21739e301de02dd5c257c7ce4bee2def06c9d0c90d5a86bc45fa9f31e456d353775916b3d5684759e4500f99ca1f91f6767a5e2f4b735ae4b756d56c358a06447fa2c2ccf0ce667be4ed143e9e1dc627a561d92ae53a62477270a7944482cbf671138bd2a85fce92b08\nA = -1da555639228fc6ead68049d836d60a4927ee77472fa0ffd3c787d55b6067012560f5b1c2ef8bbf6119345dc6419444c675c1c9cd50602a93ba3718a5b3e1a30bc108d796998b24474cdad19bc2960b295fee97e03f2ca7589a3daf35bd28eb37a67b5d2cb35a30998d5f8622bd7e6b7d3fddd1ae9670\nB = -291fea1ae6dd1c66c62ae3a3d22904f4b4adb2a48cb795d50074095345d661a033f67b20c5d7231236dab871892deaa9458c235c342bc81457cca3f014a75f5124ff4da005dcc1108e75527528e5cc9c051a97fc6cd202bb9166f9e72e366bdd77c965a70592e5684fcaaf2e03421a2025ca190fe158\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 50f4d25875150bab63e4162265a632109d6b4743f9d6b55306858034732a4895ffb3720286acceff287c38320ee9945dcd0a1bbe5ae1456b7f36337cb7d22b679a6821a450765471257d52b6ab7d59a763e75e9e64581a93aa54761f6a760866d6baf186cdf4ad2b1a6af26a3e76cdc261d1f07b0a7122c8ffdef595812e7208\nA = 78a1609a7f08c93c9bf9090ca7c93459aef815719b5dde5f217567a9f68ceca05594f6ab17a4666ce1c0c4434e0f4f38ca1f33e501d6958a10da47211cc011da219d4373d2bec4b7c6477b1ab3b00b6c45279212db39bcc11d1e7ba49916c4271adca7eea531adad509ae119348f374ef1203c5af8bc019\nB = 152b46095d3f8db5e6e1a9e3f35c085da00e52764b261c3aa775ecfcd38572d2e86bab2f4bf29c2de4fd2fb6f35f66e8685714634e1be980773526bdbf9c43b1335c5d59f4dffe1a1fe2495ff9b7a3fae3e53e7c3208968e1ad1dd1dc8cf2e2415cc76dfe5df9e2e1eb63f7c7687d539706502d56247728\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 5a3ad8d6f1b0763b77f5d40169ff0013de638b459e401f50f4cfb505565c8a4465e28ca1bf988071701dbf52ac456e01e170788ebd2b7cccb50dbfe1a65a89a8aee18b3c11986c9d6e6571f964f376f322e10a1ddd9310bbb40f14b0680385c40975aba43153970237c535c6b0e2cbf6bec918a8fa26cb2f69e98d77215c23a6\nA = 1d5c14b0b51cf31e9d97b7c49cd26097d40454978663f8a74095fcbf9c63e533708befb1a467f94cf599a41220ce13493a273fc30c49275412c5205db712d5e1832b39e65c150c3a4b251e2aab853e4ecb4f00ee5ce6982ef9215775a33565bde3ddbd932665aae506941d3ee31b3f9e4ffc0651f1fb4a5c6d\nB = -93cae5dd84584a2a3d88028d6d4cec4146cc5e350b4d92c52ba2393ab69fc1dba96e244f98e2f93f31230904169641aff30dfbdd3dc5fb1f3489d63aae1efd29335345a79ded546e42f2ee4a70ed932699fad17a771ba65fe6e689664bdd1135219aaa905c962d39531eba3e82c3425c24041e17858cbbcf2\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 61211c706730a1b98c628b3c8cb070a42e2ccf9fc6302bb1c2960fb165087f210e9d93416ad9fa21634a05dd0723cc23b8d2a846ab7c3bc402999138433725e737102094db5792249b4b5b1514a416b80c804ecfb04653c5ab18b0a34d8777f6c2955ac66fef62c9ec2819f0e3c075920f951f86b32e02bc43239d9218580067\nA = -46c8c68f492d8f7ac7834f89bc76098146432c59b3301d4eb70d9861a6e24c7c9073f910108c7b35538a79de10640291b54e5755359baf47482b97af56475211573576e9412ee017dcf961a090a6ffb5cd995992ab68e3fe60b6186f7595bd9b8acf8695c4f7359cb2ac709f032fb993d16a74822b4935536453\nB = 46953f424d988fd20700ea08880e7e09ac22d60cfc294bd4aefe637408a3cacfcd0ea6822a679b68b665d6bebed3506d25edc83cc7154b83e22953f9d91157cebd219cd5177fede28c63a15710d0f92bd9e542a7586855bbe57a94c520408fc920b3f8d65b194af2b2a580c90db1cdb27ec26ba929de4573c6eb\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 50a063fff02f2cdc68edccc23976f4b3db99641073c85709626292b9475b9a988fb8509a6223f0a517dbae0cf7cd39dcf1e8ae75196d9f5008c661d8b5153cbdb9520c71068e4719820bffda4c393032edabacf99339e0cbafddb6042ef887b8c498e87e16b62417934015172e63e7457242b864a47aa10e203f47320f03c0e5\nA = -1740e8be7b4775725516d37ba643fc64203f3a61e6b0164d112af56666ad97afb0059c2c4981fa81d72264f8669db4e50e11865907655b1f669c88f5935cacf1b12c1db63cc84507af12cf0210f990994055d04d93f148f213e3d4fdcfe9dc42117c059897697914e3e3fa8fdbf0eebbbb9c3b9fdaa7efa0c9d5c93\nB = -226308f8fbb35b5f9d129c0f6a2bd3e5c272a408bf32020905acc6d02d7e506191e76a3a2ac47cf7a63e6306b256f489ca5cdf76c7c3eede175ee4a7acedf922955e92599647b69d463cc14f2b178b88cd471b8a1c1512caa66b6d5fd8840b98b8d070e6593136e98cce9643e006b714388768920a79944be36624f\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 747cba0d1cde75dfcc0b2af9072c5027986b3e3917845870c73c452858ba21d6d1615eb71ae1b5a03ca44e22845d5432b368541b52a4bb02498668e8b99dfa2eb90ec1948d90564e6ebc388ee9816e329e1d8da0d3e2b12d901d47e22e8a1fabc37408be0f89e7a4ab0f30a03f7e2ed817006809e69c21104d0efe548165f64c\nA = 5fa76e37aaf0eb3d34d4f4c590e02b6c63fc62b1d4c9e172cb0dd82409df87ecb43a1680a2764f62d13a5e919db2db08feaf98d5cb92a859dd42bca1047ff57b8fe5974fb3ac11ba2c0d8e2203750f30650db4b2cbd31d07fe18c4df84a0dfdb30f9e528932c097e89d8f8be6ff029dd970a7d2c2551529455b9131e7\nB = 111199f91b3749f8cecfe90e9b9b6951472cb701beb39d63068c064cbb2a1e1d30736026f781836a52ad0d828be6c20303c6c0bd03ad664dbf6044a5bfb67fc20a049fd37c62ab0795d836487b883768ef7c8f427eb98e5ab6621fece77b4955822f8efd190c417ced398c221215b50e9532a869eceeb605fa1c936554\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 646cdb3ed472a7b4599f02329054846a8da173000eee7533240ade4dba82ee3d7a6a92baa3783c19dbd3f76fce6b5bdd83f1f229b1c71a6faa18602e368f1b0b9f8c62bd8c854844af85c2081924c9a153e27853b2a48147950fb614028e090e2198",
+    "e613631c95e565c2b9b64a43237fd4052089f9d1dd2c00525dd35fa946ca\nA = 1c8438247c0ca376f508ccef7933724df512f9e0877596f7f4ea73dcd824809bbc472749833b537eec01ab23656e9758da22ab8a4aaca1aab3fe8d2cffa6672ca0c44ac029c2ca6c3e71780c28c31b5f154c8dee782f6ba009a69d83b1a3a03a2d6275bb8bc3932a1170470fb7e405ae081f4770b535edf49f73a12ba589\nB = -e365c8edbca8dcc4cc11986a5a901e4ed0adbe89b0ab70a53aaf5821862432a1320cf1850b515177b630e12692cb025e3aa43e9acee0d8ad5e48bb15e9a3f34cbfd39d285127b52dde58751f572ae68ad98692899ab12d35e33652c4426ec60c5029e51f7e32ec3d2031032aa7b6b2b63f84fb0023c81d031773f3652cd6\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 7a3e22f4a3f7ae7512ed73a07abb5ce291bc90bad507a5ccc0c17185804b9d231b0ae2e72bf270dbd60170f34b240f716529a449abea0b3d98ea2890a4ce3d9e2214819aefd070e00201e9f271de925c4ba59651e55174c97a13a30197e46997c6c2b152548111aa98df120a617c54b71f8eb8b0c8b4dbd5251f5509fdb8a1a8\nA = -78a99d206b4f095847e9a21de273aa6c47034c9afd4c081a8e93c2d75f4ae5b090921ff5108c863785c413e2f7b4a361506fb66b7561b8b1c5cd537e90274bddaa4e91ce74ad81c6dfbfe1a34a631dbe455d74ed9d041a9183da3bc469bdb214d2ffe893f89c3ae30f8ab99c3aac4d2fe864b891fbf4f537745fddcc60504e\nB = 5c41274e9590c1ea44c113ce505931758f2cef80ba3b10440941ec9aa2ac984b29868bece2922eaa225555dde84a8334f1caede99091165151a39538e5b7390e81df757f521236314239c213e9b874e396a022f04629c09bfaf929a0e9fe0b0c7386b0541446f6a2570491067f64e662d8611c4fd6d1c78a9f3ae69f34d14fc\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 7fd27b6549494c9bc860146a3e8ceee785ca03faa94b0ce0a964844e7871e813414cf3f111da49fed1ede5e71e5539f34173d41f9a17ed129016bb9b04c86487f5def9fe350fd4dffc67b6e181e3cb26378ea15ff9b9ebdf1fc86c072c82ecd8bcdc241301daf1b774af5f90f37e45e6126c5da7dd3753a1e5b366038af6ae31\nA = -1930548d105661dc25a5ee303b61b559c4bc1f2e28b2c40cf3e25f98dfe01a7dcca0f3dead6463b55a5b2e0440a651cc9e08e125535e081c742bb3b2f8955ae897909cfca683a4822896d8a4a7073c29a80571445c6a0d53d2efe4a30a79d2fb5d08c0f95b735a1cab17ba40d71b054c9270ba6bc870e58591fb1bf9dc9b7ee8f\nB = -3e2a4c1509494f94406e3843c9446edaf0a6060144637234c6d9ce84d70fac54ed163d77d210bf557bbea0404922c8aebec67a0475a3c7b74bfa2f226403ce987c705c712bb8eb0934c2b390a173c3836378fe71a6939e48d187b27cc7236ac115309fbeabd9ffd0396fb7fcd6d46a1dc683606c757ddc3212f5d2ff3f2e450fc7\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 2078bb5c82a394c30a287aedcfdc5271eb3246be05954181ae4f86ad2880ce674640ecd55c2ee3f4e89e2762139586516a28558481303e3071cc9ccb9a538f887553bf5726f3849fc41ab027fb1c680ce7dee3982587ec71b3760e5da6956d6894ad8c4526d8de953c0e681ecd44883a21f0abef1544fe601743efd3e5eadb8e\nA = 40b4ba1e977825b7accb941fe0c0a49936a8a47429dfff53502fc0680d705b9fa0efe003eea3ff0b649998fdbae8d0831bea7f34159aa4c7add6bc7cd56fea97d25fb9a6a10f4572c26d792b76c18ada19b0ba06b6142c420dbb40d66be669b7c51d8cd2a5022fe1a8aef7b60965c0176eee69c32ca5023782c5410adc1b15dbdc7\nB = 1bb2f18d7c8d306bf80ae1901115c8dc3d286baf537b812ce06d6872b61e5bd44f3c53d7f31ca8461b3628b255f85338cc325856fda5a6248b7c476532c1bcdf9713dff9932a50e52a9441aff96092d3fb0fd76046a8d88288d0cd55741083a1bdb20fc6e9c20e82490273354bd826bfe001322dde9a15763f2c0e6ffd2cf60019aea\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = ef21dcee9eadceaeab13287d6e3c9741811f6ea9d5bd111799ae05260b1de2ffbc192818fa45dd7befc3baf6840e3b9d24cecbcb2cb1c3d653c4aec6531b941d926fb6692f548cf81526acd0b6b0289d70dd11ba50ca8de6e174f502eddf47e57440142c7f74f594a9abcb48ce1873df057b132ccce8b364de3edf411089d28\nA = 19d0109e0c47ad45f57b8bb8519265a4390534d2ea07f969d84ad33556518b6234d40d1631be3c3cce6d59b7be14750aed114008458f50a6a84ff75b4ee7e4b826ddcb2d2293842ed29e4e484260a92199c5c66367c402bdff0f1a8057127c6ffe452498bb352802e0005e6cb084663bcfa82783a3d72f3a2a341b8075983892e86756\nB = -81fce71491eda139ed996f6a289dde8635a3a257ad6756e844c768e66746011fd797658184fb44b0e3f3c5600c56238ac7687b5be42529d5c9b97c3ce10f3219e1e451bb2dfbbb44cae0828ef894eff3b52b8dba4c115c3b471984441045f2c2db426cf5f86949d5bb7662cd40bb3b3172a19ca3fb6858315d688f13c17550e700cd5dc\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 8a5f90344071790373044193cc4fd92116248aacf05ce639b6aac4461ec3ccb0805ff9876ef44fa71088c295db14fc820f7ae2c0aeeffca055f8f7238c6c90db706d02f2cc43b4960abe3ca4b6dec8bba55327b958e75c60c5d1f43fcf9136f12481c267481a725eecc403a16aa6221346df680560ff316a63ec8b51dc37aad6\nA = -7a54e7ca04b9a22e2b986e72e634317ffa20f6f4ee90353d559db3f3c1bc6b3b92ac6b364f6c5929090373962b49b59cb5d87554387761164982955470cb45dd00c4a8982dbaae3a1ffe700e8903a4a8e4a21eff9d00fa496d475e0e1a205be267499dacecd31551f8a9d437f37dacfdf5a2754f0876a3e02509b78674e7ea2169c43f29\nB = 652001f073d63ddd526abc957bbb48ca74154c8f9698b988178b3313dcde9acbb19ea11a935184fcbcc31e0117d8d2ec695ac56b5a71614a12cf90f21c8882187428755b6a5f11c314ac8b952ced0f65db0987f0f87e20b82a811599f4160e65c7418af7f33604e7b8952b70581e3e02dafa025cecda970d04383ee552abc620dfb9c5df9a\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 67f903e0e5623258826b681506f3e94cc0b086e262bafaa1395294aefc9f6b6323410a44427010d5e8d8288993973ad9939199b85cf02ae0a09dfb69801536a3fa6af5ac373add7efd25ba5fee6d8f040e97056f9f6fbb45795c0bac94c51ffeaf496710b00bc9ddd8e445261d976168771060c9bd9d83838a84ee9428f59d6f\nA = -19c695ee3a4ada840a7e3626e61047c5081867b15843ee9a6506ce45540d23ad25ff23b72f988bf26ab8b98363d9a2997773604f43fa732f59a4b16ddf3a45acdbc7976a1fce01b3dd55559c20acfbb7501730f794bc45fc09b1f035d60413bbcf32a83fd3c41599049a674f165ac5283c42aef213d777ae47eea960f7727f5758146efe5bf\nB = -210697d47beb73f45207340a183a729a1e78d84bdde1c7d8f80bc84559c4aa4572ab0e6927ea175acc7a268d05616201cb235e610d1012500c8ba9351a37bd68b4ec42227bea55cef5ba7d12ffb180873ab9d33d09e6e969df99fca728dc12dda6903169acbad38388fa9b001edb09056a2ee2aecfab0468822bca14a4bcdd3a4122290ec5ce1\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 5fbaff0ffcfb2330283fe59611ef51cf045bc2690e31f2ad3265046fedaa990b5d5060b3c38f17bbe8b2696e527fd77ead8650d329c2e0c1f3b2f5bec4dd85641022f3e0ae6f66ce98cde1a785bb52eca796ae45c33142e8264621ab447cafe988de926544e1a7036710128c42fe8b574f7ad69d830894237d95a55d1bc7f5ec\nA = 482db04e35f9fc1d87b42bc5efe25a049ed924f816e1b0f9c8ebe34bc771e67e26d6057563fd5d5320681e1207c0b0f4b7df547cd6d5be6a2e0f2bfb088f990b0303d0ef263cf45681e0e9a1147c29f2ca5251faa633ca53f6e0b109ba69bbe20c58a76a22789243d1acf128dcc936602e832a20a2bfbfedf963bc1027650f483814d7f5e6905\nB = 105aaf563d4c1d436c6a4552770a527776f40bbb844b7701313c5ada95180160e7cd4b7175ddb943e5a22c910585dfc184b52935f06b12c84b6431395f28af2eb9ccfa66b2ee8f40fd44d753c6a83d67a6f3fe3658fecc7fb2f4a8f357c5d244422e48a33d0e2971059695a59d0d39b235d5194e919facbae7623ffc92d771532b6b0cf771912c24\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0",
+    "a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = a9d204c1a497f350fa1300cbaf682c947eaeba8b3aa0450c1db9120852a2edd2a0249dedef3b3746298ee42834d869e9f765ce987a2aa4712a1f35ed10d0f7ba9cdef938b073c3a526e5bf45f3510c94ff1fb84bc77b08e2aa50f5cc75e2f4da37a8a711f8aed5e92f7e486877229cb4ff2a4d0755029972323c0b51a14fd1e5\nA = 13fd3d7cc9d6d6821d2f2b1c40c8e070bfa85b994ee8f3e0baab544dc71328a1a57b7ee57392ab6d24bd85f9ea0f2a312148fc4f4b22c589e9a265d97e73c7a5b420bee180409ec179c438a67abf37eba61ac76197f3c9ea5edf2d4b8aab91e9bb1a432ef1f214c043664a51ceed1f2854880dd458ca253f09d6f6acafafec310774a672d07147b1\nB = -8c90ecd56d6c7cb129d1c9c26e94cf919c5747450542cab52281d11d8fbfcf9ea797b29588340d146cc40e77dce007b68c0c24356d4b75513b75eccbef6e22a5b88417cb6c516578d17d871e7d0957c09795f9a0f19b811db75d61c27e1827fa2773846857fec020f98444e307d3e52af501114b962ea705cb0cdf815109054abd00810dcc270d7bd3\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 57aef35a3f5388c810f576dbc30d4e4e5a39248b319b7766311157179d8bc1d7ef019cdd8c2c0175a8424abe7b33565afc0128724fa38f0900140b6f96bda2e78d7c803124cec8c2f2d6649afde4030c76cd33394fb386342d1ce97a4ecd180872134fd4e22667a687915bb4fda21f7e0bc9100ed8cd3a6668ed3a235d7b15a8\nA = -673bb11795d9d20a1e4ce8ae71d041705990463964505befce5949f895fa31c92d53f91fbc110df4e789b3f3f01f184c55df92927b8b680cc92864466ce5590ed2e98901cfb78b32ea79bf68b57a14cddb53209e08a7f430fee23f4a1475fd2640a515f8b609e98c760b4301747ecb61f1e6209b07455f1c8a7bb4e20c269e17937f39c6a2fb7b2990\nB = 46beea6005cf96a2acb16f37e357bc8975f4dad502fc3aefb4666344dde456c0ee7ea43ec493b6aecbc7aecc7d4cd107aa09e874ff564f5d59d7e12047b048c1da1faea36a7e2d02d0567bc4db41b54a75110626d13597db698fffd577a5810286ea8bf50625296ee8070419345fa269a354ca2eb47fa3108387f6a4b2c0ea3e779908a14469106eefc14\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 5cdb7c451b2950c9d87638857407276959142958b06241b2010a9f93625f9106f065798f79ce5c534b9e5a31fbcbfc63cd200fc1cf10217096aa0194acb9043ccf7ced30d9f0bf66e0dfe27ee2ecc40bcd8de66fe2ed6f8cb0d874ff7b5fe71951412731fe4e19c34bee64c9312577b9e7b2ac08ed15aea753a6cd3e286192ec\nA = -1eee9d5d3854db52f9b43698e05d6a0f1d1f8df5f32884a775b25110309c46ec5c7e112eb64b2d7f948868bb9670068779b0a78bfc7e17860ee02692ec6790222b4384b9bd7db5abf29c46261c10d95f503b821a4694c45553e0dbaaa977892b916cb8990ac9ec29ab5c3d63ed77138fa1e95f395b3b233d039ab5daecb0296203166e9386d1071c61cb1\nB = -34587c2bf3473a2c5d7f3399d5ba2bb09be8105a0b9f3d8737d67b03d8b91b1c869f4e223d6246abd36d99d84052ae5894e58288a614a0da8d69f1aa57428632c2b059ba99315ea2f68ee210e65a741e94125ee4a723a7828bcc410aa2dae06ea8ed6cd23f66ccca7e85d2e071055787f230ee405e50d1519377cfe0cab4e5f97b6cb893b01134813a7c2c6c\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 95d0b209654de56bd7d6f74afaabed2cbb3247f449d80511d2d3c689f84c9b79587d78abdf0eb37f1b89f1f8dc8a83f7f9fac2c8cda1fd3fd64e16f5597b7f0a1df6da6db9e828ce7be0e876012bd52f5a74ca73ff8ca4611dd9f342bf77b485305ac28a1f8ac7538169f2bf3e4ff4dc5fdb9dedb97fa743fd8ac8791b8e288a\nA = 7821d4b65d529c30b8747e184e450cefb11b5ac5dc77905e6fcd3df64336661c82ea68d588ba616d23df485ff0658fb3376d5276027a40b392f47219edc5ecbf510cf0c5b431b02c65e5f432092f941d32ac5f71ce3496e403c7637f63a23b91e3326d01d2d32e99e0ab265108dc5e7919d3983839b3c7541848dbcd420a594e850e587f1846951852ed76d\nB = 1adf5c428f2a95c27a943637758d5dcd7ca36592fcb9d52ac0b7d27adddad5804e3edef257aa51c716801ad0c731e13c5dd000f11b5ff1b69c198f236695c1b2f99c0afffb5d084f80fdc534de3b0df4597404b50c7e784c3c55dfc9753c414d145eb0ca4d07e2f65b63f3eef8d391250a5500ef64d9bf963d7250d6906694e7670f92e3d5a7930f0f85964a21a\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 46914b197b84fa99addeaf55dd803182083a7ae34d6d4d3a55d6272af40a600563cc8d9f6b48110d0521b8b99751235bd5a340b1743497ef1cc459dccf5d6da970c4c3103c978ad2d513298f1fb3e68b24a9c7b0795f47d8f7f6ca9caaab9a9d80f15982599d764f8738217f9158517806fded5f3552fef8b7dcd2e725ee04d5\nA = 1c9f5f2a0d72806dcca92dac1450a50cba05b5dd571c2b3b988d33528d90ecc83444e3ea8df80802c30fbd5a6ec2ad9969be73aba6dd27e0dd2c842b95371d7547768916c0cb036964d041284cd323c8073095b2a8cb8797add5cd80f03595de9d18af8df7dee0d250ea7048faa47ae0131ba3f350d82864dc95e5829b88eeaf2681433dd4d58b2c6f70426af3\nB = -aa1e1b3cfd5ca0facc75e46d872584d55144620f849ab05931210b4e1526f12679bbd9cf00efdbd8863970e2abe8fc9fa7bbd21afa9e364e3c9e32f51fe66844fea4bab7f3b1bd278fd803f6bdbd0d296321e67751a0b894da338ab431871adf1514269ba05e0cea5558cd5691920fbc18237914f3dbe4b253f774e5dc1dc57023c080a3b90a004b809d237658ca1\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = ada55d93c533716ebd8c16e23603071950aa714deb942ebbf77206753d2676a7aaf61673c03a4db69d67faf6273828594d85e3c8cbf38460fa2af603fe9c1b6ce104854e7281757b26589f079da80685aec153fc5fd1a223004cdf30247f8398b8e92899857dd199d5d5c32412bedbf9d55f20e52895fc1dbd04c84cabfe1264\nA = -7d22392a8da1966e6cc5ef50d7409c614f8c8f8e5791778f68a00b4a056d0002707933043d05e48347bbd4d0dc1b6ca32a1aa4bab9992e7e620263283eb68d97af13b90a29c1b7dce39ec0b8a63878e8d65aebfb3bff4e67129e3b3725f999f1ec9ae92007911f2cdf738499661c5b6c9bf27712d0f29e871b17318e95c3d14b2e472cf9e466bea91fb71a493b2d\nB = 40279eefe59f954aa8c51c9c214fa07707b1d095f697ca40edb820401a45c472d1d7bb413eeddb64c14ce6144b4863fe9337ae4ae8698db92facacd6a56f3b33129c5b608eafa29e9d92dea620113051b926b80b75f320d7ca3d2ab597168c68774e68c47670458f5ef2ffd4604f20bffcc7817eb09c9057fd9989a6786a7e067ebe6724a89e7d1580f94ee4ed502cd4\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 4dcae9def5467526b0ff071003e56f5537852cc0bde9d86eaed2c15e36e6429c68c061e12d321bad12e29626b5013c28f118ee59624ae2f35d2c53bfd89e6afdb6db79f0321ad5c55cab03e6a1a97ff7bd58c760d0e9fd7507de987ed2f94f9c79569fe7f03652cd53c67ebc6bd3c9e6c5672891a9d2ee11b300ed3b19753c0f\nA = -127f5ca6924851faa2340c4c8f425b1dcf41b313c5c2910e5eff8ef2faaeaa43305de2b3a65a75fe54c00fb30c0ce3e8007db1ea222521190ff1de6d0cf2e777ed61ce8211dc167bf115a77890d0bd1ca786e967a04f077c89939ce484bbb1c560f669aacf7756a4338d97cbd7f09a376d2dfd4d632bb451f52c03c05762f050ebbf112f8dc5acdd9b631292fd7073b\nB = -3bc5e9c352c46449a9155b7ce5478c771293599cd2dda58a962010f1f21d094aa6bee03f9311545e8dc6213f6aa73c08b55bcdf4d1d84fecb9eda35c83eae5fedee75b2d15a003f8a82b2b788ea19f7460fdd8f447d973c950b3b250a3022c19ff312ccdc86b6ab50c4ba627b15968c8a66d306bbdae8e88fe28c1853fdfb3fde92353f46b5bc448ae42306a4c91202f03d\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 62a812e35f46e04b3afa7d26c8fd4eb168b6b64cdc839ebd0a46bf2a3a712af8e97380cdf0bfa8a274f7b73e887bb4cc73c6104a176d425aaf5352f14ee51ba549a6926bd8d059b8e3826b174385d4635b0c36df75a4e7da44c34e51eb82322b34ae00e8c712eb75b3882822bce5a2f2f5fd74355319ebe1973284c690bed2af\nA = 71c57b08127a956f0c17fd3c639bd1923ba19bfdb83c0cb9dd78e62b8fe4b7e0019cd0a6b73a334c622118f96fd6d91c1e06d4dcef8a3d0d6bf8f5beb",
+    "6389226c50d14d3947ce9f24f7e0e6a7befad2e4e92dc9ed8fbb9811d908c03ac074b2a5c67b67831a350c4d548ac70810bb5617d261a045e53cdc48117b9fe86d35950d0a181b73c8cfd35edd31af031178523b\nB = 1cda2a51a707f8c4d2cbff6337c3f63519705614c26a489b545b1faf366b705af1d953701b568a684856fd3186c035f878788f7e5dbea16b5e7b6e767cf611452a4272abf2a9c5e72b7251a1ebea5098c60cc5bf649cb70980b97d48580967ffe2913309b6b78cc12d91025ae403928851902dcdaaa60f5b323a1302a5ce114cbe174e3eb3c2fb5eafc44076396c23d53b028d\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = a9213cd809d41b6bbfc2123bb84860788ce22d5b91f8e24fb616efc286a218ae9652b42912a58bf8ce596a1b48e4c72f27e52c36be1940f7d2138eb895ee36bbb917a59f73e0b6c3266bf4759ffe2ffaee3f6179492658e0778bb43c4df4bfa1a46300c9da496033142ae2c1e33333fd7e82c5a14686b255e224c51aecc2a590\nA = 1cf4e2d5924510a5fd06ff4eeb94a740e430613277149993004b8de1a2b96ada54b05365f305e896df5fdffd3d7bcb54f9a9dba9689e5ad498012f7a684d083c31d7017aaaee720bbd42382e526a35d2add21d9369f7faa41dbcfe3dae426948a402635771a977e19d5c353ec7c1abd279975f2effc0b7bc19990154b723f2f8c29e606581ab9d3966702f68d8bb8065e9d8\nB = -cdab60f9b8e1add4c54427b638ec5f76b30654d3649b500f833b2943bf6cd5d8647549657a8ff999eaffe413ed87e06267b97bfc1b77637b57f29039235548a7569fe6d4bb16ae9c6cfd38c0b8c73aa60797d0d69b03d5a98314f7f7ee25df8b896ecdfc782cf8057f038b6c3e79c99df52f839fd4eff302ddd1256e51eb31cee24585782a0439da3db2eee79a58f889d8847fe2\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 4dde3d63aeeee47441a7e733bcccbd4f2e495ca3c746468e9855177f7672d5d82e51da8e268ac24e8971d802e25d842a16a6b8d76b8e46a7724108c02d38a4830453408ca5ced7093676a1db4bf4c94b9b7a9531ab7c26f8de520bafe4431a55a5f5d8c7576427a0f5bf2081b998b82da2e8e959f2ec4d5141b55e40bf6ddeef\nA = -5770ea0a75ff451fc2c86d428f2569884b2c88cb6d9d407cc22b191849d389f57a5765b83adcea21c350b37bc6d750d4859f547da22ea8a3698a5cb6154b946331ae2ca18e7eaace951dcd49405bf8d8a716f7762eb242b8bf5e4c53a662c906c3be89e53ddf7a706ee2406c7d0ac17b54ff259c1bd5a092325938832763ac4caf0232e80a016cd1994441808d8db7e546de3f\nB = 7e4246ad4af268695a51912053ab6628969af4fcaf7f1e97dd977984a1604e8c9fe6b920f39a764c27d89f75986a4bbc122f92ccd1860f24677cf346474fd9441f572f769daf834e6a00cbc027e15d6aa7ec2030becad41e1068740cde82abed768de7e2cfd325848f6063e2186faa76982b9ca73ef22434a28bd2e3a5ac477af50f258140bff938d3fa02fb904a8ee0ef3c1f6fed7\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 3d8bde8d0625fc46dec46fc657c49c8ab12a988cec4ec1c24e6f4d8ff94514c8d8fee4a08399c6bd23fb6464a38bb5f249591456c283325e343cc289c85df0ff2c1707a6e407ff7a24383b66ab603b75e2dc3835ffe9274eafea148f20764b8ca30cbe483c1cefd51f82dfb93d7793b3ec19a57f2ba03d884f345bcc3188fe28\nA = -1680dd51d8be6069c86ae157922d55df3b58ee6f53738677bcf7332d6e7ef304ecc7ff7c5a5e1f525459d77202f3e815c68f17f9a6bf358654a92f9f9acb252ed8e9e6a849da7491f26d0e33900541ab67ce966d042607258b4382b8108729a703b429babc34496528f198a7e0f814db80fad4900fbccdfb64908febf5e09805d3a3049c0f164f0bcdaaa9bbb06df8f05309be83c\nB = -2c6c6b3c89f6e1d1cdd9abd1a9706e4f642a25738aebbc97cbd60e1f4ad79b419dd54bd14f2bd147b1d8e9bfcf92faccee61a43dbd1a2c084bf06a2ca476b3d169fa2c99794fc827b7f4dd010c0534e7cdd03d00456033ae0203b78a7ed229afcec2d1cb96892eb18898bf53584dde56b4316b3bc5186d97e3a9edcd059d7fe14561eefe4881beb8519c1cb7c3ba22cd2e13d874aab77e\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 5b4fbf0445807c8feec7efa3c2bf8dd86b1070638f3c87f1e173ee980412a28847b263a266506e70381aae919ae05d306d3a67a6c1e72c8ccf1c27d6296526e87f0f436c98fd1391f83440b58fadd4fb1905a484bfe8f516661e7176a268660387fe6a7266ef02e5fad91ffa69247bb11cfc1b5c3a88c76b7923a26f8a31ece4\nA = 65fe4d55bfcbba2bbfbdae831aef3dc8c8746e1d04cea174c1d336974d81d026f562225b4a297b1c3b044ccc5dc9c830a805a399bf26c0369b52ab0dd2c0ad19e723fcf9f5de2990ebe5a1266653195a2aefd9a392fd3da8c22c523a362f195babbbf5329018e3b454221b3e77cd0dee79f612f86332b1d104aeae7d8d84ad06b107715bb76bce20220d1340ecfc666b2bfce812814\nB = 12f775dbabf1c112523feab443f6e95d773e8220d66fd87bb7fc702588136a048e17ab6845a9c784dca275cfa445d007e8d8383740b156df7048650f89c5ef1a84148488fc405898f9e326cb8052f626c8881abeb70f3a0f52dd83e3ae0cb82d178cbfe8c393449caa2a87e7c8e2901a87e276b49b6d012f3cbb65641add3694fed3e3177777e78fe375f3a3b378091bb8d2998286562faef\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 4f0af7cb0c4e82d0e6589b24b55528818bf2164d41f58505a2b302a8f677df146f8077945dad3790c323e19b37e3379eb95de8abdadfbe4417f8bf8da643768a622ad4898513fdbc72d3b1d2791ec9ff40634678faf0e17d6e0851f08c39405907db85b74937ac403a9a3a1004013c7bd95a585728010689fcaf63b2031bc8c0\nA = 156dcadeca94985ea8bc0d1378daf1e85ecc4c7f8b6d6c7a5cb9f9ac368a97c07e381004023bc575691c082b5e9e13a02fe813a55e76196e4ad4b0f9b1e089bb71a0d5c94254b66e3e645fea25d69bbc5af266e730482a60105306d664f0ddecbd76d54e7235979aa2d806b809b3468078b5d90aa22cbd2c441198d4a52f6259972cf3d02003dc39dafdf3581638e56d08c5181d36e9e4\nB = -9a54586072d093939ad86df11fcd3337ad7e9e478dcbefb2b89d7555883fe8565abcd5b0a9c88ab135ce5327b2a326db645bc7c0e3ce24f902544675ff9d946abf30302f123aeed0f4e28edc72758ffa760277caaf4817a3ae8615784c81896d2404e2cf47c06b09085cd0ad1ec46cfc1f04d0272eac29e774b30f19939d08c036b185983c93ba15d1d27aebe4a357b9f6a298acca3940d2730\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 7c3ac09486a6fb518b98a9bc8a8b382bf2293e2c1154470ff7961212430fe2dd28697e49256b1ad8add082ee27b6ecc016b120e971665be801b720069d30c0a8c6ea4795613017e8883e5c0d0e68f982c328379d7a0afb7825c553e087b33e9d78f90e0b95a6597076b8ec2c1d375e2143bb778c318ca0680a64072cf9a4fc08\nA = -71d8e7ef13d63b4f417c01ec1241020a8ff4c9b2db531500984fd3e45d22b2bd581894c8a248ed7cc345e70a5698407df8f0e4ac71ed2c0d42122a4f92279346f463aed899253206786928a0eb7c37f2e51e1cde7f97cf9288d85c3ed7f49e62af0bf9abf062d2c6544d83b9d3438b3881e0d07b1fa0f2a4446fd43ab3b4f81fa2cdaff199c87965e298943c68cc15f2f3f3225efad68b73\nB = 64d52de221f102af62ab1e9526935b005c81658f8fefa019bc58e641023fa785798ed0dff8f7f999dbcc2ecfa47d5314ac6676c82170d6f2b18122c17c1e1ec1b9b54e333a184a46ad35b2150c8165f0de19a24b98327715e5a641c1b6d3ff9d247c89c8749e775e6fcf5f967c6eb5e73523d4f1ec12db7321b14398f26201a364e1371f0ac922781ee252c6d2b3c657ef259ab73cb7992a370598\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = cd08b388ffd41d0aa29a3dbde74106c57b18d325be8f446a2d9ae95fa4144037dbd41eccd50fa34096984cb11bce555c117c5568d76a8f79d308ce11043fe2413d37d6aa60c366af6c1da93d525e4b2d79fc82c0a53ed62fbf72c919db8a3ae11f5ff8057d7501f5f6dfc9ae461c308d21919d0de9e31b759d1d8e3526fee58\nA = -12e58708c30c93383cfe6e99ee3c5caf1900a7e610605706e77d8f428fd59db2884f5021d7a382cb18b75ed22528961cf43be1c700c581ceac3877e83eabd860583e6e94f3f2989c179ee5047c82b53d37054c9cb7ae08be60a91b10d49510e9f0b90ddf89f93790c3e18cccad5a9d223c605a6c567550e2b4950e184fd97dd68bf30681d3f9c585365de2cadf36a43f5a5305dae555396dd50\nB = -26ea5079ba7ed137a14d00d413d6f818e911cc",
+    "183c88764de4d91d7a9b4cc7af3fad703142dc7905992eb8bf489f6d8231bdb25603ddf3c31fda8bd9bc4d78835f9ddc1e6445037f05125cb1ccd92eea2e927297e5eb915d5d965a25e5d58feb8d79a890e6036c80ee91e7469d9eb672d7a8db68905d06f5981fc40bf486575a067d35cf14ceee3ccb79b72871bf8f52b92e4910ab17e5e59ab3ae6f9\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 34714506322dccb91308c403c267f1ec75f80faf3cc4272dff4a84c13eb1e6133af6681387006c61e7e087046b64e7ae74eea8a3c0564a7c1f381e1c940d92b2c766fffdaa7318d07dbeb877943a73b50517b49e5117778b8a60212284fb92f29a9f5304f8f537e88acf8afaf01fdf64773f988cfa9551d6884baa70587ab76a\nA = 638b7c549ed14256956bad532945ef9e11a50313172965386635a2fc7db79deb0cb5c157e9854117c17f1509d505d01a0e138d2e510dfcca45b4f7ec968b5214a6699b61b8ac68adf64d5394f50d577a154c013612090e2045462160d1f552592197d7da78e03491ae284dc9faf643805f2674af8652bae93ff230fc3eaa833dc62781e5f74d0f0b90290d51d481b0a94ae6e972197c6e84ad7ae\nB = 141f62297ee88ad527fd1e0e09d9ab5dd80e17b32f34a674a27b00d719839701664ccca1b00da2613396cf633b0bdc4482ad3a0c3e209eaea7c22f33706ae44155f527c9ca4e341e651760d1c39f65d5e99e649d013730d2502b6b65adb8a73e6bc734b7d879b430798dcd53fa6c0badd57896cb566d9f1e0a7b3a9161e9808e762ca819330ce9319dbe7f49bd663a9f57ac53d65c6851dc7bc4ee66e08f\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 7adf54c77eaea2a1743bc5011ace45b7651846e77f90402297f117d8b1c0377f93f49e92a2457f3d3debec3022a96c74c166d01b2279553ef518ec0e612bd7b382529184640c55b89255b2679da9cf370913351592de39f804f1724de36db90c045fa644e8ff20627f67d6afd4546f00d7af093f668629f9a06c07fab5654ac8\nA = 19c491d5b55aa25f2e18cfb7fda18ed4b020e3f63244eb9f6c4dfa86eb8a70875cc898e305a7acdd3eee081300edb3e4c837940bbc1927f5ed9f651e46581639e133515457464e9c451390828e5e7e00a688daaea74620363706cb69e02717489ba9ad05774c424c18e295278caf4df4ced80b4cbd20cd631df43f2e16ec0334564d9dc03dfbc7111e4252504fb449d5a25cb13630b7c0c565a82ea9\nB = -c3f765349639beb80f888d9c8b7b335ab46b55064ce2a88180c80ad280c6b7314df52b7e73095dfd82896e24604854a48121353aa1de663eff07882771803010005905896357cd5a56a59f0db0045f1aa2c0b5626e132c169abc64b9893f95932f54c1d8cc25f215a9ef6e4cfdd6dba85f6faefeca81793b2258ae1d1427e81e458482aab87f6563abf435be69a05b195d1eda90146a8cc92748ca6f798b10\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 32ba5fc81a7747c3d812cf036bc0edc49f08824d53b91a65a6d41edfb1651d99c11ccb4c074d7f04e652276ae3fdc8d6eedb72c6e46cbb1f7f4070dc9d179ce3e21a3826f7dd2c27943a8d26b192d7f5c4aee9ba0647e406133e3e89c262d37cf468aa3ab8c5dd1b8900dd06cd600abc6d372d9408497d9e20c86a9a6a4ad9d1\nA = -73958019a5a52357b9c1d954c9b14f51ddaced32a4d7b7c95730697cf90029564118ea168d23a54381f7bbd6718a6b662e4c87410e48ac53b7767148582b0bd6a3d35f488e7fcf2b128e0a58b5d468dedabde4d624f4a82e808dd7b175af0d3658c6df1ac0da6495bc9a8dc012f8de55c2003da9b2d478e1a089fab776d99026684026968fc309dae46a6ef2412039a8207c3084f96b4e38e4fa01d131\nB = 4330fdf00bc6d13ffc267073b68aea7419ebef257d63f8f244accb9ee46edd04fe5481292de69d377ba6b6304804ba7ec0a063b42339e6e37867261b9945ec705d3a0029c6f499420e02a773476546993b3c5e1efc2417f51afcec7145a9c2625496865c11636e285d4c8b053ffe66887333c51a712fe9c8ea57606103fd689dc88f1fe37dbc33ae4e92067c5bf51b53e2f8205164c800e5abd677c73949b00ef\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 69b850a99b471003a56931f7856da357a2254ac50ed81dfae019c9b722b95af16047a0d5422cf7ab66ccd898e85caf0e03e74cc8a5a413661e5da483b3f0363e63a7031bb30626c8f73d6e99e290071094b7fe5bbaf4d303192e59acb5e53fc7cdee78576b51595d9f7a25ccf3c7f8889de68b9deec167778ca27ac9d4c71c3e\nA = -1976b3bbbf92acbfddbc05b5d9e7b62a7666b239c1e6270db7ec6dc2929bad1024e745b897840853d14cd815aabb01aed580e1cc66ce37f9d1cc4c9bef8ddd35d28285faa29f2003d2a4623ead7d73302ea9f380f16b3fc06b7c2b8bb4ce4c8b03bfb6056a61c620e4decc6048cdda5e2d3ed8a13b779b8829e2bbab91e9f6b0304b1c08bf8fd85e0f3cd7ee72255e5342e077ababdbb545d7f809bdf8145\nB = -2cab554f7a5d21c499a1025f61e6c81ab0fc68a874bf60470cfac57425a451365be62c380ddd31f6e202f29769e2b6106868da7c81522e03fa6f0704522a5f8bfadbd007bac65595e149f6c585d7fc022db016bab32819049e7547bf85d4232a7fe19084907c528e7eb0434f2e5a375ad9b7d463821bef2f6a721a635252576c176ba42519bfa5d97d0e47facb4426aea0d755507dac81ccf1537b1003ddbb0727f6\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 2ce33adf34f2249f8a2d2e073976cb4c78b71414e027657fcefd56fceb022a06c1969dfafd519eb9e2542662c7647102f5c528734dd005fca666be57b46234123bc3db286cfce07bcbb399eb6764daf2b9aafbc2898a5ff43ddfae849c7549289640edc4ab7c4b9fcf5e159623e5497f509ad6f0270a41fd864c9437302ce380\nA = 509f5d5b160e923b4fdd72f4d522a713d780daa4bfd10ddbd62b26497a2e7925c495afc2abf0ecfcb7980e588f96c4078bde51c7b2c19d86d15bbdad5de72fec2e0a284dd693ce0902b40e54af87ac5a5df38ae6d1d882ea6299fbe6910121ebfebd06b454ec5f855bf3e7cd544a4b0d9a764428662e824e2a6185723534f5e6ad829734347d240c48c2c0f8bd6be6ae8a495a9e383fbc7402a4096b8c2c214\nB = 1a3b7f55307031609afc974857a6cc75821e73a1a9535bd6b8e141437c3fd4a6871c904e22c5d9289df7525ac69a0341d3620bcfc5f04b38ae540e26beadbce0002a8a8bfd0f6a270007e4c52aec2fab11fb2a831b9886997256e4b7e7ad3b0ec64c0f31fb0d637869143712291f5073a5756466d7c82c31e08e09683478229bccdedc2cabb7e426af9025185d8dd5124e08afa4e981236180e0a390004adb7918de6ba\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = a81fcf9a18ce476a839c896cc5d9b639fb1d74610e2f618c25310147b57cd77806c2aab90be7be4ed10f0122baf9b862b141ee8e4be5e0c23ea776267f14c31e50b119bdd33f2b41f6a4c43d35bf6f095864593e0d8c0f1fd4656d8371af844d197308bbff14e5a28b7181eb6e6a2b31ead7361e287f3b4550ab0484bf7baaac\nA = 19f1ce60ca50bfdf8e02313f1c9a45496720a2ce467f1e8bdedbb32525d762878b61476989c7f6ae8dd29c983ea596e521bd4cbf74dba4d505dd9ea5df423474fa9725d5b65f1575d26ead95725e2a59a6c8a5397ebd6b54123e42bca44781b84c014b8e5d2c1a86cf34d764b242baaad5be285cec72ba8ace808058a0226c04f95eb2b53a828d0ac41e6b40e5a4c4092788d9f7e988752f175f075d545f421205\nB = -b115a1101d97664759538d22154de4b000c008e551e2ab10ad05f12274b10a4cbfee762d232df5188fa1161f37ba61d146e8b95fa715d98e016da8beb0600de65216cecf8b8816f6e7e73e2a2bfa7d0bac74b517b906bbc43357fca69de9cb5507bd95205515b97b3a4d6842f3d7b09606cce1c7436c462f49dd05e915d04ab6fe2748ccaf025bd5d19749cc468d228ba43452ccc479c146ac6d781717bb9966bf3835dec\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 1473f092540ae30de595666beb33e430cbec42d7a28d4f7982e62f58025cdb617cfc33f1e5ab93d2ebefd7345561b81271bdc50bfbb0db6381dc0ea023ff7c72605da26dc7da2b5664d2ad7967426ca97b3745f82528964bb68e70087e14dcf2d71d30fa0d1f7b3f10b19b357e7053fdf22bccc5188c6919eff1e5c402b750a4\nA = -68f280cecc512d51ae534f30aa198cf7b170c346c1159fa9cf158d0127d43e50a8d4704ec54b8b4295dd7f51c6771cb5767fe0c975414cbe6d2bb58ae66a095e8832d5f443498b1ade1f5bf249da58595ebd878677b34e3b4c99ba6124e2b71d86a8d99727a16746469de51b0a61d9d981459a6cebe206cd36a09f00ffce7f532e2c31999847ba000b9e01a4b84f454544b6362a5c093b9abe9d583716f4534f2d",
+    "e4\nB = 5b79684387f18d7de6eec3a63d737490dc2a46c0616ec16388dca2be60adcda11ae13063ede3fec177171a51dbef430f8c4b3f6d297b9d6c020fc44e3ffab891d0d751d033fda813861bc067c181118dc613335ce89c5960f952e5fd28bc72c41b7b6e374ec29b837f1e00271cab646c794579d315260921dbc3b984b86d98b8f8816aca4f16de50657e4102f34d9e29ec3a03e0da06e70f69952339bf2ec4a7e74daca82239\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 5e4b3f4aea7115d592bde9bf7c6594fee77372ffb19f7745b4de878a4024f81e8290c77d2915424df20004a7abb64c214104a3123e7c8f230c159ccb99bd937521b433dcfb065b186a685fc40f9166bad9380a02e297ffd6a307ce8d2c8f2f1330447a9c06c327b74f3cfc2e98f3351a8b385bae855941228969d1c29e9da3e4\nA = -11c1d396693139df5bd91825c119d1241c3f57b7ce95b46472dd82081738cdeb0868d18eb7c8ee7808016b3311f982adebd5a2e5f4e201ec4a34f3037d260fe580e771222de5a1a67947a4552cc03c5c59f9e60e25063a702ad3c3aa43f061a22567f938a91f1dd697c3e3978fa11ab1d65030bf327f8049bda745658bdd4ba8f3e34b060c6a2c6c5a8be54c7cb5f6b106f54a37d2be9f674f7747744d4350b3acdf373\nB = -25a65b6acda692ba3330d70dbc3ea4dfe208c0df358c50b7872245a909c5ac19ec568b1a1340e1a094f5b8e7d1e3b7e04bb4df002558aefd4540135d62d75bd5ce959128c1300b9d98429d7369610866d98b22c345e531f2beb80b042b6ad48da077043401a82e223e9e529e7407bfa466dd2680973006d047d837c26a60cabc36a7ef538f603ba19f8e923f168ebfc3834df8f77a559c9e0342e33df245f551bb242e5a66e5904\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 47872b544fa0425981ae17bb450ea346135e6ed7a9de0572ae14a6e85e8319f27cfab778cdd8cb5f93b417d9c66ae0fb7bcc6652620f7f3f74acc2bc9f2c090129fa8315aeec9ca7adc5356484474ee803883ba4695d7bc47c87eec508d16a15150cf3f757c4713de71366e958d6af045b2d282b6ce96976692c80b1e0b6f846\nA = 7e8f55c040862f12d8cc6e506608eeca65ce38e9e8ab18ef7007e3cf0f1c9a0696795bd10f8e1e1f55bb4f4f3a35c2e0ad18289e250571ccc26a961f730346efb1e29fb143ed97cf72deaab19834fa2e98e9c12ae4cd23b9c5ecef4a04c439f7d42e110b30caedc4334372ca24cfe4171ef1430528f7b57bbc823fd606fbd30915c5817e6c57c967c4c404a0847b1455da17effeebbec3f9357358e00001239aae209228f\nB = 1cc00b95f6bd3abfa697400c98110725a7e109aa9b8cbbe9ae16327c4fc8e5bc93afc7a94da32e98e85e4fd5eb545192c73007d97a4e84ba64fe187ef61d17f0941e165c9fe64c7b8054e24dad30f92b50d1f526b4bb031e6b1b9058be24884b170a145212273c51692b71bc57ee53176d8702b975bb6ba96284b462da2ce38e12d86b342c7f4d3cd489fbce88a309c7df1121d7bbbaab6814cd1e54953e5cc46813ead98f02360372\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 5d193b085e57c3f1e825cf3b36c8bdc936c603136bb782a244b04a79fa713dc7b08436b85ca3b483d2e100a012d6430679b30c8e4101c8f08ca0f9010dc0f27fb37be842054dfdd99362e03a7f55ae58db7b47f694bd35d91a58975ae1f255c41617e773f91c2640f768bc702a213f073682dc761e056b34c57edd85585fe04\nA = 1bb1c759ea94b61a1721ef5680f42af30fa31444b27591a03b7c9bf5b90845ab965339f463a78bddedcd62fa21197c32d6850c61bae195f86e1c7a23e7a20dc618c59ce3a1c6ea6306c0b01b11a36d0fadf8214c36a133d689438021ce7c78b20c85256ec607360cce14f139513d9f3ea6eab067b1ffd0935d7c43419b93ecfadf2c5a902b7c39a69bdc023173bdad574adc77706c1a666d66f69578a5bffdc7cd6eee28ad8a\nB = -e8072c49cea603d48f20276df188fd2fb28f8721d578220cef7db1e56379c04a6b372e56a047cbe59ea84ad026adc5d0aa930011db63bf4959f15781e060e0240dfac0e2a2c26be12a21e5650d12140bb49a2a8e0f6a86e4b1eb79d9b8aab3202bfd339096529170cfe3e0c18263128686bd9305e92a3c43e1523f97d8a6a2707773e3d441da162a79089c9ea1e094cd5a23474121188013c8c287965a5e77599f6a7d64174b06cc165e\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = aa79c899c2b9518857c9e4f96523a44607c3f6a97d1f40d6474ec79deb2feadd955fe92d789df4d362c828084559fab56b5e33a971abc5449208d31671c7e220c5945886e33ed1d804c059a8e439a92524a785076f9730732bc5a152aeffb5b9ecf3a7e4b55983016355c4c29827496fd4d7e6532c270cb9ef263573e4c63074\nA = -41b326c2b86e7ac14a2050bff67bb5bf9697f02594789c4a2b3e8455df4522546278d0620f28a680f6a88ab545de5829305485422f4e70a5ebf0ad15508dfe3f16ac556436d8fe8a8cde83ead549d88e0bb24dee52ebbb49159ae71589d918d3fac8011cfc3afad613ea09173856b7b79b55a2e43e0f7cd21eb9122d5f6a1fc5408414f5aafcff863b870c67b740256d317a0c58af9a81d8025a086a1f3d79f7408d4bfa06b9dc\nB = 4730f03c389f9bdd92fd864177e06140c9dcc02d01fe7d37b51d44de140696f116d11bb67adf7db797edeb7c304386a7f5e37bfac46a5462a6d4c49b1bc034c2e0dfa56f14bbd2a4bfaf86bbad4f6d0dfa13c782fe680847d4b43373d7137f5c2ebe4ad58c695a7d4c407bfd888ce04abaaec60a3fd33db10eaba6b6acf0e16cb61d1beb9212c2b07921bfb5595ef1eb389200b356eafe8b5288d8f0e2cf252b38301de65190d56bfadf57f\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 23f9850dccd2af799f18268c3a2918a69019513c55268faf2477c50677fce277d8ce58a0cc06dfe389170faf5f0ae13ffc4954c746eebae66efc14eaef2c2ac9001f3c7ef7e32fdc31dd725b6a8093e33daa6d19808908e0c2d3e7c1c58e0fe9ed92f4d7cf3cc222393ca4f95feab5d34fe29116410a1882dff7cd92acb87590\nA = -10a75953e5fb9903411869a2949f8f04144d6e2d61f95704ff55a02f40c4f283add405353a68bf7d6acc1b8cce738f0c6f9271a538b4c688dbeface58eef0a0a1d491a9e66958750db97bd01466edfd245cef03bb6a3acb81acc63c38538e7f15deefd15afc422a8641c357c31a069258dc0ebb63f06094ed8fe7d4d420246b40302361967c81f0a9ca542fd1de01967514ff2565de7ae3b4a200d63feaa22fb99a251cad66624df4\nB = -351242b6e6d0122f7120deb8357c3bcf25d221a15f83579883bfb4dc2e6099e6b7b95fd08f6e573d93354b0676f7bc9fad563d6eb0f3567ef43efe3d874b9c7733e4fe1ef491043e1f80aab6094cc9b9c236570972233ea74e8779a6eecda23a65d08d878850cab6005159265893dc0f66920a12c26dfb421ec326a1ac09e9ab8085825c31aba488af02cd51f96b205c50e692dbf2d844ff0a989c3ba9f1c2bc7f2e7dd9458a72d310eb28d490\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 69c7fa326630d7de69249807cd8bc55c9315acac26fed3caa3c8a9c6b51ee96a7dd0b3bacd5cc13c15f199e268c5eb91d1ec36c085f83b437b9906caa6e39ed7bf09778610b621426cc8d36d96f541d0bfcc7693525d33e0c2ecd77ccfe80289a11155b37c7ea7791b5c2be3f9b954e230c19d746575afe9a1a3a9677d23c5bb\nA = 7cb78ca8e5d903096630744c85975719c16333e2e44931956d8c45b001d35ed4e184dec88c9e2167d2f338fe6f25540a144cc419590a4ac7caedea3bbbc565365d3357baa62fdccef2c5ea616614e0bff60e81916eb4abde0c9725b1bf6869e8b1e11f6d0d08fd712bc68003e55ed462ad4946f7f982e663f65d45c07c659d9620d5139d2b3332a68d33aec36e21716a3b75f44272a19f860e6ab3864f06def9a5ddeed340ac0733353\nB = 16d5b074e008fdd30e73ea95cb5fb87de806319388b3a44f33c94d38be0e6f1a92103dbdfb3d23b6e1d19bdb29ac14833003e9482cb7524d0d7b4c377f4911e3372f2cea6f84c938d84e3994e80f0d68e7e385ca29e02f70294c921dce7cd3829c5854ce51d1f4fcf7dba910b51b48a3f53cb1f187182435f21f6981cf8440f9c8287a9749c92c0304cc2bc91eef32d8e6526be802de8aa16684e8854cb0b67d9f7ea00f6f0145d14e3c251f70881\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 72192604b2f3f68b9ed3e261120ea52b06a05869f6abd21828ce8abadb3a71c360a14947bc738e5d1d530b9636d796f785bb44508477eefa80c4b77d4e8e35463e15ea2a48c682d3288c5abeb66181e4bed7d5b4e0db20fdf5ed68513aa5ae7e0978ec1c4646368f206636ec90e808817bd1d03acf9adb9ba57dc153873fec11\nA = 1112d291463b28ef45e879412e6607a3e20d50",
+    "dba5044e71883bb3cdfe9bc694a577fd7d896dfb836a171f3a4d8fd025d3a979b43e41baafaf7b535d9050e47f4880828640e952435648960bbb74a3c25dd90bccb3fedd254dfc0f031d0e8a468e93bb69f771ed35f1653cffea1a763491fdf6efa21aefc287cb611f5ea0085f64cc3705c784f87ce00846901833d01a3c45ce047d822ba390b538f0a24720155409f60ca0d90e13991aa1\nB = -d553fa2dff0265cd9d083ad097af87a99af3d8d93a9f4c07440a28a427082004ae5c81d22bda1dd2429f540de8df175c1b4d0d50f0227489ba570b28baa35055df951d05b584ae6b051a135d7eb2a501b2441f82c135a8ec0eb81d379b96ef8f2fd526ee62293bcb934c76ef8083727a4b28bbfc9f515ebcc2bb7ed9594a106e137ce94e9105b2e2f4776aa9c6abdf426a181181fece3251c3ef4f8eecb634e6bd47c5878663fd51c74a66b92713fb7\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 459e19faf105ab17ff794927aff86196b3cc3461e69cada53ab8c8c81e2b1820408421ea1af6ae10257e8cd9dc16386906410761fed62cf9ddcf0da2a92800d99563fbb9cb1ab0ba46a17cb9dee3f2b68992c2b832a5932e4533fbd5c4487d870f3fb5d7a1c358f4aef02993360915a9e9cfde234df5f51c761d84568400b618\nA = -7a964c62e38e4124cd2bad727138dd12a086a2bf01c095b078ce2f81288d3c8435ccce0c8e00229184091130989434bcd107a3a0787a2f5f4b0e8c23b1cee9a8f39ea279fb6081efb6c3df1704fae9e87d63ac6eac4c6687b3551ab7ddac5ca0541e12047d04c2fc760fda0916cd2b585a90d25880fcc1bde8f0a1a413969938d42e8b3b5f73118798e85b901c2e15860e29e2ee8b1c95336b97dc10a21f5300e0352adb60b40a8a99333380\nB = 743ff4d91ea3e0f9c4f72e5daecb4fb00b15b86e30bacebbe4384324523d14e22abe29b00573733f594d652a88d98c987f8db08b27b4dc68577784fde02dd410ebdbfaad9e9afc6a22a8cbb13a780222bd212fc61e38faf409e940fba35ed909e6938e83b0fdf5b5e3ce138604823e788efc3aa0df924554fb70fd2faf8249e17a827c5d85942005b328bed97e5ea1f1810219d77f2fe121ce66518e37c84d64aebda3c397684212384deebd520a776b95\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 183950095d9424b0ed09985aafbbd2e5d64bf541a56b68b42ea8cf9b2c051615ee7bb6c0687ca6fb0036888fbc927cb7aeb303750871442ff2c0087a95f4efad568f48b03bd2b9a9ac26af8c259a3fa97cd2af7e3d8f36148c26785489cda6c00a21e7eca219d1f41b2e82ba8e2c1cd752eb08a2fd50c6f9077f3096e2eba05e\nA = -1d2fc778cf44c6992d1f3a056860eeb12f969358cadb087dcaebf5f96bec42bc0aa98672260adf1732da057e9e0d22081e33f5fa71f248cf89dd361036ad58692637cdfff584a191279f178242ec0ad397efc52e99462f496caa0f3133c4238aaa877fa7094662f080eb284c4cbeb992a368c2d157ac5c8c9160c167716406190fa39ce0abcdac52c8020969b87a4f84bc09a51f7b2ca288c93b1aac64e19623a7d9e69976a31074f637e4c82aa\nB = -2f188f1245b75cd21d052ec76edeb5881944a143fee31c67370fab0420a748f3f1957bb8332ffefdeabd0ca806169629f130c86c99bab490a9668fd8200f4a9b1704c589e75b5c8c855f133d50b2ce06191875e2872b36c78438d6032d53004c047f49e4cb81e19fa84da16d053e6cbc7c8eec0b9129a8831eba690e0542ca3fefd204258624e92844c8b7bcdccab986475a47c8b22e89079ea6580ef8f496099cc24dc2911dcb1921d1451e2163b55bbb7db\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = a02c38d5df9ff7055ff84122342ccdf6ed7f7d54fe8227af091371f5ae62844645586adaae99c11f4ccd828103a81471bac72dc20625962e41d603e760591bb3569a21f45bf062b86b5fd1c617a4769a4d767a0ee14d104084c12ae875316a8f2be7adec0104381dc02c20b5851efdf7d4bef0d68076975e0ada3e58e101e8b4\nA = 5daf37d616da184acb278a75fda4e4fa49e544eadcf373c054b203a309ba198233f2285a1b55dc92e05d0213b26c82e261d8383a845813077b2e1b5f4553400f09410987c8dd21d4383e0f05747d0482d1a89f160a5220b22c78393873564fc5b1e4d5627ef3d4a05612709f301381df35606e99560fba07a917d7ea7413110fb5a8290e114d5200cfecb00b6c53b2ee29911bcb2fb2930eadba0ab9dfaf46443370307d9c3b61a329f0b8b8cbe7d\nB = 1d9539fdb1afabeb9be6e774dc7c7cc4bb4fd63af7abb557a5fc80a3fd23a4600de3c7fae89b91f3d441b61d3e24b2fd3d7803cd71620e7313917b4afb89ef5171a3d8a68c3c74aa3dfc8058d555eac429dfb6db40a9e0c25aacd2050418d6f32bf21cbb76981269dcd5883178d4b69a931a0338b93022a2ed0f78f3d8877989cc406f19d6d082ea344309318c56be7946412ea0867c78418ec32b9fa3a61017c10939c9345021133116933a3d1eb86a3ef16424\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 5fca287abf1f487e0ec18c230860eed4a2e550228b1500b1e33bcd6675646b5afe505b55073129f22352dc2b113c584ea1b98808214b6916933e90e036b129b61657cdea9026e1fa087ee300e055ae8f94ffca933a2d70453ed220468a5a3cf1a65d81eca11cf570d7d038722397f487af60531f24a5f069671354882c8bd2c1\nA = 1d9fe15171dce97475f4ad329fc8fb5469fb2b8086e4b01eddb6ceffe5324cfbd28d791705848569739b6758ca7e7d7d49adf0c11d891b0a5879ca870d1ca5ff475513322ff218cd26024f97623bb8a53084594e1fd64154e1db702522883fcf4c0d677a7fe90096fc76dc3800816996308d8f0be2dbf3b879f8a000c0ac534511437e2ce2d7ebcf42fd1698a829eb846b3afa581c24d5bf97abc6e247f110f4e872a2474e3acca6c8c0d518104c3375\nB = -dc0da8f7adb8e9f7b0e3f293cf623528dc8e9668317910417e52301c50c62e7d30e77ec7e38d6817d1f5a93e851f8560f642f23a0b9f836812d27b1b41c0867088a3108332b8711047560052ea30c8840f03a25c65b227a175d8f340095823788adb5bdf2b7ebb801e20f6b6435e154f78d17b8fc4373aecee56ec7b8f5686a7d22c8571797fde85cec884d45ddc4b1f2cc47ebf56a879bf286f349a0edfb531168b733d43de3b86b49eacb10b06a432c96c63440b\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 6222c1a14c6390d73944cead58eae5e7a6c19d19e4563c36cf624f5b61d99991bed7dbf6a0723abc56469eedfb1f7982987c2c7af6191178cf0933ed5f191b8117c9d726cdfa8b82a2fb25ca5436023f5860aff5fd482c611f134569ae87395dd99e5e9d400b5ab1e3064210ded096411654518110ea45899f4be2516e35a229\nA = -7f6766be6c6ca9bd1fd7ea1f80bfe68693f7ee4b5ba2946846839060d6028eabbb9079a165c1a07eb6a01239f3f14095225b8617753a1cc3d9c1e69b516d8705cfda396f4f0d05b0944a0f08b478d261e968c06918914ba87c8e7b7adef5cc2a875917d00585571542af219bd726e502b7f3f0bdf0cb1dfc6796be2e22e8ffb5b8bfac7e15e991022974e75d3a5eba214ab8a1aab2fcfcdbc6ded2abf834d1899d2e3ff94bad9c696aece045212531773f\nB = 49c6f869745983cae44d33cb7ba141234905441ca53172abd1a2dd8bfeeac4b236605cd2dc5b04ff9aa13de84872145b935b85479136065d2d57fd15fbd97480c25c6354636c17ffbca33c9319d65e82523e39fab49321380a130fc160857a451a69b1d0509d5718a9cff8b49c2d677c1f66bf77333d2511f58d3eb2fb47b3c162cc9be8b012d8df70278f0e21123a69724a1f126369a236d54da026ebe222c513f24b577707b5ab4b90ab0e22b4e38ceb4181d4ca101\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 9e9cc8c5342dc6d6daf55fc9aa9f79ec18592e8b9724a66881c379245c91f06a7df50a6ba0964603a6dac97e77a55d06efff17c93d5faf107fe65788d0f56483915f6ea0f1ccbda7656eb58fc032b5771600beafdc12c2076110a9b9670bd0754ff6a72c5d6e1a9e4e42c688e1cc96d7aecd815bdf5dcb16fcd1be1275ce7282\nA = -11635fe16dafce21efb1c599305e9a16eb5651187cbf054cd9d911c13e8eafbb738013e212f9c2b3662ea15ac9bd82b5751d43a38e4475d2310945a812262309094ae9cf59e0e9f3d02c92d8ab01f5733a20f051054a240bcbe3a7b6bb3f7c434229f631c4af239d33bd3ce30a372a480fdb49b2716091d26071aef372b8bd8ee8eb7f2965a372a836000b3737d2a833a39230e721e4844e16031ad69cd45ced60a64510c1248fd776611934d8d2a913d965e\nB = -3bb2cde9d3fda96fd7e6b24645f8e00b43affb223f2b5c3f4b7cfee905ddd6703a9d6c01f1f099ad1174da215a645ca4707d8156e762e2a253d7cfddd05ca19823ada9d33924013f677cfe4d86bde025391e0aaf91c6b776a9cf8a09dcad7cea59ee7aea1cf5f5bfe67c9d4456332d1f98e5310db9a0230381e1867a8f75b8757283f911f1a5e0d4afe5d544afa8d86637f9c9d87428fdcf8b4eb8f477e617960948253b24565b2f23081c47e211cd3c788a92732a49077f\nM = b18a9cd6a0a89578ea773f",
+    "bfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 30dc89bad4b449d1df9ea9b8f9d40b323c71d7e1133bc44d33bdb87c38cddedf83bb849e83436e4c92a06546fcf3e24ce6cc89d2e97a48aff2c7e3703da1b167a112f662a89742355e11e131e41052f1b379753cfa32cb0efa3a07465a258c585cd68c86bc9a473f5262c86c50992aeccbb9725b69ea8b3a7ebd2b6a24db52dc\nA = 60463fae1e9354559160d55a453c12d75775a53d1606d1fd16bef7e4ad1c78f9568954112f9280c46781180951534c5372dd5aaff3f33ac9c2e0ce4934d7009aad2ab5d6a5e5a141a36846e8925c7a28d116c68fb78aa9a687ec9bef173c1b69e0d7261f96eacacf237e1fe5874e5d553985b0fe7692ce8f2a5feab9ad9a2ad9c4bbf050b73b8030ebc36b94af8c6ecb67f8c94607d80cf600efd4ce4aa006f9b1832da8a1fdf8a564be0b4369149e8639e1714\nB = 15bfc50290b771ad147695a4c6701c47f2e8aec0657a4ef999eb45685200981b0ab5f8abc143d64878b85e9548651a1afd0913e3b14d11d3a26ab9793596801662a67b0062fdc8888feb029266f71d170518b6a4a040f59996bd4f257f221e830d0faaa9688aaa6afbc1f9b40d25097eab9d71d80aabc085f3a07e48bcfb37119aa00de60be55fd07d5b1281adf7b98bb589cdf2026252edf2f075ee176e23afa6b1f924c9fcf3c34c76752e833278a2e6b62017b88b77eece5\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 8b506c9bfb75ab7ab420ae6c9b371ef035fab512188d9df76f0b31831573b44cb08266186a04d20cc761d61b6df3e33ecb86c269205c2c79ae6aa4d3ebacac8ec71d9bce1d7ab146530b131c9038041c6ce8152a6f1c09b9bec8eea4462dda0f08d75edf296eacbcefd62a0c197ed30f799343268bf6edfee4995958db7e0420\nA = 11c16713fbf8bc9696782cb5a88174cddbe68a04e8fe93dd074aab33dcd85f92baa178b2f3b8817be0cecb802cfd3ebb06734c9d399a1f090e3a8a2110aebbba0e920427bcda74bf11700b945985bd532286d44a1a615cf7c501412e454edd647f8371cb8149474557a0d47cbb782f460de7a3cc28991491ea0fc510286711b882987b09341c079565414f2c930e7c3c3a3e3e0f1d786260a7f45c70e0fa20dfc63849906af61707cfdf5a9b7a4291a1c1586d16b8\nB = -cf5638af39c6da3757a09a92e0bd54f852742682dc91c71dcdc6e72f7825a0979a1ead2e158479ce5565d22472dc3853e6bf7ba43296a5e0e0a355f0703cecc02ec79da83e3e9de10a6eccb858dedf7d4c400c27486a5b8cb34d787cde6a5fd271e83a6cf66057838fe30db1f30663cdfc22ef5d002b0b5a05831228ea200f95382a58d0d8aba36523d9b5cb7506f193131916f3ab66ac9552c26cd0c2ab1c449eaeb8fde752f4f3c3f9b060cc1f8a1e37c4fe5ec306674b66158\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 347706abeb168205cef9b0b8c6b9d6449ac501af7dfbdfbd41a20a6a47872cbd7d4cd32f7b0805ecf1573d534418b7cce98181e079d5061b02639fdf0161cea5314dbbb2ef39ec841f695281f3c7de45f33664e0dd1658f645adc1dd225f781a3fb1634517c556403587b2aecd56dceca9ec19b930cead2b1d303aa056d28bc7\nA = -5e1c869e5dbcc684c245d5c69093bfeaadf388cbf928d33a8ae2148a2b5145937e4f654c5f6a36de1124bad1de8bcc9067fe1f9a44fc6ffe55ce7ed5cd0dbb6337b0e1e96bac1eb2a3606dd97b0bdb975ea59448be50191cc7ea36481ca9fc85c1c3e1c97378dbcd6b355622046888df2ab3d18d805f4d31d464f62a8e630e955beeeb5e00c70242b8f8df708705abbeb95dea3561756298b5f3f7fe16e965294eeeea4546f5e8bacf9d6b4f2136d2e206a87dad1f47\nB = 70225f0cadd328be36ece2172c836405db3fe80ef99ec74fca25406b73a537adf5073f2b550abfc4c0fcc2c2850dace0da9a266768cb4d5ff7fc6c1c248ad74f47592101b61ef96c1302924381abbd96cf49f50c44bf7e0551721a8ae85abdf9925548d13b8c5d1a27be8a40d0f43eec3136bc3035057b75aea779b4262cc66e6bc68da93c218f1920979291105d4b02117d66deb92c3e511aa588b27130202acc9f69521957f79c7e731bbd5461552b9b6b24240dd71ac449be9777\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = a2cb238f326d47f95869e2dcb295eba819a443dcc7c2785461389b58327742702f4c86e47af129f1fd4611cda93631f9333c358a29121d58286333083d13e66f30a9533b77ba3e26089e7eff7baf19bef8054af4e24735525908864ea9c4756b42a69c897003cab7b63cfd9a5927ed562e29845308eb2a55e7f8f03c87a5b7ce\nA = -1aa7ae6f56c38b654b281525b9da953ef366c2b9cffd3042105ed428dc7e5f2f2d53ef90b468bb471753606cc7a3775d86bcd2f4d5119cdde3c487cd39bf31752c5ba297e529c1b8121487e0e1de702156d0166ccaf51888a24fe7b48624eefaec855e2200929c21858676ec9bf4ceed0a832b69efd5065af544e49a3d209b85a77b0953652cbf0aa897527c52c9a98de9ae4c827f762e251478c88d410123625ea52b3478b52f6b9987d42009ae427763357ab53195772\nB = -226630b6fcdb5e274a25066ae2ca2c803549dbb935a97c0d7f6ab2c971d74cf6acd265c9d6815a6b2dd23dcb3c23b390fe8b1bed92b8c64c76c0ce62d5e7ddd7ce445bab0ca905dcfd0f128e5f4ffe966f3903d7ff1c61fe174e373cfe35a6d83249ec40b4a354d46fa1c90682efe468e895ea3da710838c262e8a47752dc6e7a79fe20051f51180173b58e0aa37b22eb8efee5b6dc264459ce4d135f430cb15afbf8c53f0de894bd2aca1f7ea32b4209a22a075f7b3b18e86f778a9e47\nM = b18a9cd6a0a89578ea773fbfc0767c8ab817cdd585c16afad3600540d056c323d83e7756b1b74e4c2a84df7edd562e011412a0e2eb6b64178a9e04f67550f3081797873f444dbd03d776835d696e464443a0a6f48d509228fe976c54cb82925e8a80ee65c01ad9a5f56784c54192112fbca30a76ce579d3eb6e783643e971d48\n\nModMul = 9ea62ef634\nA = 55cc58c9d8\nB = 6b49179821\nM = f753311ac9\n\nModMul = e9ab3a2aa60edd30108\nA = 5134a36c2bad180dd5bf\nB = 2ba6485656d041690666\nM = 9b9cc4409e86c8b0fbbf\n\nModMul = 621f9b797e866028b7bd1ff828bf29\nA = a202338dffe171c99434d84f3\nB = fb71eee7045b3e3ab5dd809dd\nM = b3e6e8d53b7249df670e3c59c55d33\n\nModMul = 808d463d06b7b7f98e3cb2783e2196c349d62672\nA = c669426a92d3cb5b316e2b5b9\nB = ccaea3874008dcc92450d8b2f\nM = b04dd2bb325baed1940cd000e8cb2d786009ccd5\n\nModMul = 872164b92b9426b237858c4cdafe1694f96b0e0e4c19e894a0\nA = c3255cb24a813e27c3dc410f0\nB = b144f39e7c2d33605ba7bee16\nM = f3639f4dfb782f3107eb402fabb5fc878903acb5e02e129077\n\nModMul = 6124d7d171\nA = 235b938139\nB = 3a56a22a28\nM = 83eb4af4e5\n\nModMul = 9c006f56095d442ba98c\nA = 207e14237c42e3764e5e\nB = 8a495a26872432fa8e33\nM = d0cf2b8ae5c67d6736b9\n\nModMul = 97387cfaef652932a230c82de59cac\nA = 82ae0fc5e943af5bb8c4adebb\nB = db1279be12d59ba3a9c036a61\nM = aa36dc1d13390169cd54d711eb511b\n\nModMul = 32ee73c98da657464c6fed4274df20b099689e00\nA = 9baf08248ee24bcb17714e420\nB = a7f0428147bfe098666180749\nM = ce0bc198331c9ed1d21f0d498326e8185d3d602d\n\nModMul = a8b3fc0b53df3b92753edecd6fbcc5f4840dad3a44da704e34\nA = b36249e259b303e453757721c\nB = f0c1db50670d92abd93bdc84b\nM = b05cf978bf2dc7e093d7d164e46d547219c480382df32b33d9\n\nModMul = 2663b741ff\nA = 58c8e7f7f6\nB = c84681fc87\nM = e0a50dcb45\n\nModMul = 21af3c0b42328f41b81e\nA = 1f79f5b5bf78c9700d\nB = 5bd1734ba0f0e59c2a25\nM = 9ff3fdfb5c089244f327\n\nModMul = cbc280b5106c2c36cb31ad7e7c986c\nA = cadf6482b769e83ce7f7277dd\nB = f9862a06da1a9c89547b76c61\nM = cc36144c88139ce921d2fd1740bc4b\n\nModMul = 3813f2fabe016e19fd8e70687ff473651a5fbb4b\nA = 9c51a5bacb5d9f055a9ac2962\nB = bfed5625b21b4e82d1f105a0b\nM = a47977acad7c5deeb683ccd265cb30cb193f22a9\n\nModMul = 76ff291a02715fc87ebfb3e99153c04e53358dbd7beae43478\nA = 997c4a7b537d9500d73a205a4\nB = c679ce666af284a459ae5a26e\nM = d0d0fd4922953941acad8beb65c00603b19eb44fb8ca51e3c9\n\nModMul = 1a90c92fdb\nA = 94fa7bb475\nB = 564b0a3339\nM = a1501bdc75\n\nModMul = 5e7ae5470686bad7996a\nA = c725797912c6c5f30d94\nB = 3a7f4c99ee3f5fa9582c\nM = cc50c8b7408f09a74973\n\nModMul = 72a15b13bcd1b63747342a6be8f0f2\nA = c33357af48a2df569e3c11ce6\nB = a4b4c5c14d7796adab54b6cae\nM = e22a0fdca62a37f4c8a61c96a429b9\n\nModMul = 31e179bfbf65b0695dde36a4fb72d131830dcdd6\nA = ce8d3adab8cbf15c332c0b289\nB = 9333f94eeb7d7a86b82becc51\nM = a532a76bd5cff409b580d54d12ef75ad8179b381\n\nModMul = 8f4b8a585415adff3a7bc35fa88891ba31e4a82672c664fb14\nA = 9a2b56a54bd0727ab4be57ff2\nB = edf1781b4296567990773005a\nM = c5a7c3b97ba00d6f174a019c6d37eda52036c528f351bef0f1\n\nModMul = 917bcdb402\nA = 55c7dbd314\nB = 997b29ef79\nM = af5b4cbd0f\n\nModMul = 660c4bb2b771f523a4fd\nA = 43fe52461d5139620a11\nB = 1f8ec4b67de1db54ddda\nM = d0458e215b7e6903d96f\n\nModMul = 7aeff02c143e4426fcbcf32bd1277b\nA = a2671586369a990dde7829f36\nB = c7ff67937c900daccc0ab1d8c\nM = 8ad9c1d4d3cce681",
+    "d1ae27c27982df\n\nModMul = 4b153d57433f0f7276674d3484e9bd0d25227d07\nA = aea36cf51dd2ce06c66b7a407\nB = 80c9fe5bb0afd2bf8b3644f96\nM = 8cc22a67ed7e5a7a2322aaa09ec2be94998494f9\n\nModMul = 7f8447dd983b113f04c6288f9539e53a2e9cddbca8b2fefcc0\nA = f67636b03821c8f13f21217a5\nB = 8473a29f4ae33f36a0d2c6dc0\nM = b829af37b557c3ddbb5257c8b19144b90708a45a274d6655f5\n\nModMul = 17fe4644a2\nA = 912611576f\nB = 7a10d36b80\nM = c5fa605133\n\nModMul = 8159b23d4fd697b4fd35\nA = be2d646e76494439e60\nB = 60fa770d05ebc69772b2\nM = a6e7c940cd749925a85b\n\nModMul = 7c412dad5c9fff91357bf181caf2bf\nA = 80f476ed5acae75b34ed54c52\nB = fb818e2bdab3b5f4bd84db3d0\nM = d0339f7ee41337d8462d1a9c207d1d\n\nModMul = 70432c749da4ade2c38237545ebfe6c4c6a92f6b\nA = ee9c92de52210e61adaa6eb4a\nB = 8ab55a85b1abab62d33e75fe3\nM = cd3faa6de4cb62fece4c3f94492d457834a6a041\n\nModMul = 9fef1c18778a8691c5e71c0b5208e82778e9bfb632da0b7e28\nA = bd162c90bed25e84dd5b6b77c\nB = d887ee03020c5df356f091db6\nM = a2c2d45fe9decd93a0ca3edab8fee46d27ba23fad9b5294d5f\n\nModMul = 958951bd0f\nA = 12bd0d3375\nB = 668bb65b4e\nM = 9c617dfaad\n\nModMul = 8a109ebc9cbf86613e43\nA = a3e7019f1bbc35689a77\nB = 3189ecd3fd4ffd0229ef\nM = ddadc50600dff2abc1af\n\nModMul = 2b4d9f85a398c852b3a0cc82524619\nA = c244fd157267f707319ba6c6d\nB = 8a07018a748992429bbdbf326\nM = bf3813fb54f749ea5627f59ce30e07\n\nModMul = 28cab7d574e6dc56a6a622f8a7523cbb8dcc5e0f\nA = c9909dcfd3a59a3cfa538b267\nB = 8bbf89cd5a4e24adc2d8c646b\nM = c8f02682b9d480ea98faaca53b747ced33ed0419\n\nModMul = 69b2dfb3f1d8dbb13e9e479f38edcc427d5968acb7751a226a\nA = 8019266c548982a520ab48eff\nB = d33c3e3b13576dcdb3ffaa796\nM = e6255103732475604df7c6f7ef7e6b49a8ef9e2b0c717925a1\n\nModMul = 3eaa4c99fd\nA = 6fc42faa85\nB = dd0b4e318e\nM = fd7f22301b\n\nModMul = 56b6b811ced3433755cb\nA = 145573d17cb0c996c69\nB = 9d3297d5ccc184896822\nM = dcfb3b383506239e83e1\n\nModMul = 34315b6bc6d3690c28060485ae331f\nA = b963a26973894cfb42fcb2d22\nB = e8523304bbcdff1a0ed4141bb\nM = d7a379aeac7d8cf94f19e7924d35d1\n\nModMul = 2ec9466e8b3357496f07e37ba24d36a237883846\nA = a75f3904e564997695b6707eb\nB = f9f47bd779834dc1f5fba0654\nM = b3ae5abed45d09c4dc5abcadc3ac9abebe1949ed\n\nModMul = 88b4d86b2c1e1bd780e8d2499c2221e05fab4f9b7047c2a044\nA = a38eceb9c551f0e69a544072c\nB = d5f8e7c2d534b2b8985bfd213\nM = ff81809b84fb8eed3508ad891d3d8208249d8a902a12d6acf7\n\nModMul = 172f2e2e22\nA = 1584ff1055\nB = 2e0aee014d\nM = b904cb0bc9\n\nModMul = 122c10d3200270b9eaa1\nA = 86fd189e62a6dc1e4ba0\nB = 5235635f7b0336f5f235\nM = c93da97d0e95fb63dc4d\n\nModMul = 3e461e10ac4eb749512097fbf76616\nA = cf4ce10cbca07164f3812f89c\nB = b7e4639c233fbb0f923fb5104\nM = 949647857e1406871593fad5c30101\n\nModMul = 88117b59d9fed79dd6aaf083ee938215a995a221\nA = 94c888795567d434123d441a7\nB = c60ca79e61a352e34e0f78bee\nM = d2553a7c5dccd639a3927697a2e1af03845f2f25\n\nModMul = bc5f0076a8c2f6cc8f4e61540d2d6f6d6b13b775b363dcd71c\nA = c170eaddca5295d6ec6272dc2\nB = f94a5685ced7661df2efbd34e\nM = fa6bc46aa05033af72aa42793e9174af2e3ba38992f33572fd\n\nModMul = 1110cdbe5b\nA = 5db02b38f3\nB = 3369537903\nM = a8863f7979\n\nModMul = 90fcc5f3a346d3d4ea4c\nA = b93373680ea0feeb31d8\nB = 37f9dfaf0e180be64bd5\nM = d595cc29237d1c19e2db\n\nModMul = 8623a9997e514cf3c1d06c33c14053\nA = b396f5ede6212f1fdfc7e7b77\nB = 81a1ddc18306f2d2e84030148\nM = a6be32a91b34857842255ef8b1aafd\n\nModMul = 63f8f0254df06356f5cab8941b77619ad58025ed\nA = 806b2627b08d987438f920bae\nB = 83297039f4aa8efc1a185fea3\nM = bb8a7e7c19be02c25cf5682a0eee655fcd5b69a5\n\nModMul = 697238dbe3d395e81f20c9fcc8db30c234a1f75f3b2bc27438\nA = 930b04224bc097ac1d8bae8be\nB = b79496a80e45212c4663e5b64\nM = 8ff7e19d967d317c255380411898d73e3786269f09079f19f1\n\nModMul = cd93b5b8b1\nA = 47a51b2d5a\nB = 86d6ba5155\nM = efb0ad3643\n\nModMul = 2037821ea789118bde0a\nA = a92215dcae19be637ff\nB = 93b9a3664a406737958f\nM = 9df360b69ed26f610253\n\nModMul = 3bf11785d28ceb668dc55b870faf7b\nA = bc8758854dc48e057cb6210de\nB = f03ca689620a77ecd8a6f0de3\nM = f3ff0747d6e5f34a0ba4200f579259\n\nModMul = 7b30b44f75ed12f54136858ce4fe77d00e0952cf\nA = 993cd09f3e46423a8ba2053df\nB = feabee384158032dd013dc08d\nM = cd0b21388cb2033b1e792ec4078334df70b6c8f9\n\nModMul = 8ce1e17972f1a9d2e9437d0c5219354728a5f31337808d7650\nA = 90e5d18b017118177ffb080da\nB = f8e7e09032574f6c66e623ec8\nM = da795e6ef63ff7dc4baef5c327022ccf65d44e3c4e24823f11\n\nModMul = 8fcd412054\nA = 2e7f9b1a\nB = 6283de2c9a\nM = 9bff560ae7\n\nModMul = 57d0d3b79f1e2f3632fc\nA = 2f8cc403de5af54cfa39\nB = 3b798c3ead52878dfb2f\nM = 805e6cbde400d4b4bc9b\n\nModMul = 23331614e88633af879201f568c359\nA = f21f19da4b20980979a645dac\nB = ea752050b79883dcd69222536\nM = aed3faf4c88f7c4afe257c5ed90599\n\nModMul = 56dcf9ae1c787e773774df3c8762babb4675a212\nA = 9accf901fa599da05fa6ab5ff\nB = f7f6b9b1d7bae06237532e39f\nM = b5bcd776bb2eb0805ade3c8b47e883962d3cbdf5\n\nModMul = 61d0ee0786963906a028a1df01f836841ab6d39d88ca2717c0\nA = 8e57680f213d088ff1a1e7db3\nB = afebecc9943b0093f87022940\nM = b6201f68a45265d7e9183c3255feb4c110c05dadbcb13881bb\n\nModMul = 143ae78a29\nA = 334abb952a\nB = 74203e7a50\nM = c9535a9505\n\nModMul = 897a2b57e69f5a1469ea\nA = 1ec8ca0ea4fed52bdbbf\nB = 3a6273cab05e478a57b8\nM = dcb33163a8ea42c1ae6d\n\nModMul = 4a2c10e90e2d37111db79a44d3e31b\nA = a90e7bbd63fc4af6de83029ee\nB = cf09c3dd50b41afc7045e057b\nM = 8ab85d47e4270116a64f97dc4f0f15\n\nModMul = 70f94276c9d85fd3f71edfaad6051456f754da85\nA = fa3e9ff6e1aa1fb78e51711cb\nB = b115ed197c50b7ec4040ca255\nM = ad63f69ef1346e7549ba71c13b24b279f53bc9bd\n\nModMul = 861e7ef401866f815b983ba18a612913ecc20a67016d79cfac\nA = fc41a9ce06e882942f751be7a\nB = 881c05a51d1ba8134d126a48e\nM = b12200b39526c33b70e8aa23ebc400dea0d4d8fe42be103d5f\n\nModMul = 4e0051898a\nA = 2a06523f70\nB = 651b5044f0\nM = 9da4eb09b5\n\nModMul = cc8274c88d6affc3742f\nA = 9ccf0133f9628532f4f6\nB = c1d80907057be7a67b01\nM = d6e76e362da831f32685\n\nModMul = 568f15bed5c4405be9dd04673a9c46\nA = dd6029c3196feb6da7f0f4a48\nB = a5f6745f2cb64913d1d3236d8\nM = f62f02c9b9ca8993e3be9a02b444bf\n\nModMul = a629452d5ed19df040eca26eaca37d82c0fb1d8f\nA = 963c51a9415b03e85ccb09f25\nB = b1cffe333afe44311cb968ffe\nM = ab2128698d498e8d75455033cfbbf4487535773f\n\nModMul = 814030123025d287aaa8b826792999d72f2d589e0c7f7f3dbf\nA = c3b33f391e78bee97ceddf313\nB = a9136f3af450fdeb245eff425\nM = b6aa9c517eaecb70781e597b907583bbb569e970d229235a35\n\nModMul = 8735bd486d\nA = 563e15c52a\nB = 31293264e1\nM = 92f4b193df\n\nModMul = a541f69ca163b288dd0e\nA = a608b48c1dcaa18424b2\nB = 891b0b296e911068b00c\nM = d4140921f4b2c84f1eb1\n\nModMul = adc1b7cf65967b013d046866b4ed9d\nA = e97941448f65060cf63ecd486\nB = ca68936f76cb87a8fbdd37311\nM = ebbca2482fb82eeca2866057cf1179\n\nModMul = 44aa9f0dd58d4510a7364e130698b34eda23a632\nA = c11f83f01bb964ffac93a2e30\nB = e05ee40eea39f4538d735193d\nM = b5e8b511738979dc740a6a1f7291cf4561787be7\n\nModMul = 8b16b82f064f471983c7154abc9f9ba355111bacb90400372a\nA = acff8da571e1c96810bf95707\nB = cdd23e5504cc26d0c34a62b06\nM = f38902a99190ae0b5ef26849a6e943d651925666fea271fee7\n\nModMul = 193f453197\nA = 8cb3078675\nB = a8fb003a87\nM = b60ff22f4b\n\nModMul = 849c26c8cf5cae426a80\nA = 5d1e3d2b4d038a0a34be\nB = 34f70325565bf0523314\nM = cbc189f9a732cad8f425\n\nModMul = 9a4e64ff530c53a4c6c5b6b5021920\nA = f53b81723cf74f520a61e614e\nB = 9d8ac2e6b839143fdd079a2ff\nM = a115375435151798f3644bede9d863\n\nModMul = aac303a4623e80158af1cb3331965cc8e3184edd\nA = cce0a88606ff962fdc37e72c9\nB = 9840a500a2051625c517104db\nM = b99dafdbd91ec3c05791031df5e193c03d6a441d\n\nModMul = a31401dfa761bbe82b66b5f094151865b18a4ba75bb9b3dedf\nA = e6f48c027284856aaf3b96425\nB = b4c326f72a6a22fd4b93ba5b3\nM = e57d9608ac6e5b129b2c014958bfc59137f63838b1ba88a4ab\n\nModMul = 8b0929adbf\nA = 61fdf77ac0\nB = 8892f05400\nM = f12b3766eb\n\nModMul = 91b57f353307b173679d\nA = 33f8e73752072b4b5cfa\nB = b4c730f79f4f2c07945d\nM = d41be1d8d2e5753e3ae9\n\nModMul = af04c564adfeb120bc4770bc8c650c\nA = af151333b3d4cd1d29fd801db\nB = 9ccaac44ff91be11b30bdcdd0\nM = e0bd6e70d5f5ce08fbbfd48d43101f\n\nModMul = 1b8d623796a5065d9e993a53a9587a0fdbea1bbd\nA = a2fd08df2d4eab0cd6d29e213\nB = 92c9d26ae7c215b52199ee28b\nM = cd529f4cfa46f3bd3e7fadf167fdc02f6f881da3\n\nModMul = 4a8573dd8dc50a4fa39f3579d3869745eb8c1153ca508deefd\nA = 855f941d085305725da617f5d\nB = 8f09b7d2c36e0340523da5421\nM = fd8caa05edeaa81beefa01957eed97a981ab34bdeb6d8c704b\n\nModMul = 2d278e089\nA = 59d20a1716\nB = 8e2a58bc75\nM = b3d61ef699\n\nModMul = 2f937ce359d0f6cedd1\nA = 1019d11d26040ffd5b1d\nB = 7cdb6252087423d43e08\nM = e8f537323004447e669f\n",
+    "\nModMul = 6567332e25af83089f7458786ab0ca\nA = bf9565e9f8a098894447b58fb\nB = fc867626f268c24cc0ab7bf8b\nM = 930f39183353363dcd822933a438ef\n\nModMul = 3692e73ad1d91ddc19cad3808eba2c5fc88e2bf9\nA = d0a42ce512629f0ffd233a9aa\nB = 97f6d3c4c655c7353a62d6ac4\nM = eac2ea84851f880214b8f40f881a2e56a6ba6f2d\n\nModMul = 81df390c9e51b30bd639db15adb464c7cb1d011cb5e260be58\nA = c237eb242c40960861c938c08\nB = ab2f481f0d768eebd90d2574b\nM = 8697d7a28a5f42c9a7b31949b8b568f861142f44fe66c6cd3f\n\nModMul = c952f9aef\nA = 81973bbcb3\nB = 28ddee3bf7\nM = c4a40993c9\n\nModMul = 241dd53d93f7bdbbb2ee\nA = 2136eda4495c45c9f96c\nB = e74c4baa8ca3f6b7cd5b\nM = fff4594e7a5f0a1d3e15\n\nModMul = 5f861ed8b0aa835761613e6c869cfd\nA = bfc5c1572086079f5f5d18d1b\nB = 95902e14923c8010b7e905178\nM = a819c6c109d623f9b845aa23712c9b\n\nModMul = 5b8ab089c4e4c6804e48a2bc1d218718b3a32598\nA = fbe65d3852224a812c432672a\nB = d57a3f38da966d2471d70a048\nM = b9e6a626d3ad026d14248fc90c882bedd64a1f13\n\nModMul = 761438baf5b02dc095b7040e082da7b167c2b9ace956284ed\nA = fd91701ed2151f8e994bf4ee1\nB = 88b66e735b76972bccd9db182\nM = 8008b2d1274456aa68dc627b1ec3e1762c6ed2d660c64a1a55\n\nModMul = cb743c97a1\nA = 9c69ca9b60\nB = 7488f48f5\nM = d67040ed0d\n\nModMul = 931b2bee1bc30725a31\nA = 650f567b544ce02303d4\nB = 5858da30dd1fae88a675\nM = 91ce30234bb29fb9e833\n\nModMul = 5b4f262cec958a20390b5e568ccdaf\nA = f7e240e8a077e8e87506db2f1\nB = f8653fe64e3bd414782f51634\nM = fdb8225eefc1620648737d31dfe1f7\n\nModMul = 4c011d1ddfa30c901793cc6ce74db47584cebbd1\nA = eda8e9a9ea3cdae17bd50b1b4\nB = 992e8ef4a45593e4ceff67876\nM = 95e2f120cfcefbada1058af6c8853cbebedd5763\n\nModMul = 6e99aa5b8107399848cf24fbd88ed6350efb68d737e505b466\nA = ca6c51ba2f410d09bf71d60fe\nB = 8bdfa8fe5ef3b2ad02bc63c4d\nM = 84daecf412b8c50ad6dfdb546c3eb783dcc6f32003eda914bb\n\nModMul = 536175913582e73c1002083cb0cfce5471d4193a5b717881e60abfe927c829d\nA = 9b474b6f7d7f11dfbeb7a0724694f2daf9ccbaf2ec13269b5ae3329e8df95f7833baa68324509dcddfb5afa1d14f2dafc55e2c225475f16fb396beecc7a66dee\nB = d74a5081f00af2361c3537642c06cd47aae7e366741c9b4785e185af8b328acf3e2ed71e3b9a4b6fd49d956eef76740b3c6ec5850a90e7e444dfeaa7214c5eca\nM = 5efaeebe212752b28b5441a5d0b2600190504467c6359e9ab26320ee72cffcb\n\nModMul = 6161cceee2b74e7965a926fdf5344ddf8cc41994d72154a8b6014c18cf71634\nA = e7d6b74a1af0834aaf93e09a6488340b661449ba2bbc73d775e7d828163813ddbcd82719351879a6d67ab6b518011e1db43a3d620d1f24403917691d15ed6f90\nB = 3ecc8fd3103fe52a7e73ec4be4e60b69584bd886a030f017b482bde9d4b0b964ba8471cb32b3e9bd49864d9028a22d6b6b46be0451bb4222c3987b74a509f8fc\nM = 7c3e3b8b1a6110da82674aaf88c288cef4cfddf22e7c9b75640fd67fa5fad59\n\nModMul = 2acd55bdcccd55882eff0bb262bb62f78bff8e932aefc9d32f54d5d4e9b8bd76\nA = c221d1f0d1b7efe7e078dd01bed773f8876fa324b3fe91985d47d343e7f3878b457dae2f9ae68971245278a1d23cb541c56b94dd9ac43a9fbe28a46efc627651\nB = 49f94c19ff7ce990637c3d2019ed66f7e6dbb1442b04a4593cc480521b991cb1b878f8c31903240f89e34336d9e6785433617e729b71adcbef622a683357e035\nM = 43760c71742e9cf22cae6fc262c008b7f1b97a78c8063957b74aa4cd370c1eeb\n\nModMul = 504c11e38284a30e3647c1ddfaed94503d833bcecdff05e749422ad1d9442540\nA = 3fbabe2d65f443e7db0a6f332330ecc4d1d40e14fcb510499552020405cafcf10a50a5ee47cf60fd8c22a22b3f753b4167c213851f32109babe4b5c298d6c4cf\nB = 62e5b0f887dcb1f1794bae7dad46a066f810cf5f82a1eea99207b5f0fb0ae9084c5e62cc97b2672b1cf4cc1400a19bdcb093c97404876b584a6482931e7ba9b7\nM = d79fab3eb31189268b2a0689cafdaa0826f07d432591e8aa8bd3c7cdce1470a7\n\nModMul = 13a6431c57ddf0ed3979412ba8454a0dd9a2694a0dd76453aae63366c46e41db\nA = 7e1fd0bd9ab0aa75b264475604aea09f24239f94847ce2549d43b71890c0549938d167adebc7890d3c492b5874da7bf18d895ccaf1803b9776820598928b407c\nB = 5e54e5185bc86f16177f1354a57d36ac2980def141b389e4bfda134fae7c158009ccc61ef66281905128b6297f876662104ead2315024f129c56eaa387f80b4d\nM = 182572149b860615dd853f37f7d51a35e85f5e4a4249a60fde58dc68e0dd7401\n\nModMul = 145a44566bd75103083b7556a822ea6008ed3a6a1bf135b68fcf87a294c09b4\nA = a195e4315caa8cc0707063c7359c28139d4dfffb57eb726156336e13227ad9766ea1fc99152893ebb194fecfc153d47cb927a633217328f05e4d8782aeb89d04\nB = a97ae97dc7e9a224cab94ecedc08d0cbf7a012dc5209b1e1e8b5b843fcf61e65db3457d6085545a633be47b742e8237cc716357ff5bce9b00e23671ec1d049a8\nM = 29b060ee2aef7e43e02163d279ce49259127198adf462d13aa195c7dccf573a1\n\nModMul = b00740cef7791692d45f5a7110f3eeb260638f19f87c9245436fc0422de90658\nA = e6b97c11ad44fd451d168d65d1691d2220db8c3b6c8436d59f4c1366aac52558d0d6b61f5d6966460a4a31085fac711e5a09af5563d938963555d4730982eb0\nB = 6805eab5a4da534f07def6d2c320a6cbdfe4831fc2163dfcef740607b3181d8647bfae8f8c16237c1c1c5d14b9e3417132f81b3a7db4b7fc11927aab30dca590\nM = f975a94fa62b4c0e68df5c3ac5917d18927c0a6d9cf39c26f6ed97a81cedf227\n\nModMul = dc04b6ba2eb1e34ea8942a50d1d0c5479dd22109895796ffdc9cd32b53d4764\nA = 7fd3310af09a67e0684dcd8e3b4b651c7c13c2f6a0a47b59a7f5cd8bd80854d1d4fe02eaa61843d6bb2b87f99d8ec4842864681eaf056538ffff610c231e1d\nB = 15f1661c59ee9f93400073e18a91503a93d47537d2da5cf5e4bc69ccc87b07bed171a95f1c5eaa9c7d7ab207ab3f1f7634c5d16e706969e869364207f61d84bf\nM = 22e2856f4c2b6c01448d4aef74aaaee3a14e9660b5b277200f2e67464ecadfab\n\nModMul = 19299c9e960ce15087e9fbd66f95cafe82546431b92d70db1de87c3425c1bef2\nA = 8e3abb1f24e1f91496db99be9409f57f67cfb6e0e33d603a2a31e1309f1d0bbdc413c3e4fbb5e3d923f683afa9942b9b9fad6a6e558b2297889fff47ccef7d23\nB = dbdf5940dcd68127d476badbd5a2f3018aa4d8db79f81337ddfcb108637110b934e946d3284ec09d5255605ad72424f1894238ee4f7964dffc27fad838532321\nM = ab6b4e3d3909512f5d1d62a30c1ab8dd5e584cadbce9dffd12fe203f8936ee93\n\nModMul = 4f88ad4e30e6e8e38cba0452d98d4a3547c680f16308692e33e5577772658764\nA = 5137697bf48982edd869e4a42f3cb858bf65ad5b25d1c0e8b75d054460d0944ecb5a6924721c5728964d84231c7ae808f556837aefb23fe3ad36aec9f5f60f20\nB = c79554304620f8116b9a8bb56f6a23620e9fd504f7163f732e1e6367d25c6ff98cb01d16faf3e018dec6a067d1204a6aa95470598ce757bcfbc3ab4f5d8ec88\nM = 9ba20dd78923d8ef82897ac46a509cf22c9b7986a4facf42e5416bfe3576a735\n\nModMul = 985a4d2a7431e09fcad03e6a3f926582dbc0aedc588f17aa5db40c2d3566233\nA = 908bff40440aaeee6c90b6312dc017c3bdae884a9074e02b26f01be1f018390e01f0d111f99a06c16e20538df8000d4066cd4bb3628da88a3a5cc240cfac719f\nB = 6ebfe9fe53909876784f9d6e5dcca4cfa9463fbd8426c5bb8890ae84c2fad119615fe1e1f2ee5fa544a5ac713ed1da8c1e04f282f1f1b9fba4b4c4bd9db20538\nM = c66842e0a11ed6ad1e8f192ea97f5f244536cfc5234c7fdae1ff905123c72793\n\nModMul = 133d7b31537b627da2c042217cd28625437c28c3e06258427d9a4384046a1f4\nA = afb695e3e40347f60a500e01fba4df1c1f2fd4ed79e3f65913d82369f79d80db6b3978e6351c70c148f572b9c0c2b1efeefa605251b3156d9b66d240467e550f\nB = 8855046dcf50f80f278227d5260b9be53ca2e4a1cfe1afce4d35b11d0fa17a36a8bee8126e13bbb318d476becad5a935e9d160fa481e1437b292bdc169dc7d45\nM = 3eae4f0d6c7e1fb9de1a4c160404a8767783c7f839fe27a543f5c389c679d47\n\nModMul = 7f4576a315bad5c7fbb1616e8b26c5b34ca6f701b9b1adf0485fec181c41dee9\nA = bc2baf0153a4598f6b5f488c43b2546cadfaca2c1931b919f98ba71835a8fe78886da1fea25b194e60ed6f9e0ad23c988b64af9278155c1722dcf4983a1566c2\nB = d8374d91fd3c523ecdd6bdd265c9a8958dd222f9f0e25454fd683bd86d7900a273b56f1f47e033c46527e32c721094ce6bc927d25fac05d7fa6db4d7a6773c94\nM = 9975d8e7f2a4d9d1ff8d442b93ff269a83fee43a18bbfa8c2ccd7ca5fac3a8d3\n\nModMul = 57ebfb39605d4fa6ef5fd03bd8e4fd685664297c29b7ad75a40b133e15fc5ae9\nA = efed8e442154b1eb6c75775cc23e01fa65c9c361e222da123d07daad3039f305e7102edff23b65c333f0caae4f7929857c3169f4ae47c9f0fd920c38eb42bf2f\nB = db05415ea90269a74b0919ff772c148c0eeb2ff9dea76a6e73e82eb86bc76fb42308b55ef83a769a91d23b7840d5d2f5129f15279dfab7cd8d63778acf202f26\nM = 7704390c4b1da86d51ff817003e5451d601a5352296e339e5da219ec5a330479\n\nModMul = 40b6b0d44cf8a5ca7f4fd03dd6e1e2a11f74f3911dcd8727e57db8d65cd490d\nA = 6500f3cf686eec4e1f243616ac0ea8e8d11ddbade490b86baf231e7b2fd55968ee14b6bb7badf8c898874099831976af46bcbfbfaea10d49aa803c6e51238e2\nB = 1fac744fa1e26e789639e049679d0e2eb57336279f09555e10210e7143199a3df5fbf5294edc386ac762fa3a3b0b4bc28945adf21a8af747a29018bf76d3710a\nM = 5c0781a87b84ecb4362b09c623d511de53c085671dd4f08e9a551685b55ddfd1\n\nModMul = 6b778ae9822221e6a8376379e0032d7edb14d7b5e32a7310897b54d1d5626113\nA = c4a5737a9496129a136753f8c2e52bbd2660f2d3fafe4ed702900b01c14e506d13e3bbeab19b357e5ba9fce8a4fc3dcc469406a16248d6fb53862781fd9d55e4\nB = 444e5a673eeb37fd3b4f6b6f5133b0f46c2ea532e1953da4a0e144407a8e2534c5ff40cc9af7756e5aff9df57d938fcedaffb",
+    "868dcf4e458b36f506ed7fe0ce5\nM = 7f5978c0c066132a9bdcb00727bb802b72777b9e8e4265f76b80cfdc3a788817\n\nModMul = 5c717e5dd25abe60f761d6f9326ed056416add4c1384682d87b7ff12e112f855\nA = 4351965a421c75c5b4c251861e53316a300ed7983e27e17f9308420f0d2cb11e9c476294fcd9042a525bc1a044bb442d1d9f853c9e07245170e0e2711010cd1c\nB = 4e1046647c362c8f9c414be54075b4e9d151c6fa0c3da40d90e6042625947ca2c9f20cfbcfdab8666dac5a15f6cda9d47b09f654131fc5addc07e382c9639323\nM = a6c789884c66c7f028099e0367b3ed86871277bf070c541ee12fc02fcb6181d7\n\nModMul = 4452688244f542125168853f1d444f96ab0f82903bb12a97e59f0db633edfd6\nA = 9fd1cc81981bff977244c044146918057ad06d3cc26edfb8fb4118ee02b959d45555f9507ffeb23c3688e29ccdfe5f583fa3761f6727573542bee8ab5f5b600d\nB = 856e6a03b5c93fc19deea51b3bfe42c810c5bcf9ffbd08e2625eb209baf6a4e24943a3c090d89c1f70aea9f0128e511fe92e03715d917168c1e1ca77a3a8731f\nM = 2c245d407a78903ef2b279ddbe32106e6333b6f44cabf87b8641b047c79ea06b\n\nModMul = 375f8474ee47df6b9a038512002e56cddd374d69c69719d8d369232c64a839e2\nA = add40f1dd6d4a2414b17f0c628eed9a8f082f3ad1f34ec41935fa86b34d4505b22ea80c062386a9ed63f95c67e55c686f837bddf8f4da791f98b08c02f32d4b2\nB = dab1caaa11d5a208b7a6b7a1d6482a4859daaba5e3a77b1b1020e8ae62a664953dfddd0b47d40526e7a3c6a5363c6d41dd9f529fd8b58d5d31bb67e745cb71b3\nM = 4f506313a4f49873a405f2e5a6e9cfae9cd5e9f67b5ef900153366570e28a955\n\nModMul = 36fb0733a26902f0f8f11625305a3c94fcdfffe294eb6ccba110aa628a314df\nA = 52ee1498bd6a1677db801ae2eab4951345a1fcf8fe7d38e3f28dbc27fae508d87c9958e02a375ff4891b88ee916b96331e7cc082615faa028f6d541b5ce37876\nB = 9343cfa074f50c20e8472f8f7c4a7d330aa30ee417ed8027a4c956e84cc5cb31d5411c14796d9325fceef79a51b5d8a4c89182ca273ab633e6a7b22a27352300\nM = 9d7c334aa33634f9f313b71b42476a3b627a6c5bb8ac1d07a8d732d5c087bd9\n\nModMul = 4a377267508eb045e00cea66a417112dac07545304bbeac6315625275b7cbfad\nA = 19616a82b75b08499d4b1f869df2db8f71398672f3f97ffc6177a4a5aa913605ce8a6ab5f778cac508f0b3f2aa680b01ccdc57c0fdd6cd678a2ff2dcd7f01f3c\nB = a5643a9a9fe3be4134082daae4ee7dfd85d9452beee856fd939d3be9788b6bebcf3571c67ec481ff9b20f70d23e82e2171b1d0ddf0a9435b40115d32aedb6811\nM = ea0477e7f1a02cb6c21171066f3dab69d4e24429043b0f049de660fc80e51937\n\nModMul = 7952dfdb91252658430e365adeefd9093740de92cfc9dd3d92294f2dab6ca0b6\nA = 8e6cd7639b7c134b53e6ae6ac5f51268da83ed09e8e96d65e4bb130dcdbbab9e48226ddba6efe93faa510bde8ee92f2a641774c4272b5a2f88024b77a2cfa110\nB = fe4e8109a49b16b96871e384564cc096277dad4e1bbca8e5feb33f140a4fb800c8f3096b1bc7042bccf249aede88e6055c0db609f94e214b1251eda494be724b\nM = aa46853682af960824140c35d145a6dcff6283b2c59994b30ecf9b8def41a025\n\nModMul = 1aacec7f7e66b0cf4eb2dfda9d8d3fbf4eb8e928cbbc967d13e3e38612f0346d\nA = b0fd7a936b0908ba6fa797e4b855d673ff85d665ef3a345e560e2c0049becf5c25b6c0068dd617ab47a8fd151939ea0631f86806ddd40e557933c0e880fcdd0b\nB = 105c87fe2b1bf0be5405ca0d530beda1780f0045e892d7810f8a8abbe890f0a19de66497cba55bf38e190c52992467c22a320c38a4bd167f774ed812f1271d5a\nM = ac4f0a2b22df691331ded955a5d0e7d1910d7920a59d4a87636b2635397b7335\n\nModMul = 2c25d180156fa7d2fc20c9bd6d9ff0b111c9ad76ada0784e2f8fa0bd06413f66\nA = 2aa4a0a73df11f4e60956619d0b35eaef45730d619f9b920298e6d369b9861f6411de28a34af038f288d7a3d6a35b10c8082b8ad0fb275a8f67c6832ac46ba9\nB = fae1d50b72feb25da2581829409391bf289cd9f730c99d265b5b2d63889381cde4adbf85c3998c2478f2866526b8f64605d75765edd09b78ea45337207d173\nM = 65c9d79a09a820adbc9beb152bef387c1439147ed50cef872d36a69f1c7d5fe1\n\nModMul = 56ec8624fc199e7b4e68358f88f1a99f1d4d02577b8c6f7e28e4ccfdd981f995\nA = b0a0f9d05d144d2ef257c1e63a7127a3b8e0d8b64ff8f6447618560593574b5c5da6258b274efc28da0defd988bef1efca0f481f809665a78954b36741d668bd\nB = 10901b9dbf0016cbcc671da75a75b7a6ec6a66dd17b53a97344864b08f037098537380bfb0137b6becfc36a75206686d16bc4eb8fd54299494374e3f383d9b10\nM = 73882376ca850c125ce9f20c291e550ee48f0eb0d571109ab08c22d6719496e9\n\nModMul = acceebe131aa34ff21b3235f045bccc8a8f762dca20c1dd1ef6eb461ea971c6c\nA = a7714b249eb0f0cbe3e6fa0b04e895fcf14c404876197defafc6b57026ae7e5e993fc47c1819581adc03860ce07f2b7877a3f6d0912c0cbc659f5f6170a1cb2b\nB = b7278ecd154ef5243ad973ead291ea186acb63e09977e644a6a9fde195d1a33993fc47c1819581adc03860ce07f2b7877a3f6d0912c0cbc659f5f6170a1cb2b\nM = c52ae49e1a4b21ec392b76844ad559653b7b9f67a58b3bba6c2ce250017eab09\n\nModMul = 62b5b04dc84bb4ee04934c03ef361bc6e59b42144dc117b9f7771525c67c3688\nA = 2b65f491caf0b5cd9c66c859fbcadaec7213e6b848884638791b1620d6e4bc9dde087af0e7329d3b15a45df2d43ebde61b053ad7f63917aa922d58b4f3222620\nB = c1bfcdb34b0766be980540dc3256b9ee4158310fad2c43cf24bfafca08ee185647043f5842a9d9eda224449259341b7c50998086434528d47661bf5762a7ab5f\nM = f73398c32191b436d14a0b76c6069b1d61395568753c832dd0c707780a232dc9\n\nModMul = 5613c8fb0721bd3f605089def48fb2c38a4862bb387886c1edc1bc37d10f0e15\nA = a3d8b12a2c8f4021ca045a4e4903687dea63ee7e88893b1911aea77efbff00f8f5c7884cbafc71f59fa2636195c2ebee61edbf642923f34d87ba5eb49b06a7ee\nB = 3231829c81b26dcac432b502ce22e126ab564922b1e9818cd3da46edc5ce7df026d0e515809c97bcfdb9666581efbfd364437ba9959dfad099f90472f97c69ec\nM = df8344fa848d1066afe4f8d985cff65441751677dcf3a4e99b40365fc3c978e9\n\nModMul = 30325f7ccbc2c69e11d739ad7132a947c53377aa902ec70b152f3a75e050c244\nA = e4ba620125f58a63fe12fbd3eccdea477d56b120c76d5d1421bebd74e8686b4093f8169070453ccc04b63b173568385313a1d9c841a4aa82a61cb84d4286a941\nB = e87aaa990307855f8e5f2e5509d2ce31dd4b13bb7199cf5fa0593e350326e222efc33a26c69245565d6ebb5a484cfef7d2558f22dea8054d07831d536803d0dd\nM = 43d57108eb0ab9bebaa8ce137628ea825951c6accb9acb7f1e991c93b8563897\n\nModMul = 1975db7b72434ad32c9aee412645f6670b7f4af1f8a424a5031c559d3e18dce6\nA = bd64b1db27fa7da4c92a4ee092f58a2a53ed0f12d009fe13b36d5fd585defe778fafea4a60e8fe567d03e9ba3b72b189e22504ae8ca6aad7c2ac0f44abca2f6\nB = b487d8116198560d6c5b08c7ce63b0acc0c98e6f2a8d709cf4e3a409edd55f64d72fc27a70dc341e280ff5a1b09fe131773d466cb31991d2db23a2a86d225c80\nM = 39d57af763eabe569dac1a103e169e6e3b4375168e41e5c3b961b6e743915923\n\nModMul = 3bbb5bde9e3e240694326571360090e1fc0a4ea7b2311c1e0bd3961f6c159385\nA = 4181ee3bf9a98bcd49eaea243a179cddbf160981efc720685c7be1dfeb5aa552685a2cd46f340e1e1da893b3b460692fa2eaf6c100f24a14f239e45123242d53\nB = 77cd04d86dd5da322af78be54246dd6b7af490d903db1db03cbccde535570b81c6053a84110c07f097540ffe7510320024b7bafb77e9e239761def76092e1d59\nM = f3b9833a303eb540cf8b6cbc3cf16394b1634ef517be57684e42d364d8bec3e5\n\nModMul = 2d8174211f0367233b3a8df7c5bf0066d6aa792be7cdc5e850a477454d5c829f\nA = 1c08cec52d96136fbd9078b7b8db36ab63b86e19dd3dba7b2e3190ff566180e89dfee9423fa4e99be2187eda6aedfa86b9a45eb1e4655257315ae6a280f0a6ee\nB = a8b4bc9647d8df9b7c76cc6d0f2248cdbc41f5da9c061f9864aa8415c9557582cada456cf23cc32d47d1fc1caf19d36b398019aac4734e10f55ce3cad419e5e7\nM = 7eacffe21f88413af94155a2a8e37f70a431a59653738afda04a1bec72d0d9ed\n\n# Regression tests for CVE-2016-7055.\n\nModMul = ccd6f75b5f24b7c5ce2ce755fa89c2450c6a7d96ce8c8791e659eab84577a7695e3b2caa7c980fb23f60634233e9798499c28b0338c1f1a326d0ca89fd41f2fd88b759f317889832966b551a950043ec7a4b6152d3e2cbfb40e88458e70ab783b96f12d271f828d5b39e198ccaf8665411d85026282dbead5d24cd01b6c8a8e9\nA = 7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878\nB = 095d72c08c097ba488c5e439c655a192eafb6380073d8c2664668eddb4060744e16e57fb4edb9ae10a0cefcdc28a894f689a128379db279d48a2e20849d685939b7803bcf46cebf5c533fb0dd35b080593de5472e3fe5db951b8bff9b4cb8f039cc638a5ee8cdd703719f8000e6a9f63beed5f2fcd52ff293ea05a251bb4ab81\nM = d78af684e71db0c39cff4e64fb9db567132cb9c50cc98009feb820b26f2ded9b91b9b5e2b83ae0ae4eb4e0523ca726bfbe969b89fd754f674ce99118c3f2d1c5d81fdc7c54e02b60262b241d53c040e99e45826eca37a804668e690e1afc1ca42c9a15d84d4954425f0b7642fc0bd9d7b24e2618d2dcc9b729d944badacfddaf\n\nModMul = ccd6f75b5f24b7c5ce2ce755fa89c2450c6a7d96ce8c8791e659eab84577a7695e3b2caa7c980fb23f60634233e9798499c28b0338c1f1a326d0ca89fd41f2fd88b759f317889832966b551a950043ec7a4b6152d3e2cbfb40e88458e70ab783b96f12d271f828d5b39e198ccaf8665411d85026282dbead5d24cd01b6c8a8e9\nA = 095d72c08c097ba488c5e439c655a192eafb6380073d8c2664668eddb4060744e16e57fb4edb9ae10a0cefcdc28a894f689a128379db279d48a2e20849d685939b7803bcf46cebf5c533fb0dd35b080593de5472e3fe5db951b8bff",
+    "9b4cb8f039cc638a5ee8cdd703719f8000e6a9f63beed5f2fcd52ff293ea05a251bb4ab81\nB = 7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878\nM = d78af684e71db0c39cff4e64fb9db567132cb9c50cc98009feb820b26f2ded9b91b9b5e2b83ae0ae4eb4e0523ca726bfbe969b89fd754f674ce99118c3f2d1c5d81fdc7c54e02b60262b241d53c040e99e45826eca37a804668e690e1afc1ca42c9a15d84d4954425f0b7642fc0bd9d7b24e2618d2dcc9b729d944badacfddaf\n\n\n# ModSquare tests.\n#\n# These test vectors satisfy A * A = ModSquare (mod M) and 0 <= ModSquare < M.\n\n# Regression test for CVE-2017-3732.\nModSquare = fffffffdfffffd01000009000002f6fffdf403000312000402f3fff5f602fe080a0005fdfafffa00010001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000002000002fefffff7fffffd07000109fdfffef3fffdfd06000405ff00fdfbfffe00010001\nA = ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff00000000\nM = ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff\n\n# Regression test for CVE-2017-3736.\nModSquare = fe06fe0b06160c09\nA = fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8f8f800000000000010000000006c000000000000000000000000000000000000000000000000000000000000000000000000000000000000fffffffffffff8f8f8f800000000000010000000006c000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffffffff00fcfdfc\n# A in Montgomery form is fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8ffeadbcfc4dae7fff908e92820306b9544d954000000006c000000000000000000000000000000000000000000000000000000000000000000ff030202fffff8ffebdbcfc4dae7fff908e92820306b9544d954000000006c000000ff0302030000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01fc00ff02ffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00fcfdfcffffffffff000000000000000000ff0302030000000000ffffffffffffffffff00fcfdfdff030202ff00000000ffffffffffffffffff00fcfdfcffffffffff\nM = fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8f8f800000000000010000000006c000000000000000000000000000000000000000000000000000000000000000000000000000000000000fffffffffffff8f8f8f800000000000010000000006c000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffffffff\n\n\n# ModExp tests.\n#\n# These test vectors satisfy A ^ E = ModExp (mod M) and 0 <= ModExp < M.\n\nModExp = 00\nA = -01\nE = 01\nM = 01\n\nModExp = 01\nA = -02\nE = 01\nM = 03\n\nModExp = 01\nA = -01\nE = 02\nM = 03\n\nModExp = 01\nA = -02\nE = 02\nM = 03\n\nModExp = 00\nA = -03\nE = 02\nM = 03\n\nModExp = 02\nA = -04\nE = 01\nM = 03\n\nModExp = 01\nA = -04\nE = 02\nM = 03\n\n# Regression test for carry propagation bug in sqr8x_reduction.\nModExp = 19324b647d967d644b3219\nA = 050505050505\nE = 02\nM = 414141414141414141414127414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001\n\nModExp = 208f8aa0\nA = 86b49\nE = 2\nM = 30d26ecb\n\nModExp = 27308229\nA = 17591bb\nE = 6\nM = 30d26ecb\n\nModExp = 2bdf498f\nA = 21292626\nE = d\nM = 30d26ecb\n\nModExp = 11317167\nA = 4a655df24\nE = 10\nM = 30d26ecb\n\nModExp = 2e1b88e\nA = da6b761a86\nE = 35\nM = 30d26ecb\n\nModExp = 20a12ec3\nA = ea811\nE = 2\nM = 23bc042f\n\nModExp = c42ced\nA = 1011a6a\nE = 4\nM = 23bc042f\n\nModExp = 4637d79\nA = 28d9a601\nE = 8\nM = 23bc042f\n\nModExp = 20e5669b\nA = 72fe6bc20\nE = 11\nM = 23bc042f\n\nModExp = 142ab9e3\nA = 9a07b9363c\nE = 29\nM = 23bc042f\n\nModExp = 14c64646\nA = 822df\nE = 3\nM = 30915765\n\nModExp = 160e35a2\nA = 15ea542\nE = 5\nM = 30915765\n\nModExp = 2f23a488\nA = 34d2e02e\nE = e\nM = 30915765\n\nModExp = 28e67f93\nA = 636a32703\nE = 14\nM = 30915765\n\nModExp = 29bfeaa5\nA = c8646998e6\nE = 2c\nM = 30915765\n\nModExp = 30959e22\nA = 81dad\nE = 3\nM = 326dd68d\n\nModExp = 1a1da4fa\nA = 116adb9\nE = 5\nM = 326dd68d\n\nModExp = 272bf0d8\nA = 2d21ef08\nE = 8\nM = 326dd68d\n\nModExp = 29f5054b\nA = 76989850a\nE = 16\nM = 326dd68d\n\nModExp = e6c7b77\nA = b88ee70d2a\nE = 3e\nM = 326dd68d\n\nModExp = 369605e1\nA = cf26f\nE = 2\nM = 3ce082eb\n\nModExp = 168a3c5d\nA = 1f82caf\nE = 5\nM = 3ce082eb\n\nModExp = 125c4bb8\nA = 2e9c4c07\nE = 9\nM = 3ce082eb\n\nModExp = 1c5fe761\nA = 523ab37f1\nE = 14\nM = 3ce082eb\n\nModExp = 21703009\nA = dc832165e8\nE = 20\nM = 3ce082eb\n\nModExp = 1228d1e\nA = a5555\nE = 3\nM = 24665b27\n\nModExp = 5226af4\nA = 1077bd6\nE = 4\nM = 24665b27\n\nModExp = 1b14eac1\nA = 2db3a834\nE = f\nM = 24665b27\n\nModExp = 161727bc\nA = 6bd962cb6\nE = 19\nM = 24665b27\n\nModExp = 10d61d0d\nA = c10caed407\nE = 28\nM = 24665b27\n\nModExp = 233da406\nA = b125f\nE = 3\nM",
+    " = 33509981\n\nModExp = 24032799\nA = 1656b7c\nE = 6\nM = 33509981\n\nModExp = 129ecebe\nA = 2e671504\nE = a\nM = 33509981\n\nModExp = 20c20bac\nA = 4d7a2de44\nE = 1f\nM = 33509981\n\nModExp = 2e3ce9d3\nA = c53b3def4d\nE = 31\nM = 33509981\n\nModExp = 12fadfd6\nA = b4cf8\nE = 2\nM = 36e9d4ae\n\nModExp = 457ac85\nA = 1b1c7e9\nE = 7\nM = 36e9d4ae\n\nModExp = 31debef4\nA = 3a973028\nE = d\nM = 36e9d4ae\n\nModExp = 2333ad93\nA = 552b97c45\nE = 11\nM = 36e9d4ae\n\nModExp = 99ba1fb\nA = 8bfb949cbb\nE = 28\nM = 36e9d4ae\n\nModExp = 27b691de\nA = 93492\nE = 3\nM = 298fdb16\n\nModExp = 3c2b70f\nA = 14e7b0d\nE = 4\nM = 298fdb16\n\nModExp = 1486cda7\nA = 29acff81\nE = c\nM = 298fdb16\n\nModExp = 11725275\nA = 507489205\nE = 13\nM = 298fdb16\n\nModExp = 24d14627\nA = e71c55606d\nE = 35\nM = 298fdb16\n\nModExp = 222b8d14\nA = 9b1a0\nE = 3\nM = 3db59d12\n\nModExp = 3b8bd47d\nA = 13f4e8d\nE = 7\nM = 3db59d12\n\nModExp = 17e72356\nA = 334774ce\nE = a\nM = 3db59d12\n\nModExp = 306447ca\nA = 47079ddd2\nE = 12\nM = 3db59d12\n\nModExp = 90bef3b\nA = a75d62616d\nE = 37\nM = 3db59d12\n\nModExp = 1\nA = cddd44f47e84b3276cc36a5c0d742cc703e61c4756168601fbb1b6eb598c161019562344dd56ab6f603d920a12c360b285e6496a3605a2f8d691c3598233ee9366b5f2692554893bdeb67b7bdaf35ab7273ac593145e26bed82c70ba5793bf4bc5cac4c80b01785d1496beede493806e4f4aa89fd8d41de80dd6d0a3e2742678\nE = 0\nM = c95943186c7567fe8cd1bb4f07e7c659475fd9f38217571af20dfe7e4666d86286bc5b2bb013197f9b1c452c69a95bb7e450cf6e45d46e452282d5d2826978e06c52c7ca204869e8d1b1fac4911e3aef92c7b2d7551ebd8c6fe0365fad49e275cc2949a124385cadc4ace24671c4fe86a849de07c6fafacb312f55e9f3c79dcb\n\nModExp = 0\nA = 0\nE = 8de689aef79eba6b20d7debb8d146541348df2f259dff6c3bfabf5517c8caf0473866a03ddbd03fc354bb00beda35e67f342d684896bf8dbb79238a6929692b1a87f58a2dcba596fe1a0514e3019baffe1b580fc810bd9774c00ab0f37af78619b30f273e3bfb95daac34e74566f84bb8809be7650dec75a20be61b4f904ed4e\nM = c95943186c7567fe8cd1bb4f07e7c659475fd9f38217571af20dfe7e4666d86286bc5b2bb013197f9b1c452c69a95bb7e450cf6e45d46e452282d5d2826978e06c52c7ca204869e8d1b1fac4911e3aef92c7b2d7551ebd8c6fe0365fad49e275cc2949a124385cadc4ace24671c4fe86a849de07c6fafacb312f55e9f3c79dcb\n\nModExp = 5150fb769d5c5d341aaf56639a7bcc77c415fe46439938a2190283409692f29cd080bfe3433005d98d24718a03a3553c8560c5e9c8ed0f53b8945eb18290e1c1a83d919302510f66dd89b58acc2de79ad54b8a30d3e1019d4d222556beefca0821b094ecf104b5e4cfce69d2d520d2abf54f3e393d25ed3d27e8c2e3ca2e5ff9\nA = ead8c5a451541c50cab74de530c89376d9a55c723e0cac3c84b25f0093c08a2961e49ab48966361c42c9f99111587252d98395b76788400d75c66ef208ea2767a28d6f8dc3a859f39c95765d57f139e7fc14f47c908c62df051e7216d379f52028843b4d82ef49133cce8fe671ae179423ac8da5be43b01caaf425cd969300cd\nE = 8de689aef79eba6b20d7debb8d146541348df2f259dff6c3bfabf5517c8caf0473866a03ddbd03fc354bb00beda35e67f342d684896bf8dbb79238a6929692b1a87f58a2dcba596fe1a0514e3019baffe1b580fc810bd9774c00ab0f37af78619b30f273e3bfb95daac34e74566f84bb8809be7650dec75a20be61b4f904ed4e\nM = c95943186c7567fe8cd1bb4f07e7c659475fd9f38217571af20dfe7e4666d86286bc5b2bb013197f9b1c452c69a95bb7e450cf6e45d46e452282d5d2826978e06c52c7ca204869e8d1b1fac4911e3aef92c7b2d7551ebd8c6fe0365fad49e275cc2949a124385cadc4ace24671c4fe86a849de07c6fafacb312f55e9f3c79dcb\n\nModExp = 1\nA = 935561297d1d90255aef891e2e30aa09935409de3d4a5abc340ac9a9b7dce33e9f5ce407f3a67ec30e0dc30481070823f8542463e46828d9cafb672a506d6753688cbad3d2761079f770c726c0b957071a30876c4d448e884b647833befbcd6b582787bf769d63cf55e68c7b869a0b86374f8920516cf5d528f348b6057450a1\nE = 0\nM = dcc24236a1bb94c71d9ec162a6aa4697b932717e82b667cad08b6bd1bbcbddf7cd167b7458de2b0b780486b39574e749d6405f9ede774a021d6b547271523e9e84a6fdd3a98315607ccf93356f54daa9c75e1e311e1672d0dc163be13f9ed6762f7dd301f5b0a1bb2398b608f40ac357ae34fc8a87d4fef3b961cbdb806d9061\n\nModExp = 0\nA = 0\nE = bb552be12c02ae8b9e90c8beb5689ffefe3378d2c30f12a6d14496250ecce30317c642857535a741642c3df689a8d71a276d247ed482b07b50135357da6143ac2f5c74f6c739c5ff6ada21e1ab35439f6445a1019d6b607950bffb0357c6009a2bfc88cd7f4f883dc591d4eb45b1d787e85aba5c10ee4fe05ea47bf556aec94d\nM = dcc24236a1bb94c71d9ec162a6aa4697b932717e82b667cad08b6bd1bbcbddf7cd167b7458de2b0b780486b39574e749d6405f9ede774a021d6b547271523e9e84a6fdd3a98315607ccf93356f54daa9c75e1e311e1672d0dc163be13f9ed6762f7dd301f5b0a1bb2398b608f40ac357ae34fc8a87d4fef3b961cbdb806d9061\n\nModExp = bbad67352704a6321809f742826bf3d1c31c0ad057bf81432abeb30dc9913c896c03e69eb1cde6b78ffcb320c4625bd38ef23a08d6c64dc86aec951b72d74b097e209ce63092959894614e3865a6153ec0ff6fda639e44071a33763f6b18edc1c22094c3f844f04a86d414c4cb618e9812991c61289360c7ba60f190f75038d0\nA = 855144760f2be2f2038d8ff628f03a902ae2e07736f2695ec980f84a1781665ab65e2b4e53d31856f431a32fd58d8a7727acee54cc54a62161b035c0293714ca294e2161ea4a48660bf084b885f504ad23ea338030460310bd19186be9030ab5136f09fe6a9223962bce385aaaf9c39fe6ed6d005fa96163fe15cdfa08fc914d\nE = bb552be12c02ae8b9e90c8beb5689ffefe3378d2c30f12a6d14496250ecce30317c642857535a741642c3df689a8d71a276d247ed482b07b50135357da6143ac2f5c74f6c739c5ff6ada21e1ab35439f6445a1019d6b607950bffb0357c6009a2bfc88cd7f4f883dc591d4eb45b1d787e85aba5c10ee4fe05ea47bf556aec94d\nM = dcc24236a1bb94c71d9ec162a6aa4697b932717e82b667cad08b6bd1bbcbddf7cd167b7458de2b0b780486b39574e749d6405f9ede774a021d6b547271523e9e84a6fdd3a98315607ccf93356f54daa9c75e1e311e1672d0dc163be13f9ed6762f7dd301f5b0a1bb2398b608f40ac357ae34fc8a87d4fef3b961cbdb806d9061\n\nModExp = 1\nA = 9d92629c1ab181c50c31619e8acd0d235a1f5fc7a0bef4d4fd54b4f1968d45921f8522efe88e69c6c14c576c564592b9feb00d1554b88b038934eaf4a8ce81a2582732387490181ef158360c8b2d9ccb326ffe043f776a50cb8202837f08ca743b562eefa007150ab7012c341b16248478d4775c02ad71ea13d5e82b71e2d600\nE = 0\nM = cd607549668469b792f495c141e500871880b0611c8004293a561ec7f9ab6561f8a9b90872742386adafb5cd1890e8204ae12aec529cca0a9e382c96439137f09de9973b12c8492c62847e107deabb7dd946ffbb9d0ac73b462c481092bd65326a17f21d8d6527c47a5dba50aaa20c7048b8788a49eb3ea5f29bd5cfce24eb3b\n\nModExp = 0\nA = 0\nE = 9f43dcb641f3ecf4dbc97450f2bdf3b7ec6a2f3e8e96bb1df2bf34b8d2d78e1a9018d04d960ffd0e932cfc60d3b9b923e3f9f29b3f3d61cae3a9f7245078143475c7fcb896ff200f7d94c4f2708bb42750e37c185a31c876814e4f06a00771707654e1da2fb69c16b6500b16385e3b933e2276ad3569977473f699b1c7926c3b\nM = cd607549668469b792f495c141e500871880b0611c8004293a561ec7f9ab6561f8a9b90872742386adafb5cd1890e8204ae12aec529cca0a9e382c96439137f09de9973b12c8492c62847e107deabb7dd946ffbb9d0ac73b462c481092bd65326a17f21d8d6527c47a5dba50aaa20c7048b8788a49eb3ea5f29bd5cfce24eb3b\n\nModExp = 24eaead5b57883c2f454928f8edd470a344bfe07a953194f7d635d705ef13ddfc64140c8ad6f363d4c828e7c7891a6b6d4df37335de4552c319dafd1c06d1f743240082a3535df4da1475d3eea3fead20e40815fd5a0876c881c162ab65a1eda494280c258901ca953d1d039a998bf0e9aa09273bbef4865f3054663b72d75ff\nA = a31618b4532f53729ba22efb2221432fab1dbb70853d6a1159b42fd19fc949965c709b209de106a652aa422d88922ce51dae47f7f6deaf0055202e13db79ee84fc3d3c6f4c003ef96597c49d6895fa53c22ac9e4819f7048146b5272f6279424fdb389819a0b251c823c76f4bebf4f1246de455aafe82a0d34454f5039e90839\nE = 9f43dcb641f3ecf4dbc97450f2bdf3b7ec6a2f3e8e96bb1df2bf34b8d2d78e1a9018d04d960ffd0e932cfc60d3b9b923e3f9f29b3f3d61cae3a9f7245078143475c7fcb896ff200f7d94c4f2708bb42750e37c185a31c876814e4f06a00771707654e1da2fb69c16b6500b16385e3b933e2276ad3569977473f699b1c7926c3b\nM = cd607549668469b792f495c141e500871880b0611c8004293a561ec7f9ab6561f8a9b90872742386adafb5cd1890e8204ae12aec529cca0a9e382c96439137f09de9973b12c8492c62847e107deabb7dd946ffbb9d0ac73b462c481092bd65326a17f21d8d6527c47a5dba50aaa20c7048b8788a49eb3ea5f29bd5cfce24eb3b\n\nModExp = 1\nA = a8558e7f455b27c0c46d7d0862eb409cdefbeca945e0284b5bf425b7ac0f3d316bc365594cc1639decffc621214d61479bc75135120d4ac09ea8b742ad7ec1822091b62b1c6f564fe5e2f4f5b7def92cbaaa9a898549207ab01b91c2324fbd306a87f7d6379b6fb6493c5fca76729767f136120da9c90bdc7d364f7d242d5acc\nE = 0\nM = 88f3c87ac5e3272a21b8a858da640d6939fb8113a95412c38663a0f352686d69a5d7927e60b484b9fcb8ef12978fe25ff2ebc9b61c5450e04222ef20ba3cbbdc5ec45581ce0f58e10be7bb9de7fa08752303a7a1db23b2ac9c6692ec63bf09ecd6639e06c5491ba568ea886620d71da32d329615f0e1443a75d09ae35b8a2d7f\n\nModExp = 0\nA = 0\nE = a5524b41dfc6b570df1d8f6633ac7777c1131abe3a99c6166b0d29d3b8883c41b00a0c53cdd6f42820bf05c810b6ec53e77a8c1b9344ea0c91d4f410a2f204c369f3db33bf8c88217fc2cf802a9d9bce8119242d8e781875b85431be170076498c0963574ee423551aec9557e2fc672ab1ab5d0cbb1c400535df9481e7934d8f",
+    "\nM = 88f3c87ac5e3272a21b8a858da640d6939fb8113a95412c38663a0f352686d69a5d7927e60b484b9fcb8ef12978fe25ff2ebc9b61c5450e04222ef20ba3cbbdc5ec45581ce0f58e10be7bb9de7fa08752303a7a1db23b2ac9c6692ec63bf09ecd6639e06c5491ba568ea886620d71da32d329615f0e1443a75d09ae35b8a2d7f\n\nModExp = 292f0b39ca0f1c850b1a00cffd2d54924fcd5fc7e7504c9d593e6c0ff74760b1f4bdd81679fe06c50248336f3108c593fa111072ee87d0fcc89a63243a1dc89044503663eee9bc18f51c3e0193d9108303e12ac90ff78f6ec752a4386af09c42db524a7cbe9a3d4fcccd56c34d283bcc9debc17158b5fe8df0c1888a9841bf8f\nA = b4fde2908745ff92cc5826a27dcfdda09e8fffee681844fa4c7f1354d946d5d84e0e0c7a4a4cb20943d9c73dd707ca47d796945d6f6b55933b615e2c522f5dfc33e0652917b4809bab86f4fa56b32b746c177764895492d0a6a699812b2827fe701d40ef7effd78ea8efe1cac15ff74a295a09614bf04cae1a5017872ba22efe\nE = a5524b41dfc6b570df1d8f6633ac7777c1131abe3a99c6166b0d29d3b8883c41b00a0c53cdd6f42820bf05c810b6ec53e77a8c1b9344ea0c91d4f410a2f204c369f3db33bf8c88217fc2cf802a9d9bce8119242d8e781875b85431be170076498c0963574ee423551aec9557e2fc672ab1ab5d0cbb1c400535df9481e7934d8f\nM = 88f3c87ac5e3272a21b8a858da640d6939fb8113a95412c38663a0f352686d69a5d7927e60b484b9fcb8ef12978fe25ff2ebc9b61c5450e04222ef20ba3cbbdc5ec45581ce0f58e10be7bb9de7fa08752303a7a1db23b2ac9c6692ec63bf09ecd6639e06c5491ba568ea886620d71da32d329615f0e1443a75d09ae35b8a2d7f\n\nModExp = 1\nA = e2845c572b46496ac158a731f612fd40ef626fa7134755c25b1b7614f4d7b29164e6142ddb7985e4c7ebc575855ff901e95927fe98a5aea2ad3a4720c75782323bea1518b2c57790f44efd9411be4e95b3896bad1e73c59658290b309e5a7eb5ef8be08125063e57336b80f17eacee88966d12bbaaa15a25929c82e027cf696f\nE = 0\nM = cf0dee80177869a532f0c6c3a0bda3aad79bdb6b70b6c227b32d75c26e394a90c1f2a6c2bb841ba9f6556b15654a79d8b1dd0c90709a093497bf40be0807cdbb378a74de5893c25067224d3ea8d37387ed6c4a981138853cb89caa9ce6cd0f6a1e95de24d558e90960f93844db4d01e372650350d45a9d34a36042b4d4b9e78d\n\nModExp = 0\nA = 0\nE = a55703a72ca3f6074b939ed3d748196a684a3c8e411c2b39a9beb98993b6eb7ea3fa16f41bc5b5c3710b91c0fc74a8072793052f872f61695db3a2df872eaa427a110f1a8d568c85d58bd350d0df8eced7a10be80f7567360c1a8047b9c44aa2967cd0d9dd2caea2c1492358c2db4f0214da343fdf2e34272865dc5c63be2ae4\nM = cf0dee80177869a532f0c6c3a0bda3aad79bdb6b70b6c227b32d75c26e394a90c1f2a6c2bb841ba9f6556b15654a79d8b1dd0c90709a093497bf40be0807cdbb378a74de5893c25067224d3ea8d37387ed6c4a981138853cb89caa9ce6cd0f6a1e95de24d558e90960f93844db4d01e372650350d45a9d34a36042b4d4b9e78d\n\nModExp = c90e4c69df92e26549b016950b59080947f5403430698e128477782480dd70be96bed2b9042dd8c708eb432e02710555b97af11ce6fa9b53395022851c32d1f53f04237fb0763563b440ca6e81a50d909d907d9c26b7d3c420dbf88f7dadd488666848135f8cdc608dcfb0691989289fb54379c2e84c262f9765f68c012ca1b9\nA = 882ea1b9b6c79a3b1bdfd284658cb6227ad825e0178cab713c7413c2ec34f03cfaec470c4f5c521f5e9899a2123878ff0f5b36a4196c08ad1b04d03746c4bfb5d126f5eefbfe172627d6732710a8ac8890cedbd4fdef69a19f2b3253a5aa0e5dd5484f72d59b17bdd1dad3db209a3ab839368ed3975069685911d7b35e41a9e6\nE = a55703a72ca3f6074b939ed3d748196a684a3c8e411c2b39a9beb98993b6eb7ea3fa16f41bc5b5c3710b91c0fc74a8072793052f872f61695db3a2df872eaa427a110f1a8d568c85d58bd350d0df8eced7a10be80f7567360c1a8047b9c44aa2967cd0d9dd2caea2c1492358c2db4f0214da343fdf2e34272865dc5c63be2ae4\nM = cf0dee80177869a532f0c6c3a0bda3aad79bdb6b70b6c227b32d75c26e394a90c1f2a6c2bb841ba9f6556b15654a79d8b1dd0c90709a093497bf40be0807cdbb378a74de5893c25067224d3ea8d37387ed6c4a981138853cb89caa9ce6cd0f6a1e95de24d558e90960f93844db4d01e372650350d45a9d34a36042b4d4b9e78d\n\nModExp = 1\nA = d7a99e65b8af86b1c51d851f0447e43cd4f343cb0ada7236283e69aa7ebd383826acc9809e5dbc4002d0f2430022cb026458189db3805ce2de1142a31ba71a6c064ab51f0059eb4b931b8bcbaef023c38d57aa5f3e14f5df77e547fc028702071b58bd57338be1e1e4f98d3553484e4de359cefa29c5f58d3fa5d823f389dbef\nE = 0\nM = 8315dacf124bd473c578946347e83d1b20c750a7d9533d6215591be40bc78bcca77821f8c8f95375bbd6372515ada63d22bed2fa49bd6fabb0040c538d08db25b09d2fda02a93ab086cd1c27df93c37ee9c6a0527d089179b8f92b5dc3acf5ef1c75906fb80b03f5c2442a7a4088640f66376575ecfa4c697c1a571397ee5a0d\n\nModExp = 0\nA = 0\nE = 95793fe33696f53e37498b2b65aaf27079e27acf1da97dda2c3e0803e8a02139f574e04ee03f7d1ddd029f528e3f3644515ad6f10f0beac2767f23d9cd8a8b9b6c6e376e36b64a0ae2711d7d31a5a75011641935b503110edbefe9f0ff2da27b5c5f6bb8cc151fdc86f67191bb99160c6cacc86ca368d5bdfafd3f3ff5161b1e\nM = 8315dacf124bd473c578946347e83d1b20c750a7d9533d6215591be40bc78bcca77821f8c8f95375bbd6372515ada63d22bed2fa49bd6fabb0040c538d08db25b09d2fda02a93ab086cd1c27df93c37ee9c6a0527d089179b8f92b5dc3acf5ef1c75906fb80b03f5c2442a7a4088640f66376575ecfa4c697c1a571397ee5a0d\n\nModExp = 186c50ae259aa0fd31859cbcfea534e626a254de33956d5d719334bb32e7cf37cf199a21f079a5b90497228994d05efe19ccd8c769cd81f896286e8ae557cacd1630a928c629ecdfece29ab3697794aa707734e007318fa7029b050bb09ebbe6986187c6ca843f55266d275620b3f0fec0ad5f847ce8b314d929d128b33a249e\nA = 9d5e345793faddca9867f23eeddf6816c1e837f7a2cf96fa077212514acb6be87ac01a237d8f2f1d07d27a8ddd1b0ae0d97e1bda4f205a89435017284cdedea3e407b1b940d6f52112b6359b3e86e4c83074b17c210ae2c8856b42b169b4a7a6dfa65b368a7959496cf9bb1ee93d019dbd79101830e3f5ed08604ab90890b914\nE = 95793fe33696f53e37498b2b65aaf27079e27acf1da97dda2c3e0803e8a02139f574e04ee03f7d1ddd029f528e3f3644515ad6f10f0beac2767f23d9cd8a8b9b6c6e376e36b64a0ae2711d7d31a5a75011641935b503110edbefe9f0ff2da27b5c5f6bb8cc151fdc86f67191bb99160c6cacc86ca368d5bdfafd3f3ff5161b1e\nM = 8315dacf124bd473c578946347e83d1b20c750a7d9533d6215591be40bc78bcca77821f8c8f95375bbd6372515ada63d22bed2fa49bd6fabb0040c538d08db25b09d2fda02a93ab086cd1c27df93c37ee9c6a0527d089179b8f92b5dc3acf5ef1c75906fb80b03f5c2442a7a4088640f66376575ecfa4c697c1a571397ee5a0d\n\nModExp = 1\nA = e6a079bdf7b0638d50b183475e9ddfd5cbdebfb29f5fae8e9be402a0bd36085737b556492ea7fb4b1000ae9ce59db66098129b757cfb29224275fdaa46b8b7eb18a93ca7d3e446dc38c734b683d7ba7927b008d993aab01f44239d3c76be76d1503908e9b5e73b36c43ae0771368b01f39c042693bd92c4fc50810f059e1b332\nE = 0\nM = 81dd561d5d5327fc5ed7c9236b5fb21ef713c6d5e36264ba65ccc801b8eb107b714aad65bb503bb1f4721c0a6f97e5ab89300f049f42a4616ae43d29c089c286687484d18629c1be1b5befbdd0b3cfc86b1d28add89df4cc5e68dac3f56f2490a9068ca9c634ec258c030ec5023baa9133fd2af32fd1112895f9da549d410247\n\nModExp = 0\nA = 0\nE = f0460c5ca9b3a5c2d1b93c201d020dc43e1c81d1daba432e2cd310902da23eb81a5172b0b357484eb8fa2c04c270893b8198c8ad35453405dadaf05195b3aeb5ec0ccacecb4b6227ca43b27b97e240a4148a472670ed60f304302f757495fd4a91af0fe09800db0c3043a6ae213bee6703ad80523ca433d99ca0eab1e0b7c929\nM = 81dd561d5d5327fc5ed7c9236b5fb21ef713c6d5e36264ba65ccc801b8eb107b714aad65bb503bb1f4721c0a6f97e5ab89300f049f42a4616ae43d29c089c286687484d18629c1be1b5befbdd0b3cfc86b1d28add89df4cc5e68dac3f56f2490a9068ca9c634ec258c030ec5023baa9133fd2af32fd1112895f9da549d410247\n\nModExp = 60719701a2dc0bcde281a93ce0b8421d1a718adee43c1b5d9fe9e697a48ab3db4f9f33c73cff305ab6b6c300c149b05c6b289dce4580860dc56bc59de81ac074ecebdc65aa3ca040b44e5b3c80ddba1658d78b9abbc4c77e5f171f5582e70ab4438a8e1e2f062d618c4ad09c70c73b5b5fbc9f8f0bbdf1d530a933b705f85af8\nA = e1b400cd3b1f2f1c6b437adfdb970d2c8108f1b39bdbb13582179552011c6c97cba6bff2c463212b7f62776aa3e3aff9f175990e79395e819c144350b0a23d61638d500ecc97726b098e1af334aece23a851c718612442c04eb7b3805a24cc8f5b90042145eb5e5d6a408092832b6bbeb8a621419a9282fb5c075f41c7f1fdc1\nE = f0460c5ca9b3a5c2d1b93c201d020dc43e1c81d1daba432e2cd310902da23eb81a5172b0b357484eb8fa2c04c270893b8198c8ad35453405dadaf05195b3aeb5ec0ccacecb4b6227ca43b27b97e240a4148a472670ed60f304302f757495fd4a91af0fe09800db0c3043a6ae213bee6703ad80523ca433d99ca0eab1e0b7c929\nM = 81dd561d5d5327fc5ed7c9236b5fb21ef713c6d5e36264ba65ccc801b8eb107b714aad65bb503bb1f4721c0a6f97e5ab89300f049f42a4616ae43d29c089c286687484d18629c1be1b5befbdd0b3cfc86b1d28add89df4cc5e68dac3f56f2490a9068ca9c634ec258c030ec5023baa9133fd2af32fd1112895f9da549d410247\n\nModExp = 1\nA = 9dd1e6f2d3ff24096b54e0ebf0f10e283e484a1cbafc0431adda1296ed97692f3ba99440fd4f67c96dd8bab850e1123361c99362df9ea205ff8e90d1b329459f54730992d5a360e46fcc5f5a909e691abb9a06613d6991bd7c2aa609f0d7b441d7ded0c07b8c394327672d38a905efb2d76aa3be5bb14d0c002aa37e287aee79\nE = 0\nM = fda6f9d8588e3614f5a68ce867a5619f6ddbb8d64450ff402e1c4f1a08b518f79dca21e5983c207c5b7324c16895a1e9f1282fc6cf60b0645f6b02b652ed5b129e67c939e854ab492dec30ea878c3edde10a4b7d1d14c57100c6cbcc5fc085a0d7308715ed132fb",
+    "917251919c727487fedb66500d5610b0014a43419acfbb92f\n\nModExp = 0\nA = 0\nE = 8622c37631e428402343dccf8ed09d47b3f4201e95058910289a62707c3ce0b7113c390056cc4796cc9893e471b12cb3f63f900f3356ffd25c8b2fed6f6a7fba2c684eb241ca706c76cecbf72473d8a58c02338e40714b5610465cc319f0a529a7aa3898d9e638b247abd1380c6e8f7fa210c9f1a1a2164db6db83a6bba79436\nM = fda6f9d8588e3614f5a68ce867a5619f6ddbb8d64450ff402e1c4f1a08b518f79dca21e5983c207c5b7324c16895a1e9f1282fc6cf60b0645f6b02b652ed5b129e67c939e854ab492dec30ea878c3edde10a4b7d1d14c57100c6cbcc5fc085a0d7308715ed132fb917251919c727487fedb66500d5610b0014a43419acfbb92f\n\nModExp = 86fb0b8dc161c41de2adb0f3ddcc8ad49c1efd729a52793a3ac987d4011c9c1dadb18657dca718df75c8ddcc49d60f152c46ab85ae9076ee7bfd405679a7da3a5195a1bbfd7d2b998c7b135ea91f8c445cbafe1276fa502c2a85477716829a2e0d24ba02623405a3654bed8f355bc7ccdb67c3f9a01e249e358b60d7699498a9\nA = 816610e6018ca47074d55750dd16a281019dbf95dc752605794cbb8ea8d75775317ce685737859728320b529fb3b4414b40bf3a93d08d8994a21ae54682cc1c357eb529837a7b0129a0843eebd9341c9bee3a8ae30475bdbff517e885a0c9f2b6a680643bd981efb53bf9dd49f3dc3cb757e117895fb34b1b4336d9bf8384558\nE = 8622c37631e428402343dccf8ed09d47b3f4201e95058910289a62707c3ce0b7113c390056cc4796cc9893e471b12cb3f63f900f3356ffd25c8b2fed6f6a7fba2c684eb241ca706c76cecbf72473d8a58c02338e40714b5610465cc319f0a529a7aa3898d9e638b247abd1380c6e8f7fa210c9f1a1a2164db6db83a6bba79436\nM = fda6f9d8588e3614f5a68ce867a5619f6ddbb8d64450ff402e1c4f1a08b518f79dca21e5983c207c5b7324c16895a1e9f1282fc6cf60b0645f6b02b652ed5b129e67c939e854ab492dec30ea878c3edde10a4b7d1d14c57100c6cbcc5fc085a0d7308715ed132fb917251919c727487fedb66500d5610b0014a43419acfbb92f\n\nModExp = 1\nA = 9edfce4691f46eadaa2043c7b1092b831ed50f3429f0bca02f985c0b77c686d951be84d772ae4b55f08935bed6e3206c8441574f215736b5c1c1b7595b3b789b55cf56db83741b10144d6767ba2b97b23a5e83504c60e06ab22834b0145655aa0463108317a379cbfc8a93de8a66925a999b8b02bf88dd85fb9898cefe9c95c8\nE = 0\nM = dcb68f6aa530ae9b31d078e2e82670adcc98228e7cf1aa59f81e66426ef14b1591b833d889463564c75b5fd5551ea295a0da581dd80f62c7008ff0f26a1c9f4f756431d48198af157149be8698336b306b0a8b8635d3fc2c4c2194ecc4d2af31ca1892917cc2e621d702eaaeed0d9a0c3dca575451eb8bc5487e313988cae745\n\nModExp = 0\nA = 0\nE = a3be10ef04535fca6784e5dbf3733d677dedd50fabbc3a860496628950b4747a328c2ce0d903cbe1e700f0af30f59fb917202257815097a2b516df5d0a82642faeffdfc3b7883766c78fc4be5901ebef891a9ca27f3bcf00960729e659bb3fddd54a19ce628e95ab86e4c7a168588bc9f67b05dd21a583acd8dc36e615945648\nM = dcb68f6aa530ae9b31d078e2e82670adcc98228e7cf1aa59f81e66426ef14b1591b833d889463564c75b5fd5551ea295a0da581dd80f62c7008ff0f26a1c9f4f756431d48198af157149be8698336b306b0a8b8635d3fc2c4c2194ecc4d2af31ca1892917cc2e621d702eaaeed0d9a0c3dca575451eb8bc5487e313988cae745\n\nModExp = 442866609915aa6f1bae9dfb59e721e1b63f42c0f75fbf0a88344120fbbd7aacf15208fb7c9d8bb8477d553cbd826d7e685ad764a8423e81c2131c040ee83a03cab8d5ce50866a941b48c78e9f1330794d908562d4141cfbf26e8c80c69551339eec41e37e2b37b54330f7bd75748f8d26d56ab9eb3b0c127540484c6445a7fa\nA = 8ff65e2cbcbcd8697cc3ce9a26855d6422ac7eb4e66500648c08be697e005cc3c854a54cfab91d43489cd60be8b516a9b3c9688e5e009a1689c6b164a133859a5464ef422c86344fef42cc477c9df27768377c126a066d1b62f593b7f6d6e906feaee16addb7cfbfc043d741b7dc81a87c17f167b7b8ef1b1fb3dfd1eb14102d\nE = a3be10ef04535fca6784e5dbf3733d677dedd50fabbc3a860496628950b4747a328c2ce0d903cbe1e700f0af30f59fb917202257815097a2b516df5d0a82642faeffdfc3b7883766c78fc4be5901ebef891a9ca27f3bcf00960729e659bb3fddd54a19ce628e95ab86e4c7a168588bc9f67b05dd21a583acd8dc36e615945648\nM = dcb68f6aa530ae9b31d078e2e82670adcc98228e7cf1aa59f81e66426ef14b1591b833d889463564c75b5fd5551ea295a0da581dd80f62c7008ff0f26a1c9f4f756431d48198af157149be8698336b306b0a8b8635d3fc2c4c2194ecc4d2af31ca1892917cc2e621d702eaaeed0d9a0c3dca575451eb8bc5487e313988cae745\n\nModExp = 1\nA = fe9f77f7d0475e00ec964c0effb9b8e079c32e376ce77a9c40ce4018c3df44a77b4f294d9565502b2b79accb30cb58dda6d15e1543b6d4a53296543ed11c7f51baab60283ef03fae37dfeacb431392487ec2839551a933895c4dbf18844f7b375d3e6f558d3c39993cea1bbf7fb743a6a07bd3753c03eb7298811476d7f3ff1d\nE = 0\nM = e7a96cf6fa930f73c8bdc2726bbba246001a9d27f39cc2b978c99dc6f15af0e8aaf26b565302f1112e607e2df4066948baba931b89cd9bbdea2072e05b9a4968fdf282c43d997987c3a3a0434e925a679ac81f316b7a7b724b79be3d6888b66f4512759bf66cfaaa88b9513dd27a44aaea75437268a014c4eb50ba2e50093511\n\nModExp = 0\nA = 0\nE = a0bc148ed50a9b54036bb8fa1f214979052ebd47db8b347af3bb03b806bb457b468ba34781f8a25f289a7a90af4903dc14809a166df2f4c3527de2ea6911cb1afb9071a4afbb522a7d50634d66fd584c73f32d05217dc9f7f16394c68a692a953492ca85f89cc11da95fd8cac6231647923ced48a1b3b0ee68c010286d452836\nM = e7a96cf6fa930f73c8bdc2726bbba246001a9d27f39cc2b978c99dc6f15af0e8aaf26b565302f1112e607e2df4066948baba931b89cd9bbdea2072e05b9a4968fdf282c43d997987c3a3a0434e925a679ac81f316b7a7b724b79be3d6888b66f4512759bf66cfaaa88b9513dd27a44aaea75437268a014c4eb50ba2e50093511\n\nModExp = 91fd879d02f95a9f40fcd1037726f73892caf84e9b43b4aa4126d9062a0d22c464e7af2fbd91aa849612d99d9519b724a7fb1cb018fffdcff321d883ab2519953c9f174f09dd8f13ac87339887385966eb4a94842276637b2c36c0a5036b1d3bbea438bc6efd4b4851c7ec06879d60694df894717569bcd31c4b13d80df6cbca\nA = cdec5edc1cb3ea974342b85aabc0f9385cf877ca328747d40dd4d297623ad69ab6582653faeed5aef225208305135cfbee32e066cb43e18afacea3a32acc8aabbc49617ac33e741651924ae56dd6aa044a12a1ea50fef573b5befb2f4b21b9cf83ab2aaa6fd153580a0761666ade8fb94f202a3c3dc4f33297eabb4564374168\nE = a0bc148ed50a9b54036bb8fa1f214979052ebd47db8b347af3bb03b806bb457b468ba34781f8a25f289a7a90af4903dc14809a166df2f4c3527de2ea6911cb1afb9071a4afbb522a7d50634d66fd584c73f32d05217dc9f7f16394c68a692a953492ca85f89cc11da95fd8cac6231647923ced48a1b3b0ee68c010286d452836\nM = e7a96cf6fa930f73c8bdc2726bbba246001a9d27f39cc2b978c99dc6f15af0e8aaf26b565302f1112e607e2df4066948baba931b89cd9bbdea2072e05b9a4968fdf282c43d997987c3a3a0434e925a679ac81f316b7a7b724b79be3d6888b66f4512759bf66cfaaa88b9513dd27a44aaea75437268a014c4eb50ba2e50093511\n\n# Craft inputs whose Montgomery representation is 1, i.e., shorter than M, in\n# order to test the const time precomputation scattering/gathering.\n\nModExp = 9442d2eca2905ad796383947b14ddfcc341f5be8fec079135c36f6f0d9b8b2212f43e08bf29c46167ff0fe16b247cd365df4417d96cc31c94db1cf44b73b0ee3ebcc4920d9b0d003b68e49c1df91e61bc7758a8a1d2d6192ff4e1590b1a792f8be3a1b83db3ad9667d14398d873faf5d885ec3a2bef955026fae6dbf64daea2b\nA = 3a4b4c57e62c5e9d1a9065191f8268fed9d5f6f424d071acef66f0662b8210f4c029ed991512e40c9c912043c816d2c4c5b53fa0e5c253e16808aad4225130dafbbb89fd4f30cdfc1c2f2179b636a7ddc4be579795820b4b9377637bd8a21a0ef5a90d0e0f865321eee23d9be2a3b7320b4012d02941b892df2c40bdc85c1898\nE = a2c56ea1362511cac0301918e15a9afe7d37edd438a5c3538d258ea01f0a6df758de07111e868b3ad8fc89b629b4955d78a1b3af902be1806410ddde25ccc6a196ba5949395c1ad5d8725b18815dc1cd5ac1c7dd17773f571e3f2e628255af14476e0494be23a4a4dfd18e23142f33d7a59c236fec61660e360d9676a747c69f\nM = ede35a3a7afac817d413373a2032abbc067b1493f709ae6e1282ee5469743391d891b904938857168802b7872d3cd7ac18ab249a9e540a86f970b1d0f310a4cc29df1cc9d4063d98c554f1a32f4ca5eba3523cdfb142e0fc609907c7a92bb0187009d97ec471db3545f42dd5fd29c07b7816085d09477ba31fcf90084660116d\n\nModExp = a7f5844fa9e7202d4b70ee252c9846e63d3d091b0387768ded872cec53458e19df0d9b4960226e269b8ca5dd4c4eda423a67b6dbb48235c08c12c6c7c78db47287756d3ed9cecb9232f7d18d5d80b9676cb68ba4a290c97e220beb1a069976b5e6022a4c1e5ddbeec86b62dda24ffea1deda37695c9f61a8817218e6370c0679\nA = 7d6d0cc947ceb949cdc4e9e1044f5deca5bb05a491041e0d85bc4b92a0944a57c72845fad91e59010c61ad1712bd2f612d53a846a044632262a9f2e3373b062fde2484e0c165ff947f2469f743ab6e2e5e13c640fc4029b1c9213eb8473c674e7f9e95a4a5c5636d4656c1e696962340d77b322daba47d6fc894f2a2cd9e0afc\nE = b78012afe806e2344d004c739c97324256850980ac97d88c4ed9a838517639ca112e235978d21a176c33f5a68703aba0f2a05501bbe3fc8d49a000fbf530cdb431581dfaf8683cb15a2aee5e239cbc542827100da3b47babf4a16ca7c588aff9912e674abb449e0b767a15e415f4e7f2bbd6380d7131da3df8d49b13bfd35ce3\nM = b72d5c55bd2998472f1965e75a51be6155c1ba04656da8f66bcb34db36a7b1db66a89d1d05b1bde10206acf85be7b474ab689220faf1bb52ab39d8dc00512dd4e26df1179c11b973e1274db85a88c7cc2a17113abdffe58cb930ddc5f3ccc4d68b4e65c913730509f7ce5656e8bbaba9b1be177ab9f766678f018fea05da9cdf\n\nModExp = 465ff295786a88496828fdc763e9292d557",
+    "957544e9322b7996807b87fdbfa7a11614bffeec557ca831c4824c8e4ca3b1a1c7f3f4f95ec3fd6a86b73bb13d78b73af2b3c7e76954d0cc03bcb0cd606867ebb3765a8b3d0108cbe4f343a14016be9c33f6d200f0dc547e7d6b02bfab1e79dcdf9c9835a814cc6c855a12ebeb66d\nA = 89ad02bea3e9ab839a6e23f20122409daba52c68e1e893034b30d321c0305434a6af940015e3fa5ca9c35230da34beeb1ed4fbce6c1da3a8bfe3f3ae172276c1d1723b47ee61e6f8fcfdafad102d6f7ee2a79f510c7edb93096205a40a6c9e665b88b18f39a979e2e61286d939952a6f02fe8148b7515bb25f4252337cb6e60d\nE = cbd6ac628cc7afa3c61bee9c22a06a395087ec1811fe9681b55216700c435996c815e7cec8aaa90016dd2382d0306a5414630124e14f3d396a4ba02ee17851bf720f1607ff813e4bbddf01338983db12f59bd6371a738eee3eeb716f21051d6174d2d6c77602942b9edaac18d4b3a723096c0d00dd23a8a605c585022f311560\nM = fa7a3e40364c8a8d0f14f0213a3f3e035222ca0ea19d46d10ba41580e5dd2805c8a133f3856d7d5d97f922ea540e5eb0d10ad04dfdbb74f518f58da0099a6fc2b3f3def92985176e07fc78aff2faebccca10a429794e5f15ff92f75fe90f527c60ddea8093a9078c703c372ca09f7aeb27ade02f3595308c61dd9c44e62fd101\n\nModExp = cf08bf00261402102e9fe03f3074471dcf0e9b3c96d4d1503f099f24ec85e1901b023e9e048c1ad042244f5f70b38b25a99f4c0a7b57d5844bb0d0137367f45f4ce2cc7746105b77414768cb97648dc5721149aed2d4c682408cc0d50d26dd0bd77e848911f8625c727cac5f32e63bcb548f41a57d718d772f23983a42f603bd\nA = a419646a6631c2c69b18f7aa65011825eb31692eecaee9d74f92d92203811b68e9764bda31a1585bdf69b6273fc6f9f508c395ac081336506525dad88473512f08a205621ac8b16e9864c7a7c5a4f17435de00d0b32badec6ce4897e3e1076c562b6d9523f63d0b2079eaa416cb090471657763f24931d955d1fa2720c80a9c9\nE = d5a6f4a1842aaee39805356dc8d0d678ee03b2c81277345beccb2742f899132feb43271f95968a01ae68aa8277201851992dc0aa7a71c90aae71b124d873ee264ea400fb131be0fc6c4ce8c04c45f6bdaca89ac743635caf6158983d257e21cef6800d7f990e912ba21bbfb8fb779afa4abd19e07e7e07eee9908493d1ca502c\nM = e739689b6cc6def1d45fb1a2ab551643beeb303f4aaa4da47ee5e4948510f8445b4c40e99ae8354dede60b2ba6694e93bc4d573b7e8adf871b7a9a9636eb7d70f2e49328e2d7978143b177cee8374ef01bd1ee2d95862765883f5e7971668b53ef0ff41b6539faf63c397522b0bdce916388e72e26c8d3d2e58dadeb9eb5d479\n\nModExp = 827e6312ec3b14600203bb83f5b277ded197b2967363630ef673240df05edd3ba8ab2b11c86251a612206569c6c33952b31e264f129909bfe723bd0ee1624b36cfcfaa893a6ec8b5a1f7de79f83e79b459a3350f89f412ad1cfd6bc4c2a7a29272c783d6ecceeb1398fa17041835643f4debef9b5e87b098d104bb8912dddf7c\nA = b8e49c637829021d32db3a39a0c1e58cdd4c6e4eda7e8e9293be379e9c2e2d184f929d278598a81ae231cfedcf69cce4a6e31cda3c8ac14d753a7311f2436e29795f0dfb60259a0f61a997918ff984aa2284b43a9d64c974059e9682adfffd018305835f74eda8c75fe4877d811c1620f654ec9f7f32d1af5ce59115e2f41785\nE = 80e0febf369d234bf1aaad4f82df2e2ff02882c3184781f6ccdf4f7cd93b6887af86830077c84dfb02109ada05b40970b1c65228b0c19030bd6361c3537fee22a8155c03b4e7007ca006c6daa3659518d05bb81ea0079456d0ef6116df248dffdb0c935f321f5a1034deefd5a9414a0652aa6548de33325b474b9e5a8507a082\nM = d5eb1d14af842a9973274f7463d90cf0ccff19c47d710edbae184478d4f29b02693ed7958bd487054327b9e6d8879e24c9af7730b92f323eeac05558da6c1b952e5dbf13de236050a77628bb5325fe0d14cc5773bf73338759d5ab43c212b414581280f1cee250007e53791b800b61c90de0328acd7bc43fbdda48158939392d\n\nModExp = 4a1efd29c7e78549f5cd4deed1454b37462c7810ee6a8a2493b764dfa479be13b314cf9ff98259517d61865567ef499a511630c0038c97914625df181c6fe07892f329f98b344a78d751e9471483eebaa7977371bf97bb25187ae7e93a9227d6c124ccb4644423c961a11ae59c4354f89d5a95164c23d9aa256e289e9cc0858e\nA = bd86c9211fa6a47a06e5016c46cb8a99e34a043a29e22f8c3196fa7197c26b38927b8d9bc0ddc11a5fa4bcc44deb69dbf37cbe7ebc9a2fad6c74e09ab5a9dd929fa04ab4319b6caad1035739be78ba631fb0748d9e53944836d37ccda6e6a62823c696d8f31139ccd7f2f86b22fa026ecf433cfb1271a3539ac4f1c83aaac059\nE = c40b9972006d28a84c2769a86e526a2b274f73afc7c5c6a2742166757f61b5f5fdbb228afa157af62af989ffe966f232bba9e6beef5403d1690ade31a6410f7f349a35bc4267a129afd647993df7d45cc0e1a1ba4678d7f1b6e8a344d8ff7037679e1f4db25a454e4246f6b55c416567fcfa188e8a3865115851d9edf0aa8902\nM = cf424d7af75ce7eef90cad75ae55ca8810cc7b4703fdb5bce701e7bac07e0c371cae06df2aa8facb55a0faa6793e4d2bd9d7969703743b9be170be82792aeea55e2bc0f7ab7617b276486bf474dee2f4556aab595ff3ef115139cfe5e21ccd4ee05c0e1cf901bd85df86cc17195a783b0be836d00bee82ce064077f9191188f9\n\nModExp = 3137a3049fd4ad2e26d870f5c998cf11bfe82101884a82e85e43facd0928cd7434a2e346ca124619769fa141bbe92ad6f36b99231032ddaec3b349a410f82b5ca36f45e56e5fb85dc63d32053dc90805d3f1854ab385281a71a57726bf97158494e7476057214ca7379ab8b70f5bdc15f70bdad3adf33c3a1f9cd1b6bbbad556\nA = 39a1dc6a4c3f14d9c350ee968d5ce139ef725952c967a2d1bedf48ace22091283525be03807e2e263d2640be77f0525247bcd07149bba50568cec5a082c87d72962cf9e43bcb5cdb1e7e9a650fb53e0ec2fad37f09a9f036c0d7dfa528fef846769f80a9a60854910ca1b4ee05dba82ed2ee018348d6b3e52a764b8ffae61e0\nE = deaee3a3f80c9f684ed7110c0653847ccc7be5ff6d982fd4b49f59b5dd35f7210b1077babbcedbc127df35cd469dc6e569a0f84e58149b5605c94b09fd7f0b098d02b4a04631328b3fae39e6c2fce25334225cab71829abdb9507cb903701559660f2c08c3b743336119d1260a0db27054cad3f28bc1b04b2289baa58fb33965\nM = 938388927d06ed3bb1286c0f06d3054cb0ee16dc7a0bbbf13a45293c09a5f40f1d611b2e1a1b0ec2ef109b508e27af4274954905cae52034f8740a744153b4d22059f0dd262ea51785522098ecacced6da07709ee6b5acc8c4e99331379a7c3de7f4e2d1431e43b19570140955b7bcba118dfbaa552cbfa2be531e8f781166ed\n\nModExp = c15ae334455d9f4d1030cd33e734726a27c63624c2afc576238cce5e0498298a4a0c93090a0d19568b41290303c4b558f3d9dd74f9cde8798710f68569ea0d6fd971ce67ec5b54495031de3d8842b8b49288725bee5c9f72b99054d64986ccd4e18d70d5f33943f08cd694eff538f84438ea993ebaba0910c95b3a694f213510\nA = def633b955a917569df3ba8517455eef0655e7a35985edda27097a063e0d82c7c3a76dc36c5d8a71ba9d540790ddd0ea514aaed98925f9a1808eb288d387aaf9605a9ef8a333ebee7ad7057bca012efd619d5867f02266f65976ef4b16da17468426ac4f99b3e8921707e01b4de20f6f9a068e6a19d872079a27f3a44449db83\nE = a465c47b0d15d48e01bb8b1d8e3b3253e11515f6874dbed6c25818adf1a8fd927124d5593beb367f685c11e46f18415be73ccdf16fa2e93a600b728163d21d232849e5278c3749d903edad3f1c4535a2f55a2ab65e7ebc64888bd2a0527e876ecf38cec3ab1980d08138709fad8eb88ae65d960adc3f0f8e92f784fe96fcb693\nM = e43cb9ac1446154356cdc31ec771c79b0e461e22d95185bbe1a279c0945e3af07903a0cb54d553380716fcdcafb4b7cf5dc6da481dc74a8c583d75ff6c1f8e429182d200246ebc473bb56e173787987c1b7fb2dd23f5b2e438a97bc4a1df628bc044fdd1e80c0cf37030adb7b04784dab827d0dcd64f0dbf37c980612570ce11\n\nModExp = 75c3f79ab7c991b98e65505342a8a563cfb08b5d3ccf8664c7db1de50256b1d17ebf7096dc98c7bb5d7f027a894ae5cbb14dee04d5d445e775ad7e239acc82673b0ac2d819a69c83864f34e73d9a636f05de8279619a067b4c90ad038db5910447e03841d2034635018f08cbcd21efa00994247763a249082594128112f95232\nA = 34def7d76f6f158a359fd12759fb889cdf6af0a24830dc3e84283a1ab4e9b2647a6a36b86482f829b2cdf3e3d6028f9a884b1f64f7262315446bea8b0231828e2f3d990fb103c17f820b39e4b8427c85643ceeca8f5dc8f191d1255768300e859bd7d88c770319ef38269660d221cb3bc061389b6fc0783485ef042b1c7d6fef\nE = c6c46453dd5aac6b37277a446b1d0c69cbe476eeff55b3ac35edb89ba97116b0e7783660f2c7b31b2a2d6c4709d0ab45d01a838100694b0777c9c9c14c959b07c437c73a5eabb7402f1001e802d797a2e7707285834fb6440a1c2f727f7bb84ddb2a49312d32fa0ce620c43872655cb5c394749c9e75d7fa25be00efe50d47d6\nM = fbbab6698a9142095c46b38a732592e4366c1838b84bf40f8c8fc7b630f73380a0d09765562365798f8c8030ed1b6728329d8bb06e882c35a1d59bfe84146a9db2afe42a414014e247390281c782fce806d62adb54778d2bcb49555459429d6ed446af5359657667f6aa19e8e3e0e24ab2bc312b2d90b5cb1ce6f2f15af15d9d\n\nModExp = ba16d7f3f6e162ce248490d164a13c00e7720d8a667e2d3ebeb13f1663e15ef5408d5b56cbc7bc793a8ca787cc50f8e15e0e9d4ee764531d04a9114eea556bb3e206ed7d85267151a056b6e68fbf35e03f2cf829708ffe1de13e95ecfe365aff1eea36340ffcd3892dee659fb1ecbe50f5080e54737c10f9c1ba638b14ef537e\nA = 9025e6183706105e948b1b0edf922f9011b9e11887d70adb00b26f272b9e76a38f3099084d9cccf12d04b1a99c0f654f8b9ed90c6dff9478c60bf05d58d734ab60eaefa14a22230ec60c90dc1f0704b61eef0bef345785ae0e6a9af7db069cf6bd2b4e0fe58a0ade83c7e46a04b9fe1d24cb9b65c6f80de713e61d70eae5b286\nE = d7e6df5d755284929b986cd9b61c9c2c8843f24c711fbdbae1a468edcae159400943725570726cdc92b3ea94f9f206729516fdda83e31d815b0c7720e7598a91d992273e3bd8ac413b441d8f1dfe5aa7c3bf3ef573adc38292676217467731e6cf440a59611b8110af88d3e62f60209b513b01fbb69a097458ad02096b5e38f0\nM = e4e784aa1fa88625a43ba0185a153a929663920be7fe674a4d33c943d3b898cff051482e7050a070cede53be5e89f31",
+    "515772c7aea637576f99f82708f89d9e244f6ad3a24a02cbe5c0ff7bcf2dad5491f53db7c3f2698a7c41b44f086652f17bb05fe4c5c0a92433c34086b49d7e1825b28bab6c5a9bd0bc95b53d659afa0d7\n\n\n# RSAZ 512-bit.\n#\n# These are regression tests for code which historically reached the RSAZ-512\n# code. That has since been removed, but the test vectors remain. Note that the\n# lengths of the inputs, especially the *bit* length of |M|, matter a lot.\n\n# Control: No relationship between A and M except that A < M and they're the same number of limbs.\nModExp = 7f34c1cd63377bc3abf2bb5b2d1bf5f06454e1e8040fe19a72245ce9731cbee1bf9e84532300776c8021ed4f3a8de508d85b4cf320bd82065a013754857b50c4\nA = 8e4e67da6ff890643d0599387955996ef6f0c2045eb9944576ddb965ca64cdb6247727ce128ef178d4a84e5a56d2e67eb0fe389ecbf691f9244ae80f4c11b364\nE =  be99d8f0650e540b9b191e9cf96f74881b902e32ed169ffd8a1776c3f3e80f0ac765aa14615713e1549f250a20fe4ee48c4e0c6176162fc7842a0dd64d640d1\nM = f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725491\n\n# Same as above except A is negative.\nModExp = 71fa6a4c8ae75368eda8cc6282c26afa69e2af12a97fb9444f16b7dd6c99e0a5d6034cab4248cae4357346b211039f4a2bc4c5a20a297372094162417af703cd\nA = -8e4e67da6ff890643d0599387955996ef6f0c2045eb9944576ddb965ca64cdb6247727ce128ef178d4a84e5a56d2e67eb0fe389ecbf691f9244ae80f4c11b364\nE =   be99d8f0650e540b9b191e9cf96f74881b902e32ed169ffd8a1776c3f3e80f0ac765aa14615713e1549f250a20fe4ee48c4e0c6176162fc7842a0dd64d640d1\nM =  f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725491\n\n# A == M - 1 == -1 (mod M) and the exponent is odd so A ^ E (mod M) == A.\nModExp = f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725490\nA = f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725490\nE =  be99d8f0650e540b9b191e9cf96f74881b902e32ed169ffd8a1776c3f3e80f0ac765aa14615713e1549f250a20fe4ee48c4e0c6176162fc7842a0dd64d640d1\nM = f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725491\n\n# Same inputs as above except A is negative. Note that A mod M with a \"correct top\" isn't the right length for RSAZ.\nModExp = 1\nA = -f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725490\nE =   be99d8f0650e540b9b191e9cf96f74881b902e32ed169ffd8a1776c3f3e80f0ac765aa14615713e1549f250a20fe4ee48c4e0c6176162fc7842a0dd64d640d1\nM =  f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725491\n\n# A == M, so A == 0 (mod M) so A ^ E (mod M) == 0. Note that A mod M with a \"correct top\" isn't the right length for RSAZ.\nModExp = 0\nA = f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725491\nE =  be99d8f0650e540b9b191e9cf96f74881b902e32ed169ffd8a1776c3f3e80f0ac765aa14615713e1549f250a20fe4ee48c4e0c6176162fc7842a0dd64d640d1\nM = f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725491\n\n# A is negative, and A (mod M) is the right length for RSAZ.\nModExp = 8d76eb0f8c7bc3160cc8bb0e0c3590fbed26c5932f5f525b48045c0bd46dda287ba5483f97c851fb7c12c2e858ee7a4a4d1af745cbfb3eb311fa54bea12cde25\nA = -80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\nE =   be99d8f0650e540b9b191e9cf96f74881b902e32ed169ffd8a1776c3f3e80f0ac765aa14615713e1549f250a20fe4ee48c4e0c6176162fc7842a0dd64d640d1\nM =  f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725491\n\n\n# RSAZ 1024-bit.\n# Note that the lengths of the inputs, especially the *bit* length of |M|, matter a lot.\n\n# Control: No relationship between A and M except that A < M and they're the same number of limbs.\nModExp = 8984f8c16044f9c0ad7bd72347af90f58e6e003acda92b76e3c7c4a56ea8e918409d8e9b34884d4c89d0b17cb40fe898f2627c084a0f1698e46beccbf6f48eecc281e11ea9e5135adba460ddae157f2c655b5f589ce29b254d43a960a71cede8a08dbb86be4dac22458da232fb1ec2470856827302ed772c9ddafa408c931aa7\nA = 21158da5fe20356825e72b3f5384ec57720d22f727b27ce2f945c8ee311db781add73bf8fae96b775c909bd22fca75c44c2b0584284a5bb1c07f8eefcd6b0a44047a02b185df34f897f11d4fb9a86c9eb841b4cb8d0383441fdc5af3ef385b5e8380f605d73ed41bb42eb2c2a5704d6034b3ad058dafffce83dbbfb6295daaf8\nE = ecdebd112b3b5788669449dcddbd479a203ee9ab72a9bb9c406b97623513bf0ab9a22f1f23634d269e16bfd6d3b64202b71fc355057411967b6ac70f8d9cef0a4e06819a9a18cc06bbe438243fa9759303d98be8a65dc1cb13595ee9b99f138554425d50f6fbc025d8ffa3eaea828d6f3b82a3584146bafde34da257995f0575\nM = ff3a3e023db3bba929ca4ededbace13d0d1264387b5ef62734e177eaf47a78af56b58aacc8ac5d46f5b066bafb95d93d4442bb948653613eec76837b4ffb7991cb080b6c8b403fb09bc817d026e283ee47ab2fc9af274b12f626eda2fe02004a8e27b9ed7d3b614e8955c7e7c2c0700edd079455237c4475fbd41857e206e4b7\n\n# Same as above except A is negative.\nModExp = 75b54540dd6ec1e87c4e77bb93fd50477ea463fdadb5cab05119b34585d18f971617fc1194240ffa6bdfb53e4785f0a451e03f8c3c444aa6080a96af5906eaa508862a4de15b2c55c023b6f278cd04c1e24fd0711244afeda8e3444256e51261ed99fe66beedb52c43c825b4c7a1adc7d4b111e2208ecd495df91e175573ca10\nA = -21158da5fe20356825e72b3f5384ec57720d22f727b27ce2f945c8ee311db781add73bf8fae96b775c909bd22fca75c44c2b0584284a5bb1c07f8eefcd6b0a44047a02b185df34f897f11d4fb9a86c9eb841b4cb8d0383441fdc5af3ef385b5e8380f605d73ed41bb42eb2c2a5704d6034b3ad058dafffce83dbbfb6295daaf8\nE = ecdebd112b3b5788669449dcddbd479a203ee9ab72a9bb9c406b97623513bf0ab9a22f1f23634d269e16bfd6d3b64202b71fc355057411967b6ac70f8d9cef0a4e06819a9a18cc06bbe438243fa9759303d98be8a65dc1cb13595ee9b99f138554425d50f6fbc025d8ffa3eaea828d6f3b82a3584146bafde34da257995f0575\nM = ff3a3e023db3bba929ca4ededbace13d0d1264387b5ef62734e177eaf47a78af56b58aacc8ac5d46f5b066bafb95d93d4442bb948653613eec76837b4ffb7991cb080b6c8b403fb09bc817d026e283ee47ab2fc9af274b12f626eda2fe02004a8e27b9ed7d3b614e8955c7e7c2c0700edd079455237c4475fbd41857e206e4b7\n\n# A == M - 1 == -1 (mod M) and the exponent is odd so A ^ E (mod M) == A.\nModExp = b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d964\nA =  b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d964\nE = 61803d4973ae68cfb2ba6770dbed70d36760fa42c01a16d1482eacf0d01adf7a917bc86ece58a73b920295c1291b90f49167ef856ecad149330e1fd49ec71392fb62d47270b53e6d4f3c8f044b80a5736753364896932abc6d872c4c5e135d1edb200597a93ceb262ff6c99079177cd10808b9ed20c8cd7352d80ac7f6963103\nM =  b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d965\n\n# Same inputs as above except A is negative. Note that A mod M with a \"correct top\" isn't the right length for RSAZ.\nModExp = 1\nA =  -b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d964\nE = 61803d4973ae68cfb2ba6770dbed70d36760fa42c01a16d1482eacf0d01adf7a917bc86ece58a73b920295c1291b90f49167ef856ecad149330e1fd49ec71392fb62d47270b53e6d4f3c8f044b80a5736753364896932abc6d872c4c5e135d1edb200597a93ceb262ff6c99079177cd10808b9ed20c8cd7352d80ac7f6963103\nM =  b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c1",
+    "6f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d965\n\n# A == M, so A == 0 (mod M) so A ^ E (mod M) == 0. Note that A mod M with a \"correct top\" isn't the right length for RSAZ.\nModExp = 0\nA =  b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d965\nE = 61803d4973ae68cfb2ba6770dbed70d36760fa42c01a16d1482eacf0d01adf7a917bc86ece58a73b920295c1291b90f49167ef856ecad149330e1fd49ec71392fb62d47270b53e6d4f3c8f044b80a5736753364896932abc6d872c4c5e135d1edb200597a93ceb262ff6c99079177cd10808b9ed20c8cd7352d80ac7f6963103\nM =  b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d965\n\n# A is negative, and A (mod M) is the right length for RSAZ.\nModExp = 9cf810b9e89d5cbc4b79ae64e123ea06d92965e2bab077df97a1b906dc2e1ddcf96a9c4ed14e2cd96309b829ea9cc2a74a7d4b43c5f34d792a7c583201427754b8f78b783608070a84b61f18913e3ced7f7f530972de7764667c54e29d756eea38a93cd1703c676a4587231b0ebfeadddf908e2877a7a84b5bfc370ecf0d158d\nA =  -8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\nE = 61803d4973ae68cfb2ba6770dbed70d36760fa42c01a16d1482eacf0d01adf7a917bc86ece58a73b920295c1291b90f49167ef856ecad149330e1fd49ec71392fb62d47270b53e6d4f3c8f044b80a5736753364896932abc6d872c4c5e135d1edb200597a93ceb262ff6c99079177cd10808b9ed20c8cd7352d80ac7f6963103\nM =  b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d965\n\n# Regression test for CVE-2017-3738.\nModExp = d360792bd8210786607817c3dda64cc38c8d0f25569597cb1f363c7919a0c3587baff01a2283edaeb04fc288ac0ab3f279b2a89ffcb452d8bdf72422a9f9780f4aa702dc964cf033149d3a339883062cab8564aebdbfac0bf68985e522c6fe545b346044690c525ca85d3f4eb3e3c25cdf541545afc84a309e9b1d7807003461\nA = ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2020202020df\nE = 2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020FF2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020\nM = ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2020202020ff\n\n\n# Exp tests.\n#\n# These test vectors satisfy A ^ E = Exp.\n\nExp = aa6d7ac431\nA = d0e07\nE = 2\n\nExp = 12d416b110dbb4e467ff0c89a22122f4da8240\nA = 1a18cf6\nE = 6\n\nExp = 49a3b33e23d84f1ce0d5d83f5dcb651d50cf3920f0143da2310d0512a90a06cd8f38977df8a756c30883de38df092000\nA = 2a3acbd2\nE = d\n\nExp = 5b4a0d5a956f885f275712b194459980f24708bfb6393d71bd37dce852ce455724f5ee5030775fb86b4295edc98afaafc097e4d82a97c0078ec0eac763db16549c5145c4cf2d3124f88cf9a5c71da0625afb99b26801786fe49a778415dc025954021753d08691947a208b613f0be5c1\nA = 54b3ae461\nE = 1a\n\nExp = a0ea5f6a4de49beb8fb7f0dab280d6a32c5a3814c9a5153a7944cec0a9028497846a8a89044348721a0bb5f0c3ded3e980574ea321b0cdb0ead4f4e93841ea7478a7f15d9729b646a8165813a0750e8124f5465dda9b105e1bbeff18fd09c09a2e26610d9176d253b877c3a8908a6be521cbe1e472a7a1b7820e4e890f8f28aacd34609c686e76e15b01bd9324a71290812724ea564d11c874a6765b262c3e57d479da0287a76026a1e8fe53da0b02405da1d379eaa30fc65f\nA = fccec0f6df\nE = 25\n\n\n# ModSqrt tests.\n#\n# These test vectors satisfy ModSqrt * ModSqrt = A (mod P) with P a prime.\n# ModSqrt is in [0, (P-1)/2].\n\nModSqrt = 1\nA = 1\nP = 2\n\nModSqrt = 1\nA = 1\nP = 2\n\nModSqrt = 1\nA = 1\nP = 2\n\nModSqrt = 1\nA = -1\nP = 2\n\nModSqrt = 1\nA = -1\nP = 2\n\nModSqrt = 0\nA = 0\nP = 3\n\nModSqrt = 0\nA = -3\nP = 3\n\nModSqrt = 0\nA = -3\nP = 3\n\nModSqrt = 0\nA = 0\nP = 3\n\nModSqrt = 0\nA = 0\nP = 3\n\nModSqrt = 0\nA = 0\nP = 5\n\nModSqrt = 1\nA = -4\nP = 5\n\nModSqrt = 0\nA = -5\nP = 5\n\nModSqrt = 2\nA = 4\nP = 5\n\nModSqrt = 0\nA = -5\nP = 5\n\nModSqrt = 3\nA = -5\nP = 7\n\nModSqrt = 0\nA = 0\nP = 7\n\nModSqrt = 0\nA = 0\nP = 7\n\nModSqrt = 2\nA = 4\nP = 7\n\nModSqrt = 3\nA = -5\nP = 7\n\nModSqrt = 4\nA = 10\nP = b\n\nModSqrt = 0\nA = 0\nP = b\n\nModSqrt = 3\nA = -2\nP = b\n\nModSqrt = 3\nA = -2\nP = b\n\nModSqrt = 2\nA = 4\nP = b\n\nModSqrt = 2\nA = 1e\nP = d\n\nModSqrt = 2\nA = 1e\nP = d\n\nModSqrt = 0\nA = -d\nP = d\n\nModSqrt = 0\nA = -d\nP = d\n\nModSqrt = 3\nA = 9\nP = d\n\nModSqrt = 8\nA = d\nP = 11\n\nModSqrt = 6\nA = df\nP = 11\n\nModSqrt = 4\nA = 10\nP = 11\n\nModSqrt = 5\nA = 90\nP = 11\n\nModSqrt = 3\nA = 80\nP = 11\n\nModSqrt = 9\nA = -e\nP = 13\n\nModSqrt = 7\nA = 7d\nP = 13\n\nModSqrt = 6\nA = 37\nP = 13\n\nModSqrt = 1\nA = 1\nP = 13\n\nModSqrt = 8\nA = 1a\nP = 13\n\nModSqrt = 54d4cf0fafe265056a29016778cea6b712bc66a132fb5e6b6865e9b49e4c97ec\nA = 599c10484b22d0b5a115268c7538ca99b3253a311a4ab1ca11c3665b0bec393a1167d1ad94fb84cb2c7ad7e2c933e8f613bdd08fe1f1aa4a9b0b9de0c8a7c9d4\nP = cfc4ccae35458ab5be1a1bc0664188253301f8702af4f8fb19fed12de0c653b1\n\nModSqrt = 38a7365a15365e911286c1be2a7afe76ef390234d76269e04dee17313f6ea54d\nA = 1c4aabb4d8369710131c664ecf2849e963c1bc31d66e0b939bacf99a870c71f24ed71bdddcf566f3908271fee43fc1ebb51eac7e3153efae641b49d2e796a12a\nP = cfc4ccae35458ab5be1a1bc0664188253301f8702af4f8fb19fed12de0c653b1\n\nModSqrt = 35ab18a560dece04725667f640ca61d1d59f14d191f94c79f58531acd097d444\nA = 685168ae855d60eba220d803f5296459b30a289580668db9ed51bca51cc2d453a937e13819ae34f7a9a143ac96d17420c53919167e46279b562b550be1cd9abc\nP = cfc4ccae35458ab5be1a1bc0664188253301f8702af4f8fb19fed12de0c653b1\n\nModSqrt = 288370029e87024175e5bec0eab0929179f42e16995e7f6194eefc61061e54f4\nA = 2a14ab77c045bdc48220ba9c463e1a4b4049cb01edb53be0937767eb2ec19b7d719855052281250a36a0b76d9a5d967d0756e1ded7a052f7056191ad66bcfc9\nP = cfc4ccae35458ab5be1a1bc0664188253301f8702af4f8fb19fed12de0c653b1\n\nModSqrt = 32255cf01dc943577ec2bcb221b98491d7a1130d046d6c68e95fedff643ce3a4\nA = e26f6dd46a513a1dd3fb14b71be1d4c9e9d79eda1cde10ea4d1eb8abfd4d5857572205e247184dd0cbefa37b5c0bf680ba2bd28c5741f725cfe2aae37419baf\nP = cfc4ccae35458ab5be1a1bc0664188253301f8702af4f8fb19fed12de0c653b1\n\nModSqrt = 5172345e801ada63fbc4782e32583cc3b4fea88b9e6dfd542f3542f8538ade66\nA = 40dafa8342b302bb04b1f3ddb3b9015a8fc1b597857c115b40631c7be9e22de89358fca23b331596ee5ff304dad7811e6d8e8822f7aa533c9e7c882634ea550\nP = a6813d316f9aca30f98b4f864b8b4b8f51493af930bd4d3a1b205a710e99add3\n\nModSqrt = 4dcf63c423bf0e39aca2293d57f6792d023db649d6719fe936446904b9f7e60d\nA = 5bcdb514bbe84261e169203e8017909b60c9bb330400c766ee01b0189378e70e61867a164a12643ddc9e94b61e09e5b158cbe85be228a3cc48f95a552958b8f2\nP = a6813d316f9aca30f98b4f864b8b4b8f51493af930bd4d3a1b205a710e99add3\n\nModSqrt = cf77c5c2d12a500b75cbfb1f3e66ee75d886b9365cf4f8b4d1bd18a6be0f387\nA = 4652ddc2ea7b460d8ec3c9059b8f9b5dae6cac55b51f2ad86fcb336b25235737965cc515e2ff0b54835015b7ebeeda6fadd986471d8cb424d309fc353d1e269\nP = a6813d316f9aca30f98b4f864b8b4b8f51493af930bd4d3a1b205a710e99add3\n\nModSqrt = 1e0549e4c5a26023e9d24fd8c67419960746f82b1ecd113bdac66f570a475d87\nA = 5f4a6d450ab1390d96ab1deaa0ba18f897cb63daf0c9e1ef6c08e804c26b5e842f6c08f13db5d4a6e88f07af2a3cb04fa06fc3e59c410b9356f025ed81acc74\nP = a6813d316f9aca30f98b4f864b8b4b8f51493af930bd4d3a1b205a710e99add3\n\nModSqrt = 144481a781d831c1ca046ca9e322d79ad4d2c6dd9f780bea9d1ced9cd20b7b23\nA = 4c254fabca441017132b9eacd4ca40a336db3e5c09715773fa07af095989a91cc968ff07a9ff56ed06b0ce0c5269f7b2ab68564ecab9f4467a7e96b6cc6b21b7\nP = a6813d316f9aca30f98b4f864b8b4b8f51493af930bd4d3a1b205a710e99add3\n\nModSqrt = 216fecc7667f488a3d2d102a38b46b4860ab858300b8638af4f34e1103fd73ba\nA = 17878f8048227573a9d",
+    "70f53c0e76ff13fe9f56e9c984c92514d3d13dec23c816661f0618d21371b80dfd885cb59551bdf80046f65f22ea9b89c78645a6e455a\nP = bd37c850cf7d702bac879f3c21a51a5a4df2b8eb0935861e0753a6eb62261a95\n\nModSqrt = 458e5e789ccd2417174f7e30bb31914b9656bd8cf2b9f5a9752a8737a67707bc\nA = 5c7d39a4bb04e69201aa519f80ee7e62ea14ca55e13656d1da3f45367e2fb2d061aa2940708d02ac67d35cd2ccf54a1bf95bcbc759779e692cfdcbb3aa1a05b\nP = bd37c850cf7d702bac879f3c21a51a5a4df2b8eb0935861e0753a6eb62261a95\n\nModSqrt = 543125a16c2bb8b8f8a2c39c497e5224ec77533602d7dbe24002e32dcbd2ef1a\nA = 3413afae333b2ad9ff45c7f3c7e5934b3127e8b1a55225958ee6ccf42423e81559bf070ad3f3353b78c0ffd41475af49f59d268ef78bdae879f5155e8d1cc07\nP = bd37c850cf7d702bac879f3c21a51a5a4df2b8eb0935861e0753a6eb62261a95\n\nModSqrt = 10e16859c67bdb2eaab52a7c847dbf37162eda258a9f6262ebacfe4cbbbc1080\nA = 21ce7905894faf220bdf4a82a2d855994ca2dc9feaecaa53c7f146e1f49934215695e9bb46ba370b7005a90c399674caa8969eb442e7914d90f749774d7fd194\nP = bd37c850cf7d702bac879f3c21a51a5a4df2b8eb0935861e0753a6eb62261a95\n\nModSqrt = 32a00586adc6f6cc2b1a04e1be0ab569fde235e1436c38b6af92bc5ebd60bc1c\nA = 350da4fd8cf03c12f7dd6ac6d3ab801a3413964083e374662aaf878d6838b97d4feb9e52cd307a25b113e101661a865463ee2480c626aa4e2ec437d72e7bae4c\nP = bd37c850cf7d702bac879f3c21a51a5a4df2b8eb0935861e0753a6eb62261a95\n\nModSqrt = 971f75bc7afa8b4b50f1d4b05e52deac7d4836a08d30546f29649bf1ca6a247\nA = 655ed4c5d8d0afb4f9360372ee1ef1303898d2423e585108a3303faedb55064d2ef25666ed4c4d71fe6063fea1f3142b435714b0e30b339dd791d347c884654\nP = 9810151ad4bc9c5d68fc326395b509f2625bfebca1c3801ad4da7539fdbaa6f7\n\nModSqrt = 48fa882b7cb6a29de9e3769f72eb67f1efd4d2af56f0c7e410c610efcbce2065\nA = 14f3503f33b243800eac1defaab33e04c01e80163fb3efd03860970cc016832431ca4fc6d1b760f4f40166b0b8b3c40dbebc81460cc10890172243770338f090\nP = 9810151ad4bc9c5d68fc326395b509f2625bfebca1c3801ad4da7539fdbaa6f7\n\nModSqrt = 236fd7e397ea7f8bc2a288eb7236ca41936fa702b7dccca56c8852e147511f7d\nA = 1bbd0980feac854782813bcde4da85e8a054549a1b515e065da4236528035e756882e29e762cf60453e375cca9dc6ff637f9558bf86646e3b928f68f82af7efe\nP = 9810151ad4bc9c5d68fc326395b509f2625bfebca1c3801ad4da7539fdbaa6f7\n\nModSqrt = 693f0cbe8c81b0afde0cd2f83e53795dcae6b0cc4ba930ab5c752400d787f14\nA = 7b20f9664b23907e152ab8c9a907f72e8670c1c38ab4cd1411ea7c2159c09aa131afe068929b8e6ad1409b74c04975180d1cd0a9fa74e923c3fd451e8da2c34\nP = 9810151ad4bc9c5d68fc326395b509f2625bfebca1c3801ad4da7539fdbaa6f7\n\nModSqrt = 4a086c50b0bad576501ddb6280743b2c9d247841eb7f14d90561432ff7dca6f0\nA = 4367431ec0cd0d7626538b93a090c30fe0c97c18ca03b97ddae304b619112b5b4d02bf0f041fa3fd673f9ef2ceb07eb2079d11c56dd903b1a87e8252a97b8079\nP = 9810151ad4bc9c5d68fc326395b509f2625bfebca1c3801ad4da7539fdbaa6f7\n\nModSqrt = 18f8433fa468d8065157708f1f1e53b8e31d39c6011fbc2bad93de1b5548e19c\nA = 739c032bb4139c199c40f548d37234298772e4ccb9d3ba28412b60ad23b4c465b0787e2382f1c5a4a87af2d20eb978b7dcbe73f2112249477d15c8a85e54a79\nP = adcd56924f73836ebe4dccfe006ad3b1e5076562cd11b161642cab7af2284659\n\nModSqrt = 49e3c8eef5e067cabd51a7c01384ce05ab8f4342f655559d8a689eb7b20e0106\nA = 18400c2cc3e06b99b4e39c77b9af5ff0e9c683f1708321afa4cd5b6988d13b36b1d9eb4379b7902d9ceb40c03f814b2b6a01b90509bbb4532f13ab1571c4d04a\nP = adcd56924f73836ebe4dccfe006ad3b1e5076562cd11b161642cab7af2284659\n\nModSqrt = 35548c530745f440329325cc8a5fbd90c16a7f0788879a4869bc4d4f73acda0e\nA = 181a3c5ab02566e7166c4d6d2f2bd4a8ecc25991a98d270bde80cf4332766a7068b14240bf5f5dcd45e90ef252596da3eb05b11d68b2063f7b3a825742593ca9\nP = adcd56924f73836ebe4dccfe006ad3b1e5076562cd11b161642cab7af2284659\n\nModSqrt = 1ab7046e6af061ade5f9719008fa4d989007e2a579a134a5b9f19ec410984096\nA = 1008a03e211fab0d45856377079bc96b0776c2d4c0175661f3493246cea2ab0a02a706c85314fb707ad9906bedb2cfd577d62092ae08ff21d7b949373ea954c7\nP = adcd56924f73836ebe4dccfe006ad3b1e5076562cd11b161642cab7af2284659\n\nModSqrt = 2be9e3e7515960d90f115b89f60dedc173a73ce163b4036e85b7b6a76fd90852\nA = 392053a9f0100540a8e1a0c353e922068a84dad3a4a8e8962fbc0bee2b6a06e20d08ade16eb1409a16acfcac3db5c43c421505e07035ca308b15c4a6db0864c0\nP = adcd56924f73836ebe4dccfe006ad3b1e5076562cd11b161642cab7af2284659\n\nModSqrt = 5b301bb93bdcf050183107e36258b53b4805918114ea1c2227b0911d5b4dc077\nA = 55e55e5f94dc3d7aabc921f6469d85fa2e1e92a87347c57afad5872306ae69f9fb99297d1e3e793dd9e8632244208154de5da7114fd876383bf1422f7ece024\nP = d43280ac150f725f4a2a1dceb1c79bcac57855a4eba72ae93762d09bcb2444fb\n\nModSqrt = 2df9609e2f5a5156c3260461b2ee52eacdef00bd8b091479813143a6c5283f71\nA = 2099325b7f12fe77353ddf3f2b2c5ef77b49671b150af954cf84e9675e3ecde3e057084641a633d19533b4712ab49924c8b5c31d591abcc88291f51253fa2a7\nP = d43280ac150f725f4a2a1dceb1c79bcac57855a4eba72ae93762d09bcb2444fb\n\nModSqrt = dfab751710e9008e25e422d1199d6fbec4dc7fba35b4da9d225a746eb4126a0\nA = c006af53d4737fb293584df6ffe2e4cb3fd8dc77fb7c1f13b97bb9c249e3ee5fb9feff7488265b3093906c08a4946f142ac7b491937d24bfba6413366ce371d\nP = d43280ac150f725f4a2a1dceb1c79bcac57855a4eba72ae93762d09bcb2444fb\n\nModSqrt = 26bc030008d6c60a09fb0e16093a649fcb40c6c21a8e2da2353ba4b07c4f85d5\nA = 1eaabcfad2ed349ac9356e6f4da0b301266ddde811cb0f817aba8f5c10fb8b8ba9d0ef2dd386b668f16eac296118fdb8cb7afe1b865648c81c2fa3cf21f2711b\nP = d43280ac150f725f4a2a1dceb1c79bcac57855a4eba72ae93762d09bcb2444fb\n\nModSqrt = 35051b1482ec2578f3dc0000a422cb5111e43c37f1ac20b1844d3de2128c4556\nA = 315ff9de178681116f2a5fa78eebf4818e1d680435eacdfaf9d0e5c4fc01fc034b352c82fd52c81ca30d68864952dacc99d08269c9dd7ca99ccf22da98c3840\nP = d43280ac150f725f4a2a1dceb1c79bcac57855a4eba72ae93762d09bcb2444fb\n\nModSqrt = a5474252885cacf004c460a7793ff0b0a2187bb1a9ed700ae3470199faef71f\nA = 19856fc1351c4b02abf573bb2fc6ff92355fa369d62bb8f2260fa772fb1693f509a56cad661930abcac049dd70f4b16bed4a4c172e73e772504c9990ce7f92f\nP = dc315fd52684fba79e577a204de9053b11a5d7a414263fec9eff6ff62188829d\n\nModSqrt = 12daf4722387ecf47de1b0b6b110a062dc5ea2685bc9dbde66b8d15622985029\nA = fb8479787069116abc42abfd7dc0c24d2ad04fe0c04b42a6dff714af715d17e0fd77855f950f264542b06d48e8818de813ddb7975798b7debefcdaa5ff86beb\nP = dc315fd52684fba79e577a204de9053b11a5d7a414263fec9eff6ff62188829d\n\nModSqrt = 397996ed5c0ac6ad32e43c337e9de421b87774cc162bf7ac7bbedf4a9029255e\nA = 5aa04353321bd2de92481be740357f979da464b53aa39111fdbb734cf7af6b3857d1baa08d3a126a3dd34a2fbae2bf2b84e900686c1d31505b390185acef5fe5\nP = dc315fd52684fba79e577a204de9053b11a5d7a414263fec9eff6ff62188829d\n\nModSqrt = 2cf4b844a54ba359dc592ef1b49f43fcfeae84d1087edfefdd0b9174b43c0a3c\nA = 365a8650510bcfd8fa87432f167cf487234c215857403b9270b5eebeafa48cd6da47fd60dc311b94d1d72baad0447c31f0b212d755f46c256e16e5e015e6546e\nP = dc315fd52684fba79e577a204de9053b11a5d7a414263fec9eff6ff62188829d\n\nModSqrt = 9277c73043ff767c3fa606f0cd66b9d854a600c8c18287f191ce277758c3f31\nA = 62cec3901626d03e8df66299a87c54b1f7a55cafc99f0b6bba1b5d51a3d2b7d2171c9135a9d8a5346d436e0136b12e515e703e3cd84ecfe154eb94c6772a6d72\nP = dc315fd52684fba79e577a204de9053b11a5d7a414263fec9eff6ff62188829d\n\nModSqrt = 4189e5a90c1b1abdc1c7c05b3587e6f362e06f927b6cf5f0d271aab3d6f90765\nA = 336b8d0f9dac842c696bc020f49c6aa023842c16f2052eb02f17959006554ca0012042c80c72590f21c6bf5a3714c9cb552aa69730e33db93a56a909b273f39\nP = 9df9d6cc20b8540411af4e5357ef2b0353cb1f2ab5ffc3e246b41c32f71e951f\n\nModSqrt = 36ccd38cb5a6bd8a73bca55936a2227c503664422c2296faf7e2b1c6a375a43a\nA = fecfd60a376befbe48d2c4f6d070d716d2f403cd5daefbce62b720df44deb605162c8f20f49fd7ec30d4f8e70d803d45b3a44b5d912baa3410d991165d7c507\nP = 9df9d6cc20b8540411af4e5357ef2b0353cb1f2ab5ffc3e246b41c32f71e951f\n\nModSqrt = 198fc8569be172dc9b71023ed3d42d2ba94bae4099643f6517ab03f540527fdb\nA = 65bebdb00a96fc814ec44b81f98b59fba3c30203928fa5214c51e0a97091645280c947b005847f239758482b9bfc45b066fde340d1fe32fc9c1bf02e1b2d0ec\nP = 9df9d6cc20b8540411af4e5357ef2b0353cb1f2ab5ffc3e246b41c32f71e951f\n\nModSqrt = 21b7f74c30ded681d6138cf8e6fd798f32a049e94138e982f1845df3dc9e686f\nA = 9a30b791c1ba4f394b4e3dcd5837e474237f4fe8987b255c098a47b2c14c598ec69d2beae444dd4fe9c4ede8173d2b187677cc706a3c28f3b81627d8a5fb6fd\nP = 9df9d6cc20b8540411af4e5357ef2b0353cb1f2ab5ffc3e246b41c32f71e951f\n\nModSqrt = a1d52989f12f204d3d2167d9b1e6c8a6174c0c786a979a5952383b7b8bd186\nA = 2eee37cf06228a387788188e650bc6d8a2ff402931443f69156a29155eca07dcb45f3aac238d92943c0c25c896098716baa433f25bd696a142f5a69d5d937e81\nP = 9df9d6cc20b8540411af4e5357ef2b0353cb1f",
+    "2ab5ffc3e246b41c32f71e951f\n\n\n# NotModSquare tests.\n#\n# These test vectors are such that NotModSquare is not a square modulo P.\n\nNotModSquare = 03\nP = 07\n\nNotModSquare = 05\nP = 07\n\nNotModSquare = 06\nP = 07\n\nNotModSquare = 9df9d6cc20b8540411af4e5357ef2b0353cb1f2ab5ffc3e246b41c32f71e951e\nP = 9df9d6cc20b8540411af4e5357ef2b0353cb1f2ab5ffc3e246b41c32f71e951f\n\n\n# ModInv tests.\n#\n# These test vectors satisfy ModInv * A = 1 (mod M) and 0 <= ModInv < M.\n\nModInv = 00\nA = 00\nM = 01\n\nModInv = 00\nA = 01\nM = 01\n\nModInv = 00\nA = 02\nM = 01\n\nModInv = 00\nA = 03\nM = 01\n",
 };
-static const size_t kLen35 = 833482;
+static const size_t kLen35 = 836140;
 
 static const char *kData36[] = {
     "# Negation tests.\n#\n# The following tests satisfy A = -B (mod P).\n\nTest = Negate\nA = 0000000000000000000000000000000000000000000000000000000000000000\nB = 0000000000000000000000000000000000000000000000000000000000000000\n\nTest = Negate\nA = 0000000000000000000000000000000000000000000000000000000000000001\nB = ffffffff00000001000000000000000000000000fffffffffffffffffffffffe\n\nTest = Negate\nA = 0000000000000000000000000000000000000000000000000000000000000003\nB = ffffffff00000001000000000000000000000000fffffffffffffffffffffffc\n\nTest = Negate\nA = 0000000000000000000000000000000000000000000000000000000000000007\nB = ffffffff00000001000000000000000000000000fffffffffffffffffffffff8\n\nTest = Negate\nA = 000000000000000000000000000000000000000000000000000000000000000f\nB = ffffffff00000001000000000000000000000000fffffffffffffffffffffff0\n\nTest = Negate\nA = 000000000000000000000000000000000000000000000000000000000000001f\nB = ffffffff00000001000000000000000000000000ffffffffffffffffffffffe0\n\nTest = Negate\nA = 000000000000000000000000000000000000000000000000000000000000003f\nB = ffffffff00000001000000000000000000000000ffffffffffffffffffffffc0\n\nTest = Negate\nA = 000000000000000000000000000000000000000000000000000000000000007f\nB = ffffffff00000001000000000000000000000000ffffffffffffffffffffff80\n\nTest = Negate\nA = 00000000000000000000000000000000000000000000000000000000000000ff\nB = ffffffff00000001000000000000000000000000ffffffffffffffffffffff00\n\nTest = Negate\nA = 00000000000000000000000000000000000000000000000000000000000001ff\nB = ffffffff00000001000000000000000000000000fffffffffffffffffffffe00\n\nTest = Negate\nA = 00000000000000000000000000000000000000000000000000000000000003ff\nB = ffffffff00000001000000000000000000000000fffffffffffffffffffffc00\n\nTest = Negate\nA = 00000000000000000000000000000000000000000000000000000000000007ff\nB = ffffffff00000001000000000000000000000000fffffffffffffffffffff800\n\nTest = Negate\nA = 0000000000000000000000000000000000000000000000000000000000000fff\nB = ffffffff00000001000000000000000000000000fffffffffffffffffffff000\n\nTest = Negate\nA = 0000000000000000000000000000000000000000000000000000000000001fff\nB = ffffffff00000001000000000000000000000000ffffffffffffffffffffe000\n\nTest = Negate\nA = 0000000000000000000000000000000000000000000000000000000000003fff\nB = ffffffff00000001000000000000000000000000ffffffffffffffffffffc000\n\nTest = Negate\nA = 0000000000000000000000000000000000000000000000000000000000007fff\nB = ffffffff00000001000000000000000000000000ffffffffffffffffffff8000\n\nTest = Negate\nA = 000000000000000000000000000000000000000000000000000000000000ffff\nB = ffffffff00000001000000000000000000000000ffffffffffffffffffff0000\n\nTest = Negate\nA = 000000000000000000000000000000000000000000000000000000000001ffff\nB = ffffffff00000001000000000000000000000000fffffffffffffffffffe0000\n\nTest = Negate\nA = 000000000000000000000000000000000000000000000000000000000003ffff\nB = ffffffff00000001000000000000000000000000fffffffffffffffffffc0000\n\nTest = Negate\nA = 000000000000000000000000000000000000000000000000000000000007ffff\nB = ffffffff00000001000000000000000000000000fffffffffffffffffff80000\n\nTest = Negate\nA = 00000000000000000000000000000000000000000000000000000000000fffff\nB = ffffffff00000001000000000000000000000000fffffffffffffffffff00000\n\nTest = Negate\nA = 00000000000000000000000000000000000000000000000000000000001fffff\nB = ffffffff00000001000000000000000000000000ffffffffffffffffffe00000\n\nTest = Negate\nA = 00000000000000000000000000000000000000000000000000000000003fffff\nB = ffffffff00000001000000000000000000000000ffffffffffffffffffc00000\n\nTest = Negate\nA = 00000000000000000000000000000000000000000000000000000000007fffff\nB = ffffffff00000001000000000000000000000000ffffffffffffffffff800000\n\nTest = Negate\nA = 0000000000000000000000000000000000000000000000000000000000ffffff\nB = ffffffff00000001000000000000000000000000ffffffffffffffffff000000\n\nTest = Negate\nA = 0000000000000000000000000000000000000000000000000000000001ffffff\nB = ffffffff00000001000000000000000000000000fffffffffffffffffe000000\n\nTest = Negate\nA = 0000000000000000000000000000000000000000000000000000000003ffffff\nB = ffffffff00000001000000000000000000000000fffffffffffffffffc000000\n\nTest = Negate\nA = 0000000000000000000000000000000000000000000000000000000007ffffff\nB = ffffffff00000001000000000000000000000000fffffffffffffffff8000000\n\nTest = Negate\nA = 000000000000000000000000000000000000000000000000000000000fffffff\nB = ffffffff00000001000000000000000000000000fffffffffffffffff0000000\n\nTest = Negate\nA = 000000000000000000000000000000000000000000000000000000001fffffff\nB = ffffffff00000001000000000000000000000000ffffffffffffffffe0000000\n\nTest = Negate\nA = 000000000000000000000000000000000000000000000000000000003fffffff\nB = ffffffff00000001000000000000000000000000ffffffffffffffffc0000000\n\nTest = Negate\nA = 000000000000000000000000000000000000000000000000000000007fffffff\nB = ffffffff00000001000000000000000000000000ffffffffffffffff80000000\n\nTest = Negate\nA = 00000000000000000000000000000000000000000000000000000000ffffffff\nB = ffffffff00000001000000000000000000000000ffffffffffffffff00000000\n\nTest = Negate\nA = 00000000000000000000000000000000000000000000000000000001ffffffff\nB = ffffffff00000001000000000000000000000000fffffffffffffffe00000000\n\nTest = Negate\nA = 00000000000000000000000000000000000000000000000000000003ffffffff\nB = ffffffff00000001000000000000000000000000fffffffffffffffc00000000\n\nTest = Negate\nA = 00000000000000000000000000000000000000000000000000000007ffffffff\nB = ffffffff00000001000000000000000000000000fffffffffffffff800000000\n\nTest = Negate\nA = 0000000000000000000000000000000000000000000000000000000fffffffff\nB = ffffffff00000001000000000000000000000000fffffffffffffff000000000\n\nTest = Negate\nA = 0000000000000000000000000000000000000000000000000000001fffffffff\nB = ffffffff00000001000000000000000000000000ffffffffffffffe000000000\n\nTest = Negate\nA = 0000000000000000000000000000000000000000000000000000003fffffffff\nB = ffffffff00000001000000000000000000000000ffffffffffffffc000000000\n\nTest = Negate\nA = 0000000000000000000000000000000000000000000000000000007fffffffff\nB = ffffffff00000001000000000000000000000000ffffffffffffff8000000000\n\nTest = Negate\nA = 000000000000000000000000000000000000000000000000000000ffffffffff\nB = ffffffff00000001000000000000000000000000ffffffffffffff0000000000\n\nTest = Negate\nA = 000000000000000000000000000000000000000000000000000001ffffffffff\nB = ffffffff00000001000000000000000000000000fffffffffffffe0000000000\n\nTest = Negate\nA = 000000000000000000000000000000000000000000000000000003ffffffffff\nB = ffffffff00000001000000000000000000000000fffffffffffffc0000000000\n\nTest = Negate\nA = 000000000000000000000000000000000000000000000000000007ffffffffff\nB = ffffffff00000001000000000000000000000000fffffffffffff80000000000\n\nTest = Negate\nA = 00000000000000000000000000000000000000000000000000000fffffffffff\nB = ffffffff00000001000000000000000000000000fffffffffffff00000000000\n\nTest = Negate\nA = 00000000000000000000000000000000000000000000000000001fffffffffff\nB = ffffffff00000001000000000000000000000000ffffffffffffe00000000000\n\nTest = Negate\nA = 00000000000000000000000000000000000000000000000000003fffffffffff\nB = ffffffff00000001000000000000000000000000ffffffffffffc00000000000\n\nTest = Negate\nA = 00000000000000000000000000000000000000000000000000007fffffffffff\nB = ffffffff00000001000000000000000000000000ffffffffffff800000000000\n\nTest = Negate\nA = 0000000000000000000000000000000000000000000000000000ffffffffffff\nB = ffffffff00000001000000000000000000000000ffffffffffff000000000000\n\nTest = Negate\nA = 0000000000000000000000000000000000000000000000000001ffffffffffff\nB = ffffffff00000001000000000000000000000000fffffffffffe000000000000\n\nTest = Negate\nA = 0000000000000000000000000000000000000000000000000003ffffffffffff\nB = ffffffff00000001000000000000000000000000fffffffffffc000000000000\n\nTest = Negate\nA = 0000000000000000000000000000000000000000000000000007ffffffffffff\nB = ffffffff00000001000000000000000000000000fffffffffff8000000000000\n\nTest = Negate\nA = 000000000000000000000000000000000000000000000000000fffffffffffff\nB = ffffffff00000001000000000000000000000000fffffffffff0000000000000\n\nTest = Negate\nA ",
diff --git a/src/boringssl/err_data.c b/src/boringssl/err_data.c
index d8dc7aa..dc78ba8 100644
--- a/src/boringssl/err_data.c
+++ b/src/boringssl/err_data.c
@@ -75,52 +75,52 @@
     0xc3b00ea,
     0xc3b88d4,
     0x10320845,
-    0x10329513,
-    0x1033151f,
-    0x10339538,
-    0x1034154b,
-    0x10348eed,
+    0x10329535,
+    0x10331541,
+    0x1033955a,
+    0x1034156d,
+    0x10348efc,
     0x10350c5e,
-    0x1035955e,
-    0x10361573,
-    0x10369586,
-    0x103715a5,
-    0x103795be,
-    0x103815d3,
-    0x103895f1,
-    0x10391600,
-    0x1039961c,
-    0x103a1637,
-    0x103a9646,
-    0x103b1662,
-    0x103b967d,
-    0x103c1694,
+    0x10359580,
+    0x10361595,
+    0x103695a8,
+    0x103715c7,
+    0x103795e0,
+    0x103815f5,
+    0x10389613,
+    0x10391622,
+    0x1039963e,
+    0x103a1659,
+    0x103a9668,
+    0x103b1684,
+    0x103b969f,
+    0x103c16b6,
     0x103c80ea,
-    0x103d16a5,
-    0x103d96b9,
-    0x103e16d8,
-    0x103e96e7,
-    0x103f16fe,
-    0x103f9711,
+    0x103d16c7,
+    0x103d96db,
+    0x103e16fa,
+    0x103e9709,
+    0x103f1720,
+    0x103f9733,
     0x10400c22,
-    0x10409724,
-    0x10411742,
-    0x10419755,
-    0x1042176f,
-    0x1042977f,
-    0x10431793,
-    0x104397a9,
-    0x104417c1,
-    0x104497d6,
-    0x104517ea,
-    0x104597fc,
+    0x10409746,
+    0x10411764,
+    0x10419777,
+    0x10421791,
+    0x104297a1,
+    0x104317b5,
+    0x104397cb,
+    0x104417e3,
+    0x104497f8,
+    0x1045180c,
+    0x1045981e,
     0x104605fb,
     0x1046894d,
-    0x10471811,
-    0x10479828,
-    0x1048183d,
-    0x1048984b,
-    0x10490e4f,
+    0x10471833,
+    0x1047984a,
+    0x1048185f,
+    0x1048986d,
+    0x10490e5e,
     0x14320c05,
     0x14328c13,
     0x14330c22,
@@ -128,55 +128,56 @@
     0x143400ac,
     0x143480ea,
     0x18320083,
-    0x18328f43,
+    0x18328f52,
     0x183300ac,
-    0x18338f59,
-    0x18340f6d,
+    0x18338f68,
+    0x18340f7c,
     0x183480ea,
-    0x18350f82,
-    0x18358f9a,
-    0x18360faf,
-    0x18368fc3,
-    0x18370fe7,
-    0x18378ffd,
-    0x18381011,
-    0x18389021,
+    0x18350f91,
+    0x18358fa9,
+    0x18360fbe,
+    0x18368fd2,
+    0x18370ff6,
+    0x1837900c,
+    0x18381020,
+    0x18389030,
     0x18390a73,
-    0x18399031,
-    0x183a1059,
-    0x183a907f,
+    0x18399040,
+    0x183a1068,
+    0x183a908e,
     0x183b0c6a,
-    0x183b90b4,
-    0x183c10c6,
-    0x183c90d1,
-    0x183d10e1,
-    0x183d90f2,
-    0x183e1103,
-    0x183e9115,
-    0x183f113e,
-    0x183f9157,
-    0x1840116f,
+    0x183b90c3,
+    0x183c10d5,
+    0x183c90e0,
+    0x183d10f0,
+    0x183d9101,
+    0x183e1112,
+    0x183e9124,
+    0x183f114d,
+    0x183f9166,
+    0x1840117e,
     0x184086d3,
-    0x184110a2,
-    0x1841906d,
-    0x1842108c,
-    0x18429046,
-    0x20321196,
-    0x243211a2,
+    0x184110b1,
+    0x1841907c,
+    0x1842109b,
+    0x18429055,
+    0x203211b8,
+    0x203291a5,
+    0x243211c4,
     0x24328993,
-    0x243311b4,
-    0x243391c1,
-    0x243411ce,
-    0x243491e0,
-    0x243511ef,
-    0x2435920c,
-    0x24361219,
-    0x24369227,
-    0x24371235,
-    0x24379243,
-    0x2438124c,
-    0x24389259,
-    0x2439126c,
+    0x243311d6,
+    0x243391e3,
+    0x243411f0,
+    0x24349202,
+    0x24351211,
+    0x2435922e,
+    0x2436123b,
+    0x24369249,
+    0x24371257,
+    0x24379265,
+    0x2438126e,
+    0x2438927b,
+    0x2439128e,
     0x28320c52,
     0x28328c6a,
     0x28330c22,
@@ -184,43 +185,43 @@
     0x28340c5e,
     0x283480ac,
     0x283500ea,
-    0x2c322c30,
-    0x2c329283,
-    0x2c332c3e,
-    0x2c33ac50,
-    0x2c342c64,
-    0x2c34ac76,
-    0x2c352c91,
-    0x2c35aca3,
-    0x2c362cb6,
+    0x2c322c6c,
+    0x2c3292a5,
+    0x2c332c7a,
+    0x2c33ac8c,
+    0x2c342ca0,
+    0x2c34acb2,
+    0x2c352ccd,
+    0x2c35acdf,
+    0x2c362cf2,
     0x2c36832d,
-    0x2c372cc3,
-    0x2c37acd5,
-    0x2c382cfa,
-    0x2c38ad11,
-    0x2c392d1f,
-    0x2c39ad2f,
-    0x2c3a2d41,
-    0x2c3aad55,
-    0x2c3b2d66,
-    0x2c3bad85,
-    0x2c3c1295,
-    0x2c3c92ab,
-    0x2c3d2d99,
-    0x2c3d92c4,
-    0x2c3e2db6,
-    0x2c3eadc4,
-    0x2c3f2ddc,
-    0x2c3fadf4,
-    0x2c402e01,
-    0x2c409196,
-    0x2c412e12,
-    0x2c41ae25,
-    0x2c42116f,
-    0x2c42ae36,
+    0x2c372cff,
+    0x2c37ad11,
+    0x2c382d36,
+    0x2c38ad4d,
+    0x2c392d5b,
+    0x2c39ad6b,
+    0x2c3a2d7d,
+    0x2c3aad91,
+    0x2c3b2da2,
+    0x2c3badc1,
+    0x2c3c12b7,
+    0x2c3c92cd,
+    0x2c3d2dd5,
+    0x2c3d92e6,
+    0x2c3e2df2,
+    0x2c3eae00,
+    0x2c3f2e18,
+    0x2c3fae30,
+    0x2c402e3d,
+    0x2c4091b8,
+    0x2c412e4e,
+    0x2c41ae61,
+    0x2c42117e,
+    0x2c42ae72,
     0x2c430720,
-    0x2c43ad77,
-    0x2c442ce8,
+    0x2c43adb3,
+    0x2c442d24,
     0x30320000,
     0x30328015,
     0x3033001f,
@@ -335,238 +336,240 @@
     0x3c380dc0,
     0x3c388dd4,
     0x3c390c6a,
-    0x3c398de8,
-    0x3c3a0dfc,
+    0x3c398df7,
+    0x3c3a0e0b,
     0x3c3a890d,
-    0x3c3b0e0c,
-    0x3c3b8e27,
-    0x3c3c0e39,
-    0x3c3c8e6c,
-    0x3c3d0e76,
-    0x3c3d8e8a,
-    0x3c3e0e98,
-    0x3c3e8ebd,
+    0x3c3b0e1b,
+    0x3c3b8e36,
+    0x3c3c0e48,
+    0x3c3c8e7b,
+    0x3c3d0e85,
+    0x3c3d8e99,
+    0x3c3e0ea7,
+    0x3c3e8ecc,
     0x3c3f0c93,
-    0x3c3f8ea6,
+    0x3c3f8eb5,
     0x3c4000ac,
     0x3c4080ea,
     0x3c410d13,
     0x3c418d52,
-    0x3c420e4f,
-    0x403218a4,
-    0x403298ba,
-    0x403318e8,
-    0x403398f2,
-    0x40341909,
-    0x40349927,
-    0x40351937,
-    0x40359949,
-    0x40361956,
-    0x40369962,
-    0x40371977,
-    0x40379989,
-    0x40381994,
-    0x403899a6,
-    0x40390eed,
-    0x403999b6,
-    0x403a19c9,
-    0x403a99ea,
-    0x403b19fb,
-    0x403b9a0b,
+    0x3c420e5e,
+    0x3c428de8,
+    0x403218c6,
+    0x403298dc,
+    0x4033190a,
+    0x40339914,
+    0x4034192b,
+    0x40349949,
+    0x40351959,
+    0x4035996b,
+    0x40361978,
+    0x40369984,
+    0x40371999,
+    0x403799ab,
+    0x403819b6,
+    0x403899c8,
+    0x40390efc,
+    0x403999d8,
+    0x403a19eb,
+    0x403a9a0c,
+    0x403b1a1d,
+    0x403b9a2d,
     0x403c0064,
     0x403c8083,
-    0x403d1a8f,
-    0x403d9aa5,
-    0x403e1ab4,
-    0x403e9aec,
-    0x403f1b06,
-    0x403f9b14,
-    0x40401b29,
-    0x40409b3d,
-    0x40411b5a,
-    0x40419b75,
-    0x40421b8e,
-    0x40429ba1,
-    0x40431bb5,
-    0x40439bcd,
-    0x40441be4,
+    0x403d1ab1,
+    0x403d9ac7,
+    0x403e1ad6,
+    0x403e9b0e,
+    0x403f1b28,
+    0x403f9b36,
+    0x40401b4b,
+    0x40409b5f,
+    0x40411b7c,
+    0x40419b97,
+    0x40421bb0,
+    0x40429bc3,
+    0x40431bd7,
+    0x40439bef,
+    0x40441c06,
     0x404480ac,
-    0x40451bf9,
-    0x40459c0b,
-    0x40461c2f,
-    0x40469c4f,
-    0x40471c5d,
-    0x40479c84,
-    0x40481cc1,
-    0x40489cda,
-    0x40491cf1,
-    0x40499d0b,
-    0x404a1d22,
-    0x404a9d40,
-    0x404b1d58,
-    0x404b9d6f,
-    0x404c1d85,
-    0x404c9d97,
-    0x404d1db8,
-    0x404d9dda,
-    0x404e1dee,
-    0x404e9dfb,
-    0x404f1e28,
-    0x404f9e51,
-    0x40501e8c,
-    0x40509ea0,
-    0x40511ebb,
-    0x40521ecb,
-    0x40529eef,
-    0x40531f07,
-    0x40539f1a,
-    0x40541f2f,
-    0x40549f52,
-    0x40551f60,
-    0x40559f7d,
-    0x40561f8a,
-    0x40569fa3,
-    0x40571fbb,
-    0x40579fce,
-    0x40581fe3,
-    0x4058a00a,
-    0x40592039,
-    0x4059a066,
-    0x405a207a,
-    0x405aa08a,
-    0x405b20a2,
-    0x405ba0b3,
-    0x405c20c6,
-    0x405ca105,
-    0x405d2112,
-    0x405da129,
-    0x405e2167,
+    0x40451c1b,
+    0x40459c2d,
+    0x40461c51,
+    0x40469c71,
+    0x40471c7f,
+    0x40479ca6,
+    0x40481ce3,
+    0x40489d16,
+    0x40491d2d,
+    0x40499d47,
+    0x404a1d5e,
+    0x404a9d7c,
+    0x404b1d94,
+    0x404b9dab,
+    0x404c1dc1,
+    0x404c9dd3,
+    0x404d1df4,
+    0x404d9e16,
+    0x404e1e2a,
+    0x404e9e37,
+    0x404f1e64,
+    0x404f9e8d,
+    0x40501ec8,
+    0x40509edc,
+    0x40511ef7,
+    0x40521f07,
+    0x40529f2b,
+    0x40531f43,
+    0x40539f56,
+    0x40541f6b,
+    0x40549f8e,
+    0x40551f9c,
+    0x40559fb9,
+    0x40561fc6,
+    0x40569fdf,
+    0x40571ff7,
+    0x4057a00a,
+    0x4058201f,
+    0x4058a046,
+    0x40592075,
+    0x4059a0a2,
+    0x405a20b6,
+    0x405aa0c6,
+    0x405b20de,
+    0x405ba0ef,
+    0x405c2102,
+    0x405ca141,
+    0x405d214e,
+    0x405da165,
+    0x405e21a3,
     0x405e8ab1,
-    0x405f2188,
-    0x405fa195,
-    0x406021a3,
-    0x4060a1c5,
-    0x40612209,
-    0x4061a241,
-    0x40622258,
-    0x4062a269,
-    0x4063227a,
-    0x4063a28f,
-    0x406422a6,
-    0x4064a2d2,
-    0x406522ed,
-    0x4065a304,
-    0x4066231c,
-    0x4066a346,
-    0x40672371,
-    0x4067a392,
-    0x406823b9,
-    0x4068a3da,
-    0x4069240c,
-    0x4069a43a,
-    0x406a245b,
-    0x406aa47b,
-    0x406b2603,
-    0x406ba626,
-    0x406c263c,
-    0x406ca8b7,
-    0x406d28e6,
-    0x406da90e,
-    0x406e293c,
-    0x406ea989,
-    0x406f29a8,
-    0x406fa9e0,
-    0x407029f3,
-    0x4070aa10,
+    0x405f21c4,
+    0x405fa1d1,
+    0x406021df,
+    0x4060a201,
+    0x40612245,
+    0x4061a27d,
+    0x40622294,
+    0x4062a2a5,
+    0x406322b6,
+    0x4063a2cb,
+    0x406422e2,
+    0x4064a30e,
+    0x40652329,
+    0x4065a340,
+    0x40662358,
+    0x4066a382,
+    0x406723ad,
+    0x4067a3ce,
+    0x406823f5,
+    0x4068a416,
+    0x40692448,
+    0x4069a476,
+    0x406a2497,
+    0x406aa4b7,
+    0x406b263f,
+    0x406ba662,
+    0x406c2678,
+    0x406ca8f3,
+    0x406d2922,
+    0x406da94a,
+    0x406e2978,
+    0x406ea9c5,
+    0x406f29e4,
+    0x406faa1c,
+    0x40702a2f,
+    0x4070aa4c,
     0x40710800,
-    0x4071aa22,
-    0x40722a35,
-    0x4072aa4e,
-    0x40732a66,
-    0x40739482,
-    0x40742a7a,
-    0x4074aa94,
-    0x40752aa5,
-    0x4075aab9,
-    0x40762ac7,
-    0x40769259,
-    0x40772aec,
-    0x4077ab0e,
-    0x40782b29,
-    0x4078ab62,
-    0x40792b79,
-    0x4079ab8f,
-    0x407a2b9b,
-    0x407aabae,
-    0x407b2bc3,
-    0x407babd5,
-    0x407c2c06,
-    0x407cac0f,
-    0x407d23f5,
-    0x407d9e61,
-    0x407e2b3e,
-    0x407ea01a,
-    0x407f1c71,
-    0x407f9a31,
-    0x40801e38,
-    0x40809c99,
-    0x40811edd,
-    0x40819e12,
-    0x40822927,
-    0x40829a17,
-    0x40831ff5,
-    0x4083a2b7,
-    0x40841cad,
-    0x4084a052,
-    0x408520d7,
-    0x4085a1ed,
-    0x40862149,
-    0x40869e7b,
-    0x4087296d,
-    0x4087a21e,
-    0x40881a78,
-    0x4088a3a5,
-    0x40891ac7,
-    0x40899a54,
-    0x408a265c,
-    0x408a9862,
-    0x408b2bea,
-    0x408ba9bd,
-    0x408c20e7,
-    0x408c987e,
-    0x41f4252e,
-    0x41f925c0,
-    0x41fe24b3,
-    0x41fea6a8,
-    0x41ff2799,
-    0x42032547,
-    0x42082569,
-    0x4208a5a5,
-    0x42092497,
-    0x4209a5df,
-    0x420a24ee,
-    0x420aa4ce,
-    0x420b250e,
-    0x420ba587,
-    0x420c27b5,
-    0x420ca675,
-    0x420d268f,
-    0x420da6c6,
-    0x421226e0,
-    0x4217277c,
-    0x4217a722,
-    0x421c2744,
-    0x421f26ff,
-    0x422127cc,
-    0x4226275f,
-    0x422b289b,
-    0x422ba849,
-    0x422c2883,
-    0x422ca808,
-    0x422d27e7,
-    0x422da868,
-    0x422e282e,
-    0x422ea954,
+    0x4071aa5e,
+    0x40722a71,
+    0x4072aa8a,
+    0x40732aa2,
+    0x407394a4,
+    0x40742ab6,
+    0x4074aad0,
+    0x40752ae1,
+    0x4075aaf5,
+    0x40762b03,
+    0x4076927b,
+    0x40772b28,
+    0x4077ab4a,
+    0x40782b65,
+    0x4078ab9e,
+    0x40792bb5,
+    0x4079abcb,
+    0x407a2bd7,
+    0x407aabea,
+    0x407b2bff,
+    0x407bac11,
+    0x407c2c42,
+    0x407cac4b,
+    0x407d2431,
+    0x407d9e9d,
+    0x407e2b7a,
+    0x407ea056,
+    0x407f1c93,
+    0x407f9a53,
+    0x40801e74,
+    0x40809cbb,
+    0x40811f19,
+    0x40819e4e,
+    0x40822963,
+    0x40829a39,
+    0x40832031,
+    0x4083a2f3,
+    0x40841ccf,
+    0x4084a08e,
+    0x40852113,
+    0x4085a229,
+    0x40862185,
+    0x40869eb7,
+    0x408729a9,
+    0x4087a25a,
+    0x40881a9a,
+    0x4088a3e1,
+    0x40891ae9,
+    0x40899a76,
+    0x408a2698,
+    0x408a9884,
+    0x408b2c26,
+    0x408ba9f9,
+    0x408c2123,
+    0x408c98a0,
+    0x408d1cfc,
+    0x41f4256a,
+    0x41f925fc,
+    0x41fe24ef,
+    0x41fea6e4,
+    0x41ff27d5,
+    0x42032583,
+    0x420825a5,
+    0x4208a5e1,
+    0x420924d3,
+    0x4209a61b,
+    0x420a252a,
+    0x420aa50a,
+    0x420b254a,
+    0x420ba5c3,
+    0x420c27f1,
+    0x420ca6b1,
+    0x420d26cb,
+    0x420da702,
+    0x4212271c,
+    0x421727b8,
+    0x4217a75e,
+    0x421c2780,
+    0x421f273b,
+    0x42212808,
+    0x4226279b,
+    0x422b28d7,
+    0x422ba885,
+    0x422c28bf,
+    0x422ca844,
+    0x422d2823,
+    0x422da8a4,
+    0x422e286a,
+    0x422ea990,
     0x4432072b,
     0x4432873a,
     0x44330746,
@@ -584,114 +587,114 @@
     0x44390800,
     0x4439880e,
     0x443a0821,
-    0x48321283,
-    0x48329295,
-    0x483312ab,
-    0x483392c4,
-    0x4c3212e9,
-    0x4c3292f9,
-    0x4c33130c,
-    0x4c33932c,
+    0x483212a5,
+    0x483292b7,
+    0x483312cd,
+    0x483392e6,
+    0x4c32130b,
+    0x4c32931b,
+    0x4c33132e,
+    0x4c33934e,
     0x4c3400ac,
     0x4c3480ea,
-    0x4c351338,
-    0x4c359346,
-    0x4c361362,
-    0x4c369375,
-    0x4c371384,
-    0x4c379392,
-    0x4c3813a7,
-    0x4c3893b3,
-    0x4c3913d3,
-    0x4c3993fd,
-    0x4c3a1416,
-    0x4c3a942f,
+    0x4c35135a,
+    0x4c359368,
+    0x4c361384,
+    0x4c369397,
+    0x4c3713a6,
+    0x4c3793b4,
+    0x4c3813c9,
+    0x4c3893d5,
+    0x4c3913f5,
+    0x4c39941f,
+    0x4c3a1438,
+    0x4c3a9451,
     0x4c3b05fb,
-    0x4c3b9448,
-    0x4c3c145a,
-    0x4c3c9469,
-    0x4c3d1482,
+    0x4c3b946a,
+    0x4c3c147c,
+    0x4c3c948b,
+    0x4c3d14a4,
     0x4c3d8c45,
-    0x4c3e14db,
-    0x4c3e9491,
-    0x4c3f14fd,
-    0x4c3f9259,
-    0x4c4014a7,
-    0x4c4092d5,
-    0x4c4114cb,
-    0x50322e48,
-    0x5032ae57,
-    0x50332e62,
-    0x5033ae72,
-    0x50342e8b,
-    0x5034aea5,
-    0x50352eb3,
-    0x5035aec9,
-    0x50362edb,
-    0x5036aef1,
-    0x50372f0a,
-    0x5037af1d,
-    0x50382f35,
-    0x5038af46,
-    0x50392f5b,
-    0x5039af6f,
-    0x503a2f8f,
-    0x503aafa5,
-    0x503b2fbd,
-    0x503bafcf,
-    0x503c2feb,
-    0x503cb002,
-    0x503d301b,
-    0x503db031,
-    0x503e303e,
-    0x503eb054,
-    0x503f3066,
+    0x4c3e14fd,
+    0x4c3e94b3,
+    0x4c3f151f,
+    0x4c3f927b,
+    0x4c4014c9,
+    0x4c4092f7,
+    0x4c4114ed,
+    0x50322e84,
+    0x5032ae93,
+    0x50332e9e,
+    0x5033aeae,
+    0x50342ec7,
+    0x5034aee1,
+    0x50352eef,
+    0x5035af05,
+    0x50362f17,
+    0x5036af2d,
+    0x50372f46,
+    0x5037af59,
+    0x50382f71,
+    0x5038af82,
+    0x50392f97,
+    0x5039afab,
+    0x503a2fcb,
+    0x503aafe1,
+    0x503b2ff9,
+    0x503bb00b,
+    0x503c3027,
+    0x503cb03e,
+    0x503d3057,
+    0x503db06d,
+    0x503e307a,
+    0x503eb090,
+    0x503f30a2,
     0x503f8382,
-    0x50403079,
-    0x5040b089,
-    0x504130a3,
-    0x5041b0b2,
-    0x504230cc,
-    0x5042b0e9,
-    0x504330f9,
-    0x5043b109,
-    0x50443118,
+    0x504030b5,
+    0x5040b0c5,
+    0x504130df,
+    0x5041b0ee,
+    0x50423108,
+    0x5042b125,
+    0x50433135,
+    0x5043b145,
+    0x50443154,
     0x5044843f,
-    0x5045312c,
-    0x5045b14a,
-    0x5046315d,
-    0x5046b173,
-    0x50473185,
-    0x5047b19a,
-    0x504831c0,
-    0x5048b1ce,
-    0x504931e1,
-    0x5049b1f6,
-    0x504a320c,
-    0x504ab21c,
-    0x504b323c,
-    0x504bb24f,
-    0x504c3272,
-    0x504cb2a0,
-    0x504d32b2,
-    0x504db2cf,
-    0x504e32ea,
-    0x504eb306,
-    0x504f3318,
-    0x504fb32f,
-    0x5050333e,
+    0x50453168,
+    0x5045b186,
+    0x50463199,
+    0x5046b1af,
+    0x504731c1,
+    0x5047b1d6,
+    0x504831fc,
+    0x5048b20a,
+    0x5049321d,
+    0x5049b232,
+    0x504a3248,
+    0x504ab258,
+    0x504b3278,
+    0x504bb28b,
+    0x504c32ae,
+    0x504cb2dc,
+    0x504d32ee,
+    0x504db30b,
+    0x504e3326,
+    0x504eb342,
+    0x504f3354,
+    0x504fb36b,
+    0x5050337a,
     0x505086ef,
-    0x50513351,
-    0x58320f2b,
-    0x68320eed,
+    0x5051338d,
+    0x58320f3a,
+    0x68320efc,
     0x68328c6a,
     0x68330c7d,
-    0x68338efb,
-    0x68340f0b,
+    0x68338f0a,
+    0x68340f1a,
     0x683480ea,
-    0x6c320ec9,
+    0x6c320ed8,
     0x6c328c34,
-    0x6c330ed4,
+    0x6c330ee3,
     0x74320a19,
     0x743280ac,
     0x74330c45,
@@ -721,7 +724,7 @@
     0x783d8b4a,
     0x783e0aa0,
     0x783e8a52,
-    0x7c321185,
+    0x7c321194,
 };
 
 const size_t kOpenSSLReasonValuesLen = sizeof(kOpenSSLReasonValues) / sizeof(kOpenSSLReasonValues[0]);
@@ -912,6 +915,7 @@
     "INVALID_FORM\0"
     "INVALID_GROUP_ORDER\0"
     "INVALID_PRIVATE_KEY\0"
+    "INVALID_SCALAR\0"
     "MISSING_PRIVATE_KEY\0"
     "NON_NAMED_CURVE\0"
     "PKPARAMETERS2GROUP_FAILURE\0"
@@ -959,6 +963,7 @@
     "UNKNOWN_PUBLIC_KEY_TYPE\0"
     "UNSUPPORTED_ALGORITHM\0"
     "OUTPUT_TOO_LARGE\0"
+    "INVALID_OID_STRING\0"
     "UNKNOWN_NID\0"
     "BAD_BASE64_DECODE\0"
     "BAD_END_LINE\0"
@@ -1094,6 +1099,7 @@
     "DUPLICATE_EXTENSION\0"
     "DUPLICATE_KEY_SHARE\0"
     "ECC_CERT_NOT_FOR_SIGNING\0"
+    "EMPTY_HELLO_RETRY_REQUEST\0"
     "EMS_STATE_INCONSISTENT\0"
     "ENCRYPTED_LENGTH_TOO_LONG\0"
     "ERROR_ADDING_EXTENSION\0"
diff --git a/src/boringssl/gen_build_yaml.py b/src/boringssl/gen_build_yaml.py
index 221cbe7..593b66d 100755
--- a/src/boringssl/gen_build_yaml.py
+++ b/src/boringssl/gen_build_yaml.py
@@ -67,7 +67,9 @@
             ),
             'headers': sorted(
               map_dir(f)
-              for f in files['ssl_headers'] + files['ssl_internal_headers'] + files['crypto_headers'] + files['crypto_internal_headers']
+              # We want to include files['fips_fragments'], but not build them as objects.
+              # See https://boringssl-review.googlesource.com/c/boringssl/+/16946
+              for f in files['ssl_headers'] + files['ssl_internal_headers'] + files['crypto_headers'] + files['crypto_internal_headers'] + files['fips_fragments']
             ),
             'boringssl': True,
             'defaults': 'boringssl',
diff --git a/src/compiler/config.h b/src/compiler/config.h
index 36d28df..cfdc303 100644
--- a/src/compiler/config.h
+++ b/src/compiler/config.h
@@ -19,7 +19,7 @@
 #ifndef SRC_COMPILER_CONFIG_H
 #define SRC_COMPILER_CONFIG_H
 
-#include <grpc++/impl/codegen/config_protobuf.h>
+#include <grpcpp/impl/codegen/config_protobuf.h>
 
 #ifndef GRPC_CUSTOM_CODEGENERATOR
 #include <google/protobuf/compiler/code_generator.h>
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index f35bfd9..30d66b4 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -64,16 +64,15 @@
 
 void PrintIncludes(grpc_generator::Printer* printer,
                    const std::vector<grpc::string>& headers,
-                   const Parameters& params) {
+                   bool use_system_headers, const grpc::string& search_path) {
   std::map<grpc::string, grpc::string> vars;
 
-  vars["l"] = params.use_system_headers ? '<' : '"';
-  vars["r"] = params.use_system_headers ? '>' : '"';
+  vars["l"] = use_system_headers ? '<' : '"';
+  vars["r"] = use_system_headers ? '>' : '"';
 
-  auto& s = params.grpc_search_path;
-  if (!s.empty()) {
-    vars["l"] += s;
-    if (s[s.size() - 1] != '/') {
+  if (!search_path.empty()) {
+    vars["l"] += search_path;
+    if (search_path[search_path.size() - 1] != '/') {
       vars["l"] += '/';
     }
   }
@@ -124,18 +123,23 @@
     auto printer = file->CreatePrinter(&output);
     std::map<grpc::string, grpc::string> vars;
 
+    if (!params.additional_header_includes.empty()) {
+      PrintIncludes(printer.get(), params.additional_header_includes, false,
+                    "");
+    }
     static const char* headers_strs[] = {
-        "grpc++/impl/codegen/async_stream.h",
-        "grpc++/impl/codegen/async_unary_call.h",
-        "grpc++/impl/codegen/method_handler_impl.h",
-        "grpc++/impl/codegen/proto_utils.h",
-        "grpc++/impl/codegen/rpc_method.h",
-        "grpc++/impl/codegen/service_type.h",
-        "grpc++/impl/codegen/status.h",
-        "grpc++/impl/codegen/stub_options.h",
-        "grpc++/impl/codegen/sync_stream.h"};
+        "grpcpp/impl/codegen/async_stream.h",
+        "grpcpp/impl/codegen/async_unary_call.h",
+        "grpcpp/impl/codegen/method_handler_impl.h",
+        "grpcpp/impl/codegen/proto_utils.h",
+        "grpcpp/impl/codegen/rpc_method.h",
+        "grpcpp/impl/codegen/service_type.h",
+        "grpcpp/impl/codegen/status.h",
+        "grpcpp/impl/codegen/stub_options.h",
+        "grpcpp/impl/codegen/sync_stream.h"};
     std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
-    PrintIncludes(printer.get(), headers, params);
+    PrintIncludes(printer.get(), headers, params.use_system_headers,
+                  params.grpc_search_path);
     printer->Print(vars, "\n");
     printer->Print(vars, "namespace grpc {\n");
     printer->Print(vars, "class CompletionQueue;\n");
@@ -1144,16 +1148,17 @@
     std::map<grpc::string, grpc::string> vars;
 
     static const char* headers_strs[] = {
-        "grpc++/impl/codegen/async_stream.h",
-        "grpc++/impl/codegen/async_unary_call.h",
-        "grpc++/impl/codegen/channel_interface.h",
-        "grpc++/impl/codegen/client_unary_call.h",
-        "grpc++/impl/codegen/method_handler_impl.h",
-        "grpc++/impl/codegen/rpc_service_method.h",
-        "grpc++/impl/codegen/service_type.h",
-        "grpc++/impl/codegen/sync_stream.h"};
+        "grpcpp/impl/codegen/async_stream.h",
+        "grpcpp/impl/codegen/async_unary_call.h",
+        "grpcpp/impl/codegen/channel_interface.h",
+        "grpcpp/impl/codegen/client_unary_call.h",
+        "grpcpp/impl/codegen/method_handler_impl.h",
+        "grpcpp/impl/codegen/rpc_service_method.h",
+        "grpcpp/impl/codegen/service_type.h",
+        "grpcpp/impl/codegen/sync_stream.h"};
     std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
-    PrintIncludes(printer.get(), headers, params);
+    PrintIncludes(printer.get(), headers, params.use_system_headers,
+                  params.grpc_search_path);
 
     if (!file->package().empty()) {
       std::vector<grpc::string> parts = file->package_parts();
@@ -1566,24 +1571,23 @@
     std::map<grpc::string, grpc::string> vars;
 
     static const char* headers_strs[] = {
-        "grpc++/impl/codegen/async_stream.h",
-        "grpc++/impl/codegen/sync_stream.h",
+        "grpcpp/impl/codegen/async_stream.h",
+        "grpcpp/impl/codegen/sync_stream.h",
     };
     std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
-    PrintIncludes(printer.get(), headers, params);
+    PrintIncludes(printer.get(), headers, params.use_system_headers,
+                  params.grpc_search_path);
 
     std::vector<grpc::string> gmock_header;
     if (params.gmock_search_path.empty()) {
       gmock_header.push_back("gmock/gmock.h");
-      PrintIncludes(printer.get(), gmock_header, params);
+      PrintIncludes(printer.get(), gmock_header, params.use_system_headers,
+                    params.grpc_search_path);
     } else {
       gmock_header.push_back("gmock.h");
-      // Copy a params to generate gmock header.
-      Parameters gmock_params(params);
       // We use local includes when a gmock_search_path is given
-      gmock_params.use_system_headers = false;
-      gmock_params.grpc_search_path = params.gmock_search_path;
-      PrintIncludes(printer.get(), gmock_header, gmock_params);
+      PrintIncludes(printer.get(), gmock_header, false,
+                    params.gmock_search_path);
     }
 
     if (!file->package().empty()) {
diff --git a/src/compiler/cpp_generator.h b/src/compiler/cpp_generator.h
index 300a27c..d88ef75 100644
--- a/src/compiler/cpp_generator.h
+++ b/src/compiler/cpp_generator.h
@@ -54,6 +54,8 @@
   bool generate_mock_code;
   // Google Mock search path, when non-empty, local includes will be used.
   grpc::string gmock_search_path;
+  // *EXPERIMENTAL* Additional include files in grpc.pb.h
+  std::vector<grpc::string> additional_header_includes;
 };
 
 // Return the prologue of the generated header file.
diff --git a/src/compiler/cpp_plugin.cc b/src/compiler/cpp_plugin.cc
index 661282f..c8ab788 100644
--- a/src/compiler/cpp_plugin.cc
+++ b/src/compiler/cpp_plugin.cc
@@ -80,6 +80,9 @@
           }
         } else if (param[0] == "gmock_search_path") {
           generator_parameters.gmock_search_path = param[1];
+        } else if (param[0] == "additional_header_includes") {
+          generator_parameters.additional_header_includes =
+              grpc_generator::tokenize(param[1], ":");
         } else {
           *error = grpc::string("Unknown parameter: ") + *parameter_string;
           return false;
diff --git a/src/compiler/csharp_generator.cc b/src/compiler/csharp_generator.cc
index 7c97056..6e27305 100644
--- a/src/compiler/csharp_generator.cc
+++ b/src/compiler/csharp_generator.cc
@@ -451,8 +451,10 @@
       out->Print(
           "public virtual $response$ $methodname$($request$ request, "
           "grpc::Metadata "
-          "headers = null, DateTime? deadline = null, CancellationToken "
-          "cancellationToken = default(CancellationToken))\n",
+          "headers = null, global::System.DateTime? deadline = null, "
+          "global::System.Threading.CancellationToken "
+          "cancellationToken = "
+          "default(global::System.Threading.CancellationToken))\n",
           "methodname", method->name(), "request",
           GetClassName(method->input_type()), "response",
           GetClassName(method->output_type()));
@@ -492,8 +494,10 @@
     out->Print(
         "public virtual $returntype$ "
         "$methodname$($request_maybe$grpc::Metadata "
-        "headers = null, DateTime? deadline = null, CancellationToken "
-        "cancellationToken = default(CancellationToken))\n",
+        "headers = null, global::System.DateTime? deadline = null, "
+        "global::System.Threading.CancellationToken "
+        "cancellationToken = "
+        "default(global::System.Threading.CancellationToken))\n",
         "methodname", method_name, "request_maybe",
         GetMethodRequestParamMaybe(method), "returntype",
         GetMethodReturnTypeClient(method));
@@ -675,9 +679,6 @@
     out.Print("#pragma warning disable 1591\n");
     out.Print("#region Designer generated code\n");
     out.Print("\n");
-    out.Print("using System;\n");
-    out.Print("using System.Threading;\n");
-    out.Print("using System.Threading.Tasks;\n");
     out.Print("using grpc = global::Grpc.Core;\n");
     out.Print("\n");
 
diff --git a/src/compiler/objective_c_generator.cc b/src/compiler/objective_c_generator.cc
index ab7d869..ffdeb8f 100644
--- a/src/compiler/objective_c_generator.cc
+++ b/src/compiler/objective_c_generator.cc
@@ -212,37 +212,49 @@
   return output;
 }
 
-::grpc::string GetHeader(const ServiceDescriptor* service) {
+::grpc::string GetProtocol(const ServiceDescriptor* service) {
   ::grpc::string output;
-  {
-    // Scope the output stream so it closes and finalizes output to the string.
-    grpc::protobuf::io::StringOutputStream output_stream(&output);
-    Printer printer(&output_stream, '$');
 
-    map< ::grpc::string, ::grpc::string> vars = {
-        {"service_class", ServiceClassName(service)}};
+  // Scope the output stream so it closes and finalizes output to the string.
+  grpc::protobuf::io::StringOutputStream output_stream(&output);
+  Printer printer(&output_stream, '$');
 
-    printer.Print(vars, "@protocol $service_class$ <NSObject>\n\n");
+  map< ::grpc::string, ::grpc::string> vars = {
+      {"service_class", ServiceClassName(service)}};
 
-    for (int i = 0; i < service->method_count(); i++) {
-      PrintMethodDeclarations(&printer, service->method(i));
-    }
-    printer.Print("@end\n\n");
-
-    printer.Print(
-        "/**\n"
-        " * Basic service implementation, over gRPC, that only does\n"
-        " * marshalling and parsing.\n"
-        " */\n");
-    printer.Print(vars,
-                  "@interface $service_class$ :"
-                  " GRPCProtoService<$service_class$>\n");
-    printer.Print(
-        "- (instancetype)initWithHost:(NSString *)host"
-        " NS_DESIGNATED_INITIALIZER;\n");
-    printer.Print("+ (instancetype)serviceWithHost:(NSString *)host;\n");
-    printer.Print("@end\n");
+  printer.Print(vars, "@protocol $service_class$ <NSObject>\n\n");
+  for (int i = 0; i < service->method_count(); i++) {
+    PrintMethodDeclarations(&printer, service->method(i));
   }
+  printer.Print("@end\n\n");
+
+  return output;
+}
+
+::grpc::string GetInterface(const ServiceDescriptor* service) {
+  ::grpc::string output;
+
+  // Scope the output stream so it closes and finalizes output to the string.
+  grpc::protobuf::io::StringOutputStream output_stream(&output);
+  Printer printer(&output_stream, '$');
+
+  map< ::grpc::string, ::grpc::string> vars = {
+      {"service_class", ServiceClassName(service)}};
+
+  printer.Print(vars,
+                "/**\n"
+                " * Basic service implementation, over gRPC, that only does\n"
+                " * marshalling and parsing.\n"
+                " */\n");
+  printer.Print(vars,
+                "@interface $service_class$ :"
+                " GRPCProtoService<$service_class$>\n");
+  printer.Print(
+      "- (instancetype)initWithHost:(NSString *)host"
+      " NS_DESIGNATED_INITIALIZER;\n");
+  printer.Print("+ (instancetype)serviceWithHost:(NSString *)host;\n");
+  printer.Print("@end\n");
+
   return output;
 }
 
@@ -258,26 +270,32 @@
         {"service_class", ServiceClassName(service)},
         {"package", service->file()->package()}};
 
-    printer.Print(vars, "@implementation $service_class$\n\n");
+    printer.Print(vars,
+                  "@implementation $service_class$\n\n"
+                  "// Designated initializer\n"
+                  "- (instancetype)initWithHost:(NSString *)host {\n"
+                  "  self = [super initWithHost:host\n"
+                  "                 packageName:@\"$package$\"\n"
+                  "                 serviceName:@\"$service_name$\"];\n"
+                  "  return self;\n"
+                  "}\n\n");
 
-    printer.Print("// Designated initializer\n");
-    printer.Print("- (instancetype)initWithHost:(NSString *)host {\n");
-    printer.Print(
-        vars,
-        "  return (self = [super initWithHost:host"
-        " packageName:@\"$package$\" serviceName:@\"$service_name$\"]);\n");
-    printer.Print("}\n\n");
     printer.Print(
         "// Override superclass initializer to disallow different"
-        " package and service names.\n");
-    printer.Print("- (instancetype)initWithHost:(NSString *)host\n");
-    printer.Print("                 packageName:(NSString *)packageName\n");
-    printer.Print("                 serviceName:(NSString *)serviceName {\n");
-    printer.Print("  return [self initWithHost:host];\n");
-    printer.Print("}\n\n");
-    printer.Print("+ (instancetype)serviceWithHost:(NSString *)host {\n");
-    printer.Print("  return [[self alloc] initWithHost:host];\n");
-    printer.Print("}\n\n\n");
+        " package and service names.\n"
+        "- (instancetype)initWithHost:(NSString *)host\n"
+        "                 packageName:(NSString *)packageName\n"
+        "                 serviceName:(NSString *)serviceName {\n"
+        "  return [self initWithHost:host];\n"
+        "}\n\n");
+
+    printer.Print(
+        "#pragma mark - Class Methods\n\n"
+        "+ (instancetype)serviceWithHost:(NSString *)host {\n"
+        "  return [[self alloc] initWithHost:host];\n"
+        "}\n\n");
+
+    printer.Print("#pragma mark - Method Implementations\n\n");
 
     for (int i = 0; i < service->method_count(); i++) {
       PrintMethodImplementations(&printer, service->method(i));
diff --git a/src/compiler/objective_c_generator.h b/src/compiler/objective_c_generator.h
index d3aed76..eb1c7ff 100644
--- a/src/compiler/objective_c_generator.h
+++ b/src/compiler/objective_c_generator.h
@@ -31,9 +31,13 @@
 // Returns forward declaration of classes in the generated header file.
 string GetAllMessageClasses(const FileDescriptor* file);
 
-// Returns the content to be included in the "global_scope" insertion point of
-// the generated header file.
-string GetHeader(const ServiceDescriptor* service);
+// Returns the content to be included defining the @protocol segment at the
+// insertion point of the generated implementation file.
+string GetProtocol(const ServiceDescriptor* service);
+
+// Returns the content to be included defining the @interface segment at the
+// insertion point of the generated implementation file.
+string GetInterface(const ServiceDescriptor* service);
 
 // Returns the content to be included in the "global_scope" insertion point of
 // the generated implementation file.
diff --git a/src/compiler/objective_c_generator_helpers.h b/src/compiler/objective_c_generator_helpers.h
index 4004e6a..a284da9 100644
--- a/src/compiler/objective_c_generator_helpers.h
+++ b/src/compiler/objective_c_generator_helpers.h
@@ -40,5 +40,45 @@
   string prefix = file->options().objc_class_prefix();
   return prefix + service->name();
 }
+
+inline ::grpc::string LocalImport(const ::grpc::string& import) {
+  return ::grpc::string("#import \"" + import + "\"\n");
+}
+
+inline ::grpc::string SystemImport(const ::grpc::string& import) {
+  return ::grpc::string("#import <" + import + ">\n");
+}
+
+inline ::grpc::string PreprocConditional(::grpc::string symbol, bool invert) {
+  return invert ? "!defined(" + symbol + ") || !" + symbol
+                : "defined(" + symbol + ") && " + symbol;
+}
+
+inline ::grpc::string PreprocIf(const ::grpc::string& symbol,
+                                const ::grpc::string& if_true) {
+  return ::grpc::string("#if " + PreprocConditional(symbol, false) + "\n" +
+                        if_true + "#endif\n");
+}
+
+inline ::grpc::string PreprocIfNot(const ::grpc::string& symbol,
+                                   const ::grpc::string& if_true) {
+  return ::grpc::string("#if " + PreprocConditional(symbol, true) + "\n" +
+                        if_true + "#endif\n");
+}
+
+inline ::grpc::string PreprocIfElse(const ::grpc::string& symbol,
+                                    const ::grpc::string& if_true,
+                                    const ::grpc::string& if_false) {
+  return ::grpc::string("#if " + PreprocConditional(symbol, false) + "\n" +
+                        if_true + "#else\n" + if_false + "#endif\n");
+}
+
+inline ::grpc::string PreprocIfNotElse(const ::grpc::string& symbol,
+                                       const ::grpc::string& if_true,
+                                       const ::grpc::string& if_false) {
+  return ::grpc::string("#if " + PreprocConditional(symbol, true) + "\n" +
+                        if_true + "#else\n" + if_false + "#endif\n");
+}
+
 }  // namespace grpc_objective_c_generator
 #endif  // GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_HELPERS_H
diff --git a/src/compiler/objective_c_plugin.cc b/src/compiler/objective_c_plugin.cc
index d5d488e..76703d7 100644
--- a/src/compiler/objective_c_plugin.cc
+++ b/src/compiler/objective_c_plugin.cc
@@ -29,12 +29,42 @@
 using ::google::protobuf::compiler::objectivec::
     IsProtobufLibraryBundledProtoFile;
 using ::google::protobuf::compiler::objectivec::ProtobufLibraryFrameworkName;
+using ::grpc_objective_c_generator::LocalImport;
+using ::grpc_objective_c_generator::PreprocIfElse;
+using ::grpc_objective_c_generator::PreprocIfNot;
+using ::grpc_objective_c_generator::SystemImport;
+
+namespace {
+
+inline ::grpc::string ImportProtoHeaders(
+    const grpc::protobuf::FileDescriptor* dep, const char* indent) {
+  ::grpc::string header = grpc_objective_c_generator::MessageHeaderName(dep);
+
+  if (!IsProtobufLibraryBundledProtoFile(dep)) {
+    return indent + LocalImport(header);
+  }
+
+  ::grpc::string base_name = header;
+  grpc_generator::StripPrefix(&base_name, "google/protobuf/");
+  // create the import code snippet
+  ::grpc::string framework_header =
+      ::grpc::string(ProtobufLibraryFrameworkName) + "/" + base_name;
+
+  static const ::grpc::string kFrameworkImportsCondition =
+      "GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS";
+  return PreprocIfElse(kFrameworkImportsCondition,
+                       indent + SystemImport(framework_header),
+                       indent + LocalImport(header));
+}
+
+}  // namespace
 
 class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
  public:
   ObjectiveCGrpcGenerator() {}
   virtual ~ObjectiveCGrpcGenerator() {}
 
+ public:
   virtual bool Generate(const grpc::protobuf::FileDescriptor* file,
                         const ::grpc::string& parameter,
                         grpc::protobuf::compiler::GeneratorContext* context,
@@ -44,97 +74,68 @@
       return true;
     }
 
+    static const ::grpc::string kNonNullBegin = "NS_ASSUME_NONNULL_BEGIN\n";
+    static const ::grpc::string kNonNullEnd = "NS_ASSUME_NONNULL_END\n";
+    static const ::grpc::string kProtocolOnly = "GPB_GRPC_PROTOCOL_ONLY";
+    static const ::grpc::string kForwardDeclare =
+        "GPB_GRPC_FORWARD_DECLARE_MESSAGE_PROTO";
+
     ::grpc::string file_name =
         google::protobuf::compiler::objectivec::FilePath(file);
-    ::grpc::string prefix = file->options().objc_class_prefix();
 
     {
       // Generate .pbrpc.h
 
-      ::grpc::string imports =
-          ::grpc::string("#if !GPB_GRPC_FORWARD_DECLARE_MESSAGE_PROTO\n") +
-          "#import \"" + file_name +
-          ".pbobjc.h\"\n"
-          "#endif\n\n"
-          "#import <ProtoRPC/ProtoService.h>\n"
-          "#import <ProtoRPC/ProtoRPC.h>\n"
-          "#import <RxLibrary/GRXWriteable.h>\n"
-          "#import <RxLibrary/GRXWriter.h>\n";
+      ::grpc::string imports = LocalImport(file_name + ".pbobjc.h");
 
-      ::grpc::string proto_imports;
-      proto_imports += "#if GPB_GRPC_FORWARD_DECLARE_MESSAGE_PROTO\n" +
-                       grpc_objective_c_generator::GetAllMessageClasses(file) +
-                       "#else\n";
+      ::grpc::string system_imports = SystemImport("ProtoRPC/ProtoService.h") +
+                                      SystemImport("ProtoRPC/ProtoRPC.h") +
+                                      SystemImport("RxLibrary/GRXWriteable.h") +
+                                      SystemImport("RxLibrary/GRXWriter.h");
+
+      ::grpc::string forward_declarations = "@class GRPCProtoCall;\n\n";
+
+      ::grpc::string class_declarations =
+          grpc_objective_c_generator::GetAllMessageClasses(file);
+
+      ::grpc::string class_imports;
       for (int i = 0; i < file->dependency_count(); i++) {
-        ::grpc::string header =
-            grpc_objective_c_generator::MessageHeaderName(file->dependency(i));
-        const grpc::protobuf::FileDescriptor* dependency = file->dependency(i);
-        if (IsProtobufLibraryBundledProtoFile(dependency)) {
-          ::grpc::string base_name = header;
-          grpc_generator::StripPrefix(&base_name, "google/protobuf/");
-          // create the import code snippet
-          proto_imports +=
-              "  #if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS\n"
-              "    #import <" +
-              ::grpc::string(ProtobufLibraryFrameworkName) + "/" + base_name +
-              ">\n"
-              "  #else\n"
-              "    #import \"" +
-              header +
-              "\"\n"
-              "  #endif\n";
-        } else {
-          proto_imports += ::grpc::string("  #import \"") + header + "\"\n";
-        }
+        class_imports += ImportProtoHeaders(file->dependency(i), "  ");
       }
-      proto_imports += "#endif\n";
 
-      ::grpc::string declarations;
+      ::grpc::string protocols;
       for (int i = 0; i < file->service_count(); i++) {
         const grpc::protobuf::ServiceDescriptor* service = file->service(i);
-        declarations += grpc_objective_c_generator::GetHeader(service);
+        protocols += grpc_objective_c_generator::GetProtocol(service);
       }
 
-      static const ::grpc::string kNonNullBegin =
-          "\nNS_ASSUME_NONNULL_BEGIN\n\n";
-      static const ::grpc::string kNonNullEnd = "\nNS_ASSUME_NONNULL_END\n";
+      ::grpc::string interfaces;
+      for (int i = 0; i < file->service_count(); i++) {
+        const grpc::protobuf::ServiceDescriptor* service = file->service(i);
+        interfaces += grpc_objective_c_generator::GetInterface(service);
+      }
 
       Write(context, file_name + ".pbrpc.h",
-            imports + '\n' + proto_imports + '\n' + kNonNullBegin +
-                declarations + kNonNullEnd);
+            PreprocIfNot(kForwardDeclare, imports) + "\n" +
+                PreprocIfNot(kProtocolOnly, system_imports) + "\n" +
+                PreprocIfElse(kForwardDeclare, class_declarations,
+                              class_imports) +
+                "\n" + forward_declarations + "\n" + kNonNullBegin + "\n" +
+                protocols + "\n" + PreprocIfNot(kProtocolOnly, interfaces) +
+                "\n" + kNonNullEnd + "\n");
     }
 
     {
       // Generate .pbrpc.m
 
-      ::grpc::string imports = ::grpc::string("#import \"") + file_name +
-                               ".pbrpc.h\"\n"
-                               "#import \"" +
-                               file_name +
-                               ".pbobjc.h\"\n\n"
-                               "#import <ProtoRPC/ProtoRPC.h>\n"
-                               "#import <RxLibrary/GRXWriter+Immediate.h>\n";
+      ::grpc::string imports = LocalImport(file_name + ".pbrpc.h") +
+                               LocalImport(file_name + ".pbobjc.h") +
+                               SystemImport("ProtoRPC/ProtoRPC.h") +
+                               SystemImport("RxLibrary/GRXWriter+Immediate.h");
+
+      ::grpc::string class_imports;
       for (int i = 0; i < file->dependency_count(); i++) {
-        ::grpc::string header =
-            grpc_objective_c_generator::MessageHeaderName(file->dependency(i));
-        const grpc::protobuf::FileDescriptor* dependency = file->dependency(i);
-        if (IsProtobufLibraryBundledProtoFile(dependency)) {
-          ::grpc::string base_name = header;
-          grpc_generator::StripPrefix(&base_name, "google/protobuf/");
-          // create the import code snippet
-          imports +=
-              "#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS\n"
-              "  #import <" +
-              ::grpc::string(ProtobufLibraryFrameworkName) + "/" + base_name +
-              ">\n"
-              "#else\n"
-              "  #import \"" +
-              header +
-              "\"\n"
-              "#endif\n";
-        } else {
-          imports += ::grpc::string("#import \"") + header + "\"\n";
-        }
+        class_imports += ImportProtoHeaders(file->dependency(i), "");
       }
 
       ::grpc::string definitions;
@@ -143,7 +144,9 @@
         definitions += grpc_objective_c_generator::GetSource(service);
       }
 
-      Write(context, file_name + ".pbrpc.m", imports + '\n' + definitions);
+      Write(context, file_name + ".pbrpc.m",
+            PreprocIfNot(kProtocolOnly,
+                         imports + "\n" + class_imports + "\n" + definitions));
     }
 
     return true;
diff --git a/src/compiler/php_generator.cc b/src/compiler/php_generator.cc
index d9705e8..ca084cc 100644
--- a/src/compiler/php_generator.cc
+++ b/src/compiler/php_generator.cc
@@ -18,10 +18,12 @@
 
 #include <map>
 
+#include <google/protobuf/compiler/php/php_generator.h>
 #include "src/compiler/config.h"
 #include "src/compiler/generator_helpers.h"
 #include "src/compiler/php_generator_helpers.h"
 
+using google::protobuf::compiler::php::GeneratedClassName;
 using grpc::protobuf::Descriptor;
 using grpc::protobuf::FileDescriptor;
 using grpc::protobuf::MethodDescriptor;
@@ -55,8 +57,10 @@
                                    const FileDescriptor* file) {
   std::vector<grpc::string> tokens = grpc_generator::tokenize(name, ".");
   std::ostringstream oss;
-  oss << PackageName(file) << "\\"
-      << grpc_generator::CapitalizeFirstLetter(tokens[tokens.size() - 1]);
+  if (PackageName(file) != "") {
+    oss << PackageName(file) << "\\";
+  }
+  oss << grpc_generator::CapitalizeFirstLetter(tokens[tokens.size() - 1]);
   return oss.str();
 }
 
@@ -67,9 +71,9 @@
   vars["service_name"] = method->service()->full_name();
   vars["name"] = method->name();
   vars["input_type_id"] =
-      MessageIdentifierName(input_type->full_name(), input_type->file());
-  vars["output_type_id"] =
-      MessageIdentifierName(output_type->full_name(), output_type->file());
+      MessageIdentifierName(GeneratedClassName(input_type), input_type->file());
+  vars["output_type_id"] = MessageIdentifierName(
+      GeneratedClassName(output_type), output_type->file());
 
   out->Print("/**\n");
   out->Print(GetPHPComments(method, " *").c_str());
diff --git a/src/core/ext/census/grpc_context.cc b/src/core/ext/census/grpc_context.cc
index ffe7c51..599a798 100644
--- a/src/core/ext/census/grpc_context.cc
+++ b/src/core/ext/census/grpc_context.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/census.h>
 #include <grpc/grpc.h>
 #include "src/core/lib/surface/api_trace.h"
@@ -31,5 +33,6 @@
 
 census_context* grpc_census_call_get_context(grpc_call* call) {
   GRPC_API_TRACE("grpc_census_call_get_context(call=%p)", 1, (call));
-  return (census_context*)grpc_call_context_get(call, GRPC_CONTEXT_TRACING);
+  return static_cast<census_context*>(
+      grpc_call_context_get(call, GRPC_CONTEXT_TRACING));
 }
diff --git a/src/core/ext/filters/client_channel/backup_poller.cc b/src/core/ext/filters/client_channel/backup_poller.cc
index 906a72b..3e2faa5 100644
--- a/src/core/ext/filters/client_channel/backup_poller.cc
+++ b/src/core/ext/filters/client_channel/backup_poller.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2017 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/backup_poller.h"
 
 #include <grpc/grpc.h>
@@ -80,7 +82,7 @@
 }
 
 static void done_poller(void* arg, grpc_error* error) {
-  backup_poller_shutdown_unref((backup_poller*)arg);
+  backup_poller_shutdown_unref(static_cast<backup_poller*>(arg));
 }
 
 static void g_poller_unref() {
@@ -102,7 +104,7 @@
 }
 
 static void run_poller(void* arg, grpc_error* error) {
-  backup_poller* p = (backup_poller*)arg;
+  backup_poller* p = static_cast<backup_poller*>(arg);
   if (error != GRPC_ERROR_NONE) {
     if (error != GRPC_ERROR_CANCELLED) {
       GRPC_LOG_IF_ERROR("run_poller", GRPC_ERROR_REF(error));
@@ -125,16 +127,11 @@
                   &p->run_poller_closure);
 }
 
-void grpc_client_channel_start_backup_polling(
-    grpc_pollset_set* interested_parties) {
-  gpr_once_init(&g_once, init_globals);
-  if (g_poll_interval_ms == 0) {
-    return;
-  }
-  gpr_mu_lock(&g_poller_mu);
+static void g_poller_init_locked() {
   if (g_poller == nullptr) {
-    g_poller = (backup_poller*)gpr_zalloc(sizeof(backup_poller));
-    g_poller->pollset = (grpc_pollset*)gpr_zalloc(grpc_pollset_size());
+    g_poller = static_cast<backup_poller*>(gpr_zalloc(sizeof(backup_poller)));
+    g_poller->pollset =
+        static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
     g_poller->shutting_down = false;
     grpc_pollset_init(g_poller->pollset, &g_poller->pollset_mu);
     gpr_ref_init(&g_poller->refs, 0);
@@ -146,7 +143,16 @@
                     grpc_core::ExecCtx::Get()->Now() + g_poll_interval_ms,
                     &g_poller->run_poller_closure);
   }
+}
 
+void grpc_client_channel_start_backup_polling(
+    grpc_pollset_set* interested_parties) {
+  gpr_once_init(&g_once, init_globals);
+  if (g_poll_interval_ms == 0) {
+    return;
+  }
+  gpr_mu_lock(&g_poller_mu);
+  g_poller_init_locked();
   gpr_ref(&g_poller->refs);
   /* Get a reference to g_poller->pollset before releasing g_poller_mu to make
    * TSAN happy. Otherwise, reading from g_poller (i.e g_poller->pollset) after
diff --git a/src/core/ext/filters/client_channel/backup_poller.h b/src/core/ext/filters/client_channel/backup_poller.h
index 551e033..8f132f9 100644
--- a/src/core/ext/filters/client_channel/backup_poller.h
+++ b/src/core/ext/filters/client_channel/backup_poller.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
+ * Copyright 2017 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,9 +19,10 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_BACKUP_POLLER_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_BACKUP_POLLER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 #include "src/core/lib/channel/channel_stack.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
 
 /* Start polling \a interested_parties periodically in the timer thread  */
 void grpc_client_channel_start_backup_polling(
diff --git a/src/core/ext/filters/client_channel/channel_connectivity.cc b/src/core/ext/filters/client_channel/channel_connectivity.cc
index a827aa3..37860e8 100644
--- a/src/core/ext/filters/client_channel/channel_connectivity.cc
+++ b/src/core/ext/filters/client_channel/channel_connectivity.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/surface/channel.h"
 
 #include <inttypes.h>
@@ -89,7 +91,7 @@
 
 static void finished_completion(void* pw, grpc_cq_completion* ignored) {
   bool should_delete = false;
-  state_watcher* w = (state_watcher*)pw;
+  state_watcher* w = static_cast<state_watcher*>(pw);
   gpr_mu_lock(&w->mu);
   switch (w->phase) {
     case WAITING:
@@ -162,11 +164,11 @@
 }
 
 static void watch_complete(void* pw, grpc_error* error) {
-  partly_done((state_watcher*)pw, true, GRPC_ERROR_REF(error));
+  partly_done(static_cast<state_watcher*>(pw), true, GRPC_ERROR_REF(error));
 }
 
 static void timeout_complete(void* pw, grpc_error* error) {
-  partly_done((state_watcher*)pw, false, GRPC_ERROR_REF(error));
+  partly_done(static_cast<state_watcher*>(pw), false, GRPC_ERROR_REF(error));
 }
 
 int grpc_channel_num_external_connectivity_watchers(grpc_channel* channel) {
@@ -182,7 +184,7 @@
 } watcher_timer_init_arg;
 
 static void watcher_timer_init(void* arg, grpc_error* error_ignored) {
-  watcher_timer_init_arg* wa = (watcher_timer_init_arg*)arg;
+  watcher_timer_init_arg* wa = static_cast<watcher_timer_init_arg*>(arg);
 
   grpc_timer_init(&wa->w->alarm, grpc_timespec_to_millis_round_up(wa->deadline),
                   &wa->w->on_timeout);
@@ -201,7 +203,7 @@
   grpc_channel_element* client_channel_elem =
       grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
   grpc_core::ExecCtx exec_ctx;
-  state_watcher* w = (state_watcher*)gpr_malloc(sizeof(*w));
+  state_watcher* w = static_cast<state_watcher*>(gpr_malloc(sizeof(*w)));
 
   GRPC_API_TRACE(
       "grpc_channel_watch_connectivity_state("
@@ -227,8 +229,8 @@
   w->channel = channel;
   w->error = nullptr;
 
-  watcher_timer_init_arg* wa =
-      (watcher_timer_init_arg*)gpr_malloc(sizeof(watcher_timer_init_arg));
+  watcher_timer_init_arg* wa = static_cast<watcher_timer_init_arg*>(
+      gpr_malloc(sizeof(watcher_timer_init_arg)));
   wa->w = w;
   wa->deadline = deadline;
   GRPC_CLOSURE_INIT(&w->watcher_timer_init, watcher_timer_init, wa,
diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc
index 49522ef..67dd3a1 100644
--- a/src/core/ext/filters/client_channel/client_channel.cc
+++ b/src/core/ext/filters/client_channel/client_channel.cc
@@ -21,6 +21,7 @@
 #include "src/core/ext/filters/client_channel/client_channel.h"
 
 #include <inttypes.h>
+#include <limits.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <string.h>
@@ -29,158 +30,78 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/ext/filters/client_channel/backup_poller.h"
 #include "src/core/ext/filters/client_channel/http_connect_handshaker.h"
 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
+#include "src/core/ext/filters/client_channel/method_params.h"
 #include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/ext/filters/client_channel/retry_throttle.h"
 #include "src/core/ext/filters/client_channel/subchannel.h"
 #include "src/core/ext/filters/deadline/deadline_filter.h"
+#include "src/core/lib/backoff/backoff.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/channel/status_util.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/inlined_vector.h"
+#include "src/core/lib/gprpp/manual_constructor.h"
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/iomgr/polling_entity.h"
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/transport/connectivity_state.h"
+#include "src/core/lib/transport/error_utils.h"
 #include "src/core/lib/transport/metadata.h"
 #include "src/core/lib/transport/metadata_batch.h"
 #include "src/core/lib/transport/service_config.h"
 #include "src/core/lib/transport/static_metadata.h"
+#include "src/core/lib/transport/status_metadata.h"
+
+using grpc_core::internal::ClientChannelMethodParams;
 
 /* Client channel implementation */
 
+// By default, we buffer 256 KiB per RPC for retries.
+// TODO(roth): Do we have any data to suggest a better value?
+#define DEFAULT_PER_RPC_RETRY_BUFFER_SIZE (256 << 10)
+
+// This value was picked arbitrarily.  It can be changed if there is
+// any even moderately compelling reason to do so.
+#define RETRY_BACKOFF_JITTER 0.2
+
 grpc_core::TraceFlag grpc_client_channel_trace(false, "client_channel");
 
 /*************************************************************************
- * METHOD-CONFIG TABLE
- */
-
-typedef enum {
-  /* zero so it can be default initialized */
-  WAIT_FOR_READY_UNSET = 0,
-  WAIT_FOR_READY_FALSE,
-  WAIT_FOR_READY_TRUE
-} wait_for_ready_value;
-
-typedef struct {
-  gpr_refcount refs;
-  grpc_millis timeout;
-  wait_for_ready_value wait_for_ready;
-} method_parameters;
-
-static method_parameters* method_parameters_ref(
-    method_parameters* method_params) {
-  gpr_ref(&method_params->refs);
-  return method_params;
-}
-
-static void method_parameters_unref(method_parameters* method_params) {
-  if (gpr_unref(&method_params->refs)) {
-    gpr_free(method_params);
-  }
-}
-
-// Wrappers to pass to grpc_service_config_create_method_config_table().
-static void* method_parameters_ref_wrapper(void* value) {
-  return method_parameters_ref((method_parameters*)value);
-}
-static void method_parameters_unref_wrapper(void* value) {
-  method_parameters_unref((method_parameters*)value);
-}
-
-static bool parse_wait_for_ready(grpc_json* field,
-                                 wait_for_ready_value* wait_for_ready) {
-  if (field->type != GRPC_JSON_TRUE && field->type != GRPC_JSON_FALSE) {
-    return false;
-  }
-  *wait_for_ready = field->type == GRPC_JSON_TRUE ? WAIT_FOR_READY_TRUE
-                                                  : WAIT_FOR_READY_FALSE;
-  return true;
-}
-
-static bool parse_timeout(grpc_json* field, grpc_millis* timeout) {
-  if (field->type != GRPC_JSON_STRING) return false;
-  size_t len = strlen(field->value);
-  if (field->value[len - 1] != 's') return false;
-  char* buf = gpr_strdup(field->value);
-  buf[len - 1] = '\0';  // Remove trailing 's'.
-  char* decimal_point = strchr(buf, '.');
-  int nanos = 0;
-  if (decimal_point != nullptr) {
-    *decimal_point = '\0';
-    nanos = gpr_parse_nonnegative_int(decimal_point + 1);
-    if (nanos == -1) {
-      gpr_free(buf);
-      return false;
-    }
-    int num_digits = (int)strlen(decimal_point + 1);
-    if (num_digits > 9) {  // We don't accept greater precision than nanos.
-      gpr_free(buf);
-      return false;
-    }
-    for (int i = 0; i < (9 - num_digits); ++i) {
-      nanos *= 10;
-    }
-  }
-  int seconds = decimal_point == buf ? 0 : gpr_parse_nonnegative_int(buf);
-  gpr_free(buf);
-  if (seconds == -1) return false;
-  *timeout = seconds * GPR_MS_PER_SEC + nanos / GPR_NS_PER_MS;
-  return true;
-}
-
-static void* method_parameters_create_from_json(const grpc_json* json) {
-  wait_for_ready_value wait_for_ready = WAIT_FOR_READY_UNSET;
-  grpc_millis timeout = 0;
-  for (grpc_json* field = json->child; field != nullptr; field = field->next) {
-    if (field->key == nullptr) continue;
-    if (strcmp(field->key, "waitForReady") == 0) {
-      if (wait_for_ready != WAIT_FOR_READY_UNSET) return nullptr;  // Duplicate.
-      if (!parse_wait_for_ready(field, &wait_for_ready)) return nullptr;
-    } else if (strcmp(field->key, "timeout") == 0) {
-      if (timeout > 0) return nullptr;  // Duplicate.
-      if (!parse_timeout(field, &timeout)) return nullptr;
-    }
-  }
-  method_parameters* value =
-      (method_parameters*)gpr_malloc(sizeof(method_parameters));
-  gpr_ref_init(&value->refs, 1);
-  value->timeout = timeout;
-  value->wait_for_ready = wait_for_ready;
-  return value;
-}
-
-struct external_connectivity_watcher;
-
-/*************************************************************************
  * CHANNEL-WIDE FUNCTIONS
  */
 
+struct external_connectivity_watcher;
+
+typedef grpc_core::SliceHashTable<
+    grpc_core::RefCountedPtr<ClientChannelMethodParams>>
+    MethodParamsTable;
+
 typedef struct client_channel_channel_data {
-  /** resolver for this channel */
-  grpc_resolver* resolver;
-  /** have we started resolving this channel */
+  grpc_core::OrphanablePtr<grpc_core::Resolver> resolver;
   bool started_resolving;
-  /** is deadline checking enabled? */
   bool deadline_checking_enabled;
-  /** client channel factory */
   grpc_client_channel_factory* client_channel_factory;
+  bool enable_retries;
+  size_t per_rpc_retry_buffer_size;
 
   /** combiner protecting all variables below in this data structure */
   grpc_combiner* combiner;
   /** currently active load balancer */
-  grpc_lb_policy* lb_policy;
+  grpc_core::OrphanablePtr<grpc_core::LoadBalancingPolicy> lb_policy;
   /** retry throttle data */
   grpc_server_retry_throttle_data* retry_throttle_data;
   /** maps method names to method_parameters structs */
-  grpc_slice_hash_table* method_params_table;
+  grpc_core::RefCountedPtr<MethodParamsTable> method_params_table;
   /** incoming resolver result - set by resolver.next() */
   grpc_channel_args* resolver_result;
   /** a list of closures that are all waiting for resolver result to come in */
@@ -201,7 +122,7 @@
   gpr_mu external_connectivity_watcher_list_mu;
   struct external_connectivity_watcher* external_connectivity_watcher_list_head;
 
-  /* the following properties are guarded by a mutex since API's require them
+  /* the following properties are guarded by a mutex since APIs require them
      to be instantaneously available */
   gpr_mu info_mu;
   char* info_lb_policy_name;
@@ -213,7 +134,7 @@
   channel_data* chand;
   /** used as an identifier, don't dereference it because the LB policy may be
    * non-existing when the callback is run */
-  grpc_lb_policy* lb_policy;
+  grpc_core::LoadBalancingPolicy* lb_policy;
   grpc_closure closure;
 } reresolution_request_args;
 
@@ -224,11 +145,11 @@
   channel_data* chand;
   grpc_closure on_changed;
   grpc_connectivity_state state;
-  grpc_lb_policy* lb_policy;
+  grpc_core::LoadBalancingPolicy* lb_policy;
 } lb_policy_connectivity_watcher;
 
 static void watch_lb_policy_locked(channel_data* chand,
-                                   grpc_lb_policy* lb_policy,
+                                   grpc_core::LoadBalancingPolicy* lb_policy,
                                    grpc_connectivity_state current_state);
 
 static void set_channel_connectivity_state_locked(channel_data* chand,
@@ -242,15 +163,13 @@
   if (chand->lb_policy != nullptr) {
     if (state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
       /* cancel picks with wait_for_ready=false */
-      grpc_lb_policy_cancel_picks_locked(
-          chand->lb_policy,
+      chand->lb_policy->CancelMatchingPicksLocked(
           /* mask= */ GRPC_INITIAL_METADATA_WAIT_FOR_READY,
           /* check= */ 0, GRPC_ERROR_REF(error));
     } else if (state == GRPC_CHANNEL_SHUTDOWN) {
       /* cancel all picks */
-      grpc_lb_policy_cancel_picks_locked(chand->lb_policy,
-                                         /* mask= */ 0, /* check= */ 0,
-                                         GRPC_ERROR_REF(error));
+      chand->lb_policy->CancelMatchingPicksLocked(/* mask= */ 0, /* check= */ 0,
+                                                  GRPC_ERROR_REF(error));
     }
   }
   if (grpc_client_channel_trace.enabled()) {
@@ -261,9 +180,10 @@
 }
 
 static void on_lb_policy_state_changed_locked(void* arg, grpc_error* error) {
-  lb_policy_connectivity_watcher* w = (lb_policy_connectivity_watcher*)arg;
+  lb_policy_connectivity_watcher* w =
+      static_cast<lb_policy_connectivity_watcher*>(arg);
   /* check if the notification is for the latest policy */
-  if (w->lb_policy == w->chand->lb_policy) {
+  if (w->lb_policy == w->chand->lb_policy.get()) {
     if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG, "chand=%p: lb_policy=%p state changed to %s", w->chand,
               w->lb_policy, grpc_connectivity_state_name(w->state));
@@ -279,18 +199,17 @@
 }
 
 static void watch_lb_policy_locked(channel_data* chand,
-                                   grpc_lb_policy* lb_policy,
+                                   grpc_core::LoadBalancingPolicy* lb_policy,
                                    grpc_connectivity_state current_state) {
   lb_policy_connectivity_watcher* w =
-      (lb_policy_connectivity_watcher*)gpr_malloc(sizeof(*w));
+      static_cast<lb_policy_connectivity_watcher*>(gpr_malloc(sizeof(*w)));
   GRPC_CHANNEL_STACK_REF(chand->owning_stack, "watch_lb_policy");
   w->chand = chand;
   GRPC_CLOSURE_INIT(&w->on_changed, on_lb_policy_state_changed_locked, w,
                     grpc_combiner_scheduler(chand->combiner));
   w->state = current_state;
   w->lb_policy = lb_policy;
-  grpc_lb_policy_notify_on_state_change_locked(lb_policy, &w->state,
-                                               &w->on_changed);
+  lb_policy->NotifyOnStateChangeLocked(&w->state, &w->on_changed);
 }
 
 static void start_resolving_locked(channel_data* chand) {
@@ -300,8 +219,8 @@
   GPR_ASSERT(!chand->started_resolving);
   chand->started_resolving = true;
   GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
-  grpc_resolver_next_locked(chand->resolver, &chand->resolver_result,
-                            &chand->on_resolver_result_changed);
+  chand->resolver->NextLocked(&chand->resolver_result,
+                              &chand->on_resolver_result_changed);
 }
 
 typedef struct {
@@ -309,9 +228,8 @@
   grpc_server_retry_throttle_data* retry_throttle_data;
 } service_config_parsing_state;
 
-static void parse_retry_throttle_params(const grpc_json* field, void* arg) {
-  service_config_parsing_state* parsing_state =
-      (service_config_parsing_state*)arg;
+static void parse_retry_throttle_params(
+    const grpc_json* field, service_config_parsing_state* parsing_state) {
   if (strcmp(field->key, "retryThrottling") == 0) {
     if (parsing_state->retry_throttle_data != nullptr) return;  // Duplicate.
     if (field->type != GRPC_JSON_OBJECT) return;
@@ -335,7 +253,7 @@
         uint32_t decimal_value = 0;
         const char* decimal_point = strchr(sub_field->value, '.');
         if (decimal_point != nullptr) {
-          whole_len = (size_t)(decimal_point - sub_field->value);
+          whole_len = static_cast<size_t>(decimal_point - sub_field->value);
           multiplier = 1000;
           size_t decimal_len = strlen(decimal_point + 1);
           if (decimal_len > 3) decimal_len = 3;
@@ -354,7 +272,8 @@
                                        &whole_value)) {
           return;
         }
-        milli_token_ratio = (int)((whole_value * multiplier) + decimal_value);
+        milli_token_ratio =
+            static_cast<int>((whole_value * multiplier) + decimal_value);
         if (milli_token_ratio <= 0) return;
       }
     }
@@ -365,11 +284,12 @@
 }
 
 static void request_reresolution_locked(void* arg, grpc_error* error) {
-  reresolution_request_args* args = (reresolution_request_args*)arg;
+  reresolution_request_args* args =
+      static_cast<reresolution_request_args*>(arg);
   channel_data* chand = args->chand;
   // If this invocation is for a stale LB policy, treat it as an LB shutdown
   // signal.
-  if (args->lb_policy != chand->lb_policy || error != GRPC_ERROR_NONE ||
+  if (args->lb_policy != chand->lb_policy.get() || error != GRPC_ERROR_NONE ||
       chand->resolver == nullptr) {
     GRPC_CHANNEL_STACK_UNREF(chand->owning_stack, "re-resolution");
     gpr_free(args);
@@ -378,42 +298,44 @@
   if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_DEBUG, "chand=%p: started name re-resolving", chand);
   }
-  grpc_resolver_channel_saw_error_locked(chand->resolver);
+  chand->resolver->RequestReresolutionLocked();
   // Give back the closure to the LB policy.
-  grpc_lb_policy_set_reresolve_closure_locked(chand->lb_policy, &args->closure);
+  chand->lb_policy->SetReresolutionClosureLocked(&args->closure);
 }
 
+// TODO(roth): The logic in this function is very hard to follow.  We
+// should refactor this so that it's easier to understand, perhaps as
+// part of changing the resolver API to more clearly differentiate
+// between transient failures and shutdown.
 static void on_resolver_result_changed_locked(void* arg, grpc_error* error) {
-  channel_data* chand = (channel_data*)arg;
+  channel_data* chand = static_cast<channel_data*>(arg);
   if (grpc_client_channel_trace.enabled()) {
-    gpr_log(GPR_DEBUG, "chand=%p: got resolver result: error=%s", chand,
-            grpc_error_string(error));
+    gpr_log(GPR_DEBUG,
+            "chand=%p: got resolver result: resolver_result=%p error=%s", chand,
+            chand->resolver_result, grpc_error_string(error));
   }
-  // Extract the following fields from the resolver result, if non-NULL.
+  // Extract the following fields from the resolver result, if non-nullptr.
   bool lb_policy_updated = false;
+  bool lb_policy_created = false;
   char* lb_policy_name_dup = nullptr;
   bool lb_policy_name_changed = false;
-  grpc_lb_policy* new_lb_policy = nullptr;
+  grpc_core::OrphanablePtr<grpc_core::LoadBalancingPolicy> new_lb_policy;
   char* service_config_json = nullptr;
   grpc_server_retry_throttle_data* retry_throttle_data = nullptr;
-  grpc_slice_hash_table* method_params_table = nullptr;
+  grpc_core::RefCountedPtr<MethodParamsTable> method_params_table;
   if (chand->resolver_result != nullptr) {
     if (chand->resolver != nullptr) {
       // Find LB policy name.
-      const char* lb_policy_name = nullptr;
       const grpc_arg* channel_arg = grpc_channel_args_find(
           chand->resolver_result, GRPC_ARG_LB_POLICY_NAME);
-      if (channel_arg != nullptr) {
-        GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
-        lb_policy_name = channel_arg->value.string;
-      }
+      const char* lb_policy_name = grpc_channel_arg_get_string(channel_arg);
       // Special case: If at least one balancer address is present, we use
       // the grpclb policy, regardless of what the resolver actually specified.
       channel_arg =
           grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_ADDRESSES);
       if (channel_arg != nullptr && channel_arg->type == GRPC_ARG_POINTER) {
         grpc_lb_addresses* addresses =
-            (grpc_lb_addresses*)channel_arg->value.pointer.p;
+            static_cast<grpc_lb_addresses*>(channel_arg->value.pointer.p);
         bool found_balancer_address = false;
         for (size_t i = 0; i < addresses->num_addresses; ++i) {
           if (addresses->addresses[i].is_balancer) {
@@ -435,10 +357,6 @@
       // Use pick_first if nothing was specified and we didn't select grpclb
       // above.
       if (lb_policy_name == nullptr) lb_policy_name = "pick_first";
-      grpc_lb_policy_args lb_policy_args;
-      lb_policy_args.args = chand->resolver_result;
-      lb_policy_args.client_channel_factory = chand->client_channel_factory;
-      lb_policy_args.combiner = chand->combiner;
       // Check to see if we're already using the right LB policy.
       // Note: It's safe to use chand->info_lb_policy_name here without
       // taking a lock on chand->info_mu, because this function is the
@@ -450,61 +368,66 @@
       if (chand->lb_policy != nullptr && !lb_policy_name_changed) {
         // Continue using the same LB policy.  Update with new addresses.
         lb_policy_updated = true;
-        grpc_lb_policy_update_locked(chand->lb_policy, &lb_policy_args);
+        chand->lb_policy->UpdateLocked(*chand->resolver_result);
       } else {
         // Instantiate new LB policy.
-        new_lb_policy = grpc_lb_policy_create(lb_policy_name, &lb_policy_args);
+        grpc_core::LoadBalancingPolicy::Args lb_policy_args;
+        lb_policy_args.combiner = chand->combiner;
+        lb_policy_args.client_channel_factory = chand->client_channel_factory;
+        lb_policy_args.args = chand->resolver_result;
+        new_lb_policy =
+            grpc_core::LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy(
+                lb_policy_name, lb_policy_args);
         if (new_lb_policy == nullptr) {
           gpr_log(GPR_ERROR, "could not create LB policy \"%s\"",
                   lb_policy_name);
         } else {
+          lb_policy_created = true;
           reresolution_request_args* args =
-              (reresolution_request_args*)gpr_zalloc(sizeof(*args));
+              static_cast<reresolution_request_args*>(
+                  gpr_zalloc(sizeof(*args)));
           args->chand = chand;
-          args->lb_policy = new_lb_policy;
+          args->lb_policy = new_lb_policy.get();
           GRPC_CLOSURE_INIT(&args->closure, request_reresolution_locked, args,
                             grpc_combiner_scheduler(chand->combiner));
           GRPC_CHANNEL_STACK_REF(chand->owning_stack, "re-resolution");
-          grpc_lb_policy_set_reresolve_closure_locked(new_lb_policy,
-                                                      &args->closure);
-        }
-      }
-      // Find service config.
-      channel_arg = grpc_channel_args_find(chand->resolver_result,
-                                           GRPC_ARG_SERVICE_CONFIG);
-      if (channel_arg != nullptr) {
-        GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
-        service_config_json = gpr_strdup(channel_arg->value.string);
-        grpc_service_config* service_config =
-            grpc_service_config_create(service_config_json);
-        if (service_config != nullptr) {
-          channel_arg = grpc_channel_args_find(chand->resolver_result,
-                                               GRPC_ARG_SERVER_URI);
-          GPR_ASSERT(channel_arg != nullptr);
-          GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
-          grpc_uri* uri = grpc_uri_parse(channel_arg->value.string, true);
-          GPR_ASSERT(uri->path[0] != '\0');
-          service_config_parsing_state parsing_state;
-          memset(&parsing_state, 0, sizeof(parsing_state));
-          parsing_state.server_name =
-              uri->path[0] == '/' ? uri->path + 1 : uri->path;
-          grpc_service_config_parse_global_params(
-              service_config, parse_retry_throttle_params, &parsing_state);
-          grpc_uri_destroy(uri);
-          retry_throttle_data = parsing_state.retry_throttle_data;
-          method_params_table = grpc_service_config_create_method_config_table(
-              service_config, method_parameters_create_from_json,
-              method_parameters_ref_wrapper, method_parameters_unref_wrapper);
-          grpc_service_config_destroy(service_config);
+          new_lb_policy->SetReresolutionClosureLocked(&args->closure);
         }
       }
       // Before we clean up, save a copy of lb_policy_name, since it might
       // be pointing to data inside chand->resolver_result.
       // The copy will be saved in chand->lb_policy_name below.
       lb_policy_name_dup = gpr_strdup(lb_policy_name);
+      // Find service config.
+      channel_arg = grpc_channel_args_find(chand->resolver_result,
+                                           GRPC_ARG_SERVICE_CONFIG);
+      service_config_json =
+          gpr_strdup(grpc_channel_arg_get_string(channel_arg));
+      if (service_config_json != nullptr) {
+        grpc_core::UniquePtr<grpc_core::ServiceConfig> service_config =
+            grpc_core::ServiceConfig::Create(service_config_json);
+        if (service_config != nullptr) {
+          if (chand->enable_retries) {
+            channel_arg = grpc_channel_args_find(chand->resolver_result,
+                                                 GRPC_ARG_SERVER_URI);
+            const char* server_uri = grpc_channel_arg_get_string(channel_arg);
+            GPR_ASSERT(server_uri != nullptr);
+            grpc_uri* uri = grpc_uri_parse(server_uri, true);
+            GPR_ASSERT(uri->path[0] != '\0');
+            service_config_parsing_state parsing_state;
+            memset(&parsing_state, 0, sizeof(parsing_state));
+            parsing_state.server_name =
+                uri->path[0] == '/' ? uri->path + 1 : uri->path;
+            service_config->ParseGlobalParams(parse_retry_throttle_params,
+                                              &parsing_state);
+            grpc_uri_destroy(uri);
+            retry_throttle_data = parsing_state.retry_throttle_data;
+          }
+          method_params_table = service_config->CreateMethodConfigTable(
+              ClientChannelMethodParams::CreateFromJson);
+        }
+      }
     }
-    grpc_channel_args_destroy(chand->resolver_result);
-    chand->resolver_result = nullptr;
   }
   if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_DEBUG,
@@ -514,7 +437,7 @@
             lb_policy_name_changed ? " (changed)" : "", service_config_json);
   }
   // Now swap out fields in chand.  Note that the new values may still
-  // be NULL if (e.g.) the resolver failed to return results or the
+  // be nullptr if (e.g.) the resolver failed to return results or the
   // results did not contain the necessary data.
   //
   // First, swap out the data used by cc_get_channel_info().
@@ -534,29 +457,26 @@
   }
   chand->retry_throttle_data = retry_throttle_data;
   // Swap out the method params table.
-  if (chand->method_params_table != nullptr) {
-    grpc_slice_hash_table_unref(chand->method_params_table);
-  }
-  chand->method_params_table = method_params_table;
+  chand->method_params_table = std::move(method_params_table);
   // If we have a new LB policy or are shutting down (in which case
-  // new_lb_policy will be NULL), swap out the LB policy, unreffing the old one
-  // and removing its fds from chand->interested_parties. Note that we do NOT do
-  // this if either (a) we updated the existing LB policy above or (b) we failed
-  // to create the new LB policy (in which case we want to continue using the
-  // most recent one we had).
+  // new_lb_policy will be nullptr), swap out the LB policy, unreffing the
+  // old one and removing its fds from chand->interested_parties.
+  // Note that we do NOT do this if either (a) we updated the existing
+  // LB policy above or (b) we failed to create the new LB policy (in
+  // which case we want to continue using the most recent one we had).
   if (new_lb_policy != nullptr || error != GRPC_ERROR_NONE ||
       chand->resolver == nullptr) {
     if (chand->lb_policy != nullptr) {
       if (grpc_client_channel_trace.enabled()) {
         gpr_log(GPR_DEBUG, "chand=%p: unreffing lb_policy=%p", chand,
-                chand->lb_policy);
+                chand->lb_policy.get());
       }
-      grpc_pollset_set_del_pollset_set(chand->lb_policy->interested_parties,
+      grpc_pollset_set_del_pollset_set(chand->lb_policy->interested_parties(),
                                        chand->interested_parties);
-      grpc_lb_policy_shutdown_locked(chand->lb_policy, new_lb_policy);
-      GRPC_LB_POLICY_UNREF(chand->lb_policy, "channel");
+      chand->lb_policy->HandOffPendingPicksLocked(new_lb_policy.get());
+      chand->lb_policy.reset();
     }
-    chand->lb_policy = new_lb_policy;
+    chand->lb_policy = std::move(new_lb_policy);
   }
   // Now that we've swapped out the relevant fields of chand, check for
   // error or shutdown.
@@ -568,55 +488,59 @@
       if (grpc_client_channel_trace.enabled()) {
         gpr_log(GPR_DEBUG, "chand=%p: shutting down resolver", chand);
       }
-      grpc_resolver_shutdown_locked(chand->resolver);
-      GRPC_RESOLVER_UNREF(chand->resolver, "channel");
-      chand->resolver = nullptr;
+      chand->resolver.reset();
     }
     set_channel_connectivity_state_locked(
         chand, GRPC_CHANNEL_SHUTDOWN,
         GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
             "Got resolver result after disconnection", &error, 1),
         "resolver_gone");
-    GRPC_CHANNEL_STACK_UNREF(chand->owning_stack, "resolver");
     grpc_closure_list_fail_all(&chand->waiting_for_resolver_result_closures,
                                GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                                    "Channel disconnected", &error, 1));
     GRPC_CLOSURE_LIST_SCHED(&chand->waiting_for_resolver_result_closures);
+    GRPC_CHANNEL_STACK_UNREF(chand->owning_stack, "resolver");
+    grpc_channel_args_destroy(chand->resolver_result);
+    chand->resolver_result = nullptr;
   } else {  // Not shutting down.
     grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
     grpc_error* state_error =
         GRPC_ERROR_CREATE_FROM_STATIC_STRING("No load balancing policy");
-    if (new_lb_policy != nullptr) {
+    if (lb_policy_created) {
       if (grpc_client_channel_trace.enabled()) {
         gpr_log(GPR_DEBUG, "chand=%p: initializing new LB policy", chand);
       }
       GRPC_ERROR_UNREF(state_error);
-      state =
-          grpc_lb_policy_check_connectivity_locked(new_lb_policy, &state_error);
-      grpc_pollset_set_add_pollset_set(new_lb_policy->interested_parties,
+      state = chand->lb_policy->CheckConnectivityLocked(&state_error);
+      grpc_pollset_set_add_pollset_set(chand->lb_policy->interested_parties(),
                                        chand->interested_parties);
       GRPC_CLOSURE_LIST_SCHED(&chand->waiting_for_resolver_result_closures);
       if (chand->exit_idle_when_lb_policy_arrives) {
-        grpc_lb_policy_exit_idle_locked(new_lb_policy);
+        chand->lb_policy->ExitIdleLocked();
         chand->exit_idle_when_lb_policy_arrives = false;
       }
-      watch_lb_policy_locked(chand, new_lb_policy, state);
+      watch_lb_policy_locked(chand, chand->lb_policy.get(), state);
+    } else if (chand->resolver_result == nullptr) {
+      // Transient failure.
+      GRPC_CLOSURE_LIST_SCHED(&chand->waiting_for_resolver_result_closures);
     }
     if (!lb_policy_updated) {
       set_channel_connectivity_state_locked(
           chand, state, GRPC_ERROR_REF(state_error), "new_lb+resolver");
     }
-    grpc_resolver_next_locked(chand->resolver, &chand->resolver_result,
-                              &chand->on_resolver_result_changed);
+    grpc_channel_args_destroy(chand->resolver_result);
+    chand->resolver_result = nullptr;
+    chand->resolver->NextLocked(&chand->resolver_result,
+                                &chand->on_resolver_result_changed);
     GRPC_ERROR_UNREF(state_error);
   }
 }
 
 static void start_transport_op_locked(void* arg, grpc_error* error_ignored) {
-  grpc_transport_op* op = (grpc_transport_op*)arg;
+  grpc_transport_op* op = static_cast<grpc_transport_op*>(arg);
   grpc_channel_element* elem =
-      (grpc_channel_element*)op->handler_private.extra_arg;
-  channel_data* chand = (channel_data*)elem->channel_data;
+      static_cast<grpc_channel_element*>(op->handler_private.extra_arg);
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
 
   if (op->on_connectivity_state_change != nullptr) {
     grpc_connectivity_state_notify_on_state_change(
@@ -635,8 +559,8 @@
           op->send_ping.on_ack,
           GRPC_ERROR_CREATE_FROM_STATIC_STRING("Ping with no load balancing"));
     } else {
-      grpc_lb_policy_ping_one_locked(
-          chand->lb_policy, op->send_ping.on_initiate, op->send_ping.on_ack);
+      chand->lb_policy->PingOneLocked(op->send_ping.on_initiate,
+                                      op->send_ping.on_ack);
       op->bind_pollset = nullptr;
     }
     op->send_ping.on_initiate = nullptr;
@@ -648,20 +572,16 @@
       set_channel_connectivity_state_locked(
           chand, GRPC_CHANNEL_SHUTDOWN,
           GRPC_ERROR_REF(op->disconnect_with_error), "disconnect");
-      grpc_resolver_shutdown_locked(chand->resolver);
-      GRPC_RESOLVER_UNREF(chand->resolver, "channel");
-      chand->resolver = nullptr;
+      chand->resolver.reset();
       if (!chand->started_resolving) {
         grpc_closure_list_fail_all(&chand->waiting_for_resolver_result_closures,
                                    GRPC_ERROR_REF(op->disconnect_with_error));
         GRPC_CLOSURE_LIST_SCHED(&chand->waiting_for_resolver_result_closures);
       }
       if (chand->lb_policy != nullptr) {
-        grpc_pollset_set_del_pollset_set(chand->lb_policy->interested_parties,
+        grpc_pollset_set_del_pollset_set(chand->lb_policy->interested_parties(),
                                          chand->interested_parties);
-        grpc_lb_policy_shutdown_locked(chand->lb_policy, nullptr);
-        GRPC_LB_POLICY_UNREF(chand->lb_policy, "channel");
-        chand->lb_policy = nullptr;
+        chand->lb_policy.reset();
       }
     }
     GRPC_ERROR_UNREF(op->disconnect_with_error);
@@ -673,7 +593,7 @@
 
 static void cc_start_transport_op(grpc_channel_element* elem,
                                   grpc_transport_op* op) {
-  channel_data* chand = (channel_data*)elem->channel_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
 
   GPR_ASSERT(op->set_accept_stream == false);
   if (op->bind_pollset != nullptr) {
@@ -690,7 +610,7 @@
 
 static void cc_get_channel_info(grpc_channel_element* elem,
                                 const grpc_channel_info* info) {
-  channel_data* chand = (channel_data*)elem->channel_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   gpr_mu_lock(&chand->info_mu);
   if (info->lb_policy_name != nullptr) {
     *info->lb_policy_name = chand->info_lb_policy_name == nullptr
@@ -709,7 +629,7 @@
 /* Constructor for channel_data */
 static grpc_error* cc_init_channel_elem(grpc_channel_element* elem,
                                         grpc_channel_element_args* args) {
-  channel_data* chand = (channel_data*)elem->channel_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   GPR_ASSERT(args->is_last);
   GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
   // Initialize data members.
@@ -729,9 +649,17 @@
   grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE,
                                "client_channel");
   grpc_client_channel_start_backup_polling(chand->interested_parties);
+  // Record max per-RPC retry buffer size.
+  const grpc_arg* arg = grpc_channel_args_find(
+      args->channel_args, GRPC_ARG_PER_RPC_RETRY_BUFFER_SIZE);
+  chand->per_rpc_retry_buffer_size = (size_t)grpc_channel_arg_get_integer(
+      arg, {DEFAULT_PER_RPC_RETRY_BUFFER_SIZE, 0, INT_MAX});
+  // Record enable_retries.
+  arg = grpc_channel_args_find(args->channel_args, GRPC_ARG_ENABLE_RETRIES);
+  chand->enable_retries = grpc_channel_arg_get_bool(arg, true);
   // Record client channel factory.
-  const grpc_arg* arg = grpc_channel_args_find(args->channel_args,
-                                               GRPC_ARG_CLIENT_CHANNEL_FACTORY);
+  arg = grpc_channel_args_find(args->channel_args,
+                               GRPC_ARG_CLIENT_CHANNEL_FACTORY);
   if (arg == nullptr) {
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "Missing client channel factory in args for client channel filter");
@@ -741,9 +669,9 @@
         "client channel factory arg must be a pointer");
   }
   grpc_client_channel_factory_ref(
-      (grpc_client_channel_factory*)arg->value.pointer.p);
+      static_cast<grpc_client_channel_factory*>(arg->value.pointer.p));
   chand->client_channel_factory =
-      (grpc_client_channel_factory*)arg->value.pointer.p;
+      static_cast<grpc_client_channel_factory*>(arg->value.pointer.p);
   // Get server name to resolve, using proxy mapper if needed.
   arg = grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVER_URI);
   if (arg == nullptr) {
@@ -759,7 +687,7 @@
   grpc_proxy_mappers_map_name(arg->value.string, args->channel_args,
                               &proxy_name, &new_args);
   // Instantiate resolver.
-  chand->resolver = grpc_resolver_create(
+  chand->resolver = grpc_core::ResolverRegistry::CreateResolver(
       proxy_name != nullptr ? proxy_name : arg->value.string,
       new_args != nullptr ? new_args : args->channel_args,
       chand->interested_parties, chand->combiner);
@@ -774,17 +702,16 @@
 }
 
 static void shutdown_resolver_locked(void* arg, grpc_error* error) {
-  grpc_resolver* resolver = (grpc_resolver*)arg;
-  grpc_resolver_shutdown_locked(resolver);
-  GRPC_RESOLVER_UNREF(resolver, "channel");
+  grpc_core::Resolver* resolver = static_cast<grpc_core::Resolver*>(arg);
+  resolver->Orphan();
 }
 
 /* Destructor for channel_data */
 static void cc_destroy_channel_elem(grpc_channel_element* elem) {
-  channel_data* chand = (channel_data*)elem->channel_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   if (chand->resolver != nullptr) {
     GRPC_CLOSURE_SCHED(
-        GRPC_CLOSURE_CREATE(shutdown_resolver_locked, chand->resolver,
+        GRPC_CLOSURE_CREATE(shutdown_resolver_locked, chand->resolver.release(),
                             grpc_combiner_scheduler(chand->combiner)),
         GRPC_ERROR_NONE);
   }
@@ -792,10 +719,9 @@
     grpc_client_channel_factory_unref(chand->client_channel_factory);
   }
   if (chand->lb_policy != nullptr) {
-    grpc_pollset_set_del_pollset_set(chand->lb_policy->interested_parties,
+    grpc_pollset_set_del_pollset_set(chand->lb_policy->interested_parties(),
                                      chand->interested_parties);
-    grpc_lb_policy_shutdown_locked(chand->lb_policy, nullptr);
-    GRPC_LB_POLICY_UNREF(chand->lb_policy, "channel");
+    chand->lb_policy.reset();
   }
   gpr_free(chand->info_lb_policy_name);
   gpr_free(chand->info_service_config_json);
@@ -803,7 +729,7 @@
     grpc_server_retry_throttle_data_unref(chand->retry_throttle_data);
   }
   if (chand->method_params_table != nullptr) {
-    grpc_slice_hash_table_unref(chand->method_params_table);
+    chand->method_params_table.reset();
   }
   grpc_client_channel_stop_backup_polling(chand->interested_parties);
   grpc_connectivity_state_destroy(&chand->state_tracker);
@@ -818,15 +744,123 @@
  */
 
 // Max number of batches that can be pending on a call at any given
-// time.  This includes:
+// time.  This includes one batch for each of the following ops:
 //   recv_initial_metadata
 //   send_initial_metadata
 //   recv_message
 //   send_message
 //   recv_trailing_metadata
 //   send_trailing_metadata
-// We also add room for a single cancel_stream batch.
-#define MAX_WAITING_BATCHES 7
+#define MAX_PENDING_BATCHES 6
+
+// Retry support:
+//
+// In order to support retries, we act as a proxy for stream op batches.
+// When we get a batch from the surface, we add it to our list of pending
+// batches, and we then use those batches to construct separate "child"
+// batches to be started on the subchannel call.  When the child batches
+// return, we then decide which pending batches have been completed and
+// schedule their callbacks accordingly.  If a subchannel call fails and
+// we want to retry it, we do a new pick and start again, constructing
+// new "child" batches for the new subchannel call.
+//
+// Note that retries are committed when receiving data from the server
+// (except for Trailers-Only responses).  However, there may be many
+// send ops started before receiving any data, so we may have already
+// completed some number of send ops (and returned the completions up to
+// the surface) by the time we realize that we need to retry.  To deal
+// with this, we cache data for send ops, so that we can replay them on a
+// different subchannel call even after we have completed the original
+// batches.
+//
+// There are two sets of data to maintain:
+// - In call_data (in the parent channel), we maintain a list of pending
+//   ops and cached data for send ops.
+// - In the subchannel call, we maintain state to indicate what ops have
+//   already been sent down to that call.
+//
+// When constructing the "child" batches, we compare those two sets of
+// data to see which batches need to be sent to the subchannel call.
+
+// TODO(roth): In subsequent PRs:
+// - add support for transparent retries (including initial metadata)
+// - figure out how to record stats in census for retries
+//   (census filter is on top of this one)
+// - add census stats for retries
+
+// State used for starting a retryable batch on a subchannel call.
+// This provides its own grpc_transport_stream_op_batch and other data
+// structures needed to populate the ops in the batch.
+// We allocate one struct on the arena for each attempt at starting a
+// batch on a given subchannel call.
+typedef struct {
+  gpr_refcount refs;
+  grpc_call_element* elem;
+  grpc_subchannel_call* subchannel_call;  // Holds a ref.
+  // The batch to use in the subchannel call.
+  // Its payload field points to subchannel_call_retry_state.batch_payload.
+  grpc_transport_stream_op_batch batch;
+  // For send_initial_metadata.
+  // Note that we need to make a copy of the initial metadata for each
+  // subchannel call instead of just referring to the copy in call_data,
+  // because filters in the subchannel stack will probably add entries,
+  // so we need to start in a pristine state for each attempt of the call.
+  grpc_linked_mdelem* send_initial_metadata_storage;
+  grpc_metadata_batch send_initial_metadata;
+  // For send_message.
+  grpc_core::ManualConstructor<grpc_core::ByteStreamCache::CachingByteStream>
+      send_message;
+  // For send_trailing_metadata.
+  grpc_linked_mdelem* send_trailing_metadata_storage;
+  grpc_metadata_batch send_trailing_metadata;
+  // For intercepting recv_initial_metadata.
+  grpc_metadata_batch recv_initial_metadata;
+  grpc_closure recv_initial_metadata_ready;
+  bool trailing_metadata_available;
+  // For intercepting recv_message.
+  grpc_closure recv_message_ready;
+  grpc_core::OrphanablePtr<grpc_core::ByteStream> recv_message;
+  // For intercepting recv_trailing_metadata.
+  grpc_metadata_batch recv_trailing_metadata;
+  grpc_transport_stream_stats collect_stats;
+  // For intercepting on_complete.
+  grpc_closure on_complete;
+} subchannel_batch_data;
+
+// Retry state associated with a subchannel call.
+// Stored in the parent_data of the subchannel call object.
+typedef struct {
+  // subchannel_batch_data.batch.payload points to this.
+  grpc_transport_stream_op_batch_payload batch_payload;
+  // These fields indicate which ops have been started and completed on
+  // this subchannel call.
+  size_t started_send_message_count;
+  size_t completed_send_message_count;
+  size_t started_recv_message_count;
+  size_t completed_recv_message_count;
+  bool started_send_initial_metadata : 1;
+  bool completed_send_initial_metadata : 1;
+  bool started_send_trailing_metadata : 1;
+  bool completed_send_trailing_metadata : 1;
+  bool started_recv_initial_metadata : 1;
+  bool completed_recv_initial_metadata : 1;
+  bool started_recv_trailing_metadata : 1;
+  bool completed_recv_trailing_metadata : 1;
+  // State for callback processing.
+  bool retry_dispatched : 1;
+  bool recv_initial_metadata_ready_deferred : 1;
+  bool recv_message_ready_deferred : 1;
+  grpc_error* recv_initial_metadata_error;
+  grpc_error* recv_message_error;
+} subchannel_call_retry_state;
+
+// Pending batches stored in call data.
+typedef struct {
+  // The pending batch.  If nullptr, this slot is empty.
+  grpc_transport_stream_op_batch* batch;
+  // Indicates whether payload for send ops has been cached in call data.
+  bool send_ops_cached;
+} pending_batch;
 
 /** Call data.  Holds a pointer to grpc_subchannel_call and the
     associated machinery to create such a pointer.
@@ -850,159 +884,1593 @@
   grpc_call_combiner* call_combiner;
 
   grpc_server_retry_throttle_data* retry_throttle_data;
-  method_parameters* method_params;
+  grpc_core::RefCountedPtr<ClientChannelMethodParams> method_params;
 
   grpc_subchannel_call* subchannel_call;
-  grpc_error* error;
 
-  grpc_lb_policy_pick_state pick;
-  grpc_closure lb_pick_closure;
-  grpc_closure lb_pick_cancel_closure;
+  // Set when we get a cancel_stream op.
+  grpc_error* cancel_error;
+
+  grpc_core::LoadBalancingPolicy::PickState pick;
+  grpc_closure pick_closure;
+  grpc_closure pick_cancel_closure;
 
   grpc_polling_entity* pollent;
 
-  grpc_transport_stream_op_batch* waiting_for_pick_batches[MAX_WAITING_BATCHES];
-  size_t waiting_for_pick_batches_count;
-  grpc_closure handle_pending_batch_in_call_combiner[MAX_WAITING_BATCHES];
+  // Batches are added to this list when received from above.
+  // They are removed when we are done handling the batch (i.e., when
+  // either we have invoked all of the batch's callbacks or we have
+  // passed the batch down to the subchannel call and are not
+  // intercepting any of its callbacks).
+  pending_batch pending_batches[MAX_PENDING_BATCHES];
+  bool pending_send_initial_metadata : 1;
+  bool pending_send_message : 1;
+  bool pending_send_trailing_metadata : 1;
 
-  grpc_transport_stream_op_batch* initial_metadata_batch;
+  // Retry state.
+  bool enable_retries : 1;
+  bool retry_committed : 1;
+  bool last_attempt_got_server_pushback : 1;
+  int num_attempts_completed;
+  size_t bytes_buffered_for_retry;
+  grpc_core::ManualConstructor<grpc_core::BackOff> retry_backoff;
+  grpc_timer retry_timer;
 
-  grpc_closure on_complete;
-  grpc_closure* original_on_complete;
+  // Cached data for retrying send ops.
+  // send_initial_metadata
+  bool seen_send_initial_metadata;
+  grpc_linked_mdelem* send_initial_metadata_storage;
+  grpc_metadata_batch send_initial_metadata;
+  uint32_t send_initial_metadata_flags;
+  gpr_atm* peer_string;
+  // send_message
+  // When we get a send_message op, we replace the original byte stream
+  // with a CachingByteStream that caches the slices to a local buffer for
+  // use in retries.
+  // Note: We inline the cache for the first 3 send_message ops and use
+  // dynamic allocation after that.  This number was essentially picked
+  // at random; it could be changed in the future to tune performance.
+  grpc_core::InlinedVector<grpc_core::ByteStreamCache*, 3> send_messages;
+  // send_trailing_metadata
+  bool seen_send_trailing_metadata;
+  grpc_linked_mdelem* send_trailing_metadata_storage;
+  grpc_metadata_batch send_trailing_metadata;
 } call_data;
 
-grpc_subchannel_call* grpc_client_channel_get_subchannel_call(
-    grpc_call_element* elem) {
-  call_data* calld = (call_data*)elem->call_data;
-  return calld->subchannel_call;
-}
+// Forward declarations.
+static void retry_commit(grpc_call_element* elem,
+                         subchannel_call_retry_state* retry_state);
+static void start_internal_recv_trailing_metadata(grpc_call_element* elem);
+static void on_complete(void* arg, grpc_error* error);
+static void start_retriable_subchannel_batches(void* arg, grpc_error* ignored);
+static void pick_after_resolver_result_start_locked(grpc_call_element* elem);
+static void start_pick_locked(void* arg, grpc_error* ignored);
 
-// This is called via the call combiner, so access to calld is synchronized.
-static void waiting_for_pick_batches_add(
-    call_data* calld, grpc_transport_stream_op_batch* batch) {
+//
+// send op data caching
+//
+
+// Caches data for send ops so that it can be retried later, if not
+// already cached.
+static void maybe_cache_send_ops_for_batch(call_data* calld,
+                                           pending_batch* pending) {
+  if (pending->send_ops_cached) return;
+  pending->send_ops_cached = true;
+  grpc_transport_stream_op_batch* batch = pending->batch;
+  // Save a copy of metadata for send_initial_metadata ops.
   if (batch->send_initial_metadata) {
-    GPR_ASSERT(calld->initial_metadata_batch == nullptr);
-    calld->initial_metadata_batch = batch;
-  } else {
-    GPR_ASSERT(calld->waiting_for_pick_batches_count < MAX_WAITING_BATCHES);
-    calld->waiting_for_pick_batches[calld->waiting_for_pick_batches_count++] =
-        batch;
+    calld->seen_send_initial_metadata = true;
+    GPR_ASSERT(calld->send_initial_metadata_storage == nullptr);
+    grpc_metadata_batch* send_initial_metadata =
+        batch->payload->send_initial_metadata.send_initial_metadata;
+    calld->send_initial_metadata_storage = (grpc_linked_mdelem*)gpr_arena_alloc(
+        calld->arena,
+        sizeof(grpc_linked_mdelem) * send_initial_metadata->list.count);
+    grpc_metadata_batch_copy(send_initial_metadata,
+                             &calld->send_initial_metadata,
+                             calld->send_initial_metadata_storage);
+    calld->send_initial_metadata_flags =
+        batch->payload->send_initial_metadata.send_initial_metadata_flags;
+    calld->peer_string = batch->payload->send_initial_metadata.peer_string;
+  }
+  // Set up cache for send_message ops.
+  if (batch->send_message) {
+    grpc_core::ByteStreamCache* cache =
+        static_cast<grpc_core::ByteStreamCache*>(
+            gpr_arena_alloc(calld->arena, sizeof(grpc_core::ByteStreamCache)));
+    new (cache) grpc_core::ByteStreamCache(
+        std::move(batch->payload->send_message.send_message));
+    calld->send_messages.push_back(cache);
+  }
+  // Save metadata batch for send_trailing_metadata ops.
+  if (batch->send_trailing_metadata) {
+    calld->seen_send_trailing_metadata = true;
+    GPR_ASSERT(calld->send_trailing_metadata_storage == nullptr);
+    grpc_metadata_batch* send_trailing_metadata =
+        batch->payload->send_trailing_metadata.send_trailing_metadata;
+    calld->send_trailing_metadata_storage =
+        (grpc_linked_mdelem*)gpr_arena_alloc(
+            calld->arena,
+            sizeof(grpc_linked_mdelem) * send_trailing_metadata->list.count);
+    grpc_metadata_batch_copy(send_trailing_metadata,
+                             &calld->send_trailing_metadata,
+                             calld->send_trailing_metadata_storage);
   }
 }
 
-// This is called via the call combiner, so access to calld is synchronized.
-static void fail_pending_batch_in_call_combiner(void* arg, grpc_error* error) {
-  call_data* calld = (call_data*)arg;
-  if (calld->waiting_for_pick_batches_count > 0) {
-    --calld->waiting_for_pick_batches_count;
-    grpc_transport_stream_op_batch_finish_with_failure(
-        calld->waiting_for_pick_batches[calld->waiting_for_pick_batches_count],
-        GRPC_ERROR_REF(error), calld->call_combiner);
+// Frees cached send ops that have already been completed after
+// committing the call.
+static void free_cached_send_op_data_after_commit(
+    grpc_call_element* elem, subchannel_call_retry_state* retry_state) {
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  if (retry_state->completed_send_initial_metadata) {
+    grpc_metadata_batch_destroy(&calld->send_initial_metadata);
+  }
+  for (size_t i = 0; i < retry_state->completed_send_message_count; ++i) {
+    if (grpc_client_channel_trace.enabled()) {
+      gpr_log(GPR_DEBUG,
+              "chand=%p calld=%p: destroying calld->send_messages[%" PRIuPTR
+              "]",
+              chand, calld, i);
+    }
+    calld->send_messages[i]->Destroy();
+  }
+  if (retry_state->completed_send_trailing_metadata) {
+    grpc_metadata_batch_destroy(&calld->send_trailing_metadata);
   }
 }
 
+// Frees cached send ops that were completed by the completed batch in
+// batch_data.  Used when batches are completed after the call is committed.
+static void free_cached_send_op_data_for_completed_batch(
+    grpc_call_element* elem, subchannel_batch_data* batch_data,
+    subchannel_call_retry_state* retry_state) {
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  if (batch_data->batch.send_initial_metadata) {
+    grpc_metadata_batch_destroy(&calld->send_initial_metadata);
+  }
+  if (batch_data->batch.send_message) {
+    if (grpc_client_channel_trace.enabled()) {
+      gpr_log(GPR_DEBUG,
+              "chand=%p calld=%p: destroying calld->send_messages[%" PRIuPTR
+              "]",
+              chand, calld, retry_state->completed_send_message_count - 1);
+    }
+    calld->send_messages[retry_state->completed_send_message_count - 1]
+        ->Destroy();
+  }
+  if (batch_data->batch.send_trailing_metadata) {
+    grpc_metadata_batch_destroy(&calld->send_trailing_metadata);
+  }
+}
+
+//
+// pending_batches management
+//
+
+// Returns the index into calld->pending_batches to be used for batch.
+static size_t get_batch_index(grpc_transport_stream_op_batch* batch) {
+  // Note: It is important the send_initial_metadata be the first entry
+  // here, since the code in pick_subchannel_locked() assumes it will be.
+  if (batch->send_initial_metadata) return 0;
+  if (batch->send_message) return 1;
+  if (batch->send_trailing_metadata) return 2;
+  if (batch->recv_initial_metadata) return 3;
+  if (batch->recv_message) return 4;
+  if (batch->recv_trailing_metadata) return 5;
+  GPR_UNREACHABLE_CODE(return (size_t)-1);
+}
+
 // This is called via the call combiner, so access to calld is synchronized.
-static void waiting_for_pick_batches_fail(grpc_call_element* elem,
-                                          grpc_error* error) {
-  call_data* calld = (call_data*)elem->call_data;
+static void pending_batches_add(grpc_call_element* elem,
+                                grpc_transport_stream_op_batch* batch) {
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  const size_t idx = get_batch_index(batch);
   if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_DEBUG,
-            "chand=%p calld=%p: failing %" PRIuPTR " pending batches: %s",
-            elem->channel_data, calld, calld->waiting_for_pick_batches_count,
-            grpc_error_string(error));
+            "chand=%p calld=%p: adding pending batch at index %" PRIuPTR, chand,
+            calld, idx);
   }
-  for (size_t i = 0; i < calld->waiting_for_pick_batches_count; ++i) {
-    GRPC_CLOSURE_INIT(&calld->handle_pending_batch_in_call_combiner[i],
-                      fail_pending_batch_in_call_combiner, calld,
-                      grpc_schedule_on_exec_ctx);
-    GRPC_CALL_COMBINER_START(
-        calld->call_combiner, &calld->handle_pending_batch_in_call_combiner[i],
-        GRPC_ERROR_REF(error), "waiting_for_pick_batches_fail");
-  }
-  if (calld->initial_metadata_batch != nullptr) {
-    grpc_transport_stream_op_batch_finish_with_failure(
-        calld->initial_metadata_batch, GRPC_ERROR_REF(error),
-        calld->call_combiner);
-  } else {
-    GRPC_CALL_COMBINER_STOP(calld->call_combiner,
-                            "waiting_for_pick_batches_fail");
-  }
-  GRPC_ERROR_UNREF(error);
-}
-
-// This is called via the call combiner, so access to calld is synchronized.
-static void run_pending_batch_in_call_combiner(void* arg, grpc_error* ignored) {
-  call_data* calld = (call_data*)arg;
-  if (calld->waiting_for_pick_batches_count > 0) {
-    --calld->waiting_for_pick_batches_count;
-    grpc_subchannel_call_process_op(
-        calld->subchannel_call,
-        calld->waiting_for_pick_batches[calld->waiting_for_pick_batches_count]);
-  }
-}
-
-// This is called via the call combiner, so access to calld is synchronized.
-static void waiting_for_pick_batches_resume(grpc_call_element* elem) {
-  channel_data* chand = (channel_data*)elem->channel_data;
-  call_data* calld = (call_data*)elem->call_data;
-  if (grpc_client_channel_trace.enabled()) {
-    gpr_log(GPR_DEBUG,
-            "chand=%p calld=%p: sending %" PRIuPTR
-            " pending batches to subchannel_call=%p",
-            chand, calld, calld->waiting_for_pick_batches_count,
-            calld->subchannel_call);
-  }
-  for (size_t i = 0; i < calld->waiting_for_pick_batches_count; ++i) {
-    GRPC_CLOSURE_INIT(&calld->handle_pending_batch_in_call_combiner[i],
-                      run_pending_batch_in_call_combiner, calld,
-                      grpc_schedule_on_exec_ctx);
-    GRPC_CALL_COMBINER_START(
-        calld->call_combiner, &calld->handle_pending_batch_in_call_combiner[i],
-        GRPC_ERROR_NONE, "waiting_for_pick_batches_resume");
-  }
-  GPR_ASSERT(calld->initial_metadata_batch != nullptr);
-  grpc_subchannel_call_process_op(calld->subchannel_call,
-                                  calld->initial_metadata_batch);
-}
-
-// Applies service config to the call.  Must be invoked once we know
-// that the resolver has returned results to the channel.
-static void apply_service_config_to_call_locked(grpc_call_element* elem) {
-  channel_data* chand = (channel_data*)elem->channel_data;
-  call_data* calld = (call_data*)elem->call_data;
-  if (grpc_client_channel_trace.enabled()) {
-    gpr_log(GPR_DEBUG, "chand=%p calld=%p: applying service config to call",
-            chand, calld);
-  }
-  if (chand->retry_throttle_data != nullptr) {
-    calld->retry_throttle_data =
-        grpc_server_retry_throttle_data_ref(chand->retry_throttle_data);
-  }
-  if (chand->method_params_table != nullptr) {
-    calld->method_params = (method_parameters*)grpc_method_config_table_get(
-        chand->method_params_table, calld->path);
-    if (calld->method_params != nullptr) {
-      method_parameters_ref(calld->method_params);
-      // If the deadline from the service config is shorter than the one
-      // from the client API, reset the deadline timer.
-      if (chand->deadline_checking_enabled &&
-          calld->method_params->timeout != 0) {
-        const grpc_millis per_method_deadline =
-            grpc_timespec_to_millis_round_up(calld->call_start_time) +
-            calld->method_params->timeout;
-        if (per_method_deadline < calld->deadline) {
-          calld->deadline = per_method_deadline;
-          grpc_deadline_state_reset(elem, calld->deadline);
+  pending_batch* pending = &calld->pending_batches[idx];
+  GPR_ASSERT(pending->batch == nullptr);
+  pending->batch = batch;
+  pending->send_ops_cached = false;
+  if (calld->enable_retries) {
+    // Update state in calld about pending batches.
+    // Also check if the batch takes us over the retry buffer limit.
+    // Note: We don't check the size of trailing metadata here, because
+    // gRPC clients do not send trailing metadata.
+    if (batch->send_initial_metadata) {
+      calld->pending_send_initial_metadata = true;
+      calld->bytes_buffered_for_retry += grpc_metadata_batch_size(
+          batch->payload->send_initial_metadata.send_initial_metadata);
+    }
+    if (batch->send_message) {
+      calld->pending_send_message = true;
+      calld->bytes_buffered_for_retry +=
+          batch->payload->send_message.send_message->length();
+    }
+    if (batch->send_trailing_metadata) {
+      calld->pending_send_trailing_metadata = true;
+    }
+    if (calld->bytes_buffered_for_retry > chand->per_rpc_retry_buffer_size) {
+      if (grpc_client_channel_trace.enabled()) {
+        gpr_log(GPR_DEBUG,
+                "chand=%p calld=%p: exceeded retry buffer size, committing",
+                chand, calld);
+      }
+      subchannel_call_retry_state* retry_state =
+          calld->subchannel_call == nullptr
+              ? nullptr
+              : static_cast<subchannel_call_retry_state*>(
+                    grpc_connected_subchannel_call_get_parent_data(
+                        calld->subchannel_call));
+      retry_commit(elem, retry_state);
+      // If we are not going to retry and have not yet started, pretend
+      // retries are disabled so that we don't bother with retry overhead.
+      if (calld->num_attempts_completed == 0) {
+        if (grpc_client_channel_trace.enabled()) {
+          gpr_log(GPR_DEBUG,
+                  "chand=%p calld=%p: disabling retries before first attempt",
+                  chand, calld);
         }
+        calld->enable_retries = false;
       }
     }
   }
 }
 
-static void create_subchannel_call_locked(grpc_call_element* elem,
-                                          grpc_error* error) {
-  channel_data* chand = (channel_data*)elem->channel_data;
-  call_data* calld = (call_data*)elem->call_data;
+static void pending_batch_clear(call_data* calld, pending_batch* pending) {
+  if (calld->enable_retries) {
+    if (pending->batch->send_initial_metadata) {
+      calld->pending_send_initial_metadata = false;
+    }
+    if (pending->batch->send_message) {
+      calld->pending_send_message = false;
+    }
+    if (pending->batch->send_trailing_metadata) {
+      calld->pending_send_trailing_metadata = false;
+    }
+  }
+  pending->batch = nullptr;
+}
+
+// This is called via the call combiner, so access to calld is synchronized.
+static void fail_pending_batch_in_call_combiner(void* arg, grpc_error* error) {
+  grpc_transport_stream_op_batch* batch =
+      static_cast<grpc_transport_stream_op_batch*>(arg);
+  call_data* calld = static_cast<call_data*>(batch->handler_private.extra_arg);
+  // Note: This will release the call combiner.
+  grpc_transport_stream_op_batch_finish_with_failure(
+      batch, GRPC_ERROR_REF(error), calld->call_combiner);
+}
+
+// This is called via the call combiner, so access to calld is synchronized.
+// If yield_call_combiner is true, assumes responsibility for yielding
+// the call combiner.
+static void pending_batches_fail(grpc_call_element* elem, grpc_error* error,
+                                 bool yield_call_combiner) {
+  GPR_ASSERT(error != GRPC_ERROR_NONE);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  if (grpc_client_channel_trace.enabled()) {
+    size_t num_batches = 0;
+    for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) {
+      if (calld->pending_batches[i].batch != nullptr) ++num_batches;
+    }
+    gpr_log(GPR_DEBUG,
+            "chand=%p calld=%p: failing %" PRIuPTR " pending batches: %s",
+            elem->channel_data, calld, num_batches, grpc_error_string(error));
+  }
+  grpc_transport_stream_op_batch*
+      batches[GPR_ARRAY_SIZE(calld->pending_batches)];
+  size_t num_batches = 0;
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) {
+    pending_batch* pending = &calld->pending_batches[i];
+    grpc_transport_stream_op_batch* batch = pending->batch;
+    if (batch != nullptr) {
+      batches[num_batches++] = batch;
+      pending_batch_clear(calld, pending);
+    }
+  }
+  for (size_t i = yield_call_combiner ? 1 : 0; i < num_batches; ++i) {
+    grpc_transport_stream_op_batch* batch = batches[i];
+    batch->handler_private.extra_arg = calld;
+    GRPC_CLOSURE_INIT(&batch->handler_private.closure,
+                      fail_pending_batch_in_call_combiner, batch,
+                      grpc_schedule_on_exec_ctx);
+    GRPC_CALL_COMBINER_START(calld->call_combiner,
+                             &batch->handler_private.closure,
+                             GRPC_ERROR_REF(error), "pending_batches_fail");
+  }
+  if (yield_call_combiner) {
+    if (num_batches > 0) {
+      // Note: This will release the call combiner.
+      grpc_transport_stream_op_batch_finish_with_failure(
+          batches[0], GRPC_ERROR_REF(error), calld->call_combiner);
+    } else {
+      GRPC_CALL_COMBINER_STOP(calld->call_combiner, "pending_batches_fail");
+    }
+  }
+  GRPC_ERROR_UNREF(error);
+}
+
+// This is called via the call combiner, so access to calld is synchronized.
+static void resume_pending_batch_in_call_combiner(void* arg,
+                                                  grpc_error* ignored) {
+  grpc_transport_stream_op_batch* batch =
+      static_cast<grpc_transport_stream_op_batch*>(arg);
+  grpc_subchannel_call* subchannel_call =
+      static_cast<grpc_subchannel_call*>(batch->handler_private.extra_arg);
+  // Note: This will release the call combiner.
+  grpc_subchannel_call_process_op(subchannel_call, batch);
+}
+
+// This is called via the call combiner, so access to calld is synchronized.
+static void pending_batches_resume(grpc_call_element* elem) {
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  if (calld->enable_retries) {
+    start_retriable_subchannel_batches(elem, GRPC_ERROR_NONE);
+    return;
+  }
+  // Retries not enabled; send down batches as-is.
+  if (grpc_client_channel_trace.enabled()) {
+    size_t num_batches = 0;
+    for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) {
+      if (calld->pending_batches[i].batch != nullptr) ++num_batches;
+    }
+    gpr_log(GPR_DEBUG,
+            "chand=%p calld=%p: starting %" PRIuPTR
+            " pending batches on subchannel_call=%p",
+            chand, calld, num_batches, calld->subchannel_call);
+  }
+  grpc_transport_stream_op_batch*
+      batches[GPR_ARRAY_SIZE(calld->pending_batches)];
+  size_t num_batches = 0;
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) {
+    pending_batch* pending = &calld->pending_batches[i];
+    grpc_transport_stream_op_batch* batch = pending->batch;
+    if (batch != nullptr) {
+      batches[num_batches++] = batch;
+      pending_batch_clear(calld, pending);
+    }
+  }
+  for (size_t i = 1; i < num_batches; ++i) {
+    grpc_transport_stream_op_batch* batch = batches[i];
+    batch->handler_private.extra_arg = calld->subchannel_call;
+    GRPC_CLOSURE_INIT(&batch->handler_private.closure,
+                      resume_pending_batch_in_call_combiner, batch,
+                      grpc_schedule_on_exec_ctx);
+    GRPC_CALL_COMBINER_START(calld->call_combiner,
+                             &batch->handler_private.closure, GRPC_ERROR_NONE,
+                             "pending_batches_resume");
+  }
+  GPR_ASSERT(num_batches > 0);
+  // Note: This will release the call combiner.
+  grpc_subchannel_call_process_op(calld->subchannel_call, batches[0]);
+}
+
+static void maybe_clear_pending_batch(grpc_call_element* elem,
+                                      pending_batch* pending) {
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  grpc_transport_stream_op_batch* batch = pending->batch;
+  // We clear the pending batch if all of its callbacks have been
+  // scheduled and reset to nullptr.
+  if (batch->on_complete == nullptr &&
+      (!batch->recv_initial_metadata ||
+       batch->payload->recv_initial_metadata.recv_initial_metadata_ready ==
+           nullptr) &&
+      (!batch->recv_message ||
+       batch->payload->recv_message.recv_message_ready == nullptr)) {
+    if (grpc_client_channel_trace.enabled()) {
+      gpr_log(GPR_DEBUG, "chand=%p calld=%p: clearing pending batch", chand,
+              calld);
+    }
+    pending_batch_clear(calld, pending);
+  }
+}
+
+// Returns true if all ops in the pending batch have been completed.
+static bool pending_batch_is_completed(
+    pending_batch* pending, call_data* calld,
+    subchannel_call_retry_state* retry_state) {
+  if (pending->batch == nullptr || pending->batch->on_complete == nullptr) {
+    return false;
+  }
+  if (pending->batch->send_initial_metadata &&
+      !retry_state->completed_send_initial_metadata) {
+    return false;
+  }
+  if (pending->batch->send_message &&
+      retry_state->completed_send_message_count < calld->send_messages.size()) {
+    return false;
+  }
+  if (pending->batch->send_trailing_metadata &&
+      !retry_state->completed_send_trailing_metadata) {
+    return false;
+  }
+  if (pending->batch->recv_initial_metadata &&
+      !retry_state->completed_recv_initial_metadata) {
+    return false;
+  }
+  if (pending->batch->recv_message &&
+      retry_state->completed_recv_message_count <
+          retry_state->started_recv_message_count) {
+    return false;
+  }
+  if (pending->batch->recv_trailing_metadata &&
+      !retry_state->completed_recv_trailing_metadata) {
+    return false;
+  }
+  return true;
+}
+
+// Returns true if any op in the batch was not yet started.
+static bool pending_batch_is_unstarted(
+    pending_batch* pending, call_data* calld,
+    subchannel_call_retry_state* retry_state) {
+  if (pending->batch == nullptr || pending->batch->on_complete == nullptr) {
+    return false;
+  }
+  if (pending->batch->send_initial_metadata &&
+      !retry_state->started_send_initial_metadata) {
+    return true;
+  }
+  if (pending->batch->send_message &&
+      retry_state->started_send_message_count < calld->send_messages.size()) {
+    return true;
+  }
+  if (pending->batch->send_trailing_metadata &&
+      !retry_state->started_send_trailing_metadata) {
+    return true;
+  }
+  if (pending->batch->recv_initial_metadata &&
+      !retry_state->started_recv_initial_metadata) {
+    return true;
+  }
+  if (pending->batch->recv_message &&
+      retry_state->completed_recv_message_count ==
+          retry_state->started_recv_message_count) {
+    return true;
+  }
+  if (pending->batch->recv_trailing_metadata &&
+      !retry_state->started_recv_trailing_metadata) {
+    return true;
+  }
+  return false;
+}
+
+//
+// retry code
+//
+
+// Commits the call so that no further retry attempts will be performed.
+static void retry_commit(grpc_call_element* elem,
+                         subchannel_call_retry_state* retry_state) {
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  if (calld->retry_committed) return;
+  calld->retry_committed = true;
+  if (grpc_client_channel_trace.enabled()) {
+    gpr_log(GPR_DEBUG, "chand=%p calld=%p: committing retries", chand, calld);
+  }
+  if (retry_state != nullptr) {
+    free_cached_send_op_data_after_commit(elem, retry_state);
+  }
+}
+
+// Starts a retry after appropriate back-off.
+static void do_retry(grpc_call_element* elem,
+                     subchannel_call_retry_state* retry_state,
+                     grpc_millis server_pushback_ms) {
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  GPR_ASSERT(calld->method_params != nullptr);
+  const ClientChannelMethodParams::RetryPolicy* retry_policy =
+      calld->method_params->retry_policy();
+  GPR_ASSERT(retry_policy != nullptr);
+  // Reset subchannel call and connected subchannel.
+  if (calld->subchannel_call != nullptr) {
+    GRPC_SUBCHANNEL_CALL_UNREF(calld->subchannel_call,
+                               "client_channel_call_retry");
+    calld->subchannel_call = nullptr;
+  }
+  if (calld->pick.connected_subchannel != nullptr) {
+    calld->pick.connected_subchannel.reset();
+  }
+  // Compute backoff delay.
+  grpc_millis next_attempt_time;
+  if (server_pushback_ms >= 0) {
+    next_attempt_time = grpc_core::ExecCtx::Get()->Now() + server_pushback_ms;
+    calld->last_attempt_got_server_pushback = true;
+  } else {
+    if (calld->num_attempts_completed == 1 ||
+        calld->last_attempt_got_server_pushback) {
+      calld->retry_backoff.Init(
+          grpc_core::BackOff::Options()
+              .set_initial_backoff(retry_policy->initial_backoff)
+              .set_multiplier(retry_policy->backoff_multiplier)
+              .set_jitter(RETRY_BACKOFF_JITTER)
+              .set_max_backoff(retry_policy->max_backoff));
+      calld->last_attempt_got_server_pushback = false;
+    }
+    next_attempt_time = calld->retry_backoff->NextAttemptTime();
+  }
+  if (grpc_client_channel_trace.enabled()) {
+    gpr_log(GPR_DEBUG,
+            "chand=%p calld=%p: retrying failed call in %" PRIuPTR " ms", chand,
+            calld, next_attempt_time - grpc_core::ExecCtx::Get()->Now());
+  }
+  // Schedule retry after computed delay.
+  GRPC_CLOSURE_INIT(&calld->pick_closure, start_pick_locked, elem,
+                    grpc_combiner_scheduler(chand->combiner));
+  grpc_timer_init(&calld->retry_timer, next_attempt_time, &calld->pick_closure);
+  // Update bookkeeping.
+  if (retry_state != nullptr) retry_state->retry_dispatched = true;
+}
+
+// Returns true if the call is being retried.
+static bool maybe_retry(grpc_call_element* elem,
+                        subchannel_batch_data* batch_data,
+                        grpc_status_code status,
+                        grpc_mdelem* server_pushback_md) {
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  // Get retry policy.
+  if (calld->method_params == nullptr) return false;
+  const ClientChannelMethodParams::RetryPolicy* retry_policy =
+      calld->method_params->retry_policy();
+  if (retry_policy == nullptr) return false;
+  // If we've already dispatched a retry from this call, return true.
+  // This catches the case where the batch has multiple callbacks
+  // (i.e., it includes either recv_message or recv_initial_metadata).
+  subchannel_call_retry_state* retry_state = nullptr;
+  if (batch_data != nullptr) {
+    retry_state = static_cast<subchannel_call_retry_state*>(
+        grpc_connected_subchannel_call_get_parent_data(
+            batch_data->subchannel_call));
+    if (retry_state->retry_dispatched) {
+      if (grpc_client_channel_trace.enabled()) {
+        gpr_log(GPR_DEBUG, "chand=%p calld=%p: retry already dispatched", chand,
+                calld);
+      }
+      return true;
+    }
+  }
+  // Check status.
+  if (status == GRPC_STATUS_OK) {
+    grpc_server_retry_throttle_data_record_success(calld->retry_throttle_data);
+    if (grpc_client_channel_trace.enabled()) {
+      gpr_log(GPR_DEBUG, "chand=%p calld=%p: call succeeded", chand, calld);
+    }
+    return false;
+  }
+  // Status is not OK.  Check whether the status is retryable.
+  if (!retry_policy->retryable_status_codes.Contains(status)) {
+    if (grpc_client_channel_trace.enabled()) {
+      gpr_log(GPR_DEBUG,
+              "chand=%p calld=%p: status %s not configured as retryable", chand,
+              calld, grpc_status_code_to_string(status));
+    }
+    return false;
+  }
+  // Record the failure and check whether retries are throttled.
+  // Note that it's important for this check to come after the status
+  // code check above, since we should only record failures whose statuses
+  // match the configured retryable status codes, so that we don't count
+  // things like failures due to malformed requests (INVALID_ARGUMENT).
+  // Conversely, it's important for this to come before the remaining
+  // checks, so that we don't fail to record failures due to other factors.
+  if (!grpc_server_retry_throttle_data_record_failure(
+          calld->retry_throttle_data)) {
+    if (grpc_client_channel_trace.enabled()) {
+      gpr_log(GPR_DEBUG, "chand=%p calld=%p: retries throttled", chand, calld);
+    }
+    return false;
+  }
+  // Check whether the call is committed.
+  if (calld->retry_committed) {
+    if (grpc_client_channel_trace.enabled()) {
+      gpr_log(GPR_DEBUG, "chand=%p calld=%p: retries already committed", chand,
+              calld);
+    }
+    return false;
+  }
+  // Check whether we have retries remaining.
+  ++calld->num_attempts_completed;
+  if (calld->num_attempts_completed >= retry_policy->max_attempts) {
+    if (grpc_client_channel_trace.enabled()) {
+      gpr_log(GPR_DEBUG, "chand=%p calld=%p: exceeded %d retry attempts", chand,
+              calld, retry_policy->max_attempts);
+    }
+    return false;
+  }
+  // If the call was cancelled from the surface, don't retry.
+  if (calld->cancel_error != GRPC_ERROR_NONE) {
+    if (grpc_client_channel_trace.enabled()) {
+      gpr_log(GPR_DEBUG,
+              "chand=%p calld=%p: call cancelled from surface, not retrying",
+              chand, calld);
+    }
+    return false;
+  }
+  // Check server push-back.
+  grpc_millis server_pushback_ms = -1;
+  if (server_pushback_md != nullptr) {
+    // If the value is "-1" or any other unparseable string, we do not retry.
+    uint32_t ms;
+    if (!grpc_parse_slice_to_uint32(GRPC_MDVALUE(*server_pushback_md), &ms)) {
+      if (grpc_client_channel_trace.enabled()) {
+        gpr_log(GPR_DEBUG,
+                "chand=%p calld=%p: not retrying due to server push-back",
+                chand, calld);
+      }
+      return false;
+    } else {
+      if (grpc_client_channel_trace.enabled()) {
+        gpr_log(GPR_DEBUG,
+                "chand=%p calld=%p: server push-back: retry in %u ms", chand,
+                calld, ms);
+      }
+      server_pushback_ms = (grpc_millis)ms;
+    }
+  }
+  do_retry(elem, retry_state, server_pushback_ms);
+  return true;
+}
+
+//
+// subchannel_batch_data
+//
+
+static subchannel_batch_data* batch_data_create(grpc_call_element* elem,
+                                                int refcount) {
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  subchannel_call_retry_state* retry_state =
+      static_cast<subchannel_call_retry_state*>(
+          grpc_connected_subchannel_call_get_parent_data(
+              calld->subchannel_call));
+  subchannel_batch_data* batch_data = static_cast<subchannel_batch_data*>(
+      gpr_arena_alloc(calld->arena, sizeof(*batch_data)));
+  batch_data->elem = elem;
+  batch_data->subchannel_call =
+      GRPC_SUBCHANNEL_CALL_REF(calld->subchannel_call, "batch_data_create");
+  batch_data->batch.payload = &retry_state->batch_payload;
+  gpr_ref_init(&batch_data->refs, refcount);
+  GRPC_CLOSURE_INIT(&batch_data->on_complete, on_complete, batch_data,
+                    grpc_schedule_on_exec_ctx);
+  batch_data->batch.on_complete = &batch_data->on_complete;
+  GRPC_CALL_STACK_REF(calld->owning_call, "batch_data");
+  return batch_data;
+}
+
+static void batch_data_unref(subchannel_batch_data* batch_data) {
+  if (gpr_unref(&batch_data->refs)) {
+    if (batch_data->send_initial_metadata_storage != nullptr) {
+      grpc_metadata_batch_destroy(&batch_data->send_initial_metadata);
+    }
+    if (batch_data->send_trailing_metadata_storage != nullptr) {
+      grpc_metadata_batch_destroy(&batch_data->send_trailing_metadata);
+    }
+    if (batch_data->batch.recv_initial_metadata) {
+      grpc_metadata_batch_destroy(&batch_data->recv_initial_metadata);
+    }
+    if (batch_data->batch.recv_trailing_metadata) {
+      grpc_metadata_batch_destroy(&batch_data->recv_trailing_metadata);
+    }
+    GRPC_SUBCHANNEL_CALL_UNREF(batch_data->subchannel_call, "batch_data_unref");
+    call_data* calld = static_cast<call_data*>(batch_data->elem->call_data);
+    GRPC_CALL_STACK_UNREF(calld->owning_call, "batch_data");
+  }
+}
+
+//
+// recv_initial_metadata callback handling
+//
+
+// Invokes recv_initial_metadata_ready for a subchannel batch.
+static void invoke_recv_initial_metadata_callback(void* arg,
+                                                  grpc_error* error) {
+  subchannel_batch_data* batch_data = static_cast<subchannel_batch_data*>(arg);
+  channel_data* chand =
+      static_cast<channel_data*>(batch_data->elem->channel_data);
+  call_data* calld = static_cast<call_data*>(batch_data->elem->call_data);
+  // Find pending batch.
+  pending_batch* pending = nullptr;
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) {
+    grpc_transport_stream_op_batch* batch = calld->pending_batches[i].batch;
+    if (batch != nullptr && batch->recv_initial_metadata &&
+        batch->payload->recv_initial_metadata.recv_initial_metadata_ready !=
+            nullptr) {
+      if (grpc_client_channel_trace.enabled()) {
+        gpr_log(GPR_DEBUG,
+                "chand=%p calld=%p: invoking recv_initial_metadata_ready for "
+                "pending batch at index %" PRIuPTR,
+                chand, calld, i);
+      }
+      pending = &calld->pending_batches[i];
+      break;
+    }
+  }
+  GPR_ASSERT(pending != nullptr);
+  // Return metadata.
+  grpc_metadata_batch_move(
+      &batch_data->recv_initial_metadata,
+      pending->batch->payload->recv_initial_metadata.recv_initial_metadata);
+  // Update bookkeeping.
+  // Note: Need to do this before invoking the callback, since invoking
+  // the callback will result in yielding the call combiner.
+  grpc_closure* recv_initial_metadata_ready =
+      pending->batch->payload->recv_initial_metadata
+          .recv_initial_metadata_ready;
+  pending->batch->payload->recv_initial_metadata.recv_initial_metadata_ready =
+      nullptr;
+  maybe_clear_pending_batch(batch_data->elem, pending);
+  batch_data_unref(batch_data);
+  // Invoke callback.
+  GRPC_CLOSURE_RUN(recv_initial_metadata_ready, GRPC_ERROR_REF(error));
+}
+
+// Intercepts recv_initial_metadata_ready callback for retries.
+// Commits the call and returns the initial metadata up the stack.
+static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
+  subchannel_batch_data* batch_data = static_cast<subchannel_batch_data*>(arg);
+  grpc_call_element* elem = batch_data->elem;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  if (grpc_client_channel_trace.enabled()) {
+    gpr_log(GPR_DEBUG,
+            "chand=%p calld=%p: got recv_initial_metadata_ready, error=%s",
+            chand, calld, grpc_error_string(error));
+  }
+  subchannel_call_retry_state* retry_state =
+      static_cast<subchannel_call_retry_state*>(
+          grpc_connected_subchannel_call_get_parent_data(
+              batch_data->subchannel_call));
+  // If we got an error or a Trailers-Only response and have not yet gotten
+  // the recv_trailing_metadata on_complete callback, then defer
+  // propagating this callback back to the surface.  We can evaluate whether
+  // to retry when recv_trailing_metadata comes back.
+  if ((batch_data->trailing_metadata_available || error != GRPC_ERROR_NONE) &&
+      !retry_state->completed_recv_trailing_metadata) {
+    if (grpc_client_channel_trace.enabled()) {
+      gpr_log(GPR_DEBUG,
+              "chand=%p calld=%p: deferring recv_initial_metadata_ready "
+              "(Trailers-Only)",
+              chand, calld);
+    }
+    retry_state->recv_initial_metadata_ready_deferred = true;
+    retry_state->recv_initial_metadata_error = GRPC_ERROR_REF(error);
+    if (!retry_state->started_recv_trailing_metadata) {
+      // recv_trailing_metadata not yet started by application; start it
+      // ourselves to get status.
+      start_internal_recv_trailing_metadata(elem);
+    } else {
+      GRPC_CALL_COMBINER_STOP(
+          calld->call_combiner,
+          "recv_initial_metadata_ready trailers-only or error");
+    }
+    return;
+  }
+  // Received valid initial metadata, so commit the call.
+  retry_commit(elem, retry_state);
+  // Manually invoking a callback function; it does not take ownership of error.
+  invoke_recv_initial_metadata_callback(batch_data, error);
+  GRPC_ERROR_UNREF(error);
+}
+
+//
+// recv_message callback handling
+//
+
+// Invokes recv_message_ready for a subchannel batch.
+static void invoke_recv_message_callback(void* arg, grpc_error* error) {
+  subchannel_batch_data* batch_data = static_cast<subchannel_batch_data*>(arg);
+  channel_data* chand =
+      static_cast<channel_data*>(batch_data->elem->channel_data);
+  call_data* calld = static_cast<call_data*>(batch_data->elem->call_data);
+  // Find pending op.
+  pending_batch* pending = nullptr;
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) {
+    grpc_transport_stream_op_batch* batch = calld->pending_batches[i].batch;
+    if (batch != nullptr && batch->recv_message &&
+        batch->payload->recv_message.recv_message_ready != nullptr) {
+      if (grpc_client_channel_trace.enabled()) {
+        gpr_log(GPR_DEBUG,
+                "chand=%p calld=%p: invoking recv_message_ready for "
+                "pending batch at index %" PRIuPTR,
+                chand, calld, i);
+      }
+      pending = &calld->pending_batches[i];
+      break;
+    }
+  }
+  GPR_ASSERT(pending != nullptr);
+  // Return payload.
+  *pending->batch->payload->recv_message.recv_message =
+      std::move(batch_data->recv_message);
+  // Update bookkeeping.
+  // Note: Need to do this before invoking the callback, since invoking
+  // the callback will result in yielding the call combiner.
+  grpc_closure* recv_message_ready =
+      pending->batch->payload->recv_message.recv_message_ready;
+  pending->batch->payload->recv_message.recv_message_ready = nullptr;
+  maybe_clear_pending_batch(batch_data->elem, pending);
+  batch_data_unref(batch_data);
+  // Invoke callback.
+  GRPC_CLOSURE_RUN(recv_message_ready, GRPC_ERROR_REF(error));
+}
+
+// Intercepts recv_message_ready callback for retries.
+// Commits the call and returns the message up the stack.
+static void recv_message_ready(void* arg, grpc_error* error) {
+  subchannel_batch_data* batch_data = static_cast<subchannel_batch_data*>(arg);
+  grpc_call_element* elem = batch_data->elem;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  if (grpc_client_channel_trace.enabled()) {
+    gpr_log(GPR_DEBUG, "chand=%p calld=%p: got recv_message_ready, error=%s",
+            chand, calld, grpc_error_string(error));
+  }
+  subchannel_call_retry_state* retry_state =
+      static_cast<subchannel_call_retry_state*>(
+          grpc_connected_subchannel_call_get_parent_data(
+              batch_data->subchannel_call));
+  // If we got an error or the payload was nullptr and we have not yet gotten
+  // the recv_trailing_metadata on_complete callback, then defer
+  // propagating this callback back to the surface.  We can evaluate whether
+  // to retry when recv_trailing_metadata comes back.
+  if ((batch_data->recv_message == nullptr || error != GRPC_ERROR_NONE) &&
+      !retry_state->completed_recv_trailing_metadata) {
+    if (grpc_client_channel_trace.enabled()) {
+      gpr_log(GPR_DEBUG,
+              "chand=%p calld=%p: deferring recv_message_ready (nullptr "
+              "message and recv_trailing_metadata pending)",
+              chand, calld);
+    }
+    retry_state->recv_message_ready_deferred = true;
+    retry_state->recv_message_error = GRPC_ERROR_REF(error);
+    if (!retry_state->started_recv_trailing_metadata) {
+      // recv_trailing_metadata not yet started by application; start it
+      // ourselves to get status.
+      start_internal_recv_trailing_metadata(elem);
+    } else {
+      GRPC_CALL_COMBINER_STOP(calld->call_combiner, "recv_message_ready null");
+    }
+    return;
+  }
+  // Received a valid message, so commit the call.
+  retry_commit(elem, retry_state);
+  // Manually invoking a callback function; it does not take ownership of error.
+  invoke_recv_message_callback(batch_data, error);
+  GRPC_ERROR_UNREF(error);
+}
+
+//
+// on_complete callback handling
+//
+
+// Updates retry_state to reflect the ops completed in batch_data.
+static void update_retry_state_for_completed_batch(
+    subchannel_batch_data* batch_data,
+    subchannel_call_retry_state* retry_state) {
+  if (batch_data->batch.send_initial_metadata) {
+    retry_state->completed_send_initial_metadata = true;
+  }
+  if (batch_data->batch.send_message) {
+    ++retry_state->completed_send_message_count;
+  }
+  if (batch_data->batch.send_trailing_metadata) {
+    retry_state->completed_send_trailing_metadata = true;
+  }
+  if (batch_data->batch.recv_initial_metadata) {
+    retry_state->completed_recv_initial_metadata = true;
+  }
+  if (batch_data->batch.recv_message) {
+    ++retry_state->completed_recv_message_count;
+  }
+  if (batch_data->batch.recv_trailing_metadata) {
+    retry_state->completed_recv_trailing_metadata = true;
+  }
+}
+
+// Represents a closure that needs to run as a result of a completed batch.
+typedef struct {
+  grpc_closure* closure;
+  grpc_error* error;
+  const char* reason;
+} closure_to_execute;
+
+// Adds any necessary closures for deferred recv_initial_metadata and
+// recv_message callbacks to closures, updating *num_closures as needed.
+static void add_closures_for_deferred_recv_callbacks(
+    subchannel_batch_data* batch_data, subchannel_call_retry_state* retry_state,
+    closure_to_execute* closures, size_t* num_closures) {
+  if (batch_data->batch.recv_trailing_metadata &&
+      retry_state->recv_initial_metadata_ready_deferred) {
+    closure_to_execute* closure = &closures[(*num_closures)++];
+    closure->closure =
+        GRPC_CLOSURE_INIT(&batch_data->recv_initial_metadata_ready,
+                          invoke_recv_initial_metadata_callback, batch_data,
+                          grpc_schedule_on_exec_ctx);
+    closure->error = retry_state->recv_initial_metadata_error;
+    closure->reason = "resuming recv_initial_metadata_ready";
+  }
+  if (batch_data->batch.recv_trailing_metadata &&
+      retry_state->recv_message_ready_deferred) {
+    closure_to_execute* closure = &closures[(*num_closures)++];
+    closure->closure = GRPC_CLOSURE_INIT(&batch_data->recv_message_ready,
+                                         invoke_recv_message_callback,
+                                         batch_data, grpc_schedule_on_exec_ctx);
+    closure->error = retry_state->recv_message_error;
+    closure->reason = "resuming recv_message_ready";
+  }
+}
+
+// If there are any cached ops to replay or pending ops to start on the
+// subchannel call, adds a closure to closures to invoke
+// start_retriable_subchannel_batches(), updating *num_closures as needed.
+static void add_closures_for_replay_or_pending_send_ops(
+    grpc_call_element* elem, subchannel_batch_data* batch_data,
+    subchannel_call_retry_state* retry_state, closure_to_execute* closures,
+    size_t* num_closures) {
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  bool have_pending_send_message_ops =
+      retry_state->started_send_message_count < calld->send_messages.size();
+  bool have_pending_send_trailing_metadata_op =
+      calld->seen_send_trailing_metadata &&
+      !retry_state->started_send_trailing_metadata;
+  if (!have_pending_send_message_ops &&
+      !have_pending_send_trailing_metadata_op) {
+    for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) {
+      pending_batch* pending = &calld->pending_batches[i];
+      grpc_transport_stream_op_batch* batch = pending->batch;
+      if (batch == nullptr || pending->send_ops_cached) continue;
+      if (batch->send_message) have_pending_send_message_ops = true;
+      if (batch->send_trailing_metadata) {
+        have_pending_send_trailing_metadata_op = true;
+      }
+    }
+  }
+  if (have_pending_send_message_ops || have_pending_send_trailing_metadata_op) {
+    if (grpc_client_channel_trace.enabled()) {
+      gpr_log(GPR_DEBUG,
+              "chand=%p calld=%p: starting next batch for pending send op(s)",
+              chand, calld);
+    }
+    closure_to_execute* closure = &closures[(*num_closures)++];
+    closure->closure = GRPC_CLOSURE_INIT(
+        &batch_data->batch.handler_private.closure,
+        start_retriable_subchannel_batches, elem, grpc_schedule_on_exec_ctx);
+    closure->error = GRPC_ERROR_NONE;
+    closure->reason = "starting next batch for send_* op(s)";
+  }
+}
+
+// For any pending batch completed in batch_data, adds the necessary
+// completion closures to closures, updating *num_closures as needed.
+static void add_closures_for_completed_pending_batches(
+    grpc_call_element* elem, subchannel_batch_data* batch_data,
+    subchannel_call_retry_state* retry_state, grpc_error* error,
+    closure_to_execute* closures, size_t* num_closures) {
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) {
+    pending_batch* pending = &calld->pending_batches[i];
+    if (pending_batch_is_completed(pending, calld, retry_state)) {
+      if (grpc_client_channel_trace.enabled()) {
+        gpr_log(GPR_DEBUG,
+                "chand=%p calld=%p: pending batch completed at index %" PRIuPTR,
+                chand, calld, i);
+      }
+      // Copy the trailing metadata to return it to the surface.
+      if (batch_data->batch.recv_trailing_metadata) {
+        grpc_metadata_batch_move(&batch_data->recv_trailing_metadata,
+                                 pending->batch->payload->recv_trailing_metadata
+                                     .recv_trailing_metadata);
+      }
+      closure_to_execute* closure = &closures[(*num_closures)++];
+      closure->closure = pending->batch->on_complete;
+      closure->error = GRPC_ERROR_REF(error);
+      closure->reason = "on_complete for pending batch";
+      pending->batch->on_complete = nullptr;
+      maybe_clear_pending_batch(elem, pending);
+    }
+  }
+  GRPC_ERROR_UNREF(error);
+}
+
+// For any pending batch containing an op that has not yet been started,
+// adds the pending batch's completion closures to closures, updating
+// *num_closures as needed.
+static void add_closures_to_fail_unstarted_pending_batches(
+    grpc_call_element* elem, subchannel_call_retry_state* retry_state,
+    grpc_error* error, closure_to_execute* closures, size_t* num_closures) {
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) {
+    pending_batch* pending = &calld->pending_batches[i];
+    if (pending_batch_is_unstarted(pending, calld, retry_state)) {
+      if (grpc_client_channel_trace.enabled()) {
+        gpr_log(GPR_DEBUG,
+                "chand=%p calld=%p: failing unstarted pending batch at index "
+                "%" PRIuPTR,
+                chand, calld, i);
+      }
+      if (pending->batch->recv_initial_metadata) {
+        closure_to_execute* closure = &closures[(*num_closures)++];
+        closure->closure = pending->batch->payload->recv_initial_metadata
+                               .recv_initial_metadata_ready;
+        closure->error = GRPC_ERROR_REF(error);
+        closure->reason =
+            "failing recv_initial_metadata_ready for pending batch";
+        pending->batch->payload->recv_initial_metadata
+            .recv_initial_metadata_ready = nullptr;
+      }
+      if (pending->batch->recv_message) {
+        *pending->batch->payload->recv_message.recv_message = nullptr;
+        closure_to_execute* closure = &closures[(*num_closures)++];
+        closure->closure =
+            pending->batch->payload->recv_message.recv_message_ready;
+        closure->error = GRPC_ERROR_REF(error);
+        closure->reason = "failing recv_message_ready for pending batch";
+        pending->batch->payload->recv_message.recv_message_ready = nullptr;
+      }
+      closure_to_execute* closure = &closures[(*num_closures)++];
+      closure->closure = pending->batch->on_complete;
+      closure->error = GRPC_ERROR_REF(error);
+      closure->reason = "failing on_complete for pending batch";
+      pending->batch->on_complete = nullptr;
+      maybe_clear_pending_batch(elem, pending);
+    }
+  }
+  GRPC_ERROR_UNREF(error);
+}
+
+// Callback used to intercept on_complete from subchannel calls.
+// Called only when retries are enabled.
+static void on_complete(void* arg, grpc_error* error) {
+  subchannel_batch_data* batch_data = static_cast<subchannel_batch_data*>(arg);
+  grpc_call_element* elem = batch_data->elem;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  if (grpc_client_channel_trace.enabled()) {
+    char* batch_str = grpc_transport_stream_op_batch_string(&batch_data->batch);
+    gpr_log(GPR_DEBUG, "chand=%p calld=%p: got on_complete, error=%s, batch=%s",
+            chand, calld, grpc_error_string(error), batch_str);
+    gpr_free(batch_str);
+  }
+  subchannel_call_retry_state* retry_state =
+      static_cast<subchannel_call_retry_state*>(
+          grpc_connected_subchannel_call_get_parent_data(
+              batch_data->subchannel_call));
+  // If we have previously completed recv_trailing_metadata, then the
+  // call is finished.
+  bool call_finished = retry_state->completed_recv_trailing_metadata;
+  // Update bookkeeping in retry_state.
+  update_retry_state_for_completed_batch(batch_data, retry_state);
+  if (call_finished) {
+    if (grpc_client_channel_trace.enabled()) {
+      gpr_log(GPR_DEBUG, "chand=%p calld=%p: call already finished", chand,
+              calld);
+    }
+  } else {
+    // Check if this batch finished the call, and if so, get its status.
+    // The call is finished if either (a) this callback was invoked with
+    // an error or (b) we receive status.
+    grpc_status_code status = GRPC_STATUS_OK;
+    grpc_mdelem* server_pushback_md = nullptr;
+    if (error != GRPC_ERROR_NONE) {  // Case (a).
+      call_finished = true;
+      grpc_error_get_status(error, calld->deadline, &status, nullptr, nullptr,
+                            nullptr);
+    } else if (batch_data->batch.recv_trailing_metadata) {  // Case (b).
+      call_finished = true;
+      grpc_metadata_batch* md_batch =
+          batch_data->batch.payload->recv_trailing_metadata
+              .recv_trailing_metadata;
+      GPR_ASSERT(md_batch->idx.named.grpc_status != nullptr);
+      status = grpc_get_status_code_from_metadata(
+          md_batch->idx.named.grpc_status->md);
+      if (md_batch->idx.named.grpc_retry_pushback_ms != nullptr) {
+        server_pushback_md = &md_batch->idx.named.grpc_retry_pushback_ms->md;
+      }
+    } else if (retry_state->completed_recv_trailing_metadata) {
+      call_finished = true;
+    }
+    if (call_finished && grpc_client_channel_trace.enabled()) {
+      gpr_log(GPR_DEBUG, "chand=%p calld=%p: call finished, status=%s", chand,
+              calld, grpc_status_code_to_string(status));
+    }
+    // If the call is finished, check if we should retry.
+    if (call_finished &&
+        maybe_retry(elem, batch_data, status, server_pushback_md)) {
+      // Unref batch_data for deferred recv_initial_metadata_ready or
+      // recv_message_ready callbacks, if any.
+      if (batch_data->batch.recv_trailing_metadata &&
+          retry_state->recv_initial_metadata_ready_deferred) {
+        batch_data_unref(batch_data);
+        GRPC_ERROR_UNREF(retry_state->recv_initial_metadata_error);
+      }
+      if (batch_data->batch.recv_trailing_metadata &&
+          retry_state->recv_message_ready_deferred) {
+        batch_data_unref(batch_data);
+        GRPC_ERROR_UNREF(retry_state->recv_message_error);
+      }
+      batch_data_unref(batch_data);
+      return;
+    }
+  }
+  // If the call is finished or retries are committed, free cached data for
+  // send ops that we've just completed.
+  if (call_finished || calld->retry_committed) {
+    free_cached_send_op_data_for_completed_batch(elem, batch_data, retry_state);
+  }
+  // Call not being retried.
+  // Construct list of closures to execute.
+  // Max number of closures is number of pending batches plus one for
+  // each of:
+  // - recv_initial_metadata_ready (either deferred or unstarted)
+  // - recv_message_ready (either deferred or unstarted)
+  // - starting a new batch for pending send ops
+  closure_to_execute closures[GPR_ARRAY_SIZE(calld->pending_batches) + 3];
+  size_t num_closures = 0;
+  // If there are deferred recv_initial_metadata_ready or recv_message_ready
+  // callbacks, add them to closures.
+  add_closures_for_deferred_recv_callbacks(batch_data, retry_state, closures,
+                                           &num_closures);
+  // Find pending batches whose ops are now complete and add their
+  // on_complete callbacks to closures.
+  add_closures_for_completed_pending_batches(elem, batch_data, retry_state,
+                                             GRPC_ERROR_REF(error), closures,
+                                             &num_closures);
+  // Add closures to handle any pending batches that have not yet been started.
+  // If the call is finished, we fail these batches; otherwise, we add a
+  // callback to start_retriable_subchannel_batches() to start them on
+  // the subchannel call.
+  if (call_finished) {
+    add_closures_to_fail_unstarted_pending_batches(
+        elem, retry_state, GRPC_ERROR_REF(error), closures, &num_closures);
+  } else {
+    add_closures_for_replay_or_pending_send_ops(elem, batch_data, retry_state,
+                                                closures, &num_closures);
+  }
+  // Don't need batch_data anymore.
+  batch_data_unref(batch_data);
+  // Schedule all of the closures identified above.
+  // Note that the call combiner will be yielded for each closure that
+  // we schedule.  We're already running in the call combiner, so one of
+  // the closures can be scheduled directly, but the others will
+  // have to re-enter the call combiner.
+  if (num_closures > 0) {
+    GRPC_CLOSURE_SCHED(closures[0].closure, closures[0].error);
+    for (size_t i = 1; i < num_closures; ++i) {
+      GRPC_CALL_COMBINER_START(calld->call_combiner, closures[i].closure,
+                               closures[i].error, closures[i].reason);
+    }
+  } else {
+    GRPC_CALL_COMBINER_STOP(calld->call_combiner,
+                            "no closures to run for on_complete");
+  }
+}
+
+//
+// subchannel batch construction
+//
+
+// Helper function used to start a subchannel batch in the call combiner.
+static void start_batch_in_call_combiner(void* arg, grpc_error* ignored) {
+  grpc_transport_stream_op_batch* batch =
+      static_cast<grpc_transport_stream_op_batch*>(arg);
+  grpc_subchannel_call* subchannel_call =
+      static_cast<grpc_subchannel_call*>(batch->handler_private.extra_arg);
+  // Note: This will release the call combiner.
+  grpc_subchannel_call_process_op(subchannel_call, batch);
+}
+
+// Adds retriable send_initial_metadata op to batch_data.
+static void add_retriable_send_initial_metadata_op(
+    call_data* calld, subchannel_call_retry_state* retry_state,
+    subchannel_batch_data* batch_data) {
+  // Maps the number of retries to the corresponding metadata value slice.
+  static const grpc_slice* retry_count_strings[] = {
+      &GRPC_MDSTR_1, &GRPC_MDSTR_2, &GRPC_MDSTR_3, &GRPC_MDSTR_4};
+  // We need to make a copy of the metadata batch for each attempt, since
+  // the filters in the subchannel stack may modify this batch, and we don't
+  // want those modifications to be passed forward to subsequent attempts.
+  //
+  // If we've already completed one or more attempts, add the
+  // grpc-retry-attempts header.
+  batch_data->send_initial_metadata_storage =
+      static_cast<grpc_linked_mdelem*>(gpr_arena_alloc(
+          calld->arena, sizeof(grpc_linked_mdelem) *
+                            (calld->send_initial_metadata.list.count +
+                             (calld->num_attempts_completed > 0))));
+  grpc_metadata_batch_copy(&calld->send_initial_metadata,
+                           &batch_data->send_initial_metadata,
+                           batch_data->send_initial_metadata_storage);
+  if (batch_data->send_initial_metadata.idx.named.grpc_previous_rpc_attempts !=
+      nullptr) {
+    grpc_metadata_batch_remove(
+        &batch_data->send_initial_metadata,
+        batch_data->send_initial_metadata.idx.named.grpc_previous_rpc_attempts);
+  }
+  if (calld->num_attempts_completed > 0) {
+    grpc_mdelem retry_md = grpc_mdelem_from_slices(
+        GRPC_MDSTR_GRPC_PREVIOUS_RPC_ATTEMPTS,
+        *retry_count_strings[calld->num_attempts_completed - 1]);
+    grpc_error* error = grpc_metadata_batch_add_tail(
+        &batch_data->send_initial_metadata,
+        &batch_data->send_initial_metadata_storage[calld->send_initial_metadata
+                                                       .list.count],
+        retry_md);
+    if (error != GRPC_ERROR_NONE) {
+      gpr_log(GPR_ERROR, "error adding retry metadata: %s",
+              grpc_error_string(error));
+      GPR_ASSERT(false);
+    }
+  }
+  retry_state->started_send_initial_metadata = true;
+  batch_data->batch.send_initial_metadata = true;
+  batch_data->batch.payload->send_initial_metadata.send_initial_metadata =
+      &batch_data->send_initial_metadata;
+  batch_data->batch.payload->send_initial_metadata.send_initial_metadata_flags =
+      calld->send_initial_metadata_flags;
+  batch_data->batch.payload->send_initial_metadata.peer_string =
+      calld->peer_string;
+}
+
+// Adds retriable send_message op to batch_data.
+static void add_retriable_send_message_op(
+    grpc_call_element* elem, subchannel_call_retry_state* retry_state,
+    subchannel_batch_data* batch_data) {
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  if (grpc_client_channel_trace.enabled()) {
+    gpr_log(GPR_DEBUG,
+            "chand=%p calld=%p: starting calld->send_messages[%" PRIuPTR "]",
+            chand, calld, retry_state->started_send_message_count);
+  }
+  grpc_core::ByteStreamCache* cache =
+      calld->send_messages[retry_state->started_send_message_count];
+  ++retry_state->started_send_message_count;
+  batch_data->send_message.Init(cache);
+  batch_data->batch.send_message = true;
+  batch_data->batch.payload->send_message.send_message.reset(
+      batch_data->send_message.get());
+}
+
+// Adds retriable send_trailing_metadata op to batch_data.
+static void add_retriable_send_trailing_metadata_op(
+    call_data* calld, subchannel_call_retry_state* retry_state,
+    subchannel_batch_data* batch_data) {
+  // We need to make a copy of the metadata batch for each attempt, since
+  // the filters in the subchannel stack may modify this batch, and we don't
+  // want those modifications to be passed forward to subsequent attempts.
+  batch_data->send_trailing_metadata_storage =
+      static_cast<grpc_linked_mdelem*>(gpr_arena_alloc(
+          calld->arena, sizeof(grpc_linked_mdelem) *
+                            calld->send_trailing_metadata.list.count));
+  grpc_metadata_batch_copy(&calld->send_trailing_metadata,
+                           &batch_data->send_trailing_metadata,
+                           batch_data->send_trailing_metadata_storage);
+  retry_state->started_send_trailing_metadata = true;
+  batch_data->batch.send_trailing_metadata = true;
+  batch_data->batch.payload->send_trailing_metadata.send_trailing_metadata =
+      &batch_data->send_trailing_metadata;
+}
+
+// Adds retriable recv_initial_metadata op to batch_data.
+static void add_retriable_recv_initial_metadata_op(
+    call_data* calld, subchannel_call_retry_state* retry_state,
+    subchannel_batch_data* batch_data) {
+  retry_state->started_recv_initial_metadata = true;
+  batch_data->batch.recv_initial_metadata = true;
+  grpc_metadata_batch_init(&batch_data->recv_initial_metadata);
+  batch_data->batch.payload->recv_initial_metadata.recv_initial_metadata =
+      &batch_data->recv_initial_metadata;
+  batch_data->batch.payload->recv_initial_metadata.trailing_metadata_available =
+      &batch_data->trailing_metadata_available;
+  GRPC_CLOSURE_INIT(&batch_data->recv_initial_metadata_ready,
+                    recv_initial_metadata_ready, batch_data,
+                    grpc_schedule_on_exec_ctx);
+  batch_data->batch.payload->recv_initial_metadata.recv_initial_metadata_ready =
+      &batch_data->recv_initial_metadata_ready;
+}
+
+// Adds retriable recv_message op to batch_data.
+static void add_retriable_recv_message_op(
+    call_data* calld, subchannel_call_retry_state* retry_state,
+    subchannel_batch_data* batch_data) {
+  ++retry_state->started_recv_message_count;
+  batch_data->batch.recv_message = true;
+  batch_data->batch.payload->recv_message.recv_message =
+      &batch_data->recv_message;
+  GRPC_CLOSURE_INIT(&batch_data->recv_message_ready, recv_message_ready,
+                    batch_data, grpc_schedule_on_exec_ctx);
+  batch_data->batch.payload->recv_message.recv_message_ready =
+      &batch_data->recv_message_ready;
+}
+
+// Adds retriable recv_trailing_metadata op to batch_data.
+static void add_retriable_recv_trailing_metadata_op(
+    call_data* calld, subchannel_call_retry_state* retry_state,
+    subchannel_batch_data* batch_data) {
+  retry_state->started_recv_trailing_metadata = true;
+  batch_data->batch.recv_trailing_metadata = true;
+  grpc_metadata_batch_init(&batch_data->recv_trailing_metadata);
+  batch_data->batch.payload->recv_trailing_metadata.recv_trailing_metadata =
+      &batch_data->recv_trailing_metadata;
+  batch_data->batch.collect_stats = true;
+  batch_data->batch.payload->collect_stats.collect_stats =
+      &batch_data->collect_stats;
+}
+
+// Helper function used to start a recv_trailing_metadata batch.  This
+// is used in the case where a recv_initial_metadata or recv_message
+// op fails in a way that we know the call is over but when the application
+// has not yet started its own recv_trailing_metadata op.
+static void start_internal_recv_trailing_metadata(grpc_call_element* elem) {
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  if (grpc_client_channel_trace.enabled()) {
+    gpr_log(GPR_DEBUG,
+            "chand=%p calld=%p: call failed but recv_trailing_metadata not "
+            "started; starting it internally",
+            chand, calld);
+  }
+  subchannel_call_retry_state* retry_state =
+      static_cast<subchannel_call_retry_state*>(
+          grpc_connected_subchannel_call_get_parent_data(
+              calld->subchannel_call));
+  subchannel_batch_data* batch_data = batch_data_create(elem, 1);
+  add_retriable_recv_trailing_metadata_op(calld, retry_state, batch_data);
+  // Note: This will release the call combiner.
+  grpc_subchannel_call_process_op(calld->subchannel_call, &batch_data->batch);
+}
+
+// If there are any cached send ops that need to be replayed on the
+// current subchannel call, creates and returns a new subchannel batch
+// to replay those ops.  Otherwise, returns nullptr.
+static subchannel_batch_data* maybe_create_subchannel_batch_for_replay(
+    grpc_call_element* elem, subchannel_call_retry_state* retry_state) {
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  subchannel_batch_data* replay_batch_data = nullptr;
+  // send_initial_metadata.
+  if (calld->seen_send_initial_metadata &&
+      !retry_state->started_send_initial_metadata &&
+      !calld->pending_send_initial_metadata) {
+    if (grpc_client_channel_trace.enabled()) {
+      gpr_log(GPR_DEBUG,
+              "chand=%p calld=%p: replaying previously completed "
+              "send_initial_metadata op",
+              chand, calld);
+    }
+    replay_batch_data = batch_data_create(elem, 1);
+    add_retriable_send_initial_metadata_op(calld, retry_state,
+                                           replay_batch_data);
+  }
+  // send_message.
+  // Note that we can only have one send_message op in flight at a time.
+  if (retry_state->started_send_message_count < calld->send_messages.size() &&
+      retry_state->started_send_message_count ==
+          retry_state->completed_send_message_count &&
+      !calld->pending_send_message) {
+    if (grpc_client_channel_trace.enabled()) {
+      gpr_log(GPR_DEBUG,
+              "chand=%p calld=%p: replaying previously completed "
+              "send_message op",
+              chand, calld);
+    }
+    if (replay_batch_data == nullptr) {
+      replay_batch_data = batch_data_create(elem, 1);
+    }
+    add_retriable_send_message_op(elem, retry_state, replay_batch_data);
+  }
+  // send_trailing_metadata.
+  // Note that we only add this op if we have no more send_message ops
+  // to start, since we can't send down any more send_message ops after
+  // send_trailing_metadata.
+  if (calld->seen_send_trailing_metadata &&
+      retry_state->started_send_message_count == calld->send_messages.size() &&
+      !retry_state->started_send_trailing_metadata &&
+      !calld->pending_send_trailing_metadata) {
+    if (grpc_client_channel_trace.enabled()) {
+      gpr_log(GPR_DEBUG,
+              "chand=%p calld=%p: replaying previously completed "
+              "send_trailing_metadata op",
+              chand, calld);
+    }
+    if (replay_batch_data == nullptr) {
+      replay_batch_data = batch_data_create(elem, 1);
+    }
+    add_retriable_send_trailing_metadata_op(calld, retry_state,
+                                            replay_batch_data);
+  }
+  return replay_batch_data;
+}
+
+// Adds subchannel batches for pending batches to batches, updating
+// *num_batches as needed.
+static void add_subchannel_batches_for_pending_batches(
+    grpc_call_element* elem, subchannel_call_retry_state* retry_state,
+    grpc_transport_stream_op_batch** batches, size_t* num_batches) {
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) {
+    pending_batch* pending = &calld->pending_batches[i];
+    grpc_transport_stream_op_batch* batch = pending->batch;
+    if (batch == nullptr) continue;
+    // Skip any batch that either (a) has already been started on this
+    // subchannel call or (b) we can't start yet because we're still
+    // replaying send ops that need to be completed first.
+    // TODO(roth): Note that if any one op in the batch can't be sent
+    // yet due to ops that we're replaying, we don't start any of the ops
+    // in the batch.  This is probably okay, but it could conceivably
+    // lead to increased latency in some cases -- e.g., we could delay
+    // starting a recv op due to it being in the same batch with a send
+    // op.  If/when we revamp the callback protocol in
+    // transport_stream_op_batch, we may be able to fix this.
+    if (batch->send_initial_metadata &&
+        retry_state->started_send_initial_metadata) {
+      continue;
+    }
+    if (batch->send_message && retry_state->completed_send_message_count <
+                                   retry_state->started_send_message_count) {
+      continue;
+    }
+    // Note that we only start send_trailing_metadata if we have no more
+    // send_message ops to start, since we can't send down any more
+    // send_message ops after send_trailing_metadata.
+    if (batch->send_trailing_metadata &&
+        (retry_state->started_send_message_count + batch->send_message <
+             calld->send_messages.size() ||
+         retry_state->started_send_trailing_metadata)) {
+      continue;
+    }
+    if (batch->recv_initial_metadata &&
+        retry_state->started_recv_initial_metadata) {
+      continue;
+    }
+    if (batch->recv_message && retry_state->completed_recv_message_count <
+                                   retry_state->started_recv_message_count) {
+      continue;
+    }
+    if (batch->recv_trailing_metadata &&
+        retry_state->started_recv_trailing_metadata) {
+      continue;
+    }
+    // If we're not retrying, just send the batch as-is.
+    if (calld->method_params == nullptr ||
+        calld->method_params->retry_policy() == nullptr ||
+        calld->retry_committed) {
+      batches[(*num_batches)++] = batch;
+      pending_batch_clear(calld, pending);
+      continue;
+    }
+    // Create batch with the right number of callbacks.
+    const int num_callbacks =
+        1 + batch->recv_initial_metadata + batch->recv_message;
+    subchannel_batch_data* batch_data = batch_data_create(elem, num_callbacks);
+    // Cache send ops if needed.
+    maybe_cache_send_ops_for_batch(calld, pending);
+    // send_initial_metadata.
+    if (batch->send_initial_metadata) {
+      add_retriable_send_initial_metadata_op(calld, retry_state, batch_data);
+    }
+    // send_message.
+    if (batch->send_message) {
+      add_retriable_send_message_op(elem, retry_state, batch_data);
+    }
+    // send_trailing_metadata.
+    if (batch->send_trailing_metadata) {
+      add_retriable_send_trailing_metadata_op(calld, retry_state, batch_data);
+    }
+    // recv_initial_metadata.
+    if (batch->recv_initial_metadata) {
+      // recv_flags is only used on the server side.
+      GPR_ASSERT(batch->payload->recv_initial_metadata.recv_flags == nullptr);
+      add_retriable_recv_initial_metadata_op(calld, retry_state, batch_data);
+    }
+    // recv_message.
+    if (batch->recv_message) {
+      add_retriable_recv_message_op(calld, retry_state, batch_data);
+    }
+    // recv_trailing_metadata.
+    if (batch->recv_trailing_metadata) {
+      GPR_ASSERT(batch->collect_stats);
+      add_retriable_recv_trailing_metadata_op(calld, retry_state, batch_data);
+    }
+    batches[(*num_batches)++] = &batch_data->batch;
+  }
+}
+
+// Constructs and starts whatever subchannel batches are needed on the
+// subchannel call.
+static void start_retriable_subchannel_batches(void* arg, grpc_error* ignored) {
+  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  if (grpc_client_channel_trace.enabled()) {
+    gpr_log(GPR_DEBUG, "chand=%p calld=%p: constructing retriable batches",
+            chand, calld);
+  }
+  subchannel_call_retry_state* retry_state =
+      static_cast<subchannel_call_retry_state*>(
+          grpc_connected_subchannel_call_get_parent_data(
+              calld->subchannel_call));
+  // We can start up to 6 batches.
+  grpc_transport_stream_op_batch*
+      batches[GPR_ARRAY_SIZE(calld->pending_batches)];
+  size_t num_batches = 0;
+  // Replay previously-returned send_* ops if needed.
+  subchannel_batch_data* replay_batch_data =
+      maybe_create_subchannel_batch_for_replay(elem, retry_state);
+  if (replay_batch_data != nullptr) {
+    batches[num_batches++] = &replay_batch_data->batch;
+  }
+  // Now add pending batches.
+  add_subchannel_batches_for_pending_batches(elem, retry_state, batches,
+                                             &num_batches);
+  // Start batches on subchannel call.
+  // Note that the call combiner will be yielded for each batch that we
+  // send down.  We're already running in the call combiner, so one of
+  // the batches can be started directly, but the others will have to
+  // re-enter the call combiner.
+  if (grpc_client_channel_trace.enabled()) {
+    gpr_log(GPR_DEBUG,
+            "chand=%p calld=%p: starting %" PRIuPTR
+            " retriable batches on subchannel_call=%p",
+            chand, calld, num_batches, calld->subchannel_call);
+  }
+  if (num_batches == 0) {
+    // This should be fairly rare, but it can happen when (e.g.) an
+    // attempt completes before it has finished replaying all
+    // previously sent messages.
+    GRPC_CALL_COMBINER_STOP(calld->call_combiner,
+                            "no retriable subchannel batches to start");
+  } else {
+    for (size_t i = 1; i < num_batches; ++i) {
+      if (grpc_client_channel_trace.enabled()) {
+        char* batch_str = grpc_transport_stream_op_batch_string(batches[i]);
+        gpr_log(GPR_DEBUG,
+                "chand=%p calld=%p: starting batch in call combiner: %s", chand,
+                calld, batch_str);
+        gpr_free(batch_str);
+      }
+      batches[i]->handler_private.extra_arg = calld->subchannel_call;
+      GRPC_CLOSURE_INIT(&batches[i]->handler_private.closure,
+                        start_batch_in_call_combiner, batches[i],
+                        grpc_schedule_on_exec_ctx);
+      GRPC_CALL_COMBINER_START(calld->call_combiner,
+                               &batches[i]->handler_private.closure,
+                               GRPC_ERROR_NONE, "start_subchannel_batch");
+    }
+    if (grpc_client_channel_trace.enabled()) {
+      char* batch_str = grpc_transport_stream_op_batch_string(batches[0]);
+      gpr_log(GPR_DEBUG, "chand=%p calld=%p: starting batch: %s", chand, calld,
+              batch_str);
+      gpr_free(batch_str);
+    }
+    // Note: This will release the call combiner.
+    grpc_subchannel_call_process_op(calld->subchannel_call, batches[0]);
+  }
+}
+
+//
+// LB pick
+//
+
+static void create_subchannel_call(grpc_call_element* elem, grpc_error* error) {
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  const size_t parent_data_size =
+      calld->enable_retries ? sizeof(subchannel_call_retry_state) : 0;
   const grpc_core::ConnectedSubchannel::CallArgs call_args = {
       calld->pollent,                       // pollent
       calld->path,                          // path
@@ -1010,7 +2478,8 @@
       calld->deadline,                      // deadline
       calld->arena,                         // arena
       calld->pick.subchannel_call_context,  // context
-      calld->call_combiner                  // call_combiner
+      calld->call_combiner,                 // call_combiner
+      parent_data_size                      // parent_data_size
   };
   grpc_error* new_error = calld->pick.connected_subchannel->CreateCall(
       call_args, &calld->subchannel_call);
@@ -1020,36 +2489,61 @@
   }
   if (new_error != GRPC_ERROR_NONE) {
     new_error = grpc_error_add_child(new_error, error);
-    waiting_for_pick_batches_fail(elem, new_error);
+    pending_batches_fail(elem, new_error, true /* yield_call_combiner */);
   } else {
-    waiting_for_pick_batches_resume(elem);
+    if (parent_data_size > 0) {
+      subchannel_call_retry_state* retry_state =
+          static_cast<subchannel_call_retry_state*>(
+              grpc_connected_subchannel_call_get_parent_data(
+                  calld->subchannel_call));
+      retry_state->batch_payload.context = calld->pick.subchannel_call_context;
+    }
+    pending_batches_resume(elem);
   }
   GRPC_ERROR_UNREF(error);
 }
 
 // Invoked when a pick is completed, on both success or failure.
-static void pick_done_locked(grpc_call_element* elem, grpc_error* error) {
-  call_data* calld = (call_data*)elem->call_data;
-  channel_data* chand = (channel_data*)elem->channel_data;
+static void pick_done(void* arg, grpc_error* error) {
+  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   if (calld->pick.connected_subchannel == nullptr) {
     // Failed to create subchannel.
-    GRPC_ERROR_UNREF(calld->error);
-    calld->error = error == GRPC_ERROR_NONE
-                       ? GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-                             "Call dropped by load balancing policy")
-                       : GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-                             "Failed to create subchannel", &error, 1);
-    if (grpc_client_channel_trace.enabled()) {
-      gpr_log(GPR_DEBUG,
-              "chand=%p calld=%p: failed to create subchannel: error=%s", chand,
-              calld, grpc_error_string(calld->error));
+    // If there was no error, this is an LB policy drop, in which case
+    // we return an error; otherwise, we may retry.
+    grpc_status_code status = GRPC_STATUS_OK;
+    grpc_error_get_status(error, calld->deadline, &status, nullptr, nullptr,
+                          nullptr);
+    if (error == GRPC_ERROR_NONE || !calld->enable_retries ||
+        !maybe_retry(elem, nullptr /* batch_data */, status,
+                     nullptr /* server_pushback_md */)) {
+      grpc_error* new_error =
+          error == GRPC_ERROR_NONE
+              ? GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                    "Call dropped by load balancing policy")
+              : GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+                    "Failed to create subchannel", &error, 1);
+      if (grpc_client_channel_trace.enabled()) {
+        gpr_log(GPR_DEBUG,
+                "chand=%p calld=%p: failed to create subchannel: error=%s",
+                chand, calld, grpc_error_string(new_error));
+      }
+      pending_batches_fail(elem, new_error, true /* yield_call_combiner */);
     }
-    waiting_for_pick_batches_fail(elem, GRPC_ERROR_REF(calld->error));
   } else {
     /* Create call on subchannel. */
-    create_subchannel_call_locked(elem, GRPC_ERROR_REF(error));
+    create_subchannel_call(elem, GRPC_ERROR_REF(error));
   }
-  GRPC_ERROR_UNREF(error);
+}
+
+// Invoked when a pick is completed to leave the client_channel combiner
+// and continue processing in the call combiner.
+static void pick_done_locked(grpc_call_element* elem, grpc_error* error) {
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  GRPC_CLOSURE_INIT(&calld->pick_closure, pick_done, elem,
+                    grpc_schedule_on_exec_ctx);
+  GRPC_CLOSURE_SCHED(&calld->pick_closure, error);
 }
 
 // A wrapper around pick_done_locked() that is used in cases where
@@ -1057,8 +2551,8 @@
 // pick was done asynchronously.  Removes the call's polling entity from
 // chand->interested_parties before invoking pick_done_locked().
 static void async_pick_done_locked(grpc_call_element* elem, grpc_error* error) {
-  channel_data* chand = (channel_data*)elem->channel_data;
-  call_data* calld = (call_data*)elem->call_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   grpc_polling_entity_del_from_pollset_set(calld->pollent,
                                            chand->interested_parties);
   pick_done_locked(elem, error);
@@ -1067,86 +2561,138 @@
 // Note: This runs under the client_channel combiner, but will NOT be
 // holding the call combiner.
 static void pick_callback_cancel_locked(void* arg, grpc_error* error) {
-  grpc_call_element* elem = (grpc_call_element*)arg;
-  channel_data* chand = (channel_data*)elem->channel_data;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   // Note: chand->lb_policy may have changed since we started our pick,
   // in which case we will be cancelling the pick on a policy other than
   // the one we started it on.  However, this will just be a no-op.
   if (error != GRPC_ERROR_NONE && chand->lb_policy != nullptr) {
     if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG, "chand=%p calld=%p: cancelling pick from LB policy %p",
-              chand, calld, chand->lb_policy);
+              chand, calld, chand->lb_policy.get());
     }
-    grpc_lb_policy_cancel_pick_locked(chand->lb_policy, &calld->pick,
-                                      GRPC_ERROR_REF(error));
+    chand->lb_policy->CancelPickLocked(&calld->pick, GRPC_ERROR_REF(error));
   }
   GRPC_CALL_STACK_UNREF(calld->owning_call, "pick_callback_cancel");
 }
 
-// Callback invoked by grpc_lb_policy_pick_locked() for async picks.
+// Callback invoked by LoadBalancingPolicy::PickLocked() for async picks.
 // Unrefs the LB policy and invokes async_pick_done_locked().
 static void pick_callback_done_locked(void* arg, grpc_error* error) {
-  grpc_call_element* elem = (grpc_call_element*)arg;
-  channel_data* chand = (channel_data*)elem->channel_data;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_DEBUG, "chand=%p calld=%p: pick completed asynchronously",
             chand, calld);
   }
   async_pick_done_locked(elem, GRPC_ERROR_REF(error));
+  GRPC_CALL_STACK_UNREF(calld->owning_call, "pick_callback");
 }
 
-// Takes a ref to chand->lb_policy and calls grpc_lb_policy_pick_locked().
-// If the pick was completed synchronously, unrefs the LB policy and
-// returns true.
+// Applies service config to the call.  Must be invoked once we know
+// that the resolver has returned results to the channel.
+static void apply_service_config_to_call_locked(grpc_call_element* elem) {
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  if (grpc_client_channel_trace.enabled()) {
+    gpr_log(GPR_DEBUG, "chand=%p calld=%p: applying service config to call",
+            chand, calld);
+  }
+  if (chand->retry_throttle_data != nullptr) {
+    calld->retry_throttle_data =
+        grpc_server_retry_throttle_data_ref(chand->retry_throttle_data);
+  }
+  if (chand->method_params_table != nullptr) {
+    calld->method_params = grpc_core::ServiceConfig::MethodConfigTableLookup(
+        *chand->method_params_table, calld->path);
+    if (calld->method_params != nullptr) {
+      // If the deadline from the service config is shorter than the one
+      // from the client API, reset the deadline timer.
+      if (chand->deadline_checking_enabled &&
+          calld->method_params->timeout() != 0) {
+        const grpc_millis per_method_deadline =
+            grpc_timespec_to_millis_round_up(calld->call_start_time) +
+            calld->method_params->timeout();
+        if (per_method_deadline < calld->deadline) {
+          calld->deadline = per_method_deadline;
+          grpc_deadline_state_reset(elem, calld->deadline);
+        }
+      }
+    }
+  }
+  // If no retry policy, disable retries.
+  // TODO(roth): Remove this when adding support for transparent retries.
+  if (calld->method_params == nullptr ||
+      calld->method_params->retry_policy() == nullptr) {
+    calld->enable_retries = false;
+  }
+}
+
+// Starts a pick on chand->lb_policy.
+// Returns true if pick is completed synchronously.
 static bool pick_callback_start_locked(grpc_call_element* elem) {
-  channel_data* chand = (channel_data*)elem->channel_data;
-  call_data* calld = (call_data*)elem->call_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_DEBUG, "chand=%p calld=%p: starting pick on lb_policy=%p",
-            chand, calld, chand->lb_policy);
+            chand, calld, chand->lb_policy.get());
   }
-  apply_service_config_to_call_locked(elem);
+  // Only get service config data on the first attempt.
+  if (calld->num_attempts_completed == 0) {
+    apply_service_config_to_call_locked(elem);
+  }
   // If the application explicitly set wait_for_ready, use that.
   // Otherwise, if the service config specified a value for this
   // method, use that.
-  uint32_t initial_metadata_flags =
-      calld->initial_metadata_batch->payload->send_initial_metadata
-          .send_initial_metadata_flags;
+  //
+  // The send_initial_metadata batch will be the first one in the list,
+  // as set by get_batch_index() above.
+  calld->pick.initial_metadata =
+      calld->seen_send_initial_metadata
+          ? &calld->send_initial_metadata
+          : calld->pending_batches[0]
+                .batch->payload->send_initial_metadata.send_initial_metadata;
+  uint32_t send_initial_metadata_flags =
+      calld->seen_send_initial_metadata
+          ? calld->send_initial_metadata_flags
+          : calld->pending_batches[0]
+                .batch->payload->send_initial_metadata
+                .send_initial_metadata_flags;
   const bool wait_for_ready_set_from_api =
-      initial_metadata_flags &
+      send_initial_metadata_flags &
       GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET;
   const bool wait_for_ready_set_from_service_config =
       calld->method_params != nullptr &&
-      calld->method_params->wait_for_ready != WAIT_FOR_READY_UNSET;
+      calld->method_params->wait_for_ready() !=
+          ClientChannelMethodParams::WAIT_FOR_READY_UNSET;
   if (!wait_for_ready_set_from_api && wait_for_ready_set_from_service_config) {
-    if (calld->method_params->wait_for_ready == WAIT_FOR_READY_TRUE) {
-      initial_metadata_flags |= GRPC_INITIAL_METADATA_WAIT_FOR_READY;
+    if (calld->method_params->wait_for_ready() ==
+        ClientChannelMethodParams::WAIT_FOR_READY_TRUE) {
+      send_initial_metadata_flags |= GRPC_INITIAL_METADATA_WAIT_FOR_READY;
     } else {
-      initial_metadata_flags &= ~GRPC_INITIAL_METADATA_WAIT_FOR_READY;
+      send_initial_metadata_flags &= ~GRPC_INITIAL_METADATA_WAIT_FOR_READY;
     }
   }
-  calld->pick.initial_metadata =
-      calld->initial_metadata_batch->payload->send_initial_metadata
-          .send_initial_metadata;
-  calld->pick.initial_metadata_flags = initial_metadata_flags;
-  GRPC_CLOSURE_INIT(&calld->lb_pick_closure, pick_callback_done_locked, elem,
+  calld->pick.initial_metadata_flags = send_initial_metadata_flags;
+  GRPC_CLOSURE_INIT(&calld->pick_closure, pick_callback_done_locked, elem,
                     grpc_combiner_scheduler(chand->combiner));
-  calld->pick.on_complete = &calld->lb_pick_closure;
-  const bool pick_done =
-      grpc_lb_policy_pick_locked(chand->lb_policy, &calld->pick);
+  calld->pick.on_complete = &calld->pick_closure;
+  GRPC_CALL_STACK_REF(calld->owning_call, "pick_callback");
+  const bool pick_done = chand->lb_policy->PickLocked(&calld->pick);
   if (pick_done) {
-    /* synchronous grpc_lb_policy_pick call. Unref the LB policy. */
+    // Pick completed synchronously.
     if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG, "chand=%p calld=%p: pick completed synchronously",
               chand, calld);
     }
+    GRPC_CALL_STACK_UNREF(calld->owning_call, "pick_callback");
   } else {
     GRPC_CALL_STACK_REF(calld->owning_call, "pick_callback_cancel");
     grpc_call_combiner_set_notify_on_cancel(
         calld->call_combiner,
-        GRPC_CLOSURE_INIT(&calld->lb_pick_cancel_closure,
+        GRPC_CLOSURE_INIT(&calld->pick_cancel_closure,
                           pick_callback_cancel_locked, elem,
                           grpc_combiner_scheduler(chand->combiner)));
   }
@@ -1164,7 +2710,8 @@
 // holding the call combiner.
 static void pick_after_resolver_result_cancel_locked(void* arg,
                                                      grpc_error* error) {
-  pick_after_resolver_result_args* args = (pick_after_resolver_result_args*)arg;
+  pick_after_resolver_result_args* args =
+      static_cast<pick_after_resolver_result_args*>(arg);
   if (args->finished) {
     gpr_free(args);
     return;
@@ -1178,8 +2725,8 @@
   // async_pick_done_locked() to propagate the error back to the caller.
   args->finished = true;
   grpc_call_element* elem = args->elem;
-  channel_data* chand = (channel_data*)elem->channel_data;
-  call_data* calld = (call_data*)elem->call_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_DEBUG,
             "chand=%p calld=%p: cancelling pick waiting for resolver result",
@@ -1194,11 +2741,10 @@
                                    "Pick cancelled", &error, 1));
 }
 
-static void pick_after_resolver_result_start_locked(grpc_call_element* elem);
-
 static void pick_after_resolver_result_done_locked(void* arg,
                                                    grpc_error* error) {
-  pick_after_resolver_result_args* args = (pick_after_resolver_result_args*)arg;
+  pick_after_resolver_result_args* args =
+      static_cast<pick_after_resolver_result_args*>(arg);
   if (args->finished) {
     /* cancelled, do nothing */
     if (grpc_client_channel_trace.enabled()) {
@@ -1209,15 +2755,53 @@
   }
   args->finished = true;
   grpc_call_element* elem = args->elem;
-  channel_data* chand = (channel_data*)elem->channel_data;
-  call_data* calld = (call_data*)elem->call_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   if (error != GRPC_ERROR_NONE) {
     if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG, "chand=%p calld=%p: resolver failed to return data",
               chand, calld);
     }
     async_pick_done_locked(elem, GRPC_ERROR_REF(error));
-  } else if (chand->lb_policy != nullptr) {
+  } else if (chand->resolver == nullptr) {
+    // Shutting down.
+    if (grpc_client_channel_trace.enabled()) {
+      gpr_log(GPR_DEBUG, "chand=%p calld=%p: resolver disconnected", chand,
+              calld);
+    }
+    async_pick_done_locked(
+        elem, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Disconnected"));
+  } else if (chand->lb_policy == nullptr) {
+    // Transient resolver failure.
+    // If call has wait_for_ready=true, try again; otherwise, fail.
+    uint32_t send_initial_metadata_flags =
+        calld->seen_send_initial_metadata
+            ? calld->send_initial_metadata_flags
+            : calld->pending_batches[0]
+                  .batch->payload->send_initial_metadata
+                  .send_initial_metadata_flags;
+    if (send_initial_metadata_flags & GRPC_INITIAL_METADATA_WAIT_FOR_READY) {
+      if (grpc_client_channel_trace.enabled()) {
+        gpr_log(GPR_DEBUG,
+                "chand=%p calld=%p: resolver returned but no LB policy; "
+                "wait_for_ready=true; trying again",
+                chand, calld);
+      }
+      pick_after_resolver_result_start_locked(elem);
+    } else {
+      if (grpc_client_channel_trace.enabled()) {
+        gpr_log(GPR_DEBUG,
+                "chand=%p calld=%p: resolver returned but no LB policy; "
+                "wait_for_ready=false; failing",
+                chand, calld);
+      }
+      async_pick_done_locked(
+          elem,
+          grpc_error_set_int(
+              GRPC_ERROR_CREATE_FROM_STATIC_STRING("Name resolution failure"),
+              GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
+    }
+  } else {
     if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG, "chand=%p calld=%p: resolver returned, doing pick",
               chand, calld);
@@ -1231,42 +2815,18 @@
       async_pick_done_locked(elem, GRPC_ERROR_NONE);
     }
   }
-  // TODO(roth): It should be impossible for chand->lb_policy to be NULL
-  // here, so the rest of this code should never actually be executed.
-  // However, we have reports of a crash on iOS that triggers this case,
-  // so we are temporarily adding this to restore branches that were
-  // removed in https://github.com/grpc/grpc/pull/12297.  Need to figure
-  // out what is actually causing this to occur and then figure out the
-  // right way to deal with it.
-  else if (chand->resolver != nullptr) {
-    // No LB policy, so try again.
-    if (grpc_client_channel_trace.enabled()) {
-      gpr_log(GPR_DEBUG,
-              "chand=%p calld=%p: resolver returned but no LB policy, "
-              "trying again",
-              chand, calld);
-    }
-    pick_after_resolver_result_start_locked(elem);
-  } else {
-    if (grpc_client_channel_trace.enabled()) {
-      gpr_log(GPR_DEBUG, "chand=%p calld=%p: resolver disconnected", chand,
-              calld);
-    }
-    async_pick_done_locked(
-        elem, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Disconnected"));
-  }
 }
 
 static void pick_after_resolver_result_start_locked(grpc_call_element* elem) {
-  channel_data* chand = (channel_data*)elem->channel_data;
-  call_data* calld = (call_data*)elem->call_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_DEBUG,
             "chand=%p calld=%p: deferring pick pending resolver result", chand,
             calld);
   }
   pick_after_resolver_result_args* args =
-      (pick_after_resolver_result_args*)gpr_zalloc(sizeof(*args));
+      static_cast<pick_after_resolver_result_args*>(gpr_zalloc(sizeof(*args)));
   args->elem = elem;
   GRPC_CLOSURE_INIT(&args->closure, pick_after_resolver_result_done_locked,
                     args, grpc_combiner_scheduler(chand->combiner));
@@ -1280,10 +2840,11 @@
 }
 
 static void start_pick_locked(void* arg, grpc_error* ignored) {
-  grpc_call_element* elem = (grpc_call_element*)arg;
-  call_data* calld = (call_data*)elem->call_data;
-  channel_data* chand = (channel_data*)elem->channel_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   GPR_ASSERT(calld->pick.connected_subchannel == nullptr);
+  GPR_ASSERT(calld->subchannel_call == nullptr);
   if (chand->lb_policy != nullptr) {
     // We already have an LB policy, so ask it for a pick.
     if (pick_callback_start_locked(elem)) {
@@ -1312,74 +2873,60 @@
                                          chand->interested_parties);
 }
 
-static void on_complete(void* arg, grpc_error* error) {
-  grpc_call_element* elem = (grpc_call_element*)arg;
-  call_data* calld = (call_data*)elem->call_data;
-  if (calld->retry_throttle_data != nullptr) {
-    if (error == GRPC_ERROR_NONE) {
-      grpc_server_retry_throttle_data_record_success(
-          calld->retry_throttle_data);
-    } else {
-      // TODO(roth): In a subsequent PR, check the return value here and
-      // decide whether or not to retry.  Note that we should only
-      // record failures whose statuses match the configured retryable
-      // or non-fatal status codes.
-      grpc_server_retry_throttle_data_record_failure(
-          calld->retry_throttle_data);
-    }
-  }
-  GRPC_CLOSURE_RUN(calld->original_on_complete, GRPC_ERROR_REF(error));
-}
+//
+// filter call vtable functions
+//
 
 static void cc_start_transport_stream_op_batch(
     grpc_call_element* elem, grpc_transport_stream_op_batch* batch) {
   GPR_TIMER_SCOPE("cc_start_transport_stream_op_batch", 0);
-  call_data* calld = (call_data*)elem->call_data;
-  channel_data* chand = (channel_data*)elem->channel_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   if (chand->deadline_checking_enabled) {
     grpc_deadline_state_client_start_transport_stream_op_batch(elem, batch);
   }
   // If we've previously been cancelled, immediately fail any new batches.
-  if (calld->error != GRPC_ERROR_NONE) {
+  if (calld->cancel_error != GRPC_ERROR_NONE) {
     if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG, "chand=%p calld=%p: failing batch with error: %s",
-              chand, calld, grpc_error_string(calld->error));
+              chand, calld, grpc_error_string(calld->cancel_error));
     }
+    // Note: This will release the call combiner.
     grpc_transport_stream_op_batch_finish_with_failure(
-        batch, GRPC_ERROR_REF(calld->error), calld->call_combiner);
+        batch, GRPC_ERROR_REF(calld->cancel_error), calld->call_combiner);
     return;
   }
+  // Handle cancellation.
   if (batch->cancel_stream) {
     // Stash a copy of cancel_error in our call data, so that we can use
     // it for subsequent operations.  This ensures that if the call is
     // cancelled before any batches are passed down (e.g., if the deadline
     // is in the past when the call starts), we can return the right
     // error to the caller when the first batch does get passed down.
-    GRPC_ERROR_UNREF(calld->error);
-    calld->error = GRPC_ERROR_REF(batch->payload->cancel_stream.cancel_error);
+    GRPC_ERROR_UNREF(calld->cancel_error);
+    calld->cancel_error =
+        GRPC_ERROR_REF(batch->payload->cancel_stream.cancel_error);
     if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG, "chand=%p calld=%p: recording cancel_error=%s", chand,
-              calld, grpc_error_string(calld->error));
+              calld, grpc_error_string(calld->cancel_error));
     }
-    // If we have a subchannel call, send the cancellation batch down.
-    // Otherwise, fail all pending batches.
-    if (calld->subchannel_call != nullptr) {
-      grpc_subchannel_call_process_op(calld->subchannel_call, batch);
+    // If we do not have a subchannel call (i.e., a pick has not yet
+    // been started), fail all pending batches.  Otherwise, send the
+    // cancellation down to the subchannel call.
+    if (calld->subchannel_call == nullptr) {
+      pending_batches_fail(elem, GRPC_ERROR_REF(calld->cancel_error),
+                           false /* yield_call_combiner */);
+      // Note: This will release the call combiner.
+      grpc_transport_stream_op_batch_finish_with_failure(
+          batch, GRPC_ERROR_REF(calld->cancel_error), calld->call_combiner);
     } else {
-      waiting_for_pick_batches_add(calld, batch);
-      waiting_for_pick_batches_fail(elem, GRPC_ERROR_REF(calld->error));
+      // Note: This will release the call combiner.
+      grpc_subchannel_call_process_op(calld->subchannel_call, batch);
     }
     return;
   }
-  // Intercept on_complete for recv_trailing_metadata so that we can
-  // check retry throttle status.
-  if (batch->recv_trailing_metadata) {
-    GPR_ASSERT(batch->on_complete != nullptr);
-    calld->original_on_complete = batch->on_complete;
-    GRPC_CLOSURE_INIT(&calld->on_complete, on_complete, elem,
-                      grpc_schedule_on_exec_ctx);
-    batch->on_complete = &calld->on_complete;
-  }
+  // Add the batch to the pending list.
+  pending_batches_add(elem, batch);
   // Check if we've already gotten a subchannel call.
   // Note that once we have completed the pick, we do not need to enter
   // the channel combiner, which is more efficient (especially for
@@ -1387,15 +2934,13 @@
   if (calld->subchannel_call != nullptr) {
     if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG,
-              "chand=%p calld=%p: sending batch to subchannel_call=%p", chand,
+              "chand=%p calld=%p: starting batch on subchannel_call=%p", chand,
               calld, calld->subchannel_call);
     }
-    grpc_subchannel_call_process_op(calld->subchannel_call, batch);
+    pending_batches_resume(elem);
     return;
   }
   // We do not yet have a subchannel call.
-  // Add the batch to the waiting-for-pick list.
-  waiting_for_pick_batches_add(calld, batch);
   // For batches containing a send_initial_metadata op, enter the channel
   // combiner to start a pick.
   if (batch->send_initial_metadata) {
@@ -1422,8 +2967,8 @@
 /* Constructor for call_data */
 static grpc_error* cc_init_call_elem(grpc_call_element* elem,
                                      const grpc_call_element_args* args) {
-  call_data* calld = (call_data*)elem->call_data;
-  channel_data* chand = (channel_data*)elem->channel_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   // Initialize data members.
   calld->path = grpc_slice_ref_internal(args->path);
   calld->call_start_time = args->start_time;
@@ -1435,6 +2980,7 @@
     grpc_deadline_state_init(elem, args->call_stack, args->call_combiner,
                              calld->deadline);
   }
+  calld->enable_retries = chand->enable_retries;
   return GRPC_ERROR_NONE;
 }
 
@@ -1442,16 +2988,14 @@
 static void cc_destroy_call_elem(grpc_call_element* elem,
                                  const grpc_call_final_info* final_info,
                                  grpc_closure* then_schedule_closure) {
-  call_data* calld = (call_data*)elem->call_data;
-  channel_data* chand = (channel_data*)elem->channel_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   if (chand->deadline_checking_enabled) {
     grpc_deadline_state_destroy(elem);
   }
   grpc_slice_unref_internal(calld->path);
-  if (calld->method_params != nullptr) {
-    method_parameters_unref(calld->method_params);
-  }
-  GRPC_ERROR_UNREF(calld->error);
+  calld->method_params.reset();
+  GRPC_ERROR_UNREF(calld->cancel_error);
   if (calld->subchannel_call != nullptr) {
     grpc_subchannel_call_set_cleanup_closure(calld->subchannel_call,
                                              then_schedule_closure);
@@ -1459,7 +3003,9 @@
     GRPC_SUBCHANNEL_CALL_UNREF(calld->subchannel_call,
                                "client_channel_destroy_call");
   }
-  GPR_ASSERT(calld->waiting_for_pick_batches_count == 0);
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) {
+    GPR_ASSERT(calld->pending_batches[i].batch == nullptr);
+  }
   if (calld->pick.connected_subchannel != nullptr) {
     calld->pick.connected_subchannel.reset();
   }
@@ -1474,7 +3020,7 @@
 
 static void cc_set_pollset_or_pollset_set(grpc_call_element* elem,
                                           grpc_polling_entity* pollent) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   calld->pollent = pollent;
 }
 
@@ -1497,9 +3043,9 @@
 };
 
 static void try_to_connect_locked(void* arg, grpc_error* error_ignored) {
-  channel_data* chand = (channel_data*)arg;
+  channel_data* chand = static_cast<channel_data*>(arg);
   if (chand->lb_policy != nullptr) {
-    grpc_lb_policy_exit_idle_locked(chand->lb_policy);
+    chand->lb_policy->ExitIdleLocked();
   } else {
     chand->exit_idle_when_lb_policy_arrives = true;
     if (!chand->started_resolving && chand->resolver != nullptr) {
@@ -1511,7 +3057,7 @@
 
 grpc_connectivity_state grpc_client_channel_check_connectivity_state(
     grpc_channel_element* elem, int try_to_connect) {
-  channel_data* chand = (channel_data*)elem->channel_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   grpc_connectivity_state out =
       grpc_connectivity_state_check(&chand->state_tracker);
   if (out == GRPC_CHANNEL_IDLE && try_to_connect) {
@@ -1582,7 +3128,7 @@
 
 int grpc_client_channel_num_external_connectivity_watchers(
     grpc_channel_element* elem) {
-  channel_data* chand = (channel_data*)elem->channel_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   int count = 0;
 
   gpr_mu_lock(&chand->external_connectivity_watcher_list_mu);
@@ -1598,7 +3144,8 @@
 }
 
 static void on_external_watch_complete_locked(void* arg, grpc_error* error) {
-  external_connectivity_watcher* w = (external_connectivity_watcher*)arg;
+  external_connectivity_watcher* w =
+      static_cast<external_connectivity_watcher*>(arg);
   grpc_closure* follow_up = w->on_complete;
   grpc_polling_entity_del_from_pollset_set(&w->pollent,
                                            w->chand->interested_parties);
@@ -1611,7 +3158,8 @@
 
 static void watch_connectivity_state_locked(void* arg,
                                             grpc_error* error_ignored) {
-  external_connectivity_watcher* w = (external_connectivity_watcher*)arg;
+  external_connectivity_watcher* w =
+      static_cast<external_connectivity_watcher*>(arg);
   external_connectivity_watcher* found = nullptr;
   if (w->state != nullptr) {
     external_connectivity_watcher_list_append(w->chand, w);
@@ -1640,9 +3188,9 @@
     grpc_channel_element* elem, grpc_polling_entity pollent,
     grpc_connectivity_state* state, grpc_closure* closure,
     grpc_closure* watcher_timer_init) {
-  channel_data* chand = (channel_data*)elem->channel_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   external_connectivity_watcher* w =
-      (external_connectivity_watcher*)gpr_zalloc(sizeof(*w));
+      static_cast<external_connectivity_watcher*>(gpr_zalloc(sizeof(*w)));
   w->chand = chand;
   w->pollent = pollent;
   w->on_complete = closure;
@@ -1657,3 +3205,9 @@
                         grpc_combiner_scheduler(chand->combiner)),
       GRPC_ERROR_NONE);
 }
+
+grpc_subchannel_call* grpc_client_channel_get_subchannel_call(
+    grpc_call_element* elem) {
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  return calld->subchannel_call;
+}
diff --git a/src/core/ext/filters/client_channel/client_channel.h b/src/core/ext/filters/client_channel/client_channel.h
index 9670405..a21e562 100644
--- a/src/core/ext/filters/client_channel/client_channel.h
+++ b/src/core/ext/filters/client_channel/client_channel.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/client_channel_factory.h"
 #include "src/core/ext/filters/client_channel/resolver.h"
 #include "src/core/lib/channel/channel_stack.h"
diff --git a/src/core/ext/filters/client_channel/client_channel_factory.cc b/src/core/ext/filters/client_channel/client_channel_factory.cc
index 60c95d7..172e9f0 100644
--- a/src/core/ext/filters/client_channel/client_channel_factory.cc
+++ b/src/core/ext/filters/client_channel/client_channel_factory.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/client_channel_factory.h"
 #include "src/core/lib/channel/channel_args.h"
 
@@ -39,12 +41,14 @@
 }
 
 static void* factory_arg_copy(void* factory) {
-  grpc_client_channel_factory_ref((grpc_client_channel_factory*)factory);
+  grpc_client_channel_factory_ref(
+      static_cast<grpc_client_channel_factory*>(factory));
   return factory;
 }
 
 static void factory_arg_destroy(void* factory) {
-  grpc_client_channel_factory_unref((grpc_client_channel_factory*)factory);
+  grpc_client_channel_factory_unref(
+      static_cast<grpc_client_channel_factory*>(factory));
 }
 
 static int factory_arg_cmp(void* factory1, void* factory2) {
diff --git a/src/core/ext/filters/client_channel/client_channel_factory.h b/src/core/ext/filters/client_channel/client_channel_factory.h
index 766ebb9..601ec46 100644
--- a/src/core/ext/filters/client_channel/client_channel_factory.h
+++ b/src/core/ext/filters/client_channel/client_channel_factory.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_FACTORY_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_FACTORY_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/grpc_types.h>
 
 #include "src/core/ext/filters/client_channel/subchannel.h"
diff --git a/src/core/ext/filters/client_channel/client_channel_plugin.cc b/src/core/ext/filters/client_channel/client_channel_plugin.cc
index ea630d2..3c3a975 100644
--- a/src/core/ext/filters/client_channel/client_channel_plugin.cc
+++ b/src/core/ext/filters/client_channel/client_channel_plugin.cc
@@ -36,7 +36,7 @@
 
 static bool append_filter(grpc_channel_stack_builder* builder, void* arg) {
   return grpc_channel_stack_builder_append_filter(
-      builder, (const grpc_channel_filter*)arg, nullptr, nullptr);
+      builder, static_cast<const grpc_channel_filter*>(arg), nullptr, nullptr);
 }
 
 static bool set_default_host_if_unset(grpc_channel_stack_builder* builder,
@@ -49,22 +49,22 @@
       return true;
     }
   }
-  char* default_authority = grpc_get_default_authority(
-      grpc_channel_stack_builder_get_target(builder));
-  if (default_authority != nullptr) {
+  grpc_core::UniquePtr<char> default_authority =
+      grpc_core::ResolverRegistry::GetDefaultAuthority(
+          grpc_channel_stack_builder_get_target(builder));
+  if (default_authority.get() != nullptr) {
     grpc_arg arg = grpc_channel_arg_string_create(
-        (char*)GRPC_ARG_DEFAULT_AUTHORITY, default_authority);
+        (char*)GRPC_ARG_DEFAULT_AUTHORITY, default_authority.get());
     grpc_channel_args* new_args = grpc_channel_args_copy_and_add(args, &arg, 1);
     grpc_channel_stack_builder_set_channel_arguments(builder, new_args);
-    gpr_free(default_authority);
     grpc_channel_args_destroy(new_args);
   }
   return true;
 }
 
 void grpc_client_channel_init(void) {
-  grpc_lb_policy_registry_init();
-  grpc_resolver_registry_init();
+  grpc_core::LoadBalancingPolicyRegistry::Builder::InitRegistry();
+  grpc_core::ResolverRegistry::Builder::InitRegistry();
   grpc_retry_throttle_map_init();
   grpc_proxy_mapper_registry_init();
   grpc_register_http_proxy_mapper();
@@ -82,6 +82,6 @@
   grpc_channel_init_shutdown();
   grpc_proxy_mapper_registry_shutdown();
   grpc_retry_throttle_map_shutdown();
-  grpc_resolver_registry_shutdown();
-  grpc_lb_policy_registry_shutdown();
+  grpc_core::ResolverRegistry::Builder::ShutdownRegistry();
+  grpc_core::LoadBalancingPolicyRegistry::Builder::ShutdownRegistry();
 }
diff --git a/src/core/ext/filters/client_channel/connector.cc b/src/core/ext/filters/client_channel/connector.cc
index c8bf2f3..5e04b3b 100644
--- a/src/core/ext/filters/client_channel/connector.cc
+++ b/src/core/ext/filters/client_channel/connector.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/connector.h"
 
 grpc_connector* grpc_connector_ref(grpc_connector* connector) {
diff --git a/src/core/ext/filters/client_channel/connector.h b/src/core/ext/filters/client_channel/connector.h
index d657658..5565949 100644
--- a/src/core/ext/filters/client_channel/connector.h
+++ b/src/core/ext/filters/client_channel/connector.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CONNECTOR_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CONNECTOR_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/transport/transport.h"
diff --git a/src/core/ext/filters/client_channel/http_connect_handshaker.cc b/src/core/ext/filters/client_channel/http_connect_handshaker.cc
index 6bfd038..fb29fa7 100644
--- a/src/core/ext/filters/client_channel/http_connect_handshaker.cc
+++ b/src/core/ext/filters/client_channel/http_connect_handshaker.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/http_connect_handshaker.h"
 
 #include <string.h>
@@ -119,7 +121,8 @@
 
 // Callback invoked when finished writing HTTP CONNECT request.
 static void on_write_done(void* arg, grpc_error* error) {
-  http_connect_handshaker* handshaker = (http_connect_handshaker*)arg;
+  http_connect_handshaker* handshaker =
+      static_cast<http_connect_handshaker*>(arg);
   gpr_mu_lock(&handshaker->mu);
   if (error != GRPC_ERROR_NONE || handshaker->shutdown) {
     // If the write failed or we're shutting down, clean up and invoke the
@@ -139,7 +142,8 @@
 
 // Callback invoked for reading HTTP CONNECT response.
 static void on_read_done(void* arg, grpc_error* error) {
-  http_connect_handshaker* handshaker = (http_connect_handshaker*)arg;
+  http_connect_handshaker* handshaker =
+      static_cast<http_connect_handshaker*>(arg);
   gpr_mu_lock(&handshaker->mu);
   if (error != GRPC_ERROR_NONE || handshaker->shutdown) {
     // If the read failed or we're shutting down, clean up and invoke the
@@ -224,13 +228,15 @@
 //
 
 static void http_connect_handshaker_destroy(grpc_handshaker* handshaker_in) {
-  http_connect_handshaker* handshaker = (http_connect_handshaker*)handshaker_in;
+  http_connect_handshaker* handshaker =
+      reinterpret_cast<http_connect_handshaker*>(handshaker_in);
   http_connect_handshaker_unref(handshaker);
 }
 
 static void http_connect_handshaker_shutdown(grpc_handshaker* handshaker_in,
                                              grpc_error* why) {
-  http_connect_handshaker* handshaker = (http_connect_handshaker*)handshaker_in;
+  http_connect_handshaker* handshaker =
+      reinterpret_cast<http_connect_handshaker*>(handshaker_in);
   gpr_mu_lock(&handshaker->mu);
   if (!handshaker->shutdown) {
     handshaker->shutdown = true;
@@ -244,12 +250,14 @@
 static void http_connect_handshaker_do_handshake(
     grpc_handshaker* handshaker_in, grpc_tcp_server_acceptor* acceptor,
     grpc_closure* on_handshake_done, grpc_handshaker_args* args) {
-  http_connect_handshaker* handshaker = (http_connect_handshaker*)handshaker_in;
+  http_connect_handshaker* handshaker =
+      reinterpret_cast<http_connect_handshaker*>(handshaker_in);
   // Check for HTTP CONNECT channel arg.
   // If not found, invoke on_handshake_done without doing anything.
   const grpc_arg* arg =
       grpc_channel_args_find(args->args, GRPC_ARG_HTTP_CONNECT_SERVER);
-  if (arg == nullptr) {
+  char* server_name = grpc_channel_arg_get_string(arg);
+  if (server_name == nullptr) {
     // Set shutdown to true so that subsequent calls to
     // http_connect_handshaker_shutdown() do nothing.
     gpr_mu_lock(&handshaker->mu);
@@ -258,20 +266,18 @@
     GRPC_CLOSURE_SCHED(on_handshake_done, GRPC_ERROR_NONE);
     return;
   }
-  GPR_ASSERT(arg->type == GRPC_ARG_STRING);
-  char* server_name = arg->value.string;
   // Get headers from channel args.
   arg = grpc_channel_args_find(args->args, GRPC_ARG_HTTP_CONNECT_HEADERS);
+  char* arg_header_string = grpc_channel_arg_get_string(arg);
   grpc_http_header* headers = nullptr;
   size_t num_headers = 0;
   char** header_strings = nullptr;
   size_t num_header_strings = 0;
-  if (arg != nullptr) {
-    GPR_ASSERT(arg->type == GRPC_ARG_STRING);
-    gpr_string_split(arg->value.string, "\n", &header_strings,
+  if (arg_header_string != nullptr) {
+    gpr_string_split(arg_header_string, "\n", &header_strings,
                      &num_header_strings);
-    headers = (grpc_http_header*)gpr_malloc(sizeof(grpc_http_header) *
-                                            num_header_strings);
+    headers = static_cast<grpc_http_header*>(
+        gpr_malloc(sizeof(grpc_http_header) * num_header_strings));
     for (size_t i = 0; i < num_header_strings; ++i) {
       char* sep = strchr(header_strings[i], ':');
       if (sep == nullptr) {
@@ -324,7 +330,7 @@
 
 static grpc_handshaker* grpc_http_connect_handshaker_create() {
   http_connect_handshaker* handshaker =
-      (http_connect_handshaker*)gpr_malloc(sizeof(*handshaker));
+      static_cast<http_connect_handshaker*>(gpr_malloc(sizeof(*handshaker)));
   memset(handshaker, 0, sizeof(*handshaker));
   grpc_handshaker_init(&http_connect_handshaker_vtable, &handshaker->base);
   gpr_mu_init(&handshaker->mu);
diff --git a/src/core/ext/filters/client_channel/http_proxy.cc b/src/core/ext/filters/client_channel/http_proxy.cc
index 7c5f79f..29a6c0e 100644
--- a/src/core/ext/filters/client_channel/http_proxy.cc
+++ b/src/core/ext/filters/client_channel/http_proxy.cc
@@ -16,13 +16,14 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/http_proxy.h"
 
 #include <stdbool.h>
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
@@ -31,6 +32,7 @@
 #include "src/core/ext/filters/client_channel/uri_parser.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/slice/b64.h"
 
diff --git a/src/core/ext/filters/client_channel/lb_policy.cc b/src/core/ext/filters/client_channel/lb_policy.cc
index cc4fe7e..fa63dd7 100644
--- a/src/core/ext/filters/client_channel/lb_policy.cc
+++ b/src/core/ext/filters/client_channel/lb_policy.cc
@@ -16,126 +16,44 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/lb_policy.h"
 #include "src/core/lib/iomgr/combiner.h"
 
 grpc_core::DebugOnlyTraceFlag grpc_trace_lb_policy_refcount(
     false, "lb_policy_refcount");
 
-void grpc_lb_policy_init(grpc_lb_policy* policy,
-                         const grpc_lb_policy_vtable* vtable,
-                         grpc_combiner* combiner) {
-  policy->vtable = vtable;
-  gpr_ref_init(&policy->refs, 1);
-  policy->interested_parties = grpc_pollset_set_create();
-  policy->combiner = GRPC_COMBINER_REF(combiner, "lb_policy");
+namespace grpc_core {
+
+LoadBalancingPolicy::LoadBalancingPolicy(const Args& args)
+    : InternallyRefCountedWithTracing(&grpc_trace_lb_policy_refcount),
+      combiner_(GRPC_COMBINER_REF(args.combiner, "lb_policy")),
+      client_channel_factory_(args.client_channel_factory),
+      interested_parties_(grpc_pollset_set_create()),
+      request_reresolution_(nullptr) {}
+
+LoadBalancingPolicy::~LoadBalancingPolicy() {
+  grpc_pollset_set_destroy(interested_parties_);
+  GRPC_COMBINER_UNREF(combiner_, "lb_policy");
 }
 
-#ifndef NDEBUG
-void grpc_lb_policy_ref(grpc_lb_policy* lb_policy, const char* file, int line,
-                        const char* reason) {
-  if (grpc_trace_lb_policy_refcount.enabled()) {
-    gpr_atm old_refs = gpr_atm_no_barrier_load(&lb_policy->refs.count);
-    gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
-            "LB_POLICY:%p   ref %" PRIdPTR " -> %" PRIdPTR " %s", lb_policy,
-            old_refs, old_refs + 1, reason);
-  }
-#else
-void grpc_lb_policy_ref(grpc_lb_policy* lb_policy) {
-#endif
-  gpr_ref(&lb_policy->refs);
-}
-
-#ifndef NDEBUG
-void grpc_lb_policy_unref(grpc_lb_policy* lb_policy, const char* file, int line,
-                          const char* reason) {
-  if (grpc_trace_lb_policy_refcount.enabled()) {
-    gpr_atm old_refs = gpr_atm_no_barrier_load(&lb_policy->refs.count);
-    gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
-            "LB_POLICY:%p unref %" PRIdPTR " -> %" PRIdPTR " %s", lb_policy,
-            old_refs, old_refs - 1, reason);
-  }
-#else
-void grpc_lb_policy_unref(grpc_lb_policy* lb_policy) {
-#endif
-  if (gpr_unref(&lb_policy->refs)) {
-    grpc_pollset_set_destroy(lb_policy->interested_parties);
-    grpc_combiner* combiner = lb_policy->combiner;
-    lb_policy->vtable->destroy(lb_policy);
-    GRPC_COMBINER_UNREF(combiner, "lb_policy");
-  }
-}
-
-void grpc_lb_policy_shutdown_locked(grpc_lb_policy* policy,
-                                    grpc_lb_policy* new_policy) {
-  policy->vtable->shutdown_locked(policy, new_policy);
-}
-
-int grpc_lb_policy_pick_locked(grpc_lb_policy* policy,
-                               grpc_lb_policy_pick_state* pick) {
-  return policy->vtable->pick_locked(policy, pick);
-}
-
-void grpc_lb_policy_cancel_pick_locked(grpc_lb_policy* policy,
-                                       grpc_lb_policy_pick_state* pick,
-                                       grpc_error* error) {
-  policy->vtable->cancel_pick_locked(policy, pick, error);
-}
-
-void grpc_lb_policy_cancel_picks_locked(grpc_lb_policy* policy,
-                                        uint32_t initial_metadata_flags_mask,
-                                        uint32_t initial_metadata_flags_eq,
-                                        grpc_error* error) {
-  policy->vtable->cancel_picks_locked(policy, initial_metadata_flags_mask,
-                                      initial_metadata_flags_eq, error);
-}
-
-void grpc_lb_policy_exit_idle_locked(grpc_lb_policy* policy) {
-  policy->vtable->exit_idle_locked(policy);
-}
-
-void grpc_lb_policy_ping_one_locked(grpc_lb_policy* policy,
-                                    grpc_closure* on_initiate,
-                                    grpc_closure* on_ack) {
-  policy->vtable->ping_one_locked(policy, on_initiate, on_ack);
-}
-
-void grpc_lb_policy_notify_on_state_change_locked(
-    grpc_lb_policy* policy, grpc_connectivity_state* state,
-    grpc_closure* closure) {
-  policy->vtable->notify_on_state_change_locked(policy, state, closure);
-}
-
-grpc_connectivity_state grpc_lb_policy_check_connectivity_locked(
-    grpc_lb_policy* policy, grpc_error** connectivity_error) {
-  return policy->vtable->check_connectivity_locked(policy, connectivity_error);
-}
-
-void grpc_lb_policy_update_locked(grpc_lb_policy* policy,
-                                  const grpc_lb_policy_args* lb_policy_args) {
-  policy->vtable->update_locked(policy, lb_policy_args);
-}
-
-void grpc_lb_policy_set_reresolve_closure_locked(
-    grpc_lb_policy* policy, grpc_closure* request_reresolution) {
-  policy->vtable->set_reresolve_closure_locked(policy, request_reresolution);
-}
-
-void grpc_lb_policy_try_reresolve(grpc_lb_policy* policy,
-                                  grpc_core::TraceFlag* grpc_lb_trace,
-                                  grpc_error* error) {
-  if (policy->request_reresolution != nullptr) {
-    GRPC_CLOSURE_SCHED(policy->request_reresolution, error);
-    policy->request_reresolution = nullptr;
+void LoadBalancingPolicy::TryReresolutionLocked(
+    grpc_core::TraceFlag* grpc_lb_trace, grpc_error* error) {
+  if (request_reresolution_ != nullptr) {
+    GRPC_CLOSURE_SCHED(request_reresolution_, error);
+    request_reresolution_ = nullptr;
     if (grpc_lb_trace->enabled()) {
       gpr_log(GPR_DEBUG,
               "%s %p: scheduling re-resolution closure with error=%s.",
-              grpc_lb_trace->name(), policy, grpc_error_string(error));
+              grpc_lb_trace->name(), this, grpc_error_string(error));
     }
   } else {
-    if (grpc_lb_trace->enabled() && error == GRPC_ERROR_NONE) {
-      gpr_log(GPR_DEBUG, "%s %p: re-resolution already in progress.",
-              grpc_lb_trace->name(), policy);
+    if (grpc_lb_trace->enabled()) {
+      gpr_log(GPR_DEBUG, "%s %p: no available re-resolution closure.",
+              grpc_lb_trace->name(), this);
     }
   }
 }
+
+}  // namespace grpc_core
diff --git a/src/core/ext/filters/client_channel/lb_policy.h b/src/core/ext/filters/client_channel/lb_policy.h
index 30660cb..c3e43e5 100644
--- a/src/core/ext/filters/client_channel/lb_policy.h
+++ b/src/core/ext/filters/client_channel/lb_policy.h
@@ -19,186 +19,183 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_H
 
+#include <grpc/support/port_platform.h>
+
+#include "src/core/ext/filters/client_channel/client_channel_factory.h"
 #include "src/core/ext/filters/client_channel/subchannel.h"
+#include "src/core/lib/gprpp/abstract.h"
+#include "src/core/lib/gprpp/orphanable.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
+#include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/polling_entity.h"
 #include "src/core/lib/transport/connectivity_state.h"
 
-/** A load balancing policy: specified by a vtable and a struct (which
-    is expected to be extended to contain some parameters) */
-typedef struct grpc_lb_policy grpc_lb_policy;
-typedef struct grpc_lb_policy_vtable grpc_lb_policy_vtable;
-typedef struct grpc_lb_policy_args grpc_lb_policy_args;
-
 extern grpc_core::DebugOnlyTraceFlag grpc_trace_lb_policy_refcount;
 
-struct grpc_lb_policy {
-  const grpc_lb_policy_vtable* vtable;
-  gpr_refcount refs;
-  /* owned pointer to interested parties in load balancing decisions */
-  grpc_pollset_set* interested_parties;
-  /* combiner under which lb_policy actions take place */
-  grpc_combiner* combiner;
-  /* callback to force a re-resolution */
-  grpc_closure* request_reresolution;
-};
+namespace grpc_core {
 
-/// State used for an LB pick.
-typedef struct grpc_lb_policy_pick_state {
-  /// Initial metadata associated with the picking call.
-  grpc_metadata_batch* initial_metadata;
-  /// Bitmask used for selective cancelling. See \a
-  /// grpc_lb_policy_cancel_picks() and \a GRPC_INITIAL_METADATA_* in
-  /// grpc_types.h.
-  uint32_t initial_metadata_flags;
-  /// Storage for LB token in \a initial_metadata, or NULL if not used.
-  grpc_linked_mdelem lb_token_mdelem_storage;
-  /// Closure to run when pick is complete, if not completed synchronously.
-  grpc_closure* on_complete;
-  /// Will be set to the selected subchannel, or nullptr on failure or when
-  /// the LB policy decides to drop the call.
-  grpc_core::RefCountedPtr<grpc_core::ConnectedSubchannel> connected_subchannel;
-  /// Will be populated with context to pass to the subchannel call, if needed.
-  grpc_call_context_element subchannel_call_context[GRPC_CONTEXT_COUNT];
-  /// Upon success, \a *user_data will be set to whatever opaque information
-  /// may need to be propagated from the LB policy, or NULL if not needed.
-  void** user_data;
-  /// Next pointer.  For internal use by LB policy.
-  struct grpc_lb_policy_pick_state* next;
-} grpc_lb_policy_pick_state;
+/// Interface for load balancing policies.
+///
+/// Note: All methods with a "Locked" suffix must be called from the
+/// combiner passed to the constructor.
+///
+/// Any I/O done by the LB policy should be done under the pollset_set
+/// returned by \a interested_parties().
+class LoadBalancingPolicy
+    : public InternallyRefCountedWithTracing<LoadBalancingPolicy> {
+ public:
+  struct Args {
+    /// The combiner under which all LB policy calls will be run.
+    /// Policy does NOT take ownership of the reference to the combiner.
+    // TODO(roth): Once we have a C++-like interface for combiners, this
+    // API should change to take a smart pointer that does pass ownership
+    // of a reference.
+    grpc_combiner* combiner = nullptr;
+    /// Used to create channels and subchannels.
+    grpc_client_channel_factory* client_channel_factory = nullptr;
+    /// Channel args from the resolver.
+    /// Note that the LB policy gets the set of addresses from the
+    /// GRPC_ARG_LB_ADDRESSES channel arg.
+    grpc_channel_args* args = nullptr;
+  };
 
-struct grpc_lb_policy_vtable {
-  void (*destroy)(grpc_lb_policy* policy);
+  /// State used for an LB pick.
+  struct PickState {
+    /// Initial metadata associated with the picking call.
+    grpc_metadata_batch* initial_metadata;
+    /// Bitmask used for selective cancelling. See
+    /// \a CancelMatchingPicksLocked() and \a GRPC_INITIAL_METADATA_* in
+    /// grpc_types.h.
+    uint32_t initial_metadata_flags;
+    /// Storage for LB token in \a initial_metadata, or nullptr if not used.
+    grpc_linked_mdelem lb_token_mdelem_storage;
+    /// Closure to run when pick is complete, if not completed synchronously.
+    grpc_closure* on_complete;
+    /// Will be set to the selected subchannel, or nullptr on failure or when
+    /// the LB policy decides to drop the call.
+    RefCountedPtr<ConnectedSubchannel> connected_subchannel;
+    /// Will be populated with context to pass to the subchannel call, if
+    /// needed.
+    grpc_call_context_element subchannel_call_context[GRPC_CONTEXT_COUNT];
+    /// Upon success, \a *user_data will be set to whatever opaque information
+    /// may need to be propagated from the LB policy, or nullptr if not needed.
+    // TODO(roth): As part of revamping our metadata APIs, try to find a
+    // way to clean this up and C++-ify it.
+    void** user_data;
+    /// Next pointer.  For internal use by LB policy.
+    PickState* next;
+  };
 
-  /// \see grpc_lb_policy_shutdown_locked().
-  void (*shutdown_locked)(grpc_lb_policy* policy, grpc_lb_policy* new_policy);
+  // Not copyable nor movable.
+  LoadBalancingPolicy(const LoadBalancingPolicy&) = delete;
+  LoadBalancingPolicy& operator=(const LoadBalancingPolicy&) = delete;
 
-  /** \see grpc_lb_policy_pick */
-  int (*pick_locked)(grpc_lb_policy* policy, grpc_lb_policy_pick_state* pick);
+  /// Updates the policy with a new set of \a args from the resolver.
+  /// Note that the LB policy gets the set of addresses from the
+  /// GRPC_ARG_LB_ADDRESSES channel arg.
+  virtual void UpdateLocked(const grpc_channel_args& args) GRPC_ABSTRACT;
 
-  /** \see grpc_lb_policy_cancel_pick */
-  void (*cancel_pick_locked)(grpc_lb_policy* policy,
-                             grpc_lb_policy_pick_state* pick,
+  /// Finds an appropriate subchannel for a call, based on data in \a pick.
+  /// \a pick must remain alive until the pick is complete.
+  ///
+  /// If the pick succeeds and a result is known immediately, returns true.
+  /// Otherwise, \a pick->on_complete will be invoked once the pick is
+  /// complete with its error argument set to indicate success or failure.
+  virtual bool PickLocked(PickState* pick) GRPC_ABSTRACT;
+
+  /// Cancels \a pick.
+  /// The \a on_complete callback of the pending pick will be invoked with
+  /// \a pick->connected_subchannel set to null.
+  virtual void CancelPickLocked(PickState* pick,
+                                grpc_error* error) GRPC_ABSTRACT;
+
+  /// Cancels all pending picks for which their \a initial_metadata_flags (as
+  /// given in the call to \a PickLocked()) matches
+  /// \a initial_metadata_flags_eq when ANDed with
+  /// \a initial_metadata_flags_mask.
+  virtual void CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask,
+                                         uint32_t initial_metadata_flags_eq,
+                                         grpc_error* error) GRPC_ABSTRACT;
+
+  /// Requests a notification when the connectivity state of the policy
+  /// changes from \a *state.  When that happens, sets \a *state to the
+  /// new state and schedules \a closure.
+  virtual void NotifyOnStateChangeLocked(grpc_connectivity_state* state,
+                                         grpc_closure* closure) GRPC_ABSTRACT;
+
+  /// Returns the policy's current connectivity state.  Sets \a error to
+  /// the associated error, if any.
+  virtual grpc_connectivity_state CheckConnectivityLocked(
+      grpc_error** connectivity_error) GRPC_ABSTRACT;
+
+  /// Hands off pending picks to \a new_policy.
+  virtual void HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy)
+      GRPC_ABSTRACT;
+
+  /// Performs a connected subchannel ping via \a ConnectedSubchannel::Ping()
+  /// against one of the connected subchannels managed by the policy.
+  /// Note: This is intended only for use in tests.
+  virtual void PingOneLocked(grpc_closure* on_initiate,
+                             grpc_closure* on_ack) GRPC_ABSTRACT;
+
+  /// Tries to enter a READY connectivity state.
+  /// TODO(roth): As part of restructuring how we handle IDLE state,
+  /// consider whether this method is still needed.
+  virtual void ExitIdleLocked() GRPC_ABSTRACT;
+
+  void Orphan() override {
+    // Invoke ShutdownAndUnrefLocked() inside of the combiner.
+    GRPC_CLOSURE_SCHED(
+        GRPC_CLOSURE_CREATE(&LoadBalancingPolicy::ShutdownAndUnrefLocked, this,
+                            grpc_combiner_scheduler(combiner_)),
+        GRPC_ERROR_NONE);
+  }
+
+  /// Sets the re-resolution closure to \a request_reresolution.
+  void SetReresolutionClosureLocked(grpc_closure* request_reresolution) {
+    GPR_ASSERT(request_reresolution_ == nullptr);
+    request_reresolution_ = request_reresolution;
+  }
+
+  grpc_pollset_set* interested_parties() const { return interested_parties_; }
+
+  GRPC_ABSTRACT_BASE_CLASS
+
+ protected:
+  explicit LoadBalancingPolicy(const Args& args);
+  virtual ~LoadBalancingPolicy();
+
+  grpc_combiner* combiner() const { return combiner_; }
+  grpc_client_channel_factory* client_channel_factory() const {
+    return client_channel_factory_;
+  }
+
+  /// Shuts down the policy.  Any pending picks that have not been
+  /// handed off to a new policy via HandOffPendingPicksLocked() will be
+  /// failed.
+  virtual void ShutdownLocked() GRPC_ABSTRACT;
+
+  /// Tries to request a re-resolution.
+  void TryReresolutionLocked(grpc_core::TraceFlag* grpc_lb_trace,
                              grpc_error* error);
 
-  /** \see grpc_lb_policy_cancel_picks */
-  void (*cancel_picks_locked)(grpc_lb_policy* policy,
-                              uint32_t initial_metadata_flags_mask,
-                              uint32_t initial_metadata_flags_eq,
-                              grpc_error* error);
+ private:
+  static void ShutdownAndUnrefLocked(void* arg, grpc_error* ignored) {
+    LoadBalancingPolicy* policy = static_cast<LoadBalancingPolicy*>(arg);
+    policy->ShutdownLocked();
+    policy->Unref();
+  }
 
-  /** \see grpc_lb_policy_ping_one */
-  void (*ping_one_locked)(grpc_lb_policy* policy, grpc_closure* on_initiate,
-                          grpc_closure* on_ack);
-
-  /** Try to enter a READY connectivity state */
-  void (*exit_idle_locked)(grpc_lb_policy* policy);
-
-  /** check the current connectivity of the lb_policy */
-  grpc_connectivity_state (*check_connectivity_locked)(
-      grpc_lb_policy* policy, grpc_error** connectivity_error);
-
-  /** call notify when the connectivity state of a channel changes from *state.
-      Updates *state with the new state of the policy. Calling with a NULL \a
-      state cancels the subscription.  */
-  void (*notify_on_state_change_locked)(grpc_lb_policy* policy,
-                                        grpc_connectivity_state* state,
-                                        grpc_closure* closure);
-
-  void (*update_locked)(grpc_lb_policy* policy,
-                        const grpc_lb_policy_args* args);
-
-  /** \see grpc_lb_policy_set_reresolve_closure */
-  void (*set_reresolve_closure_locked)(grpc_lb_policy* policy,
-                                       grpc_closure* request_reresolution);
+  /// Combiner under which LB policy actions take place.
+  grpc_combiner* combiner_;
+  /// Client channel factory, used to create channels and subchannels.
+  grpc_client_channel_factory* client_channel_factory_;
+  /// Owned pointer to interested parties in load balancing decisions.
+  grpc_pollset_set* interested_parties_;
+  /// Callback to force a re-resolution.
+  grpc_closure* request_reresolution_;
 };
 
-#ifndef NDEBUG
-#define GRPC_LB_POLICY_REF(p, r) \
-  grpc_lb_policy_ref((p), __FILE__, __LINE__, (r))
-#define GRPC_LB_POLICY_UNREF(p, r) \
-  grpc_lb_policy_unref((p), __FILE__, __LINE__, (r))
-void grpc_lb_policy_ref(grpc_lb_policy* policy, const char* file, int line,
-                        const char* reason);
-void grpc_lb_policy_unref(grpc_lb_policy* policy, const char* file, int line,
-                          const char* reason);
-#else  // !NDEBUG
-#define GRPC_LB_POLICY_REF(p, r) grpc_lb_policy_ref((p))
-#define GRPC_LB_POLICY_UNREF(p, r) grpc_lb_policy_unref((p))
-void grpc_lb_policy_ref(grpc_lb_policy* policy);
-void grpc_lb_policy_unref(grpc_lb_policy* policy);
-#endif
-
-/** called by concrete implementations to initialize the base struct */
-void grpc_lb_policy_init(grpc_lb_policy* policy,
-                         const grpc_lb_policy_vtable* vtable,
-                         grpc_combiner* combiner);
-
-/// Shuts down \a policy.
-/// If \a new_policy is non-null, any pending picks will be restarted
-/// on that policy; otherwise, they will be failed.
-void grpc_lb_policy_shutdown_locked(grpc_lb_policy* policy,
-                                    grpc_lb_policy* new_policy);
-
-/** Finds an appropriate subchannel for a call, based on data in \a pick.
-    \a pick must remain alive until the pick is complete.
-
-    If the pick succeeds and a result is known immediately, a non-zero
-    value will be returned.  Otherwise, \a pick->on_complete will be invoked
-    once the pick is complete with its error argument set to indicate
-    success or failure.
-
-    Any IO should be done under the \a interested_parties \a grpc_pollset_set
-    in the \a grpc_lb_policy struct. */
-int grpc_lb_policy_pick_locked(grpc_lb_policy* policy,
-                               grpc_lb_policy_pick_state* pick);
-
-/** Perform a connected subchannel ping (see \a
-   grpc_core::ConnectedSubchannel::Ping)
-    against one of the connected subchannels managed by \a policy. */
-void grpc_lb_policy_ping_one_locked(grpc_lb_policy* policy,
-                                    grpc_closure* on_initiate,
-                                    grpc_closure* on_ack);
-
-/** Cancel picks for \a pick.
-    The \a on_complete callback of the pending picks will be invoked with \a
-    *target set to NULL. */
-void grpc_lb_policy_cancel_pick_locked(grpc_lb_policy* policy,
-                                       grpc_lb_policy_pick_state* pick,
-                                       grpc_error* error);
-
-/** Cancel all pending picks for which their \a initial_metadata_flags (as given
-    in the call to \a grpc_lb_policy_pick) matches \a initial_metadata_flags_eq
-    when AND'd with \a initial_metadata_flags_mask */
-void grpc_lb_policy_cancel_picks_locked(grpc_lb_policy* policy,
-                                        uint32_t initial_metadata_flags_mask,
-                                        uint32_t initial_metadata_flags_eq,
-                                        grpc_error* error);
-
-/** Try to enter a READY connectivity state */
-void grpc_lb_policy_exit_idle_locked(grpc_lb_policy* policy);
-
-/* Call notify when the connectivity state of a channel changes from \a *state.
- * Updates \a *state with the new state of the policy */
-void grpc_lb_policy_notify_on_state_change_locked(
-    grpc_lb_policy* policy, grpc_connectivity_state* state,
-    grpc_closure* closure);
-
-grpc_connectivity_state grpc_lb_policy_check_connectivity_locked(
-    grpc_lb_policy* policy, grpc_error** connectivity_error);
-
-/** Update \a policy with \a lb_policy_args. */
-void grpc_lb_policy_update_locked(grpc_lb_policy* policy,
-                                  const grpc_lb_policy_args* lb_policy_args);
-
-/** Set the re-resolution closure to \a request_reresolution. */
-void grpc_lb_policy_set_reresolve_closure_locked(
-    grpc_lb_policy* policy, grpc_closure* request_reresolution);
-
-/** Try to request a re-resolution. It's NOT a public API; it's only for use by
-    the LB policy implementations. */
-void grpc_lb_policy_try_reresolve(grpc_lb_policy* policy,
-                                  grpc_core::TraceFlag* grpc_lb_trace,
-                                  grpc_error* error);
+}  // namespace grpc_core
 
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_H */
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc
index d6b7592..18ef1f6 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h"
 
 #include <grpc/support/atm.h>
@@ -48,7 +50,7 @@
 }  // namespace
 
 static void on_complete_for_send(void* arg, grpc_error* error) {
-  call_data* calld = (call_data*)arg;
+  call_data* calld = static_cast<call_data*>(arg);
   if (error == GRPC_ERROR_NONE) {
     calld->send_initial_metadata_succeeded = true;
   }
@@ -56,7 +58,7 @@
 }
 
 static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
-  call_data* calld = (call_data*)arg;
+  call_data* calld = static_cast<call_data*>(arg);
   if (error == GRPC_ERROR_NONE) {
     calld->recv_initial_metadata_succeeded = true;
   }
@@ -66,13 +68,13 @@
 
 static grpc_error* init_call_elem(grpc_call_element* elem,
                                   const grpc_call_element_args* args) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   // Get stats object from context and take a ref.
   GPR_ASSERT(args->context != nullptr);
   if (args->context[GRPC_GRPCLB_CLIENT_STATS].value != nullptr) {
-    calld->client_stats = grpc_grpclb_client_stats_ref(
-        (grpc_grpclb_client_stats*)args->context[GRPC_GRPCLB_CLIENT_STATS]
-            .value);
+    calld->client_stats =
+        grpc_grpclb_client_stats_ref(static_cast<grpc_grpclb_client_stats*>(
+            args->context[GRPC_GRPCLB_CLIENT_STATS].value));
     // Record call started.
     grpc_grpclb_client_stats_add_call_started(calld->client_stats);
   }
@@ -82,7 +84,7 @@
 static void destroy_call_elem(grpc_call_element* elem,
                               const grpc_call_final_info* final_info,
                               grpc_closure* ignored) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   if (calld->client_stats != nullptr) {
     // Record call finished, optionally setting client_failed_to_send and
     // received.
@@ -97,7 +99,7 @@
 
 static void start_transport_stream_op_batch(
     grpc_call_element* elem, grpc_transport_stream_op_batch* batch) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   GPR_TIMER_SCOPE("clr_start_transport_stream_op_batch", 0);
   if (calld->client_stats != nullptr) {
     // Intercept send_initial_metadata.
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h
index 04de7a0..838e2ef 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_CLIENT_LOAD_REPORTING_FILTER_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_CLIENT_LOAD_REPORTING_FILTER_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/channel/channel_stack.h"
 
 extern const grpc_channel_filter grpc_client_load_reporting_filter;
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
index 1709e56..e805593 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
@@ -16,69 +16,52 @@
  *
  */
 
-/** Implementation of the gRPC LB policy.
- *
- * This policy takes as input a set of resolved addresses {a1..an} for which the
- * LB set was set (it's the resolver's responsibility to ensure this). That is
- * to say, {a1..an} represent a collection of LB servers.
- *
- * An internal channel (\a glb_lb_policy.lb_channel) is created over {a1..an}.
- * This channel behaves just like a regular channel. In particular, the
- * constructed URI over the addresses a1..an will use the default pick first
- * policy to select from this list of LB server backends.
- *
- * The first time the policy gets a request for a pick, a ping, or to exit the
- * idle state, \a query_for_backends_locked() is called. This function sets up
- * and initiates the internal communication with the LB server. In particular,
- * it's responsible for instantiating the internal *streaming* call to the LB
- * server (whichever address from {a1..an} pick-first chose). This call is
- * serviced by two callbacks, \a lb_on_server_status_received and \a
- * lb_on_response_received. The former will be called when the call to the LB
- * server completes. This can happen if the LB server closes the connection or
- * if this policy itself cancels the call (for example because it's shutting
- * down). If the internal call times out, the usual behavior of pick-first
- * applies, continuing to pick from the list {a1..an}.
- *
- * Upon sucesss, the incoming \a LoadBalancingResponse is processed by \a
- * res_recv. An invalid one results in the termination of the streaming call. A
- * new streaming call should be created if possible, failing the original call
- * otherwise. For a valid \a LoadBalancingResponse, the server list of actual
- * backends is extracted. A Round Robin policy will be created from this list.
- * There are two possible scenarios:
- *
- * 1. This is the first server list received. There was no previous instance of
- *    the Round Robin policy. \a rr_handover_locked() will instantiate the RR
- *    policy and perform all the pending operations over it.
- * 2. There's already a RR policy instance active. We need to introduce the new
- *    one build from the new serverlist, but taking care not to disrupt the
- *    operations in progress over the old RR instance. This is done by
- *    decreasing the reference count on the old policy. The moment no more
- *    references are held on the old RR policy, it'll be destroyed and \a
- *    on_rr_connectivity_changed notified with a \a GRPC_CHANNEL_SHUTDOWN
- *    state. At this point we can transition to a new RR instance safely, which
- *    is done once again via \a rr_handover_locked().
- *
- *
- * Once a RR policy instance is in place (and getting updated as described),
- * calls to for a pick, a ping or a cancellation will be serviced right away by
- * forwarding them to the RR instance. Any time there's no RR policy available
- * (ie, right after the creation of the gRPCLB policy, if an empty serverlist is
- * received, etc), pick/ping requests are added to a list of pending picks/pings
- * to be flushed and serviced as part of \a rr_handover_locked() the moment the
- * RR policy instance becomes available.
- *
- * \see https://github.com/grpc/grpc/blob/master/doc/load-balancing.md for the
- * high level design and details. */
+/// Implementation of the gRPC LB policy.
+///
+/// This policy takes as input a list of resolved addresses, which must
+/// include at least one balancer address.
+///
+/// An internal channel (\a lb_channel_) is created for the addresses
+/// from that are balancers.  This channel behaves just like a regular
+/// channel that uses pick_first to select from the list of balancer
+/// addresses.
+///
+/// The first time the policy gets a request for a pick, a ping, or to exit
+/// the idle state, \a StartPickingLocked() is called. This method is
+/// responsible for instantiating the internal *streaming* call to the LB
+/// server (whichever address pick_first chose).  The call will be complete
+/// when either the balancer sends status or when we cancel the call (e.g.,
+/// because we are shutting down).  In needed, we retry the call.  If we
+/// received at least one valid message from the server, a new call attempt
+/// will be made immediately; otherwise, we apply back-off delays between
+/// attempts.
+///
+/// We maintain an internal round_robin policy instance for distributing
+/// requests across backends.  Whenever we receive a new serverlist from
+/// the balancer, we update the round_robin policy with the new list of
+/// addresses.  If we cannot communicate with the balancer on startup,
+/// however, we may enter fallback mode, in which case we will populate
+/// the RR policy's addresses from the backend addresses returned by the
+/// resolver.
+///
+/// Once an RR policy instance is in place (and getting updated as described),
+/// calls for a pick, a ping, or a cancellation will be serviced right
+/// away by forwarding them to the RR instance.  Any time there's no RR
+/// policy available (i.e., right after the creation of the gRPCLB policy),
+/// pick and ping requests are added to a list of pending picks and pings
+/// to be flushed and serviced when the RR policy instance becomes available.
+///
+/// \see https://github.com/grpc/grpc/blob/master/doc/load-balancing.md for the
+/// high level design and details.
 
-/* TODO(dgq):
- * - Implement LB service forwarding (point 2c. in the doc's diagram).
- */
+// With the addition of a libuv endpoint, sockaddr.h now includes uv.h when
+// using that endpoint. Because of various transitive includes in uv.h,
+// including windows.h on Windows, uv.h must be included before other system
+// headers. Therefore, sockaddr.h must always be included first.
+#include <grpc/support/port_platform.h>
 
-/* With the addition of a libuv endpoint, sockaddr.h now includes uv.h when
-   using that endpoint. Because of various transitive includes in uv.h,
-   including windows.h on Windows, uv.h must be included before other system
-   headers. Therefore, sockaddr.h must always be included first */
 #include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/iomgr/socket_utils.h"
 
 #include <inttypes.h>
 #include <limits.h>
@@ -87,14 +70,12 @@
 #include <grpc/byte_buffer_reader.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
 
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/client_channel/client_channel_factory.h"
 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h"
-#include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h"
 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h"
 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h"
 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h"
@@ -106,8 +87,12 @@
 #include "src/core/lib/backoff/backoff.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/manual_constructor.h"
+#include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/gprpp/orphanable.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
@@ -126,320 +111,287 @@
 #define GRPC_GRPCLB_RECONNECT_JITTER 0.2
 #define GRPC_GRPCLB_DEFAULT_FALLBACK_TIMEOUT_MS 10000
 
-grpc_core::TraceFlag grpc_lb_glb_trace(false, "glb");
+namespace grpc_core {
 
-struct glb_lb_policy;
+TraceFlag grpc_lb_glb_trace(false, "glb");
 
 namespace {
 
-/// Linked list of pending pick requests. It stores all information needed to
-/// eventually call (Round Robin's) pick() on them. They mainly stay pending
-/// waiting for the RR policy to be created.
-///
-/// Note that when a pick is sent to the RR policy, we inject our own
-/// on_complete callback, so that we can intercept the result before
-/// invoking the original on_complete callback.  This allows us to set the
-/// LB token metadata and add client_stats to the call context.
-/// See \a pending_pick_complete() for details.
-struct pending_pick {
-  // Our on_complete closure and the original one.
-  grpc_closure on_complete;
-  grpc_closure* original_on_complete;
-  // The original pick.
-  grpc_lb_policy_pick_state* pick;
-  // Stats for client-side load reporting. Note that this holds a
-  // reference, which must be either passed on via context or unreffed.
-  grpc_grpclb_client_stats* client_stats;
-  // The LB token associated with the pick.  This is set via user_data in
-  // the pick.
-  grpc_mdelem lb_token;
-  // The grpclb instance that created the wrapping. This instance is not owned,
-  // reference counts are untouched. It's used only for logging purposes.
-  glb_lb_policy* glb_policy;
-  // Next pending pick.
-  struct pending_pick* next;
+class GrpcLb : public LoadBalancingPolicy {
+ public:
+  GrpcLb(const grpc_lb_addresses* addresses, const Args& args);
+
+  void UpdateLocked(const grpc_channel_args& args) override;
+  bool PickLocked(PickState* pick) override;
+  void CancelPickLocked(PickState* pick, grpc_error* error) override;
+  void CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask,
+                                 uint32_t initial_metadata_flags_eq,
+                                 grpc_error* error) override;
+  void NotifyOnStateChangeLocked(grpc_connectivity_state* state,
+                                 grpc_closure* closure) override;
+  grpc_connectivity_state CheckConnectivityLocked(
+      grpc_error** connectivity_error) override;
+  void HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) override;
+  void PingOneLocked(grpc_closure* on_initiate, grpc_closure* on_ack) override;
+  void ExitIdleLocked() override;
+
+ private:
+  /// Linked list of pending pick requests. It stores all information needed to
+  /// eventually call (Round Robin's) pick() on them. They mainly stay pending
+  /// waiting for the RR policy to be created.
+  ///
+  /// Note that when a pick is sent to the RR policy, we inject our own
+  /// on_complete callback, so that we can intercept the result before
+  /// invoking the original on_complete callback.  This allows us to set the
+  /// LB token metadata and add client_stats to the call context.
+  /// See \a pending_pick_complete() for details.
+  struct PendingPick {
+    // The grpclb instance that created the wrapping. This instance is not
+    // owned; reference counts are untouched. It's used only for logging
+    // purposes.
+    GrpcLb* grpclb_policy;
+    // The original pick.
+    PickState* pick;
+    // Our on_complete closure and the original one.
+    grpc_closure on_complete;
+    grpc_closure* original_on_complete;
+    // The LB token associated with the pick.  This is set via user_data in
+    // the pick.
+    grpc_mdelem lb_token;
+    // Stats for client-side load reporting. Note that this holds a
+    // reference, which must be either passed on via context or unreffed.
+    grpc_grpclb_client_stats* client_stats = nullptr;
+    // Next pending pick.
+    PendingPick* next = nullptr;
+  };
+
+  /// A linked list of pending pings waiting for the RR policy to be created.
+  struct PendingPing {
+    grpc_closure* on_initiate;
+    grpc_closure* on_ack;
+    PendingPing* next = nullptr;
+  };
+
+  /// Contains a call to the LB server and all the data related to the call.
+  class BalancerCallState
+      : public InternallyRefCountedWithTracing<BalancerCallState> {
+   public:
+    explicit BalancerCallState(
+        RefCountedPtr<LoadBalancingPolicy> parent_grpclb_policy);
+
+    // It's the caller's responsibility to ensure that Orphan() is called from
+    // inside the combiner.
+    void Orphan() override;
+
+    void StartQuery();
+
+    grpc_grpclb_client_stats* client_stats() const { return client_stats_; }
+    bool seen_initial_response() const { return seen_initial_response_; }
+
+   private:
+    ~BalancerCallState();
+
+    GrpcLb* grpclb_policy() const {
+      return static_cast<GrpcLb*>(grpclb_policy_.get());
+    }
+
+    void ScheduleNextClientLoadReportLocked();
+    void SendClientLoadReportLocked();
+
+    static bool LoadReportCountersAreZero(grpc_grpclb_request* request);
+
+    static void MaybeSendClientLoadReportLocked(void* arg, grpc_error* error);
+    static void ClientLoadReportDoneLocked(void* arg, grpc_error* error);
+    static void OnInitialRequestSentLocked(void* arg, grpc_error* error);
+    static void OnBalancerMessageReceivedLocked(void* arg, grpc_error* error);
+    static void OnBalancerStatusReceivedLocked(void* arg, grpc_error* error);
+
+    // The owning LB policy.
+    RefCountedPtr<LoadBalancingPolicy> grpclb_policy_;
+
+    // The streaming call to the LB server. Always non-NULL.
+    grpc_call* lb_call_ = nullptr;
+
+    // recv_initial_metadata
+    grpc_metadata_array lb_initial_metadata_recv_;
+
+    // send_message
+    grpc_byte_buffer* send_message_payload_ = nullptr;
+    grpc_closure lb_on_initial_request_sent_;
+
+    // recv_message
+    grpc_byte_buffer* recv_message_payload_ = nullptr;
+    grpc_closure lb_on_balancer_message_received_;
+    bool seen_initial_response_ = false;
+
+    // recv_trailing_metadata
+    grpc_closure lb_on_balancer_status_received_;
+    grpc_metadata_array lb_trailing_metadata_recv_;
+    grpc_status_code lb_call_status_;
+    grpc_slice lb_call_status_details_;
+
+    // The stats for client-side load reporting associated with this LB call.
+    // Created after the first serverlist is received.
+    grpc_grpclb_client_stats* client_stats_ = nullptr;
+    grpc_millis client_stats_report_interval_ = 0;
+    grpc_timer client_load_report_timer_;
+    bool client_load_report_timer_callback_pending_ = false;
+    bool last_client_load_report_counters_were_zero_ = false;
+    bool client_load_report_is_due_ = false;
+    // The closure used for either the load report timer or the callback for
+    // completion of sending the load report.
+    grpc_closure client_load_report_closure_;
+  };
+
+  ~GrpcLb();
+
+  void ShutdownLocked() override;
+
+  // Helper function used in ctor and UpdateLocked().
+  void ProcessChannelArgsLocked(const grpc_channel_args& args);
+
+  // Methods for dealing with the balancer channel and call.
+  void StartPickingLocked();
+  void StartBalancerCallLocked();
+  static void OnFallbackTimerLocked(void* arg, grpc_error* error);
+  void StartBalancerCallRetryTimerLocked();
+  static void OnBalancerCallRetryTimerLocked(void* arg, grpc_error* error);
+  static void OnBalancerChannelConnectivityChangedLocked(void* arg,
+                                                         grpc_error* error);
+
+  // Pending pick methods.
+  static void PendingPickSetMetadataAndContext(PendingPick* pp);
+  PendingPick* PendingPickCreate(PickState* pick);
+  void AddPendingPick(PendingPick* pp);
+  static void OnPendingPickComplete(void* arg, grpc_error* error);
+
+  // Pending ping methods.
+  void AddPendingPing(grpc_closure* on_initiate, grpc_closure* on_ack);
+
+  // Methods for dealing with the RR policy.
+  void CreateOrUpdateRoundRobinPolicyLocked();
+  grpc_channel_args* CreateRoundRobinPolicyArgsLocked();
+  void CreateRoundRobinPolicyLocked(const Args& args);
+  bool PickFromRoundRobinPolicyLocked(bool force_async, PendingPick* pp);
+  void UpdateConnectivityStateFromRoundRobinPolicyLocked(
+      grpc_error* rr_state_error);
+  static void OnRoundRobinConnectivityChangedLocked(void* arg,
+                                                    grpc_error* error);
+  static void OnRoundRobinRequestReresolutionLocked(void* arg,
+                                                    grpc_error* error);
+
+  // Who the client is trying to communicate with.
+  const char* server_name_ = nullptr;
+
+  // Current channel args from the resolver.
+  grpc_channel_args* args_ = nullptr;
+
+  // Internal state.
+  bool started_picking_ = false;
+  bool shutting_down_ = false;
+  grpc_connectivity_state_tracker state_tracker_;
+
+  // The channel for communicating with the LB server.
+  grpc_channel* lb_channel_ = nullptr;
+  grpc_connectivity_state lb_channel_connectivity_;
+  grpc_closure lb_channel_on_connectivity_changed_;
+  // Are we already watching the LB channel's connectivity?
+  bool watching_lb_channel_ = false;
+  // Response generator to inject address updates into lb_channel_.
+  RefCountedPtr<FakeResolverResponseGenerator> response_generator_;
+
+  // The data associated with the current LB call. It holds a ref to this LB
+  // policy. It's initialized every time we query for backends. It's reset to
+  // NULL whenever the current LB call is no longer needed (e.g., the LB policy
+  // is shutting down, or the LB call has ended). A non-NULL lb_calld_ always
+  // contains a non-NULL lb_call_.
+  OrphanablePtr<BalancerCallState> lb_calld_;
+  // Timeout in milliseconds for the LB call. 0 means no deadline.
+  int lb_call_timeout_ms_ = 0;
+  // Balancer call retry state.
+  BackOff lb_call_backoff_;
+  bool retry_timer_callback_pending_ = false;
+  grpc_timer lb_call_retry_timer_;
+  grpc_closure lb_on_call_retry_;
+
+  // The deserialized response from the balancer. May be nullptr until one
+  // such response has arrived.
+  grpc_grpclb_serverlist* serverlist_ = nullptr;
+  // Index into serverlist for next pick.
+  // If the server at this index is a drop, we return a drop.
+  // Otherwise, we delegate to the RR policy.
+  size_t serverlist_index_ = 0;
+
+  // Timeout in milliseconds for before using fallback backend addresses.
+  // 0 means not using fallback.
+  int lb_fallback_timeout_ms_ = 0;
+  // The backend addresses from the resolver.
+  grpc_lb_addresses* fallback_backend_addresses_ = nullptr;
+  // Fallback timer.
+  bool fallback_timer_callback_pending_ = false;
+  grpc_timer lb_fallback_timer_;
+  grpc_closure lb_on_fallback_;
+
+  // Pending picks and pings that are waiting on the RR policy's connectivity.
+  PendingPick* pending_picks_ = nullptr;
+  PendingPing* pending_pings_ = nullptr;
+
+  // The RR policy to use for the backends.
+  OrphanablePtr<LoadBalancingPolicy> rr_policy_;
+  grpc_connectivity_state rr_connectivity_state_;
+  grpc_closure on_rr_connectivity_changed_;
+  grpc_closure on_rr_request_reresolution_;
 };
 
-/// A linked list of pending pings waiting for the RR policy to be created.
-struct pending_ping {
-  grpc_closure* on_initiate;
-  grpc_closure* on_ack;
-  struct pending_ping* next;
-};
+//
+// serverlist parsing code
+//
 
-}  // namespace
-
-typedef struct glb_lb_call_data {
-  struct glb_lb_policy* glb_policy;
-  // TODO(juanlishen): c++ize this struct.
-  gpr_refcount refs;
-
-  /** The streaming call to the LB server. Always non-NULL. */
-  grpc_call* lb_call;
-
-  /** The initial metadata received from the LB server. */
-  grpc_metadata_array lb_initial_metadata_recv;
-
-  /** The message sent to the LB server. It's used to query for backends (the
-   * value may vary if the LB server indicates a redirect) or send client load
-   * report. */
-  grpc_byte_buffer* send_message_payload;
-  /** The callback after the initial request is sent. */
-  grpc_closure lb_on_sent_initial_request;
-
-  /** The response received from the LB server, if any. */
-  grpc_byte_buffer* recv_message_payload;
-  /** The callback to process the response received from the LB server. */
-  grpc_closure lb_on_response_received;
-  bool seen_initial_response;
-
-  /** The callback to process the status received from the LB server, which
-   * signals the end of the LB call. */
-  grpc_closure lb_on_server_status_received;
-  /** The trailing metadata from the LB server. */
-  grpc_metadata_array lb_trailing_metadata_recv;
-  /** The call status code and details. */
-  grpc_status_code lb_call_status;
-  grpc_slice lb_call_status_details;
-
-  /** The stats for client-side load reporting associated with this LB call.
-   * Created after the first serverlist is received. */
-  grpc_grpclb_client_stats* client_stats;
-  /** The interval and timer for next client load report. */
-  grpc_millis client_stats_report_interval;
-  grpc_timer client_load_report_timer;
-  bool client_load_report_timer_callback_pending;
-  bool last_client_load_report_counters_were_zero;
-  bool client_load_report_is_due;
-  /** The closure used for either the load report timer or the callback for
-   * completion of sending the load report. */
-  grpc_closure client_load_report_closure;
-} glb_lb_call_data;
-
-typedef struct glb_lb_policy {
-  /** Base policy: must be first. */
-  grpc_lb_policy base;
-
-  /** Who the client is trying to communicate with. */
-  const char* server_name;
-
-  /** Channel related data that will be propagated to the internal RR policy. */
-  grpc_client_channel_factory* cc_factory;
-  grpc_channel_args* args;
-
-  /** Timeout in milliseconds for before using fallback backend addresses.
-   * 0 means not using fallback. */
-  int lb_fallback_timeout_ms;
-
-  /** The channel for communicating with the LB server. */
-  grpc_channel* lb_channel;
-
-  /** The data associated with the current LB call. It holds a ref to this LB
-   * policy. It's initialized every time we query for backends. It's reset to
-   * NULL whenever the current LB call is no longer needed (e.g., the LB policy
-   * is shutting down, or the LB call has ended). A non-NULL lb_calld always
-   * contains a non-NULL lb_call. */
-  glb_lb_call_data* lb_calld;
-
-  /** response generator to inject address updates into \a lb_channel */
-  grpc_fake_resolver_response_generator* response_generator;
-
-  /** the RR policy to use of the backend servers returned by the LB server */
-  grpc_lb_policy* rr_policy;
-
-  grpc_closure on_rr_connectivity_changed;
-  grpc_connectivity_state rr_connectivity_state;
-
-  bool started_picking;
-
-  /** our connectivity state tracker */
-  grpc_connectivity_state_tracker state_tracker;
-
-  /** connectivity state of the LB channel */
-  grpc_connectivity_state lb_channel_connectivity;
-
-  /** stores the deserialized response from the LB. May be nullptr until one
-   * such response has arrived. */
-  grpc_grpclb_serverlist* serverlist;
-
-  /** Index into serverlist for next pick.
-   * If the server at this index is a drop, we return a drop.
-   * Otherwise, we delegate to the RR policy. */
-  size_t serverlist_index;
-
-  /** stores the backend addresses from the resolver */
-  grpc_lb_addresses* fallback_backend_addresses;
-
-  /** list of picks that are waiting on RR's policy connectivity */
-  pending_pick* pending_picks;
-
-  /** list of pings that are waiting on RR's policy connectivity */
-  pending_ping* pending_pings;
-
-  bool shutting_down;
-
-  /** are we already watching the LB channel's connectivity? */
-  bool watching_lb_channel;
-
-  /** is the callback associated with \a lb_call_retry_timer pending? */
-  bool retry_timer_callback_pending;
-
-  /** is the callback associated with \a lb_fallback_timer pending? */
-  bool fallback_timer_callback_pending;
-
-  /** called upon changes to the LB channel's connectivity. */
-  grpc_closure lb_channel_on_connectivity_changed;
-
-  /************************************************************/
-  /*  client data associated with the LB server communication */
-  /************************************************************/
-
-  /** LB call retry backoff state */
-  grpc_core::ManualConstructor<grpc_core::BackOff> lb_call_backoff;
-
-  /** timeout in milliseconds for the LB call. 0 means no deadline. */
-  int lb_call_timeout_ms;
-
-  /** LB call retry timer */
-  grpc_timer lb_call_retry_timer;
-  /** LB call retry timer callback */
-  grpc_closure lb_on_call_retry;
-
-  /** LB fallback timer */
-  grpc_timer lb_fallback_timer;
-  /** LB fallback timer callback */
-  grpc_closure lb_on_fallback;
-} glb_lb_policy;
-
-static void glb_lb_call_data_ref(glb_lb_call_data* lb_calld,
-                                 const char* reason) {
-  gpr_ref_non_zero(&lb_calld->refs);
-  if (grpc_lb_glb_trace.enabled()) {
-    const gpr_atm count = gpr_atm_acq_load(&lb_calld->refs.count);
-    gpr_log(GPR_DEBUG, "[%s %p] lb_calld %p REF %lu->%lu (%s)",
-            grpc_lb_glb_trace.name(), lb_calld->glb_policy, lb_calld,
-            (unsigned long)(count - 1), (unsigned long)count, reason);
+// vtable for LB tokens in grpc_lb_addresses
+void* lb_token_copy(void* token) {
+  return token == nullptr
+             ? nullptr
+             : (void*)GRPC_MDELEM_REF(grpc_mdelem{(uintptr_t)token}).payload;
+}
+void lb_token_destroy(void* token) {
+  if (token != nullptr) {
+    GRPC_MDELEM_UNREF(grpc_mdelem{(uintptr_t)token});
   }
 }
-
-static void glb_lb_call_data_unref(glb_lb_call_data* lb_calld,
-                                   const char* reason) {
-  const bool done = gpr_unref(&lb_calld->refs);
-  if (grpc_lb_glb_trace.enabled()) {
-    const gpr_atm count = gpr_atm_acq_load(&lb_calld->refs.count);
-    gpr_log(GPR_DEBUG, "[%s %p] lb_calld %p UNREF %lu->%lu (%s)",
-            grpc_lb_glb_trace.name(), lb_calld->glb_policy, lb_calld,
-            (unsigned long)(count + 1), (unsigned long)count, reason);
-  }
-  if (done) {
-    GPR_ASSERT(lb_calld->lb_call != nullptr);
-    grpc_call_unref(lb_calld->lb_call);
-    grpc_metadata_array_destroy(&lb_calld->lb_initial_metadata_recv);
-    grpc_metadata_array_destroy(&lb_calld->lb_trailing_metadata_recv);
-    grpc_byte_buffer_destroy(lb_calld->send_message_payload);
-    grpc_byte_buffer_destroy(lb_calld->recv_message_payload);
-    grpc_slice_unref_internal(lb_calld->lb_call_status_details);
-    if (lb_calld->client_stats != nullptr) {
-      grpc_grpclb_client_stats_unref(lb_calld->client_stats);
-    }
-    GRPC_LB_POLICY_UNREF(&lb_calld->glb_policy->base, "lb_calld");
-    gpr_free(lb_calld);
-  }
+int lb_token_cmp(void* token1, void* token2) {
+  if (token1 > token2) return 1;
+  if (token1 < token2) return -1;
+  return 0;
 }
+const grpc_lb_user_data_vtable lb_token_vtable = {
+    lb_token_copy, lb_token_destroy, lb_token_cmp};
 
-static void lb_call_data_shutdown(glb_lb_policy* glb_policy) {
-  GPR_ASSERT(glb_policy->lb_calld != nullptr);
-  GPR_ASSERT(glb_policy->lb_calld->lb_call != nullptr);
-  // lb_on_server_status_received will complete the cancellation and clean up.
-  grpc_call_cancel(glb_policy->lb_calld->lb_call, nullptr);
-  if (glb_policy->lb_calld->client_load_report_timer_callback_pending) {
-    grpc_timer_cancel(&glb_policy->lb_calld->client_load_report_timer);
-  }
-  glb_policy->lb_calld = nullptr;
-}
-
-/* add lb_token of selected subchannel (address) to the call's initial
- * metadata */
-static grpc_error* initial_metadata_add_lb_token(
-    grpc_metadata_batch* initial_metadata,
-    grpc_linked_mdelem* lb_token_mdelem_storage, grpc_mdelem lb_token) {
-  GPR_ASSERT(lb_token_mdelem_storage != nullptr);
-  GPR_ASSERT(!GRPC_MDISNULL(lb_token));
-  return grpc_metadata_batch_add_tail(initial_metadata, lb_token_mdelem_storage,
-                                      lb_token);
-}
-
-static void destroy_client_stats(void* arg) {
-  grpc_grpclb_client_stats_unref((grpc_grpclb_client_stats*)arg);
-}
-
-static void pending_pick_set_metadata_and_context(pending_pick* pp) {
-  /* if connected_subchannel is nullptr, no pick has been made by the RR
-   * policy (e.g., all addresses failed to connect). There won't be any
-   * user_data/token available */
-  if (pp->pick->connected_subchannel != nullptr) {
-    if (!GRPC_MDISNULL(pp->lb_token)) {
-      initial_metadata_add_lb_token(pp->pick->initial_metadata,
-                                    &pp->pick->lb_token_mdelem_storage,
-                                    GRPC_MDELEM_REF(pp->lb_token));
-    } else {
-      gpr_log(GPR_ERROR,
-              "[grpclb %p] No LB token for connected subchannel pick %p",
-              pp->glb_policy, pp->pick);
-      abort();
-    }
-    // Pass on client stats via context. Passes ownership of the reference.
-    if (pp->client_stats != nullptr) {
-      pp->pick->subchannel_call_context[GRPC_GRPCLB_CLIENT_STATS].value =
-          pp->client_stats;
-      pp->pick->subchannel_call_context[GRPC_GRPCLB_CLIENT_STATS].destroy =
-          destroy_client_stats;
-    }
-  } else {
-    if (pp->client_stats != nullptr) {
-      grpc_grpclb_client_stats_unref(pp->client_stats);
+// Returns the backend addresses extracted from the given addresses.
+grpc_lb_addresses* ExtractBackendAddresses(const grpc_lb_addresses* addresses) {
+  // First pass: count the number of backend addresses.
+  size_t num_backends = 0;
+  for (size_t i = 0; i < addresses->num_addresses; ++i) {
+    if (!addresses->addresses[i].is_balancer) {
+      ++num_backends;
     }
   }
+  // Second pass: actually populate the addresses and (empty) LB tokens.
+  grpc_lb_addresses* backend_addresses =
+      grpc_lb_addresses_create(num_backends, &lb_token_vtable);
+  size_t num_copied = 0;
+  for (size_t i = 0; i < addresses->num_addresses; ++i) {
+    if (addresses->addresses[i].is_balancer) continue;
+    const grpc_resolved_address* addr = &addresses->addresses[i].address;
+    grpc_lb_addresses_set_address(backend_addresses, num_copied, &addr->addr,
+                                  addr->len, false /* is_balancer */,
+                                  nullptr /* balancer_name */,
+                                  (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload);
+    ++num_copied;
+  }
+  return backend_addresses;
 }
 
-/* The \a on_complete closure passed as part of the pick requires keeping a
- * reference to its associated round robin instance. We wrap this closure in
- * order to unref the round robin instance upon its invocation */
-static void pending_pick_complete(void* arg, grpc_error* error) {
-  pending_pick* pp = (pending_pick*)arg;
-  pending_pick_set_metadata_and_context(pp);
-  GRPC_CLOSURE_SCHED(pp->original_on_complete, GRPC_ERROR_REF(error));
-  gpr_free(pp);
-}
-
-static pending_pick* pending_pick_create(glb_lb_policy* glb_policy,
-                                         grpc_lb_policy_pick_state* pick) {
-  pending_pick* pp = (pending_pick*)gpr_zalloc(sizeof(*pp));
-  pp->pick = pick;
-  pp->glb_policy = glb_policy;
-  GRPC_CLOSURE_INIT(&pp->on_complete, pending_pick_complete, pp,
-                    grpc_schedule_on_exec_ctx);
-  pp->original_on_complete = pick->on_complete;
-  pp->pick->on_complete = &pp->on_complete;
-  return pp;
-}
-
-static void pending_pick_add(pending_pick** root, pending_pick* new_pp) {
-  new_pp->next = *root;
-  *root = new_pp;
-}
-
-static void pending_ping_add(pending_ping** root, grpc_closure* on_initiate,
-                             grpc_closure* on_ack) {
-  pending_ping* pping = (pending_ping*)gpr_zalloc(sizeof(*pping));
-  pping->on_initiate = on_initiate;
-  pping->on_ack = on_ack;
-  pping->next = *root;
-  *root = pping;
-}
-
-static bool is_server_valid(const grpc_grpclb_server* server, size_t idx,
-                            bool log) {
+bool IsServerValid(const grpc_grpclb_server* server, size_t idx, bool log) {
   if (server->drop) return false;
   const grpc_grpclb_ip_address* ip = &server->ip_address;
   if (server->port >> 16 != 0) {
@@ -462,56 +414,36 @@
   return true;
 }
 
-/* vtable for LB tokens in grpc_lb_addresses. */
-static void* lb_token_copy(void* token) {
-  return token == nullptr
-             ? nullptr
-             : (void*)GRPC_MDELEM_REF(grpc_mdelem{(uintptr_t)token}).payload;
-}
-static void lb_token_destroy(void* token) {
-  if (token != nullptr) {
-    GRPC_MDELEM_UNREF(grpc_mdelem{(uintptr_t)token});
-  }
-}
-static int lb_token_cmp(void* token1, void* token2) {
-  if (token1 > token2) return 1;
-  if (token1 < token2) return -1;
-  return 0;
-}
-static const grpc_lb_user_data_vtable lb_token_vtable = {
-    lb_token_copy, lb_token_destroy, lb_token_cmp};
-
-static void parse_server(const grpc_grpclb_server* server,
-                         grpc_resolved_address* addr) {
+void ParseServer(const grpc_grpclb_server* server,
+                 grpc_resolved_address* addr) {
   memset(addr, 0, sizeof(*addr));
   if (server->drop) return;
-  const uint16_t netorder_port = htons((uint16_t)server->port);
+  const uint16_t netorder_port = grpc_htons((uint16_t)server->port);
   /* the addresses are given in binary format (a in(6)_addr struct) in
    * server->ip_address.bytes. */
   const grpc_grpclb_ip_address* ip = &server->ip_address;
   if (ip->size == 4) {
-    addr->len = sizeof(struct sockaddr_in);
-    struct sockaddr_in* addr4 = (struct sockaddr_in*)&addr->addr;
-    addr4->sin_family = AF_INET;
+    addr->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in));
+    grpc_sockaddr_in* addr4 = reinterpret_cast<grpc_sockaddr_in*>(&addr->addr);
+    addr4->sin_family = GRPC_AF_INET;
     memcpy(&addr4->sin_addr, ip->bytes, ip->size);
     addr4->sin_port = netorder_port;
   } else if (ip->size == 16) {
-    addr->len = sizeof(struct sockaddr_in6);
-    struct sockaddr_in6* addr6 = (struct sockaddr_in6*)&addr->addr;
-    addr6->sin6_family = AF_INET6;
+    addr->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in6));
+    grpc_sockaddr_in6* addr6 = (grpc_sockaddr_in6*)&addr->addr;
+    addr6->sin6_family = GRPC_AF_INET6;
     memcpy(&addr6->sin6_addr, ip->bytes, ip->size);
     addr6->sin6_port = netorder_port;
   }
 }
 
-/* Returns addresses extracted from \a serverlist. */
-static grpc_lb_addresses* process_serverlist_locked(
-    const grpc_grpclb_serverlist* serverlist) {
+// Returns addresses extracted from \a serverlist.
+grpc_lb_addresses* ProcessServerlist(const grpc_grpclb_serverlist* serverlist) {
   size_t num_valid = 0;
   /* first pass: count how many are valid in order to allocate the necessary
    * memory in a single block */
   for (size_t i = 0; i < serverlist->num_servers; ++i) {
-    if (is_server_valid(serverlist->servers[i], i, true)) ++num_valid;
+    if (IsServerValid(serverlist->servers[i], i, true)) ++num_valid;
   }
   grpc_lb_addresses* lb_addresses =
       grpc_lb_addresses_create(num_valid, &lb_token_vtable);
@@ -523,11 +455,11 @@
   size_t addr_idx = 0;
   for (size_t sl_idx = 0; sl_idx < serverlist->num_servers; ++sl_idx) {
     const grpc_grpclb_server* server = serverlist->servers[sl_idx];
-    if (!is_server_valid(serverlist->servers[sl_idx], sl_idx, false)) continue;
+    if (!IsServerValid(serverlist->servers[sl_idx], sl_idx, false)) continue;
     GPR_ASSERT(addr_idx < num_valid);
     /* address processing */
     grpc_resolved_address addr;
-    parse_server(server, &addr);
+    ParseServer(server, &addr);
     /* lb token processing */
     void* user_data;
     if (server->has_load_balance_token) {
@@ -558,37 +490,1283 @@
   return lb_addresses;
 }
 
-/* Returns the backend addresses extracted from the given addresses */
-static grpc_lb_addresses* extract_backend_addresses_locked(
-    const grpc_lb_addresses* addresses) {
-  /* first pass: count the number of backend addresses */
-  size_t num_backends = 0;
-  for (size_t i = 0; i < addresses->num_addresses; ++i) {
-    if (!addresses->addresses[i].is_balancer) {
-      ++num_backends;
-    }
-  }
-  /* second pass: actually populate the addresses and (empty) LB tokens */
-  grpc_lb_addresses* backend_addresses =
-      grpc_lb_addresses_create(num_backends, &lb_token_vtable);
-  size_t num_copied = 0;
-  for (size_t i = 0; i < addresses->num_addresses; ++i) {
-    if (addresses->addresses[i].is_balancer) continue;
-    const grpc_resolved_address* addr = &addresses->addresses[i].address;
-    grpc_lb_addresses_set_address(backend_addresses, num_copied, &addr->addr,
-                                  addr->len, false /* is_balancer */,
-                                  nullptr /* balancer_name */,
-                                  (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload);
-    ++num_copied;
-  }
-  return backend_addresses;
+//
+// GrpcLb::BalancerCallState
+//
+
+GrpcLb::BalancerCallState::BalancerCallState(
+    RefCountedPtr<LoadBalancingPolicy> parent_grpclb_policy)
+    : InternallyRefCountedWithTracing<BalancerCallState>(&grpc_lb_glb_trace),
+      grpclb_policy_(std::move(parent_grpclb_policy)) {
+  GPR_ASSERT(grpclb_policy_ != nullptr);
+  GPR_ASSERT(!grpclb_policy()->shutting_down_);
+  // Init the LB call. Note that the LB call will progress every time there's
+  // activity in grpclb_policy_->interested_parties(), which is comprised of
+  // the polling entities from client_channel.
+  GPR_ASSERT(grpclb_policy()->server_name_ != nullptr);
+  GPR_ASSERT(grpclb_policy()->server_name_[0] != '\0');
+  grpc_slice host =
+      grpc_slice_from_copied_string(grpclb_policy()->server_name_);
+  grpc_millis deadline =
+      grpclb_policy()->lb_call_timeout_ms_ == 0
+          ? GRPC_MILLIS_INF_FUTURE
+          : ExecCtx::Get()->Now() + grpclb_policy()->lb_call_timeout_ms_;
+  lb_call_ = grpc_channel_create_pollset_set_call(
+      grpclb_policy()->lb_channel_, nullptr, GRPC_PROPAGATE_DEFAULTS,
+      grpclb_policy_->interested_parties(),
+      GRPC_MDSTR_SLASH_GRPC_DOT_LB_DOT_V1_DOT_LOADBALANCER_SLASH_BALANCELOAD,
+      &host, deadline, nullptr);
+  grpc_slice_unref_internal(host);
+  // Init the LB call request payload.
+  grpc_grpclb_request* request =
+      grpc_grpclb_request_create(grpclb_policy()->server_name_);
+  grpc_slice request_payload_slice = grpc_grpclb_request_encode(request);
+  send_message_payload_ =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  grpc_slice_unref_internal(request_payload_slice);
+  grpc_grpclb_request_destroy(request);
+  // Init other data associated with the LB call.
+  grpc_metadata_array_init(&lb_initial_metadata_recv_);
+  grpc_metadata_array_init(&lb_trailing_metadata_recv_);
+  GRPC_CLOSURE_INIT(&lb_on_initial_request_sent_, OnInitialRequestSentLocked,
+                    this, grpc_combiner_scheduler(grpclb_policy()->combiner()));
+  GRPC_CLOSURE_INIT(&lb_on_balancer_message_received_,
+                    OnBalancerMessageReceivedLocked, this,
+                    grpc_combiner_scheduler(grpclb_policy()->combiner()));
+  GRPC_CLOSURE_INIT(&lb_on_balancer_status_received_,
+                    OnBalancerStatusReceivedLocked, this,
+                    grpc_combiner_scheduler(grpclb_policy()->combiner()));
 }
 
-static void update_lb_connectivity_status_locked(
-    glb_lb_policy* glb_policy, grpc_connectivity_state rr_state,
+GrpcLb::BalancerCallState::~BalancerCallState() {
+  GPR_ASSERT(lb_call_ != nullptr);
+  grpc_call_unref(lb_call_);
+  grpc_metadata_array_destroy(&lb_initial_metadata_recv_);
+  grpc_metadata_array_destroy(&lb_trailing_metadata_recv_);
+  grpc_byte_buffer_destroy(send_message_payload_);
+  grpc_byte_buffer_destroy(recv_message_payload_);
+  grpc_slice_unref_internal(lb_call_status_details_);
+  if (client_stats_ != nullptr) {
+    grpc_grpclb_client_stats_unref(client_stats_);
+  }
+}
+
+void GrpcLb::BalancerCallState::Orphan() {
+  GPR_ASSERT(lb_call_ != nullptr);
+  // If we are here because grpclb_policy wants to cancel the call,
+  // lb_on_balancer_status_received_ will complete the cancellation and clean
+  // up. Otherwise, we are here because grpclb_policy has to orphan a failed
+  // call, then the following cancellation will be a no-op.
+  grpc_call_cancel(lb_call_, nullptr);
+  if (client_load_report_timer_callback_pending_) {
+    grpc_timer_cancel(&client_load_report_timer_);
+  }
+  // Note that the initial ref is hold by lb_on_balancer_status_received_
+  // instead of the caller of this function. So the corresponding unref happens
+  // in lb_on_balancer_status_received_ instead of here.
+}
+
+void GrpcLb::BalancerCallState::StartQuery() {
+  GPR_ASSERT(lb_call_ != nullptr);
+  if (grpc_lb_glb_trace.enabled()) {
+    gpr_log(GPR_INFO,
+            "[grpclb %p] Starting LB call (lb_calld: %p, lb_call: %p)",
+            grpclb_policy_.get(), this, lb_call_);
+  }
+  // Create the ops.
+  grpc_call_error call_error;
+  grpc_op ops[3];
+  memset(ops, 0, sizeof(ops));
+  // Op: send initial metadata.
+  grpc_op* op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  // Op: send request message.
+  GPR_ASSERT(send_message_payload_ != nullptr);
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = send_message_payload_;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  // TODO(roth): We currently track this ref manually.  Once the
+  // ClosureRef API is ready, we should pass the RefCountedPtr<> along
+  // with the callback.
+  auto self = Ref(DEBUG_LOCATION, "on_initial_request_sent");
+  self.release();
+  call_error = grpc_call_start_batch_and_execute(
+      lb_call_, ops, (size_t)(op - ops), &lb_on_initial_request_sent_);
+  GPR_ASSERT(GRPC_CALL_OK == call_error);
+  // Op: recv initial metadata.
+  op = ops;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata =
+      &lb_initial_metadata_recv_;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  // Op: recv response.
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &recv_message_payload_;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  // TODO(roth): We currently track this ref manually.  Once the
+  // ClosureRef API is ready, we should pass the RefCountedPtr<> along
+  // with the callback.
+  self = Ref(DEBUG_LOCATION, "on_message_received");
+  self.release();
+  call_error = grpc_call_start_batch_and_execute(
+      lb_call_, ops, (size_t)(op - ops), &lb_on_balancer_message_received_);
+  GPR_ASSERT(GRPC_CALL_OK == call_error);
+  // Op: recv server status.
+  op = ops;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata =
+      &lb_trailing_metadata_recv_;
+  op->data.recv_status_on_client.status = &lb_call_status_;
+  op->data.recv_status_on_client.status_details = &lb_call_status_details_;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  // This callback signals the end of the LB call, so it relies on the initial
+  // ref instead of a new ref. When it's invoked, it's the initial ref that is
+  // unreffed.
+  call_error = grpc_call_start_batch_and_execute(
+      lb_call_, ops, (size_t)(op - ops), &lb_on_balancer_status_received_);
+  GPR_ASSERT(GRPC_CALL_OK == call_error);
+};
+
+void GrpcLb::BalancerCallState::ScheduleNextClientLoadReportLocked() {
+  const grpc_millis next_client_load_report_time =
+      ExecCtx::Get()->Now() + client_stats_report_interval_;
+  GRPC_CLOSURE_INIT(&client_load_report_closure_,
+                    MaybeSendClientLoadReportLocked, this,
+                    grpc_combiner_scheduler(grpclb_policy()->combiner()));
+  grpc_timer_init(&client_load_report_timer_, next_client_load_report_time,
+                  &client_load_report_closure_);
+  client_load_report_timer_callback_pending_ = true;
+}
+
+void GrpcLb::BalancerCallState::MaybeSendClientLoadReportLocked(
+    void* arg, grpc_error* error) {
+  BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
+  GrpcLb* grpclb_policy = lb_calld->grpclb_policy();
+  lb_calld->client_load_report_timer_callback_pending_ = false;
+  if (error != GRPC_ERROR_NONE || lb_calld != grpclb_policy->lb_calld_.get()) {
+    lb_calld->Unref(DEBUG_LOCATION, "client_load_report");
+    return;
+  }
+  // If we've already sent the initial request, then we can go ahead and send
+  // the load report. Otherwise, we need to wait until the initial request has
+  // been sent to send this (see OnInitialRequestSentLocked()).
+  if (lb_calld->send_message_payload_ == nullptr) {
+    lb_calld->SendClientLoadReportLocked();
+  } else {
+    lb_calld->client_load_report_is_due_ = true;
+  }
+}
+
+bool GrpcLb::BalancerCallState::LoadReportCountersAreZero(
+    grpc_grpclb_request* request) {
+  grpc_grpclb_dropped_call_counts* drop_entries =
+      static_cast<grpc_grpclb_dropped_call_counts*>(
+          request->client_stats.calls_finished_with_drop.arg);
+  return request->client_stats.num_calls_started == 0 &&
+         request->client_stats.num_calls_finished == 0 &&
+         request->client_stats.num_calls_finished_with_client_failed_to_send ==
+             0 &&
+         request->client_stats.num_calls_finished_known_received == 0 &&
+         (drop_entries == nullptr || drop_entries->num_entries == 0);
+}
+
+void GrpcLb::BalancerCallState::SendClientLoadReportLocked() {
+  // Construct message payload.
+  GPR_ASSERT(send_message_payload_ == nullptr);
+  grpc_grpclb_request* request =
+      grpc_grpclb_load_report_request_create_locked(client_stats_);
+  // Skip client load report if the counters were all zero in the last
+  // report and they are still zero in this one.
+  if (LoadReportCountersAreZero(request)) {
+    if (last_client_load_report_counters_were_zero_) {
+      grpc_grpclb_request_destroy(request);
+      ScheduleNextClientLoadReportLocked();
+      return;
+    }
+    last_client_load_report_counters_were_zero_ = true;
+  } else {
+    last_client_load_report_counters_were_zero_ = false;
+  }
+  grpc_slice request_payload_slice = grpc_grpclb_request_encode(request);
+  send_message_payload_ =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  grpc_slice_unref_internal(request_payload_slice);
+  grpc_grpclb_request_destroy(request);
+  // Send the report.
+  grpc_op op;
+  memset(&op, 0, sizeof(op));
+  op.op = GRPC_OP_SEND_MESSAGE;
+  op.data.send_message.send_message = send_message_payload_;
+  GRPC_CLOSURE_INIT(&client_load_report_closure_, ClientLoadReportDoneLocked,
+                    this, grpc_combiner_scheduler(grpclb_policy()->combiner()));
+  grpc_call_error call_error = grpc_call_start_batch_and_execute(
+      lb_call_, &op, 1, &client_load_report_closure_);
+  if (call_error != GRPC_CALL_OK) {
+    gpr_log(GPR_ERROR, "[grpclb %p] call_error=%d", grpclb_policy_.get(),
+            call_error);
+    GPR_ASSERT(GRPC_CALL_OK == call_error);
+  }
+}
+
+void GrpcLb::BalancerCallState::ClientLoadReportDoneLocked(void* arg,
+                                                           grpc_error* error) {
+  BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
+  GrpcLb* grpclb_policy = lb_calld->grpclb_policy();
+  grpc_byte_buffer_destroy(lb_calld->send_message_payload_);
+  lb_calld->send_message_payload_ = nullptr;
+  if (error != GRPC_ERROR_NONE || lb_calld != grpclb_policy->lb_calld_.get()) {
+    lb_calld->Unref(DEBUG_LOCATION, "client_load_report");
+    return;
+  }
+  lb_calld->ScheduleNextClientLoadReportLocked();
+}
+
+void GrpcLb::BalancerCallState::OnInitialRequestSentLocked(void* arg,
+                                                           grpc_error* error) {
+  BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
+  grpc_byte_buffer_destroy(lb_calld->send_message_payload_);
+  lb_calld->send_message_payload_ = nullptr;
+  // If we attempted to send a client load report before the initial request was
+  // sent (and this lb_calld is still in use), send the load report now.
+  if (lb_calld->client_load_report_is_due_ &&
+      lb_calld == lb_calld->grpclb_policy()->lb_calld_.get()) {
+    lb_calld->SendClientLoadReportLocked();
+    lb_calld->client_load_report_is_due_ = false;
+  }
+  lb_calld->Unref(DEBUG_LOCATION, "on_initial_request_sent");
+}
+
+void GrpcLb::BalancerCallState::OnBalancerMessageReceivedLocked(
+    void* arg, grpc_error* error) {
+  BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
+  GrpcLb* grpclb_policy = lb_calld->grpclb_policy();
+  // Empty payload means the LB call was cancelled.
+  if (lb_calld != grpclb_policy->lb_calld_.get() ||
+      lb_calld->recv_message_payload_ == nullptr) {
+    lb_calld->Unref(DEBUG_LOCATION, "on_message_received");
+    return;
+  }
+  grpc_byte_buffer_reader bbr;
+  grpc_byte_buffer_reader_init(&bbr, lb_calld->recv_message_payload_);
+  grpc_slice response_slice = grpc_byte_buffer_reader_readall(&bbr);
+  grpc_byte_buffer_reader_destroy(&bbr);
+  grpc_byte_buffer_destroy(lb_calld->recv_message_payload_);
+  lb_calld->recv_message_payload_ = nullptr;
+  grpc_grpclb_initial_response* initial_response;
+  grpc_grpclb_serverlist* serverlist;
+  if (!lb_calld->seen_initial_response_ &&
+      (initial_response = grpc_grpclb_initial_response_parse(response_slice)) !=
+          nullptr) {
+    // Have NOT seen initial response, look for initial response.
+    if (initial_response->has_client_stats_report_interval) {
+      lb_calld->client_stats_report_interval_ = GPR_MAX(
+          GPR_MS_PER_SEC, grpc_grpclb_duration_to_millis(
+                              &initial_response->client_stats_report_interval));
+      if (grpc_lb_glb_trace.enabled()) {
+        gpr_log(GPR_INFO,
+                "[grpclb %p] Received initial LB response message; "
+                "client load reporting interval = %" PRIdPTR " milliseconds",
+                grpclb_policy, lb_calld->client_stats_report_interval_);
+      }
+    } else if (grpc_lb_glb_trace.enabled()) {
+      gpr_log(GPR_INFO,
+              "[grpclb %p] Received initial LB response message; client load "
+              "reporting NOT enabled",
+              grpclb_policy);
+    }
+    grpc_grpclb_initial_response_destroy(initial_response);
+    lb_calld->seen_initial_response_ = true;
+  } else if ((serverlist = grpc_grpclb_response_parse_serverlist(
+                  response_slice)) != nullptr) {
+    // Have seen initial response, look for serverlist.
+    GPR_ASSERT(lb_calld->lb_call_ != nullptr);
+    if (grpc_lb_glb_trace.enabled()) {
+      gpr_log(GPR_INFO,
+              "[grpclb %p] Serverlist with %" PRIuPTR " servers received",
+              grpclb_policy, serverlist->num_servers);
+      for (size_t i = 0; i < serverlist->num_servers; ++i) {
+        grpc_resolved_address addr;
+        ParseServer(serverlist->servers[i], &addr);
+        char* ipport;
+        grpc_sockaddr_to_string(&ipport, &addr, false);
+        gpr_log(GPR_INFO, "[grpclb %p] Serverlist[%" PRIuPTR "]: %s",
+                grpclb_policy, i, ipport);
+        gpr_free(ipport);
+      }
+    }
+    /* update serverlist */
+    if (serverlist->num_servers > 0) {
+      // Start sending client load report only after we start using the
+      // serverlist returned from the current LB call.
+      if (lb_calld->client_stats_report_interval_ > 0 &&
+          lb_calld->client_stats_ == nullptr) {
+        lb_calld->client_stats_ = grpc_grpclb_client_stats_create();
+        // TODO(roth): We currently track this ref manually.  Once the
+        // ClosureRef API is ready, we should pass the RefCountedPtr<> along
+        // with the callback.
+        auto self = lb_calld->Ref(DEBUG_LOCATION, "client_load_report");
+        self.release();
+        lb_calld->ScheduleNextClientLoadReportLocked();
+      }
+      if (grpc_grpclb_serverlist_equals(grpclb_policy->serverlist_,
+                                        serverlist)) {
+        if (grpc_lb_glb_trace.enabled()) {
+          gpr_log(GPR_INFO,
+                  "[grpclb %p] Incoming server list identical to current, "
+                  "ignoring.",
+                  grpclb_policy);
+        }
+        grpc_grpclb_destroy_serverlist(serverlist);
+      } else { /* new serverlist */
+        if (grpclb_policy->serverlist_ != nullptr) {
+          /* dispose of the old serverlist */
+          grpc_grpclb_destroy_serverlist(grpclb_policy->serverlist_);
+        } else {
+          /* or dispose of the fallback */
+          grpc_lb_addresses_destroy(grpclb_policy->fallback_backend_addresses_);
+          grpclb_policy->fallback_backend_addresses_ = nullptr;
+          if (grpclb_policy->fallback_timer_callback_pending_) {
+            grpc_timer_cancel(&grpclb_policy->lb_fallback_timer_);
+          }
+        }
+        // and update the copy in the GrpcLb instance. This
+        // serverlist instance will be destroyed either upon the next
+        // update or when the GrpcLb instance is destroyed.
+        grpclb_policy->serverlist_ = serverlist;
+        grpclb_policy->serverlist_index_ = 0;
+        grpclb_policy->CreateOrUpdateRoundRobinPolicyLocked();
+      }
+    } else {
+      if (grpc_lb_glb_trace.enabled()) {
+        gpr_log(GPR_INFO, "[grpclb %p] Received empty server list, ignoring.",
+                grpclb_policy);
+      }
+      grpc_grpclb_destroy_serverlist(serverlist);
+    }
+  } else {
+    // No valid initial response or serverlist found.
+    gpr_log(GPR_ERROR,
+            "[grpclb %p] Invalid LB response received: '%s'. Ignoring.",
+            grpclb_policy,
+            grpc_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX));
+  }
+  grpc_slice_unref_internal(response_slice);
+  if (!grpclb_policy->shutting_down_) {
+    // Keep listening for serverlist updates.
+    grpc_op op;
+    memset(&op, 0, sizeof(op));
+    op.op = GRPC_OP_RECV_MESSAGE;
+    op.data.recv_message.recv_message = &lb_calld->recv_message_payload_;
+    op.flags = 0;
+    op.reserved = nullptr;
+    // Reuse the "OnBalancerMessageReceivedLocked" ref taken in StartQuery().
+    const grpc_call_error call_error = grpc_call_start_batch_and_execute(
+        lb_calld->lb_call_, &op, 1,
+        &lb_calld->lb_on_balancer_message_received_);
+    GPR_ASSERT(GRPC_CALL_OK == call_error);
+  } else {
+    lb_calld->Unref(DEBUG_LOCATION, "on_message_received+grpclb_shutdown");
+  }
+}
+
+void GrpcLb::BalancerCallState::OnBalancerStatusReceivedLocked(
+    void* arg, grpc_error* error) {
+  BalancerCallState* lb_calld = static_cast<BalancerCallState*>(arg);
+  GrpcLb* grpclb_policy = lb_calld->grpclb_policy();
+  GPR_ASSERT(lb_calld->lb_call_ != nullptr);
+  if (grpc_lb_glb_trace.enabled()) {
+    char* status_details =
+        grpc_slice_to_c_string(lb_calld->lb_call_status_details_);
+    gpr_log(GPR_INFO,
+            "[grpclb %p] Status from LB server received. Status = %d, details "
+            "= '%s', (lb_calld: %p, lb_call: %p), error '%s'",
+            grpclb_policy, lb_calld->lb_call_status_, status_details, lb_calld,
+            lb_calld->lb_call_, grpc_error_string(error));
+    gpr_free(status_details);
+  }
+  grpclb_policy->TryReresolutionLocked(&grpc_lb_glb_trace, GRPC_ERROR_NONE);
+  // If this lb_calld is still in use, this call ended because of a failure so
+  // we want to retry connecting. Otherwise, we have deliberately ended this
+  // call and no further action is required.
+  if (lb_calld == grpclb_policy->lb_calld_.get()) {
+    grpclb_policy->lb_calld_.reset();
+    GPR_ASSERT(!grpclb_policy->shutting_down_);
+    if (lb_calld->seen_initial_response_) {
+      // If we lose connection to the LB server, reset the backoff and restart
+      // the LB call immediately.
+      grpclb_policy->lb_call_backoff_.Reset();
+      grpclb_policy->StartBalancerCallLocked();
+    } else {
+      // If this LB call fails establishing any connection to the LB server,
+      // retry later.
+      grpclb_policy->StartBalancerCallRetryTimerLocked();
+    }
+  }
+  lb_calld->Unref(DEBUG_LOCATION, "lb_call_ended");
+}
+
+//
+// helper code for creating balancer channel
+//
+
+grpc_lb_addresses* ExtractBalancerAddresses(
+    const grpc_lb_addresses* addresses) {
+  size_t num_grpclb_addrs = 0;
+  for (size_t i = 0; i < addresses->num_addresses; ++i) {
+    if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs;
+  }
+  // There must be at least one balancer address, or else the
+  // client_channel would not have chosen this LB policy.
+  GPR_ASSERT(num_grpclb_addrs > 0);
+  grpc_lb_addresses* lb_addresses =
+      grpc_lb_addresses_create(num_grpclb_addrs, nullptr);
+  size_t lb_addresses_idx = 0;
+  for (size_t i = 0; i < addresses->num_addresses; ++i) {
+    if (!addresses->addresses[i].is_balancer) continue;
+    if (addresses->addresses[i].user_data != nullptr) {
+      gpr_log(GPR_ERROR,
+              "This LB policy doesn't support user data. It will be ignored");
+    }
+    grpc_lb_addresses_set_address(
+        lb_addresses, lb_addresses_idx++, addresses->addresses[i].address.addr,
+        addresses->addresses[i].address.len, false /* is balancer */,
+        addresses->addresses[i].balancer_name, nullptr /* user data */);
+  }
+  GPR_ASSERT(num_grpclb_addrs == lb_addresses_idx);
+  return lb_addresses;
+}
+
+/* Returns the channel args for the LB channel, used to create a bidirectional
+ * stream for the reception of load balancing updates.
+ *
+ * Inputs:
+ *   - \a addresses: corresponding to the balancers.
+ *   - \a response_generator: in order to propagate updates from the resolver
+ *   above the grpclb policy.
+ *   - \a args: other args inherited from the grpclb policy. */
+grpc_channel_args* BuildBalancerChannelArgs(
+    const grpc_lb_addresses* addresses,
+    FakeResolverResponseGenerator* response_generator,
+    const grpc_channel_args* args) {
+  grpc_lb_addresses* lb_addresses = ExtractBalancerAddresses(addresses);
+  // Channel args to remove.
+  static const char* args_to_remove[] = {
+      // LB policy name, since we want to use the default (pick_first) in
+      // the LB channel.
+      GRPC_ARG_LB_POLICY_NAME,
+      // The channel arg for the server URI, since that will be different for
+      // the LB channel than for the parent channel.  The client channel
+      // factory will re-add this arg with the right value.
+      GRPC_ARG_SERVER_URI,
+      // The resolved addresses, which will be generated by the name resolver
+      // used in the LB channel.  Note that the LB channel will use the fake
+      // resolver, so this won't actually generate a query to DNS (or some
+      // other name service).  However, the addresses returned by the fake
+      // resolver will have is_balancer=false, whereas our own addresses have
+      // is_balancer=true.  We need the LB channel to return addresses with
+      // is_balancer=false so that it does not wind up recursively using the
+      // grpclb LB policy, as per the special case logic in client_channel.c.
+      GRPC_ARG_LB_ADDRESSES,
+      // The fake resolver response generator, because we are replacing it
+      // with the one from the grpclb policy, used to propagate updates to
+      // the LB channel.
+      GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR,
+  };
+  // Channel args to add.
+  const grpc_arg args_to_add[] = {
+      // New LB addresses.
+      // Note that we pass these in both when creating the LB channel
+      // and via the fake resolver.  The latter is what actually gets used.
+      grpc_lb_addresses_create_channel_arg(lb_addresses),
+      // The fake resolver response generator, which we use to inject
+      // address updates into the LB channel.
+      grpc_core::FakeResolverResponseGenerator::MakeChannelArg(
+          response_generator),
+  };
+  // Construct channel args.
+  grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove(
+      args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add,
+      GPR_ARRAY_SIZE(args_to_add));
+  // Make any necessary modifications for security.
+  new_args = grpc_lb_policy_grpclb_modify_lb_channel_args(new_args);
+  // Clean up.
+  grpc_lb_addresses_destroy(lb_addresses);
+  return new_args;
+}
+
+//
+// ctor and dtor
+//
+
+GrpcLb::GrpcLb(const grpc_lb_addresses* addresses,
+               const LoadBalancingPolicy::Args& args)
+    : LoadBalancingPolicy(args),
+      response_generator_(MakeRefCounted<FakeResolverResponseGenerator>()),
+      lb_call_backoff_(
+          BackOff::Options()
+              .set_initial_backoff(GRPC_GRPCLB_INITIAL_CONNECT_BACKOFF_SECONDS *
+                                   1000)
+              .set_multiplier(GRPC_GRPCLB_RECONNECT_BACKOFF_MULTIPLIER)
+              .set_jitter(GRPC_GRPCLB_RECONNECT_JITTER)
+              .set_max_backoff(GRPC_GRPCLB_RECONNECT_MAX_BACKOFF_SECONDS *
+                               1000)) {
+  // Initialization.
+  grpc_subchannel_index_ref();
+  GRPC_CLOSURE_INIT(&lb_channel_on_connectivity_changed_,
+                    &GrpcLb::OnBalancerChannelConnectivityChangedLocked, this,
+                    grpc_combiner_scheduler(args.combiner));
+  GRPC_CLOSURE_INIT(&on_rr_connectivity_changed_,
+                    &GrpcLb::OnRoundRobinConnectivityChangedLocked, this,
+                    grpc_combiner_scheduler(args.combiner));
+  GRPC_CLOSURE_INIT(&on_rr_request_reresolution_,
+                    &GrpcLb::OnRoundRobinRequestReresolutionLocked, this,
+                    grpc_combiner_scheduler(args.combiner));
+  grpc_connectivity_state_init(&state_tracker_, GRPC_CHANNEL_IDLE, "grpclb");
+  // Record server name.
+  const grpc_arg* arg = grpc_channel_args_find(args.args, GRPC_ARG_SERVER_URI);
+  const char* server_uri = grpc_channel_arg_get_string(arg);
+  GPR_ASSERT(server_uri != nullptr);
+  grpc_uri* uri = grpc_uri_parse(server_uri, true);
+  GPR_ASSERT(uri->path[0] != '\0');
+  server_name_ = gpr_strdup(uri->path[0] == '/' ? uri->path + 1 : uri->path);
+  if (grpc_lb_glb_trace.enabled()) {
+    gpr_log(GPR_INFO,
+            "[grpclb %p] Will use '%s' as the server name for LB request.",
+            this, server_name_);
+  }
+  grpc_uri_destroy(uri);
+  // Record LB call timeout.
+  arg = grpc_channel_args_find(args.args, GRPC_ARG_GRPCLB_CALL_TIMEOUT_MS);
+  lb_call_timeout_ms_ = grpc_channel_arg_get_integer(arg, {0, 0, INT_MAX});
+  // Record fallback timeout.
+  arg = grpc_channel_args_find(args.args, GRPC_ARG_GRPCLB_FALLBACK_TIMEOUT_MS);
+  lb_fallback_timeout_ms_ = grpc_channel_arg_get_integer(
+      arg, {GRPC_GRPCLB_DEFAULT_FALLBACK_TIMEOUT_MS, 0, INT_MAX});
+  // Process channel args.
+  ProcessChannelArgsLocked(*args.args);
+}
+
+GrpcLb::~GrpcLb() {
+  GPR_ASSERT(pending_picks_ == nullptr);
+  GPR_ASSERT(pending_pings_ == nullptr);
+  gpr_free((void*)server_name_);
+  grpc_channel_args_destroy(args_);
+  grpc_connectivity_state_destroy(&state_tracker_);
+  if (serverlist_ != nullptr) {
+    grpc_grpclb_destroy_serverlist(serverlist_);
+  }
+  if (fallback_backend_addresses_ != nullptr) {
+    grpc_lb_addresses_destroy(fallback_backend_addresses_);
+  }
+  grpc_subchannel_index_unref();
+}
+
+void GrpcLb::ShutdownLocked() {
+  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel shutdown");
+  shutting_down_ = true;
+  lb_calld_.reset();
+  if (retry_timer_callback_pending_) {
+    grpc_timer_cancel(&lb_call_retry_timer_);
+  }
+  if (fallback_timer_callback_pending_) {
+    grpc_timer_cancel(&lb_fallback_timer_);
+  }
+  rr_policy_.reset();
+  TryReresolutionLocked(&grpc_lb_glb_trace, GRPC_ERROR_CANCELLED);
+  // We destroy the LB channel here instead of in our destructor because
+  // destroying the channel triggers a last callback to
+  // OnBalancerChannelConnectivityChangedLocked(), and we need to be
+  // alive when that callback is invoked.
+  if (lb_channel_ != nullptr) {
+    grpc_channel_destroy(lb_channel_);
+    lb_channel_ = nullptr;
+  }
+  grpc_connectivity_state_set(&state_tracker_, GRPC_CHANNEL_SHUTDOWN,
+                              GRPC_ERROR_REF(error), "grpclb_shutdown");
+  // Clear pending picks.
+  PendingPick* pp;
+  while ((pp = pending_picks_) != nullptr) {
+    pending_picks_ = pp->next;
+    pp->pick->connected_subchannel.reset();
+    // Note: pp is deleted in this callback.
+    GRPC_CLOSURE_SCHED(&pp->on_complete, GRPC_ERROR_REF(error));
+  }
+  // Clear pending pings.
+  PendingPing* pping;
+  while ((pping = pending_pings_) != nullptr) {
+    pending_pings_ = pping->next;
+    GRPC_CLOSURE_SCHED(pping->on_initiate, GRPC_ERROR_REF(error));
+    GRPC_CLOSURE_SCHED(pping->on_ack, GRPC_ERROR_REF(error));
+    Delete(pping);
+  }
+  GRPC_ERROR_UNREF(error);
+}
+
+//
+// public methods
+//
+
+void GrpcLb::HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) {
+  PendingPick* pp;
+  while ((pp = pending_picks_) != nullptr) {
+    pending_picks_ = pp->next;
+    pp->pick->on_complete = pp->original_on_complete;
+    pp->pick->user_data = nullptr;
+    if (new_policy->PickLocked(pp->pick)) {
+      // Synchronous return; schedule closure.
+      GRPC_CLOSURE_SCHED(pp->pick->on_complete, GRPC_ERROR_NONE);
+    }
+    Delete(pp);
+  }
+}
+
+// Cancel a specific pending pick.
+//
+// A grpclb pick progresses as follows:
+// - If there's a Round Robin policy (rr_policy_) available, it'll be
+//   handed over to the RR policy (in CreateRoundRobinPolicyLocked()). From
+//   that point onwards, it'll be RR's responsibility. For cancellations, that
+//   implies the pick needs also be cancelled by the RR instance.
+// - Otherwise, without an RR instance, picks stay pending at this policy's
+//   level (grpclb), inside the pending_picks_ list. To cancel these,
+//   we invoke the completion closure and set the pick's connected
+//   subchannel to nullptr right here.
+void GrpcLb::CancelPickLocked(PickState* pick, grpc_error* error) {
+  PendingPick* pp = pending_picks_;
+  pending_picks_ = nullptr;
+  while (pp != nullptr) {
+    PendingPick* next = pp->next;
+    if (pp->pick == pick) {
+      pick->connected_subchannel.reset();
+      // Note: pp is deleted in this callback.
+      GRPC_CLOSURE_SCHED(&pp->on_complete,
+                         GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+                             "Pick Cancelled", &error, 1));
+    } else {
+      pp->next = pending_picks_;
+      pending_picks_ = pp;
+    }
+    pp = next;
+  }
+  if (rr_policy_ != nullptr) {
+    rr_policy_->CancelPickLocked(pick, GRPC_ERROR_REF(error));
+  }
+  GRPC_ERROR_UNREF(error);
+}
+
+// Cancel all pending picks.
+//
+// A grpclb pick progresses as follows:
+// - If there's a Round Robin policy (rr_policy_) available, it'll be
+//   handed over to the RR policy (in CreateRoundRobinPolicyLocked()). From
+//   that point onwards, it'll be RR's responsibility. For cancellations, that
+//   implies the pick needs also be cancelled by the RR instance.
+// - Otherwise, without an RR instance, picks stay pending at this policy's
+//   level (grpclb), inside the pending_picks_ list. To cancel these,
+//   we invoke the completion closure and set the pick's connected
+//   subchannel to nullptr right here.
+void GrpcLb::CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask,
+                                       uint32_t initial_metadata_flags_eq,
+                                       grpc_error* error) {
+  PendingPick* pp = pending_picks_;
+  pending_picks_ = nullptr;
+  while (pp != nullptr) {
+    PendingPick* next = pp->next;
+    if ((pp->pick->initial_metadata_flags & initial_metadata_flags_mask) ==
+        initial_metadata_flags_eq) {
+      // Note: pp is deleted in this callback.
+      GRPC_CLOSURE_SCHED(&pp->on_complete,
+                         GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+                             "Pick Cancelled", &error, 1));
+    } else {
+      pp->next = pending_picks_;
+      pending_picks_ = pp;
+    }
+    pp = next;
+  }
+  if (rr_policy_ != nullptr) {
+    rr_policy_->CancelMatchingPicksLocked(initial_metadata_flags_mask,
+                                          initial_metadata_flags_eq,
+                                          GRPC_ERROR_REF(error));
+  }
+  GRPC_ERROR_UNREF(error);
+}
+
+void GrpcLb::ExitIdleLocked() {
+  if (!started_picking_) {
+    StartPickingLocked();
+  }
+}
+
+bool GrpcLb::PickLocked(PickState* pick) {
+  PendingPick* pp = PendingPickCreate(pick);
+  bool pick_done = false;
+  if (rr_policy_ != nullptr) {
+    const grpc_connectivity_state rr_connectivity_state =
+        rr_policy_->CheckConnectivityLocked(nullptr);
+    // The RR policy may have transitioned to SHUTDOWN but the callback
+    // registered to capture this event (on_rr_connectivity_changed_) may not
+    // have been invoked yet. We need to make sure we aren't trying to pick
+    // from an RR policy instance that's in shutdown.
+    if (rr_connectivity_state == GRPC_CHANNEL_SHUTDOWN) {
+      if (grpc_lb_glb_trace.enabled()) {
+        gpr_log(GPR_INFO,
+                "[grpclb %p] NOT picking from from RR %p: RR conn state=%s",
+                this, rr_policy_.get(),
+                grpc_connectivity_state_name(rr_connectivity_state));
+      }
+      AddPendingPick(pp);
+      pick_done = false;
+    } else {  // RR not in shutdown
+      if (grpc_lb_glb_trace.enabled()) {
+        gpr_log(GPR_INFO, "[grpclb %p] about to PICK from RR %p", this,
+                rr_policy_.get());
+      }
+      pick_done = PickFromRoundRobinPolicyLocked(false /* force_async */, pp);
+    }
+  } else {  // rr_policy_ == NULL
+    if (grpc_lb_glb_trace.enabled()) {
+      gpr_log(GPR_DEBUG,
+              "[grpclb %p] No RR policy. Adding to grpclb's pending picks",
+              this);
+    }
+    AddPendingPick(pp);
+    if (!started_picking_) {
+      StartPickingLocked();
+    }
+    pick_done = false;
+  }
+  return pick_done;
+}
+
+void GrpcLb::PingOneLocked(grpc_closure* on_initiate, grpc_closure* on_ack) {
+  if (rr_policy_ != nullptr) {
+    rr_policy_->PingOneLocked(on_initiate, on_ack);
+  } else {
+    AddPendingPing(on_initiate, on_ack);
+    if (!started_picking_) {
+      StartPickingLocked();
+    }
+  }
+}
+
+grpc_connectivity_state GrpcLb::CheckConnectivityLocked(
+    grpc_error** connectivity_error) {
+  return grpc_connectivity_state_get(&state_tracker_, connectivity_error);
+}
+
+void GrpcLb::NotifyOnStateChangeLocked(grpc_connectivity_state* current,
+                                       grpc_closure* notify) {
+  grpc_connectivity_state_notify_on_state_change(&state_tracker_, current,
+                                                 notify);
+}
+
+void GrpcLb::ProcessChannelArgsLocked(const grpc_channel_args& args) {
+  const grpc_arg* arg = grpc_channel_args_find(&args, GRPC_ARG_LB_ADDRESSES);
+  if (arg == nullptr || arg->type != GRPC_ARG_POINTER) {
+    // Ignore this update.
+    gpr_log(
+        GPR_ERROR,
+        "[grpclb %p] No valid LB addresses channel arg in update, ignoring.",
+        this);
+    return;
+  }
+  const grpc_lb_addresses* addresses =
+      static_cast<const grpc_lb_addresses*>(arg->value.pointer.p);
+  // Update fallback address list.
+  if (fallback_backend_addresses_ != nullptr) {
+    grpc_lb_addresses_destroy(fallback_backend_addresses_);
+  }
+  fallback_backend_addresses_ = ExtractBackendAddresses(addresses);
+  // Make sure that GRPC_ARG_LB_POLICY_NAME is set in channel args,
+  // since we use this to trigger the client_load_reporting filter.
+  static const char* args_to_remove[] = {GRPC_ARG_LB_POLICY_NAME};
+  grpc_arg new_arg = grpc_channel_arg_string_create(
+      (char*)GRPC_ARG_LB_POLICY_NAME, (char*)"grpclb");
+  grpc_channel_args_destroy(args_);
+  args_ = grpc_channel_args_copy_and_add_and_remove(
+      &args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), &new_arg, 1);
+  // Construct args for balancer channel.
+  grpc_channel_args* lb_channel_args =
+      BuildBalancerChannelArgs(addresses, response_generator_.get(), &args);
+  // Create balancer channel if needed.
+  if (lb_channel_ == nullptr) {
+    char* uri_str;
+    gpr_asprintf(&uri_str, "fake:///%s", server_name_);
+    lb_channel_ = grpc_client_channel_factory_create_channel(
+        client_channel_factory(), uri_str,
+        GRPC_CLIENT_CHANNEL_TYPE_LOAD_BALANCING, lb_channel_args);
+    GPR_ASSERT(lb_channel_ != nullptr);
+    gpr_free(uri_str);
+  }
+  // Propagate updates to the LB channel (pick_first) through the fake
+  // resolver.
+  response_generator_->SetResponse(lb_channel_args);
+  grpc_channel_args_destroy(lb_channel_args);
+}
+
+void GrpcLb::UpdateLocked(const grpc_channel_args& args) {
+  ProcessChannelArgsLocked(args);
+  // If fallback is configured and the RR policy already exists, update
+  // it with the new fallback addresses.
+  if (lb_fallback_timeout_ms_ > 0 && rr_policy_ != nullptr) {
+    CreateOrUpdateRoundRobinPolicyLocked();
+  }
+  // Start watching the LB channel connectivity for connection, if not
+  // already doing so.
+  if (!watching_lb_channel_) {
+    lb_channel_connectivity_ = grpc_channel_check_connectivity_state(
+        lb_channel_, true /* try to connect */);
+    grpc_channel_element* client_channel_elem = grpc_channel_stack_last_element(
+        grpc_channel_get_channel_stack(lb_channel_));
+    GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter);
+    watching_lb_channel_ = true;
+    // TODO(roth): We currently track this ref manually.  Once the
+    // ClosureRef API is ready, we should pass the RefCountedPtr<> along
+    // with the callback.
+    auto self = Ref(DEBUG_LOCATION, "watch_lb_channel_connectivity");
+    self.release();
+    grpc_client_channel_watch_connectivity_state(
+        client_channel_elem,
+        grpc_polling_entity_create_from_pollset_set(interested_parties()),
+        &lb_channel_connectivity_, &lb_channel_on_connectivity_changed_,
+        nullptr);
+  }
+}
+
+//
+// code for balancer channel and call
+//
+
+void GrpcLb::StartPickingLocked() {
+  // Start a timer to fall back.
+  if (lb_fallback_timeout_ms_ > 0 && serverlist_ == nullptr &&
+      !fallback_timer_callback_pending_) {
+    grpc_millis deadline = ExecCtx::Get()->Now() + lb_fallback_timeout_ms_;
+    // TODO(roth): We currently track this ref manually.  Once the
+    // ClosureRef API is ready, we should pass the RefCountedPtr<> along
+    // with the callback.
+    auto self = Ref(DEBUG_LOCATION, "on_fallback_timer");
+    self.release();
+    GRPC_CLOSURE_INIT(&lb_on_fallback_, &GrpcLb::OnFallbackTimerLocked, this,
+                      grpc_combiner_scheduler(combiner()));
+    fallback_timer_callback_pending_ = true;
+    grpc_timer_init(&lb_fallback_timer_, deadline, &lb_on_fallback_);
+  }
+  started_picking_ = true;
+  StartBalancerCallLocked();
+}
+
+void GrpcLb::StartBalancerCallLocked() {
+  GPR_ASSERT(lb_channel_ != nullptr);
+  if (shutting_down_) return;
+  // Init the LB call data.
+  GPR_ASSERT(lb_calld_ == nullptr);
+  lb_calld_ = MakeOrphanable<BalancerCallState>(Ref());
+  if (grpc_lb_glb_trace.enabled()) {
+    gpr_log(GPR_INFO,
+            "[grpclb %p] Query for backends (lb_channel: %p, lb_calld: %p)",
+            this, lb_channel_, lb_calld_.get());
+  }
+  lb_calld_->StartQuery();
+}
+
+void GrpcLb::OnFallbackTimerLocked(void* arg, grpc_error* error) {
+  GrpcLb* grpclb_policy = static_cast<GrpcLb*>(arg);
+  grpclb_policy->fallback_timer_callback_pending_ = false;
+  // If we receive a serverlist after the timer fires but before this callback
+  // actually runs, don't fall back.
+  if (grpclb_policy->serverlist_ == nullptr && !grpclb_policy->shutting_down_ &&
+      error == GRPC_ERROR_NONE) {
+    if (grpc_lb_glb_trace.enabled()) {
+      gpr_log(GPR_INFO,
+              "[grpclb %p] Falling back to use backends from resolver",
+              grpclb_policy);
+    }
+    GPR_ASSERT(grpclb_policy->fallback_backend_addresses_ != nullptr);
+    grpclb_policy->CreateOrUpdateRoundRobinPolicyLocked();
+  }
+  grpclb_policy->Unref(DEBUG_LOCATION, "on_fallback_timer");
+}
+
+void GrpcLb::StartBalancerCallRetryTimerLocked() {
+  grpc_millis next_try = lb_call_backoff_.NextAttemptTime();
+  if (grpc_lb_glb_trace.enabled()) {
+    gpr_log(GPR_DEBUG, "[grpclb %p] Connection to LB server lost...", this);
+    grpc_millis timeout = next_try - ExecCtx::Get()->Now();
+    if (timeout > 0) {
+      gpr_log(GPR_DEBUG,
+              "[grpclb %p] ... retry_timer_active in %" PRIuPTR "ms.", this,
+              timeout);
+    } else {
+      gpr_log(GPR_DEBUG, "[grpclb %p] ... retry_timer_active immediately.",
+              this);
+    }
+  }
+  // TODO(roth): We currently track this ref manually.  Once the
+  // ClosureRef API is ready, we should pass the RefCountedPtr<> along
+  // with the callback.
+  auto self = Ref(DEBUG_LOCATION, "on_balancer_call_retry_timer");
+  self.release();
+  GRPC_CLOSURE_INIT(&lb_on_call_retry_, &GrpcLb::OnBalancerCallRetryTimerLocked,
+                    this, grpc_combiner_scheduler(combiner()));
+  retry_timer_callback_pending_ = true;
+  grpc_timer_init(&lb_call_retry_timer_, next_try, &lb_on_call_retry_);
+}
+
+void GrpcLb::OnBalancerCallRetryTimerLocked(void* arg, grpc_error* error) {
+  GrpcLb* grpclb_policy = static_cast<GrpcLb*>(arg);
+  grpclb_policy->retry_timer_callback_pending_ = false;
+  if (!grpclb_policy->shutting_down_ && error == GRPC_ERROR_NONE &&
+      grpclb_policy->lb_calld_ == nullptr) {
+    if (grpc_lb_glb_trace.enabled()) {
+      gpr_log(GPR_INFO, "[grpclb %p] Restarting call to LB server",
+              grpclb_policy);
+    }
+    grpclb_policy->StartBalancerCallLocked();
+  }
+  grpclb_policy->Unref(DEBUG_LOCATION, "on_balancer_call_retry_timer");
+}
+
+// Invoked as part of the update process. It continues watching the LB channel
+// until it shuts down or becomes READY. It's invoked even if the LB channel
+// stayed READY throughout the update (for example if the update is identical).
+void GrpcLb::OnBalancerChannelConnectivityChangedLocked(void* arg,
+                                                        grpc_error* error) {
+  GrpcLb* grpclb_policy = static_cast<GrpcLb*>(arg);
+  if (grpclb_policy->shutting_down_) goto done;
+  // Re-initialize the lb_call. This should also take care of updating the
+  // embedded RR policy. Note that the current RR policy, if any, will stay in
+  // effect until an update from the new lb_call is received.
+  switch (grpclb_policy->lb_channel_connectivity_) {
+    case GRPC_CHANNEL_CONNECTING:
+    case GRPC_CHANNEL_TRANSIENT_FAILURE: {
+      // Keep watching the LB channel.
+      grpc_channel_element* client_channel_elem =
+          grpc_channel_stack_last_element(
+              grpc_channel_get_channel_stack(grpclb_policy->lb_channel_));
+      GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter);
+      grpc_client_channel_watch_connectivity_state(
+          client_channel_elem,
+          grpc_polling_entity_create_from_pollset_set(
+              grpclb_policy->interested_parties()),
+          &grpclb_policy->lb_channel_connectivity_,
+          &grpclb_policy->lb_channel_on_connectivity_changed_, nullptr);
+      break;
+    }
+      // The LB channel may be IDLE because it's shut down before the update.
+      // Restart the LB call to kick the LB channel into gear.
+    case GRPC_CHANNEL_IDLE:
+    case GRPC_CHANNEL_READY:
+      grpclb_policy->lb_calld_.reset();
+      if (grpclb_policy->started_picking_) {
+        if (grpclb_policy->retry_timer_callback_pending_) {
+          grpc_timer_cancel(&grpclb_policy->lb_call_retry_timer_);
+        }
+        grpclb_policy->lb_call_backoff_.Reset();
+        grpclb_policy->StartBalancerCallLocked();
+      }
+      // Fall through.
+    case GRPC_CHANNEL_SHUTDOWN:
+    done:
+      grpclb_policy->watching_lb_channel_ = false;
+      grpclb_policy->Unref(DEBUG_LOCATION,
+                           "watch_lb_channel_connectivity_cb_shutdown");
+  }
+}
+
+//
+// PendingPick
+//
+
+// Adds lb_token of selected subchannel (address) to the call's initial
+// metadata.
+grpc_error* AddLbTokenToInitialMetadata(
+    grpc_mdelem lb_token, grpc_linked_mdelem* lb_token_mdelem_storage,
+    grpc_metadata_batch* initial_metadata) {
+  GPR_ASSERT(lb_token_mdelem_storage != nullptr);
+  GPR_ASSERT(!GRPC_MDISNULL(lb_token));
+  return grpc_metadata_batch_add_tail(initial_metadata, lb_token_mdelem_storage,
+                                      lb_token);
+}
+
+// Destroy function used when embedding client stats in call context.
+void DestroyClientStats(void* arg) {
+  grpc_grpclb_client_stats_unref(static_cast<grpc_grpclb_client_stats*>(arg));
+}
+
+void GrpcLb::PendingPickSetMetadataAndContext(PendingPick* pp) {
+  /* if connected_subchannel is nullptr, no pick has been made by the RR
+   * policy (e.g., all addresses failed to connect). There won't be any
+   * user_data/token available */
+  if (pp->pick->connected_subchannel != nullptr) {
+    if (!GRPC_MDISNULL(pp->lb_token)) {
+      AddLbTokenToInitialMetadata(GRPC_MDELEM_REF(pp->lb_token),
+                                  &pp->pick->lb_token_mdelem_storage,
+                                  pp->pick->initial_metadata);
+    } else {
+      gpr_log(GPR_ERROR,
+              "[grpclb %p] No LB token for connected subchannel pick %p",
+              pp->grpclb_policy, pp->pick);
+      abort();
+    }
+    // Pass on client stats via context. Passes ownership of the reference.
+    if (pp->client_stats != nullptr) {
+      pp->pick->subchannel_call_context[GRPC_GRPCLB_CLIENT_STATS].value =
+          pp->client_stats;
+      pp->pick->subchannel_call_context[GRPC_GRPCLB_CLIENT_STATS].destroy =
+          DestroyClientStats;
+    }
+  } else {
+    if (pp->client_stats != nullptr) {
+      grpc_grpclb_client_stats_unref(pp->client_stats);
+    }
+  }
+}
+
+/* The \a on_complete closure passed as part of the pick requires keeping a
+ * reference to its associated round robin instance. We wrap this closure in
+ * order to unref the round robin instance upon its invocation */
+void GrpcLb::OnPendingPickComplete(void* arg, grpc_error* error) {
+  PendingPick* pp = static_cast<PendingPick*>(arg);
+  PendingPickSetMetadataAndContext(pp);
+  GRPC_CLOSURE_SCHED(pp->original_on_complete, GRPC_ERROR_REF(error));
+  Delete(pp);
+}
+
+GrpcLb::PendingPick* GrpcLb::PendingPickCreate(PickState* pick) {
+  PendingPick* pp = New<PendingPick>();
+  pp->grpclb_policy = this;
+  pp->pick = pick;
+  GRPC_CLOSURE_INIT(&pp->on_complete, &GrpcLb::OnPendingPickComplete, pp,
+                    grpc_schedule_on_exec_ctx);
+  pp->original_on_complete = pick->on_complete;
+  pick->on_complete = &pp->on_complete;
+  return pp;
+}
+
+void GrpcLb::AddPendingPick(PendingPick* pp) {
+  pp->next = pending_picks_;
+  pending_picks_ = pp;
+}
+
+//
+// PendingPing
+//
+
+void GrpcLb::AddPendingPing(grpc_closure* on_initiate, grpc_closure* on_ack) {
+  PendingPing* pping = New<PendingPing>();
+  pping->on_initiate = on_initiate;
+  pping->on_ack = on_ack;
+  pping->next = pending_pings_;
+  pending_pings_ = pping;
+}
+
+//
+// code for interacting with the RR policy
+//
+
+// Performs a pick over \a rr_policy_. Given that a pick can return
+// immediately (ignoring its completion callback), we need to perform the
+// cleanups this callback would otherwise be responsible for.
+// If \a force_async is true, then we will manually schedule the
+// completion callback even if the pick is available immediately.
+bool GrpcLb::PickFromRoundRobinPolicyLocked(bool force_async, PendingPick* pp) {
+  // Check for drops if we are not using fallback backend addresses.
+  if (serverlist_ != nullptr) {
+    // Look at the index into the serverlist to see if we should drop this call.
+    grpc_grpclb_server* server = serverlist_->servers[serverlist_index_++];
+    if (serverlist_index_ == serverlist_->num_servers) {
+      serverlist_index_ = 0;  // Wrap-around.
+    }
+    if (server->drop) {
+      // Update client load reporting stats to indicate the number of
+      // dropped calls.  Note that we have to do this here instead of in
+      // the client_load_reporting filter, because we do not create a
+      // subchannel call (and therefore no client_load_reporting filter)
+      // for dropped calls.
+      if (lb_calld_ != nullptr && lb_calld_->client_stats() != nullptr) {
+        grpc_grpclb_client_stats_add_call_dropped_locked(
+            server->load_balance_token, lb_calld_->client_stats());
+      }
+      if (force_async) {
+        GRPC_CLOSURE_SCHED(pp->original_on_complete, GRPC_ERROR_NONE);
+        Delete(pp);
+        return false;
+      }
+      Delete(pp);
+      return true;
+    }
+  }
+  // Set client_stats and user_data.
+  if (lb_calld_ != nullptr && lb_calld_->client_stats() != nullptr) {
+    pp->client_stats = grpc_grpclb_client_stats_ref(lb_calld_->client_stats());
+  }
+  GPR_ASSERT(pp->pick->user_data == nullptr);
+  pp->pick->user_data = (void**)&pp->lb_token;
+  // Pick via the RR policy.
+  bool pick_done = rr_policy_->PickLocked(pp->pick);
+  if (pick_done) {
+    PendingPickSetMetadataAndContext(pp);
+    if (force_async) {
+      GRPC_CLOSURE_SCHED(pp->original_on_complete, GRPC_ERROR_NONE);
+      pick_done = false;
+    }
+    Delete(pp);
+  }
+  // else, the pending pick will be registered and taken care of by the
+  // pending pick list inside the RR policy.  Eventually,
+  // OnPendingPickComplete() will be called, which will (among other
+  // things) add the LB token to the call's initial metadata.
+  return pick_done;
+}
+
+void GrpcLb::CreateRoundRobinPolicyLocked(const Args& args) {
+  GPR_ASSERT(rr_policy_ == nullptr);
+  rr_policy_ = LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy(
+      "round_robin", args);
+  if (rr_policy_ == nullptr) {
+    gpr_log(GPR_ERROR, "[grpclb %p] Failure creating a RoundRobin policy",
+            this);
+    return;
+  }
+  // TODO(roth): We currently track this ref manually.  Once the new
+  // ClosureRef API is done, pass the RefCountedPtr<> along with the closure.
+  auto self = Ref(DEBUG_LOCATION, "on_rr_reresolution_requested");
+  self.release();
+  rr_policy_->SetReresolutionClosureLocked(&on_rr_request_reresolution_);
+  grpc_error* rr_state_error = nullptr;
+  rr_connectivity_state_ = rr_policy_->CheckConnectivityLocked(&rr_state_error);
+  // Connectivity state is a function of the RR policy updated/created.
+  UpdateConnectivityStateFromRoundRobinPolicyLocked(rr_state_error);
+  // Add the gRPC LB's interested_parties pollset_set to that of the newly
+  // created RR policy. This will make the RR policy progress upon activity on
+  // gRPC LB, which in turn is tied to the application's call.
+  grpc_pollset_set_add_pollset_set(rr_policy_->interested_parties(),
+                                   interested_parties());
+  // Subscribe to changes to the connectivity of the new RR.
+  // TODO(roth): We currently track this ref manually.  Once the new
+  // ClosureRef API is done, pass the RefCountedPtr<> along with the closure.
+  self = Ref(DEBUG_LOCATION, "on_rr_connectivity_changed");
+  self.release();
+  rr_policy_->NotifyOnStateChangeLocked(&rr_connectivity_state_,
+                                        &on_rr_connectivity_changed_);
+  rr_policy_->ExitIdleLocked();
+  // Send pending picks to RR policy.
+  PendingPick* pp;
+  while ((pp = pending_picks_)) {
+    pending_picks_ = pp->next;
+    if (grpc_lb_glb_trace.enabled()) {
+      gpr_log(GPR_INFO,
+              "[grpclb %p] Pending pick about to (async) PICK from RR %p", this,
+              rr_policy_.get());
+    }
+    PickFromRoundRobinPolicyLocked(true /* force_async */, pp);
+  }
+  // Send pending pings to RR policy.
+  PendingPing* pping;
+  while ((pping = pending_pings_)) {
+    pending_pings_ = pping->next;
+    if (grpc_lb_glb_trace.enabled()) {
+      gpr_log(GPR_INFO, "[grpclb %p] Pending ping about to PING from RR %p",
+              this, rr_policy_.get());
+    }
+    rr_policy_->PingOneLocked(pping->on_initiate, pping->on_ack);
+    Delete(pping);
+  }
+}
+
+grpc_channel_args* GrpcLb::CreateRoundRobinPolicyArgsLocked() {
+  grpc_lb_addresses* addresses;
+  if (serverlist_ != nullptr) {
+    GPR_ASSERT(serverlist_->num_servers > 0);
+    addresses = ProcessServerlist(serverlist_);
+  } else {
+    // If CreateOrUpdateRoundRobinPolicyLocked() is invoked when we haven't
+    // received any serverlist from the balancer, we use the fallback backends
+    // returned by the resolver. Note that the fallback backend list may be
+    // empty, in which case the new round_robin policy will keep the requested
+    // picks pending.
+    GPR_ASSERT(fallback_backend_addresses_ != nullptr);
+    addresses = grpc_lb_addresses_copy(fallback_backend_addresses_);
+  }
+  GPR_ASSERT(addresses != nullptr);
+  // Replace the LB addresses in the channel args that we pass down to
+  // the subchannel.
+  static const char* keys_to_remove[] = {GRPC_ARG_LB_ADDRESSES};
+  const grpc_arg arg = grpc_lb_addresses_create_channel_arg(addresses);
+  grpc_channel_args* args = grpc_channel_args_copy_and_add_and_remove(
+      args_, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &arg, 1);
+  grpc_lb_addresses_destroy(addresses);
+  return args;
+}
+
+void GrpcLb::CreateOrUpdateRoundRobinPolicyLocked() {
+  if (shutting_down_) return;
+  grpc_channel_args* args = CreateRoundRobinPolicyArgsLocked();
+  GPR_ASSERT(args != nullptr);
+  if (rr_policy_ != nullptr) {
+    if (grpc_lb_glb_trace.enabled()) {
+      gpr_log(GPR_DEBUG, "[grpclb %p] Updating RR policy %p", this,
+              rr_policy_.get());
+    }
+    rr_policy_->UpdateLocked(*args);
+  } else {
+    LoadBalancingPolicy::Args lb_policy_args;
+    lb_policy_args.combiner = combiner();
+    lb_policy_args.client_channel_factory = client_channel_factory();
+    lb_policy_args.args = args;
+    CreateRoundRobinPolicyLocked(lb_policy_args);
+    if (grpc_lb_glb_trace.enabled()) {
+      gpr_log(GPR_DEBUG, "[grpclb %p] Created new RR policy %p", this,
+              rr_policy_.get());
+    }
+  }
+  grpc_channel_args_destroy(args);
+}
+
+void GrpcLb::OnRoundRobinRequestReresolutionLocked(void* arg,
+                                                   grpc_error* error) {
+  GrpcLb* grpclb_policy = static_cast<GrpcLb*>(arg);
+  if (grpclb_policy->shutting_down_ || error != GRPC_ERROR_NONE) {
+    grpclb_policy->Unref(DEBUG_LOCATION, "on_rr_reresolution_requested");
+    return;
+  }
+  if (grpc_lb_glb_trace.enabled()) {
+    gpr_log(
+        GPR_DEBUG,
+        "[grpclb %p] Re-resolution requested from the internal RR policy (%p).",
+        grpclb_policy, grpclb_policy->rr_policy_.get());
+  }
+  // If we are talking to a balancer, we expect to get updated addresses form
+  // the balancer, so we can ignore the re-resolution request from the RR
+  // policy. Otherwise, handle the re-resolution request using the
+  // grpclb policy's original re-resolution closure.
+  if (grpclb_policy->lb_calld_ == nullptr ||
+      !grpclb_policy->lb_calld_->seen_initial_response()) {
+    grpclb_policy->TryReresolutionLocked(&grpc_lb_glb_trace, GRPC_ERROR_NONE);
+  }
+  // Give back the wrapper closure to the RR policy.
+  grpclb_policy->rr_policy_->SetReresolutionClosureLocked(
+      &grpclb_policy->on_rr_request_reresolution_);
+}
+
+void GrpcLb::UpdateConnectivityStateFromRoundRobinPolicyLocked(
     grpc_error* rr_state_error) {
   const grpc_connectivity_state curr_glb_state =
-      grpc_connectivity_state_check(&glb_policy->state_tracker);
+      grpc_connectivity_state_check(&state_tracker_);
   /* The new connectivity status is a function of the previous one and the new
    * input coming from the status of the RR policy.
    *
@@ -618,7 +1796,7 @@
    *
    *  (*) This function mustn't be called during shutting down. */
   GPR_ASSERT(curr_glb_state != GRPC_CHANNEL_SHUTDOWN);
-  switch (rr_state) {
+  switch (rr_connectivity_state_) {
     case GRPC_CHANNEL_TRANSIENT_FAILURE:
     case GRPC_CHANNEL_SHUTDOWN:
       GPR_ASSERT(rr_state_error != GRPC_ERROR_NONE);
@@ -632,1287 +1810,69 @@
     gpr_log(
         GPR_INFO,
         "[grpclb %p] Setting grpclb's state to %s from new RR policy %p state.",
-        glb_policy, grpc_connectivity_state_name(rr_state),
-        glb_policy->rr_policy);
+        this, grpc_connectivity_state_name(rr_connectivity_state_),
+        rr_policy_.get());
   }
-  grpc_connectivity_state_set(&glb_policy->state_tracker, rr_state,
+  grpc_connectivity_state_set(&state_tracker_, rr_connectivity_state_,
                               rr_state_error,
                               "update_lb_connectivity_status_locked");
 }
 
-/* Perform a pick over \a glb_policy->rr_policy. Given that a pick can return
- * immediately (ignoring its completion callback), we need to perform the
- * cleanups this callback would otherwise be responsible for.
- * If \a force_async is true, then we will manually schedule the
- * completion callback even if the pick is available immediately. */
-static bool pick_from_internal_rr_locked(glb_lb_policy* glb_policy,
-                                         bool force_async, pending_pick* pp) {
-  // Check for drops if we are not using fallback backend addresses.
-  if (glb_policy->serverlist != nullptr) {
-    // Look at the index into the serverlist to see if we should drop this call.
-    grpc_grpclb_server* server =
-        glb_policy->serverlist->servers[glb_policy->serverlist_index++];
-    if (glb_policy->serverlist_index == glb_policy->serverlist->num_servers) {
-      glb_policy->serverlist_index = 0;  // Wrap-around.
-    }
-    if (server->drop) {
-      // Update client load reporting stats to indicate the number of
-      // dropped calls.  Note that we have to do this here instead of in
-      // the client_load_reporting filter, because we do not create a
-      // subchannel call (and therefore no client_load_reporting filter)
-      // for dropped calls.
-      if (glb_policy->lb_calld != nullptr &&
-          glb_policy->lb_calld->client_stats != nullptr) {
-        grpc_grpclb_client_stats_add_call_dropped_locked(
-            server->load_balance_token, glb_policy->lb_calld->client_stats);
-      }
-      if (force_async) {
-        GRPC_CLOSURE_SCHED(pp->original_on_complete, GRPC_ERROR_NONE);
-        gpr_free(pp);
-        return false;
-      }
-      gpr_free(pp);
-      return true;
-    }
-  }
-  // Set client_stats and user_data.
-  if (glb_policy->lb_calld != nullptr &&
-      glb_policy->lb_calld->client_stats != nullptr) {
-    pp->client_stats =
-        grpc_grpclb_client_stats_ref(glb_policy->lb_calld->client_stats);
-  }
-  GPR_ASSERT(pp->pick->user_data == nullptr);
-  pp->pick->user_data = (void**)&pp->lb_token;
-  // Pick via the RR policy.
-  bool pick_done = grpc_lb_policy_pick_locked(glb_policy->rr_policy, pp->pick);
-  if (pick_done) {
-    pending_pick_set_metadata_and_context(pp);
-    if (force_async) {
-      GRPC_CLOSURE_SCHED(pp->original_on_complete, GRPC_ERROR_NONE);
-      pick_done = false;
-    }
-    gpr_free(pp);
-  }
-  /* else, the pending pick will be registered and taken care of by the
-   * pending pick list inside the RR policy (glb_policy->rr_policy).
-   * Eventually, wrapped_on_complete will be called, which will -among other
-   * things- add the LB token to the call's initial metadata */
-  return pick_done;
-}
-
-static grpc_lb_policy_args* lb_policy_args_create(glb_lb_policy* glb_policy) {
-  grpc_lb_addresses* addresses;
-  if (glb_policy->serverlist != nullptr) {
-    GPR_ASSERT(glb_policy->serverlist->num_servers > 0);
-    addresses = process_serverlist_locked(glb_policy->serverlist);
-  } else {
-    // If rr_handover_locked() is invoked when we haven't received any
-    // serverlist from the balancer, we use the fallback backends returned by
-    // the resolver. Note that the fallback backend list may be empty, in which
-    // case the new round_robin policy will keep the requested picks pending.
-    GPR_ASSERT(glb_policy->fallback_backend_addresses != nullptr);
-    addresses = grpc_lb_addresses_copy(glb_policy->fallback_backend_addresses);
-  }
-  GPR_ASSERT(addresses != nullptr);
-  grpc_lb_policy_args* args = (grpc_lb_policy_args*)gpr_zalloc(sizeof(*args));
-  args->client_channel_factory = glb_policy->cc_factory;
-  args->combiner = glb_policy->base.combiner;
-  // Replace the LB addresses in the channel args that we pass down to
-  // the subchannel.
-  static const char* keys_to_remove[] = {GRPC_ARG_LB_ADDRESSES};
-  const grpc_arg arg = grpc_lb_addresses_create_channel_arg(addresses);
-  args->args = grpc_channel_args_copy_and_add_and_remove(
-      glb_policy->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &arg,
-      1);
-  grpc_lb_addresses_destroy(addresses);
-  return args;
-}
-
-static void lb_policy_args_destroy(grpc_lb_policy_args* args) {
-  grpc_channel_args_destroy(args->args);
-  gpr_free(args);
-}
-
-static void on_rr_connectivity_changed_locked(void* arg, grpc_error* error);
-static void create_rr_locked(glb_lb_policy* glb_policy,
-                             grpc_lb_policy_args* args) {
-  GPR_ASSERT(glb_policy->rr_policy == nullptr);
-
-  grpc_lb_policy* new_rr_policy = grpc_lb_policy_create("round_robin", args);
-  if (new_rr_policy == nullptr) {
-    gpr_log(GPR_ERROR,
-            "[grpclb %p] Failure creating a RoundRobin policy for serverlist "
-            "update with %" PRIuPTR
-            " entries. The previous RR instance (%p), if any, will continue to "
-            "be used. Future updates from the LB will attempt to create new "
-            "instances.",
-            glb_policy, glb_policy->serverlist->num_servers,
-            glb_policy->rr_policy);
+void GrpcLb::OnRoundRobinConnectivityChangedLocked(void* arg,
+                                                   grpc_error* error) {
+  GrpcLb* grpclb_policy = static_cast<GrpcLb*>(arg);
+  if (grpclb_policy->shutting_down_) {
+    grpclb_policy->Unref(DEBUG_LOCATION, "on_rr_connectivity_changed");
     return;
   }
-  grpc_lb_policy_set_reresolve_closure_locked(
-      new_rr_policy, glb_policy->base.request_reresolution);
-  glb_policy->base.request_reresolution = nullptr;
-  glb_policy->rr_policy = new_rr_policy;
-  grpc_error* rr_state_error = nullptr;
-  glb_policy->rr_connectivity_state = grpc_lb_policy_check_connectivity_locked(
-      glb_policy->rr_policy, &rr_state_error);
-  /* Connectivity state is a function of the RR policy updated/created */
-  update_lb_connectivity_status_locked(
-      glb_policy, glb_policy->rr_connectivity_state, rr_state_error);
-  /* Add the gRPC LB's interested_parties pollset_set to that of the newly
-   * created RR policy. This will make the RR policy progress upon activity on
-   * gRPC LB, which in turn is tied to the application's call */
-  grpc_pollset_set_add_pollset_set(glb_policy->rr_policy->interested_parties,
-                                   glb_policy->base.interested_parties);
-  GRPC_CLOSURE_INIT(&glb_policy->on_rr_connectivity_changed,
-                    on_rr_connectivity_changed_locked, glb_policy,
-                    grpc_combiner_scheduler(glb_policy->base.combiner));
-  /* Subscribe to changes to the connectivity of the new RR */
-  GRPC_LB_POLICY_REF(&glb_policy->base, "glb_rr_connectivity_cb");
-  grpc_lb_policy_notify_on_state_change_locked(
-      glb_policy->rr_policy, &glb_policy->rr_connectivity_state,
-      &glb_policy->on_rr_connectivity_changed);
-  grpc_lb_policy_exit_idle_locked(glb_policy->rr_policy);
-  // Send pending picks to RR policy.
-  pending_pick* pp;
-  while ((pp = glb_policy->pending_picks)) {
-    glb_policy->pending_picks = pp->next;
-    if (grpc_lb_glb_trace.enabled()) {
-      gpr_log(GPR_INFO,
-              "[grpclb %p] Pending pick about to (async) PICK from RR %p",
-              glb_policy, glb_policy->rr_policy);
-    }
-    pick_from_internal_rr_locked(glb_policy, true /* force_async */, pp);
-  }
-  // Send pending pings to RR policy.
-  pending_ping* pping;
-  while ((pping = glb_policy->pending_pings)) {
-    glb_policy->pending_pings = pping->next;
-    if (grpc_lb_glb_trace.enabled()) {
-      gpr_log(GPR_INFO, "[grpclb %p] Pending ping about to PING from RR %p",
-              glb_policy, glb_policy->rr_policy);
-    }
-    grpc_lb_policy_ping_one_locked(glb_policy->rr_policy, pping->on_initiate,
-                                   pping->on_ack);
-    gpr_free(pping);
-  }
+  grpclb_policy->UpdateConnectivityStateFromRoundRobinPolicyLocked(
+      GRPC_ERROR_REF(error));
+  // Resubscribe. Reuse the "on_rr_connectivity_changed" ref.
+  grpclb_policy->rr_policy_->NotifyOnStateChangeLocked(
+      &grpclb_policy->rr_connectivity_state_,
+      &grpclb_policy->on_rr_connectivity_changed_);
 }
 
-/* glb_policy->rr_policy may be nullptr (initial handover) */
-static void rr_handover_locked(glb_lb_policy* glb_policy) {
-  if (glb_policy->shutting_down) return;
-  grpc_lb_policy_args* args = lb_policy_args_create(glb_policy);
-  GPR_ASSERT(args != nullptr);
-  if (glb_policy->rr_policy != nullptr) {
-    if (grpc_lb_glb_trace.enabled()) {
-      gpr_log(GPR_DEBUG, "[grpclb %p] Updating RR policy %p", glb_policy,
-              glb_policy->rr_policy);
-    }
-    grpc_lb_policy_update_locked(glb_policy->rr_policy, args);
-  } else {
-    create_rr_locked(glb_policy, args);
-    if (grpc_lb_glb_trace.enabled()) {
-      gpr_log(GPR_DEBUG, "[grpclb %p] Created new RR policy %p", glb_policy,
-              glb_policy->rr_policy);
-    }
-  }
-  lb_policy_args_destroy(args);
-}
-
-static void on_rr_connectivity_changed_locked(void* arg, grpc_error* error) {
-  glb_lb_policy* glb_policy = (glb_lb_policy*)arg;
-  if (glb_policy->shutting_down) {
-    GRPC_LB_POLICY_UNREF(&glb_policy->base, "glb_rr_connectivity_cb");
-    return;
-  }
-  if (glb_policy->rr_connectivity_state == GRPC_CHANNEL_SHUTDOWN) {
-    /* An RR policy that has transitioned into the SHUTDOWN connectivity state
-     * should not be considered for picks or updates: the SHUTDOWN state is a
-     * sink, policies can't transition back from it. .*/
-    GRPC_LB_POLICY_UNREF(glb_policy->rr_policy, "rr_connectivity_shutdown");
-    glb_policy->rr_policy = nullptr;
-    GRPC_LB_POLICY_UNREF(&glb_policy->base, "glb_rr_connectivity_cb");
-    return;
-  }
-  /* rr state != SHUTDOWN && !glb_policy->shutting down: biz as usual */
-  update_lb_connectivity_status_locked(
-      glb_policy, glb_policy->rr_connectivity_state, GRPC_ERROR_REF(error));
-  /* Resubscribe. Reuse the "glb_rr_connectivity_cb" ref. */
-  grpc_lb_policy_notify_on_state_change_locked(
-      glb_policy->rr_policy, &glb_policy->rr_connectivity_state,
-      &glb_policy->on_rr_connectivity_changed);
-}
-
-static void destroy_balancer_name(void* balancer_name) {
-  gpr_free(balancer_name);
-}
-
-static grpc_slice_hash_table_entry targets_info_entry_create(
-    const char* address, const char* balancer_name) {
-  grpc_slice_hash_table_entry entry;
-  entry.key = grpc_slice_from_copied_string(address);
-  entry.value = gpr_strdup(balancer_name);
-  return entry;
-}
-
-static int balancer_name_cmp_fn(void* a, void* b) {
-  const char* a_str = (const char*)a;
-  const char* b_str = (const char*)b;
-  return strcmp(a_str, b_str);
-}
-
-/* Returns the channel args for the LB channel, used to create a bidirectional
- * stream for the reception of load balancing updates.
- *
- * Inputs:
- *   - \a addresses: corresponding to the balancers.
- *   - \a response_generator: in order to propagate updates from the resolver
- *   above the grpclb policy.
- *   - \a args: other args inherited from the grpclb policy. */
-static grpc_channel_args* build_lb_channel_args(
-    const grpc_lb_addresses* addresses,
-    grpc_fake_resolver_response_generator* response_generator,
-    const grpc_channel_args* args) {
-  size_t num_grpclb_addrs = 0;
-  for (size_t i = 0; i < addresses->num_addresses; ++i) {
-    if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs;
-  }
-  /* All input addresses come from a resolver that claims they are LB services.
-   * It's the resolver's responsibility to make sure this policy is only
-   * instantiated and used in that case. Otherwise, something has gone wrong. */
-  GPR_ASSERT(num_grpclb_addrs > 0);
-  grpc_lb_addresses* lb_addresses =
-      grpc_lb_addresses_create(num_grpclb_addrs, nullptr);
-  grpc_slice_hash_table_entry* targets_info_entries =
-      (grpc_slice_hash_table_entry*)gpr_zalloc(sizeof(*targets_info_entries) *
-                                               num_grpclb_addrs);
-
-  size_t lb_addresses_idx = 0;
-  for (size_t i = 0; i < addresses->num_addresses; ++i) {
-    if (!addresses->addresses[i].is_balancer) continue;
-    if (addresses->addresses[i].user_data != nullptr) {
-      gpr_log(GPR_ERROR,
-              "This LB policy doesn't support user data. It will be ignored");
-    }
-    char* addr_str;
-    GPR_ASSERT(grpc_sockaddr_to_string(
-                   &addr_str, &addresses->addresses[i].address, true) > 0);
-    targets_info_entries[lb_addresses_idx] = targets_info_entry_create(
-        addr_str, addresses->addresses[i].balancer_name);
-    gpr_free(addr_str);
-
-    grpc_lb_addresses_set_address(
-        lb_addresses, lb_addresses_idx++, addresses->addresses[i].address.addr,
-        addresses->addresses[i].address.len, false /* is balancer */,
-        addresses->addresses[i].balancer_name, nullptr /* user data */);
-  }
-  GPR_ASSERT(num_grpclb_addrs == lb_addresses_idx);
-  grpc_slice_hash_table* targets_info =
-      grpc_slice_hash_table_create(num_grpclb_addrs, targets_info_entries,
-                                   destroy_balancer_name, balancer_name_cmp_fn);
-  gpr_free(targets_info_entries);
-
-  grpc_channel_args* lb_channel_args =
-      grpc_lb_policy_grpclb_build_lb_channel_args(targets_info,
-                                                  response_generator, args);
-
-  grpc_arg lb_channel_addresses_arg =
-      grpc_lb_addresses_create_channel_arg(lb_addresses);
-
-  grpc_channel_args* result = grpc_channel_args_copy_and_add(
-      lb_channel_args, &lb_channel_addresses_arg, 1);
-  grpc_slice_hash_table_unref(targets_info);
-  grpc_channel_args_destroy(lb_channel_args);
-  grpc_lb_addresses_destroy(lb_addresses);
-  return result;
-}
-
-static void glb_destroy(grpc_lb_policy* pol) {
-  glb_lb_policy* glb_policy = (glb_lb_policy*)pol;
-  GPR_ASSERT(glb_policy->pending_picks == nullptr);
-  GPR_ASSERT(glb_policy->pending_pings == nullptr);
-  gpr_free((void*)glb_policy->server_name);
-  grpc_channel_args_destroy(glb_policy->args);
-  grpc_connectivity_state_destroy(&glb_policy->state_tracker);
-  if (glb_policy->serverlist != nullptr) {
-    grpc_grpclb_destroy_serverlist(glb_policy->serverlist);
-  }
-  if (glb_policy->fallback_backend_addresses != nullptr) {
-    grpc_lb_addresses_destroy(glb_policy->fallback_backend_addresses);
-  }
-  grpc_fake_resolver_response_generator_unref(glb_policy->response_generator);
-  grpc_subchannel_index_unref();
-  gpr_free(glb_policy);
-}
-
-static void glb_shutdown_locked(grpc_lb_policy* pol,
-                                grpc_lb_policy* new_policy) {
-  glb_lb_policy* glb_policy = (glb_lb_policy*)pol;
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel shutdown");
-  glb_policy->shutting_down = true;
-  if (glb_policy->lb_calld != nullptr) {
-    lb_call_data_shutdown(glb_policy);
-  }
-  if (glb_policy->retry_timer_callback_pending) {
-    grpc_timer_cancel(&glb_policy->lb_call_retry_timer);
-  }
-  if (glb_policy->fallback_timer_callback_pending) {
-    grpc_timer_cancel(&glb_policy->lb_fallback_timer);
-  }
-  if (glb_policy->rr_policy != nullptr) {
-    grpc_lb_policy_shutdown_locked(glb_policy->rr_policy, nullptr);
-    GRPC_LB_POLICY_UNREF(glb_policy->rr_policy, "glb_shutdown");
-  } else {
-    grpc_lb_policy_try_reresolve(pol, &grpc_lb_glb_trace, GRPC_ERROR_CANCELLED);
-  }
-  // We destroy the LB channel here because
-  // glb_lb_channel_on_connectivity_changed_cb needs a valid glb_policy
-  // instance.  Destroying the lb channel in glb_destroy would likely result in
-  // a callback invocation without a valid glb_policy arg.
-  if (glb_policy->lb_channel != nullptr) {
-    grpc_channel_destroy(glb_policy->lb_channel);
-    glb_policy->lb_channel = nullptr;
-  }
-  grpc_connectivity_state_set(&glb_policy->state_tracker, GRPC_CHANNEL_SHUTDOWN,
-                              GRPC_ERROR_REF(error), "glb_shutdown");
-  // Clear pending picks.
-  pending_pick* pp = glb_policy->pending_picks;
-  glb_policy->pending_picks = nullptr;
-  while (pp != nullptr) {
-    pending_pick* next = pp->next;
-    if (new_policy != nullptr) {
-      // Hand pick over to new policy.
-      if (pp->client_stats != nullptr) {
-        grpc_grpclb_client_stats_unref(pp->client_stats);
-      }
-      pp->pick->on_complete = pp->original_on_complete;
-      if (grpc_lb_policy_pick_locked(new_policy, pp->pick)) {
-        // Synchronous return; schedule callback.
-        GRPC_CLOSURE_SCHED(pp->pick->on_complete, GRPC_ERROR_NONE);
-      }
-      gpr_free(pp);
-    } else {
-      pp->pick->connected_subchannel.reset();
-      GRPC_CLOSURE_SCHED(&pp->on_complete, GRPC_ERROR_REF(error));
-    }
-    pp = next;
-  }
-  // Clear pending pings.
-  pending_ping* pping = glb_policy->pending_pings;
-  glb_policy->pending_pings = nullptr;
-  while (pping != nullptr) {
-    pending_ping* next = pping->next;
-    GRPC_CLOSURE_SCHED(pping->on_initiate, GRPC_ERROR_REF(error));
-    GRPC_CLOSURE_SCHED(pping->on_ack, GRPC_ERROR_REF(error));
-    gpr_free(pping);
-    pping = next;
-  }
-  GRPC_ERROR_UNREF(error);
-}
-
-// Cancel a specific pending pick.
 //
-// A grpclb pick progresses as follows:
-// - If there's a Round Robin policy (glb_policy->rr_policy) available, it'll be
-//   handed over to the RR policy (in create_rr_locked()). From that point
-//   onwards, it'll be RR's responsibility. For cancellations, that implies the
-//   pick needs also be cancelled by the RR instance.
-// - Otherwise, without an RR instance, picks stay pending at this policy's
-//   level (grpclb), inside the glb_policy->pending_picks list. To cancel these,
-//   we invoke the completion closure and set *target to nullptr right here.
-static void glb_cancel_pick_locked(grpc_lb_policy* pol,
-                                   grpc_lb_policy_pick_state* pick,
-                                   grpc_error* error) {
-  glb_lb_policy* glb_policy = (glb_lb_policy*)pol;
-  pending_pick* pp = glb_policy->pending_picks;
-  glb_policy->pending_picks = nullptr;
-  while (pp != nullptr) {
-    pending_pick* next = pp->next;
-    if (pp->pick == pick) {
-      pick->connected_subchannel.reset();
-      GRPC_CLOSURE_SCHED(&pp->on_complete,
-                         GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-                             "Pick Cancelled", &error, 1));
-    } else {
-      pp->next = glb_policy->pending_picks;
-      glb_policy->pending_picks = pp;
-    }
-    pp = next;
-  }
-  if (glb_policy->rr_policy != nullptr) {
-    grpc_lb_policy_cancel_pick_locked(glb_policy->rr_policy, pick,
-                                      GRPC_ERROR_REF(error));
-  }
-  GRPC_ERROR_UNREF(error);
-}
-
-// Cancel all pending picks.
+// factory
 //
-// A grpclb pick progresses as follows:
-// - If there's a Round Robin policy (glb_policy->rr_policy) available, it'll be
-//   handed over to the RR policy (in create_rr_locked()). From that point
-//   onwards, it'll be RR's responsibility. For cancellations, that implies the
-//   pick needs also be cancelled by the RR instance.
-// - Otherwise, without an RR instance, picks stay pending at this policy's
-//   level (grpclb), inside the glb_policy->pending_picks list. To cancel these,
-//   we invoke the completion closure and set *target to nullptr right here.
-static void glb_cancel_picks_locked(grpc_lb_policy* pol,
-                                    uint32_t initial_metadata_flags_mask,
-                                    uint32_t initial_metadata_flags_eq,
-                                    grpc_error* error) {
-  glb_lb_policy* glb_policy = (glb_lb_policy*)pol;
-  pending_pick* pp = glb_policy->pending_picks;
-  glb_policy->pending_picks = nullptr;
-  while (pp != nullptr) {
-    pending_pick* next = pp->next;
-    if ((pp->pick->initial_metadata_flags & initial_metadata_flags_mask) ==
-        initial_metadata_flags_eq) {
-      GRPC_CLOSURE_SCHED(&pp->on_complete,
-                         GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-                             "Pick Cancelled", &error, 1));
-    } else {
-      pp->next = glb_policy->pending_picks;
-      glb_policy->pending_picks = pp;
+
+class GrpcLbFactory : public LoadBalancingPolicyFactory {
+ public:
+  OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
+      const LoadBalancingPolicy::Args& args) const override {
+    /* Count the number of gRPC-LB addresses. There must be at least one. */
+    const grpc_arg* arg =
+        grpc_channel_args_find(args.args, GRPC_ARG_LB_ADDRESSES);
+    if (arg == nullptr || arg->type != GRPC_ARG_POINTER) {
+      return nullptr;
     }
-    pp = next;
-  }
-  if (glb_policy->rr_policy != nullptr) {
-    grpc_lb_policy_cancel_picks_locked(
-        glb_policy->rr_policy, initial_metadata_flags_mask,
-        initial_metadata_flags_eq, GRPC_ERROR_REF(error));
-  }
-  GRPC_ERROR_UNREF(error);
-}
-
-static void lb_on_fallback_timer_locked(void* arg, grpc_error* error);
-static void query_for_backends_locked(glb_lb_policy* glb_policy);
-static void start_picking_locked(glb_lb_policy* glb_policy) {
-  /* start a timer to fall back */
-  if (glb_policy->lb_fallback_timeout_ms > 0 &&
-      glb_policy->serverlist == nullptr &&
-      !glb_policy->fallback_timer_callback_pending) {
-    grpc_millis deadline =
-        grpc_core::ExecCtx::Get()->Now() + glb_policy->lb_fallback_timeout_ms;
-    GRPC_LB_POLICY_REF(&glb_policy->base, "grpclb_fallback_timer");
-    GRPC_CLOSURE_INIT(&glb_policy->lb_on_fallback, lb_on_fallback_timer_locked,
-                      glb_policy,
-                      grpc_combiner_scheduler(glb_policy->base.combiner));
-    glb_policy->fallback_timer_callback_pending = true;
-    grpc_timer_init(&glb_policy->lb_fallback_timer, deadline,
-                    &glb_policy->lb_on_fallback);
-  }
-  glb_policy->started_picking = true;
-  glb_policy->lb_call_backoff->Reset();
-  query_for_backends_locked(glb_policy);
-}
-
-static void glb_exit_idle_locked(grpc_lb_policy* pol) {
-  glb_lb_policy* glb_policy = (glb_lb_policy*)pol;
-  if (!glb_policy->started_picking) {
-    start_picking_locked(glb_policy);
-  }
-}
-
-static int glb_pick_locked(grpc_lb_policy* pol,
-                           grpc_lb_policy_pick_state* pick) {
-  glb_lb_policy* glb_policy = (glb_lb_policy*)pol;
-  pending_pick* pp = pending_pick_create(glb_policy, pick);
-  bool pick_done = false;
-  if (glb_policy->rr_policy != nullptr) {
-    const grpc_connectivity_state rr_connectivity_state =
-        grpc_lb_policy_check_connectivity_locked(glb_policy->rr_policy,
-                                                 nullptr);
-    // The glb_policy->rr_policy may have transitioned to SHUTDOWN but the
-    // callback registered to capture this event
-    // (on_rr_connectivity_changed_locked) may not have been invoked yet. We
-    // need to make sure we aren't trying to pick from a RR policy instance
-    // that's in shutdown.
-    if (rr_connectivity_state == GRPC_CHANNEL_SHUTDOWN) {
-      if (grpc_lb_glb_trace.enabled()) {
-        gpr_log(GPR_INFO,
-                "[grpclb %p] NOT picking from from RR %p: RR conn state=%s",
-                glb_policy, glb_policy->rr_policy,
-                grpc_connectivity_state_name(rr_connectivity_state));
-      }
-      pending_pick_add(&glb_policy->pending_picks, pp);
-      pick_done = false;
-    } else {  // RR not in shutdown
-      if (grpc_lb_glb_trace.enabled()) {
-        gpr_log(GPR_INFO, "[grpclb %p] about to PICK from RR %p", glb_policy,
-                glb_policy->rr_policy);
-      }
-      pick_done =
-          pick_from_internal_rr_locked(glb_policy, false /* force_async */, pp);
+    grpc_lb_addresses* addresses =
+        static_cast<grpc_lb_addresses*>(arg->value.pointer.p);
+    size_t num_grpclb_addrs = 0;
+    for (size_t i = 0; i < addresses->num_addresses; ++i) {
+      if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs;
     }
-  } else {  // glb_policy->rr_policy == NULL
-    if (grpc_lb_glb_trace.enabled()) {
-      gpr_log(GPR_DEBUG,
-              "[grpclb %p] No RR policy. Adding to grpclb's pending picks",
-              glb_policy);
-    }
-    pending_pick_add(&glb_policy->pending_picks, pp);
-    if (!glb_policy->started_picking) {
-      start_picking_locked(glb_policy);
-    }
-    pick_done = false;
+    if (num_grpclb_addrs == 0) return nullptr;
+    return OrphanablePtr<LoadBalancingPolicy>(New<GrpcLb>(addresses, args));
   }
-  return pick_done;
-}
 
-static grpc_connectivity_state glb_check_connectivity_locked(
-    grpc_lb_policy* pol, grpc_error** connectivity_error) {
-  glb_lb_policy* glb_policy = (glb_lb_policy*)pol;
-  return grpc_connectivity_state_get(&glb_policy->state_tracker,
-                                     connectivity_error);
-}
+  const char* name() const override { return "grpclb"; }
+};
 
-static void glb_ping_one_locked(grpc_lb_policy* pol, grpc_closure* on_initiate,
-                                grpc_closure* on_ack) {
-  glb_lb_policy* glb_policy = (glb_lb_policy*)pol;
-  if (glb_policy->rr_policy) {
-    grpc_lb_policy_ping_one_locked(glb_policy->rr_policy, on_initiate, on_ack);
-  } else {
-    pending_ping_add(&glb_policy->pending_pings, on_initiate, on_ack);
-    if (!glb_policy->started_picking) {
-      start_picking_locked(glb_policy);
-    }
-  }
-}
+}  // namespace
 
-static void glb_notify_on_state_change_locked(grpc_lb_policy* pol,
-                                              grpc_connectivity_state* current,
-                                              grpc_closure* notify) {
-  glb_lb_policy* glb_policy = (glb_lb_policy*)pol;
-  grpc_connectivity_state_notify_on_state_change(&glb_policy->state_tracker,
-                                                 current, notify);
-}
+}  // namespace grpc_core
 
-static void lb_call_on_retry_timer_locked(void* arg, grpc_error* error) {
-  glb_lb_policy* glb_policy = (glb_lb_policy*)arg;
-  glb_policy->retry_timer_callback_pending = false;
-  if (!glb_policy->shutting_down && error == GRPC_ERROR_NONE &&
-      glb_policy->lb_calld == nullptr) {
-    if (grpc_lb_glb_trace.enabled()) {
-      gpr_log(GPR_INFO, "[grpclb %p] Restarting call to LB server", glb_policy);
-    }
-    query_for_backends_locked(glb_policy);
-  }
-  GRPC_LB_POLICY_UNREF(&glb_policy->base, "grpclb_retry_timer");
-}
+//
+// Plugin registration
+//
 
-static void start_lb_call_retry_timer_locked(glb_lb_policy* glb_policy) {
-  grpc_millis next_try = glb_policy->lb_call_backoff->NextAttemptTime();
-  if (grpc_lb_glb_trace.enabled()) {
-    gpr_log(GPR_DEBUG, "[grpclb %p] Connection to LB server lost...",
-            glb_policy);
-    grpc_millis timeout = next_try - grpc_core::ExecCtx::Get()->Now();
-    if (timeout > 0) {
-      gpr_log(GPR_DEBUG,
-              "[grpclb %p] ... retry_timer_active in %" PRIuPTR "ms.",
-              glb_policy, timeout);
-    } else {
-      gpr_log(GPR_DEBUG, "[grpclb %p] ... retry_timer_active immediately.",
-              glb_policy);
-    }
-  }
-  GRPC_LB_POLICY_REF(&glb_policy->base, "grpclb_retry_timer");
-  GRPC_CLOSURE_INIT(&glb_policy->lb_on_call_retry,
-                    lb_call_on_retry_timer_locked, glb_policy,
-                    grpc_combiner_scheduler(glb_policy->base.combiner));
-  glb_policy->retry_timer_callback_pending = true;
-  grpc_timer_init(&glb_policy->lb_call_retry_timer, next_try,
-                  &glb_policy->lb_on_call_retry);
-}
-
-static void maybe_send_client_load_report_locked(void* arg, grpc_error* error);
-
-static void schedule_next_client_load_report(glb_lb_call_data* lb_calld) {
-  const grpc_millis next_client_load_report_time =
-      grpc_core::ExecCtx::Get()->Now() + lb_calld->client_stats_report_interval;
-  GRPC_CLOSURE_INIT(
-      &lb_calld->client_load_report_closure,
-      maybe_send_client_load_report_locked, lb_calld,
-      grpc_combiner_scheduler(lb_calld->glb_policy->base.combiner));
-  grpc_timer_init(&lb_calld->client_load_report_timer,
-                  next_client_load_report_time,
-                  &lb_calld->client_load_report_closure);
-  lb_calld->client_load_report_timer_callback_pending = true;
-}
-
-static void client_load_report_done_locked(void* arg, grpc_error* error) {
-  glb_lb_call_data* lb_calld = (glb_lb_call_data*)arg;
-  glb_lb_policy* glb_policy = lb_calld->glb_policy;
-  grpc_byte_buffer_destroy(lb_calld->send_message_payload);
-  lb_calld->send_message_payload = nullptr;
-  if (error != GRPC_ERROR_NONE || lb_calld != glb_policy->lb_calld) {
-    glb_lb_call_data_unref(lb_calld, "client_load_report");
-    return;
-  }
-  schedule_next_client_load_report(lb_calld);
-}
-
-static bool load_report_counters_are_zero(grpc_grpclb_request* request) {
-  grpc_grpclb_dropped_call_counts* drop_entries =
-      (grpc_grpclb_dropped_call_counts*)
-          request->client_stats.calls_finished_with_drop.arg;
-  return request->client_stats.num_calls_started == 0 &&
-         request->client_stats.num_calls_finished == 0 &&
-         request->client_stats.num_calls_finished_with_client_failed_to_send ==
-             0 &&
-         request->client_stats.num_calls_finished_known_received == 0 &&
-         (drop_entries == nullptr || drop_entries->num_entries == 0);
-}
-
-static void send_client_load_report_locked(glb_lb_call_data* lb_calld) {
-  glb_lb_policy* glb_policy = lb_calld->glb_policy;
-  // Construct message payload.
-  GPR_ASSERT(lb_calld->send_message_payload == nullptr);
-  grpc_grpclb_request* request =
-      grpc_grpclb_load_report_request_create_locked(lb_calld->client_stats);
-  // Skip client load report if the counters were all zero in the last
-  // report and they are still zero in this one.
-  if (load_report_counters_are_zero(request)) {
-    if (lb_calld->last_client_load_report_counters_were_zero) {
-      grpc_grpclb_request_destroy(request);
-      schedule_next_client_load_report(lb_calld);
-      return;
-    }
-    lb_calld->last_client_load_report_counters_were_zero = true;
-  } else {
-    lb_calld->last_client_load_report_counters_were_zero = false;
-  }
-  grpc_slice request_payload_slice = grpc_grpclb_request_encode(request);
-  lb_calld->send_message_payload =
-      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
-  grpc_slice_unref_internal(request_payload_slice);
-  grpc_grpclb_request_destroy(request);
-  // Send the report.
-  grpc_op op;
-  memset(&op, 0, sizeof(op));
-  op.op = GRPC_OP_SEND_MESSAGE;
-  op.data.send_message.send_message = lb_calld->send_message_payload;
-  GRPC_CLOSURE_INIT(&lb_calld->client_load_report_closure,
-                    client_load_report_done_locked, lb_calld,
-                    grpc_combiner_scheduler(glb_policy->base.combiner));
-  grpc_call_error call_error = grpc_call_start_batch_and_execute(
-      lb_calld->lb_call, &op, 1, &lb_calld->client_load_report_closure);
-  if (call_error != GRPC_CALL_OK) {
-    gpr_log(GPR_ERROR, "[grpclb %p] call_error=%d", glb_policy, call_error);
-    GPR_ASSERT(GRPC_CALL_OK == call_error);
-  }
-}
-
-static void maybe_send_client_load_report_locked(void* arg, grpc_error* error) {
-  glb_lb_call_data* lb_calld = (glb_lb_call_data*)arg;
-  glb_lb_policy* glb_policy = lb_calld->glb_policy;
-  lb_calld->client_load_report_timer_callback_pending = false;
-  if (error != GRPC_ERROR_NONE || lb_calld != glb_policy->lb_calld) {
-    glb_lb_call_data_unref(lb_calld, "client_load_report");
-    return;
-  }
-  // If we've already sent the initial request, then we can go ahead and send
-  // the load report. Otherwise, we need to wait until the initial request has
-  // been sent to send this (see lb_on_sent_initial_request_locked()).
-  if (lb_calld->send_message_payload == nullptr) {
-    send_client_load_report_locked(lb_calld);
-  } else {
-    lb_calld->client_load_report_is_due = true;
-  }
-}
-
-static void lb_on_sent_initial_request_locked(void* arg, grpc_error* error);
-static void lb_on_server_status_received_locked(void* arg, grpc_error* error);
-static void lb_on_response_received_locked(void* arg, grpc_error* error);
-static glb_lb_call_data* lb_call_data_create_locked(glb_lb_policy* glb_policy) {
-  GPR_ASSERT(!glb_policy->shutting_down);
-  // Init the LB call. Note that the LB call will progress every time there's
-  // activity in glb_policy->base.interested_parties, which is comprised of the
-  // polling entities from client_channel.
-  GPR_ASSERT(glb_policy->server_name != nullptr);
-  GPR_ASSERT(glb_policy->server_name[0] != '\0');
-  grpc_slice host = grpc_slice_from_copied_string(glb_policy->server_name);
-  grpc_millis deadline =
-      glb_policy->lb_call_timeout_ms == 0
-          ? GRPC_MILLIS_INF_FUTURE
-          : grpc_core::ExecCtx::Get()->Now() + glb_policy->lb_call_timeout_ms;
-  glb_lb_call_data* lb_calld = (glb_lb_call_data*)gpr_zalloc(sizeof(*lb_calld));
-  lb_calld->lb_call = grpc_channel_create_pollset_set_call(
-      glb_policy->lb_channel, nullptr, GRPC_PROPAGATE_DEFAULTS,
-      glb_policy->base.interested_parties,
-      GRPC_MDSTR_SLASH_GRPC_DOT_LB_DOT_V1_DOT_LOADBALANCER_SLASH_BALANCELOAD,
-      &host, deadline, nullptr);
-  grpc_slice_unref_internal(host);
-  // Init the LB call request payload.
-  grpc_grpclb_request* request =
-      grpc_grpclb_request_create(glb_policy->server_name);
-  grpc_slice request_payload_slice = grpc_grpclb_request_encode(request);
-  lb_calld->send_message_payload =
-      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
-  grpc_slice_unref_internal(request_payload_slice);
-  grpc_grpclb_request_destroy(request);
-  // Init other data associated with the LB call.
-  lb_calld->glb_policy = glb_policy;
-  gpr_ref_init(&lb_calld->refs, 1);
-  grpc_metadata_array_init(&lb_calld->lb_initial_metadata_recv);
-  grpc_metadata_array_init(&lb_calld->lb_trailing_metadata_recv);
-  GRPC_CLOSURE_INIT(&lb_calld->lb_on_sent_initial_request,
-                    lb_on_sent_initial_request_locked, lb_calld,
-                    grpc_combiner_scheduler(glb_policy->base.combiner));
-  GRPC_CLOSURE_INIT(&lb_calld->lb_on_response_received,
-                    lb_on_response_received_locked, lb_calld,
-                    grpc_combiner_scheduler(glb_policy->base.combiner));
-  GRPC_CLOSURE_INIT(&lb_calld->lb_on_server_status_received,
-                    lb_on_server_status_received_locked, lb_calld,
-                    grpc_combiner_scheduler(glb_policy->base.combiner));
-  // Hold a ref to the glb_policy.
-  GRPC_LB_POLICY_REF(&glb_policy->base, "lb_calld");
-  return lb_calld;
-}
-
-/*
- * Auxiliary functions and LB client callbacks.
- */
-
-static void query_for_backends_locked(glb_lb_policy* glb_policy) {
-  GPR_ASSERT(glb_policy->lb_channel != nullptr);
-  if (glb_policy->shutting_down) return;
-  // Init the LB call data.
-  GPR_ASSERT(glb_policy->lb_calld == nullptr);
-  glb_policy->lb_calld = lb_call_data_create_locked(glb_policy);
-  if (grpc_lb_glb_trace.enabled()) {
-    gpr_log(GPR_INFO,
-            "[grpclb %p] Query for backends (lb_channel: %p, lb_calld: %p, "
-            "lb_call: %p)",
-            glb_policy, glb_policy->lb_channel, glb_policy->lb_calld,
-            glb_policy->lb_calld->lb_call);
-  }
-  GPR_ASSERT(glb_policy->lb_calld->lb_call != nullptr);
-  // Create the ops.
-  grpc_call_error call_error;
-  grpc_op ops[3];
-  memset(ops, 0, sizeof(ops));
-  // Op: send initial metadata.
-  grpc_op* op = ops;
-  op->op = GRPC_OP_SEND_INITIAL_METADATA;
-  op->data.send_initial_metadata.count = 0;
-  op->flags = 0;
-  op->reserved = nullptr;
-  op++;
-  // Op: send request message.
-  GPR_ASSERT(glb_policy->lb_calld->send_message_payload != nullptr);
-  op->op = GRPC_OP_SEND_MESSAGE;
-  op->data.send_message.send_message =
-      glb_policy->lb_calld->send_message_payload;
-  op->flags = 0;
-  op->reserved = nullptr;
-  op++;
-  glb_lb_call_data_ref(glb_policy->lb_calld,
-                       "lb_on_sent_initial_request_locked");
-  call_error = grpc_call_start_batch_and_execute(
-      glb_policy->lb_calld->lb_call, ops, (size_t)(op - ops),
-      &glb_policy->lb_calld->lb_on_sent_initial_request);
-  GPR_ASSERT(GRPC_CALL_OK == call_error);
-  // Op: recv initial metadata.
-  op = ops;
-  op->op = GRPC_OP_RECV_INITIAL_METADATA;
-  op->data.recv_initial_metadata.recv_initial_metadata =
-      &glb_policy->lb_calld->lb_initial_metadata_recv;
-  op->flags = 0;
-  op->reserved = nullptr;
-  op++;
-  // Op: recv response.
-  op->op = GRPC_OP_RECV_MESSAGE;
-  op->data.recv_message.recv_message =
-      &glb_policy->lb_calld->recv_message_payload;
-  op->flags = 0;
-  op->reserved = nullptr;
-  op++;
-  glb_lb_call_data_ref(glb_policy->lb_calld, "lb_on_response_received_locked");
-  call_error = grpc_call_start_batch_and_execute(
-      glb_policy->lb_calld->lb_call, ops, (size_t)(op - ops),
-      &glb_policy->lb_calld->lb_on_response_received);
-  GPR_ASSERT(GRPC_CALL_OK == call_error);
-  // Op: recv server status.
-  op = ops;
-  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
-  op->data.recv_status_on_client.trailing_metadata =
-      &glb_policy->lb_calld->lb_trailing_metadata_recv;
-  op->data.recv_status_on_client.status = &glb_policy->lb_calld->lb_call_status;
-  op->data.recv_status_on_client.status_details =
-      &glb_policy->lb_calld->lb_call_status_details;
-  op->flags = 0;
-  op->reserved = nullptr;
-  op++;
-  // This callback signals the end of the LB call, so it relies on the initial
-  // ref instead of a new ref. When it's invoked, it's the initial ref that is
-  // unreffed.
-  call_error = grpc_call_start_batch_and_execute(
-      glb_policy->lb_calld->lb_call, ops, (size_t)(op - ops),
-      &glb_policy->lb_calld->lb_on_server_status_received);
-  GPR_ASSERT(GRPC_CALL_OK == call_error);
-}
-
-static void lb_on_sent_initial_request_locked(void* arg, grpc_error* error) {
-  glb_lb_call_data* lb_calld = (glb_lb_call_data*)arg;
-  grpc_byte_buffer_destroy(lb_calld->send_message_payload);
-  lb_calld->send_message_payload = nullptr;
-  // If we attempted to send a client load report before the initial request was
-  // sent (and this lb_calld is still in use), send the load report now.
-  if (lb_calld->client_load_report_is_due &&
-      lb_calld == lb_calld->glb_policy->lb_calld) {
-    send_client_load_report_locked(lb_calld);
-    lb_calld->client_load_report_is_due = false;
-  }
-  glb_lb_call_data_unref(lb_calld, "lb_on_sent_initial_request_locked");
-}
-
-static void lb_on_response_received_locked(void* arg, grpc_error* error) {
-  glb_lb_call_data* lb_calld = (glb_lb_call_data*)arg;
-  glb_lb_policy* glb_policy = lb_calld->glb_policy;
-  // Empty payload means the LB call was cancelled.
-  if (lb_calld != glb_policy->lb_calld ||
-      lb_calld->recv_message_payload == nullptr) {
-    glb_lb_call_data_unref(lb_calld, "lb_on_response_received_locked");
-    return;
-  }
-  grpc_op ops[2];
-  memset(ops, 0, sizeof(ops));
-  grpc_op* op = ops;
-  glb_policy->lb_call_backoff->Reset();
-  grpc_byte_buffer_reader bbr;
-  grpc_byte_buffer_reader_init(&bbr, lb_calld->recv_message_payload);
-  grpc_slice response_slice = grpc_byte_buffer_reader_readall(&bbr);
-  grpc_byte_buffer_reader_destroy(&bbr);
-  grpc_byte_buffer_destroy(lb_calld->recv_message_payload);
-  lb_calld->recv_message_payload = nullptr;
-  grpc_grpclb_initial_response* initial_response;
-  grpc_grpclb_serverlist* serverlist;
-  if (!lb_calld->seen_initial_response &&
-      (initial_response = grpc_grpclb_initial_response_parse(response_slice)) !=
-          nullptr) {
-    // Have NOT seen initial response, look for initial response.
-    if (initial_response->has_client_stats_report_interval) {
-      lb_calld->client_stats_report_interval = GPR_MAX(
-          GPR_MS_PER_SEC, grpc_grpclb_duration_to_millis(
-                              &initial_response->client_stats_report_interval));
-      if (grpc_lb_glb_trace.enabled()) {
-        gpr_log(GPR_INFO,
-                "[grpclb %p] Received initial LB response message; "
-                "client load reporting interval = %" PRIdPTR " milliseconds",
-                glb_policy, lb_calld->client_stats_report_interval);
-      }
-    } else if (grpc_lb_glb_trace.enabled()) {
-      gpr_log(GPR_INFO,
-              "[grpclb %p] Received initial LB response message; client load "
-              "reporting NOT enabled",
-              glb_policy);
-    }
-    grpc_grpclb_initial_response_destroy(initial_response);
-    lb_calld->seen_initial_response = true;
-  } else if ((serverlist = grpc_grpclb_response_parse_serverlist(
-                  response_slice)) != nullptr) {
-    // Have seen initial response, look for serverlist.
-    GPR_ASSERT(lb_calld->lb_call != nullptr);
-    if (grpc_lb_glb_trace.enabled()) {
-      gpr_log(GPR_INFO,
-              "[grpclb %p] Serverlist with %" PRIuPTR " servers received",
-              glb_policy, serverlist->num_servers);
-      for (size_t i = 0; i < serverlist->num_servers; ++i) {
-        grpc_resolved_address addr;
-        parse_server(serverlist->servers[i], &addr);
-        char* ipport;
-        grpc_sockaddr_to_string(&ipport, &addr, false);
-        gpr_log(GPR_INFO, "[grpclb %p] Serverlist[%" PRIuPTR "]: %s",
-                glb_policy, i, ipport);
-        gpr_free(ipport);
-      }
-    }
-    /* update serverlist */
-    if (serverlist->num_servers > 0) {
-      // Start sending client load report only after we start using the
-      // serverlist returned from the current LB call.
-      if (lb_calld->client_stats_report_interval > 0 &&
-          lb_calld->client_stats == nullptr) {
-        lb_calld->client_stats = grpc_grpclb_client_stats_create();
-        glb_lb_call_data_ref(lb_calld, "client_load_report");
-        schedule_next_client_load_report(lb_calld);
-      }
-      if (grpc_grpclb_serverlist_equals(glb_policy->serverlist, serverlist)) {
-        if (grpc_lb_glb_trace.enabled()) {
-          gpr_log(GPR_INFO,
-                  "[grpclb %p] Incoming server list identical to current, "
-                  "ignoring.",
-                  glb_policy);
-        }
-        grpc_grpclb_destroy_serverlist(serverlist);
-      } else { /* new serverlist */
-        if (glb_policy->serverlist != nullptr) {
-          /* dispose of the old serverlist */
-          grpc_grpclb_destroy_serverlist(glb_policy->serverlist);
-        } else {
-          /* or dispose of the fallback */
-          grpc_lb_addresses_destroy(glb_policy->fallback_backend_addresses);
-          glb_policy->fallback_backend_addresses = nullptr;
-          if (glb_policy->fallback_timer_callback_pending) {
-            grpc_timer_cancel(&glb_policy->lb_fallback_timer);
-            glb_policy->fallback_timer_callback_pending = false;
-          }
-        }
-        /* and update the copy in the glb_lb_policy instance. This
-         * serverlist instance will be destroyed either upon the next
-         * update or in glb_destroy() */
-        glb_policy->serverlist = serverlist;
-        glb_policy->serverlist_index = 0;
-        rr_handover_locked(glb_policy);
-      }
-    } else {
-      if (grpc_lb_glb_trace.enabled()) {
-        gpr_log(GPR_INFO, "[grpclb %p] Received empty server list, ignoring.",
-                glb_policy);
-      }
-      grpc_grpclb_destroy_serverlist(serverlist);
-    }
-  } else {
-    // No valid initial response or serverlist found.
-    gpr_log(GPR_ERROR,
-            "[grpclb %p] Invalid LB response received: '%s'. Ignoring.",
-            glb_policy,
-            grpc_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX));
-  }
-  grpc_slice_unref_internal(response_slice);
-  if (!glb_policy->shutting_down) {
-    // Keep listening for serverlist updates.
-    op->op = GRPC_OP_RECV_MESSAGE;
-    op->data.recv_message.recv_message = &lb_calld->recv_message_payload;
-    op->flags = 0;
-    op->reserved = nullptr;
-    op++;
-    // Reuse the "lb_on_response_received_locked" ref taken in
-    // query_for_backends_locked().
-    const grpc_call_error call_error = grpc_call_start_batch_and_execute(
-        lb_calld->lb_call, ops, (size_t)(op - ops),
-        &lb_calld->lb_on_response_received);
-    GPR_ASSERT(GRPC_CALL_OK == call_error);
-  } else {
-    glb_lb_call_data_unref(lb_calld,
-                           "lb_on_response_received_locked+glb_shutdown");
-  }
-}
-
-static void lb_on_server_status_received_locked(void* arg, grpc_error* error) {
-  glb_lb_call_data* lb_calld = (glb_lb_call_data*)arg;
-  glb_lb_policy* glb_policy = lb_calld->glb_policy;
-  GPR_ASSERT(lb_calld->lb_call != nullptr);
-  if (grpc_lb_glb_trace.enabled()) {
-    char* status_details =
-        grpc_slice_to_c_string(lb_calld->lb_call_status_details);
-    gpr_log(GPR_INFO,
-            "[grpclb %p] Status from LB server received. Status = %d, details "
-            "= '%s', (lb_calld: %p, lb_call: %p), error '%s'",
-            lb_calld->glb_policy, lb_calld->lb_call_status, status_details,
-            lb_calld, lb_calld->lb_call, grpc_error_string(error));
-    gpr_free(status_details);
-  }
-  // If this lb_calld is still in use, this call ended because of a failure so
-  // we want to retry connecting. Otherwise, we have deliberately ended this
-  // call and no further action is required.
-  if (lb_calld == glb_policy->lb_calld) {
-    glb_policy->lb_calld = nullptr;
-    if (lb_calld->client_load_report_timer_callback_pending) {
-      grpc_timer_cancel(&lb_calld->client_load_report_timer);
-    }
-    GPR_ASSERT(!glb_policy->shutting_down);
-    if (lb_calld->seen_initial_response) {
-      // If we lose connection to the LB server, reset the backoff and restart
-      // the LB call immediately.
-      glb_policy->lb_call_backoff->Reset();
-      query_for_backends_locked(glb_policy);
-    } else {
-      // If this LB call fails establishing any connection to the LB server,
-      // retry later.
-      start_lb_call_retry_timer_locked(glb_policy);
-    }
-  }
-  glb_lb_call_data_unref(lb_calld, "lb_call_ended");
-}
-
-static void lb_on_fallback_timer_locked(void* arg, grpc_error* error) {
-  glb_lb_policy* glb_policy = (glb_lb_policy*)arg;
-  glb_policy->fallback_timer_callback_pending = false;
-  /* If we receive a serverlist after the timer fires but before this callback
-   * actually runs, don't fall back. */
-  if (glb_policy->serverlist == nullptr) {
-    if (!glb_policy->shutting_down && error == GRPC_ERROR_NONE) {
-      if (grpc_lb_glb_trace.enabled()) {
-        gpr_log(GPR_INFO,
-                "[grpclb %p] Falling back to use backends from resolver",
-                glb_policy);
-      }
-      GPR_ASSERT(glb_policy->fallback_backend_addresses != nullptr);
-      rr_handover_locked(glb_policy);
-    }
-  }
-  GRPC_LB_POLICY_UNREF(&glb_policy->base, "grpclb_fallback_timer");
-}
-
-static void fallback_update_locked(glb_lb_policy* glb_policy,
-                                   const grpc_lb_addresses* addresses) {
-  GPR_ASSERT(glb_policy->fallback_backend_addresses != nullptr);
-  grpc_lb_addresses_destroy(glb_policy->fallback_backend_addresses);
-  glb_policy->fallback_backend_addresses =
-      extract_backend_addresses_locked(addresses);
-  if (glb_policy->lb_fallback_timeout_ms > 0 &&
-      glb_policy->rr_policy != nullptr) {
-    rr_handover_locked(glb_policy);
-  }
-}
-
-static void glb_update_locked(grpc_lb_policy* policy,
-                              const grpc_lb_policy_args* args) {
-  glb_lb_policy* glb_policy = (glb_lb_policy*)policy;
-  const grpc_arg* arg =
-      grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES);
-  if (arg == nullptr || arg->type != GRPC_ARG_POINTER) {
-    if (glb_policy->lb_channel == nullptr) {
-      // If we don't have a current channel to the LB, go into TRANSIENT
-      // FAILURE.
-      grpc_connectivity_state_set(
-          &glb_policy->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
-          GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing update in args"),
-          "glb_update_missing");
-    } else {
-      // otherwise, keep using the current LB channel (ignore this update).
-      gpr_log(
-          GPR_ERROR,
-          "[grpclb %p] No valid LB addresses channel arg in update, ignoring.",
-          glb_policy);
-    }
-    return;
-  }
-  const grpc_lb_addresses* addresses =
-      (const grpc_lb_addresses*)arg->value.pointer.p;
-  // If a non-empty serverlist hasn't been received from the balancer,
-  // propagate the update to fallback_backend_addresses.
-  if (glb_policy->serverlist == nullptr) {
-    fallback_update_locked(glb_policy, addresses);
-  }
-  GPR_ASSERT(glb_policy->lb_channel != nullptr);
-  // Propagate updates to the LB channel (pick_first) through the fake
-  // resolver.
-  grpc_channel_args* lb_channel_args = build_lb_channel_args(
-      addresses, glb_policy->response_generator, args->args);
-  grpc_fake_resolver_response_generator_set_response(
-      glb_policy->response_generator, lb_channel_args);
-  grpc_channel_args_destroy(lb_channel_args);
-  // Start watching the LB channel connectivity for connection, if not
-  // already doing so.
-  if (!glb_policy->watching_lb_channel) {
-    glb_policy->lb_channel_connectivity = grpc_channel_check_connectivity_state(
-        glb_policy->lb_channel, true /* try to connect */);
-    grpc_channel_element* client_channel_elem = grpc_channel_stack_last_element(
-        grpc_channel_get_channel_stack(glb_policy->lb_channel));
-    GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter);
-    glb_policy->watching_lb_channel = true;
-    GRPC_LB_POLICY_REF(&glb_policy->base, "watch_lb_channel_connectivity");
-    grpc_client_channel_watch_connectivity_state(
-        client_channel_elem,
-        grpc_polling_entity_create_from_pollset_set(
-            glb_policy->base.interested_parties),
-        &glb_policy->lb_channel_connectivity,
-        &glb_policy->lb_channel_on_connectivity_changed, nullptr);
-  }
-}
-
-// Invoked as part of the update process. It continues watching the LB channel
-// until it shuts down or becomes READY. It's invoked even if the LB channel
-// stayed READY throughout the update (for example if the update is identical).
-static void glb_lb_channel_on_connectivity_changed_cb(void* arg,
-                                                      grpc_error* error) {
-  glb_lb_policy* glb_policy = (glb_lb_policy*)arg;
-  if (glb_policy->shutting_down) goto done;
-  // Re-initialize the lb_call. This should also take care of updating the
-  // embedded RR policy. Note that the current RR policy, if any, will stay in
-  // effect until an update from the new lb_call is received.
-  switch (glb_policy->lb_channel_connectivity) {
-    case GRPC_CHANNEL_CONNECTING:
-    case GRPC_CHANNEL_TRANSIENT_FAILURE: {
-      // Keep watching the LB channel.
-      grpc_channel_element* client_channel_elem =
-          grpc_channel_stack_last_element(
-              grpc_channel_get_channel_stack(glb_policy->lb_channel));
-      GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter);
-      grpc_client_channel_watch_connectivity_state(
-          client_channel_elem,
-          grpc_polling_entity_create_from_pollset_set(
-              glb_policy->base.interested_parties),
-          &glb_policy->lb_channel_connectivity,
-          &glb_policy->lb_channel_on_connectivity_changed, nullptr);
-      break;
-    }
-      // The LB channel may be IDLE because it's shut down before the update.
-      // Restart the LB call to kick the LB channel into gear.
-    case GRPC_CHANNEL_IDLE:
-    case GRPC_CHANNEL_READY:
-      if (glb_policy->lb_calld != nullptr) {
-        lb_call_data_shutdown(glb_policy);
-      }
-      if (glb_policy->started_picking) {
-        if (glb_policy->retry_timer_callback_pending) {
-          grpc_timer_cancel(&glb_policy->lb_call_retry_timer);
-        }
-        glb_policy->lb_call_backoff->Reset();
-        query_for_backends_locked(glb_policy);
-      }
-      // Fall through.
-    case GRPC_CHANNEL_SHUTDOWN:
-    done:
-      glb_policy->watching_lb_channel = false;
-      GRPC_LB_POLICY_UNREF(&glb_policy->base,
-                           "watch_lb_channel_connectivity_cb_shutdown");
-  }
-}
-
-static void glb_set_reresolve_closure_locked(
-    grpc_lb_policy* policy, grpc_closure* request_reresolution) {
-  glb_lb_policy* glb_policy = (glb_lb_policy*)policy;
-  GPR_ASSERT(!glb_policy->shutting_down);
-  GPR_ASSERT(glb_policy->base.request_reresolution == nullptr);
-  if (glb_policy->rr_policy != nullptr) {
-    grpc_lb_policy_set_reresolve_closure_locked(glb_policy->rr_policy,
-                                                request_reresolution);
-  } else {
-    glb_policy->base.request_reresolution = request_reresolution;
-  }
-}
-
-/* Code wiring the policy with the rest of the core */
-static const grpc_lb_policy_vtable glb_lb_policy_vtable = {
-    glb_destroy,
-    glb_shutdown_locked,
-    glb_pick_locked,
-    glb_cancel_pick_locked,
-    glb_cancel_picks_locked,
-    glb_ping_one_locked,
-    glb_exit_idle_locked,
-    glb_check_connectivity_locked,
-    glb_notify_on_state_change_locked,
-    glb_update_locked,
-    glb_set_reresolve_closure_locked};
-
-static grpc_lb_policy* glb_create(grpc_lb_policy_factory* factory,
-                                  grpc_lb_policy_args* args) {
-  /* Count the number of gRPC-LB addresses. There must be at least one. */
-  const grpc_arg* arg =
-      grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES);
-  if (arg == nullptr || arg->type != GRPC_ARG_POINTER) {
-    return nullptr;
-  }
-  grpc_lb_addresses* addresses = (grpc_lb_addresses*)arg->value.pointer.p;
-  size_t num_grpclb_addrs = 0;
-  for (size_t i = 0; i < addresses->num_addresses; ++i) {
-    if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs;
-  }
-  if (num_grpclb_addrs == 0) return nullptr;
-
-  glb_lb_policy* glb_policy = (glb_lb_policy*)gpr_zalloc(sizeof(*glb_policy));
-
-  /* Get server name. */
-  arg = grpc_channel_args_find(args->args, GRPC_ARG_SERVER_URI);
-  GPR_ASSERT(arg != nullptr);
-  GPR_ASSERT(arg->type == GRPC_ARG_STRING);
-  grpc_uri* uri = grpc_uri_parse(arg->value.string, true);
-  GPR_ASSERT(uri->path[0] != '\0');
-  glb_policy->server_name =
-      gpr_strdup(uri->path[0] == '/' ? uri->path + 1 : uri->path);
-  if (grpc_lb_glb_trace.enabled()) {
-    gpr_log(GPR_INFO,
-            "[grpclb %p] Will use '%s' as the server name for LB request.",
-            glb_policy, glb_policy->server_name);
-  }
-  grpc_uri_destroy(uri);
-
-  glb_policy->cc_factory = args->client_channel_factory;
-  GPR_ASSERT(glb_policy->cc_factory != nullptr);
-
-  arg = grpc_channel_args_find(args->args, GRPC_ARG_GRPCLB_CALL_TIMEOUT_MS);
-  glb_policy->lb_call_timeout_ms =
-      grpc_channel_arg_get_integer(arg, {0, 0, INT_MAX});
-
-  arg = grpc_channel_args_find(args->args, GRPC_ARG_GRPCLB_FALLBACK_TIMEOUT_MS);
-  glb_policy->lb_fallback_timeout_ms = grpc_channel_arg_get_integer(
-      arg, {GRPC_GRPCLB_DEFAULT_FALLBACK_TIMEOUT_MS, 0, INT_MAX});
-
-  // Make sure that GRPC_ARG_LB_POLICY_NAME is set in channel args,
-  // since we use this to trigger the client_load_reporting filter.
-  grpc_arg new_arg = grpc_channel_arg_string_create(
-      (char*)GRPC_ARG_LB_POLICY_NAME, (char*)"grpclb");
-  static const char* args_to_remove[] = {GRPC_ARG_LB_POLICY_NAME};
-  glb_policy->args = grpc_channel_args_copy_and_add_and_remove(
-      args->args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), &new_arg, 1);
-
-  /* Extract the backend addresses (may be empty) from the resolver for
-   * fallback. */
-  glb_policy->fallback_backend_addresses =
-      extract_backend_addresses_locked(addresses);
-
-  /* Create a client channel over them to communicate with a LB service */
-  glb_policy->response_generator =
-      grpc_fake_resolver_response_generator_create();
-  grpc_channel_args* lb_channel_args = build_lb_channel_args(
-      addresses, glb_policy->response_generator, args->args);
-  char* uri_str;
-  gpr_asprintf(&uri_str, "fake:///%s", glb_policy->server_name);
-  glb_policy->lb_channel = grpc_lb_policy_grpclb_create_lb_channel(
-      uri_str, args->client_channel_factory, lb_channel_args);
-
-  /* Propagate initial resolution */
-  grpc_fake_resolver_response_generator_set_response(
-      glb_policy->response_generator, lb_channel_args);
-  grpc_channel_args_destroy(lb_channel_args);
-  gpr_free(uri_str);
-  if (glb_policy->lb_channel == nullptr) {
-    gpr_free((void*)glb_policy->server_name);
-    grpc_channel_args_destroy(glb_policy->args);
-    gpr_free(glb_policy);
-    return nullptr;
-  }
-  grpc_subchannel_index_ref();
-  GRPC_CLOSURE_INIT(&glb_policy->lb_channel_on_connectivity_changed,
-                    glb_lb_channel_on_connectivity_changed_cb, glb_policy,
-                    grpc_combiner_scheduler(args->combiner));
-  grpc_lb_policy_init(&glb_policy->base, &glb_lb_policy_vtable, args->combiner);
-  grpc_connectivity_state_init(&glb_policy->state_tracker, GRPC_CHANNEL_IDLE,
-                               "grpclb");
-  // Init LB call backoff option.
-  grpc_core::BackOff::Options backoff_options;
-  backoff_options
-      .set_initial_backoff(GRPC_GRPCLB_INITIAL_CONNECT_BACKOFF_SECONDS * 1000)
-      .set_multiplier(GRPC_GRPCLB_RECONNECT_BACKOFF_MULTIPLIER)
-      .set_jitter(GRPC_GRPCLB_RECONNECT_JITTER)
-      .set_max_backoff(GRPC_GRPCLB_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
-  glb_policy->lb_call_backoff.Init(backoff_options);
-  return &glb_policy->base;
-}
-
-static void glb_factory_ref(grpc_lb_policy_factory* factory) {}
-
-static void glb_factory_unref(grpc_lb_policy_factory* factory) {}
-
-static const grpc_lb_policy_factory_vtable glb_factory_vtable = {
-    glb_factory_ref, glb_factory_unref, glb_create, "grpclb"};
-
-static grpc_lb_policy_factory glb_lb_policy_factory = {&glb_factory_vtable};
-
-grpc_lb_policy_factory* grpc_glb_lb_factory_create() {
-  return &glb_lb_policy_factory;
-}
-
-/* Plugin registration */
+namespace {
 
 // Only add client_load_reporting filter if the grpclb LB policy is used.
-static bool maybe_add_client_load_reporting_filter(
-    grpc_channel_stack_builder* builder, void* arg) {
+bool maybe_add_client_load_reporting_filter(grpc_channel_stack_builder* builder,
+                                            void* arg) {
   const grpc_channel_args* args =
       grpc_channel_stack_builder_get_channel_arguments(builder);
   const grpc_arg* channel_arg =
@@ -1925,8 +1885,13 @@
   return true;
 }
 
+}  // namespace
+
 void grpc_lb_policy_grpclb_init() {
-  grpc_register_lb_policy(grpc_glb_lb_factory_create());
+  grpc_core::LoadBalancingPolicyRegistry::Builder::
+      RegisterLoadBalancingPolicyFactory(
+          grpc_core::UniquePtr<grpc_core::LoadBalancingPolicyFactory>(
+              grpc_core::New<grpc_core::GrpcLbFactory>()));
   grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL,
                                    GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
                                    maybe_add_client_load_reporting_filter,
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h
deleted file mode 100644
index 0a2edb0..0000000
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- *
- * Copyright 2016 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_H
-#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_H
-
-#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
-
-/** Returns a load balancing factory for the glb policy, which tries to connect
- * to a load balancing server to decide the next successfully connected
- * subchannel to pick. */
-grpc_lb_policy_factory* grpc_glb_lb_factory_create();
-
-#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_H */
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.cc
index 1e7f34b..fd873f0 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.cc
@@ -16,56 +16,11 @@
  *
  */
 
-#include <grpc/support/alloc.h>
-#include <grpc/support/string_util.h>
+#include <grpc/support/port_platform.h>
 
-#include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h"
-#include "src/core/lib/channel/channel_args.h"
-#include "src/core/lib/gpr/string.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
 
-grpc_channel* grpc_lb_policy_grpclb_create_lb_channel(
-    const char* lb_service_target_addresses,
-    grpc_client_channel_factory* client_channel_factory,
+grpc_channel_args* grpc_lb_policy_grpclb_modify_lb_channel_args(
     grpc_channel_args* args) {
-  grpc_channel* lb_channel = grpc_client_channel_factory_create_channel(
-      client_channel_factory, lb_service_target_addresses,
-      GRPC_CLIENT_CHANNEL_TYPE_LOAD_BALANCING, args);
-  return lb_channel;
-}
-
-grpc_channel_args* grpc_lb_policy_grpclb_build_lb_channel_args(
-    grpc_slice_hash_table* targets_info,
-    grpc_fake_resolver_response_generator* response_generator,
-    const grpc_channel_args* args) {
-  const grpc_arg to_add[] = {
-      grpc_fake_resolver_response_generator_arg(response_generator)};
-  /* We remove:
-   *
-   * - The channel arg for the LB policy name, since we want to use the default
-   *   (pick_first) in this case.
-   *
-   * - The channel arg for the resolved addresses, since that will be generated
-   *   by the name resolver used in the LB channel.  Note that the LB channel
-   *   will use the fake resolver, so this won't actually generate a query
-   *   to DNS (or some other name service).  However, the addresses returned by
-   *   the fake resolver will have is_balancer=false, whereas our own
-   *   addresses have is_balancer=true.  We need the LB channel to return
-   *   addresses with is_balancer=false so that it does not wind up recursively
-   *   using the grpclb LB policy, as per the special case logic in
-   *   client_channel.c.
-   *
-   * - The channel arg for the server URI, since that will be different for the
-   *   LB channel than for the parent channel (the client channel factory will
-   *   re-add this arg with the right value).
-   *
-   * - The fake resolver generator, because we are replacing it with the one
-   *   from the grpclb policy, used to propagate updates to the LB channel. */
-  static const char* keys_to_remove[] = {
-      GRPC_ARG_LB_POLICY_NAME, GRPC_ARG_LB_ADDRESSES, GRPC_ARG_SERVER_URI,
-      GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR};
-  return grpc_channel_args_copy_and_add_and_remove(
-      args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), to_add,
-      GPR_ARRAY_SIZE(to_add));
+  return args;
 }
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
index 56104b2..825065a 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
@@ -19,26 +19,18 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_CHANNEL_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_CHANNEL_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/lb_policy_factory.h"
-#include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
-#include "src/core/lib/slice/slice_hash_table.h"
 
-/** Create the channel used for communicating with an LB service.
- * Note that an LB *service* may be comprised of several LB *servers*.
- *
- * \a lb_service_target_addresses is the target URI containing the addresses
- * from resolving the LB service's name (eg, ipv4:10.0.0.1:1234,10.2.3.4:9876).
- * \a client_channel_factory will be used for the creation of the LB channel,
- * alongside the channel args passed in \a args. */
-grpc_channel* grpc_lb_policy_grpclb_create_lb_channel(
-    const char* lb_service_target_addresses,
-    grpc_client_channel_factory* client_channel_factory,
+/// Makes any necessary modifications to \a args for use in the grpclb
+/// balancer channel.
+///
+/// Takes ownership of \a args.
+///
+/// Caller takes ownership of the returned args.
+grpc_channel_args* grpc_lb_policy_grpclb_modify_lb_channel_args(
     grpc_channel_args* args);
 
-grpc_channel_args* grpc_lb_policy_grpclb_build_lb_channel_args(
-    grpc_slice_hash_table* targets_info,
-    grpc_fake_resolver_response_generator* response_generator,
-    const grpc_channel_args* args);
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_CHANNEL_H \
         */
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc
index 15233d3..441efd5 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc
@@ -16,84 +16,93 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
+#include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h"
+
+#include <string.h>
+
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
 
 #include "src/core/ext/filters/client_channel/client_channel.h"
-#include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/security/credentials/credentials.h"
-#include "src/core/lib/security/transport/lb_targets_info.h"
+#include "src/core/lib/security/transport/target_authority_table.h"
 #include "src/core/lib/slice/slice_internal.h"
 
-grpc_channel* grpc_lb_policy_grpclb_create_lb_channel(
-    const char* lb_service_target_addresses,
-    grpc_client_channel_factory* client_channel_factory,
+namespace grpc_core {
+namespace {
+
+int BalancerNameCmp(const grpc_core::UniquePtr<char>& a,
+                    const grpc_core::UniquePtr<char>& b) {
+  return strcmp(a.get(), b.get());
+}
+
+RefCountedPtr<TargetAuthorityTable> CreateTargetAuthorityTable(
+    grpc_lb_addresses* addresses) {
+  TargetAuthorityTable::Entry* target_authority_entries =
+      static_cast<TargetAuthorityTable::Entry*>(gpr_zalloc(
+          sizeof(*target_authority_entries) * addresses->num_addresses));
+  for (size_t i = 0; i < addresses->num_addresses; ++i) {
+    char* addr_str;
+    GPR_ASSERT(grpc_sockaddr_to_string(
+                   &addr_str, &addresses->addresses[i].address, true) > 0);
+    target_authority_entries[i].key = grpc_slice_from_copied_string(addr_str);
+    target_authority_entries[i].value.reset(
+        gpr_strdup(addresses->addresses[i].balancer_name));
+    gpr_free(addr_str);
+  }
+  RefCountedPtr<TargetAuthorityTable> target_authority_table =
+      TargetAuthorityTable::Create(addresses->num_addresses,
+                                   target_authority_entries, BalancerNameCmp);
+  gpr_free(target_authority_entries);
+  return target_authority_table;
+}
+
+}  // namespace
+}  // namespace grpc_core
+
+grpc_channel_args* grpc_lb_policy_grpclb_modify_lb_channel_args(
     grpc_channel_args* args) {
-  grpc_channel_args* new_args = args;
+  const char* args_to_remove[1];
+  size_t num_args_to_remove = 0;
+  grpc_arg args_to_add[2];
+  size_t num_args_to_add = 0;
+  // Add arg for targets info table.
+  const grpc_arg* arg = grpc_channel_args_find(args, GRPC_ARG_LB_ADDRESSES);
+  GPR_ASSERT(arg != nullptr);
+  GPR_ASSERT(arg->type == GRPC_ARG_POINTER);
+  grpc_lb_addresses* addresses =
+      static_cast<grpc_lb_addresses*>(arg->value.pointer.p);
+  grpc_core::RefCountedPtr<grpc_core::TargetAuthorityTable>
+      target_authority_table = grpc_core::CreateTargetAuthorityTable(addresses);
+  args_to_add[num_args_to_add++] =
+      grpc_core::CreateTargetAuthorityTableChannelArg(
+          target_authority_table.get());
+  // Substitute the channel credentials with a version without call
+  // credentials: the load balancer is not necessarily trusted to handle
+  // bearer token credentials.
   grpc_channel_credentials* channel_credentials =
       grpc_channel_credentials_find_in_args(args);
+  grpc_channel_credentials* creds_sans_call_creds = nullptr;
   if (channel_credentials != nullptr) {
-    /* Substitute the channel credentials with a version without call
-     * credentials: the load balancer is not necessarily trusted to handle
-     * bearer token credentials */
-    static const char* keys_to_remove[] = {GRPC_ARG_CHANNEL_CREDENTIALS};
-    grpc_channel_credentials* creds_sans_call_creds =
+    creds_sans_call_creds =
         grpc_channel_credentials_duplicate_without_call_credentials(
             channel_credentials);
     GPR_ASSERT(creds_sans_call_creds != nullptr);
-    grpc_arg args_to_add[] = {
-        grpc_channel_credentials_to_arg(creds_sans_call_creds)};
-    /* Create the new set of channel args */
-    new_args = grpc_channel_args_copy_and_add_and_remove(
-        args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), args_to_add,
-        GPR_ARRAY_SIZE(args_to_add));
+    args_to_remove[num_args_to_remove++] = GRPC_ARG_CHANNEL_CREDENTIALS;
+    args_to_add[num_args_to_add++] =
+        grpc_channel_credentials_to_arg(creds_sans_call_creds);
+  }
+  grpc_channel_args* result = grpc_channel_args_copy_and_add_and_remove(
+      args, args_to_remove, num_args_to_remove, args_to_add, num_args_to_add);
+  // Clean up.
+  grpc_channel_args_destroy(args);
+  if (creds_sans_call_creds != nullptr) {
     grpc_channel_credentials_unref(creds_sans_call_creds);
   }
-  grpc_channel* lb_channel = grpc_client_channel_factory_create_channel(
-      client_channel_factory, lb_service_target_addresses,
-      GRPC_CLIENT_CHANNEL_TYPE_LOAD_BALANCING, new_args);
-  if (channel_credentials != nullptr) {
-    grpc_channel_args_destroy(new_args);
-  }
-  return lb_channel;
-}
-
-grpc_channel_args* grpc_lb_policy_grpclb_build_lb_channel_args(
-    grpc_slice_hash_table* targets_info,
-    grpc_fake_resolver_response_generator* response_generator,
-    const grpc_channel_args* args) {
-  const grpc_arg to_add[] = {
-      grpc_lb_targets_info_create_channel_arg(targets_info),
-      grpc_fake_resolver_response_generator_arg(response_generator)};
-  /* We remove:
-   *
-   * - The channel arg for the LB policy name, since we want to use the default
-   *   (pick_first) in this case.
-   *
-   * - The channel arg for the resolved addresses, since that will be generated
-   *   by the name resolver used in the LB channel.  Note that the LB channel
-   *   will use the fake resolver, so this won't actually generate a query
-   *   to DNS (or some other name service).  However, the addresses returned by
-   *   the fake resolver will have is_balancer=false, whereas our own
-   *   addresses have is_balancer=true.  We need the LB channel to return
-   *   addresses with is_balancer=false so that it does not wind up recursively
-   *   using the grpclb LB policy, as per the special case logic in
-   *   client_channel.c.
-   *
-   * - The channel arg for the server URI, since that will be different for the
-   *   LB channel than for the parent channel (the client channel factory will
-   *   re-add this arg with the right value).
-   *
-   * - The fake resolver generator, because we are replacing it with the one
-   *   from the grpclb policy, used to propagate updates to the LB channel. */
-  static const char* keys_to_remove[] = {
-      GRPC_ARG_LB_POLICY_NAME, GRPC_ARG_LB_ADDRESSES, GRPC_ARG_SERVER_URI,
-      GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR};
-  /* Add the targets info table to be used for secure naming */
-  return grpc_channel_args_copy_and_add_and_remove(
-      args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), to_add,
-      GPR_ARRAY_SIZE(to_add));
+  return result;
 }
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc
index e19a6a7..dfbaead 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h"
 
 #include <string.h>
@@ -24,7 +26,6 @@
 #include <grpc/support/atm.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/channel/channel_args.h"
 
@@ -43,7 +44,7 @@
 
 grpc_grpclb_client_stats* grpc_grpclb_client_stats_create() {
   grpc_grpclb_client_stats* client_stats =
-      (grpc_grpclb_client_stats*)gpr_zalloc(sizeof(*client_stats));
+      static_cast<grpc_grpclb_client_stats*>(gpr_zalloc(sizeof(*client_stats)));
   gpr_ref_init(&client_stats->refs, 1);
   return client_stats;
 }
@@ -89,8 +90,8 @@
   // Record the drop.
   if (client_stats->drop_token_counts == nullptr) {
     client_stats->drop_token_counts =
-        (grpc_grpclb_dropped_call_counts*)gpr_zalloc(
-            sizeof(grpc_grpclb_dropped_call_counts));
+        static_cast<grpc_grpclb_dropped_call_counts*>(
+            gpr_zalloc(sizeof(grpc_grpclb_dropped_call_counts)));
   }
   grpc_grpclb_dropped_call_counts* drop_token_counts =
       client_stats->drop_token_counts;
@@ -105,9 +106,9 @@
   while (new_num_entries < drop_token_counts->num_entries + 1) {
     new_num_entries *= 2;
   }
-  drop_token_counts->token_counts = (grpc_grpclb_drop_token_count*)gpr_realloc(
-      drop_token_counts->token_counts,
-      new_num_entries * sizeof(grpc_grpclb_drop_token_count));
+  drop_token_counts->token_counts = static_cast<grpc_grpclb_drop_token_count*>(
+      gpr_realloc(drop_token_counts->token_counts,
+                  new_num_entries * sizeof(grpc_grpclb_drop_token_count)));
   grpc_grpclb_drop_token_count* new_entry =
       &drop_token_counts->token_counts[drop_token_counts->num_entries++];
   new_entry->token = gpr_strdup(token);
@@ -115,7 +116,7 @@
 }
 
 static void atomic_get_and_reset_counter(int64_t* value, gpr_atm* counter) {
-  *value = (int64_t)gpr_atm_acq_load(counter);
+  *value = static_cast<int64_t>(gpr_atm_acq_load(counter));
   gpr_atm_full_fetch_add(counter, (gpr_atm)(-*value));
 }
 
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h
index d4b9d06..c971e56 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_CLIENT_STATS_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_CLIENT_STATS_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stdbool.h>
 
 #include <grpc/impl/codegen/grpc_types.h>
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
index fc781da..7ef3bcf 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h"
 #include "third_party/nanopb/pb_decode.h"
 #include "third_party/nanopb/pb_encode.h"
@@ -25,7 +27,7 @@
 /* invoked once for every Server in ServerList */
 static bool count_serverlist(pb_istream_t* stream, const pb_field_t* field,
                              void** arg) {
-  grpc_grpclb_serverlist* sl = (grpc_grpclb_serverlist*)*arg;
+  grpc_grpclb_serverlist* sl = static_cast<grpc_grpclb_serverlist*>(*arg);
   grpc_grpclb_server server;
   if (!pb_decode(stream, grpc_lb_v1_Server_fields, &server)) {
     gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(stream));
@@ -46,10 +48,10 @@
 /* invoked once for every Server in ServerList */
 static bool decode_serverlist(pb_istream_t* stream, const pb_field_t* field,
                               void** arg) {
-  decode_serverlist_arg* dec_arg = (decode_serverlist_arg*)*arg;
+  decode_serverlist_arg* dec_arg = static_cast<decode_serverlist_arg*>(*arg);
   GPR_ASSERT(dec_arg->serverlist->num_servers >= dec_arg->decoding_idx);
   grpc_grpclb_server* server =
-      (grpc_grpclb_server*)gpr_zalloc(sizeof(grpc_grpclb_server));
+      static_cast<grpc_grpclb_server*>(gpr_zalloc(sizeof(grpc_grpclb_server)));
   if (!pb_decode(stream, grpc_lb_v1_Server_fields, server)) {
     gpr_free(server);
     gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(stream));
@@ -60,8 +62,8 @@
 }
 
 grpc_grpclb_request* grpc_grpclb_request_create(const char* lb_service_name) {
-  grpc_grpclb_request* req =
-      (grpc_grpclb_request*)gpr_malloc(sizeof(grpc_grpclb_request));
+  grpc_grpclb_request* req = static_cast<grpc_grpclb_request*>(
+      gpr_malloc(sizeof(grpc_grpclb_request)));
   req->has_client_stats = false;
   req->has_initial_request = true;
   req->initial_request.has_name = true;
@@ -80,15 +82,15 @@
 
 static bool encode_string(pb_ostream_t* stream, const pb_field_t* field,
                           void* const* arg) {
-  char* str = (char*)*arg;
+  char* str = static_cast<char*>(*arg);
   if (!pb_encode_tag_for_field(stream, field)) return false;
-  return pb_encode_string(stream, (uint8_t*)str, strlen(str));
+  return pb_encode_string(stream, reinterpret_cast<uint8_t*>(str), strlen(str));
 }
 
 static bool encode_drops(pb_ostream_t* stream, const pb_field_t* field,
                          void* const* arg) {
   grpc_grpclb_dropped_call_counts* drop_entries =
-      (grpc_grpclb_dropped_call_counts*)*arg;
+      static_cast<grpc_grpclb_dropped_call_counts*>(*arg);
   if (drop_entries == nullptr) return true;
   for (size_t i = 0; i < drop_entries->num_entries; ++i) {
     if (!pb_encode_tag_for_field(stream, field)) return false;
@@ -107,8 +109,8 @@
 
 grpc_grpclb_request* grpc_grpclb_load_report_request_create_locked(
     grpc_grpclb_client_stats* client_stats) {
-  grpc_grpclb_request* req =
-      (grpc_grpclb_request*)gpr_zalloc(sizeof(grpc_grpclb_request));
+  grpc_grpclb_request* req = static_cast<grpc_grpclb_request*>(
+      gpr_zalloc(sizeof(grpc_grpclb_request)));
   req->has_client_stats = true;
   req->client_stats.has_timestamp = true;
   populate_timestamp(gpr_now(GPR_CLOCK_REALTIME), &req->client_stats.timestamp);
@@ -123,8 +125,8 @@
       &req->client_stats.num_calls_finished,
       &req->client_stats.num_calls_finished_with_client_failed_to_send,
       &req->client_stats.num_calls_finished_known_received,
-      (grpc_grpclb_dropped_call_counts**)&req->client_stats
-          .calls_finished_with_drop.arg);
+      reinterpret_cast<grpc_grpclb_dropped_call_counts**>(
+          &req->client_stats.calls_finished_with_drop.arg));
   return req;
 }
 
@@ -148,8 +150,8 @@
 void grpc_grpclb_request_destroy(grpc_grpclb_request* request) {
   if (request->has_client_stats) {
     grpc_grpclb_dropped_call_counts* drop_entries =
-        (grpc_grpclb_dropped_call_counts*)
-            request->client_stats.calls_finished_with_drop.arg;
+        static_cast<grpc_grpclb_dropped_call_counts*>(
+            request->client_stats.calls_finished_with_drop.arg);
     grpc_grpclb_dropped_call_counts_destroy(drop_entries);
   }
   gpr_free(request);
@@ -171,8 +173,8 @@
   if (!res.has_initial_response) return nullptr;
 
   grpc_grpclb_initial_response* initial_res =
-      (grpc_grpclb_initial_response*)gpr_malloc(
-          sizeof(grpc_grpclb_initial_response));
+      static_cast<grpc_grpclb_initial_response*>(
+          gpr_malloc(sizeof(grpc_grpclb_initial_response)));
   memcpy(initial_res, &res.initial_response,
          sizeof(grpc_grpclb_initial_response));
 
@@ -185,8 +187,8 @@
       pb_istream_from_buffer(GRPC_SLICE_START_PTR(encoded_grpc_grpclb_response),
                              GRPC_SLICE_LENGTH(encoded_grpc_grpclb_response));
   pb_istream_t stream_at_start = stream;
-  grpc_grpclb_serverlist* sl =
-      (grpc_grpclb_serverlist*)gpr_zalloc(sizeof(grpc_grpclb_serverlist));
+  grpc_grpclb_serverlist* sl = static_cast<grpc_grpclb_serverlist*>(
+      gpr_zalloc(sizeof(grpc_grpclb_serverlist)));
   grpc_grpclb_response res;
   memset(&res, 0, sizeof(grpc_grpclb_response));
   // First pass: count number of servers.
@@ -200,8 +202,8 @@
   }
   // Second pass: populate servers.
   if (sl->num_servers > 0) {
-    sl->servers = (grpc_grpclb_server**)gpr_zalloc(sizeof(grpc_grpclb_server*) *
-                                                   sl->num_servers);
+    sl->servers = static_cast<grpc_grpclb_server**>(
+        gpr_zalloc(sizeof(grpc_grpclb_server*) * sl->num_servers));
     decode_serverlist_arg decode_arg;
     memset(&decode_arg, 0, sizeof(decode_arg));
     decode_arg.serverlist = sl;
@@ -231,14 +233,14 @@
 
 grpc_grpclb_serverlist* grpc_grpclb_serverlist_copy(
     const grpc_grpclb_serverlist* sl) {
-  grpc_grpclb_serverlist* copy =
-      (grpc_grpclb_serverlist*)gpr_zalloc(sizeof(grpc_grpclb_serverlist));
+  grpc_grpclb_serverlist* copy = static_cast<grpc_grpclb_serverlist*>(
+      gpr_zalloc(sizeof(grpc_grpclb_serverlist)));
   copy->num_servers = sl->num_servers;
-  copy->servers = (grpc_grpclb_server**)gpr_malloc(sizeof(grpc_grpclb_server*) *
-                                                   sl->num_servers);
+  copy->servers = static_cast<grpc_grpclb_server**>(
+      gpr_malloc(sizeof(grpc_grpclb_server*) * sl->num_servers));
   for (size_t i = 0; i < sl->num_servers; i++) {
-    copy->servers[i] =
-        (grpc_grpclb_server*)gpr_malloc(sizeof(grpc_grpclb_server));
+    copy->servers[i] = static_cast<grpc_grpclb_server*>(
+        gpr_malloc(sizeof(grpc_grpclb_server)));
     memcpy(copy->servers[i], sl->servers[i], sizeof(grpc_grpclb_server));
   }
   return copy;
@@ -291,7 +293,7 @@
 }
 
 grpc_millis grpc_grpclb_duration_to_millis(grpc_grpclb_duration* duration_pb) {
-  return (grpc_millis)(
+  return static_cast<grpc_millis>(
       (duration_pb->has_seconds ? duration_pb->seconds : 0) * GPR_MS_PER_SEC +
       (duration_pb->has_nanos ? duration_pb->nanos : 0) / GPR_NS_PER_MS);
 }
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
index ccb0212..d4270f2 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_LOAD_BALANCER_API_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_LOAD_BALANCER_API_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice_buffer.h>
 
 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h"
diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
index 725b78d..9090c34 100644
--- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <string.h>
 
 #include <grpc/support/alloc.h>
@@ -29,194 +31,225 @@
 #include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/transport/connectivity_state.h"
 
-grpc_core::TraceFlag grpc_lb_pick_first_trace(false, "pick_first");
+namespace grpc_core {
 
-typedef struct {
-  /** base policy: must be first */
-  grpc_lb_policy base;
+TraceFlag grpc_lb_pick_first_trace(false, "pick_first");
+
+namespace {
+
+//
+// pick_first LB policy
+//
+
+class PickFirst : public LoadBalancingPolicy {
+ public:
+  explicit PickFirst(const Args& args);
+
+  void UpdateLocked(const grpc_channel_args& args) override;
+  bool PickLocked(PickState* pick) override;
+  void CancelPickLocked(PickState* pick, grpc_error* error) override;
+  void CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask,
+                                 uint32_t initial_metadata_flags_eq,
+                                 grpc_error* error) override;
+  void NotifyOnStateChangeLocked(grpc_connectivity_state* state,
+                                 grpc_closure* closure) override;
+  grpc_connectivity_state CheckConnectivityLocked(
+      grpc_error** connectivity_error) override;
+  void HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) override;
+  void PingOneLocked(grpc_closure* on_initiate, grpc_closure* on_ack) override;
+  void ExitIdleLocked() override;
+
+ private:
+  ~PickFirst();
+
+  void ShutdownLocked() override;
+
+  void StartPickingLocked();
+  void DestroyUnselectedSubchannelsLocked();
+
+  static void OnConnectivityChangedLocked(void* arg, grpc_error* error);
+
+  void SubchannelListRefForConnectivityWatch(
+      grpc_lb_subchannel_list* subchannel_list, const char* reason);
+  void SubchannelListUnrefForConnectivityWatch(
+      grpc_lb_subchannel_list* subchannel_list, const char* reason);
+
   /** all our subchannels */
-  grpc_lb_subchannel_list* subchannel_list;
+  grpc_lb_subchannel_list* subchannel_list_ = nullptr;
   /** latest pending subchannel list */
-  grpc_lb_subchannel_list* latest_pending_subchannel_list;
+  grpc_lb_subchannel_list* latest_pending_subchannel_list_ = nullptr;
   /** selected subchannel in \a subchannel_list */
-  grpc_lb_subchannel_data* selected;
+  grpc_lb_subchannel_data* selected_ = nullptr;
   /** have we started picking? */
-  bool started_picking;
+  bool started_picking_ = false;
   /** are we shut down? */
-  bool shutdown;
+  bool shutdown_ = false;
   /** list of picks that are waiting on connectivity */
-  grpc_lb_policy_pick_state* pending_picks;
+  PickState* pending_picks_ = nullptr;
   /** our connectivity state tracker */
-  grpc_connectivity_state_tracker state_tracker;
-} pick_first_lb_policy;
+  grpc_connectivity_state_tracker state_tracker_;
+};
 
-static void pf_destroy(grpc_lb_policy* pol) {
-  pick_first_lb_policy* p = (pick_first_lb_policy*)pol;
-  GPR_ASSERT(p->subchannel_list == nullptr);
-  GPR_ASSERT(p->latest_pending_subchannel_list == nullptr);
-  GPR_ASSERT(p->pending_picks == nullptr);
-  grpc_connectivity_state_destroy(&p->state_tracker);
-  gpr_free(p);
-  grpc_subchannel_index_unref();
+PickFirst::PickFirst(const Args& args) : LoadBalancingPolicy(args) {
+  GPR_ASSERT(args.client_channel_factory != nullptr);
+  grpc_connectivity_state_init(&state_tracker_, GRPC_CHANNEL_IDLE,
+                               "pick_first");
   if (grpc_lb_pick_first_trace.enabled()) {
-    gpr_log(GPR_DEBUG, "Pick First %p destroyed.", (void*)p);
+    gpr_log(GPR_DEBUG, "Pick First %p created.", this);
+  }
+  UpdateLocked(*args.args);
+  grpc_subchannel_index_ref();
+}
+
+PickFirst::~PickFirst() {
+  if (grpc_lb_pick_first_trace.enabled()) {
+    gpr_log(GPR_DEBUG, "Destroying Pick First %p", this);
+  }
+  GPR_ASSERT(subchannel_list_ == nullptr);
+  GPR_ASSERT(latest_pending_subchannel_list_ == nullptr);
+  GPR_ASSERT(pending_picks_ == nullptr);
+  grpc_connectivity_state_destroy(&state_tracker_);
+  grpc_subchannel_index_unref();
+}
+
+void PickFirst::HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) {
+  PickState* pick;
+  while ((pick = pending_picks_) != nullptr) {
+    pending_picks_ = pick->next;
+    if (new_policy->PickLocked(pick)) {
+      // Synchronous return, schedule closure.
+      GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_NONE);
+    }
   }
 }
 
-static void pf_shutdown_locked(grpc_lb_policy* pol,
-                               grpc_lb_policy* new_policy) {
-  pick_first_lb_policy* p = (pick_first_lb_policy*)pol;
+void PickFirst::ShutdownLocked() {
   grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel shutdown");
   if (grpc_lb_pick_first_trace.enabled()) {
-    gpr_log(GPR_DEBUG, "Pick First %p Shutting down", p);
+    gpr_log(GPR_DEBUG, "Pick First %p Shutting down", this);
   }
-  p->shutdown = true;
-  grpc_lb_policy_pick_state* pick;
-  while ((pick = p->pending_picks) != nullptr) {
-    p->pending_picks = pick->next;
-    if (new_policy != nullptr) {
-      // Hand off to new LB policy.
-      if (grpc_lb_policy_pick_locked(new_policy, pick)) {
-        // Synchronous return, schedule closure.
-        GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_NONE);
-      }
-    } else {
-      pick->connected_subchannel.reset();
-      GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_REF(error));
-    }
+  shutdown_ = true;
+  PickState* pick;
+  while ((pick = pending_picks_) != nullptr) {
+    pending_picks_ = pick->next;
+    pick->connected_subchannel.reset();
+    GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_REF(error));
   }
-  grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
+  grpc_connectivity_state_set(&state_tracker_, GRPC_CHANNEL_SHUTDOWN,
                               GRPC_ERROR_REF(error), "shutdown");
-  if (p->subchannel_list != nullptr) {
-    grpc_lb_subchannel_list_shutdown_and_unref(p->subchannel_list,
+  if (subchannel_list_ != nullptr) {
+    grpc_lb_subchannel_list_shutdown_and_unref(subchannel_list_, "pf_shutdown");
+    subchannel_list_ = nullptr;
+  }
+  if (latest_pending_subchannel_list_ != nullptr) {
+    grpc_lb_subchannel_list_shutdown_and_unref(latest_pending_subchannel_list_,
                                                "pf_shutdown");
-    p->subchannel_list = nullptr;
+    latest_pending_subchannel_list_ = nullptr;
   }
-  if (p->latest_pending_subchannel_list != nullptr) {
-    grpc_lb_subchannel_list_shutdown_and_unref(
-        p->latest_pending_subchannel_list, "pf_shutdown");
-    p->latest_pending_subchannel_list = nullptr;
-  }
-  grpc_lb_policy_try_reresolve(&p->base, &grpc_lb_pick_first_trace,
-                               GRPC_ERROR_CANCELLED);
+  TryReresolutionLocked(&grpc_lb_pick_first_trace, GRPC_ERROR_CANCELLED);
   GRPC_ERROR_UNREF(error);
 }
 
-static void pf_cancel_pick_locked(grpc_lb_policy* pol,
-                                  grpc_lb_policy_pick_state* pick,
-                                  grpc_error* error) {
-  pick_first_lb_policy* p = (pick_first_lb_policy*)pol;
-  grpc_lb_policy_pick_state* pp = p->pending_picks;
-  p->pending_picks = nullptr;
+void PickFirst::CancelPickLocked(PickState* pick, grpc_error* error) {
+  PickState* pp = pending_picks_;
+  pending_picks_ = nullptr;
   while (pp != nullptr) {
-    grpc_lb_policy_pick_state* next = pp->next;
+    PickState* next = pp->next;
     if (pp == pick) {
       pick->connected_subchannel.reset();
       GRPC_CLOSURE_SCHED(pick->on_complete,
                          GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                              "Pick Cancelled", &error, 1));
     } else {
-      pp->next = p->pending_picks;
-      p->pending_picks = pp;
+      pp->next = pending_picks_;
+      pending_picks_ = pp;
     }
     pp = next;
   }
   GRPC_ERROR_UNREF(error);
 }
 
-static void pf_cancel_picks_locked(grpc_lb_policy* pol,
-                                   uint32_t initial_metadata_flags_mask,
-                                   uint32_t initial_metadata_flags_eq,
-                                   grpc_error* error) {
-  pick_first_lb_policy* p = (pick_first_lb_policy*)pol;
-  grpc_lb_policy_pick_state* pick = p->pending_picks;
-  p->pending_picks = nullptr;
+void PickFirst::CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask,
+                                          uint32_t initial_metadata_flags_eq,
+                                          grpc_error* error) {
+  PickState* pick = pending_picks_;
+  pending_picks_ = nullptr;
   while (pick != nullptr) {
-    grpc_lb_policy_pick_state* next = pick->next;
+    PickState* next = pick->next;
     if ((pick->initial_metadata_flags & initial_metadata_flags_mask) ==
         initial_metadata_flags_eq) {
       GRPC_CLOSURE_SCHED(pick->on_complete,
                          GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                              "Pick Cancelled", &error, 1));
     } else {
-      pick->next = p->pending_picks;
-      p->pending_picks = pick;
+      pick->next = pending_picks_;
+      pending_picks_ = pick;
     }
     pick = next;
   }
   GRPC_ERROR_UNREF(error);
 }
 
-static void start_picking_locked(pick_first_lb_policy* p) {
-  p->started_picking = true;
-  if (p->subchannel_list != nullptr &&
-      p->subchannel_list->num_subchannels > 0) {
-    p->subchannel_list->checking_subchannel = 0;
-    for (size_t i = 0; i < p->subchannel_list->num_subchannels; ++i) {
-      if (p->subchannel_list->subchannels[i].subchannel != nullptr) {
-        grpc_lb_subchannel_list_ref_for_connectivity_watch(
-            p->subchannel_list, "connectivity_watch+start_picking");
+void PickFirst::StartPickingLocked() {
+  started_picking_ = true;
+  if (subchannel_list_ != nullptr && subchannel_list_->num_subchannels > 0) {
+    subchannel_list_->checking_subchannel = 0;
+    for (size_t i = 0; i < subchannel_list_->num_subchannels; ++i) {
+      if (subchannel_list_->subchannels[i].subchannel != nullptr) {
+        SubchannelListRefForConnectivityWatch(
+            subchannel_list_, "connectivity_watch+start_picking");
         grpc_lb_subchannel_data_start_connectivity_watch(
-            &p->subchannel_list->subchannels[i]);
+            &subchannel_list_->subchannels[i]);
         break;
       }
     }
   }
 }
 
-static void pf_exit_idle_locked(grpc_lb_policy* pol) {
-  pick_first_lb_policy* p = (pick_first_lb_policy*)pol;
-  if (!p->started_picking) {
-    start_picking_locked(p);
+void PickFirst::ExitIdleLocked() {
+  if (!started_picking_) {
+    StartPickingLocked();
   }
 }
 
-static int pf_pick_locked(grpc_lb_policy* pol,
-                          grpc_lb_policy_pick_state* pick) {
-  pick_first_lb_policy* p = (pick_first_lb_policy*)pol;
+bool PickFirst::PickLocked(PickState* pick) {
   // If we have a selected subchannel already, return synchronously.
-  if (p->selected != nullptr) {
-    pick->connected_subchannel = p->selected->connected_subchannel;
-    return 1;
+  if (selected_ != nullptr) {
+    pick->connected_subchannel = selected_->connected_subchannel;
+    return true;
   }
   // No subchannel selected yet, so handle asynchronously.
-  if (!p->started_picking) {
-    start_picking_locked(p);
+  if (!started_picking_) {
+    StartPickingLocked();
   }
-  pick->next = p->pending_picks;
-  p->pending_picks = pick;
-  return 0;
+  pick->next = pending_picks_;
+  pending_picks_ = pick;
+  return false;
 }
 
-static void destroy_unselected_subchannels_locked(pick_first_lb_policy* p) {
-  for (size_t i = 0; i < p->subchannel_list->num_subchannels; ++i) {
-    grpc_lb_subchannel_data* sd = &p->subchannel_list->subchannels[i];
-    if (p->selected != sd) {
+void PickFirst::DestroyUnselectedSubchannelsLocked() {
+  for (size_t i = 0; i < subchannel_list_->num_subchannels; ++i) {
+    grpc_lb_subchannel_data* sd = &subchannel_list_->subchannels[i];
+    if (selected_ != sd) {
       grpc_lb_subchannel_data_unref_subchannel(sd,
                                                "selected_different_subchannel");
     }
   }
 }
 
-static grpc_connectivity_state pf_check_connectivity_locked(
-    grpc_lb_policy* pol, grpc_error** error) {
-  pick_first_lb_policy* p = (pick_first_lb_policy*)pol;
-  return grpc_connectivity_state_get(&p->state_tracker, error);
+grpc_connectivity_state PickFirst::CheckConnectivityLocked(grpc_error** error) {
+  return grpc_connectivity_state_get(&state_tracker_, error);
 }
 
-static void pf_notify_on_state_change_locked(grpc_lb_policy* pol,
-                                             grpc_connectivity_state* current,
-                                             grpc_closure* notify) {
-  pick_first_lb_policy* p = (pick_first_lb_policy*)pol;
-  grpc_connectivity_state_notify_on_state_change(&p->state_tracker, current,
+void PickFirst::NotifyOnStateChangeLocked(grpc_connectivity_state* current,
+                                          grpc_closure* notify) {
+  grpc_connectivity_state_notify_on_state_change(&state_tracker_, current,
                                                  notify);
 }
 
-static void pf_ping_one_locked(grpc_lb_policy* pol, grpc_closure* on_initiate,
-                               grpc_closure* on_ack) {
-  pick_first_lb_policy* p = (pick_first_lb_policy*)pol;
-  if (p->selected) {
-    p->selected->connected_subchannel->Ping(on_initiate, on_ack);
+void PickFirst::PingOneLocked(grpc_closure* on_initiate, grpc_closure* on_ack) {
+  if (selected_ != nullptr) {
+    selected_->connected_subchannel->Ping(on_initiate, on_ack);
   } else {
     GRPC_CLOSURE_SCHED(on_initiate,
                        GRPC_ERROR_CREATE_FROM_STATIC_STRING("Not connected"));
@@ -225,18 +258,31 @@
   }
 }
 
-static void pf_connectivity_changed_locked(void* arg, grpc_error* error);
+void PickFirst::SubchannelListRefForConnectivityWatch(
+    grpc_lb_subchannel_list* subchannel_list, const char* reason) {
+  // TODO(roth): We currently track this ref manually.  Once the new
+  // ClosureRef API is ready and the subchannel_list code has been
+  // converted to a C++ API, find a way to hold the RefCountedPtr<>
+  // somewhere (maybe in the subchannel_data object) instead of doing
+  // this manually.
+  auto self = Ref(DEBUG_LOCATION, reason);
+  self.release();
+  grpc_lb_subchannel_list_ref(subchannel_list, reason);
+}
 
-static void pf_update_locked(grpc_lb_policy* policy,
-                             const grpc_lb_policy_args* args) {
-  pick_first_lb_policy* p = (pick_first_lb_policy*)policy;
-  const grpc_arg* arg =
-      grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES);
+void PickFirst::SubchannelListUnrefForConnectivityWatch(
+    grpc_lb_subchannel_list* subchannel_list, const char* reason) {
+  Unref(DEBUG_LOCATION, reason);
+  grpc_lb_subchannel_list_unref(subchannel_list, reason);
+}
+
+void PickFirst::UpdateLocked(const grpc_channel_args& args) {
+  const grpc_arg* arg = grpc_channel_args_find(&args, GRPC_ARG_LB_ADDRESSES);
   if (arg == nullptr || arg->type != GRPC_ARG_POINTER) {
-    if (p->subchannel_list == nullptr) {
+    if (subchannel_list_ == nullptr) {
       // If we don't have a current subchannel list, go into TRANSIENT FAILURE.
       grpc_connectivity_state_set(
-          &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
+          &state_tracker_, GRPC_CHANNEL_TRANSIENT_FAILURE,
           GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing update in args"),
           "pf_update_missing");
     } else {
@@ -244,77 +290,78 @@
       gpr_log(GPR_ERROR,
               "No valid LB addresses channel arg for Pick First %p update, "
               "ignoring.",
-              (void*)p);
+              this);
     }
     return;
   }
   const grpc_lb_addresses* addresses =
       (const grpc_lb_addresses*)arg->value.pointer.p;
   if (grpc_lb_pick_first_trace.enabled()) {
-    gpr_log(GPR_INFO, "Pick First %p received update with %lu addresses",
-            (void*)p, (unsigned long)addresses->num_addresses);
+    gpr_log(GPR_INFO,
+            "Pick First %p received update with %" PRIuPTR " addresses", this,
+            addresses->num_addresses);
   }
   grpc_lb_subchannel_list* subchannel_list = grpc_lb_subchannel_list_create(
-      &p->base, &grpc_lb_pick_first_trace, addresses, args,
-      pf_connectivity_changed_locked);
+      this, &grpc_lb_pick_first_trace, addresses, combiner(),
+      client_channel_factory(), args, &PickFirst::OnConnectivityChangedLocked);
   if (subchannel_list->num_subchannels == 0) {
     // Empty update or no valid subchannels. Unsubscribe from all current
     // subchannels and put the channel in TRANSIENT_FAILURE.
     grpc_connectivity_state_set(
-        &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
+        &state_tracker_, GRPC_CHANNEL_TRANSIENT_FAILURE,
         GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty update"),
         "pf_update_empty");
-    if (p->subchannel_list != nullptr) {
-      grpc_lb_subchannel_list_shutdown_and_unref(p->subchannel_list,
+    if (subchannel_list_ != nullptr) {
+      grpc_lb_subchannel_list_shutdown_and_unref(subchannel_list_,
                                                  "sl_shutdown_empty_update");
     }
-    p->subchannel_list = subchannel_list;  // Empty list.
-    p->selected = nullptr;
+    subchannel_list_ = subchannel_list;  // Empty list.
+    selected_ = nullptr;
     return;
   }
-  if (p->selected == nullptr) {
+  if (selected_ == nullptr) {
     // We don't yet have a selected subchannel, so replace the current
     // subchannel list immediately.
-    if (p->subchannel_list != nullptr) {
-      grpc_lb_subchannel_list_shutdown_and_unref(p->subchannel_list,
+    if (subchannel_list_ != nullptr) {
+      grpc_lb_subchannel_list_shutdown_and_unref(subchannel_list_,
                                                  "pf_update_before_selected");
     }
-    p->subchannel_list = subchannel_list;
+    subchannel_list_ = subchannel_list;
   } else {
     // We do have a selected subchannel.
     // Check if it's present in the new list.  If so, we're done.
     for (size_t i = 0; i < subchannel_list->num_subchannels; ++i) {
       grpc_lb_subchannel_data* sd = &subchannel_list->subchannels[i];
-      if (sd->subchannel == p->selected->subchannel) {
+      if (sd->subchannel == selected_->subchannel) {
         // The currently selected subchannel is in the update: we are done.
         if (grpc_lb_pick_first_trace.enabled()) {
           gpr_log(GPR_INFO,
                   "Pick First %p found already selected subchannel %p "
                   "at update index %" PRIuPTR " of %" PRIuPTR "; update done",
-                  p, p->selected->subchannel, i,
+                  this, selected_->subchannel, i,
                   subchannel_list->num_subchannels);
         }
-        if (p->selected->connected_subchannel != nullptr) {
-          sd->connected_subchannel = p->selected->connected_subchannel;
+        if (selected_->connected_subchannel != nullptr) {
+          sd->connected_subchannel = selected_->connected_subchannel;
         }
-        p->selected = sd;
-        if (p->subchannel_list != nullptr) {
+        selected_ = sd;
+        if (subchannel_list_ != nullptr) {
           grpc_lb_subchannel_list_shutdown_and_unref(
-              p->subchannel_list, "pf_update_includes_selected");
+              subchannel_list_, "pf_update_includes_selected");
         }
-        p->subchannel_list = subchannel_list;
-        destroy_unselected_subchannels_locked(p);
-        grpc_lb_subchannel_list_ref_for_connectivity_watch(
+        subchannel_list_ = subchannel_list;
+        DestroyUnselectedSubchannelsLocked();
+        SubchannelListRefForConnectivityWatch(
             subchannel_list, "connectivity_watch+replace_selected");
         grpc_lb_subchannel_data_start_connectivity_watch(sd);
         // If there was a previously pending update (which may or may
         // not have contained the currently selected subchannel), drop
         // it, so that it doesn't override what we've done here.
-        if (p->latest_pending_subchannel_list != nullptr) {
+        if (latest_pending_subchannel_list_ != nullptr) {
           grpc_lb_subchannel_list_shutdown_and_unref(
-              p->latest_pending_subchannel_list,
+              latest_pending_subchannel_list_,
               "pf_update_includes_selected+outdated");
-          p->latest_pending_subchannel_list = nullptr;
+          latest_pending_subchannel_list_ = nullptr;
         }
         return;
       }
@@ -323,83 +370,81 @@
     // pending subchannel list to the new subchannel list.  We will wait
     // for it to report READY before swapping it into the current
     // subchannel list.
-    if (p->latest_pending_subchannel_list != nullptr) {
+    if (latest_pending_subchannel_list_ != nullptr) {
       if (grpc_lb_pick_first_trace.enabled()) {
         gpr_log(GPR_DEBUG,
                 "Pick First %p Shutting down latest pending subchannel list "
                 "%p, about to be replaced by newer latest %p",
-                (void*)p, (void*)p->latest_pending_subchannel_list,
-                (void*)subchannel_list);
+                this, latest_pending_subchannel_list_, subchannel_list);
       }
       grpc_lb_subchannel_list_shutdown_and_unref(
-          p->latest_pending_subchannel_list, "sl_outdated_dont_smash");
+          latest_pending_subchannel_list_, "sl_outdated_dont_smash");
     }
-    p->latest_pending_subchannel_list = subchannel_list;
+    latest_pending_subchannel_list_ = subchannel_list;
   }
   // If we've started picking, start trying to connect to the first
   // subchannel in the new list.
-  if (p->started_picking) {
-    grpc_lb_subchannel_list_ref_for_connectivity_watch(
-        subchannel_list, "connectivity_watch+update");
+  if (started_picking_) {
+    SubchannelListRefForConnectivityWatch(subchannel_list,
+                                          "connectivity_watch+update");
     grpc_lb_subchannel_data_start_connectivity_watch(
         &subchannel_list->subchannels[0]);
   }
 }
 
-static void pf_connectivity_changed_locked(void* arg, grpc_error* error) {
-  grpc_lb_subchannel_data* sd = (grpc_lb_subchannel_data*)arg;
-  pick_first_lb_policy* p = (pick_first_lb_policy*)sd->subchannel_list->policy;
+void PickFirst::OnConnectivityChangedLocked(void* arg, grpc_error* error) {
+  grpc_lb_subchannel_data* sd = static_cast<grpc_lb_subchannel_data*>(arg);
+  PickFirst* p = static_cast<PickFirst*>(sd->subchannel_list->policy);
   if (grpc_lb_pick_first_trace.enabled()) {
     gpr_log(GPR_DEBUG,
             "Pick First %p connectivity changed for subchannel %p (%" PRIuPTR
             " of %" PRIuPTR
-            "), subchannel_list %p: state=%s p->shutdown=%d "
+            "), subchannel_list %p: state=%s p->shutdown_=%d "
             "sd->subchannel_list->shutting_down=%d error=%s",
-            (void*)p, (void*)sd->subchannel,
-            sd->subchannel_list->checking_subchannel,
-            sd->subchannel_list->num_subchannels, (void*)sd->subchannel_list,
+            p, sd->subchannel, sd->subchannel_list->checking_subchannel,
+            sd->subchannel_list->num_subchannels, sd->subchannel_list,
             grpc_connectivity_state_name(sd->pending_connectivity_state_unsafe),
-            p->shutdown, sd->subchannel_list->shutting_down,
+            p->shutdown_, sd->subchannel_list->shutting_down,
             grpc_error_string(error));
   }
   // If the policy is shutting down, unref and return.
-  if (p->shutdown) {
+  if (p->shutdown_) {
     grpc_lb_subchannel_data_stop_connectivity_watch(sd);
     grpc_lb_subchannel_data_unref_subchannel(sd, "pf_shutdown");
-    grpc_lb_subchannel_list_unref_for_connectivity_watch(sd->subchannel_list,
-                                                         "pf_shutdown");
+    p->SubchannelListUnrefForConnectivityWatch(sd->subchannel_list,
+                                               "pf_shutdown");
     return;
   }
   // If the subchannel list is shutting down, stop watching.
   if (sd->subchannel_list->shutting_down || error == GRPC_ERROR_CANCELLED) {
     grpc_lb_subchannel_data_stop_connectivity_watch(sd);
     grpc_lb_subchannel_data_unref_subchannel(sd, "pf_sl_shutdown");
-    grpc_lb_subchannel_list_unref_for_connectivity_watch(sd->subchannel_list,
-                                                         "pf_sl_shutdown");
+    p->SubchannelListUnrefForConnectivityWatch(sd->subchannel_list,
+                                               "pf_sl_shutdown");
     return;
   }
   // If we're still here, the notification must be for a subchannel in
   // either the current or latest pending subchannel lists.
-  GPR_ASSERT(sd->subchannel_list == p->subchannel_list ||
-             sd->subchannel_list == p->latest_pending_subchannel_list);
+  GPR_ASSERT(sd->subchannel_list == p->subchannel_list_ ||
+             sd->subchannel_list == p->latest_pending_subchannel_list_);
   // Update state.
   sd->curr_connectivity_state = sd->pending_connectivity_state_unsafe;
   // Handle updates for the currently selected subchannel.
-  if (p->selected == sd) {
+  if (p->selected_ == sd) {
     // If the new state is anything other than READY and there is a
     // pending update, switch to the pending update.
     if (sd->curr_connectivity_state != GRPC_CHANNEL_READY &&
-        p->latest_pending_subchannel_list != nullptr) {
-      p->selected = nullptr;
+        p->latest_pending_subchannel_list_ != nullptr) {
+      p->selected_ = nullptr;
       grpc_lb_subchannel_data_stop_connectivity_watch(sd);
-      grpc_lb_subchannel_list_unref_for_connectivity_watch(
+      p->SubchannelListUnrefForConnectivityWatch(
           sd->subchannel_list, "selected_not_ready+switch_to_update");
       grpc_lb_subchannel_list_shutdown_and_unref(
-          p->subchannel_list, "selected_not_ready+switch_to_update");
-      p->subchannel_list = p->latest_pending_subchannel_list;
-      p->latest_pending_subchannel_list = nullptr;
+          p->subchannel_list_, "selected_not_ready+switch_to_update");
+      p->subchannel_list_ = p->latest_pending_subchannel_list_;
+      p->latest_pending_subchannel_list_ = nullptr;
       grpc_connectivity_state_set(
-          &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
+          &p->state_tracker_, GRPC_CHANNEL_TRANSIENT_FAILURE,
           GRPC_ERROR_REF(error), "selected_not_ready+switch_to_update");
     } else {
       // TODO(juanlishen): we re-resolve when the selected subchannel goes to
@@ -410,21 +455,20 @@
       GPR_ASSERT(sd->curr_connectivity_state != GRPC_CHANNEL_SHUTDOWN);
       if (sd->curr_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
         // If the selected channel goes bad, request a re-resolution.
-        grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_IDLE,
+        grpc_connectivity_state_set(&p->state_tracker_, GRPC_CHANNEL_IDLE,
                                     GRPC_ERROR_NONE,
                                     "selected_changed+reresolve");
-        p->started_picking = false;
-        grpc_lb_policy_try_reresolve(&p->base, &grpc_lb_pick_first_trace,
-                                     GRPC_ERROR_NONE);
-        // in transient failure. Rely on re-resolution to recover.
-        p->selected = nullptr;
+        p->started_picking_ = false;
+        p->TryReresolutionLocked(&grpc_lb_pick_first_trace, GRPC_ERROR_NONE);
+        // In transient failure. Rely on re-resolution to recover.
+        p->selected_ = nullptr;
         grpc_lb_subchannel_data_stop_connectivity_watch(sd);
-        grpc_lb_subchannel_list_unref_for_connectivity_watch(
-            sd->subchannel_list, "pf_selected_shutdown");
+        p->SubchannelListUnrefForConnectivityWatch(sd->subchannel_list,
+                                                   "pf_selected_shutdown");
         grpc_lb_subchannel_data_unref_subchannel(
             sd, "pf_selected_shutdown");  // Unrefs connected subchannel
       } else {
-        grpc_connectivity_state_set(&p->state_tracker,
+        grpc_connectivity_state_set(&p->state_tracker_,
                                     sd->curr_connectivity_state,
                                     GRPC_ERROR_REF(error), "selected_changed");
         // Renew notification.
@@ -435,45 +479,45 @@
   }
   // If we get here, there are two possible cases:
   // 1. We do not currently have a selected subchannel, and the update is
-  //    for a subchannel in p->subchannel_list that we're trying to
+  //    for a subchannel in p->subchannel_list_ that we're trying to
   //    connect to.  The goal here is to find a subchannel that we can
   //    select.
   // 2. We do currently have a selected subchannel, and the update is
-  //    for a subchannel in p->latest_pending_subchannel_list.  The
+  //    for a subchannel in p->latest_pending_subchannel_list_.  The
   //    goal here is to find a subchannel from the update that we can
   //    select in place of the current one.
   switch (sd->curr_connectivity_state) {
     case GRPC_CHANNEL_READY: {
-      // Case 2.  Promote p->latest_pending_subchannel_list to
-      // p->subchannel_list.
+      // Case 2.  Promote p->latest_pending_subchannel_list_ to
+      // p->subchannel_list_.
       sd->connected_subchannel =
           grpc_subchannel_get_connected_subchannel(sd->subchannel);
-      if (sd->subchannel_list == p->latest_pending_subchannel_list) {
-        GPR_ASSERT(p->subchannel_list != nullptr);
-        grpc_lb_subchannel_list_shutdown_and_unref(p->subchannel_list,
+      if (sd->subchannel_list == p->latest_pending_subchannel_list_) {
+        GPR_ASSERT(p->subchannel_list_ != nullptr);
+        grpc_lb_subchannel_list_shutdown_and_unref(p->subchannel_list_,
                                                    "finish_update");
-        p->subchannel_list = p->latest_pending_subchannel_list;
-        p->latest_pending_subchannel_list = nullptr;
+        p->subchannel_list_ = p->latest_pending_subchannel_list_;
+        p->latest_pending_subchannel_list_ = nullptr;
       }
       // Cases 1 and 2.
-      grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_READY,
+      grpc_connectivity_state_set(&p->state_tracker_, GRPC_CHANNEL_READY,
                                   GRPC_ERROR_NONE, "connecting_ready");
-      p->selected = sd;
+      p->selected_ = sd;
       if (grpc_lb_pick_first_trace.enabled()) {
-        gpr_log(GPR_INFO, "Pick First %p selected subchannel %p", (void*)p,
-                (void*)sd->subchannel);
+        gpr_log(GPR_INFO, "Pick First %p selected subchannel %p", p,
+                sd->subchannel);
       }
       // Drop all other subchannels, since we are now connected.
-      destroy_unselected_subchannels_locked(p);
+      p->DestroyUnselectedSubchannelsLocked();
       // Update any calls that were waiting for a pick.
-      grpc_lb_policy_pick_state* pick;
-      while ((pick = p->pending_picks)) {
-        p->pending_picks = pick->next;
-        pick->connected_subchannel = p->selected->connected_subchannel;
+      PickState* pick;
+      while ((pick = p->pending_picks_)) {
+        p->pending_picks_ = pick->next;
+        pick->connected_subchannel = p->selected_->connected_subchannel;
         if (grpc_lb_pick_first_trace.enabled()) {
           gpr_log(GPR_INFO,
                   "Servicing pending pick with selected subchannel %p",
-                  (void*)p->selected);
+                  p->selected_);
         }
         GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_NONE);
       }
@@ -493,9 +537,9 @@
       // Case 1: Only set state to TRANSIENT_FAILURE if we've tried
       // all subchannels.
       if (sd->subchannel_list->checking_subchannel == 0 &&
-          sd->subchannel_list == p->subchannel_list) {
+          sd->subchannel_list == p->subchannel_list_) {
         grpc_connectivity_state_set(
-            &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
+            &p->state_tracker_, GRPC_CHANNEL_TRANSIENT_FAILURE,
             GRPC_ERROR_REF(error), "connecting_transient_failure");
       }
       // Reuses the connectivity refs from the previous watch.
@@ -505,8 +549,8 @@
     case GRPC_CHANNEL_CONNECTING:
     case GRPC_CHANNEL_IDLE: {
       // Only update connectivity state in case 1.
-      if (sd->subchannel_list == p->subchannel_list) {
-        grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_CONNECTING,
+      if (sd->subchannel_list == p->subchannel_list_) {
+        grpc_connectivity_state_set(&p->state_tracker_, GRPC_CHANNEL_CONNECTING,
                                     GRPC_ERROR_REF(error),
                                     "connecting_changed");
       }
@@ -519,59 +563,29 @@
   }
 }
 
-static void pf_set_reresolve_closure_locked(
-    grpc_lb_policy* policy, grpc_closure* request_reresolution) {
-  pick_first_lb_policy* p = (pick_first_lb_policy*)policy;
-  GPR_ASSERT(!p->shutdown);
-  GPR_ASSERT(policy->request_reresolution == nullptr);
-  policy->request_reresolution = request_reresolution;
-}
+//
+// factory
+//
 
-static const grpc_lb_policy_vtable pick_first_lb_policy_vtable = {
-    pf_destroy,
-    pf_shutdown_locked,
-    pf_pick_locked,
-    pf_cancel_pick_locked,
-    pf_cancel_picks_locked,
-    pf_ping_one_locked,
-    pf_exit_idle_locked,
-    pf_check_connectivity_locked,
-    pf_notify_on_state_change_locked,
-    pf_update_locked,
-    pf_set_reresolve_closure_locked};
-
-static void pick_first_factory_ref(grpc_lb_policy_factory* factory) {}
-
-static void pick_first_factory_unref(grpc_lb_policy_factory* factory) {}
-
-static grpc_lb_policy* create_pick_first(grpc_lb_policy_factory* factory,
-                                         grpc_lb_policy_args* args) {
-  GPR_ASSERT(args->client_channel_factory != nullptr);
-  pick_first_lb_policy* p = (pick_first_lb_policy*)gpr_zalloc(sizeof(*p));
-  if (grpc_lb_pick_first_trace.enabled()) {
-    gpr_log(GPR_DEBUG, "Pick First %p created.", (void*)p);
+class PickFirstFactory : public LoadBalancingPolicyFactory {
+ public:
+  OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
+      const LoadBalancingPolicy::Args& args) const override {
+    return OrphanablePtr<LoadBalancingPolicy>(New<PickFirst>(args));
   }
-  pf_update_locked(&p->base, args);
-  grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable, args->combiner);
-  grpc_subchannel_index_ref();
-  return &p->base;
-}
 
-static const grpc_lb_policy_factory_vtable pick_first_factory_vtable = {
-    pick_first_factory_ref, pick_first_factory_unref, create_pick_first,
-    "pick_first"};
+  const char* name() const override { return "pick_first"; }
+};
 
-static grpc_lb_policy_factory pick_first_lb_policy_factory = {
-    &pick_first_factory_vtable};
+}  // namespace
 
-static grpc_lb_policy_factory* pick_first_lb_factory_create() {
-  return &pick_first_lb_policy_factory;
-}
-
-/* Plugin registration */
+}  // namespace grpc_core
 
 void grpc_lb_policy_pick_first_init() {
-  grpc_register_lb_policy(pick_first_lb_factory_create());
+  grpc_core::LoadBalancingPolicyRegistry::Builder::
+      RegisterLoadBalancingPolicyFactory(
+          grpc_core::UniquePtr<grpc_core::LoadBalancingPolicyFactory>(
+              grpc_core::New<grpc_core::PickFirstFactory>()));
 }
 
 void grpc_lb_policy_pick_first_shutdown() {}
diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
index 24c381a..e534131 100644
--- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
@@ -24,6 +24,8 @@
  * updates. Note however that updates will start picking from the beginning of
  * the updated list. */
 
+#include <grpc/support/port_platform.h>
+
 #include <string.h>
 
 #include <grpc/support/alloc.h>
@@ -40,34 +42,94 @@
 #include "src/core/lib/transport/connectivity_state.h"
 #include "src/core/lib/transport/static_metadata.h"
 
-grpc_core::TraceFlag grpc_lb_round_robin_trace(false, "round_robin");
+namespace grpc_core {
 
-typedef struct round_robin_lb_policy {
-  /** base policy: must be first */
-  grpc_lb_policy base;
+TraceFlag grpc_lb_round_robin_trace(false, "round_robin");
 
-  grpc_lb_subchannel_list* subchannel_list;
+namespace {
 
+//
+// round_robin LB policy
+//
+
+class RoundRobin : public LoadBalancingPolicy {
+ public:
+  explicit RoundRobin(const Args& args);
+
+  void UpdateLocked(const grpc_channel_args& args) override;
+  bool PickLocked(PickState* pick) override;
+  void CancelPickLocked(PickState* pick, grpc_error* error) override;
+  void CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask,
+                                 uint32_t initial_metadata_flags_eq,
+                                 grpc_error* error) override;
+  void NotifyOnStateChangeLocked(grpc_connectivity_state* state,
+                                 grpc_closure* closure) override;
+  grpc_connectivity_state CheckConnectivityLocked(
+      grpc_error** connectivity_error) override;
+  void HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) override;
+  void PingOneLocked(grpc_closure* on_initiate, grpc_closure* on_ack) override;
+  void ExitIdleLocked() override;
+
+ private:
+  ~RoundRobin();
+
+  void ShutdownLocked() override;
+
+  void StartPickingLocked();
+  size_t GetNextReadySubchannelIndexLocked();
+  void UpdateLastReadySubchannelIndexLocked(size_t last_ready_index);
+  void UpdateConnectivityStatusLocked(grpc_lb_subchannel_data* sd,
+                                      grpc_error* error);
+
+  static void OnConnectivityChangedLocked(void* arg, grpc_error* error);
+
+  void SubchannelListRefForConnectivityWatch(
+      grpc_lb_subchannel_list* subchannel_list, const char* reason);
+  void SubchannelListUnrefForConnectivityWatch(
+      grpc_lb_subchannel_list* subchannel_list, const char* reason);
+
+  /** list of subchannels */
+  grpc_lb_subchannel_list* subchannel_list_ = nullptr;
   /** have we started picking? */
-  bool started_picking;
+  bool started_picking_ = false;
   /** are we shutting down? */
-  bool shutdown;
+  bool shutdown_ = false;
   /** List of picks that are waiting on connectivity */
-  grpc_lb_policy_pick_state* pending_picks;
-
+  PickState* pending_picks_ = nullptr;
   /** our connectivity state tracker */
-  grpc_connectivity_state_tracker state_tracker;
-
+  grpc_connectivity_state_tracker state_tracker_;
   /** Index into subchannels for last pick. */
-  size_t last_ready_subchannel_index;
-
+  size_t last_ready_subchannel_index_ = 0;
   /** Latest version of the subchannel list.
    * Subchannel connectivity callbacks will only promote updated subchannel
    * lists if they equal \a latest_pending_subchannel_list. In other words,
    * racing callbacks that reference outdated subchannel lists won't perform any
    * update. */
-  grpc_lb_subchannel_list* latest_pending_subchannel_list;
-} round_robin_lb_policy;
+  grpc_lb_subchannel_list* latest_pending_subchannel_list_ = nullptr;
+};
+
+RoundRobin::RoundRobin(const Args& args) : LoadBalancingPolicy(args) {
+  GPR_ASSERT(args.client_channel_factory != nullptr);
+  grpc_connectivity_state_init(&state_tracker_, GRPC_CHANNEL_IDLE,
+                               "round_robin");
+  UpdateLocked(*args.args);
+  if (grpc_lb_round_robin_trace.enabled()) {
+    gpr_log(GPR_DEBUG, "[RR %p] Created with %" PRIuPTR " subchannels", this,
+            subchannel_list_->num_subchannels);
+  }
+  grpc_subchannel_index_ref();
+}
+
+RoundRobin::~RoundRobin() {
+  if (grpc_lb_round_robin_trace.enabled()) {
+    gpr_log(GPR_DEBUG, "[RR %p] Destroying Round Robin policy", this);
+  }
+  GPR_ASSERT(subchannel_list_ == nullptr);
+  GPR_ASSERT(latest_pending_subchannel_list_ == nullptr);
+  GPR_ASSERT(pending_picks_ == nullptr);
+  grpc_connectivity_state_destroy(&state_tracker_);
+  grpc_subchannel_index_unref();
+}
 
 /** Returns the index into p->subchannel_list->subchannels of the next
  * subchannel in READY state, or p->subchannel_list->num_subchannels if no
@@ -75,194 +137,190 @@
  *
  * Note that this function does *not* update p->last_ready_subchannel_index.
  * The caller must do that if it returns a pick. */
-static size_t get_next_ready_subchannel_index_locked(
-    const round_robin_lb_policy* p) {
-  GPR_ASSERT(p->subchannel_list != nullptr);
+size_t RoundRobin::GetNextReadySubchannelIndexLocked() {
+  GPR_ASSERT(subchannel_list_ != nullptr);
   if (grpc_lb_round_robin_trace.enabled()) {
     gpr_log(GPR_INFO,
-            "[RR %p] getting next ready subchannel (out of %lu), "
-            "last_ready_subchannel_index=%lu",
-            (void*)p, (unsigned long)p->subchannel_list->num_subchannels,
-            (unsigned long)p->last_ready_subchannel_index);
+            "[RR %p] getting next ready subchannel (out of %" PRIuPTR
+            "), "
+            "last_ready_subchannel_index=%" PRIuPTR,
+            this, subchannel_list_->num_subchannels,
+            last_ready_subchannel_index_);
   }
-  for (size_t i = 0; i < p->subchannel_list->num_subchannels; ++i) {
-    const size_t index = (i + p->last_ready_subchannel_index + 1) %
-                         p->subchannel_list->num_subchannels;
+  for (size_t i = 0; i < subchannel_list_->num_subchannels; ++i) {
+    const size_t index = (i + last_ready_subchannel_index_ + 1) %
+                         subchannel_list_->num_subchannels;
     if (grpc_lb_round_robin_trace.enabled()) {
       gpr_log(
           GPR_DEBUG,
-          "[RR %p] checking subchannel %p, subchannel_list %p, index %lu: "
-          "state=%s",
-          (void*)p, (void*)p->subchannel_list->subchannels[index].subchannel,
-          (void*)p->subchannel_list, (unsigned long)index,
+          "[RR %p] checking subchannel %p, subchannel_list %p, index %" PRIuPTR
+          ": state=%s",
+          this, subchannel_list_->subchannels[index].subchannel,
+          subchannel_list_, index,
           grpc_connectivity_state_name(
-              p->subchannel_list->subchannels[index].curr_connectivity_state));
+              subchannel_list_->subchannels[index].curr_connectivity_state));
     }
-    if (p->subchannel_list->subchannels[index].curr_connectivity_state ==
+    if (subchannel_list_->subchannels[index].curr_connectivity_state ==
         GRPC_CHANNEL_READY) {
       if (grpc_lb_round_robin_trace.enabled()) {
         gpr_log(GPR_DEBUG,
-                "[RR %p] found next ready subchannel (%p) at index %lu of "
-                "subchannel_list %p",
-                (void*)p,
-                (void*)p->subchannel_list->subchannels[index].subchannel,
-                (unsigned long)index, (void*)p->subchannel_list);
+                "[RR %p] found next ready subchannel (%p) at index %" PRIuPTR
+                " of subchannel_list %p",
+                this, subchannel_list_->subchannels[index].subchannel, index,
+                subchannel_list_);
       }
       return index;
     }
   }
   if (grpc_lb_round_robin_trace.enabled()) {
-    gpr_log(GPR_DEBUG, "[RR %p] no subchannels in ready state", (void*)p);
+    gpr_log(GPR_DEBUG, "[RR %p] no subchannels in ready state", this);
   }
-  return p->subchannel_list->num_subchannels;
+  return subchannel_list_->num_subchannels;
 }
 
-// Sets p->last_ready_subchannel_index to last_ready_index.
-static void update_last_ready_subchannel_index_locked(round_robin_lb_policy* p,
-                                                      size_t last_ready_index) {
-  GPR_ASSERT(last_ready_index < p->subchannel_list->num_subchannels);
-  p->last_ready_subchannel_index = last_ready_index;
+// Sets last_ready_subchannel_index_ to last_ready_index.
+void RoundRobin::UpdateLastReadySubchannelIndexLocked(size_t last_ready_index) {
+  GPR_ASSERT(last_ready_index < subchannel_list_->num_subchannels);
+  last_ready_subchannel_index_ = last_ready_index;
   if (grpc_lb_round_robin_trace.enabled()) {
     gpr_log(GPR_DEBUG,
-            "[RR %p] setting last_ready_subchannel_index=%lu (SC %p, CSC %p)",
-            (void*)p, (unsigned long)last_ready_index,
-            (void*)p->subchannel_list->subchannels[last_ready_index].subchannel,
-            (void*)p->subchannel_list->subchannels[last_ready_index]
+            "[RR %p] setting last_ready_subchannel_index=%" PRIuPTR
+            " (SC %p, CSC %p)",
+            this, last_ready_index,
+            subchannel_list_->subchannels[last_ready_index].subchannel,
+            subchannel_list_->subchannels[last_ready_index]
                 .connected_subchannel.get());
   }
 }
 
-static void rr_destroy(grpc_lb_policy* pol) {
-  round_robin_lb_policy* p = (round_robin_lb_policy*)pol;
-  if (grpc_lb_round_robin_trace.enabled()) {
-    gpr_log(GPR_DEBUG, "[RR %p] Destroying Round Robin policy at %p",
-            (void*)pol, (void*)pol);
-  }
-  GPR_ASSERT(p->subchannel_list == nullptr);
-  GPR_ASSERT(p->latest_pending_subchannel_list == nullptr);
-  grpc_connectivity_state_destroy(&p->state_tracker);
-  grpc_subchannel_index_unref();
-  gpr_free(p);
-}
-
-static void rr_shutdown_locked(grpc_lb_policy* pol,
-                               grpc_lb_policy* new_policy) {
-  round_robin_lb_policy* p = (round_robin_lb_policy*)pol;
-  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel shutdown");
-  if (grpc_lb_round_robin_trace.enabled()) {
-    gpr_log(GPR_DEBUG, "[RR %p] Shutting down", p);
-  }
-  p->shutdown = true;
-  grpc_lb_policy_pick_state* pick;
-  while ((pick = p->pending_picks) != nullptr) {
-    p->pending_picks = pick->next;
-    if (new_policy != nullptr) {
-      // Hand off to new LB policy.
-      if (grpc_lb_policy_pick_locked(new_policy, pick)) {
-        // Synchronous return; schedule callback.
-        GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_NONE);
-      }
-    } else {
-      pick->connected_subchannel.reset();
-      GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_REF(error));
+void RoundRobin::HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) {
+  PickState* pick;
+  while ((pick = pending_picks_) != nullptr) {
+    pending_picks_ = pick->next;
+    if (new_policy->PickLocked(pick)) {
+      // Synchronous return, schedule closure.
+      GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_NONE);
     }
   }
-  grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
+}
+
+void RoundRobin::ShutdownLocked() {
+  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel shutdown");
+  if (grpc_lb_round_robin_trace.enabled()) {
+    gpr_log(GPR_DEBUG, "[RR %p] Shutting down", this);
+  }
+  shutdown_ = true;
+  PickState* pick;
+  while ((pick = pending_picks_) != nullptr) {
+    pending_picks_ = pick->next;
+    pick->connected_subchannel.reset();
+    GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_REF(error));
+  }
+  grpc_connectivity_state_set(&state_tracker_, GRPC_CHANNEL_SHUTDOWN,
                               GRPC_ERROR_REF(error), "rr_shutdown");
-  if (p->subchannel_list != nullptr) {
-    grpc_lb_subchannel_list_shutdown_and_unref(p->subchannel_list,
+  if (subchannel_list_ != nullptr) {
+    grpc_lb_subchannel_list_shutdown_and_unref(subchannel_list_,
                                                "sl_shutdown_rr_shutdown");
-    p->subchannel_list = nullptr;
+    subchannel_list_ = nullptr;
   }
-  if (p->latest_pending_subchannel_list != nullptr) {
+  if (latest_pending_subchannel_list_ != nullptr) {
     grpc_lb_subchannel_list_shutdown_and_unref(
-        p->latest_pending_subchannel_list, "sl_shutdown_pending_rr_shutdown");
-    p->latest_pending_subchannel_list = nullptr;
+        latest_pending_subchannel_list_, "sl_shutdown_pending_rr_shutdown");
+    latest_pending_subchannel_list_ = nullptr;
   }
-  grpc_lb_policy_try_reresolve(&p->base, &grpc_lb_round_robin_trace,
-                               GRPC_ERROR_CANCELLED);
+  TryReresolutionLocked(&grpc_lb_round_robin_trace, GRPC_ERROR_CANCELLED);
   GRPC_ERROR_UNREF(error);
 }
 
-static void rr_cancel_pick_locked(grpc_lb_policy* pol,
-                                  grpc_lb_policy_pick_state* pick,
-                                  grpc_error* error) {
-  round_robin_lb_policy* p = (round_robin_lb_policy*)pol;
-  grpc_lb_policy_pick_state* pp = p->pending_picks;
-  p->pending_picks = nullptr;
+void RoundRobin::CancelPickLocked(PickState* pick, grpc_error* error) {
+  PickState* pp = pending_picks_;
+  pending_picks_ = nullptr;
   while (pp != nullptr) {
-    grpc_lb_policy_pick_state* next = pp->next;
+    PickState* next = pp->next;
     if (pp == pick) {
       pick->connected_subchannel.reset();
       GRPC_CLOSURE_SCHED(pick->on_complete,
                          GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-                             "Pick cancelled", &error, 1));
+                             "Pick Cancelled", &error, 1));
     } else {
-      pp->next = p->pending_picks;
-      p->pending_picks = pp;
+      pp->next = pending_picks_;
+      pending_picks_ = pp;
     }
     pp = next;
   }
   GRPC_ERROR_UNREF(error);
 }
 
-static void rr_cancel_picks_locked(grpc_lb_policy* pol,
-                                   uint32_t initial_metadata_flags_mask,
-                                   uint32_t initial_metadata_flags_eq,
-                                   grpc_error* error) {
-  round_robin_lb_policy* p = (round_robin_lb_policy*)pol;
-  grpc_lb_policy_pick_state* pick = p->pending_picks;
-  p->pending_picks = nullptr;
+void RoundRobin::CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask,
+                                           uint32_t initial_metadata_flags_eq,
+                                           grpc_error* error) {
+  PickState* pick = pending_picks_;
+  pending_picks_ = nullptr;
   while (pick != nullptr) {
-    grpc_lb_policy_pick_state* next = pick->next;
+    PickState* next = pick->next;
     if ((pick->initial_metadata_flags & initial_metadata_flags_mask) ==
         initial_metadata_flags_eq) {
       pick->connected_subchannel.reset();
       GRPC_CLOSURE_SCHED(pick->on_complete,
                          GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-                             "Pick cancelled", &error, 1));
+                             "Pick Cancelled", &error, 1));
     } else {
-      pick->next = p->pending_picks;
-      p->pending_picks = pick;
+      pick->next = pending_picks_;
+      pending_picks_ = pick;
     }
     pick = next;
   }
   GRPC_ERROR_UNREF(error);
 }
 
-static void start_picking_locked(round_robin_lb_policy* p) {
-  p->started_picking = true;
-  for (size_t i = 0; i < p->subchannel_list->num_subchannels; i++) {
-    if (p->subchannel_list->subchannels[i].subchannel != nullptr) {
-      grpc_lb_subchannel_list_ref_for_connectivity_watch(p->subchannel_list,
-                                                         "connectivity_watch");
+void RoundRobin::SubchannelListRefForConnectivityWatch(
+    grpc_lb_subchannel_list* subchannel_list, const char* reason) {
+  // TODO(roth): We currently track this ref manually.  Once the new
+  // ClosureRef API is ready and the subchannel_list code has been
+  // converted to a C++ API, find a way to hold the RefCountedPtr<>
+  // somewhere (maybe in the subchannel_data object) instead of doing
+  // this manually.
+  auto self = Ref(DEBUG_LOCATION, reason);
+  self.release();
+  grpc_lb_subchannel_list_ref(subchannel_list, reason);
+}
+
+void RoundRobin::SubchannelListUnrefForConnectivityWatch(
+    grpc_lb_subchannel_list* subchannel_list, const char* reason) {
+  Unref(DEBUG_LOCATION, reason);
+  grpc_lb_subchannel_list_unref(subchannel_list, reason);
+}
+
+void RoundRobin::StartPickingLocked() {
+  started_picking_ = true;
+  for (size_t i = 0; i < subchannel_list_->num_subchannels; i++) {
+    if (subchannel_list_->subchannels[i].subchannel != nullptr) {
+      SubchannelListRefForConnectivityWatch(subchannel_list_,
+                                            "connectivity_watch");
       grpc_lb_subchannel_data_start_connectivity_watch(
-          &p->subchannel_list->subchannels[i]);
+          &subchannel_list_->subchannels[i]);
     }
   }
 }
 
-static void rr_exit_idle_locked(grpc_lb_policy* pol) {
-  round_robin_lb_policy* p = (round_robin_lb_policy*)pol;
-  if (!p->started_picking) {
-    start_picking_locked(p);
+void RoundRobin::ExitIdleLocked() {
+  if (!started_picking_) {
+    StartPickingLocked();
   }
 }
 
-static int rr_pick_locked(grpc_lb_policy* pol,
-                          grpc_lb_policy_pick_state* pick) {
-  round_robin_lb_policy* p = (round_robin_lb_policy*)pol;
+bool RoundRobin::PickLocked(PickState* pick) {
   if (grpc_lb_round_robin_trace.enabled()) {
-    gpr_log(GPR_INFO, "[RR %p] Trying to pick (shutdown: %d)", pol,
-            p->shutdown);
+    gpr_log(GPR_DEBUG, "[RR %p] Trying to pick (shutdown: %d)", this,
+            shutdown_);
   }
-  GPR_ASSERT(!p->shutdown);
-  if (p->subchannel_list != nullptr) {
-    const size_t next_ready_index = get_next_ready_subchannel_index_locked(p);
-    if (next_ready_index < p->subchannel_list->num_subchannels) {
+  GPR_ASSERT(!shutdown_);
+  if (subchannel_list_ != nullptr) {
+    const size_t next_ready_index = GetNextReadySubchannelIndexLocked();
+    if (next_ready_index < subchannel_list_->num_subchannels) {
       /* readily available, report right away */
       grpc_lb_subchannel_data* sd =
-          &p->subchannel_list->subchannels[next_ready_index];
+          &subchannel_list_->subchannels[next_ready_index];
       pick->connected_subchannel = sd->connected_subchannel;
       if (pick->user_data != nullptr) {
         *pick->user_data = sd->user_data;
@@ -272,24 +330,24 @@
             GPR_DEBUG,
             "[RR %p] Picked target <-- Subchannel %p (connected %p) (sl %p, "
             "index %" PRIuPTR ")",
-            p, sd->subchannel, pick->connected_subchannel.get(),
+            this, sd->subchannel, pick->connected_subchannel.get(),
             sd->subchannel_list, next_ready_index);
       }
       /* only advance the last picked pointer if the selection was used */
-      update_last_ready_subchannel_index_locked(p, next_ready_index);
-      return 1;
+      UpdateLastReadySubchannelIndexLocked(next_ready_index);
+      return true;
     }
   }
   /* no pick currently available. Save for later in list of pending picks */
-  if (!p->started_picking) {
-    start_picking_locked(p);
+  if (!started_picking_) {
+    StartPickingLocked();
   }
-  pick->next = p->pending_picks;
-  p->pending_picks = pick;
-  return 0;
+  pick->next = pending_picks_;
+  pending_picks_ = pick;
+  return false;
 }
 
-static void update_state_counters_locked(grpc_lb_subchannel_data* sd) {
+void UpdateStateCountersLocked(grpc_lb_subchannel_data* sd) {
   grpc_lb_subchannel_list* subchannel_list = sd->subchannel_list;
   GPR_ASSERT(sd->prev_connectivity_state != GRPC_CHANNEL_SHUTDOWN);
   GPR_ASSERT(sd->curr_connectivity_state != GRPC_CHANNEL_SHUTDOWN);
@@ -317,8 +375,8 @@
  * (the grpc_lb_subchannel_data associated with the updated subchannel) and the
  * subchannel list \a sd belongs to (sd->subchannel_list). \a error will be used
  * only if the policy transitions to state TRANSIENT_FAILURE. */
-static void update_lb_connectivity_status_locked(grpc_lb_subchannel_data* sd,
-                                                 grpc_error* error) {
+void RoundRobin::UpdateConnectivityStatusLocked(grpc_lb_subchannel_data* sd,
+                                                grpc_error* error) {
   /* In priority order. The first rule to match terminates the search (ie, if we
    * are on rule n, all previous rules were unfulfilled).
    *
@@ -328,98 +386,84 @@
    * 2) RULE: ANY subchannel is CONNECTING => policy is CONNECTING.
    *    CHECK: sd->curr_connectivity_state == CONNECTING.
    *
-   * 3) RULE: ALL subchannels are SHUTDOWN => policy is IDLE (and requests
-   *          re-resolution).
-   *    CHECK: subchannel_list->num_shutdown ==
-   *           subchannel_list->num_subchannels.
-   *
-   * 4) RULE: ALL subchannels are SHUTDOWN or TRANSIENT_FAILURE => policy is
-   *          TRANSIENT_FAILURE.
-   *    CHECK: subchannel_list->num_shutdown +
-   *             subchannel_list->num_transient_failures ==
+   * 3) RULE: ALL subchannels are TRANSIENT_FAILURE => policy is
+   *                                                   TRANSIENT_FAILURE.
+   *    CHECK: subchannel_list->num_transient_failures ==
    *           subchannel_list->num_subchannels.
    */
-  // TODO(juanlishen): For rule 4, we may want to re-resolve instead.
   grpc_lb_subchannel_list* subchannel_list = sd->subchannel_list;
-  round_robin_lb_policy* p = (round_robin_lb_policy*)subchannel_list->policy;
   GPR_ASSERT(sd->curr_connectivity_state != GRPC_CHANNEL_IDLE);
   if (subchannel_list->num_ready > 0) {
     /* 1) READY */
-    grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_READY,
+    grpc_connectivity_state_set(&state_tracker_, GRPC_CHANNEL_READY,
                                 GRPC_ERROR_NONE, "rr_ready");
   } else if (sd->curr_connectivity_state == GRPC_CHANNEL_CONNECTING) {
     /* 2) CONNECTING */
-    grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_CONNECTING,
+    grpc_connectivity_state_set(&state_tracker_, GRPC_CHANNEL_CONNECTING,
                                 GRPC_ERROR_NONE, "rr_connecting");
-  } else if (subchannel_list->num_shutdown ==
+  } else if (subchannel_list->num_transient_failures ==
              subchannel_list->num_subchannels) {
-    /* 3) IDLE and re-resolve */
-    grpc_connectivity_state_set(&p->state_tracker, GRPC_CHANNEL_IDLE,
-                                GRPC_ERROR_NONE,
-                                "rr_exhausted_subchannels+reresolve");
-    p->started_picking = false;
-    grpc_lb_policy_try_reresolve(&p->base, &grpc_lb_round_robin_trace,
-                                 GRPC_ERROR_NONE);
-  } else if (subchannel_list->num_shutdown +
-                 subchannel_list->num_transient_failures ==
-             subchannel_list->num_subchannels) {
-    /* 4) TRANSIENT_FAILURE */
-    grpc_connectivity_state_set(&p->state_tracker,
-                                GRPC_CHANNEL_TRANSIENT_FAILURE,
-                                GRPC_ERROR_REF(error), "rr_transient_failure");
+    /* 3) TRANSIENT_FAILURE */
+    grpc_connectivity_state_set(&state_tracker_, GRPC_CHANNEL_TRANSIENT_FAILURE,
+                                GRPC_ERROR_REF(error),
+                                "rr_exhausted_subchannels");
   }
   GRPC_ERROR_UNREF(error);
 }
 
-static void rr_connectivity_changed_locked(void* arg, grpc_error* error) {
-  grpc_lb_subchannel_data* sd = (grpc_lb_subchannel_data*)arg;
-  round_robin_lb_policy* p =
-      (round_robin_lb_policy*)sd->subchannel_list->policy;
+void RoundRobin::OnConnectivityChangedLocked(void* arg, grpc_error* error) {
+  grpc_lb_subchannel_data* sd = static_cast<grpc_lb_subchannel_data*>(arg);
+  RoundRobin* p = static_cast<RoundRobin*>(sd->subchannel_list->policy);
   if (grpc_lb_round_robin_trace.enabled()) {
     gpr_log(
         GPR_DEBUG,
         "[RR %p] connectivity changed for subchannel %p, subchannel_list %p: "
         "prev_state=%s new_state=%s p->shutdown=%d "
         "sd->subchannel_list->shutting_down=%d error=%s",
-        (void*)p, (void*)sd->subchannel, (void*)sd->subchannel_list,
+        p, sd->subchannel, sd->subchannel_list,
         grpc_connectivity_state_name(sd->prev_connectivity_state),
         grpc_connectivity_state_name(sd->pending_connectivity_state_unsafe),
-        p->shutdown, sd->subchannel_list->shutting_down,
+        p->shutdown_, sd->subchannel_list->shutting_down,
         grpc_error_string(error));
   }
+  GPR_ASSERT(sd->subchannel != nullptr);
   // If the policy is shutting down, unref and return.
-  if (p->shutdown) {
+  if (p->shutdown_) {
     grpc_lb_subchannel_data_stop_connectivity_watch(sd);
     grpc_lb_subchannel_data_unref_subchannel(sd, "rr_shutdown");
-    grpc_lb_subchannel_list_unref_for_connectivity_watch(sd->subchannel_list,
-                                                         "rr_shutdown");
+    p->SubchannelListUnrefForConnectivityWatch(sd->subchannel_list,
+                                               "rr_shutdown");
     return;
   }
   // If the subchannel list is shutting down, stop watching.
   if (sd->subchannel_list->shutting_down || error == GRPC_ERROR_CANCELLED) {
     grpc_lb_subchannel_data_stop_connectivity_watch(sd);
     grpc_lb_subchannel_data_unref_subchannel(sd, "rr_sl_shutdown");
-    grpc_lb_subchannel_list_unref_for_connectivity_watch(sd->subchannel_list,
-                                                         "rr_sl_shutdown");
+    p->SubchannelListUnrefForConnectivityWatch(sd->subchannel_list,
+                                               "rr_sl_shutdown");
     return;
   }
   // If we're still here, the notification must be for a subchannel in
   // either the current or latest pending subchannel lists.
-  GPR_ASSERT(sd->subchannel_list == p->subchannel_list ||
-             sd->subchannel_list == p->latest_pending_subchannel_list);
+  GPR_ASSERT(sd->subchannel_list == p->subchannel_list_ ||
+             sd->subchannel_list == p->latest_pending_subchannel_list_);
   GPR_ASSERT(sd->pending_connectivity_state_unsafe != GRPC_CHANNEL_SHUTDOWN);
   // Now that we're inside the combiner, copy the pending connectivity
   // state (which was set by the connectivity state watcher) to
   // curr_connectivity_state, which is what we use inside of the combiner.
   sd->curr_connectivity_state = sd->pending_connectivity_state_unsafe;
-  // Update state counters and new overall state.
-  update_state_counters_locked(sd);
-  update_lb_connectivity_status_locked(sd, GRPC_ERROR_REF(error));
   // If the sd's new state is TRANSIENT_FAILURE, unref the *connected*
   // subchannel, if any.
   switch (sd->curr_connectivity_state) {
     case GRPC_CHANNEL_TRANSIENT_FAILURE: {
       sd->connected_subchannel.reset();
+      if (grpc_lb_round_robin_trace.enabled()) {
+        gpr_log(GPR_DEBUG,
+                "[RR %p] Subchannel %p has gone into TRANSIENT_FAILURE. "
+                "Requesting re-resolution",
+                p, sd->subchannel);
+      }
+      p->TryReresolutionLocked(&grpc_lb_round_robin_trace, GRPC_ERROR_NONE);
       break;
     }
     case GRPC_CHANNEL_READY: {
@@ -427,47 +471,47 @@
         sd->connected_subchannel =
             grpc_subchannel_get_connected_subchannel(sd->subchannel);
       }
-      if (sd->subchannel_list != p->subchannel_list) {
-        // promote sd->subchannel_list to p->subchannel_list.
+      if (sd->subchannel_list != p->subchannel_list_) {
+        // promote sd->subchannel_list to p->subchannel_list_.
         // sd->subchannel_list must be equal to
-        // p->latest_pending_subchannel_list because we have already filtered
+        // p->latest_pending_subchannel_list_ because we have already filtered
         // for sds belonging to outdated subchannel lists.
-        GPR_ASSERT(sd->subchannel_list == p->latest_pending_subchannel_list);
+        GPR_ASSERT(sd->subchannel_list == p->latest_pending_subchannel_list_);
         GPR_ASSERT(!sd->subchannel_list->shutting_down);
         if (grpc_lb_round_robin_trace.enabled()) {
-          const unsigned long num_subchannels =
-              p->subchannel_list != nullptr
-                  ? (unsigned long)p->subchannel_list->num_subchannels
+          const size_t num_subchannels =
+              p->subchannel_list_ != nullptr
+                  ? p->subchannel_list_->num_subchannels
                   : 0;
           gpr_log(GPR_DEBUG,
-                  "[RR %p] phasing out subchannel list %p (size %lu) in favor "
-                  "of %p (size %lu)",
-                  (void*)p, (void*)p->subchannel_list, num_subchannels,
-                  (void*)sd->subchannel_list, num_subchannels);
+                  "[RR %p] phasing out subchannel list %p (size %" PRIuPTR
+                  ") in favor of %p (size %" PRIuPTR ")",
+                  p, p->subchannel_list_, num_subchannels, sd->subchannel_list,
+                  num_subchannels);
         }
-        if (p->subchannel_list != nullptr) {
+        if (p->subchannel_list_ != nullptr) {
           // dispose of the current subchannel_list
-          grpc_lb_subchannel_list_shutdown_and_unref(p->subchannel_list,
+          grpc_lb_subchannel_list_shutdown_and_unref(p->subchannel_list_,
                                                      "sl_phase_out_shutdown");
         }
-        p->subchannel_list = p->latest_pending_subchannel_list;
-        p->latest_pending_subchannel_list = nullptr;
+        p->subchannel_list_ = p->latest_pending_subchannel_list_;
+        p->latest_pending_subchannel_list_ = nullptr;
       }
       /* at this point we know there's at least one suitable subchannel. Go
        * ahead and pick one and notify the pending suitors in
        * p->pending_picks. This preemptively replicates rr_pick()'s actions. */
-      const size_t next_ready_index = get_next_ready_subchannel_index_locked(p);
-      GPR_ASSERT(next_ready_index < p->subchannel_list->num_subchannels);
+      const size_t next_ready_index = p->GetNextReadySubchannelIndexLocked();
+      GPR_ASSERT(next_ready_index < p->subchannel_list_->num_subchannels);
       grpc_lb_subchannel_data* selected =
-          &p->subchannel_list->subchannels[next_ready_index];
-      if (p->pending_picks != nullptr) {
+          &p->subchannel_list_->subchannels[next_ready_index];
+      if (p->pending_picks_ != nullptr) {
         // if the selected subchannel is going to be used for the pending
         // picks, update the last picked pointer
-        update_last_ready_subchannel_index_locked(p, next_ready_index);
+        p->UpdateLastReadySubchannelIndexLocked(next_ready_index);
       }
-      grpc_lb_policy_pick_state* pick;
-      while ((pick = p->pending_picks)) {
-        p->pending_picks = pick->next;
+      PickState* pick;
+      while ((pick = p->pending_picks_)) {
+        p->pending_picks_ = pick->next;
         pick->connected_subchannel = selected->connected_subchannel;
         if (pick->user_data != nullptr) {
           *pick->user_data = selected->user_data;
@@ -475,9 +519,9 @@
         if (grpc_lb_round_robin_trace.enabled()) {
           gpr_log(GPR_DEBUG,
                   "[RR %p] Fulfilling pending pick. Target <-- subchannel %p "
-                  "(subchannel_list %p, index %lu)",
-                  (void*)p, (void*)selected->subchannel,
-                  (void*)p->subchannel_list, (unsigned long)next_ready_index);
+                  "(subchannel_list %p, index %" PRIuPTR ")",
+                  p, selected->subchannel, p->subchannel_list_,
+                  next_ready_index);
         }
         GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_NONE);
       }
@@ -488,34 +532,34 @@
     case GRPC_CHANNEL_CONNECTING:
     case GRPC_CHANNEL_IDLE:;  // fallthrough
   }
+  // Update state counters.
+  UpdateStateCountersLocked(sd);
+  // Only update connectivity based on the selected subchannel list.
+  if (sd->subchannel_list == p->subchannel_list_) {
+    p->UpdateConnectivityStatusLocked(sd, GRPC_ERROR_REF(error));
+  }
   // Renew notification.
   grpc_lb_subchannel_data_start_connectivity_watch(sd);
 }
 
-static grpc_connectivity_state rr_check_connectivity_locked(
-    grpc_lb_policy* pol, grpc_error** error) {
-  round_robin_lb_policy* p = (round_robin_lb_policy*)pol;
-  return grpc_connectivity_state_get(&p->state_tracker, error);
+grpc_connectivity_state RoundRobin::CheckConnectivityLocked(
+    grpc_error** error) {
+  return grpc_connectivity_state_get(&state_tracker_, error);
 }
 
-static void rr_notify_on_state_change_locked(grpc_lb_policy* pol,
-                                             grpc_connectivity_state* current,
-                                             grpc_closure* notify) {
-  round_robin_lb_policy* p = (round_robin_lb_policy*)pol;
-  grpc_connectivity_state_notify_on_state_change(&p->state_tracker, current,
+void RoundRobin::NotifyOnStateChangeLocked(grpc_connectivity_state* current,
+                                           grpc_closure* notify) {
+  grpc_connectivity_state_notify_on_state_change(&state_tracker_, current,
                                                  notify);
 }
 
-static void rr_ping_one_locked(grpc_lb_policy* pol, grpc_closure* on_initiate,
+void RoundRobin::PingOneLocked(grpc_closure* on_initiate,
                                grpc_closure* on_ack) {
-  round_robin_lb_policy* p = (round_robin_lb_policy*)pol;
-  const size_t next_ready_index = get_next_ready_subchannel_index_locked(p);
-  if (next_ready_index < p->subchannel_list->num_subchannels) {
+  const size_t next_ready_index = GetNextReadySubchannelIndexLocked();
+  if (next_ready_index < subchannel_list_->num_subchannels) {
     grpc_lb_subchannel_data* selected =
-        &p->subchannel_list->subchannels[next_ready_index];
-    grpc_core::RefCountedPtr<grpc_core::ConnectedSubchannel> target =
-        selected->connected_subchannel;
-    target->Ping(on_initiate, on_ack);
+        &subchannel_list_->subchannels[next_ready_index];
+    selected->connected_subchannel->Ping(on_initiate, on_ack);
   } else {
     GRPC_CLOSURE_SCHED(on_initiate, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
                                         "Round Robin not connected"));
@@ -524,18 +568,15 @@
   }
 }
 
-static void rr_update_locked(grpc_lb_policy* policy,
-                             const grpc_lb_policy_args* args) {
-  round_robin_lb_policy* p = (round_robin_lb_policy*)policy;
-  const grpc_arg* arg =
-      grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES);
+void RoundRobin::UpdateLocked(const grpc_channel_args& args) {
+  const grpc_arg* arg = grpc_channel_args_find(&args, GRPC_ARG_LB_ADDRESSES);
   if (arg == nullptr || arg->type != GRPC_ARG_POINTER) {
-    gpr_log(GPR_ERROR, "[RR %p] update provided no addresses; ignoring", p);
+    gpr_log(GPR_ERROR, "[RR %p] update provided no addresses; ignoring", this);
     // If we don't have a current subchannel list, go into TRANSIENT_FAILURE.
     // Otherwise, keep using the current subchannel list (ignore this update).
-    if (p->subchannel_list == nullptr) {
+    if (subchannel_list_ == nullptr) {
       grpc_connectivity_state_set(
-          &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
+          &state_tracker_, GRPC_CHANNEL_TRANSIENT_FAILURE,
           GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing update in args"),
           "rr_update_missing");
     }
@@ -543,114 +584,104 @@
   }
   grpc_lb_addresses* addresses = (grpc_lb_addresses*)arg->value.pointer.p;
   if (grpc_lb_round_robin_trace.enabled()) {
-    gpr_log(GPR_DEBUG, "[RR %p] received update with %" PRIuPTR " addresses", p,
-            addresses->num_addresses);
+    gpr_log(GPR_DEBUG, "[RR %p] received update with %" PRIuPTR " addresses",
+            this, addresses->num_addresses);
   }
   grpc_lb_subchannel_list* subchannel_list = grpc_lb_subchannel_list_create(
-      &p->base, &grpc_lb_round_robin_trace, addresses, args,
-      rr_connectivity_changed_locked);
+      this, &grpc_lb_round_robin_trace, addresses, combiner(),
+      client_channel_factory(), args, &RoundRobin::OnConnectivityChangedLocked);
   if (subchannel_list->num_subchannels == 0) {
     grpc_connectivity_state_set(
-        &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
+        &state_tracker_, GRPC_CHANNEL_TRANSIENT_FAILURE,
         GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty update"),
         "rr_update_empty");
-    if (p->subchannel_list != nullptr) {
-      grpc_lb_subchannel_list_shutdown_and_unref(p->subchannel_list,
+    if (subchannel_list_ != nullptr) {
+      grpc_lb_subchannel_list_shutdown_and_unref(subchannel_list_,
                                                  "sl_shutdown_empty_update");
     }
-    p->subchannel_list = subchannel_list;  // empty list
+    subchannel_list_ = subchannel_list;  // empty list
     return;
   }
-  if (p->started_picking) {
-    if (p->latest_pending_subchannel_list != nullptr) {
+  if (started_picking_) {
+    for (size_t i = 0; i < subchannel_list->num_subchannels; ++i) {
+      const grpc_connectivity_state subchannel_state =
+          grpc_subchannel_check_connectivity(
+              subchannel_list->subchannels[i].subchannel, nullptr);
+      // Override the default setting of IDLE for connectivity notification
+      // purposes if the subchannel is already in transient failure. Otherwise
+      // we'd be immediately notified of the IDLE-TRANSIENT_FAILURE
+      // discrepancy, attempt to re-resolve and end up here again.
+      // TODO(roth): As part of C++-ifying the subchannel_list API, design a
+      // better API for notifying the LB policy of subchannel states, which can
+      // be used both for the subchannel's initial state and for subsequent
+      // state changes. This will allow us to handle this more generally instead
+      // of special-casing TRANSIENT_FAILURE (e.g., we can also distribute any
+      // pending picks across all READY subchannels rather than sending them all
+      // to the first one).
+      if (subchannel_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
+        subchannel_list->subchannels[i].pending_connectivity_state_unsafe =
+            subchannel_list->subchannels[i].curr_connectivity_state =
+                subchannel_list->subchannels[i].prev_connectivity_state =
+                    subchannel_state;
+        --subchannel_list->num_idle;
+        ++subchannel_list->num_transient_failures;
+      }
+    }
+    if (latest_pending_subchannel_list_ != nullptr) {
       if (grpc_lb_round_robin_trace.enabled()) {
         gpr_log(GPR_DEBUG,
                 "[RR %p] Shutting down latest pending subchannel list %p, "
                 "about to be replaced by newer latest %p",
-                (void*)p, (void*)p->latest_pending_subchannel_list,
-                (void*)subchannel_list);
+                this, latest_pending_subchannel_list_, subchannel_list);
       }
       grpc_lb_subchannel_list_shutdown_and_unref(
-          p->latest_pending_subchannel_list, "sl_outdated");
+          latest_pending_subchannel_list_, "sl_outdated");
     }
-    p->latest_pending_subchannel_list = subchannel_list;
+    latest_pending_subchannel_list_ = subchannel_list;
     for (size_t i = 0; i < subchannel_list->num_subchannels; ++i) {
       /* Watch every new subchannel. A subchannel list becomes active the
        * moment one of its subchannels is READY. At that moment, we swap
        * p->subchannel_list for sd->subchannel_list, provided the subchannel
        * list is still valid (ie, isn't shutting down) */
-      grpc_lb_subchannel_list_ref_for_connectivity_watch(subchannel_list,
-                                                         "connectivity_watch");
+      SubchannelListRefForConnectivityWatch(subchannel_list,
+                                            "connectivity_watch");
       grpc_lb_subchannel_data_start_connectivity_watch(
           &subchannel_list->subchannels[i]);
     }
   } else {
     // The policy isn't picking yet. Save the update for later, disposing of
     // previous version if any.
-    if (p->subchannel_list != nullptr) {
+    if (subchannel_list_ != nullptr) {
       grpc_lb_subchannel_list_shutdown_and_unref(
-          p->subchannel_list, "rr_update_before_started_picking");
+          subchannel_list_, "rr_update_before_started_picking");
     }
-    p->subchannel_list = subchannel_list;
+    subchannel_list_ = subchannel_list;
   }
 }
 
-static void rr_set_reresolve_closure_locked(
-    grpc_lb_policy* policy, grpc_closure* request_reresolution) {
-  round_robin_lb_policy* p = (round_robin_lb_policy*)policy;
-  GPR_ASSERT(!p->shutdown);
-  GPR_ASSERT(policy->request_reresolution == nullptr);
-  policy->request_reresolution = request_reresolution;
-}
+//
+// factory
+//
 
-static const grpc_lb_policy_vtable round_robin_lb_policy_vtable = {
-    rr_destroy,
-    rr_shutdown_locked,
-    rr_pick_locked,
-    rr_cancel_pick_locked,
-    rr_cancel_picks_locked,
-    rr_ping_one_locked,
-    rr_exit_idle_locked,
-    rr_check_connectivity_locked,
-    rr_notify_on_state_change_locked,
-    rr_update_locked,
-    rr_set_reresolve_closure_locked};
-
-static void round_robin_factory_ref(grpc_lb_policy_factory* factory) {}
-
-static void round_robin_factory_unref(grpc_lb_policy_factory* factory) {}
-
-static grpc_lb_policy* round_robin_create(grpc_lb_policy_factory* factory,
-                                          grpc_lb_policy_args* args) {
-  GPR_ASSERT(args->client_channel_factory != nullptr);
-  round_robin_lb_policy* p = (round_robin_lb_policy*)gpr_zalloc(sizeof(*p));
-  grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable, args->combiner);
-  grpc_subchannel_index_ref();
-  grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE,
-                               "round_robin");
-  rr_update_locked(&p->base, args);
-  if (grpc_lb_round_robin_trace.enabled()) {
-    gpr_log(GPR_DEBUG, "[RR %p] Created with %lu subchannels", (void*)p,
-            (unsigned long)p->subchannel_list->num_subchannels);
+class RoundRobinFactory : public LoadBalancingPolicyFactory {
+ public:
+  OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
+      const LoadBalancingPolicy::Args& args) const override {
+    return OrphanablePtr<LoadBalancingPolicy>(New<RoundRobin>(args));
   }
-  return &p->base;
-}
 
-static const grpc_lb_policy_factory_vtable round_robin_factory_vtable = {
-    round_robin_factory_ref, round_robin_factory_unref, round_robin_create,
-    "round_robin"};
+  const char* name() const override { return "round_robin"; }
+};
 
-static grpc_lb_policy_factory round_robin_lb_policy_factory = {
-    &round_robin_factory_vtable};
+}  // namespace
 
-static grpc_lb_policy_factory* round_robin_lb_factory_create() {
-  return &round_robin_lb_policy_factory;
-}
-
-/* Plugin registration */
+}  // namespace grpc_core
 
 void grpc_lb_policy_round_robin_init() {
-  grpc_register_lb_policy(round_robin_lb_factory_create());
+  grpc_core::LoadBalancingPolicyRegistry::Builder::
+      RegisterLoadBalancingPolicyFactory(
+          grpc_core::UniquePtr<grpc_core::LoadBalancingPolicyFactory>(
+              grpc_core::New<grpc_core::RoundRobinFactory>()));
 }
 
 void grpc_lb_policy_round_robin_shutdown() {}
diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc
index fa2ffcc..79cb64c 100644
--- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <string.h>
 
 #include <grpc/support/alloc.h>
@@ -37,7 +39,7 @@
               " (subchannel %p): unreffing subchannel",
               sd->subchannel_list->tracer->name(), sd->subchannel_list->policy,
               sd->subchannel_list,
-              (size_t)(sd - sd->subchannel_list->subchannels),
+              static_cast<size_t>(sd - sd->subchannel_list->subchannels),
               sd->subchannel_list->num_subchannels, sd->subchannel);
     }
     GRPC_SUBCHANNEL_UNREF(sd->subchannel, reason);
@@ -54,17 +56,20 @@
 void grpc_lb_subchannel_data_start_connectivity_watch(
     grpc_lb_subchannel_data* sd) {
   if (sd->subchannel_list->tracer->enabled()) {
-    gpr_log(GPR_DEBUG,
-            "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
-            " (subchannel %p): requesting connectivity change notification",
-            sd->subchannel_list->tracer->name(), sd->subchannel_list->policy,
-            sd->subchannel_list,
-            (size_t)(sd - sd->subchannel_list->subchannels),
-            sd->subchannel_list->num_subchannels, sd->subchannel);
+    gpr_log(
+        GPR_DEBUG,
+        "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
+        " (subchannel %p): requesting connectivity change "
+        "notification (from %s)",
+        sd->subchannel_list->tracer->name(), sd->subchannel_list->policy,
+        sd->subchannel_list,
+        static_cast<size_t>(sd - sd->subchannel_list->subchannels),
+        sd->subchannel_list->num_subchannels, sd->subchannel,
+        grpc_connectivity_state_name(sd->pending_connectivity_state_unsafe));
   }
   sd->connectivity_notification_pending = true;
   grpc_subchannel_notify_on_state_change(
-      sd->subchannel, sd->subchannel_list->policy->interested_parties,
+      sd->subchannel, sd->subchannel_list->policy->interested_parties(),
       &sd->pending_connectivity_state_unsafe,
       &sd->connectivity_changed_closure);
 }
@@ -77,7 +82,7 @@
             " (subchannel %p): stopping connectivity watch",
             sd->subchannel_list->tracer->name(), sd->subchannel_list->policy,
             sd->subchannel_list,
-            (size_t)(sd - sd->subchannel_list->subchannels),
+            static_cast<size_t>(sd - sd->subchannel_list->subchannels),
             sd->subchannel_list->num_subchannels, sd->subchannel);
   }
   GPR_ASSERT(sd->connectivity_notification_pending);
@@ -85,11 +90,13 @@
 }
 
 grpc_lb_subchannel_list* grpc_lb_subchannel_list_create(
-    grpc_lb_policy* p, grpc_core::TraceFlag* tracer,
-    const grpc_lb_addresses* addresses, const grpc_lb_policy_args* args,
-    grpc_iomgr_cb_func connectivity_changed_cb) {
+    grpc_core::LoadBalancingPolicy* p, grpc_core::TraceFlag* tracer,
+    const grpc_lb_addresses* addresses, grpc_combiner* combiner,
+    grpc_client_channel_factory* client_channel_factory,
+    const grpc_channel_args& args, grpc_iomgr_cb_func connectivity_changed_cb) {
   grpc_lb_subchannel_list* subchannel_list =
-      (grpc_lb_subchannel_list*)gpr_zalloc(sizeof(*subchannel_list));
+      static_cast<grpc_lb_subchannel_list*>(
+          gpr_zalloc(sizeof(*subchannel_list)));
   if (tracer->enabled()) {
     gpr_log(GPR_DEBUG,
             "[%s %p] Creating subchannel list %p for %" PRIuPTR " subchannels",
@@ -98,8 +105,8 @@
   subchannel_list->policy = p;
   subchannel_list->tracer = tracer;
   gpr_ref_init(&subchannel_list->refcount, 1);
-  subchannel_list->subchannels = (grpc_lb_subchannel_data*)gpr_zalloc(
-      sizeof(grpc_lb_subchannel_data) * addresses->num_addresses);
+  subchannel_list->subchannels = static_cast<grpc_lb_subchannel_data*>(
+      gpr_zalloc(sizeof(grpc_lb_subchannel_data) * addresses->num_addresses));
   // We need to remove the LB addresses in order to be able to compare the
   // subchannel keys of subchannels from a different batch of addresses.
   static const char* keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS,
@@ -114,12 +121,11 @@
     grpc_arg addr_arg =
         grpc_create_subchannel_address_arg(&addresses->addresses[i].address);
     grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove(
-        args->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &addr_arg,
-        1);
+        &args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &addr_arg, 1);
     gpr_free(addr_arg.value.string);
     sc_args.args = new_args;
     grpc_subchannel* subchannel = grpc_client_channel_factory_create_subchannel(
-        args->client_channel_factory, &sc_args);
+        client_channel_factory, &sc_args);
     grpc_channel_args_destroy(new_args);
     if (subchannel == nullptr) {
       // Subchannel could not be created.
@@ -150,7 +156,7 @@
     sd->subchannel = subchannel;
     GRPC_CLOSURE_INIT(&sd->connectivity_changed_closure,
                       connectivity_changed_cb, sd,
-                      grpc_combiner_scheduler(args->combiner));
+                      grpc_combiner_scheduler(combiner));
     // We assume that the current state is IDLE.  If not, we'll get a
     // callback telling us that.
     sd->prev_connectivity_state = GRPC_CHANNEL_IDLE;
@@ -188,8 +194,8 @@
     const gpr_atm count = gpr_atm_acq_load(&subchannel_list->refcount.count);
     gpr_log(GPR_DEBUG, "[%s %p] subchannel_list %p REF %lu->%lu (%s)",
             subchannel_list->tracer->name(), subchannel_list->policy,
-            subchannel_list, (unsigned long)(count - 1), (unsigned long)count,
-            reason);
+            subchannel_list, static_cast<unsigned long>(count - 1),
+            static_cast<unsigned long>(count), reason);
   }
 }
 
@@ -200,26 +206,14 @@
     const gpr_atm count = gpr_atm_acq_load(&subchannel_list->refcount.count);
     gpr_log(GPR_DEBUG, "[%s %p] subchannel_list %p UNREF %lu->%lu (%s)",
             subchannel_list->tracer->name(), subchannel_list->policy,
-            subchannel_list, (unsigned long)(count + 1), (unsigned long)count,
-            reason);
+            subchannel_list, static_cast<unsigned long>(count + 1),
+            static_cast<unsigned long>(count), reason);
   }
   if (done) {
     subchannel_list_destroy(subchannel_list);
   }
 }
 
-void grpc_lb_subchannel_list_ref_for_connectivity_watch(
-    grpc_lb_subchannel_list* subchannel_list, const char* reason) {
-  GRPC_LB_POLICY_REF(subchannel_list->policy, reason);
-  grpc_lb_subchannel_list_ref(subchannel_list, reason);
-}
-
-void grpc_lb_subchannel_list_unref_for_connectivity_watch(
-    grpc_lb_subchannel_list* subchannel_list, const char* reason) {
-  GRPC_LB_POLICY_UNREF(subchannel_list->policy, reason);
-  grpc_lb_subchannel_list_unref(subchannel_list, reason);
-}
-
 static void subchannel_data_cancel_connectivity_watch(
     grpc_lb_subchannel_data* sd, const char* reason) {
   if (sd->subchannel_list->tracer->enabled()) {
@@ -228,7 +222,7 @@
             " (subchannel %p): canceling connectivity watch (%s)",
             sd->subchannel_list->tracer->name(), sd->subchannel_list->policy,
             sd->subchannel_list,
-            (size_t)(sd - sd->subchannel_list->subchannels),
+            static_cast<size_t>(sd - sd->subchannel_list->subchannels),
             sd->subchannel_list->num_subchannels, sd->subchannel, reason);
   }
   grpc_subchannel_notify_on_state_change(sd->subchannel, nullptr, nullptr,
diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
index 3377605..6889d59 100644
--- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
+++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_SUBCHANNEL_LIST_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_SUBCHANNEL_LIST_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
 #include "src/core/ext/filters/client_channel/subchannel.h"
 #include "src/core/lib/debug/trace.h"
@@ -82,7 +84,7 @@
 
 struct grpc_lb_subchannel_list {
   /** backpointer to owning policy */
-  grpc_lb_policy* policy;
+  grpc_core::LoadBalancingPolicy* policy;
 
   grpc_core::TraceFlag* tracer;
 
@@ -101,8 +103,6 @@
   size_t num_ready;
   /** how many subchannels are in state TRANSIENT_FAILURE */
   size_t num_transient_failures;
-  /** how many subchannels are in state SHUTDOWN */
-  size_t num_shutdown;
   /** how many subchannels are in state IDLE */
   size_t num_idle;
 
@@ -117,9 +117,10 @@
 };
 
 grpc_lb_subchannel_list* grpc_lb_subchannel_list_create(
-    grpc_lb_policy* p, grpc_core::TraceFlag* tracer,
-    const grpc_lb_addresses* addresses, const grpc_lb_policy_args* args,
-    grpc_iomgr_cb_func connectivity_changed_cb);
+    grpc_core::LoadBalancingPolicy* p, grpc_core::TraceFlag* tracer,
+    const grpc_lb_addresses* addresses, grpc_combiner* combiner,
+    grpc_client_channel_factory* client_channel_factory,
+    const grpc_channel_args& args, grpc_iomgr_cb_func connectivity_changed_cb);
 
 void grpc_lb_subchannel_list_ref(grpc_lb_subchannel_list* subchannel_list,
                                  const char* reason);
@@ -127,13 +128,6 @@
 void grpc_lb_subchannel_list_unref(grpc_lb_subchannel_list* subchannel_list,
                                    const char* reason);
 
-/// Takes and releases refs needed for a connectivity notification.
-/// This includes a ref to subchannel_list and a weak ref to the LB policy.
-void grpc_lb_subchannel_list_ref_for_connectivity_watch(
-    grpc_lb_subchannel_list* subchannel_list, const char* reason);
-void grpc_lb_subchannel_list_unref_for_connectivity_watch(
-    grpc_lb_subchannel_list* subchannel_list, const char* reason);
-
 /// Mark subchannel_list as discarded. Unsubscribes all its subchannels. The
 /// connectivity state notification callback will ultimately unref it.
 void grpc_lb_subchannel_list_shutdown_and_unref(
diff --git a/src/core/ext/filters/client_channel/lb_policy_factory.cc b/src/core/ext/filters/client_channel/lb_policy_factory.cc
index dbf69fd..7c8cba5 100644
--- a/src/core/ext/filters/client_channel/lb_policy_factory.cc
+++ b/src/core/ext/filters/client_channel/lb_policy_factory.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <string.h>
 
 #include <grpc/support/alloc.h>
@@ -29,11 +31,12 @@
 grpc_lb_addresses* grpc_lb_addresses_create(
     size_t num_addresses, const grpc_lb_user_data_vtable* user_data_vtable) {
   grpc_lb_addresses* addresses =
-      (grpc_lb_addresses*)gpr_zalloc(sizeof(grpc_lb_addresses));
+      static_cast<grpc_lb_addresses*>(gpr_zalloc(sizeof(grpc_lb_addresses)));
   addresses->num_addresses = num_addresses;
   addresses->user_data_vtable = user_data_vtable;
   const size_t addresses_size = sizeof(grpc_lb_address) * num_addresses;
-  addresses->addresses = (grpc_lb_address*)gpr_zalloc(addresses_size);
+  addresses->addresses =
+      static_cast<grpc_lb_address*>(gpr_zalloc(addresses_size));
   return addresses;
 }
 
@@ -63,7 +66,7 @@
   if (user_data != nullptr) GPR_ASSERT(addresses->user_data_vtable != nullptr);
   grpc_lb_address* target = &addresses->addresses[index];
   memcpy(target->address.addr, address, address_len);
-  target->address.len = address_len;
+  target->address.len = static_cast<socklen_t>(address_len);
   target->is_balancer = is_balancer;
   target->balancer_name = gpr_strdup(balancer_name);
   target->user_data = user_data;
@@ -124,14 +127,14 @@
 }
 
 static void* lb_addresses_copy(void* addresses) {
-  return grpc_lb_addresses_copy((grpc_lb_addresses*)addresses);
+  return grpc_lb_addresses_copy(static_cast<grpc_lb_addresses*>(addresses));
 }
 static void lb_addresses_destroy(void* addresses) {
-  grpc_lb_addresses_destroy((grpc_lb_addresses*)addresses);
+  grpc_lb_addresses_destroy(static_cast<grpc_lb_addresses*>(addresses));
 }
 static int lb_addresses_cmp(void* addresses1, void* addresses2) {
-  return grpc_lb_addresses_cmp((grpc_lb_addresses*)addresses1,
-                               (grpc_lb_addresses*)addresses2);
+  return grpc_lb_addresses_cmp(static_cast<grpc_lb_addresses*>(addresses1),
+                               static_cast<grpc_lb_addresses*>(addresses2));
 }
 static const grpc_arg_pointer_vtable lb_addresses_arg_vtable = {
     lb_addresses_copy, lb_addresses_destroy, lb_addresses_cmp};
@@ -148,19 +151,5 @@
       grpc_channel_args_find(channel_args, GRPC_ARG_LB_ADDRESSES);
   if (lb_addresses_arg == nullptr || lb_addresses_arg->type != GRPC_ARG_POINTER)
     return nullptr;
-  return (grpc_lb_addresses*)lb_addresses_arg->value.pointer.p;
-}
-
-void grpc_lb_policy_factory_ref(grpc_lb_policy_factory* factory) {
-  factory->vtable->ref(factory);
-}
-
-void grpc_lb_policy_factory_unref(grpc_lb_policy_factory* factory) {
-  factory->vtable->unref(factory);
-}
-
-grpc_lb_policy* grpc_lb_policy_factory_create_lb_policy(
-    grpc_lb_policy_factory* factory, grpc_lb_policy_args* args) {
-  if (factory == nullptr) return nullptr;
-  return factory->vtable->create_lb_policy(factory, args);
+  return static_cast<grpc_lb_addresses*>(lb_addresses_arg->value.pointer.p);
 }
diff --git a/src/core/ext/filters/client_channel/lb_policy_factory.h b/src/core/ext/filters/client_channel/lb_policy_factory.h
index 9da231b..6440258 100644
--- a/src/core/ext/filters/client_channel/lb_policy_factory.h
+++ b/src/core/ext/filters/client_channel/lb_policy_factory.h
@@ -19,28 +19,28 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_FACTORY_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_FACTORY_H
 
-#include "src/core/lib/iomgr/exec_ctx.h"
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/resolve_address.h"
 
 #include "src/core/ext/filters/client_channel/client_channel_factory.h"
 #include "src/core/ext/filters/client_channel/lb_policy.h"
 #include "src/core/ext/filters/client_channel/uri_parser.h"
 
+//
+// representation of an LB address
+//
+
 // Channel arg key for grpc_lb_addresses.
 #define GRPC_ARG_LB_ADDRESSES "grpc.lb_addresses"
 
-typedef struct grpc_lb_policy_factory grpc_lb_policy_factory;
-typedef struct grpc_lb_policy_factory_vtable grpc_lb_policy_factory_vtable;
-
-struct grpc_lb_policy_factory {
-  const grpc_lb_policy_factory_vtable* vtable;
-};
-
 /** A resolved address alongside any LB related information associated with it.
  * \a user_data, if not NULL, contains opaque data meant to be consumed by the
  * gRPC LB policy. Note that no all LB policies support \a user_data as input.
  * Those who don't will simply ignore it and will correspondingly return NULL in
  * their namesake pick() output argument. */
+// TODO(roth): Once we figure out a better way of handling user_data in
+// LB policies, convert these structs to C++ classes.
 typedef struct grpc_lb_address {
   grpc_resolved_address address;
   bool is_balancer;
@@ -101,30 +101,27 @@
 grpc_lb_addresses* grpc_lb_addresses_find_channel_arg(
     const grpc_channel_args* channel_args);
 
-/** Arguments passed to LB policies. */
-struct grpc_lb_policy_args {
-  grpc_client_channel_factory* client_channel_factory;
-  grpc_channel_args* args;
-  grpc_combiner* combiner;
+//
+// LB policy factory
+//
+
+namespace grpc_core {
+
+class LoadBalancingPolicyFactory {
+ public:
+  /// Returns a new LB policy instance.
+  virtual OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
+      const LoadBalancingPolicy::Args& args) const GRPC_ABSTRACT;
+
+  /// Returns the LB policy name that this factory provides.
+  /// Caller does NOT take ownership of result.
+  virtual const char* name() const GRPC_ABSTRACT;
+
+  virtual ~LoadBalancingPolicyFactory() {}
+
+  GRPC_ABSTRACT_BASE_CLASS
 };
 
-struct grpc_lb_policy_factory_vtable {
-  void (*ref)(grpc_lb_policy_factory* factory);
-  void (*unref)(grpc_lb_policy_factory* factory);
-
-  /** Implementation of grpc_lb_policy_factory_create_lb_policy */
-  grpc_lb_policy* (*create_lb_policy)(grpc_lb_policy_factory* factory,
-                                      grpc_lb_policy_args* args);
-
-  /** Name for the LB policy this factory implements */
-  const char* name;
-};
-
-void grpc_lb_policy_factory_ref(grpc_lb_policy_factory* factory);
-void grpc_lb_policy_factory_unref(grpc_lb_policy_factory* factory);
-
-/** Create a lb_policy instance. */
-grpc_lb_policy* grpc_lb_policy_factory_create_lb_policy(
-    grpc_lb_policy_factory* factory, grpc_lb_policy_args* args);
+}  // namespace grpc_core
 
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_FACTORY_H */
diff --git a/src/core/ext/filters/client_channel/lb_policy_registry.cc b/src/core/ext/filters/client_channel/lb_policy_registry.cc
index 8414504..d651b11 100644
--- a/src/core/ext/filters/client_channel/lb_policy_registry.cc
+++ b/src/core/ext/filters/client_channel/lb_policy_registry.cc
@@ -16,55 +16,82 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
 
 #include <string.h>
 
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/inlined_vector.h"
 
-#define MAX_POLICIES 10
+namespace grpc_core {
 
-static grpc_lb_policy_factory* g_all_of_the_lb_policies[MAX_POLICIES];
-static int g_number_of_lb_policies = 0;
+namespace {
 
-void grpc_lb_policy_registry_init(void) { g_number_of_lb_policies = 0; }
+class RegistryState {
+ public:
+  RegistryState() {}
 
-void grpc_lb_policy_registry_shutdown(void) {
-  int i;
-  for (i = 0; i < g_number_of_lb_policies; i++) {
-    grpc_lb_policy_factory_unref(g_all_of_the_lb_policies[i]);
-  }
-}
-
-void grpc_register_lb_policy(grpc_lb_policy_factory* factory) {
-  int i;
-  for (i = 0; i < g_number_of_lb_policies; i++) {
-    GPR_ASSERT(0 != gpr_stricmp(factory->vtable->name,
-                                g_all_of_the_lb_policies[i]->vtable->name));
-  }
-  GPR_ASSERT(g_number_of_lb_policies != MAX_POLICIES);
-  grpc_lb_policy_factory_ref(factory);
-  g_all_of_the_lb_policies[g_number_of_lb_policies++] = factory;
-}
-
-static grpc_lb_policy_factory* lookup_factory(const char* name) {
-  int i;
-
-  if (name == nullptr) return nullptr;
-
-  for (i = 0; i < g_number_of_lb_policies; i++) {
-    if (0 == gpr_stricmp(name, g_all_of_the_lb_policies[i]->vtable->name)) {
-      return g_all_of_the_lb_policies[i];
+  void RegisterLoadBalancingPolicyFactory(
+      UniquePtr<LoadBalancingPolicyFactory> factory) {
+    for (size_t i = 0; i < factories_.size(); ++i) {
+      GPR_ASSERT(strcmp(factories_[i]->name(), factory->name()) != 0);
     }
+    factories_.push_back(std::move(factory));
   }
 
-  return nullptr;
+  LoadBalancingPolicyFactory* GetLoadBalancingPolicyFactory(
+      const char* name) const {
+    for (size_t i = 0; i < factories_.size(); ++i) {
+      if (strcmp(name, factories_[i]->name()) == 0) {
+        return factories_[i].get();
+      }
+    }
+    return nullptr;
+  }
+
+ private:
+  InlinedVector<UniquePtr<LoadBalancingPolicyFactory>, 10> factories_;
+};
+
+RegistryState* g_state = nullptr;
+
+}  // namespace
+
+//
+// LoadBalancingPolicyRegistry::Builder
+//
+
+void LoadBalancingPolicyRegistry::Builder::InitRegistry() {
+  if (g_state == nullptr) g_state = New<RegistryState>();
 }
 
-grpc_lb_policy* grpc_lb_policy_create(const char* name,
-                                      grpc_lb_policy_args* args) {
-  grpc_lb_policy_factory* factory = lookup_factory(name);
-  grpc_lb_policy* lb_policy =
-      grpc_lb_policy_factory_create_lb_policy(factory, args);
-  return lb_policy;
+void LoadBalancingPolicyRegistry::Builder::ShutdownRegistry() {
+  Delete(g_state);
+  g_state = nullptr;
 }
+
+void LoadBalancingPolicyRegistry::Builder::RegisterLoadBalancingPolicyFactory(
+    UniquePtr<LoadBalancingPolicyFactory> factory) {
+  InitRegistry();
+  g_state->RegisterLoadBalancingPolicyFactory(std::move(factory));
+}
+
+//
+// LoadBalancingPolicyRegistry
+//
+
+OrphanablePtr<LoadBalancingPolicy>
+LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy(
+    const char* name, const LoadBalancingPolicy::Args& args) {
+  GPR_ASSERT(g_state != nullptr);
+  // Find factory.
+  LoadBalancingPolicyFactory* factory =
+      g_state->GetLoadBalancingPolicyFactory(name);
+  if (factory == nullptr) return nullptr;  // Specified name not found.
+  // Create policy via factory.
+  return factory->CreateLoadBalancingPolicy(args);
+}
+
+}  // namespace grpc_core
diff --git a/src/core/ext/filters/client_channel/lb_policy_registry.h b/src/core/ext/filters/client_channel/lb_policy_registry.h
index 5aff793..2e9bb06 100644
--- a/src/core/ext/filters/client_channel/lb_policy_registry.h
+++ b/src/core/ext/filters/client_channel/lb_policy_registry.h
@@ -19,22 +19,36 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/lb_policy_factory.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/gprpp/orphanable.h"
 
-/** Initialize the registry and set \a default_factory as the factory to be
- * returned when no name is provided in a lookup */
-void grpc_lb_policy_registry_init(void);
-void grpc_lb_policy_registry_shutdown(void);
+namespace grpc_core {
 
-/** Register a LB policy factory. */
-void grpc_register_lb_policy(grpc_lb_policy_factory* factory);
+class LoadBalancingPolicyRegistry {
+ public:
+  /// Methods used to create and populate the LoadBalancingPolicyRegistry.
+  /// NOT THREAD SAFE -- to be used only during global gRPC
+  /// initialization and shutdown.
+  class Builder {
+   public:
+    /// Global initialization and shutdown hooks.
+    static void InitRegistry();
+    static void ShutdownRegistry();
 
-/** Create a \a grpc_lb_policy instance.
- *
- * If \a name is NULL, the default factory from \a grpc_lb_policy_registry_init
- * will be returned. */
-grpc_lb_policy* grpc_lb_policy_create(const char* name,
-                                      grpc_lb_policy_args* args);
+    /// Registers an LB policy factory.  The factory will be used to create an
+    /// LB policy whose name matches that of the factory.
+    static void RegisterLoadBalancingPolicyFactory(
+        UniquePtr<LoadBalancingPolicyFactory> factory);
+  };
+
+  /// Creates an LB policy of the type specified by \a name.
+  static OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
+      const char* name, const LoadBalancingPolicy::Args& args);
+};
+
+}  // namespace grpc_core
 
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H */
diff --git a/src/core/ext/filters/client_channel/method_params.cc b/src/core/ext/filters/client_channel/method_params.cc
new file mode 100644
index 0000000..1f116bb
--- /dev/null
+++ b/src/core/ext/filters/client_channel/method_params.cc
@@ -0,0 +1,178 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/ext/filters/client_channel/method_params.h"
+#include "src/core/lib/channel/status_util.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/memory.h"
+
+// As per the retry design, we do not allow more than 5 retry attempts.
+#define MAX_MAX_RETRY_ATTEMPTS 5
+
+namespace grpc_core {
+namespace internal {
+
+namespace {
+
+bool ParseWaitForReady(
+    grpc_json* field, ClientChannelMethodParams::WaitForReady* wait_for_ready) {
+  if (field->type != GRPC_JSON_TRUE && field->type != GRPC_JSON_FALSE) {
+    return false;
+  }
+  *wait_for_ready = field->type == GRPC_JSON_TRUE
+                        ? ClientChannelMethodParams::WAIT_FOR_READY_TRUE
+                        : ClientChannelMethodParams::WAIT_FOR_READY_FALSE;
+  return true;
+}
+
+// Parses a JSON field of the form generated for a google.proto.Duration
+// proto message, as per:
+//   https://developers.google.com/protocol-buffers/docs/proto3#json
+bool ParseDuration(grpc_json* field, grpc_millis* duration) {
+  if (field->type != GRPC_JSON_STRING) return false;
+  size_t len = strlen(field->value);
+  if (field->value[len - 1] != 's') return false;
+  UniquePtr<char> buf(gpr_strdup(field->value));
+  *(buf.get() + len - 1) = '\0';  // Remove trailing 's'.
+  char* decimal_point = strchr(buf.get(), '.');
+  int nanos = 0;
+  if (decimal_point != nullptr) {
+    *decimal_point = '\0';
+    nanos = gpr_parse_nonnegative_int(decimal_point + 1);
+    if (nanos == -1) {
+      return false;
+    }
+    int num_digits = static_cast<int>(strlen(decimal_point + 1));
+    if (num_digits > 9) {  // We don't accept greater precision than nanos.
+      return false;
+    }
+    for (int i = 0; i < (9 - num_digits); ++i) {
+      nanos *= 10;
+    }
+  }
+  int seconds =
+      decimal_point == buf.get() ? 0 : gpr_parse_nonnegative_int(buf.get());
+  if (seconds == -1) return false;
+  *duration = seconds * GPR_MS_PER_SEC + nanos / GPR_NS_PER_MS;
+  return true;
+}
+
+UniquePtr<ClientChannelMethodParams::RetryPolicy> ParseRetryPolicy(
+    grpc_json* field) {
+  auto retry_policy = MakeUnique<ClientChannelMethodParams::RetryPolicy>();
+  if (field->type != GRPC_JSON_OBJECT) return nullptr;
+  for (grpc_json* sub_field = field->child; sub_field != nullptr;
+       sub_field = sub_field->next) {
+    if (sub_field->key == nullptr) return nullptr;
+    if (strcmp(sub_field->key, "maxAttempts") == 0) {
+      if (retry_policy->max_attempts != 0) return nullptr;  // Duplicate.
+      if (sub_field->type != GRPC_JSON_NUMBER) return nullptr;
+      retry_policy->max_attempts = gpr_parse_nonnegative_int(sub_field->value);
+      if (retry_policy->max_attempts <= 1) return nullptr;
+      if (retry_policy->max_attempts > MAX_MAX_RETRY_ATTEMPTS) {
+        gpr_log(GPR_ERROR,
+                "service config: clamped retryPolicy.maxAttempts at %d",
+                MAX_MAX_RETRY_ATTEMPTS);
+        retry_policy->max_attempts = MAX_MAX_RETRY_ATTEMPTS;
+      }
+    } else if (strcmp(sub_field->key, "initialBackoff") == 0) {
+      if (retry_policy->initial_backoff > 0) return nullptr;  // Duplicate.
+      if (!ParseDuration(sub_field, &retry_policy->initial_backoff)) {
+        return nullptr;
+      }
+      if (retry_policy->initial_backoff == 0) return nullptr;
+    } else if (strcmp(sub_field->key, "maxBackoff") == 0) {
+      if (retry_policy->max_backoff > 0) return nullptr;  // Duplicate.
+      if (!ParseDuration(sub_field, &retry_policy->max_backoff)) {
+        return nullptr;
+      }
+      if (retry_policy->max_backoff == 0) return nullptr;
+    } else if (strcmp(sub_field->key, "backoffMultiplier") == 0) {
+      if (retry_policy->backoff_multiplier != 0) return nullptr;  // Duplicate.
+      if (sub_field->type != GRPC_JSON_NUMBER) return nullptr;
+      if (sscanf(sub_field->value, "%f", &retry_policy->backoff_multiplier) !=
+          1) {
+        return nullptr;
+      }
+      if (retry_policy->backoff_multiplier <= 0) return nullptr;
+    } else if (strcmp(sub_field->key, "retryableStatusCodes") == 0) {
+      if (!retry_policy->retryable_status_codes.Empty()) {
+        return nullptr;  // Duplicate.
+      }
+      if (sub_field->type != GRPC_JSON_ARRAY) return nullptr;
+      for (grpc_json* element = sub_field->child; element != nullptr;
+           element = element->next) {
+        if (element->type != GRPC_JSON_STRING) return nullptr;
+        grpc_status_code status;
+        if (!grpc_status_code_from_string(element->value, &status)) {
+          return nullptr;
+        }
+        retry_policy->retryable_status_codes.Add(status);
+      }
+      if (retry_policy->retryable_status_codes.Empty()) return nullptr;
+    }
+  }
+  // Make sure required fields are set.
+  if (retry_policy->max_attempts == 0 || retry_policy->initial_backoff == 0 ||
+      retry_policy->max_backoff == 0 || retry_policy->backoff_multiplier == 0 ||
+      retry_policy->retryable_status_codes.Empty()) {
+    return nullptr;
+  }
+  return retry_policy;
+}
+
+}  // namespace
+
+RefCountedPtr<ClientChannelMethodParams>
+ClientChannelMethodParams::CreateFromJson(const grpc_json* json) {
+  RefCountedPtr<ClientChannelMethodParams> method_params =
+      MakeRefCounted<ClientChannelMethodParams>();
+  for (grpc_json* field = json->child; field != nullptr; field = field->next) {
+    if (field->key == nullptr) continue;
+    if (strcmp(field->key, "waitForReady") == 0) {
+      if (method_params->wait_for_ready_ != WAIT_FOR_READY_UNSET) {
+        return nullptr;  // Duplicate.
+      }
+      if (!ParseWaitForReady(field, &method_params->wait_for_ready_)) {
+        return nullptr;
+      }
+    } else if (strcmp(field->key, "timeout") == 0) {
+      if (method_params->timeout_ > 0) return nullptr;  // Duplicate.
+      if (!ParseDuration(field, &method_params->timeout_)) return nullptr;
+    } else if (strcmp(field->key, "retryPolicy") == 0) {
+      if (method_params->retry_policy_ != nullptr) {
+        return nullptr;  // Duplicate.
+      }
+      method_params->retry_policy_ = ParseRetryPolicy(field);
+      if (method_params->retry_policy_ == nullptr) return nullptr;
+    }
+  }
+  return method_params;
+}
+
+}  // namespace internal
+}  // namespace grpc_core
diff --git a/src/core/ext/filters/client_channel/method_params.h b/src/core/ext/filters/client_channel/method_params.h
new file mode 100644
index 0000000..099924e
--- /dev/null
+++ b/src/core/ext/filters/client_channel/method_params.h
@@ -0,0 +1,74 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_METHOD_PARAMS_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_METHOD_PARAMS_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/channel/status_util.h"
+#include "src/core/lib/gprpp/ref_counted.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
+#include "src/core/lib/iomgr/exec_ctx.h"  // for grpc_millis
+#include "src/core/lib/json/json.h"
+
+namespace grpc_core {
+namespace internal {
+
+class ClientChannelMethodParams : public RefCounted<ClientChannelMethodParams> {
+ public:
+  enum WaitForReady {
+    WAIT_FOR_READY_UNSET = 0,
+    WAIT_FOR_READY_FALSE,
+    WAIT_FOR_READY_TRUE
+  };
+
+  struct RetryPolicy {
+    int max_attempts = 0;
+    grpc_millis initial_backoff = 0;
+    grpc_millis max_backoff = 0;
+    float backoff_multiplier = 0;
+    StatusCodeSet retryable_status_codes;
+  };
+
+  /// Creates a method_parameters object from \a json.
+  /// Intended for use with ServiceConfig::CreateMethodConfigTable().
+  static RefCountedPtr<ClientChannelMethodParams> CreateFromJson(
+      const grpc_json* json);
+
+  grpc_millis timeout() const { return timeout_; }
+  WaitForReady wait_for_ready() const { return wait_for_ready_; }
+  const RetryPolicy* retry_policy() const { return retry_policy_.get(); }
+
+ private:
+  // So New() can call our private ctor.
+  template <typename T, typename... Args>
+  friend T* grpc_core::New(Args&&... args);
+
+  ClientChannelMethodParams() {}
+  virtual ~ClientChannelMethodParams() {}
+
+  grpc_millis timeout_ = 0;
+  WaitForReady wait_for_ready_ = WAIT_FOR_READY_UNSET;
+  UniquePtr<RetryPolicy> retry_policy_;
+};
+
+}  // namespace internal
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_METHOD_PARAMS_H */
diff --git a/src/core/ext/filters/client_channel/parse_address.cc b/src/core/ext/filters/client_channel/parse_address.cc
index c3309e3..b390011 100644
--- a/src/core/ext/filters/client_channel/parse_address.cc
+++ b/src/core/ext/filters/client_channel/parse_address.cc
@@ -16,8 +16,11 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/parse_address.h"
 #include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/iomgr/socket_utils.h"
 
 #include <stdio.h>
 #include <string.h>
@@ -26,9 +29,10 @@
 #endif
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
+
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
 
 #ifdef GRPC_HAVE_UNIX_SOCKET
@@ -39,13 +43,14 @@
     gpr_log(GPR_ERROR, "Expected 'unix' scheme, got '%s'", uri->scheme);
     return false;
   }
-  struct sockaddr_un* un = (struct sockaddr_un*)resolved_addr->addr;
+  struct sockaddr_un* un =
+      reinterpret_cast<struct sockaddr_un*>(resolved_addr->addr);
   const size_t maxlen = sizeof(un->sun_path);
   const size_t path_len = strnlen(uri->path, maxlen);
   if (path_len == maxlen) return false;
   un->sun_family = AF_UNIX;
   strcpy(un->sun_path, uri->path);
-  resolved_addr->len = sizeof(*un);
+  resolved_addr->len = static_cast<socklen_t>(sizeof(*un));
   return true;
 }
 
@@ -67,10 +72,10 @@
   if (!gpr_split_host_port(hostport, &host, &port)) return false;
   // Parse IP address.
   memset(addr, 0, sizeof(*addr));
-  addr->len = sizeof(struct sockaddr_in);
-  struct sockaddr_in* in = (struct sockaddr_in*)addr->addr;
-  in->sin_family = AF_INET;
-  if (inet_pton(AF_INET, host, &in->sin_addr) == 0) {
+  addr->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in));
+  grpc_sockaddr_in* in = reinterpret_cast<grpc_sockaddr_in*>(addr->addr);
+  in->sin_family = GRPC_AF_INET;
+  if (grpc_inet_pton(GRPC_AF_INET, host, &in->sin_addr) == 0) {
     if (log_errors) gpr_log(GPR_ERROR, "invalid ipv4 address: '%s'", host);
     goto done;
   }
@@ -84,7 +89,7 @@
     if (log_errors) gpr_log(GPR_ERROR, "invalid ipv4 port: '%s'", port);
     goto done;
   }
-  in->sin_port = htons((uint16_t)port_num);
+  in->sin_port = grpc_htons(static_cast<uint16_t>(port_num));
   success = true;
 done:
   gpr_free(host);
@@ -113,19 +118,20 @@
   if (!gpr_split_host_port(hostport, &host, &port)) return false;
   // Parse IP address.
   memset(addr, 0, sizeof(*addr));
-  addr->len = sizeof(struct sockaddr_in6);
-  struct sockaddr_in6* in6 = (struct sockaddr_in6*)addr->addr;
-  in6->sin6_family = AF_INET6;
+  addr->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in6));
+  grpc_sockaddr_in6* in6 = reinterpret_cast<grpc_sockaddr_in6*>(addr->addr);
+  in6->sin6_family = GRPC_AF_INET6;
   // Handle the RFC6874 syntax for IPv6 zone identifiers.
-  char* host_end = (char*)gpr_memrchr(host, '%', strlen(host));
+  char* host_end = static_cast<char*>(gpr_memrchr(host, '%', strlen(host)));
   if (host_end != nullptr) {
     GPR_ASSERT(host_end >= host);
-    char host_without_scope[INET6_ADDRSTRLEN];
-    size_t host_without_scope_len = (size_t)(host_end - host);
+    char host_without_scope[GRPC_INET6_ADDRSTRLEN];
+    size_t host_without_scope_len = static_cast<size_t>(host_end - host);
     uint32_t sin6_scope_id = 0;
     strncpy(host_without_scope, host, host_without_scope_len);
     host_without_scope[host_without_scope_len] = '\0';
-    if (inet_pton(AF_INET6, host_without_scope, &in6->sin6_addr) == 0) {
+    if (grpc_inet_pton(GRPC_AF_INET6, host_without_scope, &in6->sin6_addr) ==
+        0) {
       gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host_without_scope);
       goto done;
     }
@@ -138,7 +144,7 @@
     // Handle "sin6_scope_id" being type "u_long". See grpc issue #10027.
     in6->sin6_scope_id = sin6_scope_id;
   } else {
-    if (inet_pton(AF_INET6, host, &in6->sin6_addr) == 0) {
+    if (grpc_inet_pton(GRPC_AF_INET6, host, &in6->sin6_addr) == 0) {
       gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host);
       goto done;
     }
@@ -153,7 +159,7 @@
     if (log_errors) gpr_log(GPR_ERROR, "invalid ipv6 port: '%s'", port);
     goto done;
   }
-  in6->sin6_port = htons((uint16_t)port_num);
+  in6->sin6_port = grpc_htons(static_cast<uint16_t>(port_num));
   success = true;
 done:
   gpr_free(host);
diff --git a/src/core/ext/filters/client_channel/parse_address.h b/src/core/ext/filters/client_channel/parse_address.h
index ca0a0d1..9a88b66 100644
--- a/src/core/ext/filters/client_channel/parse_address.h
+++ b/src/core/ext/filters/client_channel/parse_address.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PARSE_ADDRESS_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PARSE_ADDRESS_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stddef.h>
 
 #include "src/core/ext/filters/client_channel/uri_parser.h"
diff --git a/src/core/ext/filters/client_channel/proxy_mapper.cc b/src/core/ext/filters/client_channel/proxy_mapper.cc
index be85cfc..c4da067 100644
--- a/src/core/ext/filters/client_channel/proxy_mapper.cc
+++ b/src/core/ext/filters/client_channel/proxy_mapper.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/proxy_mapper.h"
 
 void grpc_proxy_mapper_init(const grpc_proxy_mapper_vtable* vtable,
diff --git a/src/core/ext/filters/client_channel/proxy_mapper.h b/src/core/ext/filters/client_channel/proxy_mapper.h
index ce3e65e..634b0ed 100644
--- a/src/core/ext/filters/client_channel/proxy_mapper.h
+++ b/src/core/ext/filters/client_channel/proxy_mapper.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PROXY_MAPPER_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PROXY_MAPPER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stdbool.h>
 
 #include <grpc/impl/codegen/grpc_types.h>
diff --git a/src/core/ext/filters/client_channel/proxy_mapper_registry.cc b/src/core/ext/filters/client_channel/proxy_mapper_registry.cc
index 51778a2..a02a5f5 100644
--- a/src/core/ext/filters/client_channel/proxy_mapper_registry.cc
+++ b/src/core/ext/filters/client_channel/proxy_mapper_registry.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
 
 #include <string.h>
@@ -34,8 +36,8 @@
 static void grpc_proxy_mapper_list_register(grpc_proxy_mapper_list* list,
                                             bool at_start,
                                             grpc_proxy_mapper* mapper) {
-  list->list = (grpc_proxy_mapper**)gpr_realloc(
-      list->list, (list->num_mappers + 1) * sizeof(grpc_proxy_mapper*));
+  list->list = static_cast<grpc_proxy_mapper**>(gpr_realloc(
+      list->list, (list->num_mappers + 1) * sizeof(grpc_proxy_mapper*)));
   if (at_start) {
     memmove(list->list + 1, list->list,
             sizeof(grpc_proxy_mapper*) * list->num_mappers);
diff --git a/src/core/ext/filters/client_channel/proxy_mapper_registry.h b/src/core/ext/filters/client_channel/proxy_mapper_registry.h
index 2ad6c04..326b582 100644
--- a/src/core/ext/filters/client_channel/proxy_mapper_registry.h
+++ b/src/core/ext/filters/client_channel/proxy_mapper_registry.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PROXY_MAPPER_REGISTRY_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PROXY_MAPPER_REGISTRY_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/proxy_mapper.h"
 
 void grpc_proxy_mapper_registry_init();
diff --git a/src/core/ext/filters/client_channel/resolver.cc b/src/core/ext/filters/client_channel/resolver.cc
index ff54e71..cd11eeb 100644
--- a/src/core/ext/filters/client_channel/resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver.cc
@@ -16,64 +16,20 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/resolver.h"
 #include "src/core/lib/iomgr/combiner.h"
 
 grpc_core::DebugOnlyTraceFlag grpc_trace_resolver_refcount(false,
                                                            "resolver_refcount");
 
-void grpc_resolver_init(grpc_resolver* resolver,
-                        const grpc_resolver_vtable* vtable,
-                        grpc_combiner* combiner) {
-  resolver->vtable = vtable;
-  resolver->combiner = GRPC_COMBINER_REF(combiner, "resolver");
-  gpr_ref_init(&resolver->refs, 1);
-}
+namespace grpc_core {
 
-#ifndef NDEBUG
-void grpc_resolver_ref(grpc_resolver* resolver, const char* file, int line,
-                       const char* reason) {
-  if (grpc_trace_resolver_refcount.enabled()) {
-    gpr_atm old_refs = gpr_atm_no_barrier_load(&resolver->refs.count);
-    gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
-            "RESOLVER:%p   ref %" PRIdPTR " -> %" PRIdPTR " %s", resolver,
-            old_refs, old_refs + 1, reason);
-  }
-#else
-void grpc_resolver_ref(grpc_resolver* resolver) {
-#endif
-  gpr_ref(&resolver->refs);
-}
+Resolver::Resolver(grpc_combiner* combiner)
+    : InternallyRefCountedWithTracing(&grpc_trace_resolver_refcount),
+      combiner_(GRPC_COMBINER_REF(combiner, "resolver")) {}
 
-#ifndef NDEBUG
-void grpc_resolver_unref(grpc_resolver* resolver, const char* file, int line,
-                         const char* reason) {
-  if (grpc_trace_resolver_refcount.enabled()) {
-    gpr_atm old_refs = gpr_atm_no_barrier_load(&resolver->refs.count);
-    gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
-            "RESOLVER:%p unref %" PRIdPTR " -> %" PRIdPTR " %s", resolver,
-            old_refs, old_refs - 1, reason);
-  }
-#else
-void grpc_resolver_unref(grpc_resolver* resolver) {
-#endif
-  if (gpr_unref(&resolver->refs)) {
-    grpc_combiner* combiner = resolver->combiner;
-    resolver->vtable->destroy(resolver);
-    GRPC_COMBINER_UNREF(combiner, "resolver");
-  }
-}
+Resolver::~Resolver() { GRPC_COMBINER_UNREF(combiner_, "resolver"); }
 
-void grpc_resolver_shutdown_locked(grpc_resolver* resolver) {
-  resolver->vtable->shutdown_locked(resolver);
-}
-
-void grpc_resolver_channel_saw_error_locked(grpc_resolver* resolver) {
-  resolver->vtable->channel_saw_error_locked(resolver);
-}
-
-void grpc_resolver_next_locked(grpc_resolver* resolver,
-                               grpc_channel_args** result,
-                               grpc_closure* on_complete) {
-  resolver->vtable->next_locked(resolver, result, on_complete);
-}
+}  // namespace grpc_core
diff --git a/src/core/ext/filters/client_channel/resolver.h b/src/core/ext/filters/client_channel/resolver.h
index f6a4af0..cdb5a20 100644
--- a/src/core/ext/filters/client_channel/resolver.h
+++ b/src/core/ext/filters/client_channel/resolver.h
@@ -19,67 +19,116 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_H
 
-#include "src/core/ext/filters/client_channel/subchannel.h"
-#include "src/core/lib/iomgr/iomgr.h"
+#include <grpc/support/port_platform.h>
 
-typedef struct grpc_resolver grpc_resolver;
-typedef struct grpc_resolver_vtable grpc_resolver_vtable;
+#include <grpc/impl/codegen/grpc_types.h>
+
+#include "src/core/lib/gprpp/abstract.h"
+#include "src/core/lib/gprpp/orphanable.h"
+#include "src/core/lib/iomgr/combiner.h"
+#include "src/core/lib/iomgr/iomgr.h"
 
 extern grpc_core::DebugOnlyTraceFlag grpc_trace_resolver_refcount;
 
-/** \a grpc_resolver provides \a grpc_channel_args objects to its caller */
-struct grpc_resolver {
-  const grpc_resolver_vtable* vtable;
-  gpr_refcount refs;
-  grpc_combiner* combiner;
+namespace grpc_core {
+
+/// Interface for name resolution.
+///
+/// This interface is designed to support both push-based and pull-based
+/// mechanisms.  A push-based mechanism is one where the resolver will
+/// subscribe to updates for a given name, and the name service will
+/// proactively send new data to the resolver whenever the data associated
+/// with the name changes.  A pull-based mechanism is one where the resolver
+/// needs to query the name service again to get updated information (e.g.,
+/// DNS).
+///
+/// Note: All methods with a "Locked" suffix must be called from the
+/// combiner passed to the constructor.
+class Resolver : public InternallyRefCountedWithTracing<Resolver> {
+ public:
+  // Not copyable nor movable.
+  Resolver(const Resolver&) = delete;
+  Resolver& operator=(const Resolver&) = delete;
+
+  /// Requests a callback when a new result becomes available.
+  /// When the new result is available, sets \a *result to the new result
+  /// and schedules \a on_complete for execution.
+  /// Upon transient failure, sets \a *result to nullptr and schedules
+  /// \a on_complete with no error.
+  /// If resolution is fatally broken, sets \a *result to nullptr and
+  /// schedules \a on_complete with an error.
+  /// TODO(roth): When we have time, improve the way this API represents
+  /// transient failure vs. shutdown.
+  ///
+  /// Note that the client channel will almost always have a request
+  /// to \a NextLocked() pending.  When it gets the callback, it will
+  /// process the new result and then immediately make another call to
+  /// \a NextLocked().  This allows push-based resolvers to provide new
+  /// data as soon as it becomes available.
+  virtual void NextLocked(grpc_channel_args** result,
+                          grpc_closure* on_complete) GRPC_ABSTRACT;
+
+  /// Asks the resolver to obtain an updated resolver result, if
+  /// applicable.
+  ///
+  /// This is useful for pull-based implementations to decide when to
+  /// re-resolve.  However, the implementation is not required to
+  /// re-resolve immediately upon receiving this call; it may instead
+  /// elect to delay based on some configured minimum time between
+  /// queries, to avoid hammering the name service with queries.
+  ///
+  /// For push-based implementations, this may be a no-op.
+  ///
+  /// If this causes new data to become available, then the currently
+  /// pending call to \a NextLocked() will return the new result.
+  ///
+  /// Note: Currently, all resolvers are required to return a new result
+  /// shortly after this method is called.  For pull-based mechanisms, if
+  /// the implementation decides to delay querying the name service, it
+  /// should immediately return a new copy of the previously returned
+  /// result (and it can then return the updated data later, when it
+  /// actually does query the name service).  For push-based mechanisms,
+  /// the implementation should immediately return a new copy of the
+  /// last-seen result.
+  /// TODO(roth): Remove this requirement once we fix pick_first to not
+  /// throw away unselected subchannels.
+  virtual void RequestReresolutionLocked() GRPC_ABSTRACT;
+
+  void Orphan() override {
+    // Invoke ShutdownAndUnrefLocked() inside of the combiner.
+    GRPC_CLOSURE_SCHED(
+        GRPC_CLOSURE_CREATE(&Resolver::ShutdownAndUnrefLocked, this,
+                            grpc_combiner_scheduler(combiner_)),
+        GRPC_ERROR_NONE);
+  }
+
+  GRPC_ABSTRACT_BASE_CLASS
+
+ protected:
+  /// Does NOT take ownership of the reference to \a combiner.
+  // TODO(roth): Once we have a C++-like interface for combiners, this
+  // API should change to take a RefCountedPtr<>, so that we always take
+  // ownership of a new ref.
+  explicit Resolver(grpc_combiner* combiner);
+
+  virtual ~Resolver();
+
+  /// Shuts down the resolver.  If there is a pending call to
+  /// NextLocked(), the callback will be scheduled with an error.
+  virtual void ShutdownLocked() GRPC_ABSTRACT;
+
+  grpc_combiner* combiner() const { return combiner_; }
+
+ private:
+  static void ShutdownAndUnrefLocked(void* arg, grpc_error* ignored) {
+    Resolver* resolver = static_cast<Resolver*>(arg);
+    resolver->ShutdownLocked();
+    resolver->Unref();
+  }
+
+  grpc_combiner* combiner_;
 };
 
-struct grpc_resolver_vtable {
-  void (*destroy)(grpc_resolver* resolver);
-  void (*shutdown_locked)(grpc_resolver* resolver);
-  void (*channel_saw_error_locked)(grpc_resolver* resolver);
-  void (*next_locked)(grpc_resolver* resolver, grpc_channel_args** result,
-                      grpc_closure* on_complete);
-};
-
-#ifndef NDEBUG
-#define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p), __FILE__, __LINE__, (r))
-#define GRPC_RESOLVER_UNREF(p, r) \
-  grpc_resolver_unref((p), __FILE__, __LINE__, (r))
-void grpc_resolver_ref(grpc_resolver* policy, const char* file, int line,
-                       const char* reason);
-void grpc_resolver_unref(grpc_resolver* policy, const char* file, int line,
-                         const char* reason);
-#else
-#define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p))
-#define GRPC_RESOLVER_UNREF(p, r) grpc_resolver_unref((p))
-void grpc_resolver_ref(grpc_resolver* policy);
-void grpc_resolver_unref(grpc_resolver* policy);
-#endif
-
-void grpc_resolver_init(grpc_resolver* resolver,
-                        const grpc_resolver_vtable* vtable,
-                        grpc_combiner* combiner);
-
-void grpc_resolver_shutdown_locked(grpc_resolver* resolver);
-
-/** Notification that the channel has seen an error on some address.
-    Can be used as a hint that re-resolution is desirable soon.
-
-    Must be called from the combiner passed as a resolver_arg at construction
-    time.*/
-void grpc_resolver_channel_saw_error_locked(grpc_resolver* resolver);
-
-/** Get the next result from the resolver.  Expected to set \a *result with
-    new channel args and then schedule \a on_complete for execution.
-
-    If resolution is fatally broken, set \a *result to NULL and
-    schedule \a on_complete.
-
-    Must be called from the combiner passed as a resolver_arg at construction
-    time.*/
-void grpc_resolver_next_locked(grpc_resolver* resolver,
-                               grpc_channel_args** result,
-                               grpc_closure* on_complete);
+}  // namespace grpc_core
 
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_H */
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
index e5b2815..aca7307 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
@@ -17,6 +17,7 @@
  */
 
 #include <grpc/support/port_platform.h>
+
 #if GRPC_ARES == 1 && !defined(GRPC_UV)
 
 #include <limits.h>
@@ -25,9 +26,10 @@
 #include <unistd.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/string_util.h>
 
+#include <address_sorting/address_sorting.h>
+
 #include "src/core/ext/filters/client_channel/http_connect_handshaker.h"
 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
@@ -35,6 +37,7 @@
 #include "src/core/lib/backoff/backoff.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/manual_constructor.h"
 #include "src/core/lib/iomgr/combiner.h"
@@ -49,109 +52,168 @@
 #define GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS 120
 #define GRPC_DNS_RECONNECT_JITTER 0.2
 
-typedef struct {
-  /** base class: must be first */
-  grpc_resolver base;
-  /** DNS server to use (if not system default) */
-  char* dns_server;
-  /** name to resolve (usually the same as target_name) */
-  char* name_to_resolve;
-  /** default port to use */
-  char* default_port;
-  /** channel args. */
-  grpc_channel_args* channel_args;
-  /** whether to request the service config */
-  bool request_service_config;
-  /** pollset_set to drive the name resolution process */
-  grpc_pollset_set* interested_parties;
+namespace grpc_core {
 
-  /** Closures used by the combiner */
-  grpc_closure dns_ares_on_next_resolution_timer_closure;
-  grpc_closure dns_ares_on_resolved_closure;
+namespace {
 
-  /** Combiner guarding the rest of the state */
-  grpc_combiner* combiner;
-  /** are we currently resolving? */
-  bool resolving;
-  /** the pending resolving request */
-  grpc_ares_request* pending_request;
-  /** which version of the result have we published? */
-  int published_version;
-  /** which version of the result is current? */
-  int resolved_version;
-  /** pending next completion, or NULL */
-  grpc_closure* next_completion;
-  /** target result address for next completion */
-  grpc_channel_args** target_result;
-  /** current (fully resolved) result */
-  grpc_channel_args* resolved_result;
-  /** next resolution timer */
-  bool have_next_resolution_timer;
-  grpc_timer next_resolution_timer;
-  /** retry backoff state */
-  grpc_core::ManualConstructor<grpc_core::BackOff> backoff;
-  /** min resolution period. Max one resolution will happen per period */
-  grpc_millis min_time_between_resolutions;
-  /** when was the last resolution? -1 if no resolution has happened yet */
-  grpc_millis last_resolution_timestamp;
-  /** currently resolving addresses */
-  grpc_lb_addresses* lb_addresses;
-  /** currently resolving service config */
-  char* service_config_json;
-} ares_dns_resolver;
+const char kDefaultPort[] = "https";
 
-static void dns_ares_destroy(grpc_resolver* r);
+class AresDnsResolver : public Resolver {
+ public:
+  explicit AresDnsResolver(const ResolverArgs& args);
 
-static void dns_ares_start_resolving_locked(ares_dns_resolver* r);
-static void dns_ares_maybe_start_resolving_locked(ares_dns_resolver* r);
-static void dns_ares_maybe_finish_next_locked(ares_dns_resolver* r);
+  void NextLocked(grpc_channel_args** result,
+                  grpc_closure* on_complete) override;
 
-static void dns_ares_shutdown_locked(grpc_resolver* r);
-static void dns_ares_channel_saw_error_locked(grpc_resolver* r);
-static void dns_ares_next_locked(grpc_resolver* r,
-                                 grpc_channel_args** target_result,
-                                 grpc_closure* on_complete);
+  void RequestReresolutionLocked() override;
 
-static const grpc_resolver_vtable dns_ares_resolver_vtable = {
-    dns_ares_destroy, dns_ares_shutdown_locked,
-    dns_ares_channel_saw_error_locked, dns_ares_next_locked};
+  void ShutdownLocked() override;
 
-static void dns_ares_shutdown_locked(grpc_resolver* resolver) {
-  ares_dns_resolver* r = (ares_dns_resolver*)resolver;
-  if (r->have_next_resolution_timer) {
-    grpc_timer_cancel(&r->next_resolution_timer);
+ private:
+  virtual ~AresDnsResolver();
+
+  void MaybeStartResolvingLocked();
+  void StartResolvingLocked();
+  void MaybeFinishNextLocked();
+
+  static void OnNextResolutionLocked(void* arg, grpc_error* error);
+  static void OnResolvedLocked(void* arg, grpc_error* error);
+
+  /// DNS server to use (if not system default)
+  char* dns_server_;
+  /// name to resolve (usually the same as target_name)
+  char* name_to_resolve_;
+  /// channel args
+  grpc_channel_args* channel_args_;
+  /// whether to request the service config
+  bool request_service_config_;
+  /// pollset_set to drive the name resolution process
+  grpc_pollset_set* interested_parties_;
+  /// closures used by the combiner
+  grpc_closure on_next_resolution_;
+  grpc_closure on_resolved_;
+  /// are we currently resolving?
+  bool resolving_ = false;
+  /// the pending resolving request
+  grpc_ares_request* pending_request_ = nullptr;
+  /// which version of the result have we published?
+  int published_version_ = 0;
+  /// which version of the result is current?
+  int resolved_version_ = 0;
+  /// pending next completion, or NULL
+  grpc_closure* next_completion_ = nullptr;
+  /// target result address for next completion
+  grpc_channel_args** target_result_ = nullptr;
+  /// current (fully resolved) result
+  grpc_channel_args* resolved_result_ = nullptr;
+  /// next resolution timer
+  bool have_next_resolution_timer_ = false;
+  grpc_timer next_resolution_timer_;
+  /// min interval between DNS requests
+  grpc_millis min_time_between_resolutions_;
+  /// timestamp of last DNS request
+  grpc_millis last_resolution_timestamp_ = -1;
+  /// retry backoff state
+  BackOff backoff_;
+  /// currently resolving addresses
+  grpc_lb_addresses* lb_addresses_ = nullptr;
+  /// currently resolving service config
+  char* service_config_json_ = nullptr;
+};
+
+AresDnsResolver::AresDnsResolver(const ResolverArgs& args)
+    : Resolver(args.combiner),
+      backoff_(
+          BackOff::Options()
+              .set_initial_backoff(GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS *
+                                   1000)
+              .set_multiplier(GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER)
+              .set_jitter(GRPC_DNS_RECONNECT_JITTER)
+              .set_max_backoff(GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000)) {
+  // Get name to resolve from URI path.
+  const char* path = args.uri->path;
+  if (path[0] == '/') ++path;
+  name_to_resolve_ = gpr_strdup(path);
+  // Get DNS server from URI authority.
+  if (0 != strcmp(args.uri->authority, "")) {
+    dns_server_ = gpr_strdup(args.uri->authority);
   }
-  if (r->pending_request != nullptr) {
-    grpc_cancel_ares_request(r->pending_request);
+  channel_args_ = grpc_channel_args_copy(args.args);
+  const grpc_arg* arg = grpc_channel_args_find(
+      channel_args_, GRPC_ARG_SERVICE_CONFIG_DISABLE_RESOLUTION);
+  request_service_config_ = !grpc_channel_arg_get_integer(
+      arg, (grpc_integer_options){false, false, true});
+  arg = grpc_channel_args_find(channel_args_,
+                               GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS);
+  min_time_between_resolutions_ =
+      grpc_channel_arg_get_integer(arg, {1000, 0, INT_MAX});
+  interested_parties_ = grpc_pollset_set_create();
+  if (args.pollset_set != nullptr) {
+    grpc_pollset_set_add_pollset_set(interested_parties_, args.pollset_set);
   }
-  if (r->next_completion != nullptr) {
-    *r->target_result = nullptr;
-    GRPC_CLOSURE_SCHED(r->next_completion, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-                                               "Resolver Shutdown"));
-    r->next_completion = nullptr;
+  GRPC_CLOSURE_INIT(&on_next_resolution_, OnNextResolutionLocked, this,
+                    grpc_combiner_scheduler(combiner()));
+  GRPC_CLOSURE_INIT(&on_resolved_, OnResolvedLocked, this,
+                    grpc_combiner_scheduler(combiner()));
+}
+
+AresDnsResolver::~AresDnsResolver() {
+  gpr_log(GPR_DEBUG, "destroying AresDnsResolver");
+  if (resolved_result_ != nullptr) {
+    grpc_channel_args_destroy(resolved_result_);
+  }
+  grpc_pollset_set_destroy(interested_parties_);
+  gpr_free(dns_server_);
+  gpr_free(name_to_resolve_);
+  grpc_channel_args_destroy(channel_args_);
+}
+
+void AresDnsResolver::NextLocked(grpc_channel_args** target_result,
+                                 grpc_closure* on_complete) {
+  gpr_log(GPR_DEBUG, "AresDnsResolver::NextLocked() is called.");
+  GPR_ASSERT(next_completion_ == nullptr);
+  next_completion_ = on_complete;
+  target_result_ = target_result;
+  if (resolved_version_ == 0 && !resolving_) {
+    MaybeStartResolvingLocked();
+  } else {
+    MaybeFinishNextLocked();
   }
 }
 
-static void dns_ares_channel_saw_error_locked(grpc_resolver* resolver) {
-  ares_dns_resolver* r = (ares_dns_resolver*)resolver;
-  if (!r->resolving) {
-    dns_ares_maybe_start_resolving_locked(r);
+void AresDnsResolver::RequestReresolutionLocked() {
+  if (!resolving_) {
+    MaybeStartResolvingLocked();
   }
 }
 
-static void dns_ares_on_next_resolution_timer_locked(void* arg,
-                                                     grpc_error* error) {
-  ares_dns_resolver* r = (ares_dns_resolver*)arg;
-  r->have_next_resolution_timer = false;
+void AresDnsResolver::ShutdownLocked() {
+  if (have_next_resolution_timer_) {
+    grpc_timer_cancel(&next_resolution_timer_);
+  }
+  if (pending_request_ != nullptr) {
+    grpc_cancel_ares_request(pending_request_);
+  }
+  if (next_completion_ != nullptr) {
+    *target_result_ = nullptr;
+    GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                                             "Resolver Shutdown"));
+    next_completion_ = nullptr;
+  }
+}
+
+void AresDnsResolver::OnNextResolutionLocked(void* arg, grpc_error* error) {
+  AresDnsResolver* r = static_cast<AresDnsResolver*>(arg);
+  r->have_next_resolution_timer_ = false;
   if (error == GRPC_ERROR_NONE) {
-    if (!r->resolving) {
-      dns_ares_start_resolving_locked(r);
+    if (!r->resolving_) {
+      r->StartResolvingLocked();
     }
   }
-  GRPC_RESOLVER_UNREF(&r->base, "next_resolution_timer");
+  r->Unref(DEBUG_LOCATION, "next_resolution_timer");
 }
 
-static bool value_in_json_array(grpc_json* array, const char* value) {
+bool ValueInJsonArray(grpc_json* array, const char* value) {
   for (grpc_json* entry = array->child; entry != nullptr; entry = entry->next) {
     if (entry->type == GRPC_JSON_STRING && strcmp(entry->value, value) == 0) {
       return true;
@@ -160,7 +222,7 @@
   return false;
 }
 
-static char* choose_service_config(char* service_config_choice_json) {
+char* ChooseServiceConfig(char* service_config_choice_json) {
   grpc_json* choices_json = grpc_json_parse_string(service_config_choice_json);
   if (choices_json == nullptr || choices_json->type != GRPC_JSON_ARRAY) {
     gpr_log(GPR_ERROR, "cannot parse service config JSON string");
@@ -178,8 +240,7 @@
          field = field->next) {
       // Check client language, if specified.
       if (strcmp(field->key, "clientLanguage") == 0) {
-        if (field->type != GRPC_JSON_ARRAY ||
-            !value_in_json_array(field, "c++")) {
+        if (field->type != GRPC_JSON_ARRAY || !ValueInJsonArray(field, "c++")) {
           service_config_json = nullptr;
           break;
         }
@@ -188,7 +249,7 @@
       if (strcmp(field->key, "clientHostname") == 0) {
         char* hostname = grpc_gethostname();
         if (hostname == nullptr || field->type != GRPC_JSON_ARRAY ||
-            !value_in_json_array(field, hostname)) {
+            !ValueInJsonArray(field, hostname)) {
           service_config_json = nullptr;
           break;
         }
@@ -223,258 +284,204 @@
   return service_config;
 }
 
-static void dns_ares_on_resolved_locked(void* arg, grpc_error* error) {
-  ares_dns_resolver* r = (ares_dns_resolver*)arg;
+void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) {
+  AresDnsResolver* r = static_cast<AresDnsResolver*>(arg);
   grpc_channel_args* result = nullptr;
-  GPR_ASSERT(r->resolving);
-  r->resolving = false;
-  r->pending_request = nullptr;
-  if (r->lb_addresses != nullptr) {
+  GPR_ASSERT(r->resolving_);
+  r->resolving_ = false;
+  r->pending_request_ = nullptr;
+  if (r->lb_addresses_ != nullptr) {
     static const char* args_to_remove[2];
     size_t num_args_to_remove = 0;
     grpc_arg new_args[3];
     size_t num_args_to_add = 0;
     new_args[num_args_to_add++] =
-        grpc_lb_addresses_create_channel_arg(r->lb_addresses);
-    grpc_service_config* service_config = nullptr;
+        grpc_lb_addresses_create_channel_arg(r->lb_addresses_);
+    grpc_core::UniquePtr<grpc_core::ServiceConfig> service_config;
     char* service_config_string = nullptr;
-    if (r->service_config_json != nullptr) {
-      service_config_string = choose_service_config(r->service_config_json);
-      gpr_free(r->service_config_json);
+    if (r->service_config_json_ != nullptr) {
+      service_config_string = ChooseServiceConfig(r->service_config_json_);
+      gpr_free(r->service_config_json_);
       if (service_config_string != nullptr) {
         gpr_log(GPR_INFO, "selected service config choice: %s",
                 service_config_string);
         args_to_remove[num_args_to_remove++] = GRPC_ARG_SERVICE_CONFIG;
         new_args[num_args_to_add++] = grpc_channel_arg_string_create(
             (char*)GRPC_ARG_SERVICE_CONFIG, service_config_string);
-        service_config = grpc_service_config_create(service_config_string);
+        service_config =
+            grpc_core::ServiceConfig::Create(service_config_string);
         if (service_config != nullptr) {
           const char* lb_policy_name =
-              grpc_service_config_get_lb_policy_name(service_config);
+              service_config->GetLoadBalancingPolicyName();
           if (lb_policy_name != nullptr) {
             args_to_remove[num_args_to_remove++] = GRPC_ARG_LB_POLICY_NAME;
             new_args[num_args_to_add++] = grpc_channel_arg_string_create(
-                (char*)GRPC_ARG_LB_POLICY_NAME, (char*)lb_policy_name);
+                (char*)GRPC_ARG_LB_POLICY_NAME,
+                const_cast<char*>(lb_policy_name));
           }
         }
       }
     }
     result = grpc_channel_args_copy_and_add_and_remove(
-        r->channel_args, args_to_remove, num_args_to_remove, new_args,
+        r->channel_args_, args_to_remove, num_args_to_remove, new_args,
         num_args_to_add);
-    if (service_config != nullptr) grpc_service_config_destroy(service_config);
     gpr_free(service_config_string);
-    grpc_lb_addresses_destroy(r->lb_addresses);
+    grpc_lb_addresses_destroy(r->lb_addresses_);
     // Reset backoff state so that we start from the beginning when the
     // next request gets triggered.
-    r->backoff->Reset();
+    r->backoff_.Reset();
   } else {
     const char* msg = grpc_error_string(error);
     gpr_log(GPR_DEBUG, "dns resolution failed: %s", msg);
-    grpc_millis next_try = r->backoff->NextAttemptTime();
-    grpc_millis timeout = next_try - grpc_core::ExecCtx::Get()->Now();
+    grpc_millis next_try = r->backoff_.NextAttemptTime();
+    grpc_millis timeout = next_try - ExecCtx::Get()->Now();
     gpr_log(GPR_INFO, "dns resolution failed (will retry): %s",
             grpc_error_string(error));
-    GPR_ASSERT(!r->have_next_resolution_timer);
-    r->have_next_resolution_timer = true;
-    GRPC_RESOLVER_REF(&r->base, "next_resolution_timer");
+    GPR_ASSERT(!r->have_next_resolution_timer_);
+    r->have_next_resolution_timer_ = true;
+    // TODO(roth): We currently deal with this ref manually.  Once the
+    // new closure API is done, find a way to track this ref with the timer
+    // callback as part of the type system.
+    RefCountedPtr<Resolver> self = r->Ref(DEBUG_LOCATION, "retry-timer");
+    self.release();
     if (timeout > 0) {
       gpr_log(GPR_DEBUG, "retrying in %" PRIdPTR " milliseconds", timeout);
     } else {
       gpr_log(GPR_DEBUG, "retrying immediately");
     }
-    grpc_timer_init(&r->next_resolution_timer, next_try,
-                    &r->dns_ares_on_next_resolution_timer_closure);
+    grpc_timer_init(&r->next_resolution_timer_, next_try,
+                    &r->on_next_resolution_);
   }
-  if (r->resolved_result != nullptr) {
-    grpc_channel_args_destroy(r->resolved_result);
+  if (r->resolved_result_ != nullptr) {
+    grpc_channel_args_destroy(r->resolved_result_);
   }
-  r->resolved_result = result;
-  r->last_resolution_timestamp = grpc_core::ExecCtx::Get()->Now();
-  r->resolved_version++;
-  dns_ares_maybe_finish_next_locked(r);
-  GRPC_RESOLVER_UNREF(&r->base, "dns-resolving");
+  r->resolved_result_ = result;
+  ++r->resolved_version_;
+  r->MaybeFinishNextLocked();
+  r->Unref(DEBUG_LOCATION, "dns-resolving");
 }
 
-static void dns_ares_next_locked(grpc_resolver* resolver,
-                                 grpc_channel_args** target_result,
-                                 grpc_closure* on_complete) {
-  gpr_log(GPR_DEBUG, "dns_ares_next is called.");
-  ares_dns_resolver* r = (ares_dns_resolver*)resolver;
-  GPR_ASSERT(!r->next_completion);
-  r->next_completion = on_complete;
-  r->target_result = target_result;
-  if (r->resolved_version == 0 && !r->resolving) {
-    dns_ares_maybe_start_resolving_locked(r);
-  } else {
-    dns_ares_maybe_finish_next_locked(r);
-  }
-}
-
-static void dns_ares_start_resolving_locked(ares_dns_resolver* r) {
-  GRPC_RESOLVER_REF(&r->base, "dns-resolving");
-  GPR_ASSERT(!r->resolving);
-  r->resolving = true;
-  r->lb_addresses = nullptr;
-  r->service_config_json = nullptr;
-  r->pending_request = grpc_dns_lookup_ares(
-      r->dns_server, r->name_to_resolve, r->default_port, r->interested_parties,
-      &r->dns_ares_on_resolved_closure, &r->lb_addresses,
-      true /* check_grpclb */,
-      r->request_service_config ? &r->service_config_json : nullptr);
-}
-
-static void dns_ares_maybe_finish_next_locked(ares_dns_resolver* r) {
-  if (r->next_completion != nullptr &&
-      r->resolved_version != r->published_version) {
-    *r->target_result = r->resolved_result == nullptr
-                            ? nullptr
-                            : grpc_channel_args_copy(r->resolved_result);
-    gpr_log(GPR_DEBUG, "dns_ares_maybe_finish_next_locked");
-    GRPC_CLOSURE_SCHED(r->next_completion, GRPC_ERROR_NONE);
-    r->next_completion = nullptr;
-    r->published_version = r->resolved_version;
-  }
-}
-
-static void dns_ares_maybe_start_resolving_locked(ares_dns_resolver* r) {
-  if (r->last_resolution_timestamp >= 0) {
+void AresDnsResolver::MaybeStartResolvingLocked() {
+  if (last_resolution_timestamp_ >= 0) {
     const grpc_millis earliest_next_resolution =
-        r->last_resolution_timestamp + r->min_time_between_resolutions;
+        last_resolution_timestamp_ + min_time_between_resolutions_;
     const grpc_millis ms_until_next_resolution =
         earliest_next_resolution - grpc_core::ExecCtx::Get()->Now();
     if (ms_until_next_resolution > 0) {
       const grpc_millis last_resolution_ago =
-          grpc_core::ExecCtx::Get()->Now() - r->last_resolution_timestamp;
+          grpc_core::ExecCtx::Get()->Now() - last_resolution_timestamp_;
       gpr_log(GPR_DEBUG,
               "In cooldown from last resolution (from %" PRIdPTR
               " ms ago). Will resolve again in %" PRIdPTR " ms",
               last_resolution_ago, ms_until_next_resolution);
-      if (!r->have_next_resolution_timer) {
-        r->have_next_resolution_timer = true;
-        GRPC_RESOLVER_REF(&r->base, "next_resolution_timer_cooldown");
-        grpc_timer_init(&r->next_resolution_timer, ms_until_next_resolution,
-                        &r->dns_ares_on_next_resolution_timer_closure);
+      if (!have_next_resolution_timer_) {
+        have_next_resolution_timer_ = true;
+        // TODO(roth): We currently deal with this ref manually.  Once the
+        // new closure API is done, find a way to track this ref with the timer
+        // callback as part of the type system.
+        RefCountedPtr<Resolver> self =
+            Ref(DEBUG_LOCATION, "next_resolution_timer_cooldown");
+        self.release();
+        grpc_timer_init(&next_resolution_timer_, ms_until_next_resolution,
+                        &on_next_resolution_);
       }
       // TODO(dgq): remove the following two lines once Pick First stops
       // discarding subchannels after selecting.
-      ++r->resolved_version;
-      dns_ares_maybe_finish_next_locked(r);
+      ++resolved_version_;
+      MaybeFinishNextLocked();
       return;
     }
   }
-  dns_ares_start_resolving_locked(r);
+  StartResolvingLocked();
 }
 
-static void dns_ares_destroy(grpc_resolver* gr) {
-  gpr_log(GPR_DEBUG, "dns_ares_destroy");
-  ares_dns_resolver* r = (ares_dns_resolver*)gr;
-  if (r->resolved_result != nullptr) {
-    grpc_channel_args_destroy(r->resolved_result);
+void AresDnsResolver::StartResolvingLocked() {
+  // TODO(roth): We currently deal with this ref manually.  Once the
+  // new closure API is done, find a way to track this ref with the timer
+  // callback as part of the type system.
+  RefCountedPtr<Resolver> self = Ref(DEBUG_LOCATION, "dns-resolving");
+  self.release();
+  GPR_ASSERT(!resolving_);
+  resolving_ = true;
+  lb_addresses_ = nullptr;
+  service_config_json_ = nullptr;
+  pending_request_ = grpc_dns_lookup_ares(
+      dns_server_, name_to_resolve_, kDefaultPort, interested_parties_,
+      &on_resolved_, &lb_addresses_, true /* check_grpclb */,
+      request_service_config_ ? &service_config_json_ : nullptr);
+  last_resolution_timestamp_ = grpc_core::ExecCtx::Get()->Now();
+}
+
+void AresDnsResolver::MaybeFinishNextLocked() {
+  if (next_completion_ != nullptr && resolved_version_ != published_version_) {
+    *target_result_ = resolved_result_ == nullptr
+                          ? nullptr
+                          : grpc_channel_args_copy(resolved_result_);
+    gpr_log(GPR_DEBUG, "AresDnsResolver::MaybeFinishNextLocked()");
+    GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_NONE);
+    next_completion_ = nullptr;
+    published_version_ = resolved_version_;
   }
-  grpc_pollset_set_destroy(r->interested_parties);
-  gpr_free(r->dns_server);
-  gpr_free(r->name_to_resolve);
-  gpr_free(r->default_port);
-  grpc_channel_args_destroy(r->channel_args);
-  gpr_free(r);
 }
 
-static grpc_resolver* dns_ares_create(grpc_resolver_args* args,
-                                      const char* default_port) {
-  /* Get name from args. */
-  const char* path = args->uri->path;
-  if (path[0] == '/') ++path;
-  /* Create resolver. */
-  ares_dns_resolver* r =
-      (ares_dns_resolver*)gpr_zalloc(sizeof(ares_dns_resolver));
-  grpc_resolver_init(&r->base, &dns_ares_resolver_vtable, args->combiner);
-  if (0 != strcmp(args->uri->authority, "")) {
-    r->dns_server = gpr_strdup(args->uri->authority);
+//
+// Factory
+//
+
+class AresDnsResolverFactory : public ResolverFactory {
+ public:
+  OrphanablePtr<Resolver> CreateResolver(
+      const ResolverArgs& args) const override {
+    return OrphanablePtr<Resolver>(New<AresDnsResolver>(args));
   }
-  r->name_to_resolve = gpr_strdup(path);
-  r->default_port = gpr_strdup(default_port);
-  r->channel_args = grpc_channel_args_copy(args->args);
-  const grpc_arg* arg = grpc_channel_args_find(
-      r->channel_args, GRPC_ARG_SERVICE_CONFIG_DISABLE_RESOLUTION);
-  r->request_service_config = !grpc_channel_arg_get_integer(
-      arg, (grpc_integer_options){false, false, true});
-  r->interested_parties = grpc_pollset_set_create();
-  if (args->pollset_set != nullptr) {
-    grpc_pollset_set_add_pollset_set(r->interested_parties, args->pollset_set);
-  }
-  grpc_core::BackOff::Options backoff_options;
-  backoff_options
-      .set_initial_backoff(GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS * 1000)
-      .set_multiplier(GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER)
-      .set_jitter(GRPC_DNS_RECONNECT_JITTER)
-      .set_max_backoff(GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
-  r->backoff.Init(grpc_core::BackOff(backoff_options));
-  GRPC_CLOSURE_INIT(&r->dns_ares_on_next_resolution_timer_closure,
-                    dns_ares_on_next_resolution_timer_locked, r,
-                    grpc_combiner_scheduler(r->base.combiner));
-  GRPC_CLOSURE_INIT(&r->dns_ares_on_resolved_closure,
-                    dns_ares_on_resolved_locked, r,
-                    grpc_combiner_scheduler(r->base.combiner));
-  const grpc_arg* period_arg = grpc_channel_args_find(
-      args->args, GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS);
-  r->min_time_between_resolutions =
-      grpc_channel_arg_get_integer(period_arg, {1000, 0, INT_MAX});
-  r->last_resolution_timestamp = -1;
-  return &r->base;
+
+  const char* scheme() const override { return "dns"; }
+};
+
+}  // namespace
+
+}  // namespace grpc_core
+
+extern grpc_address_resolver_vtable* grpc_resolve_address_impl;
+static grpc_address_resolver_vtable* default_resolver;
+
+static grpc_error* blocking_resolve_address_ares(
+    const char* name, const char* default_port,
+    grpc_resolved_addresses** addresses) {
+  return default_resolver->blocking_resolve_address(name, default_port,
+                                                    addresses);
 }
 
-/*
- * FACTORY
- */
+static grpc_address_resolver_vtable ares_resolver = {
+    grpc_resolve_address_ares, blocking_resolve_address_ares};
 
-static void dns_ares_factory_ref(grpc_resolver_factory* factory) {}
-
-static void dns_ares_factory_unref(grpc_resolver_factory* factory) {}
-
-static grpc_resolver* dns_factory_create_resolver(
-    grpc_resolver_factory* factory, grpc_resolver_args* args) {
-  return dns_ares_create(args, "https");
-}
-
-static char* dns_ares_factory_get_default_host_name(
-    grpc_resolver_factory* factory, grpc_uri* uri) {
-  const char* path = uri->path;
-  if (path[0] == '/') ++path;
-  return gpr_strdup(path);
-}
-
-static const grpc_resolver_factory_vtable dns_ares_factory_vtable = {
-    dns_ares_factory_ref, dns_ares_factory_unref, dns_factory_create_resolver,
-    dns_ares_factory_get_default_host_name, "dns"};
-static grpc_resolver_factory dns_resolver_factory = {&dns_ares_factory_vtable};
-
-static grpc_resolver_factory* dns_ares_resolver_factory_create() {
-  return &dns_resolver_factory;
-}
-
-void grpc_resolver_dns_ares_init(void) {
-  char* resolver = gpr_getenv("GRPC_DNS_RESOLVER");
+void grpc_resolver_dns_ares_init() {
+  char* resolver_env = gpr_getenv("GRPC_DNS_RESOLVER");
   /* TODO(zyc): Turn on c-ares based resolver by default after the address
      sorter and the CNAME support are added. */
-  if (resolver != nullptr && gpr_stricmp(resolver, "ares") == 0) {
+  if (resolver_env != nullptr && gpr_stricmp(resolver_env, "ares") == 0) {
+    address_sorting_init();
     grpc_error* error = grpc_ares_init();
     if (error != GRPC_ERROR_NONE) {
       GRPC_LOG_IF_ERROR("ares_library_init() failed", error);
       return;
     }
-    grpc_resolve_address = grpc_resolve_address_ares;
-    grpc_register_resolver_type(dns_ares_resolver_factory_create());
+    default_resolver = grpc_resolve_address_impl;
+    grpc_set_resolver_impl(&ares_resolver);
+    grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
+        grpc_core::UniquePtr<grpc_core::ResolverFactory>(
+            grpc_core::New<grpc_core::AresDnsResolverFactory>()));
   }
-  gpr_free(resolver);
+  gpr_free(resolver_env);
 }
 
-void grpc_resolver_dns_ares_shutdown(void) {
-  char* resolver = gpr_getenv("GRPC_DNS_RESOLVER");
-  if (resolver != nullptr && gpr_stricmp(resolver, "ares") == 0) {
+void grpc_resolver_dns_ares_shutdown() {
+  char* resolver_env = gpr_getenv("GRPC_DNS_RESOLVER");
+  if (resolver_env != nullptr && gpr_stricmp(resolver_env, "ares") == 0) {
+    address_sorting_shutdown();
     grpc_ares_cleanup();
   }
-  gpr_free(resolver);
+  gpr_free(resolver_env);
 }
 
 #else /* GRPC_ARES == 1 && !defined(GRPC_UV) */
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
index ba7dad6..6239549 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
@@ -19,8 +19,9 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_EV_DRIVER_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_EV_DRIVER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <ares.h>
-#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/pollset_set.h"
 
 typedef struct grpc_ares_ev_driver grpc_ares_ev_driver;
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
index 2eb2a9b..b604f2b 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
@@ -16,6 +16,7 @@
  *
  */
 #include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 #if GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET)
 
@@ -28,7 +29,6 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/ev_posix.h"
@@ -125,7 +125,8 @@
 
 grpc_error* grpc_ares_ev_driver_create(grpc_ares_ev_driver** ev_driver,
                                        grpc_pollset_set* pollset_set) {
-  *ev_driver = (grpc_ares_ev_driver*)gpr_malloc(sizeof(grpc_ares_ev_driver));
+  *ev_driver = static_cast<grpc_ares_ev_driver*>(
+      gpr_malloc(sizeof(grpc_ares_ev_driver)));
   int status = ares_init(&(*ev_driver)->channel);
   gpr_log(GPR_DEBUG, "grpc_ares_ev_driver_create");
   if (status != ARES_SUCCESS) {
@@ -196,7 +197,7 @@
 }
 
 static void on_readable_cb(void* arg, grpc_error* error) {
-  fd_node* fdn = (fd_node*)arg;
+  fd_node* fdn = static_cast<fd_node*>(arg);
   grpc_ares_ev_driver* ev_driver = fdn->ev_driver;
   gpr_mu_lock(&fdn->mu);
   const int fd = grpc_fd_wrapped_fd(fdn->fd);
@@ -230,7 +231,7 @@
 }
 
 static void on_writable_cb(void* arg, grpc_error* error) {
-  fd_node* fdn = (fd_node*)arg;
+  fd_node* fdn = static_cast<fd_node*>(arg);
   grpc_ares_ev_driver* ev_driver = fdn->ev_driver;
   gpr_mu_lock(&fdn->mu);
   const int fd = grpc_fd_wrapped_fd(fdn->fd);
@@ -281,7 +282,7 @@
         if (fdn == nullptr) {
           char* fd_name;
           gpr_asprintf(&fd_name, "ares_ev_driver-%" PRIuPTR, i);
-          fdn = (fd_node*)gpr_malloc(sizeof(fd_node));
+          fdn = static_cast<fd_node*>(gpr_malloc(sizeof(fd_node)));
           gpr_log(GPR_DEBUG, "new fd: %d", socks[i]);
           fdn->fd = grpc_fd_create(socks[i], fd_name);
           fdn->ev_driver = ev_driver;
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
index e05f9d2..fb24357 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
@@ -17,6 +17,7 @@
  */
 
 #include <grpc/support/port_platform.h>
+
 #if GRPC_ARES == 1 && !defined(GRPC_UV)
 
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
@@ -28,14 +29,14 @@
 
 #include <ares.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
+#include <address_sorting/address_sorting.h>
 #include "src/core/ext/filters/client_channel/parse_address.h"
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/executor.h"
@@ -46,6 +47,9 @@
 static gpr_once g_basic_init = GPR_ONCE_INIT;
 static gpr_mu g_init_mu;
 
+grpc_core::TraceFlag grpc_trace_cares_address_sorting(false,
+                                                      "cares_address_sorting");
+
 struct grpc_ares_request {
   /** indicates the DNS server to use, if specified */
   struct ares_addr_port_node dns_server_addr;
@@ -89,18 +93,67 @@
   } else if (strcmp(port, "https") == 0) {
     return htons(443);
   }
-  return htons((unsigned short)atoi(port));
+  return htons(static_cast<unsigned short>(atoi(port)));
 }
 
 static void grpc_ares_request_ref(grpc_ares_request* r) {
   gpr_ref(&r->pending_queries);
 }
 
+static void log_address_sorting_list(grpc_lb_addresses* lb_addrs,
+                                     const char* input_output_str) {
+  for (size_t i = 0; i < lb_addrs->num_addresses; i++) {
+    char* addr_str;
+    if (grpc_sockaddr_to_string(&addr_str, &lb_addrs->addresses[i].address,
+                                true)) {
+      gpr_log(GPR_DEBUG, "c-ares address sorting: %s[%" PRIuPTR "]=%s",
+              input_output_str, i, addr_str);
+      gpr_free(addr_str);
+    } else {
+      gpr_log(GPR_DEBUG,
+              "c-ares address sorting: %s[%" PRIuPTR "]=<unprintable>",
+              input_output_str, i);
+    }
+  }
+}
+
+void grpc_cares_wrapper_address_sorting_sort(grpc_lb_addresses* lb_addrs) {
+  if (grpc_trace_cares_address_sorting.enabled()) {
+    log_address_sorting_list(lb_addrs, "input");
+  }
+  address_sorting_sortable* sortables = (address_sorting_sortable*)gpr_zalloc(
+      sizeof(address_sorting_sortable) * lb_addrs->num_addresses);
+  for (size_t i = 0; i < lb_addrs->num_addresses; i++) {
+    sortables[i].user_data = &lb_addrs->addresses[i];
+    memcpy(&sortables[i].dest_addr.addr, &lb_addrs->addresses[i].address.addr,
+           lb_addrs->addresses[i].address.len);
+    sortables[i].dest_addr.len = lb_addrs->addresses[i].address.len;
+  }
+  address_sorting_rfc_6724_sort(sortables, lb_addrs->num_addresses);
+  grpc_lb_address* sorted_lb_addrs = (grpc_lb_address*)gpr_zalloc(
+      sizeof(grpc_lb_address) * lb_addrs->num_addresses);
+  for (size_t i = 0; i < lb_addrs->num_addresses; i++) {
+    sorted_lb_addrs[i] = *(grpc_lb_address*)sortables[i].user_data;
+  }
+  gpr_free(sortables);
+  gpr_free(lb_addrs->addresses);
+  lb_addrs->addresses = sorted_lb_addrs;
+  if (grpc_trace_cares_address_sorting.enabled()) {
+    log_address_sorting_list(lb_addrs, "output");
+  }
+}
+
+/* Allow tests to access grpc_ares_wrapper_address_sorting_sort */
+void grpc_cares_wrapper_test_only_address_sorting_sort(
+    grpc_lb_addresses* lb_addrs) {
+  grpc_cares_wrapper_address_sorting_sort(lb_addrs);
+}
+
 static void grpc_ares_request_unref(grpc_ares_request* r) {
   /* If there are no pending queries, invoke on_done callback and destroy the
      request */
   if (gpr_unref(&r->pending_queries)) {
-    /* TODO(zyc): Sort results with RFC6724 before invoking on_done. */
+    grpc_cares_wrapper_address_sorting_sort(*(r->lb_addrs_out));
     GRPC_CLOSURE_SCHED(r->on_done, r->error);
     gpr_mu_destroy(&r->mu);
     grpc_ares_ev_driver_destroy(r->ev_driver);
@@ -111,8 +164,8 @@
 static grpc_ares_hostbyname_request* create_hostbyname_request(
     grpc_ares_request* parent_request, char* host, uint16_t port,
     bool is_balancer) {
-  grpc_ares_hostbyname_request* hr = (grpc_ares_hostbyname_request*)gpr_zalloc(
-      sizeof(grpc_ares_hostbyname_request));
+  grpc_ares_hostbyname_request* hr = static_cast<grpc_ares_hostbyname_request*>(
+      gpr_zalloc(sizeof(grpc_ares_hostbyname_request)));
   hr->parent_request = parent_request;
   hr->host = gpr_strdup(host);
   hr->port = port;
@@ -129,7 +182,8 @@
 
 static void on_hostbyname_done_cb(void* arg, int status, int timeouts,
                                   struct hostent* hostent) {
-  grpc_ares_hostbyname_request* hr = (grpc_ares_hostbyname_request*)arg;
+  grpc_ares_hostbyname_request* hr =
+      static_cast<grpc_ares_hostbyname_request*>(arg);
   grpc_ares_request* r = hr->parent_request;
   gpr_mu_lock(&r->mu);
   if (status == ARES_SUCCESS) {
@@ -145,9 +199,9 @@
     for (i = 0; hostent->h_addr_list[i] != nullptr; i++) {
     }
     (*lb_addresses)->num_addresses += i;
-    (*lb_addresses)->addresses = (grpc_lb_address*)gpr_realloc(
-        (*lb_addresses)->addresses,
-        sizeof(grpc_lb_address) * (*lb_addresses)->num_addresses);
+    (*lb_addresses)->addresses = static_cast<grpc_lb_address*>(
+        gpr_realloc((*lb_addresses)->addresses,
+                    sizeof(grpc_lb_address) * (*lb_addresses)->num_addresses));
     for (i = prev_naddr; i < (*lb_addresses)->num_addresses; i++) {
       switch (hostent->h_addrtype) {
         case AF_INET6: {
@@ -156,7 +210,7 @@
           memset(&addr, 0, addr_len);
           memcpy(&addr.sin6_addr, hostent->h_addr_list[i - prev_naddr],
                  sizeof(struct in6_addr));
-          addr.sin6_family = (sa_family_t)hostent->h_addrtype;
+          addr.sin6_family = static_cast<sa_family_t>(hostent->h_addrtype);
           addr.sin6_port = hr->port;
           grpc_lb_addresses_set_address(
               *lb_addresses, i, &addr, addr_len,
@@ -177,7 +231,7 @@
           memset(&addr, 0, addr_len);
           memcpy(&addr.sin_addr, hostent->h_addr_list[i - prev_naddr],
                  sizeof(struct in_addr));
-          addr.sin_family = (sa_family_t)hostent->h_addrtype;
+          addr.sin_family = static_cast<sa_family_t>(hostent->h_addrtype);
           addr.sin_port = hr->port;
           grpc_lb_addresses_set_address(
               *lb_addresses, i, &addr, addr_len,
@@ -212,7 +266,7 @@
 
 static void on_srv_query_done_cb(void* arg, int status, int timeouts,
                                  unsigned char* abuf, int alen) {
-  grpc_ares_request* r = (grpc_ares_request*)arg;
+  grpc_ares_request* r = static_cast<grpc_ares_request*>(arg);
   grpc_core::ExecCtx exec_ctx;
   gpr_log(GPR_DEBUG, "on_query_srv_done_cb");
   if (status == ARES_SUCCESS) {
@@ -260,7 +314,7 @@
                            unsigned char* buf, int len) {
   gpr_log(GPR_DEBUG, "on_txt_done_cb");
   char* error_msg;
-  grpc_ares_request* r = (grpc_ares_request*)arg;
+  grpc_ares_request* r = static_cast<grpc_ares_request*>(arg);
   const size_t prefix_len = sizeof(g_service_config_attribute_prefix) - 1;
   struct ares_txt_ext* result = nullptr;
   struct ares_txt_ext* reply = nullptr;
@@ -280,13 +334,15 @@
   // Found a service config record.
   if (result != nullptr) {
     size_t service_config_len = result->length - prefix_len;
-    *r->service_config_json_out = (char*)gpr_malloc(service_config_len + 1);
+    *r->service_config_json_out =
+        static_cast<char*>(gpr_malloc(service_config_len + 1));
     memcpy(*r->service_config_json_out, result->txt + prefix_len,
            service_config_len);
     for (result = result->next; result != nullptr && !result->record_start;
          result = result->next) {
-      *r->service_config_json_out = (char*)gpr_realloc(
-          *r->service_config_json_out, service_config_len + result->length + 1);
+      *r->service_config_json_out = static_cast<char*>(
+          gpr_realloc(*r->service_config_json_out,
+                      service_config_len + result->length + 1));
       memcpy(*r->service_config_json_out + service_config_len, result->txt,
              result->length);
       service_config_len += result->length;
@@ -349,7 +405,7 @@
   error = grpc_ares_ev_driver_create(&ev_driver, interested_parties);
   if (error != GRPC_ERROR_NONE) goto error_cleanup;
 
-  r = (grpc_ares_request*)gpr_zalloc(sizeof(grpc_ares_request));
+  r = static_cast<grpc_ares_request*>(gpr_zalloc(sizeof(grpc_ares_request)));
   gpr_mu_init(&r->mu);
   r->ev_driver = ev_driver;
   r->on_done = on_done;
@@ -365,7 +421,7 @@
     grpc_resolved_address addr;
     if (grpc_parse_ipv4_hostport(dns_server, &addr, false /* log_errors */)) {
       r->dns_server_addr.family = AF_INET;
-      struct sockaddr_in* in = (struct sockaddr_in*)addr.addr;
+      struct sockaddr_in* in = reinterpret_cast<struct sockaddr_in*>(addr.addr);
       memcpy(&r->dns_server_addr.addr.addr4, &in->sin_addr,
              sizeof(struct in_addr));
       r->dns_server_addr.tcp_port = grpc_sockaddr_get_port(&addr);
@@ -373,7 +429,8 @@
     } else if (grpc_parse_ipv6_hostport(dns_server, &addr,
                                         false /* log_errors */)) {
       r->dns_server_addr.family = AF_INET6;
-      struct sockaddr_in6* in6 = (struct sockaddr_in6*)addr.addr;
+      struct sockaddr_in6* in6 =
+          reinterpret_cast<struct sockaddr_in6*>(addr.addr);
       memcpy(&r->dns_server_addr.addr.addr6, &in6->sin6_addr,
              sizeof(struct in6_addr));
       r->dns_server_addr.tcp_port = grpc_sockaddr_get_port(&addr);
@@ -488,16 +545,17 @@
 
 static void on_dns_lookup_done_cb(void* arg, grpc_error* error) {
   grpc_resolve_address_ares_request* r =
-      (grpc_resolve_address_ares_request*)arg;
+      static_cast<grpc_resolve_address_ares_request*>(arg);
   grpc_resolved_addresses** resolved_addresses = r->addrs_out;
   if (r->lb_addrs == nullptr || r->lb_addrs->num_addresses == 0) {
     *resolved_addresses = nullptr;
   } else {
-    *resolved_addresses =
-        (grpc_resolved_addresses*)gpr_zalloc(sizeof(grpc_resolved_addresses));
+    *resolved_addresses = static_cast<grpc_resolved_addresses*>(
+        gpr_zalloc(sizeof(grpc_resolved_addresses)));
     (*resolved_addresses)->naddrs = r->lb_addrs->num_addresses;
-    (*resolved_addresses)->addrs = (grpc_resolved_address*)gpr_zalloc(
-        sizeof(grpc_resolved_address) * (*resolved_addresses)->naddrs);
+    (*resolved_addresses)->addrs =
+        static_cast<grpc_resolved_address*>(gpr_zalloc(
+            sizeof(grpc_resolved_address) * (*resolved_addresses)->naddrs));
     for (size_t i = 0; i < (*resolved_addresses)->naddrs; i++) {
       GPR_ASSERT(!r->lb_addrs->addresses[i].is_balancer);
       memcpy(&(*resolved_addresses)->addrs[i],
@@ -515,8 +573,8 @@
                                            grpc_closure* on_done,
                                            grpc_resolved_addresses** addrs) {
   grpc_resolve_address_ares_request* r =
-      (grpc_resolve_address_ares_request*)gpr_zalloc(
-          sizeof(grpc_resolve_address_ares_request));
+      static_cast<grpc_resolve_address_ares_request*>(
+          gpr_zalloc(sizeof(grpc_resolve_address_ares_request)));
   r->addrs_out = addrs;
   r->on_resolve_address_done = on_done;
   GRPC_CLOSURE_INIT(&r->on_dns_lookup_done, on_dns_lookup_done_cb, r,
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
index 86d870e..2d84a03 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
@@ -19,12 +19,15 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/lb_policy_factory.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/iomgr/polling_entity.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 
+extern grpc_core::TraceFlag grpc_trace_cares_address_sorting;
+
 typedef struct grpc_ares_request grpc_ares_request;
 
 /* Asynchronously resolve \a name. Use \a default_port if a port isn't
@@ -63,5 +66,9 @@
    it has been called the same number of times as grpc_ares_init(). */
 void grpc_ares_cleanup(void);
 
+/* Exposed only for testing */
+void grpc_cares_wrapper_test_only_address_sorting_sort(
+    grpc_lb_addresses* lb_addrs);
+
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H \
         */
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc
index a184cf2..5096e48 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc
@@ -17,6 +17,7 @@
  */
 
 #include <grpc/support/port_platform.h>
+
 #if GRPC_ARES != 1 || defined(GRPC_UV)
 
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
diff --git a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
index 2c79818..fbab136 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
@@ -23,7 +23,6 @@
 #include <cstring>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
 
@@ -32,6 +31,7 @@
 #include "src/core/lib/backoff/backoff.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/manual_constructor.h"
 #include "src/core/lib/iomgr/combiner.h"
@@ -43,301 +43,298 @@
 #define GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS 120
 #define GRPC_DNS_RECONNECT_JITTER 0.2
 
-typedef struct {
-  /** base class: must be first */
-  grpc_resolver base;
-  /** name to resolve */
-  char* name_to_resolve;
-  /** default port to use */
-  char* default_port;
-  /** channel args. */
-  grpc_channel_args* channel_args;
-  /** pollset_set to drive the name resolution process */
-  grpc_pollset_set* interested_parties;
+namespace grpc_core {
 
-  /** are we currently resolving? */
-  bool resolving;
-  /** which version of the result have we published? */
-  int published_version;
-  /** which version of the result is current? */
-  int resolved_version;
-  /** pending next completion, or NULL */
-  grpc_closure* next_completion;
-  /** target result address for next completion */
-  grpc_channel_args** target_result;
-  /** current (fully resolved) result */
-  grpc_channel_args* resolved_result;
-  /** next resolution timer */
-  bool have_next_resolution_timer;
-  grpc_timer next_resolution_timer;
-  grpc_closure next_resolution_closure;
-  /** retry backoff state */
-  grpc_core::ManualConstructor<grpc_core::BackOff> backoff;
-  /** min resolution period. Max one resolution will happen per period */
-  grpc_millis min_time_between_resolutions;
-  /** when was the last resolution? -1 if no resolution has happened yet */
-  grpc_millis last_resolution_timestamp;
-  /** currently resolving addresses */
-  grpc_resolved_addresses* addresses;
-} dns_resolver;
+namespace {
 
-static void dns_destroy(grpc_resolver* r);
+const char kDefaultPort[] = "https";
 
-static void dns_start_resolving_locked(dns_resolver* r);
-static void maybe_start_resolving_locked(dns_resolver* r);
-static void dns_maybe_finish_next_locked(dns_resolver* r);
+class NativeDnsResolver : public Resolver {
+ public:
+  explicit NativeDnsResolver(const ResolverArgs& args);
 
-static void dns_shutdown_locked(grpc_resolver* r);
-static void dns_channel_saw_error_locked(grpc_resolver* r);
-static void dns_next_locked(grpc_resolver* r, grpc_channel_args** target_result,
-                            grpc_closure* on_complete);
+  void NextLocked(grpc_channel_args** result,
+                  grpc_closure* on_complete) override;
 
-static const grpc_resolver_vtable dns_resolver_vtable = {
-    dns_destroy, dns_shutdown_locked, dns_channel_saw_error_locked,
-    dns_next_locked};
+  void RequestReresolutionLocked() override;
 
-static void dns_shutdown_locked(grpc_resolver* resolver) {
-  dns_resolver* r = (dns_resolver*)resolver;
-  if (r->have_next_resolution_timer) {
-    grpc_timer_cancel(&r->next_resolution_timer);
+  void ShutdownLocked() override;
+
+ private:
+  virtual ~NativeDnsResolver();
+
+  void MaybeStartResolvingLocked();
+  void StartResolvingLocked();
+  void MaybeFinishNextLocked();
+
+  static void OnNextResolutionLocked(void* arg, grpc_error* error);
+  static void OnResolvedLocked(void* arg, grpc_error* error);
+
+  /// name to resolve
+  char* name_to_resolve_ = nullptr;
+  /// channel args
+  grpc_channel_args* channel_args_ = nullptr;
+  /// pollset_set to drive the name resolution process
+  grpc_pollset_set* interested_parties_ = nullptr;
+  /// are we currently resolving?
+  bool resolving_ = false;
+  grpc_closure on_resolved_;
+  /// which version of the result have we published?
+  int published_version_ = 0;
+  /// which version of the result is current?
+  int resolved_version_ = 0;
+  /// pending next completion, or nullptr
+  grpc_closure* next_completion_ = nullptr;
+  /// target result address for next completion
+  grpc_channel_args** target_result_ = nullptr;
+  /// current (fully resolved) result
+  grpc_channel_args* resolved_result_ = nullptr;
+  /// next resolution timer
+  bool have_next_resolution_timer_ = false;
+  grpc_timer next_resolution_timer_;
+  grpc_closure on_next_resolution_;
+  /// min time between DNS requests
+  grpc_millis min_time_between_resolutions_;
+  /// timestamp of last DNS request
+  grpc_millis last_resolution_timestamp_ = -1;
+  /// retry backoff state
+  BackOff backoff_;
+  /// currently resolving addresses
+  grpc_resolved_addresses* addresses_ = nullptr;
+};
+
+NativeDnsResolver::NativeDnsResolver(const ResolverArgs& args)
+    : Resolver(args.combiner),
+      backoff_(
+          BackOff::Options()
+              .set_initial_backoff(GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS *
+                                   1000)
+              .set_multiplier(GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER)
+              .set_jitter(GRPC_DNS_RECONNECT_JITTER)
+              .set_max_backoff(GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000)) {
+  char* path = args.uri->path;
+  if (path[0] == '/') ++path;
+  name_to_resolve_ = gpr_strdup(path);
+  channel_args_ = grpc_channel_args_copy(args.args);
+  const grpc_arg* arg = grpc_channel_args_find(
+      args.args, GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS);
+  min_time_between_resolutions_ =
+      grpc_channel_arg_get_integer(arg, {1000, 0, INT_MAX});
+  interested_parties_ = grpc_pollset_set_create();
+  if (args.pollset_set != nullptr) {
+    grpc_pollset_set_add_pollset_set(interested_parties_, args.pollset_set);
   }
-  if (r->next_completion != nullptr) {
-    *r->target_result = nullptr;
-    GRPC_CLOSURE_SCHED(r->next_completion, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-                                               "Resolver Shutdown"));
-    r->next_completion = nullptr;
-  }
+  GRPC_CLOSURE_INIT(&on_next_resolution_,
+                    NativeDnsResolver::OnNextResolutionLocked, this,
+                    grpc_combiner_scheduler(args.combiner));
+  GRPC_CLOSURE_INIT(&on_resolved_, NativeDnsResolver::OnResolvedLocked, this,
+                    grpc_combiner_scheduler(args.combiner));
 }
 
-static void dns_channel_saw_error_locked(grpc_resolver* resolver) {
-  dns_resolver* r = (dns_resolver*)resolver;
-  if (!r->resolving) {
-    maybe_start_resolving_locked(r);
+NativeDnsResolver::~NativeDnsResolver() {
+  if (resolved_result_ != nullptr) {
+    grpc_channel_args_destroy(resolved_result_);
   }
+  grpc_pollset_set_destroy(interested_parties_);
+  gpr_free(name_to_resolve_);
+  grpc_channel_args_destroy(channel_args_);
 }
 
-static void dns_next_locked(grpc_resolver* resolver,
-                            grpc_channel_args** target_result,
-                            grpc_closure* on_complete) {
-  dns_resolver* r = (dns_resolver*)resolver;
-  GPR_ASSERT(!r->next_completion);
-  r->next_completion = on_complete;
-  r->target_result = target_result;
-  if (r->resolved_version == 0 && !r->resolving) {
-    maybe_start_resolving_locked(r);
+void NativeDnsResolver::NextLocked(grpc_channel_args** result,
+                                   grpc_closure* on_complete) {
+  GPR_ASSERT(next_completion_ == nullptr);
+  next_completion_ = on_complete;
+  target_result_ = result;
+  if (resolved_version_ == 0 && !resolving_) {
+    MaybeStartResolvingLocked();
   } else {
-    dns_maybe_finish_next_locked(r);
+    MaybeFinishNextLocked();
   }
 }
 
-static void dns_on_next_resolution_timer_locked(void* arg, grpc_error* error) {
-  dns_resolver* r = (dns_resolver*)arg;
-  r->have_next_resolution_timer = false;
-  if (error == GRPC_ERROR_NONE && !r->resolving) {
-    dns_start_resolving_locked(r);
+void NativeDnsResolver::RequestReresolutionLocked() {
+  if (!resolving_) {
+    MaybeStartResolvingLocked();
   }
-  GRPC_RESOLVER_UNREF(&r->base, "next_resolution_timer");
 }
 
-static void dns_on_resolved_locked(void* arg, grpc_error* error) {
-  dns_resolver* r = (dns_resolver*)arg;
+void NativeDnsResolver::ShutdownLocked() {
+  if (have_next_resolution_timer_) {
+    grpc_timer_cancel(&next_resolution_timer_);
+  }
+  if (next_completion_ != nullptr) {
+    *target_result_ = nullptr;
+    GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                                             "Resolver Shutdown"));
+    next_completion_ = nullptr;
+  }
+}
+
+void NativeDnsResolver::OnNextResolutionLocked(void* arg, grpc_error* error) {
+  NativeDnsResolver* r = static_cast<NativeDnsResolver*>(arg);
+  r->have_next_resolution_timer_ = false;
+  if (error == GRPC_ERROR_NONE && !r->resolving_) {
+    r->StartResolvingLocked();
+  }
+  r->Unref(DEBUG_LOCATION, "retry-timer");
+}
+
+void NativeDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) {
+  NativeDnsResolver* r = static_cast<NativeDnsResolver*>(arg);
   grpc_channel_args* result = nullptr;
-  GPR_ASSERT(r->resolving);
-  r->resolving = false;
+  GPR_ASSERT(r->resolving_);
+  r->resolving_ = false;
   GRPC_ERROR_REF(error);
-  error = grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS,
-                             grpc_slice_from_copied_string(r->name_to_resolve));
-  if (r->addresses != nullptr) {
+  error =
+      grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS,
+                         grpc_slice_from_copied_string(r->name_to_resolve_));
+  if (r->addresses_ != nullptr) {
     grpc_lb_addresses* addresses = grpc_lb_addresses_create(
-        r->addresses->naddrs, nullptr /* user_data_vtable */);
-    for (size_t i = 0; i < r->addresses->naddrs; ++i) {
+        r->addresses_->naddrs, nullptr /* user_data_vtable */);
+    for (size_t i = 0; i < r->addresses_->naddrs; ++i) {
       grpc_lb_addresses_set_address(
-          addresses, i, &r->addresses->addrs[i].addr,
-          r->addresses->addrs[i].len, false /* is_balancer */,
+          addresses, i, &r->addresses_->addrs[i].addr,
+          r->addresses_->addrs[i].len, false /* is_balancer */,
           nullptr /* balancer_name */, nullptr /* user_data */);
     }
     grpc_arg new_arg = grpc_lb_addresses_create_channel_arg(addresses);
-    result = grpc_channel_args_copy_and_add(r->channel_args, &new_arg, 1);
-    grpc_resolved_addresses_destroy(r->addresses);
+    result = grpc_channel_args_copy_and_add(r->channel_args_, &new_arg, 1);
+    grpc_resolved_addresses_destroy(r->addresses_);
     grpc_lb_addresses_destroy(addresses);
     // Reset backoff state so that we start from the beginning when the
     // next request gets triggered.
-    r->backoff->Reset();
+    r->backoff_.Reset();
   } else {
-    grpc_millis next_try = r->backoff->NextAttemptTime();
-    grpc_millis timeout = next_try - grpc_core::ExecCtx::Get()->Now();
+    grpc_millis next_try = r->backoff_.NextAttemptTime();
+    grpc_millis timeout = next_try - ExecCtx::Get()->Now();
     gpr_log(GPR_INFO, "dns resolution failed (will retry): %s",
             grpc_error_string(error));
-    GPR_ASSERT(!r->have_next_resolution_timer);
-    r->have_next_resolution_timer = true;
-    GRPC_RESOLVER_REF(&r->base, "next_resolution_timer");
+    GPR_ASSERT(!r->have_next_resolution_timer_);
+    r->have_next_resolution_timer_ = true;
+    // TODO(roth): We currently deal with this ref manually.  Once the
+    // new closure API is done, find a way to track this ref with the timer
+    // callback as part of the type system.
+    RefCountedPtr<Resolver> self =
+        r->Ref(DEBUG_LOCATION, "next_resolution_timer");
+    self.release();
     if (timeout > 0) {
       gpr_log(GPR_DEBUG, "retrying in %" PRIdPTR " milliseconds", timeout);
     } else {
       gpr_log(GPR_DEBUG, "retrying immediately");
     }
-    grpc_timer_init(&r->next_resolution_timer, next_try,
-                    &r->next_resolution_closure);
+    grpc_timer_init(&r->next_resolution_timer_, next_try,
+                    &r->on_next_resolution_);
   }
-  if (r->resolved_result != nullptr) {
-    grpc_channel_args_destroy(r->resolved_result);
+  if (r->resolved_result_ != nullptr) {
+    grpc_channel_args_destroy(r->resolved_result_);
   }
-  r->resolved_result = result;
-  r->resolved_version++;
-  dns_maybe_finish_next_locked(r);
+  r->resolved_result_ = result;
+  ++r->resolved_version_;
+  r->MaybeFinishNextLocked();
   GRPC_ERROR_UNREF(error);
-
-  GRPC_RESOLVER_UNREF(&r->base, "dns-resolving");
+  r->Unref(DEBUG_LOCATION, "dns-resolving");
 }
 
-static void maybe_start_resolving_locked(dns_resolver* r) {
-  if (r->last_resolution_timestamp >= 0) {
+void NativeDnsResolver::MaybeStartResolvingLocked() {
+  if (last_resolution_timestamp_ >= 0) {
     const grpc_millis earliest_next_resolution =
-        r->last_resolution_timestamp + r->min_time_between_resolutions;
+        last_resolution_timestamp_ + min_time_between_resolutions_;
     const grpc_millis ms_until_next_resolution =
         earliest_next_resolution - grpc_core::ExecCtx::Get()->Now();
     if (ms_until_next_resolution > 0) {
       const grpc_millis last_resolution_ago =
-          grpc_core::ExecCtx::Get()->Now() - r->last_resolution_timestamp;
+          grpc_core::ExecCtx::Get()->Now() - last_resolution_timestamp_;
       gpr_log(GPR_DEBUG,
               "In cooldown from last resolution (from %" PRIdPTR
               " ms ago). Will resolve again in %" PRIdPTR " ms",
               last_resolution_ago, ms_until_next_resolution);
-      if (!r->have_next_resolution_timer) {
-        r->have_next_resolution_timer = true;
-        GRPC_RESOLVER_REF(&r->base, "next_resolution_timer_cooldown");
-        grpc_timer_init(&r->next_resolution_timer, ms_until_next_resolution,
-                        &r->next_resolution_closure);
+      if (!have_next_resolution_timer_) {
+        have_next_resolution_timer_ = true;
+        // TODO(roth): We currently deal with this ref manually.  Once the
+        // new closure API is done, find a way to track this ref with the timer
+        // callback as part of the type system.
+        RefCountedPtr<Resolver> self =
+            Ref(DEBUG_LOCATION, "next_resolution_timer_cooldown");
+        self.release();
+        grpc_timer_init(&next_resolution_timer_, ms_until_next_resolution,
+                        &on_next_resolution_);
       }
       // TODO(dgq): remove the following two lines once Pick First stops
       // discarding subchannels after selecting.
-      ++r->resolved_version;
-      dns_maybe_finish_next_locked(r);
+      ++resolved_version_;
+      MaybeFinishNextLocked();
       return;
     }
   }
-  dns_start_resolving_locked(r);
+  StartResolvingLocked();
 }
 
-static void dns_start_resolving_locked(dns_resolver* r) {
-  GRPC_RESOLVER_REF(&r->base, "dns-resolving");
-  GPR_ASSERT(!r->resolving);
-  r->resolving = true;
-  r->addresses = nullptr;
-  grpc_resolve_address(
-      r->name_to_resolve, r->default_port, r->interested_parties,
-      GRPC_CLOSURE_CREATE(dns_on_resolved_locked, r,
-                          grpc_combiner_scheduler(r->base.combiner)),
-      &r->addresses);
-  r->last_resolution_timestamp = grpc_core::ExecCtx::Get()->Now();
+void NativeDnsResolver::StartResolvingLocked() {
+  // TODO(roth): We currently deal with this ref manually.  Once the
+  // new closure API is done, find a way to track this ref with the timer
+  // callback as part of the type system.
+  RefCountedPtr<Resolver> self = Ref(DEBUG_LOCATION, "dns-resolving");
+  self.release();
+  GPR_ASSERT(!resolving_);
+  resolving_ = true;
+  addresses_ = nullptr;
+  grpc_resolve_address(name_to_resolve_, kDefaultPort, interested_parties_,
+                       &on_resolved_, &addresses_);
+  last_resolution_timestamp_ = grpc_core::ExecCtx::Get()->Now();
 }
 
-static void dns_maybe_finish_next_locked(dns_resolver* r) {
-  if (r->next_completion != nullptr &&
-      r->resolved_version != r->published_version) {
-    *r->target_result = r->resolved_result == nullptr
-                            ? nullptr
-                            : grpc_channel_args_copy(r->resolved_result);
-    GRPC_CLOSURE_SCHED(r->next_completion, GRPC_ERROR_NONE);
-    r->next_completion = nullptr;
-    r->published_version = r->resolved_version;
+void NativeDnsResolver::MaybeFinishNextLocked() {
+  if (next_completion_ != nullptr && resolved_version_ != published_version_) {
+    *target_result_ = resolved_result_ == nullptr
+                          ? nullptr
+                          : grpc_channel_args_copy(resolved_result_);
+    GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_NONE);
+    next_completion_ = nullptr;
+    published_version_ = resolved_version_;
   }
 }
 
-static void dns_destroy(grpc_resolver* gr) {
-  dns_resolver* r = (dns_resolver*)gr;
-  if (r->resolved_result != nullptr) {
-    grpc_channel_args_destroy(r->resolved_result);
+//
+// Factory
+//
+
+class NativeDnsResolverFactory : public ResolverFactory {
+ public:
+  OrphanablePtr<Resolver> CreateResolver(
+      const ResolverArgs& args) const override {
+    if (0 != strcmp(args.uri->authority, "")) {
+      gpr_log(GPR_ERROR, "authority based dns uri's not supported");
+      return OrphanablePtr<Resolver>(nullptr);
+    }
+    return OrphanablePtr<Resolver>(New<NativeDnsResolver>(args));
   }
-  grpc_pollset_set_destroy(r->interested_parties);
-  gpr_free(r->name_to_resolve);
-  gpr_free(r->default_port);
-  grpc_channel_args_destroy(r->channel_args);
-  gpr_free(r);
-}
 
-static grpc_resolver* dns_create(grpc_resolver_args* args,
-                                 const char* default_port) {
-  if (0 != strcmp(args->uri->authority, "")) {
-    gpr_log(GPR_ERROR, "authority based dns uri's not supported");
-    return nullptr;
-  }
-  // Get name from args.
-  char* path = args->uri->path;
-  if (path[0] == '/') ++path;
-  // Create resolver.
-  dns_resolver* r = (dns_resolver*)gpr_zalloc(sizeof(dns_resolver));
-  grpc_resolver_init(&r->base, &dns_resolver_vtable, args->combiner);
-  r->name_to_resolve = gpr_strdup(path);
-  r->default_port = gpr_strdup(default_port);
-  r->channel_args = grpc_channel_args_copy(args->args);
-  r->interested_parties = grpc_pollset_set_create();
-  if (args->pollset_set != nullptr) {
-    grpc_pollset_set_add_pollset_set(r->interested_parties, args->pollset_set);
-  }
-  grpc_core::BackOff::Options backoff_options;
-  backoff_options
-      .set_initial_backoff(GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS * 1000)
-      .set_multiplier(GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER)
-      .set_jitter(GRPC_DNS_RECONNECT_JITTER)
-      .set_max_backoff(GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
-  r->backoff.Init(grpc_core::BackOff(backoff_options));
-  const grpc_arg* period_arg = grpc_channel_args_find(
-      args->args, GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS);
-  r->min_time_between_resolutions =
-      grpc_channel_arg_get_integer(period_arg, {1000, 0, INT_MAX});
-  r->last_resolution_timestamp = -1;
-  GRPC_CLOSURE_INIT(&r->next_resolution_closure,
-                    dns_on_next_resolution_timer_locked, r,
-                    grpc_combiner_scheduler(r->base.combiner));
-  return &r->base;
-}
+  const char* scheme() const override { return "dns"; }
+};
 
-/*
- * FACTORY
- */
+}  // namespace
 
-static void dns_factory_ref(grpc_resolver_factory* factory) {}
+}  // namespace grpc_core
 
-static void dns_factory_unref(grpc_resolver_factory* factory) {}
-
-static grpc_resolver* dns_factory_create_resolver(
-    grpc_resolver_factory* factory, grpc_resolver_args* args) {
-  return dns_create(args, "https");
-}
-
-static char* dns_factory_get_default_host_name(grpc_resolver_factory* factory,
-                                               grpc_uri* uri) {
-  const char* path = uri->path;
-  if (path[0] == '/') ++path;
-  return gpr_strdup(path);
-}
-
-static const grpc_resolver_factory_vtable dns_factory_vtable = {
-    dns_factory_ref, dns_factory_unref, dns_factory_create_resolver,
-    dns_factory_get_default_host_name, "dns"};
-static grpc_resolver_factory dns_resolver_factory = {&dns_factory_vtable};
-
-static grpc_resolver_factory* dns_resolver_factory_create() {
-  return &dns_resolver_factory;
-}
-
-void grpc_resolver_dns_native_init(void) {
-  char* resolver = gpr_getenv("GRPC_DNS_RESOLVER");
-  if (resolver != nullptr && gpr_stricmp(resolver, "native") == 0) {
+void grpc_resolver_dns_native_init() {
+  char* resolver_env = gpr_getenv("GRPC_DNS_RESOLVER");
+  if (resolver_env != nullptr && gpr_stricmp(resolver_env, "native") == 0) {
     gpr_log(GPR_DEBUG, "Using native dns resolver");
-    grpc_register_resolver_type(dns_resolver_factory_create());
+    grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
+        grpc_core::UniquePtr<grpc_core::ResolverFactory>(
+            grpc_core::New<grpc_core::NativeDnsResolverFactory>()));
   } else {
-    grpc_resolver_factory* existing_factory =
-        grpc_resolver_factory_lookup("dns");
+    grpc_core::ResolverRegistry::Builder::InitRegistry();
+    grpc_core::ResolverFactory* existing_factory =
+        grpc_core::ResolverRegistry::LookupResolverFactory("dns");
     if (existing_factory == nullptr) {
       gpr_log(GPR_DEBUG, "Using native dns resolver");
-      grpc_register_resolver_type(dns_resolver_factory_create());
-    } else {
-      grpc_resolver_factory_unref(existing_factory);
+      grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
+          grpc_core::UniquePtr<grpc_core::ResolverFactory>(
+              grpc_core::New<grpc_core::NativeDnsResolverFactory>()));
     }
   }
-  gpr_free(resolver);
+  gpr_free(resolver_env);
 }
 
-void grpc_resolver_dns_native_shutdown(void) {}
+void grpc_resolver_dns_native_shutdown() {}
diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
index e945d08..99a33f2 100644
--- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
@@ -17,6 +17,8 @@
 // This is similar to the sockaddr resolver, except that it supports a
 // bunch of query args that are useful for dependency injection in tests.
 
+#include <grpc/support/port_platform.h>
+
 #include <limits.h>
 #include <stdbool.h>
 #include <stdio.h>
@@ -24,14 +26,13 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
-#include <grpc/support/port_platform.h>
 #include <grpc/support/string_util.h>
 
 #include "src/core/ext/filters/client_channel/lb_policy_factory.h"
 #include "src/core/ext/filters/client_channel/parse_address.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/closure.h"
 #include "src/core/lib/iomgr/combiner.h"
@@ -42,190 +43,203 @@
 
 #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
 
-//
-// fake_resolver
-//
+namespace grpc_core {
 
-typedef struct {
-  // Base class -- must be first
-  grpc_resolver base;
+// This cannot be in an anonymous namespace, because it is a friend of
+// FakeResolverResponseGenerator.
+class FakeResolver : public Resolver {
+ public:
+  explicit FakeResolver(const ResolverArgs& args);
 
-  // Passed-in parameters
-  grpc_channel_args* channel_args;
+  void NextLocked(grpc_channel_args** result,
+                  grpc_closure* on_complete) override;
 
+  void RequestReresolutionLocked() override;
+
+ private:
+  friend class FakeResolverResponseGenerator;
+
+  virtual ~FakeResolver();
+
+  void MaybeFinishNextLocked();
+
+  void ShutdownLocked() override;
+
+  // passed-in parameters
+  grpc_channel_args* channel_args_ = nullptr;
   // If not NULL, the next set of resolution results to be returned to
-  // grpc_resolver_next_locked()'s closure.
-  grpc_channel_args* next_results;
-
+  // NextLocked()'s closure.
+  grpc_channel_args* next_results_ = nullptr;
   // Results to use for the pretended re-resolution in
-  // fake_resolver_channel_saw_error_locked().
-  grpc_channel_args* results_upon_error;
-
+  // RequestReresolutionLocked().
+  grpc_channel_args* reresolution_results_ = nullptr;
   // TODO(juanlishen): This can go away once pick_first is changed to not throw
   // away its subchannels, since that will eliminate its dependence on
   // channel_saw_error_locked() causing an immediate resolver return.
   // A copy of the most-recently used resolution results.
-  grpc_channel_args* last_used_results;
-
-  // Pending next completion, or NULL
-  grpc_closure* next_completion;
-
-  // Target result address for next completion
-  grpc_channel_args** target_result;
-} fake_resolver;
-
-static void fake_resolver_destroy(grpc_resolver* gr) {
-  fake_resolver* r = (fake_resolver*)gr;
-  grpc_channel_args_destroy(r->next_results);
-  grpc_channel_args_destroy(r->results_upon_error);
-  grpc_channel_args_destroy(r->last_used_results);
-  grpc_channel_args_destroy(r->channel_args);
-  gpr_free(r);
-}
-
-static void fake_resolver_shutdown_locked(grpc_resolver* resolver) {
-  fake_resolver* r = (fake_resolver*)resolver;
-  if (r->next_completion != nullptr) {
-    *r->target_result = nullptr;
-    GRPC_CLOSURE_SCHED(r->next_completion, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-                                               "Resolver Shutdown"));
-    r->next_completion = nullptr;
-  }
-}
-
-static void fake_resolver_maybe_finish_next_locked(fake_resolver* r) {
-  if (r->next_completion != nullptr && r->next_results != nullptr) {
-    *r->target_result =
-        grpc_channel_args_union(r->next_results, r->channel_args);
-    grpc_channel_args_destroy(r->next_results);
-    r->next_results = nullptr;
-    GRPC_CLOSURE_SCHED(r->next_completion, GRPC_ERROR_NONE);
-    r->next_completion = nullptr;
-  }
-}
-
-static void fake_resolver_channel_saw_error_locked(grpc_resolver* resolver) {
-  fake_resolver* r = (fake_resolver*)resolver;
-  // A resolution must have been returned before an error is seen.
-  GPR_ASSERT(r->last_used_results != nullptr);
-  grpc_channel_args_destroy(r->next_results);
-  if (r->results_upon_error != nullptr) {
-    r->next_results = grpc_channel_args_copy(r->results_upon_error);
-  } else {
-    // If results_upon_error is unavailable, re-resolve with the most-recently
-    // used results to avoid a no-op re-resolution.
-    r->next_results = grpc_channel_args_copy(r->last_used_results);
-  }
-  fake_resolver_maybe_finish_next_locked(r);
-}
-
-static void fake_resolver_next_locked(grpc_resolver* resolver,
-                                      grpc_channel_args** target_result,
-                                      grpc_closure* on_complete) {
-  fake_resolver* r = (fake_resolver*)resolver;
-  GPR_ASSERT(!r->next_completion);
-  r->next_completion = on_complete;
-  r->target_result = target_result;
-  fake_resolver_maybe_finish_next_locked(r);
-}
-
-static const grpc_resolver_vtable fake_resolver_vtable = {
-    fake_resolver_destroy, fake_resolver_shutdown_locked,
-    fake_resolver_channel_saw_error_locked, fake_resolver_next_locked};
-
-struct grpc_fake_resolver_response_generator {
-  fake_resolver* resolver;  // Set by the fake_resolver constructor to itself.
-  gpr_refcount refcount;
+  grpc_channel_args* last_used_results_ = nullptr;
+  // pending next completion, or NULL
+  grpc_closure* next_completion_ = nullptr;
+  // target result address for next completion
+  grpc_channel_args** target_result_ = nullptr;
+  // if true, return failure
+  bool return_failure_ = false;
 };
 
-grpc_fake_resolver_response_generator*
-grpc_fake_resolver_response_generator_create() {
-  grpc_fake_resolver_response_generator* generator =
-      (grpc_fake_resolver_response_generator*)gpr_zalloc(sizeof(*generator));
-  gpr_ref_init(&generator->refcount, 1);
-  return generator;
+FakeResolver::FakeResolver(const ResolverArgs& args) : Resolver(args.combiner) {
+  channel_args_ = grpc_channel_args_copy(args.args);
+  FakeResolverResponseGenerator* response_generator =
+      FakeResolverResponseGenerator::GetFromArgs(args.args);
+  if (response_generator != nullptr) response_generator->resolver_ = this;
 }
 
-grpc_fake_resolver_response_generator*
-grpc_fake_resolver_response_generator_ref(
-    grpc_fake_resolver_response_generator* generator) {
-  gpr_ref(&generator->refcount);
-  return generator;
+FakeResolver::~FakeResolver() {
+  grpc_channel_args_destroy(next_results_);
+  grpc_channel_args_destroy(reresolution_results_);
+  grpc_channel_args_destroy(last_used_results_);
+  grpc_channel_args_destroy(channel_args_);
 }
 
-void grpc_fake_resolver_response_generator_unref(
-    grpc_fake_resolver_response_generator* generator) {
-  if (gpr_unref(&generator->refcount)) {
-    gpr_free(generator);
-  }
+void FakeResolver::NextLocked(grpc_channel_args** target_result,
+                              grpc_closure* on_complete) {
+  GPR_ASSERT(next_completion_ == nullptr);
+  next_completion_ = on_complete;
+  target_result_ = target_result;
+  MaybeFinishNextLocked();
 }
 
-typedef struct set_response_closure_arg {
-  grpc_closure set_response_closure;
-  grpc_fake_resolver_response_generator* generator;
-  grpc_channel_args* response;
-  bool upon_error;
-} set_response_closure_arg;
-
-static void set_response_closure_locked(void* arg, grpc_error* error) {
-  set_response_closure_arg* closure_arg = (set_response_closure_arg*)arg;
-  grpc_fake_resolver_response_generator* generator = closure_arg->generator;
-  fake_resolver* r = generator->resolver;
-  if (!closure_arg->upon_error) {
-    grpc_channel_args_destroy(r->next_results);
-    r->next_results = closure_arg->response;
-    grpc_channel_args_destroy(r->last_used_results);
-    r->last_used_results = grpc_channel_args_copy(closure_arg->response);
-    fake_resolver_maybe_finish_next_locked(r);
+void FakeResolver::RequestReresolutionLocked() {
+  // A resolution must have been returned before an error is seen.
+  GPR_ASSERT(last_used_results_ != nullptr);
+  grpc_channel_args_destroy(next_results_);
+  if (reresolution_results_ != nullptr) {
+    next_results_ = grpc_channel_args_copy(reresolution_results_);
   } else {
-    grpc_channel_args_destroy(r->results_upon_error);
-    r->results_upon_error = closure_arg->response;
+    // If reresolution_results is unavailable, re-resolve with the most-recently
+    // used results to avoid a no-op re-resolution.
+    next_results_ = grpc_channel_args_copy(last_used_results_);
   }
-  gpr_free(closure_arg);
+  MaybeFinishNextLocked();
 }
 
-void grpc_fake_resolver_response_generator_set_response(
-    grpc_fake_resolver_response_generator* generator,
-    grpc_channel_args* response) {
-  GPR_ASSERT(generator->resolver != nullptr);
+void FakeResolver::MaybeFinishNextLocked() {
+  if (next_completion_ != nullptr &&
+      (next_results_ != nullptr || return_failure_)) {
+    *target_result_ =
+        return_failure_ ? nullptr
+                        : grpc_channel_args_union(next_results_, channel_args_);
+    grpc_channel_args_destroy(next_results_);
+    next_results_ = nullptr;
+    GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_NONE);
+    next_completion_ = nullptr;
+    return_failure_ = false;
+  }
+}
+
+void FakeResolver::ShutdownLocked() {
+  if (next_completion_ != nullptr) {
+    *target_result_ = nullptr;
+    GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                                             "Resolver Shutdown"));
+    next_completion_ = nullptr;
+  }
+}
+
+//
+// FakeResolverResponseGenerator
+//
+
+struct SetResponseClosureArg {
+  grpc_closure set_response_closure;
+  FakeResolverResponseGenerator* generator;
+  grpc_channel_args* response;
+};
+
+void FakeResolverResponseGenerator::SetResponseLocked(void* arg,
+                                                      grpc_error* error) {
+  SetResponseClosureArg* closure_arg = static_cast<SetResponseClosureArg*>(arg);
+  FakeResolver* resolver = closure_arg->generator->resolver_;
+  grpc_channel_args_destroy(resolver->next_results_);
+  resolver->next_results_ = closure_arg->response;
+  grpc_channel_args_destroy(resolver->last_used_results_);
+  resolver->last_used_results_ = grpc_channel_args_copy(closure_arg->response);
+  resolver->MaybeFinishNextLocked();
+  Delete(closure_arg);
+}
+
+void FakeResolverResponseGenerator::SetResponse(grpc_channel_args* response) {
   GPR_ASSERT(response != nullptr);
-  set_response_closure_arg* closure_arg =
-      (set_response_closure_arg*)gpr_zalloc(sizeof(*closure_arg));
-  closure_arg->generator = generator;
+  GPR_ASSERT(resolver_ != nullptr);
+  SetResponseClosureArg* closure_arg = New<SetResponseClosureArg>();
+  closure_arg->generator = this;
   closure_arg->response = grpc_channel_args_copy(response);
-  closure_arg->upon_error = false;
-  GRPC_CLOSURE_SCHED(GRPC_CLOSURE_INIT(&closure_arg->set_response_closure,
-                                       set_response_closure_locked, closure_arg,
-                                       grpc_combiner_scheduler(
-                                           generator->resolver->base.combiner)),
-                     GRPC_ERROR_NONE);
+  GRPC_CLOSURE_SCHED(
+      GRPC_CLOSURE_INIT(&closure_arg->set_response_closure, SetResponseLocked,
+                        closure_arg,
+                        grpc_combiner_scheduler(resolver_->combiner())),
+      GRPC_ERROR_NONE);
 }
 
-void grpc_fake_resolver_response_generator_set_response_upon_error(
-    grpc_fake_resolver_response_generator* generator,
+void FakeResolverResponseGenerator::SetReresolutionResponseLocked(
+    void* arg, grpc_error* error) {
+  SetResponseClosureArg* closure_arg = static_cast<SetResponseClosureArg*>(arg);
+  FakeResolver* resolver = closure_arg->generator->resolver_;
+  grpc_channel_args_destroy(resolver->reresolution_results_);
+  resolver->reresolution_results_ = closure_arg->response;
+  Delete(closure_arg);
+}
+
+void FakeResolverResponseGenerator::SetReresolutionResponse(
     grpc_channel_args* response) {
-  GPR_ASSERT(generator->resolver != nullptr);
-  set_response_closure_arg* closure_arg =
-      (set_response_closure_arg*)gpr_zalloc(sizeof(*closure_arg));
-  closure_arg->generator = generator;
+  GPR_ASSERT(resolver_ != nullptr);
+  SetResponseClosureArg* closure_arg = New<SetResponseClosureArg>();
+  closure_arg->generator = this;
   closure_arg->response =
       response != nullptr ? grpc_channel_args_copy(response) : nullptr;
-  closure_arg->upon_error = true;
-  GRPC_CLOSURE_SCHED(GRPC_CLOSURE_INIT(&closure_arg->set_response_closure,
-                                       set_response_closure_locked, closure_arg,
-                                       grpc_combiner_scheduler(
-                                           generator->resolver->base.combiner)),
-                     GRPC_ERROR_NONE);
+  GRPC_CLOSURE_SCHED(
+      GRPC_CLOSURE_INIT(&closure_arg->set_response_closure,
+                        SetReresolutionResponseLocked, closure_arg,
+                        grpc_combiner_scheduler(resolver_->combiner())),
+      GRPC_ERROR_NONE);
 }
 
+void FakeResolverResponseGenerator::SetFailureLocked(void* arg,
+                                                     grpc_error* error) {
+  SetResponseClosureArg* closure_arg = static_cast<SetResponseClosureArg*>(arg);
+  FakeResolver* resolver = closure_arg->generator->resolver_;
+  resolver->return_failure_ = true;
+  resolver->MaybeFinishNextLocked();
+  Delete(closure_arg);
+}
+
+void FakeResolverResponseGenerator::SetFailure() {
+  GPR_ASSERT(resolver_ != nullptr);
+  SetResponseClosureArg* closure_arg = New<SetResponseClosureArg>();
+  closure_arg->generator = this;
+  GRPC_CLOSURE_SCHED(
+      GRPC_CLOSURE_INIT(&closure_arg->set_response_closure, SetFailureLocked,
+                        closure_arg,
+                        grpc_combiner_scheduler(resolver_->combiner())),
+      GRPC_ERROR_NONE);
+}
+
+namespace {
+
 static void* response_generator_arg_copy(void* p) {
-  return grpc_fake_resolver_response_generator_ref(
-      (grpc_fake_resolver_response_generator*)p);
+  FakeResolverResponseGenerator* generator =
+      static_cast<FakeResolverResponseGenerator*>(p);
+  // TODO(roth): We currently deal with this ref manually.  Once the
+  // new channel args code is converted to C++, find a way to track this ref
+  // in a cleaner way.
+  RefCountedPtr<FakeResolverResponseGenerator> copy = generator->Ref();
+  copy.release();
+  return p;
 }
 
 static void response_generator_arg_destroy(void* p) {
-  grpc_fake_resolver_response_generator_unref(
-      (grpc_fake_resolver_response_generator*)p);
+  FakeResolverResponseGenerator* generator =
+      static_cast<FakeResolverResponseGenerator*>(p);
+  generator->Unref();
 }
 
 static int response_generator_cmp(void* a, void* b) { return GPR_ICMP(a, b); }
@@ -234,8 +248,10 @@
     response_generator_arg_copy, response_generator_arg_destroy,
     response_generator_cmp};
 
-grpc_arg grpc_fake_resolver_response_generator_arg(
-    grpc_fake_resolver_response_generator* generator) {
+}  // namespace
+
+grpc_arg FakeResolverResponseGenerator::MakeChannelArg(
+    FakeResolverResponseGenerator* generator) {
   grpc_arg arg;
   arg.type = GRPC_ARG_POINTER;
   arg.key = (char*)GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR;
@@ -244,49 +260,38 @@
   return arg;
 }
 
-grpc_fake_resolver_response_generator*
-grpc_fake_resolver_get_response_generator(const grpc_channel_args* args) {
+FakeResolverResponseGenerator* FakeResolverResponseGenerator::GetFromArgs(
+    const grpc_channel_args* args) {
   const grpc_arg* arg =
       grpc_channel_args_find(args, GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR);
   if (arg == nullptr || arg->type != GRPC_ARG_POINTER) return nullptr;
-  return (grpc_fake_resolver_response_generator*)arg->value.pointer.p;
+  return static_cast<FakeResolverResponseGenerator*>(arg->value.pointer.p);
 }
 
 //
-// fake_resolver_factory
+// Factory
 //
 
-static void fake_resolver_factory_ref(grpc_resolver_factory* factory) {}
+namespace {
 
-static void fake_resolver_factory_unref(grpc_resolver_factory* factory) {}
+class FakeResolverFactory : public ResolverFactory {
+ public:
+  OrphanablePtr<Resolver> CreateResolver(
+      const ResolverArgs& args) const override {
+    return OrphanablePtr<Resolver>(New<FakeResolver>(args));
+  }
 
-static grpc_resolver* fake_resolver_create(grpc_resolver_factory* factory,
-                                           grpc_resolver_args* args) {
-  fake_resolver* r = (fake_resolver*)gpr_zalloc(sizeof(*r));
-  r->channel_args = grpc_channel_args_copy(args->args);
-  grpc_resolver_init(&r->base, &fake_resolver_vtable, args->combiner);
-  grpc_fake_resolver_response_generator* response_generator =
-      grpc_fake_resolver_get_response_generator(args->args);
-  if (response_generator != nullptr) response_generator->resolver = r;
-  return &r->base;
+  const char* scheme() const override { return "fake"; }
+};
+
+}  // namespace
+
+}  // namespace grpc_core
+
+void grpc_resolver_fake_init() {
+  grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
+      grpc_core::UniquePtr<grpc_core::ResolverFactory>(
+          grpc_core::New<grpc_core::FakeResolverFactory>()));
 }
 
-static char* fake_resolver_get_default_authority(grpc_resolver_factory* factory,
-                                                 grpc_uri* uri) {
-  const char* path = uri->path;
-  if (path[0] == '/') ++path;
-  return gpr_strdup(path);
-}
-
-static const grpc_resolver_factory_vtable fake_resolver_factory_vtable = {
-    fake_resolver_factory_ref, fake_resolver_factory_unref,
-    fake_resolver_create, fake_resolver_get_default_authority, "fake"};
-
-static grpc_resolver_factory fake_resolver_factory = {
-    &fake_resolver_factory_vtable};
-
-void grpc_resolver_fake_init(void) {
-  grpc_register_resolver_type(&fake_resolver_factory);
-}
-
-void grpc_resolver_fake_shutdown(void) {}
+void grpc_resolver_fake_shutdown() {}
diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h
index 94f9a8e..e5175f9 100644
--- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h
+++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h
@@ -17,53 +17,67 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FAKE_FAKE_RESOLVER_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FAKE_FAKE_RESOLVER_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/lb_policy_factory.h"
 #include "src/core/ext/filters/client_channel/uri_parser.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gprpp/ref_counted.h"
 
 #define GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR \
   "grpc.fake_resolver.response_generator"
 
-void grpc_resolver_fake_init();
+namespace grpc_core {
 
-// Instances of \a grpc_fake_resolver_response_generator are passed to the
-// fake resolver in a channel argument (see \a
-// grpc_fake_resolver_response_generator_arg) in order to inject and trigger
-// custom resolutions. See also \a
-// grpc_fake_resolver_response_generator_set_response.
-typedef struct grpc_fake_resolver_response_generator
-    grpc_fake_resolver_response_generator;
-grpc_fake_resolver_response_generator*
-grpc_fake_resolver_response_generator_create();
+class FakeResolver;
 
-// Set next response of the fake resolver associated with the \a
-// response_generator instance and trigger a new resolution.
-void grpc_fake_resolver_response_generator_set_response(
-    grpc_fake_resolver_response_generator* generator,
-    grpc_channel_args* response);
+/// A mechanism for generating responses for the fake resolver.
+/// An instance of this class is passed to the fake resolver via a channel
+/// argument (see \a MakeChannelArg()) and used to inject and trigger custom
+/// resolutions.
+// TODO(roth): I would ideally like this to be InternallyRefCounted
+// instead of RefCounted, but external refs are currently needed to
+// encode this in channel args.  Once channel_args are converted to C++,
+// see if we can find a way to fix this.
+class FakeResolverResponseGenerator
+    : public RefCounted<FakeResolverResponseGenerator> {
+ public:
+  FakeResolverResponseGenerator() {}
 
-// Set results_upon_error of the fake resolver associated with the \a
-// response_generator instance. When fake_resolver_channel_saw_error_locked() is
-// called, results_upon_error will be returned as long as it's non-NULL,
-// otherwise the last value set by
-// grpc_fake_resolver_response_generator_set_response() will be returned.
-void grpc_fake_resolver_response_generator_set_response_upon_error(
-    grpc_fake_resolver_response_generator* generator,
-    grpc_channel_args* response);
+  // Instructs the fake resolver associated with the response generator
+  // instance to trigger a new resolution with the specified response.
+  void SetResponse(grpc_channel_args* next_response);
 
-// Return a \a grpc_arg for a \a grpc_fake_resolver_response_generator instance.
-grpc_arg grpc_fake_resolver_response_generator_arg(
-    grpc_fake_resolver_response_generator* generator);
-// Return the \a grpc_fake_resolver_response_generator instance in \a args or
-// NULL.
-grpc_fake_resolver_response_generator*
-grpc_fake_resolver_get_response_generator(const grpc_channel_args* args);
+  // Sets the re-resolution response, which is returned by the fake resolver
+  // when re-resolution is requested (via \a RequestReresolutionLocked()).
+  // The new re-resolution response replaces any previous re-resolution
+  // response that may have been set by a previous call.
+  // If the re-resolution response is set to NULL, then the fake
+  // resolver will return the last value set via \a SetResponse().
+  void SetReresolutionResponse(grpc_channel_args* response);
 
-grpc_fake_resolver_response_generator*
-grpc_fake_resolver_response_generator_ref(
-    grpc_fake_resolver_response_generator* generator);
-void grpc_fake_resolver_response_generator_unref(
-    grpc_fake_resolver_response_generator* generator);
+  // Tells the resolver to return a transient failure (signalled by
+  // returning a null result with no error).
+  void SetFailure();
+
+  // Returns a channel arg containing \a generator.
+  static grpc_arg MakeChannelArg(FakeResolverResponseGenerator* generator);
+
+  // Returns the response generator in \a args, or null if not found.
+  static FakeResolverResponseGenerator* GetFromArgs(
+      const grpc_channel_args* args);
+
+ private:
+  friend class FakeResolver;
+
+  static void SetResponseLocked(void* arg, grpc_error* error);
+  static void SetReresolutionResponseLocked(void* arg, grpc_error* error);
+  static void SetFailureLocked(void* arg, grpc_error* error);
+
+  FakeResolver* resolver_ = nullptr;  // Do not own.
+};
+
+}  // namespace grpc_core
 
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FAKE_FAKE_RESOLVER_H \
         */
diff --git a/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
index 99ad78e..f74ac5a 100644
--- a/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
@@ -16,20 +16,21 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
-#include <grpc/support/port_platform.h>
 #include <grpc/support/string_util.h>
 
 #include "src/core/ext/filters/client_channel/lb_policy_factory.h"
 #include "src/core/ext/filters/client_channel/parse_address.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/resolve_address.h"
@@ -37,115 +38,99 @@
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 
-typedef struct {
-  /** base class: must be first */
-  grpc_resolver base;
-  /** the addresses that we've 'resolved' */
-  grpc_lb_addresses* addresses;
-  /** channel args */
-  grpc_channel_args* channel_args;
-  /** have we published? */
-  bool published;
-  /** pending next completion, or NULL */
-  grpc_closure* next_completion;
-  /** target result address for next completion */
-  grpc_channel_args** target_result;
-} sockaddr_resolver;
+namespace grpc_core {
 
-static void sockaddr_destroy(grpc_resolver* r);
+namespace {
 
-static void sockaddr_maybe_finish_next_locked(sockaddr_resolver* r);
+class SockaddrResolver : public Resolver {
+ public:
+  /// Takes ownership of \a addresses.
+  SockaddrResolver(const ResolverArgs& args, grpc_lb_addresses* addresses);
 
-static void sockaddr_shutdown_locked(grpc_resolver* r);
-static void sockaddr_channel_saw_error_locked(grpc_resolver* r);
-static void sockaddr_next_locked(grpc_resolver* r,
-                                 grpc_channel_args** target_result,
-                                 grpc_closure* on_complete);
+  void NextLocked(grpc_channel_args** result,
+                  grpc_closure* on_complete) override;
 
-static const grpc_resolver_vtable sockaddr_resolver_vtable = {
-    sockaddr_destroy, sockaddr_shutdown_locked,
-    sockaddr_channel_saw_error_locked, sockaddr_next_locked};
+  void RequestReresolutionLocked() override;
 
-static void sockaddr_shutdown_locked(grpc_resolver* resolver) {
-  sockaddr_resolver* r = (sockaddr_resolver*)resolver;
-  if (r->next_completion != nullptr) {
-    *r->target_result = nullptr;
-    GRPC_CLOSURE_SCHED(r->next_completion, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-                                               "Resolver Shutdown"));
-    r->next_completion = nullptr;
+  void ShutdownLocked() override;
+
+ private:
+  virtual ~SockaddrResolver();
+
+  void MaybeFinishNextLocked();
+
+  /// the addresses that we've "resolved"
+  grpc_lb_addresses* addresses_ = nullptr;
+  /// channel args
+  grpc_channel_args* channel_args_ = nullptr;
+  /// have we published?
+  bool published_ = false;
+  /// pending next completion, or NULL
+  grpc_closure* next_completion_ = nullptr;
+  /// target result address for next completion
+  grpc_channel_args** target_result_ = nullptr;
+};
+
+SockaddrResolver::SockaddrResolver(const ResolverArgs& args,
+                                   grpc_lb_addresses* addresses)
+    : Resolver(args.combiner),
+      addresses_(addresses),
+      channel_args_(grpc_channel_args_copy(args.args)) {}
+
+SockaddrResolver::~SockaddrResolver() {
+  grpc_lb_addresses_destroy(addresses_);
+  grpc_channel_args_destroy(channel_args_);
+}
+
+void SockaddrResolver::NextLocked(grpc_channel_args** target_result,
+                                  grpc_closure* on_complete) {
+  GPR_ASSERT(!next_completion_);
+  next_completion_ = on_complete;
+  target_result_ = target_result;
+  MaybeFinishNextLocked();
+}
+
+void SockaddrResolver::RequestReresolutionLocked() {
+  published_ = false;
+  MaybeFinishNextLocked();
+}
+
+void SockaddrResolver::ShutdownLocked() {
+  if (next_completion_ != nullptr) {
+    *target_result_ = nullptr;
+    GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                                             "Resolver Shutdown"));
+    next_completion_ = nullptr;
   }
 }
 
-static void sockaddr_channel_saw_error_locked(grpc_resolver* resolver) {
-  sockaddr_resolver* r = (sockaddr_resolver*)resolver;
-  r->published = false;
-  sockaddr_maybe_finish_next_locked(r);
-}
-
-static void sockaddr_next_locked(grpc_resolver* resolver,
-                                 grpc_channel_args** target_result,
-                                 grpc_closure* on_complete) {
-  sockaddr_resolver* r = (sockaddr_resolver*)resolver;
-  GPR_ASSERT(!r->next_completion);
-  r->next_completion = on_complete;
-  r->target_result = target_result;
-  sockaddr_maybe_finish_next_locked(r);
-}
-
-static void sockaddr_maybe_finish_next_locked(sockaddr_resolver* r) {
-  if (r->next_completion != nullptr && !r->published) {
-    r->published = true;
-    grpc_arg arg = grpc_lb_addresses_create_channel_arg(r->addresses);
-    *r->target_result =
-        grpc_channel_args_copy_and_add(r->channel_args, &arg, 1);
-    GRPC_CLOSURE_SCHED(r->next_completion, GRPC_ERROR_NONE);
-    r->next_completion = nullptr;
+void SockaddrResolver::MaybeFinishNextLocked() {
+  if (next_completion_ != nullptr && !published_) {
+    published_ = true;
+    grpc_arg arg = grpc_lb_addresses_create_channel_arg(addresses_);
+    *target_result_ = grpc_channel_args_copy_and_add(channel_args_, &arg, 1);
+    GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_NONE);
+    next_completion_ = nullptr;
   }
 }
 
-static void sockaddr_destroy(grpc_resolver* gr) {
-  sockaddr_resolver* r = (sockaddr_resolver*)gr;
-  grpc_lb_addresses_destroy(r->addresses);
-  grpc_channel_args_destroy(r->channel_args);
-  gpr_free(r);
-}
+//
+// Factory
+//
 
-static char* ip_get_default_authority(grpc_uri* uri) {
-  const char* path = uri->path;
-  if (path[0] == '/') ++path;
-  return gpr_strdup(path);
-}
+void DoNothing(void* ignored) {}
 
-static char* ipv4_get_default_authority(grpc_resolver_factory* factory,
-                                        grpc_uri* uri) {
-  return ip_get_default_authority(uri);
-}
-
-static char* ipv6_get_default_authority(grpc_resolver_factory* factory,
-                                        grpc_uri* uri) {
-  return ip_get_default_authority(uri);
-}
-
-#ifdef GRPC_HAVE_UNIX_SOCKET
-char* unix_get_default_authority(grpc_resolver_factory* factory,
-                                 grpc_uri* uri) {
-  return gpr_strdup("localhost");
-}
-#endif
-
-static void do_nothing(void* ignored) {}
-
-static grpc_resolver* sockaddr_create(grpc_resolver_args* args,
-                                      bool parse(const grpc_uri* uri,
-                                                 grpc_resolved_address* dst)) {
-  if (0 != strcmp(args->uri->authority, "")) {
-    gpr_log(GPR_ERROR, "authority based uri's not supported by the %s scheme",
-            args->uri->scheme);
-    return nullptr;
+OrphanablePtr<Resolver> CreateSockaddrResolver(
+    const ResolverArgs& args,
+    bool parse(const grpc_uri* uri, grpc_resolved_address* dst)) {
+  if (0 != strcmp(args.uri->authority, "")) {
+    gpr_log(GPR_ERROR, "authority-based URIs not supported by the %s scheme",
+            args.uri->scheme);
+    return OrphanablePtr<Resolver>(nullptr);
   }
-  /* Construct addresses. */
+  // Construct addresses.
   grpc_slice path_slice =
-      grpc_slice_new(args->uri->path, strlen(args->uri->path), do_nothing);
+      grpc_slice_new(args.uri->path, strlen(args.uri->path), DoNothing);
   grpc_slice_buffer path_parts;
   grpc_slice_buffer_init(&path_parts);
   grpc_slice_split(path_slice, ",", &path_parts);
@@ -153,7 +138,7 @@
       path_parts.count, nullptr /* user_data_vtable */);
   bool errors_found = false;
   for (size_t i = 0; i < addresses->num_addresses; i++) {
-    grpc_uri ith_uri = *args->uri;
+    grpc_uri ith_uri = *args.uri;
     char* part_str = grpc_slice_to_c_string(path_parts.slices[i]);
     ith_uri.path = part_str;
     if (!parse(&ith_uri, &addresses->addresses[i].address)) {
@@ -166,48 +151,64 @@
   grpc_slice_unref_internal(path_slice);
   if (errors_found) {
     grpc_lb_addresses_destroy(addresses);
-    return nullptr;
+    return OrphanablePtr<Resolver>(nullptr);
   }
-  /* Instantiate resolver. */
-  sockaddr_resolver* r =
-      (sockaddr_resolver*)gpr_zalloc(sizeof(sockaddr_resolver));
-  r->addresses = addresses;
-  r->channel_args = grpc_channel_args_copy(args->args);
-  grpc_resolver_init(&r->base, &sockaddr_resolver_vtable, args->combiner);
-  return &r->base;
+  // Instantiate resolver.
+  return OrphanablePtr<Resolver>(New<SockaddrResolver>(args, addresses));
 }
 
-/*
- * FACTORY
- */
+class IPv4ResolverFactory : public ResolverFactory {
+ public:
+  OrphanablePtr<Resolver> CreateResolver(
+      const ResolverArgs& args) const override {
+    return CreateSockaddrResolver(args, grpc_parse_ipv4);
+  }
 
-static void sockaddr_factory_ref(grpc_resolver_factory* factory) {}
+  const char* scheme() const override { return "ipv4"; }
+};
 
-static void sockaddr_factory_unref(grpc_resolver_factory* factory) {}
+class IPv6ResolverFactory : public ResolverFactory {
+ public:
+  OrphanablePtr<Resolver> CreateResolver(
+      const ResolverArgs& args) const override {
+    return CreateSockaddrResolver(args, grpc_parse_ipv6);
+  }
 
-#define DECL_FACTORY(name)                                                  \
-  static grpc_resolver* name##_factory_create_resolver(                     \
-      grpc_resolver_factory* factory, grpc_resolver_args* args) {           \
-    return sockaddr_create(args, grpc_parse_##name);                        \
-  }                                                                         \
-  static const grpc_resolver_factory_vtable name##_factory_vtable = {       \
-      sockaddr_factory_ref, sockaddr_factory_unref,                         \
-      name##_factory_create_resolver, name##_get_default_authority, #name}; \
-  static grpc_resolver_factory name##_resolver_factory = {                  \
-      &name##_factory_vtable}
+  const char* scheme() const override { return "ipv6"; }
+};
 
 #ifdef GRPC_HAVE_UNIX_SOCKET
-DECL_FACTORY(unix);
-#endif
-DECL_FACTORY(ipv4);
-DECL_FACTORY(ipv6);
+class UnixResolverFactory : public ResolverFactory {
+ public:
+  OrphanablePtr<Resolver> CreateResolver(
+      const ResolverArgs& args) const override {
+    return CreateSockaddrResolver(args, grpc_parse_unix);
+  }
 
-void grpc_resolver_sockaddr_init(void) {
-  grpc_register_resolver_type(&ipv4_resolver_factory);
-  grpc_register_resolver_type(&ipv6_resolver_factory);
+  UniquePtr<char> GetDefaultAuthority(grpc_uri* uri) const override {
+    return UniquePtr<char>(gpr_strdup("localhost"));
+  }
+
+  const char* scheme() const override { return "unix"; }
+};
+#endif  // GRPC_HAVE_UNIX_SOCKET
+
+}  // namespace
+
+}  // namespace grpc_core
+
+void grpc_resolver_sockaddr_init() {
+  grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
+      grpc_core::UniquePtr<grpc_core::ResolverFactory>(
+          grpc_core::New<grpc_core::IPv4ResolverFactory>()));
+  grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
+      grpc_core::UniquePtr<grpc_core::ResolverFactory>(
+          grpc_core::New<grpc_core::IPv6ResolverFactory>()));
 #ifdef GRPC_HAVE_UNIX_SOCKET
-  grpc_register_resolver_type(&unix_resolver_factory);
+  grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
+      grpc_core::UniquePtr<grpc_core::ResolverFactory>(
+          grpc_core::New<grpc_core::UnixResolverFactory>()));
 #endif
 }
 
-void grpc_resolver_sockaddr_shutdown(void) {}
+void grpc_resolver_sockaddr_shutdown() {}
diff --git a/src/core/ext/filters/client_channel/resolver_factory.cc b/src/core/ext/filters/client_channel/resolver_factory.cc
deleted file mode 100644
index 9b3ec2f..0000000
--- a/src/core/ext/filters/client_channel/resolver_factory.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "src/core/ext/filters/client_channel/resolver_factory.h"
-
-void grpc_resolver_factory_ref(grpc_resolver_factory* factory) {
-  factory->vtable->ref(factory);
-}
-
-void grpc_resolver_factory_unref(grpc_resolver_factory* factory) {
-  factory->vtable->unref(factory);
-}
-
-/** Create a resolver instance for a name */
-grpc_resolver* grpc_resolver_factory_create_resolver(
-    grpc_resolver_factory* factory, grpc_resolver_args* args) {
-  if (factory == nullptr) return nullptr;
-  return factory->vtable->create_resolver(factory, args);
-}
-
-char* grpc_resolver_factory_get_default_authority(
-    grpc_resolver_factory* factory, grpc_uri* uri) {
-  if (factory == nullptr) return nullptr;
-  return factory->vtable->get_default_authority(factory, uri);
-}
diff --git a/src/core/ext/filters/client_channel/resolver_factory.h b/src/core/ext/filters/client_channel/resolver_factory.h
index 170ecc0..ee3cfee 100644
--- a/src/core/ext/filters/client_channel/resolver_factory.h
+++ b/src/core/ext/filters/client_channel/resolver_factory.h
@@ -19,50 +19,53 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FACTORY_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FACTORY_H
 
-#include "src/core/ext/filters/client_channel/client_channel_factory.h"
+#include <grpc/support/port_platform.h>
+
+#include <grpc/support/string_util.h>
+
 #include "src/core/ext/filters/client_channel/resolver.h"
 #include "src/core/ext/filters/client_channel/uri_parser.h"
+#include "src/core/lib/gprpp/abstract.h"
+#include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/gprpp/orphanable.h"
 #include "src/core/lib/iomgr/pollset_set.h"
 
-typedef struct grpc_resolver_factory grpc_resolver_factory;
-typedef struct grpc_resolver_factory_vtable grpc_resolver_factory_vtable;
+namespace grpc_core {
 
-struct grpc_resolver_factory {
-  const grpc_resolver_factory_vtable* vtable;
+struct ResolverArgs {
+  /// The parsed URI to resolve.
+  grpc_uri* uri = nullptr;
+  /// Channel args to be included in resolver results.
+  const grpc_channel_args* args = nullptr;
+  /// Used to drive I/O in the name resolution process.
+  grpc_pollset_set* pollset_set = nullptr;
+  /// The combiner under which all resolver calls will be run.
+  grpc_combiner* combiner = nullptr;
 };
 
-typedef struct grpc_resolver_args {
-  grpc_uri* uri;
-  const grpc_channel_args* args;
-  grpc_pollset_set* pollset_set;
-  grpc_combiner* combiner;
-} grpc_resolver_args;
+class ResolverFactory {
+ public:
+  /// Returns a new resolver instance.
+  virtual OrphanablePtr<Resolver> CreateResolver(const ResolverArgs& args) const
+      GRPC_ABSTRACT;
 
-struct grpc_resolver_factory_vtable {
-  void (*ref)(grpc_resolver_factory* factory);
-  void (*unref)(grpc_resolver_factory* factory);
+  /// Returns a string representing the default authority to use for this
+  /// scheme.
+  virtual UniquePtr<char> GetDefaultAuthority(grpc_uri* uri) const {
+    const char* path = uri->path;
+    if (path[0] == '/') ++path;
+    return UniquePtr<char>(gpr_strdup(path));
+  }
 
-  /** Implementation of grpc_resolver_factory_create_resolver */
-  grpc_resolver* (*create_resolver)(grpc_resolver_factory* factory,
-                                    grpc_resolver_args* args);
+  /// Returns the URI scheme that this factory implements.
+  /// Caller does NOT take ownership of result.
+  virtual const char* scheme() const GRPC_ABSTRACT;
 
-  /** Implementation of grpc_resolver_factory_get_default_authority */
-  char* (*get_default_authority)(grpc_resolver_factory* factory, grpc_uri* uri);
+  virtual ~ResolverFactory() {}
 
-  /** URI scheme that this factory implements */
-  const char* scheme;
+  GRPC_ABSTRACT_BASE_CLASS
 };
 
-void grpc_resolver_factory_ref(grpc_resolver_factory* resolver);
-void grpc_resolver_factory_unref(grpc_resolver_factory* resolver);
-
-/** Create a resolver instance for a name */
-grpc_resolver* grpc_resolver_factory_create_resolver(
-    grpc_resolver_factory* factory, grpc_resolver_args* args);
-
-/** Return a (freshly allocated with gpr_malloc) string representing
-    the default authority to use for this scheme. */
-char* grpc_resolver_factory_get_default_authority(
-    grpc_resolver_factory* factory, grpc_uri* uri);
+}  // namespace grpc_core
 
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FACTORY_H */
diff --git a/src/core/ext/filters/client_channel/resolver_registry.cc b/src/core/ext/filters/client_channel/resolver_registry.cc
index 3f8451d..91c0267 100644
--- a/src/core/ext/filters/client_channel/resolver_registry.cc
+++ b/src/core/ext/filters/client_channel/resolver_registry.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 
 #include <string.h>
@@ -24,133 +26,153 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
-#define MAX_RESOLVERS 10
-#define DEFAULT_RESOLVER_PREFIX_MAX_LENGTH 32
+namespace grpc_core {
 
-static grpc_resolver_factory* g_all_of_the_resolvers[MAX_RESOLVERS];
-static int g_number_of_resolvers = 0;
+namespace {
 
-static char g_default_resolver_prefix[DEFAULT_RESOLVER_PREFIX_MAX_LENGTH] =
-    "dns:///";
+class RegistryState {
+ public:
+  RegistryState() : default_prefix_(gpr_strdup("dns:///")) {}
 
-void grpc_resolver_registry_init() {}
-
-void grpc_resolver_registry_shutdown(void) {
-  for (int i = 0; i < g_number_of_resolvers; i++) {
-    grpc_resolver_factory_unref(g_all_of_the_resolvers[i]);
+  void SetDefaultPrefix(const char* default_resolver_prefix) {
+    GPR_ASSERT(default_resolver_prefix != nullptr);
+    GPR_ASSERT(*default_resolver_prefix != '\0');
+    default_prefix_.reset(gpr_strdup(default_resolver_prefix));
   }
-  // FIXME(ctiller): this should live in grpc_resolver_registry_init,
-  // however that would have the client_channel plugin call this AFTER we start
-  // registering resolvers from third party plugins, and so they'd never show
-  // up.
-  // We likely need some kind of dependency system for plugins.... what form
-  // that takes is TBD.
-  g_number_of_resolvers = 0;
-}
 
-void grpc_resolver_registry_set_default_prefix(
-    const char* default_resolver_prefix) {
-  const size_t len = strlen(default_resolver_prefix);
-  GPR_ASSERT(len < DEFAULT_RESOLVER_PREFIX_MAX_LENGTH &&
-             "default resolver prefix too long");
-  GPR_ASSERT(len > 0 && "default resolver prefix can't be empty");
-  // By the previous assert, default_resolver_prefix is safe to be copied with a
-  // plain strcpy.
-  strcpy(g_default_resolver_prefix, default_resolver_prefix);
-}
-
-void grpc_register_resolver_type(grpc_resolver_factory* factory) {
-  int i;
-  for (i = 0; i < g_number_of_resolvers; i++) {
-    GPR_ASSERT(0 != strcmp(factory->vtable->scheme,
-                           g_all_of_the_resolvers[i]->vtable->scheme));
-  }
-  GPR_ASSERT(g_number_of_resolvers != MAX_RESOLVERS);
-  grpc_resolver_factory_ref(factory);
-  g_all_of_the_resolvers[g_number_of_resolvers++] = factory;
-}
-
-static grpc_resolver_factory* lookup_factory(const char* name) {
-  int i;
-
-  for (i = 0; i < g_number_of_resolvers; i++) {
-    if (0 == strcmp(name, g_all_of_the_resolvers[i]->vtable->scheme)) {
-      return g_all_of_the_resolvers[i];
+  void RegisterResolverFactory(UniquePtr<ResolverFactory> factory) {
+    for (size_t i = 0; i < factories_.size(); ++i) {
+      GPR_ASSERT(strcmp(factories_[i]->scheme(), factory->scheme()) != 0);
     }
+    factories_.push_back(std::move(factory));
   }
-  return nullptr;
-}
 
-grpc_resolver_factory* grpc_resolver_factory_lookup(const char* name) {
-  grpc_resolver_factory* f = lookup_factory(name);
-  if (f) grpc_resolver_factory_ref(f);
-  return f;
-}
+  ResolverFactory* LookupResolverFactory(const char* scheme) const {
+    for (size_t i = 0; i < factories_.size(); ++i) {
+      if (strcmp(scheme, factories_[i]->scheme()) == 0) {
+        return factories_[i].get();
+      }
+    }
+    return nullptr;
+  }
 
-static grpc_resolver_factory* lookup_factory_by_uri(grpc_uri* uri) {
-  if (!uri) return nullptr;
-  return lookup_factory(uri->scheme);
-}
-
-static grpc_resolver_factory* resolve_factory(const char* target,
-                                              grpc_uri** uri,
-                                              char** canonical_target) {
-  grpc_resolver_factory* factory = nullptr;
-
-  GPR_ASSERT(uri != nullptr);
-  *uri = grpc_uri_parse(target, 1);
-  factory = lookup_factory_by_uri(*uri);
-  if (factory == nullptr) {
-    grpc_uri_destroy(*uri);
-    gpr_asprintf(canonical_target, "%s%s", g_default_resolver_prefix, target);
-    *uri = grpc_uri_parse(*canonical_target, 1);
-    factory = lookup_factory_by_uri(*uri);
+  // Returns the factory for the scheme of \a target.  If \a target does
+  // not parse as a URI, prepends \a default_prefix_ and tries again.
+  // If URI parsing is successful (in either attempt), sets \a uri to
+  // point to the parsed URI.
+  // If \a default_prefix_ needs to be prepended, sets \a canonical_target
+  // to the canonical target string.
+  ResolverFactory* FindResolverFactory(const char* target, grpc_uri** uri,
+                                       char** canonical_target) const {
+    GPR_ASSERT(uri != nullptr);
+    *uri = grpc_uri_parse(target, 1);
+    ResolverFactory* factory =
+        *uri == nullptr ? nullptr : LookupResolverFactory((*uri)->scheme);
     if (factory == nullptr) {
-      grpc_uri_destroy(grpc_uri_parse(target, 0));
-      grpc_uri_destroy(grpc_uri_parse(*canonical_target, 0));
-      gpr_log(GPR_ERROR, "don't know how to resolve '%s' or '%s'", target,
-              *canonical_target);
+      grpc_uri_destroy(*uri);
+      gpr_asprintf(canonical_target, "%s%s", default_prefix_.get(), target);
+      *uri = grpc_uri_parse(*canonical_target, 1);
+      factory =
+          *uri == nullptr ? nullptr : LookupResolverFactory((*uri)->scheme);
+      if (factory == nullptr) {
+        grpc_uri_destroy(grpc_uri_parse(target, 0));
+        grpc_uri_destroy(grpc_uri_parse(*canonical_target, 0));
+        gpr_log(GPR_ERROR, "don't know how to resolve '%s' or '%s'", target,
+                *canonical_target);
+      }
     }
+    return factory;
   }
-  return factory;
+
+ private:
+  // We currently support 10 factories without doing additional
+  // allocation.  This number could be raised if there is a case where
+  // more factories are needed and the additional allocations are
+  // hurting performance (which is unlikely, since these allocations
+  // only occur at gRPC initialization time).
+  InlinedVector<UniquePtr<ResolverFactory>, 10> factories_;
+  UniquePtr<char> default_prefix_;
+};
+
+static RegistryState* g_state = nullptr;
+
+}  // namespace
+
+//
+// ResolverRegistry::Builder
+//
+
+void ResolverRegistry::Builder::InitRegistry() {
+  if (g_state == nullptr) g_state = New<RegistryState>();
 }
 
-grpc_resolver* grpc_resolver_create(const char* target,
-                                    const grpc_channel_args* args,
-                                    grpc_pollset_set* pollset_set,
-                                    grpc_combiner* combiner) {
+void ResolverRegistry::Builder::ShutdownRegistry() {
+  Delete(g_state);
+  g_state = nullptr;
+}
+
+void ResolverRegistry::Builder::SetDefaultPrefix(
+    const char* default_resolver_prefix) {
+  InitRegistry();
+  g_state->SetDefaultPrefix(default_resolver_prefix);
+}
+
+void ResolverRegistry::Builder::RegisterResolverFactory(
+    UniquePtr<ResolverFactory> factory) {
+  InitRegistry();
+  g_state->RegisterResolverFactory(std::move(factory));
+}
+
+//
+// ResolverRegistry
+//
+
+ResolverFactory* ResolverRegistry::LookupResolverFactory(const char* scheme) {
+  GPR_ASSERT(g_state != nullptr);
+  return g_state->LookupResolverFactory(scheme);
+}
+
+OrphanablePtr<Resolver> ResolverRegistry::CreateResolver(
+    const char* target, const grpc_channel_args* args,
+    grpc_pollset_set* pollset_set, grpc_combiner* combiner) {
+  GPR_ASSERT(g_state != nullptr);
   grpc_uri* uri = nullptr;
   char* canonical_target = nullptr;
-  grpc_resolver_factory* factory =
-      resolve_factory(target, &uri, &canonical_target);
-  grpc_resolver* resolver;
-  grpc_resolver_args resolver_args;
-  memset(&resolver_args, 0, sizeof(resolver_args));
+  ResolverFactory* factory =
+      g_state->FindResolverFactory(target, &uri, &canonical_target);
+  ResolverArgs resolver_args;
   resolver_args.uri = uri;
   resolver_args.args = args;
   resolver_args.pollset_set = pollset_set;
   resolver_args.combiner = combiner;
-  resolver = grpc_resolver_factory_create_resolver(factory, &resolver_args);
+  OrphanablePtr<Resolver> resolver =
+      factory == nullptr ? nullptr : factory->CreateResolver(resolver_args);
   grpc_uri_destroy(uri);
   gpr_free(canonical_target);
   return resolver;
 }
 
-char* grpc_get_default_authority(const char* target) {
+UniquePtr<char> ResolverRegistry::GetDefaultAuthority(const char* target) {
+  GPR_ASSERT(g_state != nullptr);
   grpc_uri* uri = nullptr;
   char* canonical_target = nullptr;
-  grpc_resolver_factory* factory =
-      resolve_factory(target, &uri, &canonical_target);
-  char* authority = grpc_resolver_factory_get_default_authority(factory, uri);
+  ResolverFactory* factory =
+      g_state->FindResolverFactory(target, &uri, &canonical_target);
+  UniquePtr<char> authority =
+      factory == nullptr ? nullptr : factory->GetDefaultAuthority(uri);
   grpc_uri_destroy(uri);
   gpr_free(canonical_target);
   return authority;
 }
 
-char* grpc_resolver_factory_add_default_prefix_if_needed(const char* target) {
+UniquePtr<char> ResolverRegistry::AddDefaultPrefixIfNeeded(const char* target) {
+  GPR_ASSERT(g_state != nullptr);
   grpc_uri* uri = nullptr;
   char* canonical_target = nullptr;
-  resolve_factory(target, &uri, &canonical_target);
+  g_state->FindResolverFactory(target, &uri, &canonical_target);
   grpc_uri_destroy(uri);
-  return canonical_target == nullptr ? gpr_strdup(target) : canonical_target;
+  return UniquePtr<char>(canonical_target == nullptr ? gpr_strdup(target)
+                                                     : canonical_target);
 }
+
+}  // namespace grpc_core
diff --git a/src/core/ext/filters/client_channel/resolver_registry.h b/src/core/ext/filters/client_channel/resolver_registry.h
index bbd30df..d6ec681 100644
--- a/src/core/ext/filters/client_channel/resolver_registry.h
+++ b/src/core/ext/filters/client_channel/resolver_registry.h
@@ -19,50 +19,65 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_REGISTRY_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_REGISTRY_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/resolver_factory.h"
+#include "src/core/lib/gprpp/inlined_vector.h"
+#include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/gprpp/orphanable.h"
 #include "src/core/lib/iomgr/pollset_set.h"
 
-void grpc_resolver_registry_init();
-void grpc_resolver_registry_shutdown(void);
+namespace grpc_core {
 
-/** Set the default URI prefix to \a default_prefix. */
-void grpc_resolver_registry_set_default_prefix(const char* default_prefix);
+class ResolverRegistry {
+ public:
+  /// Methods used to create and populate the ResolverRegistry.
+  /// NOT THREAD SAFE -- to be used only during global gRPC
+  /// initialization and shutdown.
+  class Builder {
+   public:
+    /// Global initialization and shutdown hooks.
+    static void InitRegistry();
+    static void ShutdownRegistry();
 
-/** Register a resolver type.
-    URI's of \a scheme will be resolved with the given resolver.
-    If \a priority is greater than zero, then the resolver will be eligible
-    to resolve names that are passed in with no scheme. Higher priority
-    resolvers will be tried before lower priority schemes. */
-void grpc_register_resolver_type(grpc_resolver_factory* factory);
+    /// Sets the default URI prefix to \a default_prefix.
+    /// Calls InitRegistry() if it has not already been called.
+    static void SetDefaultPrefix(const char* default_prefix);
 
-/** Create a resolver given \a target.
-    First tries to parse \a target as a URI. If this succeeds, tries
-    to locate a registered resolver factory based on the URI scheme.
-    If parsing or location fails, prefixes default_prefix from
-    grpc_resolver_registry_init to target, and tries again (if default_prefix
-    was not NULL).
-    If a resolver factory was found, use it to instantiate a resolver and
-    return it.
-    If a resolver factory was not found, return NULL.
-    \a args is a set of channel arguments to be included in the result
-    (typically the set of arguments passed in from the client API).
-    \a pollset_set is used to drive IO in the name resolution process, it
-    should not be NULL. */
-grpc_resolver* grpc_resolver_create(const char* target,
-                                    const grpc_channel_args* args,
-                                    grpc_pollset_set* pollset_set,
-                                    grpc_combiner* combiner);
+    /// Registers a resolver factory.  The factory will be used to create a
+    /// resolver for any URI whose scheme matches that of the factory.
+    /// Calls InitRegistry() if it has not already been called.
+    static void RegisterResolverFactory(UniquePtr<ResolverFactory> factory);
+  };
 
-/** Find a resolver factory given a name and return an (owned-by-the-caller)
- *  reference to it */
-grpc_resolver_factory* grpc_resolver_factory_lookup(const char* name);
+  /// Creates a resolver given \a target.
+  /// First tries to parse \a target as a URI. If this succeeds, tries
+  /// to locate a registered resolver factory based on the URI scheme.
+  /// If parsing fails or there is no factory for the URI's scheme,
+  /// prepends default_prefix to target and tries again.
+  /// If a resolver factory is found, uses it to instantiate a resolver and
+  /// returns it; otherwise, returns nullptr.
+  /// \a args, \a pollset_set, and \a combiner are passed to the factory's
+  /// \a CreateResolver() method.
+  /// \a args are the channel args to be included in resolver results.
+  /// \a pollset_set is used to drive I/O in the name resolution process.
+  /// \a combiner is the combiner under which all resolver calls will be run.
+  static OrphanablePtr<Resolver> CreateResolver(const char* target,
+                                                const grpc_channel_args* args,
+                                                grpc_pollset_set* pollset_set,
+                                                grpc_combiner* combiner);
 
-/** Given a target, return a (freshly allocated with gpr_malloc) string
-    representing the default authority to pass from a client. */
-char* grpc_get_default_authority(const char* target);
+  /// Returns the default authority to pass from a client for \a target.
+  static UniquePtr<char> GetDefaultAuthority(const char* target);
 
-/** Returns a newly allocated string containing \a target, adding the
-    default prefix if needed. */
-char* grpc_resolver_factory_add_default_prefix_if_needed(const char* target);
+  /// Returns \a target with the default prefix prepended, if needed.
+  static UniquePtr<char> AddDefaultPrefixIfNeeded(const char* target);
+
+  /// Returns the resolver factory for \a scheme.
+  /// Caller does NOT own the return value.
+  static ResolverFactory* LookupResolverFactory(const char* scheme);
+};
+
+}  // namespace grpc_core
 
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_REGISTRY_H */
diff --git a/src/core/ext/filters/client_channel/retry_throttle.cc b/src/core/ext/filters/client_channel/retry_throttle.cc
index 867d775..45de666 100644
--- a/src/core/ext/filters/client_channel/retry_throttle.cc
+++ b/src/core/ext/filters/client_channel/retry_throttle.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/retry_throttle.h"
 
 #include <limits.h>
@@ -23,10 +25,11 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/atm.h>
-#include <grpc/support/avl.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
 
+#include "src/core/lib/avl/avl.h"
+
 //
 // server_retry_throttle_data
 //
@@ -37,7 +40,7 @@
   int milli_token_ratio;
   gpr_atm milli_tokens;
   // A pointer to the replacement for this grpc_server_retry_throttle_data
-  // entry.  If non-NULL, then this entry is stale and must not be used.
+  // entry.  If non-nullptr, then this entry is stale and must not be used.
   // We hold a reference to the replacement.
   gpr_atm replacement;
 };
@@ -55,12 +58,14 @@
 
 bool grpc_server_retry_throttle_data_record_failure(
     grpc_server_retry_throttle_data* throttle_data) {
+  if (throttle_data == nullptr) return true;
   // First, check if we are stale and need to be replaced.
   get_replacement_throttle_data_if_needed(&throttle_data);
   // We decrement milli_tokens by 1000 (1 token) for each failure.
-  const int new_value = (int)gpr_atm_no_barrier_clamped_add(
-      &throttle_data->milli_tokens, (gpr_atm)-1000, (gpr_atm)0,
-      (gpr_atm)throttle_data->max_milli_tokens);
+  const int new_value = static_cast<int>(gpr_atm_no_barrier_clamped_add(
+      &throttle_data->milli_tokens, static_cast<gpr_atm>(-1000),
+      static_cast<gpr_atm>(0),
+      static_cast<gpr_atm>(throttle_data->max_milli_tokens)));
   // Retries are allowed as long as the new value is above the threshold
   // (max_milli_tokens / 2).
   return new_value > throttle_data->max_milli_tokens / 2;
@@ -68,12 +73,15 @@
 
 void grpc_server_retry_throttle_data_record_success(
     grpc_server_retry_throttle_data* throttle_data) {
+  if (throttle_data == nullptr) return;
   // First, check if we are stale and need to be replaced.
   get_replacement_throttle_data_if_needed(&throttle_data);
   // We increment milli_tokens by milli_token_ratio for each success.
   gpr_atm_no_barrier_clamped_add(
-      &throttle_data->milli_tokens, (gpr_atm)throttle_data->milli_token_ratio,
-      (gpr_atm)0, (gpr_atm)throttle_data->max_milli_tokens);
+      &throttle_data->milli_tokens,
+      static_cast<gpr_atm>(throttle_data->milli_token_ratio),
+      static_cast<gpr_atm>(0),
+      static_cast<gpr_atm>(throttle_data->max_milli_tokens));
 }
 
 grpc_server_retry_throttle_data* grpc_server_retry_throttle_data_ref(
@@ -99,7 +107,8 @@
     int max_milli_tokens, int milli_token_ratio,
     grpc_server_retry_throttle_data* old_throttle_data) {
   grpc_server_retry_throttle_data* throttle_data =
-      (grpc_server_retry_throttle_data*)gpr_malloc(sizeof(*throttle_data));
+      static_cast<grpc_server_retry_throttle_data*>(
+          gpr_malloc(sizeof(*throttle_data)));
   memset(throttle_data, 0, sizeof(*throttle_data));
   gpr_ref_init(&throttle_data->refs, 1);
   throttle_data->max_milli_tokens = max_milli_tokens;
@@ -111,9 +120,9 @@
   // we will start out doing the same thing on the new one.
   if (old_throttle_data != nullptr) {
     double token_fraction =
-        (int)gpr_atm_acq_load(&old_throttle_data->milli_tokens) /
-        (double)old_throttle_data->max_milli_tokens;
-    initial_milli_tokens = (int)(token_fraction * max_milli_tokens);
+        static_cast<int>(gpr_atm_acq_load(&old_throttle_data->milli_tokens)) /
+        static_cast<double>(old_throttle_data->max_milli_tokens);
+    initial_milli_tokens = static_cast<int>(token_fraction * max_milli_tokens);
   }
   gpr_atm_rel_store(&throttle_data->milli_tokens,
                     (gpr_atm)initial_milli_tokens);
@@ -131,28 +140,28 @@
 //
 
 static void* copy_server_name(void* key, void* unused) {
-  return gpr_strdup((const char*)key);
+  return gpr_strdup(static_cast<const char*>(key));
 }
 
 static long compare_server_name(void* key1, void* key2, void* unused) {
-  return strcmp((const char*)key1, (const char*)key2);
+  return strcmp(static_cast<const char*>(key1), static_cast<const char*>(key2));
 }
 
 static void destroy_server_retry_throttle_data(void* value, void* unused) {
   grpc_server_retry_throttle_data* throttle_data =
-      (grpc_server_retry_throttle_data*)value;
+      static_cast<grpc_server_retry_throttle_data*>(value);
   grpc_server_retry_throttle_data_unref(throttle_data);
 }
 
 static void* copy_server_retry_throttle_data(void* value, void* unused) {
   grpc_server_retry_throttle_data* throttle_data =
-      (grpc_server_retry_throttle_data*)value;
+      static_cast<grpc_server_retry_throttle_data*>(value);
   return grpc_server_retry_throttle_data_ref(throttle_data);
 }
 
 static void destroy_server_name(void* key, void* unused) { gpr_free(key); }
 
-static const gpr_avl_vtable avl_vtable = {
+static const grpc_avl_vtable avl_vtable = {
     destroy_server_name, copy_server_name, compare_server_name,
     destroy_server_retry_throttle_data, copy_server_retry_throttle_data};
 
@@ -161,29 +170,30 @@
 //
 
 static gpr_mu g_mu;
-static gpr_avl g_avl;
+static grpc_avl g_avl;
 
 void grpc_retry_throttle_map_init() {
   gpr_mu_init(&g_mu);
-  g_avl = gpr_avl_create(&avl_vtable);
+  g_avl = grpc_avl_create(&avl_vtable);
 }
 
 void grpc_retry_throttle_map_shutdown() {
   gpr_mu_destroy(&g_mu);
-  gpr_avl_unref(g_avl, nullptr);
+  grpc_avl_unref(g_avl, nullptr);
 }
 
 grpc_server_retry_throttle_data* grpc_retry_throttle_map_get_data_for_server(
     const char* server_name, int max_milli_tokens, int milli_token_ratio) {
   gpr_mu_lock(&g_mu);
   grpc_server_retry_throttle_data* throttle_data =
-      (grpc_server_retry_throttle_data*)gpr_avl_get(g_avl, (char*)server_name,
-                                                    nullptr);
+      static_cast<grpc_server_retry_throttle_data*>(
+          grpc_avl_get(g_avl, const_cast<char*>(server_name), nullptr));
   if (throttle_data == nullptr) {
     // Entry not found.  Create a new one.
     throttle_data = grpc_server_retry_throttle_data_create(
         max_milli_tokens, milli_token_ratio, nullptr);
-    g_avl = gpr_avl_add(g_avl, (char*)server_name, throttle_data, nullptr);
+    g_avl = grpc_avl_add(g_avl, const_cast<char*>(server_name), throttle_data,
+                         nullptr);
   } else {
     if (throttle_data->max_milli_tokens != max_milli_tokens ||
         throttle_data->milli_token_ratio != milli_token_ratio) {
@@ -191,7 +201,8 @@
       // the original one.
       throttle_data = grpc_server_retry_throttle_data_create(
           max_milli_tokens, milli_token_ratio, throttle_data);
-      g_avl = gpr_avl_add(g_avl, (char*)server_name, throttle_data, nullptr);
+      g_avl = grpc_avl_add(g_avl, const_cast<char*>(server_name), throttle_data,
+                           nullptr);
     } else {
       // Entry found.  Increase refcount.
       grpc_server_retry_throttle_data_ref(throttle_data);
diff --git a/src/core/ext/filters/client_channel/retry_throttle.h b/src/core/ext/filters/client_channel/retry_throttle.h
index bf99297..0505fc2 100644
--- a/src/core/ext/filters/client_channel/retry_throttle.h
+++ b/src/core/ext/filters/client_channel/retry_throttle.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RETRY_THROTTLE_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RETRY_THROTTLE_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stdbool.h>
 
 /// Tracks retry throttling data for an individual server name.
diff --git a/src/core/ext/filters/client_channel/subchannel.cc b/src/core/ext/filters/client_channel/subchannel.cc
index dc1beee..d7815fb 100644
--- a/src/core/ext/filters/client_channel/subchannel.cc
+++ b/src/core/ext/filters/client_channel/subchannel.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/subchannel.h"
 
 #include <inttypes.h>
@@ -25,7 +27,6 @@
 #include <cstring>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/avl.h>
 #include <grpc/support/string_util.h>
 
 #include "src/core/ext/filters/client_channel/client_channel.h"
@@ -39,6 +40,7 @@
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/gprpp/debug_location.h"
 #include "src/core/lib/gprpp/manual_constructor.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/profiling/timers.h"
@@ -160,7 +162,7 @@
  */
 
 static void connection_destroy(void* arg, grpc_error* error) {
-  grpc_channel_stack* stk = (grpc_channel_stack*)arg;
+  grpc_channel_stack* stk = static_cast<grpc_channel_stack*>(arg);
   grpc_channel_stack_destroy(stk);
   gpr_free(stk);
 }
@@ -170,7 +172,7 @@
  */
 
 static void subchannel_destroy(void* arg, grpc_error* error) {
-  grpc_subchannel* c = (grpc_subchannel*)arg;
+  grpc_subchannel* c = static_cast<grpc_subchannel*>(arg);
   gpr_free((void*)c->filters);
   grpc_channel_args_destroy(c->args);
   grpc_connectivity_state_destroy(&c->state_tracker);
@@ -242,8 +244,9 @@
 void grpc_subchannel_unref(grpc_subchannel* c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
   gpr_atm old_refs;
   // add a weak ref and subtract a strong ref (atomically)
-  old_refs = ref_mutate(c, (gpr_atm)1 - (gpr_atm)(1 << INTERNAL_REF_BITS),
-                        1 REF_MUTATE_PURPOSE("STRONG_UNREF"));
+  old_refs = ref_mutate(
+      c, static_cast<gpr_atm>(1) - static_cast<gpr_atm>(1 << INTERNAL_REF_BITS),
+      1 REF_MUTATE_PURPOSE("STRONG_UNREF"));
   if ((old_refs & STRONG_REF_MASK) == (1 << INTERNAL_REF_BITS)) {
     disconnect(c);
   }
@@ -253,7 +256,8 @@
 void grpc_subchannel_weak_unref(
     grpc_subchannel* c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
   gpr_atm old_refs;
-  old_refs = ref_mutate(c, -(gpr_atm)1, 1 REF_MUTATE_PURPOSE("WEAK_UNREF"));
+  old_refs = ref_mutate(c, -static_cast<gpr_atm>(1),
+                        1 REF_MUTATE_PURPOSE("WEAK_UNREF"));
   if (old_refs == 1) {
     GRPC_CLOSURE_SCHED(
         GRPC_CLOSURE_CREATE(subchannel_destroy, c, grpc_schedule_on_exec_ctx),
@@ -319,15 +323,15 @@
   }
 
   GRPC_STATS_INC_CLIENT_SUBCHANNELS_CREATED();
-  c = (grpc_subchannel*)gpr_zalloc(sizeof(*c));
+  c = static_cast<grpc_subchannel*>(gpr_zalloc(sizeof(*c)));
   c->key = key;
   gpr_atm_no_barrier_store(&c->ref_pair, 1 << INTERNAL_REF_BITS);
   c->connector = connector;
   grpc_connector_ref(c->connector);
   c->num_filters = args->filter_count;
   if (c->num_filters > 0) {
-    c->filters = (const grpc_channel_filter**)gpr_malloc(
-        sizeof(grpc_channel_filter*) * c->num_filters);
+    c->filters = static_cast<const grpc_channel_filter**>(
+        gpr_malloc(sizeof(grpc_channel_filter*) * c->num_filters));
     memcpy((void*)c->filters, args->filters,
            sizeof(grpc_channel_filter*) * c->num_filters);
   } else {
@@ -335,7 +339,7 @@
   }
   c->pollset_set = grpc_pollset_set_create();
   grpc_resolved_address* addr =
-      (grpc_resolved_address*)gpr_malloc(sizeof(*addr));
+      static_cast<grpc_resolved_address*>(gpr_malloc(sizeof(*addr)));
   grpc_get_subchannel_address_arg(args->args, addr);
   grpc_resolved_address* new_address = nullptr;
   grpc_channel_args* new_args = nullptr;
@@ -392,7 +396,7 @@
 }
 
 static void on_external_state_watcher_done(void* arg, grpc_error* error) {
-  external_state_watcher* w = (external_state_watcher*)arg;
+  external_state_watcher* w = static_cast<external_state_watcher*>(arg);
   grpc_closure* follow_up = w->notify;
   if (w->pollset_set != nullptr) {
     grpc_pollset_set_del_pollset_set(w->subchannel->pollset_set,
@@ -408,7 +412,7 @@
 }
 
 static void on_alarm(void* arg, grpc_error* error) {
-  grpc_subchannel* c = (grpc_subchannel*)arg;
+  grpc_subchannel* c = static_cast<grpc_subchannel*>(arg);
   gpr_mu_lock(&c->mu);
   c->have_alarm = false;
   if (c->disconnected) {
@@ -487,7 +491,7 @@
     }
     gpr_mu_unlock(&c->mu);
   } else {
-    w = (external_state_watcher*)gpr_malloc(sizeof(*w));
+    w = static_cast<external_state_watcher*>(gpr_malloc(sizeof(*w)));
     w->subchannel = c;
     w->pollset_set = interested_parties;
     w->notify = notify;
@@ -510,7 +514,7 @@
 
 static void on_connected_subchannel_connectivity_changed(void* p,
                                                          grpc_error* error) {
-  state_watcher* connected_subchannel_watcher = (state_watcher*)p;
+  state_watcher* connected_subchannel_watcher = static_cast<state_watcher*>(p);
   grpc_subchannel* c = connected_subchannel_watcher->subchannel;
   gpr_mu* mu = &c->mu;
 
@@ -571,7 +575,8 @@
   }
   grpc_channel_stack* stk;
   grpc_error* error = grpc_channel_stack_builder_finish(
-      builder, 0, 1, connection_destroy, nullptr, (void**)&stk);
+      builder, 0, 1, connection_destroy, nullptr,
+      reinterpret_cast<void**>(&stk));
   if (error != GRPC_ERROR_NONE) {
     grpc_transport_destroy(c->connecting_result.transport);
     gpr_log(GPR_ERROR, "error initializing subchannel stack: %s",
@@ -582,8 +587,8 @@
   memset(&c->connecting_result, 0, sizeof(c->connecting_result));
 
   /* initialize state watcher */
-  state_watcher* connected_subchannel_watcher =
-      (state_watcher*)gpr_zalloc(sizeof(*connected_subchannel_watcher));
+  state_watcher* connected_subchannel_watcher = static_cast<state_watcher*>(
+      gpr_zalloc(sizeof(*connected_subchannel_watcher)));
   connected_subchannel_watcher->subchannel = c;
   connected_subchannel_watcher->connectivity_state = GRPC_CHANNEL_READY;
   GRPC_CLOSURE_INIT(&connected_subchannel_watcher->closure,
@@ -618,7 +623,7 @@
 }
 
 static void on_subchannel_connected(void* arg, grpc_error* error) {
-  grpc_subchannel* c = (grpc_subchannel*)arg;
+  grpc_subchannel* c = static_cast<grpc_subchannel*>(arg);
   grpc_channel_args* delete_channel_args = c->connecting_result.channel_args;
 
   GRPC_SUBCHANNEL_WEAK_REF(c, "on_subchannel_connected");
@@ -654,8 +659,7 @@
 
 static void subchannel_call_destroy(void* call, grpc_error* error) {
   GPR_TIMER_SCOPE("grpc_subchannel_call_unref.destroy", 0);
-  grpc_subchannel_call* c = (grpc_subchannel_call*)call;
-  GPR_ASSERT(c->schedule_closure_after_destroy != nullptr);
+  grpc_subchannel_call* c = static_cast<grpc_subchannel_call*>(call);
   grpc_core::ConnectedSubchannel* connection = c->connection;
   grpc_call_stack_destroy(SUBCHANNEL_CALL_TO_CALL_STACK(c), nullptr,
                           c->schedule_closure_after_destroy);
@@ -669,9 +673,10 @@
   call->schedule_closure_after_destroy = closure;
 }
 
-void grpc_subchannel_call_ref(
+grpc_subchannel_call* grpc_subchannel_call_ref(
     grpc_subchannel_call* c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
   GRPC_CALL_STACK_REF(SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON);
+  return c;
 }
 
 void grpc_subchannel_call_unref(
@@ -701,6 +706,13 @@
   return subchannel->key;
 }
 
+void* grpc_connected_subchannel_call_get_parent_data(
+    grpc_subchannel_call* subchannel_call) {
+  grpc_channel_stack* chanstk = subchannel_call->connection->channel_stack();
+  return (char*)subchannel_call + sizeof(grpc_subchannel_call) +
+         chanstk->call_stack_size;
+}
+
 grpc_call_stack* grpc_subchannel_call_get_call_stack(
     grpc_subchannel_call* subchannel_call) {
   return SUBCHANNEL_CALL_TO_CALL_STACK(subchannel_call);
@@ -726,9 +738,9 @@
 const char* grpc_get_subchannel_address_uri_arg(const grpc_channel_args* args) {
   const grpc_arg* addr_arg =
       grpc_channel_args_find(args, GRPC_ARG_SUBCHANNEL_ADDRESS);
-  GPR_ASSERT(addr_arg != nullptr);  // Should have been set by LB policy.
-  GPR_ASSERT(addr_arg->type == GRPC_ARG_STRING);
-  return addr_arg->value.string;
+  const char* addr_str = grpc_channel_arg_get_string(addr_arg);
+  GPR_ASSERT(addr_str != nullptr);  // Should have been set by LB policy.
+  return addr_str;
 }
 
 grpc_arg grpc_create_subchannel_address_arg(const grpc_resolved_address* addr) {
@@ -738,8 +750,9 @@
 }
 
 namespace grpc_core {
+
 ConnectedSubchannel::ConnectedSubchannel(grpc_channel_stack* channel_stack)
-    : grpc_core::RefCountedWithTracing(&grpc_trace_stream_refcount),
+    : RefCountedWithTracing<ConnectedSubchannel>(&grpc_trace_stream_refcount),
       channel_stack_(channel_stack) {}
 
 ConnectedSubchannel::~ConnectedSubchannel() {
@@ -770,11 +783,13 @@
 
 grpc_error* ConnectedSubchannel::CreateCall(const CallArgs& args,
                                             grpc_subchannel_call** call) {
-  *call = (grpc_subchannel_call*)gpr_arena_alloc(
-      args.arena,
-      sizeof(grpc_subchannel_call) + channel_stack_->call_stack_size);
+  *call = static_cast<grpc_subchannel_call*>(gpr_arena_alloc(
+      args.arena, sizeof(grpc_subchannel_call) +
+                      channel_stack_->call_stack_size + args.parent_data_size));
   grpc_call_stack* callstk = SUBCHANNEL_CALL_TO_CALL_STACK(*call);
-  Ref(DEBUG_LOCATION, "subchannel_call");
+  RefCountedPtr<ConnectedSubchannel> connection =
+      Ref(DEBUG_LOCATION, "subchannel_call");
+  connection.release();  // Ref is passed to the grpc_subchannel_call object.
   (*call)->connection = this;
   const grpc_call_element_args call_args = {
       callstk,           /* call_stack */
@@ -796,4 +811,5 @@
   grpc_call_stack_set_pollset_or_pollset_set(callstk, args.pollent);
   return GRPC_ERROR_NONE;
 }
+
 }  // namespace grpc_core
diff --git a/src/core/ext/filters/client_channel/subchannel.h b/src/core/ext/filters/client_channel/subchannel.h
index b7593ec..e23aec1 100644
--- a/src/core/ext/filters/client_channel/subchannel.h
+++ b/src/core/ext/filters/client_channel/subchannel.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/connector.h"
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/gpr/arena.h"
@@ -68,7 +70,8 @@
 #endif
 
 namespace grpc_core {
-class ConnectedSubchannel : public grpc_core::RefCountedWithTracing {
+
+class ConnectedSubchannel : public RefCountedWithTracing<ConnectedSubchannel> {
  public:
   struct CallArgs {
     grpc_polling_entity* pollent;
@@ -78,6 +81,7 @@
     gpr_arena* arena;
     grpc_call_context_element* context;
     grpc_call_combiner* call_combiner;
+    size_t parent_data_size;
   };
 
   explicit ConnectedSubchannel(grpc_channel_stack* channel_stack);
@@ -93,6 +97,7 @@
  private:
   grpc_channel_stack* channel_stack_;
 };
+
 }  // namespace grpc_core
 
 grpc_subchannel* grpc_subchannel_ref(
@@ -105,11 +110,17 @@
     grpc_subchannel* channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
 void grpc_subchannel_weak_unref(
     grpc_subchannel* channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
-void grpc_subchannel_call_ref(
+grpc_subchannel_call* grpc_subchannel_call_ref(
     grpc_subchannel_call* call GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
 void grpc_subchannel_call_unref(
     grpc_subchannel_call* call GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
 
+/** Returns a pointer to the parent data associated with \a subchannel_call.
+    The data will be of the size specified in \a parent_data_size
+    field of the args passed to \a grpc_connected_subchannel_create_call(). */
+void* grpc_connected_subchannel_call_get_parent_data(
+    grpc_subchannel_call* subchannel_call);
+
 /** poll the current connectivity state of a channel */
 grpc_connectivity_state grpc_subchannel_check_connectivity(
     grpc_subchannel* channel, grpc_error** error);
diff --git a/src/core/ext/filters/client_channel/subchannel_index.cc b/src/core/ext/filters/client_channel/subchannel_index.cc
index 052b047..cb02b1a 100644
--- a/src/core/ext/filters/client_channel/subchannel_index.cc
+++ b/src/core/ext/filters/client_channel/subchannel_index.cc
@@ -16,21 +16,23 @@
 //
 //
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/subchannel_index.h"
 
 #include <stdbool.h>
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/avl.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/tls.h>
 
+#include "src/core/lib/avl/avl.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/tls.h"
 
 // a map of subchannel_key --> subchannel, used for detecting connections
 // to the same destination in order to share them
-static gpr_avl g_subchannel_index;
+static grpc_avl g_subchannel_index;
 
 static gpr_mu g_mu;
 
@@ -45,13 +47,14 @@
 static grpc_subchannel_key* create_key(
     const grpc_subchannel_args* args,
     grpc_channel_args* (*copy_channel_args)(const grpc_channel_args* args)) {
-  grpc_subchannel_key* k = (grpc_subchannel_key*)gpr_malloc(sizeof(*k));
+  grpc_subchannel_key* k =
+      static_cast<grpc_subchannel_key*>(gpr_malloc(sizeof(*k)));
   k->args.filter_count = args->filter_count;
   if (k->args.filter_count > 0) {
-    k->args.filters = (const grpc_channel_filter**)gpr_malloc(
-        sizeof(*k->args.filters) * k->args.filter_count);
-    memcpy((grpc_channel_filter*)k->args.filters, args->filters,
-           sizeof(*k->args.filters) * k->args.filter_count);
+    k->args.filters = static_cast<const grpc_channel_filter**>(
+        gpr_malloc(sizeof(*k->args.filters) * k->args.filter_count));
+    memcpy(reinterpret_cast<grpc_channel_filter*>(k->args.filters),
+           args->filters, sizeof(*k->args.filters) * k->args.filter_count);
   } else {
     k->args.filters = nullptr;
   }
@@ -82,22 +85,22 @@
 }
 
 void grpc_subchannel_key_destroy(grpc_subchannel_key* k) {
-  gpr_free((grpc_channel_args*)k->args.filters);
-  grpc_channel_args_destroy((grpc_channel_args*)k->args.args);
+  gpr_free(reinterpret_cast<grpc_channel_args*>(k->args.filters));
+  grpc_channel_args_destroy(const_cast<grpc_channel_args*>(k->args.args));
   gpr_free(k);
 }
 
 static void sck_avl_destroy(void* p, void* user_data) {
-  grpc_subchannel_key_destroy((grpc_subchannel_key*)p);
+  grpc_subchannel_key_destroy(static_cast<grpc_subchannel_key*>(p));
 }
 
 static void* sck_avl_copy(void* p, void* unused) {
-  return subchannel_key_copy((grpc_subchannel_key*)p);
+  return subchannel_key_copy(static_cast<grpc_subchannel_key*>(p));
 }
 
 static long sck_avl_compare(void* a, void* b, void* unused) {
-  return grpc_subchannel_key_compare((grpc_subchannel_key*)a,
-                                     (grpc_subchannel_key*)b);
+  return grpc_subchannel_key_compare(static_cast<grpc_subchannel_key*>(a),
+                                     static_cast<grpc_subchannel_key*>(b));
 }
 
 static void scv_avl_destroy(void* p, void* user_data) {
@@ -109,7 +112,7 @@
   return p;
 }
 
-static const gpr_avl_vtable subchannel_avl_vtable = {
+static const grpc_avl_vtable subchannel_avl_vtable = {
     sck_avl_destroy,  // destroy_key
     sck_avl_copy,     // copy_key
     sck_avl_compare,  // compare_keys
@@ -118,7 +121,7 @@
 };
 
 void grpc_subchannel_index_init(void) {
-  g_subchannel_index = gpr_avl_create(&subchannel_avl_vtable);
+  g_subchannel_index = grpc_avl_create(&subchannel_avl_vtable);
   gpr_mu_init(&g_mu);
   gpr_ref_init(&g_refcount, 1);
 }
@@ -133,7 +136,7 @@
 void grpc_subchannel_index_unref(void) {
   if (gpr_unref(&g_refcount)) {
     gpr_mu_destroy(&g_mu);
-    gpr_avl_unref(g_subchannel_index, grpc_core::ExecCtx::Get());
+    grpc_avl_unref(g_subchannel_index, grpc_core::ExecCtx::Get());
   }
 }
 
@@ -143,13 +146,13 @@
   // Lock, and take a reference to the subchannel index.
   // We don't need to do the search under a lock as avl's are immutable.
   gpr_mu_lock(&g_mu);
-  gpr_avl index = gpr_avl_ref(g_subchannel_index, grpc_core::ExecCtx::Get());
+  grpc_avl index = grpc_avl_ref(g_subchannel_index, grpc_core::ExecCtx::Get());
   gpr_mu_unlock(&g_mu);
 
   grpc_subchannel* c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(
-      (grpc_subchannel*)gpr_avl_get(index, key, grpc_core::ExecCtx::Get()),
+      (grpc_subchannel*)grpc_avl_get(index, key, grpc_core::ExecCtx::Get()),
       "index_find");
-  gpr_avl_unref(index, grpc_core::ExecCtx::Get());
+  grpc_avl_unref(index, grpc_core::ExecCtx::Get());
 
   return c;
 }
@@ -165,11 +168,13 @@
     // Compare and swap loop:
     // - take a reference to the current index
     gpr_mu_lock(&g_mu);
-    gpr_avl index = gpr_avl_ref(g_subchannel_index, grpc_core::ExecCtx::Get());
+    grpc_avl index =
+        grpc_avl_ref(g_subchannel_index, grpc_core::ExecCtx::Get());
     gpr_mu_unlock(&g_mu);
 
     // - Check to see if a subchannel already exists
-    c = (grpc_subchannel*)gpr_avl_get(index, key, grpc_core::ExecCtx::Get());
+    c = static_cast<grpc_subchannel*>(
+        grpc_avl_get(index, key, grpc_core::ExecCtx::Get()));
     if (c != nullptr) {
       c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(c, "index_register");
     }
@@ -178,25 +183,25 @@
       need_to_unref_constructed = true;
     } else {
       // no -> update the avl and compare/swap
-      gpr_avl updated =
-          gpr_avl_add(gpr_avl_ref(index, grpc_core::ExecCtx::Get()),
-                      subchannel_key_copy(key),
-                      GRPC_SUBCHANNEL_WEAK_REF(constructed, "index_register"),
-                      grpc_core::ExecCtx::Get());
+      grpc_avl updated =
+          grpc_avl_add(grpc_avl_ref(index, grpc_core::ExecCtx::Get()),
+                       subchannel_key_copy(key),
+                       GRPC_SUBCHANNEL_WEAK_REF(constructed, "index_register"),
+                       grpc_core::ExecCtx::Get());
 
       // it may happen (but it's expected to be unlikely)
       // that some other thread has changed the index:
       // compare/swap here to check that, and retry as necessary
       gpr_mu_lock(&g_mu);
       if (index.root == g_subchannel_index.root) {
-        GPR_SWAP(gpr_avl, updated, g_subchannel_index);
+        GPR_SWAP(grpc_avl, updated, g_subchannel_index);
         c = constructed;
       }
       gpr_mu_unlock(&g_mu);
 
-      gpr_avl_unref(updated, grpc_core::ExecCtx::Get());
+      grpc_avl_unref(updated, grpc_core::ExecCtx::Get());
     }
-    gpr_avl_unref(index, grpc_core::ExecCtx::Get());
+    grpc_avl_unref(index, grpc_core::ExecCtx::Get());
   }
 
   if (need_to_unref_constructed) {
@@ -213,33 +218,34 @@
     // Compare and swap loop:
     // - take a reference to the current index
     gpr_mu_lock(&g_mu);
-    gpr_avl index = gpr_avl_ref(g_subchannel_index, grpc_core::ExecCtx::Get());
+    grpc_avl index =
+        grpc_avl_ref(g_subchannel_index, grpc_core::ExecCtx::Get());
     gpr_mu_unlock(&g_mu);
 
     // Check to see if this key still refers to the previously
     // registered subchannel
-    grpc_subchannel* c =
-        (grpc_subchannel*)gpr_avl_get(index, key, grpc_core::ExecCtx::Get());
+    grpc_subchannel* c = static_cast<grpc_subchannel*>(
+        grpc_avl_get(index, key, grpc_core::ExecCtx::Get()));
     if (c != constructed) {
-      gpr_avl_unref(index, grpc_core::ExecCtx::Get());
+      grpc_avl_unref(index, grpc_core::ExecCtx::Get());
       break;
     }
 
     // compare and swap the update (some other thread may have
     // mutated the index behind us)
-    gpr_avl updated =
-        gpr_avl_remove(gpr_avl_ref(index, grpc_core::ExecCtx::Get()), key,
-                       grpc_core::ExecCtx::Get());
+    grpc_avl updated =
+        grpc_avl_remove(grpc_avl_ref(index, grpc_core::ExecCtx::Get()), key,
+                        grpc_core::ExecCtx::Get());
 
     gpr_mu_lock(&g_mu);
     if (index.root == g_subchannel_index.root) {
-      GPR_SWAP(gpr_avl, updated, g_subchannel_index);
+      GPR_SWAP(grpc_avl, updated, g_subchannel_index);
       done = true;
     }
     gpr_mu_unlock(&g_mu);
 
-    gpr_avl_unref(updated, grpc_core::ExecCtx::Get());
-    gpr_avl_unref(index, grpc_core::ExecCtx::Get());
+    grpc_avl_unref(updated, grpc_core::ExecCtx::Get());
+    grpc_avl_unref(index, grpc_core::ExecCtx::Get());
   }
 }
 
diff --git a/src/core/ext/filters/client_channel/subchannel_index.h b/src/core/ext/filters/client_channel/subchannel_index.h
index bd160a3..a7dae9d 100644
--- a/src/core/ext/filters/client_channel/subchannel_index.h
+++ b/src/core/ext/filters/client_channel/subchannel_index.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_INDEX_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_INDEX_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/subchannel.h"
 
 /** \file Provides an index of active subchannels so that they can be
diff --git a/src/core/ext/filters/client_channel/uri_parser.cc b/src/core/ext/filters/client_channel/uri_parser.cc
index c5f2d68..0572034 100644
--- a/src/core/ext/filters/client_channel/uri_parser.cc
+++ b/src/core/ext/filters/client_channel/uri_parser.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/uri_parser.h"
 
 #include <string.h>
@@ -23,7 +25,6 @@
 #include <grpc/slice_buffer.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
 #include <grpc/support/string_util.h>
 
 #include "src/core/lib/gpr/string.h"
@@ -45,7 +46,7 @@
     gpr_log(GPR_ERROR, "%s%s'", line_prefix, uri_text);
     gpr_free(line_prefix);
 
-    line_prefix = (char*)gpr_malloc(pfx_len + 1);
+    line_prefix = static_cast<char*>(gpr_malloc(pfx_len + 1));
     memset(line_prefix, ' ', pfx_len);
     line_prefix[pfx_len] = 0;
     gpr_log(GPR_ERROR, "%s^ here", line_prefix);
@@ -159,7 +160,7 @@
   gpr_string_split(uri->query, QUERY_PARTS_SEPARATOR, &uri->query_parts,
                    &uri->num_query_parts);
   uri->query_parts_values =
-      (char**)gpr_malloc(uri->num_query_parts * sizeof(char**));
+      static_cast<char**>(gpr_malloc(uri->num_query_parts * sizeof(char**)));
   for (size_t i = 0; i < uri->num_query_parts; i++) {
     char** query_param_parts;
     size_t num_query_param_parts;
@@ -271,7 +272,7 @@
     fragment_end = i;
   }
 
-  uri = (grpc_uri*)gpr_zalloc(sizeof(*uri));
+  uri = static_cast<grpc_uri*>(gpr_zalloc(sizeof(*uri)));
   uri->scheme = decode_and_copy_component(uri_text, scheme_begin, scheme_end);
   uri->authority =
       decode_and_copy_component(uri_text, authority_begin, authority_end);
diff --git a/src/core/ext/filters/client_channel/uri_parser.h b/src/core/ext/filters/client_channel/uri_parser.h
index 24ff06c..d749f23 100644
--- a/src/core/ext/filters/client_channel/uri_parser.h
+++ b/src/core/ext/filters/client_channel/uri_parser.h
@@ -19,8 +19,9 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_URI_PARSER_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_URI_PARSER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stddef.h>
-#include "src/core/lib/iomgr/exec_ctx.h"
 
 typedef struct {
   char* scheme;
diff --git a/src/core/ext/filters/deadline/deadline_filter.cc b/src/core/ext/filters/deadline/deadline_filter.cc
index c430f3d..27d3eac 100644
--- a/src/core/ext/filters/deadline/deadline_filter.cc
+++ b/src/core/ext/filters/deadline/deadline_filter.cc
@@ -14,6 +14,8 @@
 // limitations under the License.
 //
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/deadline/deadline_filter.h"
 
 #include <stdbool.h>
@@ -25,7 +27,6 @@
 #include <grpc/support/time.h>
 
 #include "src/core/lib/channel/channel_stack_builder.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/surface/channel_init.h"
@@ -37,7 +38,7 @@
 // The on_complete callback used when sending a cancel_error batch down the
 // filter stack.  Yields the call combiner when the batch returns.
 static void yield_call_combiner(void* arg, grpc_error* ignored) {
-  grpc_deadline_state* deadline_state = (grpc_deadline_state*)arg;
+  grpc_deadline_state* deadline_state = static_cast<grpc_deadline_state*>(arg);
   GRPC_CALL_COMBINER_STOP(deadline_state->call_combiner,
                           "got on_complete from cancel_stream batch");
   GRPC_CALL_STACK_UNREF(deadline_state->call_stack, "deadline_timer");
@@ -46,8 +47,9 @@
 // This is called via the call combiner, so access to deadline_state is
 // synchronized.
 static void send_cancel_op_in_call_combiner(void* arg, grpc_error* error) {
-  grpc_call_element* elem = (grpc_call_element*)arg;
-  grpc_deadline_state* deadline_state = (grpc_deadline_state*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
+  grpc_deadline_state* deadline_state =
+      static_cast<grpc_deadline_state*>(elem->call_data);
   grpc_transport_stream_op_batch* batch = grpc_make_transport_stream_op(
       GRPC_CLOSURE_INIT(&deadline_state->timer_callback, yield_call_combiner,
                         deadline_state, grpc_schedule_on_exec_ctx));
@@ -58,8 +60,9 @@
 
 // Timer callback.
 static void timer_callback(void* arg, grpc_error* error) {
-  grpc_call_element* elem = (grpc_call_element*)arg;
-  grpc_deadline_state* deadline_state = (grpc_deadline_state*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
+  grpc_deadline_state* deadline_state =
+      static_cast<grpc_deadline_state*>(elem->call_data);
   if (error != GRPC_ERROR_CANCELLED) {
     error = grpc_error_set_int(
         GRPC_ERROR_CREATE_FROM_STATIC_STRING("Deadline Exceeded"),
@@ -85,7 +88,8 @@
   if (deadline == GRPC_MILLIS_INF_FUTURE) {
     return;
   }
-  grpc_deadline_state* deadline_state = (grpc_deadline_state*)elem->call_data;
+  grpc_deadline_state* deadline_state =
+      static_cast<grpc_deadline_state*>(elem->call_data);
   grpc_closure* closure = nullptr;
   switch (deadline_state->timer_state) {
     case GRPC_DEADLINE_STATE_PENDING:
@@ -126,7 +130,7 @@
 
 // Callback run when the call is complete.
 static void on_complete(void* arg, grpc_error* error) {
-  grpc_deadline_state* deadline_state = (grpc_deadline_state*)arg;
+  grpc_deadline_state* deadline_state = static_cast<grpc_deadline_state*>(arg);
   cancel_timer_if_needed(deadline_state);
   // Invoke the next callback.
   GRPC_CLOSURE_RUN(deadline_state->next_on_complete, GRPC_ERROR_REF(error));
@@ -151,9 +155,9 @@
 };
 static void start_timer_after_init(void* arg, grpc_error* error) {
   struct start_timer_after_init_state* state =
-      (struct start_timer_after_init_state*)arg;
+      static_cast<struct start_timer_after_init_state*>(arg);
   grpc_deadline_state* deadline_state =
-      (grpc_deadline_state*)state->elem->call_data;
+      static_cast<grpc_deadline_state*>(state->elem->call_data);
   if (!state->in_call_combiner) {
     // We are initially called without holding the call combiner, so we
     // need to bounce ourselves into it.
@@ -173,7 +177,8 @@
                               grpc_call_stack* call_stack,
                               grpc_call_combiner* call_combiner,
                               grpc_millis deadline) {
-  grpc_deadline_state* deadline_state = (grpc_deadline_state*)elem->call_data;
+  grpc_deadline_state* deadline_state =
+      static_cast<grpc_deadline_state*>(elem->call_data);
   deadline_state->call_stack = call_stack;
   deadline_state->call_combiner = call_combiner;
   // Deadline will always be infinite on servers, so the timer will only be
@@ -187,7 +192,8 @@
     // create a closure to start the timer, and we schedule that closure
     // to be run after call stack initialization is done.
     struct start_timer_after_init_state* state =
-        (struct start_timer_after_init_state*)gpr_zalloc(sizeof(*state));
+        static_cast<struct start_timer_after_init_state*>(
+            gpr_zalloc(sizeof(*state)));
     state->elem = elem;
     state->deadline = deadline;
     GRPC_CLOSURE_INIT(&state->closure, start_timer_after_init, state,
@@ -197,20 +203,23 @@
 }
 
 void grpc_deadline_state_destroy(grpc_call_element* elem) {
-  grpc_deadline_state* deadline_state = (grpc_deadline_state*)elem->call_data;
+  grpc_deadline_state* deadline_state =
+      static_cast<grpc_deadline_state*>(elem->call_data);
   cancel_timer_if_needed(deadline_state);
 }
 
 void grpc_deadline_state_reset(grpc_call_element* elem,
                                grpc_millis new_deadline) {
-  grpc_deadline_state* deadline_state = (grpc_deadline_state*)elem->call_data;
+  grpc_deadline_state* deadline_state =
+      static_cast<grpc_deadline_state*>(elem->call_data);
   cancel_timer_if_needed(deadline_state);
   start_timer_if_needed(elem, new_deadline);
 }
 
 void grpc_deadline_state_client_start_transport_stream_op_batch(
     grpc_call_element* elem, grpc_transport_stream_op_batch* op) {
-  grpc_deadline_state* deadline_state = (grpc_deadline_state*)elem->call_data;
+  grpc_deadline_state* deadline_state =
+      static_cast<grpc_deadline_state*>(elem->call_data);
   if (op->cancel_stream) {
     cancel_timer_if_needed(deadline_state);
   } else {
@@ -278,8 +287,8 @@
 
 // Callback for receiving initial metadata on the server.
 static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
-  grpc_call_element* elem = (grpc_call_element*)arg;
-  server_call_data* calld = (server_call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
+  server_call_data* calld = static_cast<server_call_data*>(elem->call_data);
   // Get deadline from metadata and start the timer if needed.
   start_timer_if_needed(elem, calld->recv_initial_metadata->deadline);
   // Invoke the next callback.
@@ -290,7 +299,7 @@
 // Method for starting a call op for server filter.
 static void server_start_transport_stream_op_batch(
     grpc_call_element* elem, grpc_transport_stream_op_batch* op) {
-  server_call_data* calld = (server_call_data*)elem->call_data;
+  server_call_data* calld = static_cast<server_call_data*>(elem->call_data);
   if (op->cancel_stream) {
     cancel_timer_if_needed(&calld->base.deadline_state);
   } else {
@@ -360,7 +369,8 @@
   return grpc_deadline_checking_enabled(
              grpc_channel_stack_builder_get_channel_arguments(builder))
              ? grpc_channel_stack_builder_prepend_filter(
-                   builder, (const grpc_channel_filter*)arg, nullptr, nullptr)
+                   builder, static_cast<const grpc_channel_filter*>(arg),
+                   nullptr, nullptr)
              : true;
 }
 
diff --git a/src/core/ext/filters/deadline/deadline_filter.h b/src/core/ext/filters/deadline/deadline_filter.h
index 4de817e..13207cb 100644
--- a/src/core/ext/filters/deadline/deadline_filter.h
+++ b/src/core/ext/filters/deadline/deadline_filter.h
@@ -17,6 +17,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_DEADLINE_DEADLINE_FILTER_H
 #define GRPC_CORE_EXT_FILTERS_DEADLINE_DEADLINE_FILTER_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/iomgr/timer.h"
 
diff --git a/src/core/ext/filters/http/client/http_client_filter.cc b/src/core/ext/filters/http/client/http_client_filter.cc
index befd5a3..ae94ce4 100644
--- a/src/core/ext/filters/http/client/http_client_filter.cc
+++ b/src/core/ext/filters/http/client/http_client_filter.cc
@@ -15,12 +15,16 @@
  *
  */
 
-#include "src/core/ext/filters/http/client/http_client_filter.h"
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
+#include <stdint.h>
 #include <string.h>
+#include "src/core/ext/filters/http/client/http_client_filter.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/manual_constructor.h"
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/slice/b64.h"
 #include "src/core/lib/slice/percent_encoding.h"
@@ -56,8 +60,9 @@
   // State for handling send_message ops.
   grpc_transport_stream_op_batch* send_message_batch;
   size_t send_message_bytes_read;
-  grpc_byte_stream_cache send_message_cache;
-  grpc_caching_byte_stream send_message_caching_stream;
+  grpc_core::ManualConstructor<grpc_core::ByteStreamCache> send_message_cache;
+  grpc_core::ManualConstructor<grpc_core::ByteStreamCache::CachingByteStream>
+      send_message_caching_stream;
   grpc_closure on_send_message_next_done;
   grpc_closure* original_send_message_on_complete;
   grpc_closure send_message_on_complete;
@@ -138,8 +143,8 @@
 }
 
 static void recv_initial_metadata_ready(void* user_data, grpc_error* error) {
-  grpc_call_element* elem = (grpc_call_element*)user_data;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   if (error == GRPC_ERROR_NONE) {
     error = client_filter_incoming_metadata(elem, calld->recv_initial_metadata);
   } else {
@@ -150,8 +155,8 @@
 
 static void recv_trailing_metadata_on_complete(void* user_data,
                                                grpc_error* error) {
-  grpc_call_element* elem = (grpc_call_element*)user_data;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   if (error == GRPC_ERROR_NONE) {
     error =
         client_filter_incoming_metadata(elem, calld->recv_trailing_metadata);
@@ -162,9 +167,9 @@
 }
 
 static void send_message_on_complete(void* arg, grpc_error* error) {
-  grpc_call_element* elem = (grpc_call_element*)arg;
-  call_data* calld = (call_data*)elem->call_data;
-  grpc_byte_stream_cache_destroy(&calld->send_message_cache);
+  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  calld->send_message_cache.Destroy();
   GRPC_CLOSURE_RUN(calld->original_send_message_on_complete,
                    GRPC_ERROR_REF(error));
 }
@@ -173,8 +178,7 @@
 // calld->send_message_bytes_read.
 static grpc_error* pull_slice_from_send_message(call_data* calld) {
   grpc_slice incoming_slice;
-  grpc_error* error = grpc_byte_stream_pull(
-      &calld->send_message_caching_stream.base, &incoming_slice);
+  grpc_error* error = calld->send_message_caching_stream->Pull(&incoming_slice);
   if (error == GRPC_ERROR_NONE) {
     calld->send_message_bytes_read += GRPC_SLICE_LENGTH(incoming_slice);
     grpc_slice_unref_internal(incoming_slice);
@@ -184,26 +188,26 @@
 
 // Reads as many slices as possible from the send_message byte stream.
 // Upon successful return, if calld->send_message_bytes_read ==
-// calld->send_message_caching_stream.base.length, then we have completed
+// calld->send_message_caching_stream->length(), then we have completed
 // reading from the byte stream; otherwise, an async read has been dispatched
 // and on_send_message_next_done() will be invoked when it is complete.
 static grpc_error* read_all_available_send_message_data(call_data* calld) {
-  while (grpc_byte_stream_next(&calld->send_message_caching_stream.base,
-                               ~(size_t)0, &calld->on_send_message_next_done)) {
+  while (calld->send_message_caching_stream->Next(
+      SIZE_MAX, &calld->on_send_message_next_done)) {
     grpc_error* error = pull_slice_from_send_message(calld);
     if (error != GRPC_ERROR_NONE) return error;
     if (calld->send_message_bytes_read ==
-        calld->send_message_caching_stream.base.length) {
+        calld->send_message_caching_stream->length()) {
       break;
     }
   }
   return GRPC_ERROR_NONE;
 }
 
-// Async callback for grpc_byte_stream_next().
+// Async callback for ByteStream::Next().
 static void on_send_message_next_done(void* arg, grpc_error* error) {
-  grpc_call_element* elem = (grpc_call_element*)arg;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   if (error != GRPC_ERROR_NONE) {
     grpc_transport_stream_op_batch_finish_with_failure(
         calld->send_message_batch, error, calld->call_combiner);
@@ -219,12 +223,13 @@
   // here, then we know that all of the data was not available
   // synchronously, so we were not able to do a cached call.  Instead,
   // we just reset the byte stream and then send down the batch as-is.
-  grpc_caching_byte_stream_reset(&calld->send_message_caching_stream);
+  calld->send_message_caching_stream->Reset();
   grpc_call_next_op(elem, calld->send_message_batch);
 }
 
 static char* slice_buffer_to_string(grpc_slice_buffer* slice_buffer) {
-  char* payload_bytes = (char*)gpr_malloc(slice_buffer->length + 1);
+  char* payload_bytes =
+      static_cast<char*>(gpr_malloc(slice_buffer->length + 1));
   size_t offset = 0;
   for (size_t i = 0; i < slice_buffer->count; ++i) {
     memcpy(payload_bytes + offset,
@@ -240,7 +245,7 @@
 // append the base64-encoded query for a GET request.
 static grpc_error* update_path_for_get(grpc_call_element* elem,
                                        grpc_transport_stream_op_batch* batch) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   grpc_slice path_slice =
       GRPC_MDVALUE(batch->payload->send_initial_metadata.send_initial_metadata
                        ->idx.named.path->md);
@@ -249,23 +254,25 @@
   size_t estimated_len = GRPC_SLICE_LENGTH(path_slice);
   estimated_len++; /* for the '?' */
   estimated_len += grpc_base64_estimate_encoded_size(
-      batch->payload->send_message.send_message->length, true /* url_safe */,
+      batch->payload->send_message.send_message->length(), true /* url_safe */,
       false /* multi_line */);
   grpc_slice path_with_query_slice = GRPC_SLICE_MALLOC(estimated_len);
   /* memcopy individual pieces into this slice */
-  char* write_ptr = (char*)GRPC_SLICE_START_PTR(path_with_query_slice);
-  char* original_path = (char*)GRPC_SLICE_START_PTR(path_slice);
+  char* write_ptr =
+      reinterpret_cast<char*> GRPC_SLICE_START_PTR(path_with_query_slice);
+  char* original_path =
+      reinterpret_cast<char*> GRPC_SLICE_START_PTR(path_slice);
   memcpy(write_ptr, original_path, GRPC_SLICE_LENGTH(path_slice));
   write_ptr += GRPC_SLICE_LENGTH(path_slice);
   *write_ptr++ = '?';
   char* payload_bytes =
-      slice_buffer_to_string(&calld->send_message_cache.cache_buffer);
-  grpc_base64_encode_core((char*)write_ptr, payload_bytes,
-                          batch->payload->send_message.send_message->length,
+      slice_buffer_to_string(calld->send_message_cache->cache_buffer());
+  grpc_base64_encode_core(write_ptr, payload_bytes,
+                          batch->payload->send_message.send_message->length(),
                           true /* url_safe */, false /* multi_line */);
   gpr_free(payload_bytes);
   /* remove trailing unused memory and add trailing 0 to terminate string */
-  char* t = (char*)GRPC_SLICE_START_PTR(path_with_query_slice);
+  char* t = reinterpret_cast<char*> GRPC_SLICE_START_PTR(path_with_query_slice);
   /* safe to use strlen since base64_encode will always add '\0' */
   path_with_query_slice =
       grpc_slice_sub_no_ref(path_with_query_slice, 0, strlen(t));
@@ -287,8 +294,8 @@
 
 static void hc_start_transport_stream_op_batch(
     grpc_call_element* elem, grpc_transport_stream_op_batch* batch) {
-  call_data* calld = (call_data*)elem->call_data;
-  channel_data* channeld = (channel_data*)elem->channel_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  channel_data* channeld = static_cast<channel_data*>(elem->channel_data);
   GPR_TIMER_SCOPE("hc_start_transport_stream_op_batch", 0);
 
   if (batch->recv_initial_metadata) {
@@ -320,15 +327,14 @@
     if (batch->send_message &&
         (batch->payload->send_initial_metadata.send_initial_metadata_flags &
          GRPC_INITIAL_METADATA_CACHEABLE_REQUEST) &&
-        batch->payload->send_message.send_message->length <
+        batch->payload->send_message.send_message->length() <
             channeld->max_payload_size_for_get) {
       calld->send_message_bytes_read = 0;
-      grpc_byte_stream_cache_init(&calld->send_message_cache,
-                                  batch->payload->send_message.send_message);
-      grpc_caching_byte_stream_init(&calld->send_message_caching_stream,
-                                    &calld->send_message_cache);
-      batch->payload->send_message.send_message =
-          &calld->send_message_caching_stream.base;
+      calld->send_message_cache.Init(
+          std::move(batch->payload->send_message.send_message));
+      calld->send_message_caching_stream.Init(calld->send_message_cache.get());
+      batch->payload->send_message.send_message.reset(
+          calld->send_message_caching_stream.get());
       calld->original_send_message_on_complete = batch->on_complete;
       batch->on_complete = &calld->send_message_on_complete;
       calld->send_message_batch = batch;
@@ -336,12 +342,12 @@
       if (error != GRPC_ERROR_NONE) goto done;
       // If all the data has been read, then we can use GET.
       if (calld->send_message_bytes_read ==
-          calld->send_message_caching_stream.base.length) {
+          calld->send_message_caching_stream->length()) {
         method = GRPC_MDELEM_METHOD_GET;
         error = update_path_for_get(elem, batch);
         if (error != GRPC_ERROR_NONE) goto done;
         batch->send_message = false;
-        grpc_byte_stream_destroy(&calld->send_message_caching_stream.base);
+        calld->send_message_caching_stream->Orphan();
       } else {
         // Not all data is available.  The batch will be sent down
         // asynchronously in on_send_message_next_done().
@@ -409,7 +415,7 @@
 /* Constructor for call_data */
 static grpc_error* init_call_elem(grpc_call_element* elem,
                                   const grpc_call_element_args* args) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   calld->call_combiner = args->call_combiner;
   GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready,
                     recv_initial_metadata_ready, elem,
@@ -458,7 +464,7 @@
           gpr_log(GPR_ERROR, "%s: must be an integer",
                   GRPC_ARG_MAX_PAYLOAD_SIZE_FOR_GET);
         } else {
-          return (size_t)args->args[i].value.integer;
+          return static_cast<size_t>(args->args[i].value.integer);
         }
       }
     }
@@ -519,7 +525,7 @@
 /* Constructor for channel_data */
 static grpc_error* init_channel_elem(grpc_channel_element* elem,
                                      grpc_channel_element_args* args) {
-  channel_data* chand = (channel_data*)elem->channel_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   GPR_ASSERT(!args->is_last);
   GPR_ASSERT(args->optional_transport != nullptr);
   chand->static_scheme = scheme_from_args(args->channel_args);
@@ -534,7 +540,7 @@
 
 /* Destructor for channel data */
 static void destroy_channel_elem(grpc_channel_element* elem) {
-  channel_data* chand = (channel_data*)elem->channel_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   GRPC_MDELEM_UNREF(chand->user_agent);
 }
 
diff --git a/src/core/ext/filters/http/client/http_client_filter.h b/src/core/ext/filters/http/client/http_client_filter.h
index ec8177c..b7cef33 100644
--- a/src/core/ext/filters/http/client/http_client_filter.h
+++ b/src/core/ext/filters/http/client/http_client_filter.h
@@ -18,6 +18,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_HTTP_CLIENT_HTTP_CLIENT_FILTER_H
 #define GRPC_CORE_EXT_FILTERS_HTTP_CLIENT_HTTP_CLIENT_FILTER_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/channel/channel_stack.h"
 
 /* Processes metadata on the client side for HTTP2 transports */
diff --git a/src/core/ext/filters/http/http_filters_plugin.cc b/src/core/ext/filters/http/http_filters_plugin.cc
index deec77c..f03fa01 100644
--- a/src/core/ext/filters/http/http_filters_plugin.cc
+++ b/src/core/ext/filters/http/http_filters_plugin.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <string.h>
 
 #include "src/core/ext/filters/http/client/http_client_filter.h"
@@ -43,7 +45,7 @@
 static bool maybe_add_optional_filter(grpc_channel_stack_builder* builder,
                                       void* arg) {
   if (!is_building_http_like_transport(builder)) return true;
-  optional_filter* filtarg = (optional_filter*)arg;
+  optional_filter* filtarg = static_cast<optional_filter*>(arg);
   const grpc_channel_args* channel_args =
       grpc_channel_stack_builder_get_channel_arguments(builder);
   bool enable = grpc_channel_arg_get_bool(
@@ -58,7 +60,8 @@
                                       void* arg) {
   return is_building_http_like_transport(builder)
              ? grpc_channel_stack_builder_prepend_filter(
-                   builder, (const grpc_channel_filter*)arg, nullptr, nullptr)
+                   builder, static_cast<const grpc_channel_filter*>(arg),
+                   nullptr, nullptr)
              : true;
 }
 
diff --git a/src/core/ext/filters/http/message_compress/message_compress_filter.cc b/src/core/ext/filters/http/message_compress/message_compress_filter.cc
index 4083014..e7d9949 100644
--- a/src/core/ext/filters/http/message_compress/message_compress_filter.cc
+++ b/src/core/ext/filters/http/message_compress/message_compress_filter.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <assert.h>
 #include <string.h>
 
@@ -30,6 +32,7 @@
 #include "src/core/lib/compression/compression_internal.h"
 #include "src/core/lib/compression/message_compress.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/manual_constructor.h"
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
@@ -60,7 +63,8 @@
   grpc_closure start_send_message_batch_in_call_combiner;
   grpc_transport_stream_op_batch* send_message_batch;
   grpc_slice_buffer slices; /**< Buffers up input slices to be compressed */
-  grpc_slice_buffer_stream replacement_stream;
+  grpc_core::ManualConstructor<grpc_core::SliceBufferByteStream>
+      replacement_stream;
   grpc_closure* original_send_message_on_complete;
   grpc_closure send_message_on_complete;
   grpc_closure on_send_message_next_done;
@@ -80,8 +84,8 @@
 
 static bool skip_compression(grpc_call_element* elem, uint32_t flags,
                              bool has_compression_algorithm) {
-  call_data* calld = (call_data*)elem->call_data;
-  channel_data* channeld = (channel_data*)elem->channel_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  channel_data* channeld = static_cast<channel_data*>(elem->channel_data);
 
   if (flags & (GRPC_WRITE_NO_COMPRESS | GRPC_WRITE_INTERNAL_COMPRESS)) {
     return true;
@@ -103,8 +107,8 @@
 static grpc_error* process_send_initial_metadata(
     grpc_call_element* elem, grpc_metadata_batch* initial_metadata,
     bool* has_compression_algorithm) {
-  call_data* calld = (call_data*)elem->call_data;
-  channel_data* channeld = (channel_data*)elem->channel_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  channel_data* channeld = static_cast<channel_data*>(elem->channel_data);
   *has_compression_algorithm = false;
   grpc_compression_algorithm compression_algorithm;
   grpc_stream_compression_algorithm stream_compression_algorithm =
@@ -194,15 +198,15 @@
 }
 
 static void send_message_on_complete(void* arg, grpc_error* error) {
-  grpc_call_element* elem = (grpc_call_element*)arg;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   grpc_slice_buffer_reset_and_unref_internal(&calld->slices);
   GRPC_CLOSURE_RUN(calld->original_send_message_on_complete,
                    GRPC_ERROR_REF(error));
 }
 
 static void send_message_batch_continue(grpc_call_element* elem) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   // Note: The call to grpc_call_next_op() results in yielding the
   // call combiner, so we need to clear calld->send_message_batch
   // before we do that.
@@ -213,12 +217,12 @@
 }
 
 static void finish_send_message(grpc_call_element* elem) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   // Compress the data if appropriate.
   grpc_slice_buffer tmp;
   grpc_slice_buffer_init(&tmp);
   uint32_t send_flags =
-      calld->send_message_batch->payload->send_message.send_message->flags;
+      calld->send_message_batch->payload->send_message.send_message->flags();
   bool did_compress = grpc_msg_compress(calld->message_compression_algorithm,
                                         &calld->slices, &tmp);
   if (did_compress) {
@@ -226,7 +230,8 @@
       const char* algo_name;
       const size_t before_size = calld->slices.length;
       const size_t after_size = tmp.length;
-      const float savings_ratio = 1.0f - (float)after_size / (float)before_size;
+      const float savings_ratio = 1.0f - static_cast<float>(after_size) /
+                                             static_cast<float>(before_size);
       GPR_ASSERT(grpc_message_compression_algorithm_name(
           calld->message_compression_algorithm, &algo_name));
       gpr_log(GPR_DEBUG,
@@ -250,12 +255,9 @@
   grpc_slice_buffer_destroy_internal(&tmp);
   // Swap out the original byte stream with our new one and send the
   // batch down.
-  grpc_byte_stream_destroy(
-      calld->send_message_batch->payload->send_message.send_message);
-  grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices,
-                                send_flags);
-  calld->send_message_batch->payload->send_message.send_message =
-      &calld->replacement_stream.base;
+  calld->replacement_stream.Init(&calld->slices, send_flags);
+  calld->send_message_batch->payload->send_message.send_message.reset(
+      calld->replacement_stream.get());
   calld->original_send_message_on_complete =
       calld->send_message_batch->on_complete;
   calld->send_message_batch->on_complete = &calld->send_message_on_complete;
@@ -264,7 +266,7 @@
 
 static void fail_send_message_batch_in_call_combiner(void* arg,
                                                      grpc_error* error) {
-  call_data* calld = (call_data*)arg;
+  call_data* calld = static_cast<call_data*>(arg);
   if (calld->send_message_batch != nullptr) {
     grpc_transport_stream_op_batch_finish_with_failure(
         calld->send_message_batch, GRPC_ERROR_REF(error), calld->call_combiner);
@@ -275,9 +277,9 @@
 // Pulls a slice from the send_message byte stream and adds it to calld->slices.
 static grpc_error* pull_slice_from_send_message(call_data* calld) {
   grpc_slice incoming_slice;
-  grpc_error* error = grpc_byte_stream_pull(
-      calld->send_message_batch->payload->send_message.send_message,
-      &incoming_slice);
+  grpc_error* error =
+      calld->send_message_batch->payload->send_message.send_message->Pull(
+          &incoming_slice);
   if (error == GRPC_ERROR_NONE) {
     grpc_slice_buffer_add(&calld->slices, incoming_slice);
   }
@@ -286,13 +288,12 @@
 
 // Reads as many slices as possible from the send_message byte stream.
 // If all data has been read, invokes finish_send_message().  Otherwise,
-// an async call to grpc_byte_stream_next() has been started, which will
+// an async call to ByteStream::Next() has been started, which will
 // eventually result in calling on_send_message_next_done().
 static void continue_reading_send_message(grpc_call_element* elem) {
-  call_data* calld = (call_data*)elem->call_data;
-  while (grpc_byte_stream_next(
-      calld->send_message_batch->payload->send_message.send_message, ~(size_t)0,
-      &calld->on_send_message_next_done)) {
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  while (calld->send_message_batch->payload->send_message.send_message->Next(
+      ~static_cast<size_t>(0), &calld->on_send_message_next_done)) {
     grpc_error* error = pull_slice_from_send_message(calld);
     if (error != GRPC_ERROR_NONE) {
       // Closure callback; does not take ownership of error.
@@ -300,18 +301,18 @@
       GRPC_ERROR_UNREF(error);
       return;
     }
-    if (calld->slices.length ==
-        calld->send_message_batch->payload->send_message.send_message->length) {
+    if (calld->slices.length == calld->send_message_batch->payload->send_message
+                                    .send_message->length()) {
       finish_send_message(elem);
       break;
     }
   }
 }
 
-// Async callback for grpc_byte_stream_next().
+// Async callback for ByteStream::Next().
 static void on_send_message_next_done(void* arg, grpc_error* error) {
-  grpc_call_element* elem = (grpc_call_element*)arg;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   if (error != GRPC_ERROR_NONE) {
     // Closure callback; does not take ownership of error.
     fail_send_message_batch_in_call_combiner(calld, error);
@@ -325,7 +326,7 @@
     return;
   }
   if (calld->slices.length ==
-      calld->send_message_batch->payload->send_message.send_message->length) {
+      calld->send_message_batch->payload->send_message.send_message->length()) {
     finish_send_message(elem);
   } else {
     continue_reading_send_message(elem);
@@ -333,11 +334,12 @@
 }
 
 static void start_send_message_batch(void* arg, grpc_error* unused) {
-  grpc_call_element* elem = (grpc_call_element*)arg;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   if (skip_compression(
           elem,
-          calld->send_message_batch->payload->send_message.send_message->flags,
+          calld->send_message_batch->payload->send_message.send_message
+              ->flags(),
           calld->send_initial_metadata_state == HAS_COMPRESSION_ALGORITHM)) {
     send_message_batch_continue(elem);
   } else {
@@ -348,7 +350,7 @@
 static void compress_start_transport_stream_op_batch(
     grpc_call_element* elem, grpc_transport_stream_op_batch* batch) {
   GPR_TIMER_SCOPE("compress_start_transport_stream_op_batch", 0);
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   // Handle cancel_stream.
   if (batch->cancel_stream) {
     GRPC_ERROR_UNREF(calld->cancel_error);
@@ -362,9 +364,7 @@
                                 grpc_schedule_on_exec_ctx),
             GRPC_ERROR_REF(calld->cancel_error), "failing send_message op");
       } else {
-        grpc_byte_stream_shutdown(
-
-            calld->send_message_batch->payload->send_message.send_message,
+        calld->send_message_batch->payload->send_message.send_message->Shutdown(
             GRPC_ERROR_REF(calld->cancel_error));
       }
     }
@@ -424,7 +424,7 @@
 /* Constructor for call_data */
 static grpc_error* init_call_elem(grpc_call_element* elem,
                                   const grpc_call_element_args* args) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   calld->call_combiner = args->call_combiner;
   calld->cancel_error = GRPC_ERROR_NONE;
   grpc_slice_buffer_init(&calld->slices);
@@ -441,7 +441,7 @@
 static void destroy_call_elem(grpc_call_element* elem,
                               const grpc_call_final_info* final_info,
                               grpc_closure* ignored) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   grpc_slice_buffer_destroy_internal(&calld->slices);
   GRPC_ERROR_UNREF(calld->cancel_error);
 }
@@ -449,7 +449,7 @@
 /* Constructor for channel_data */
 static grpc_error* init_channel_elem(grpc_channel_element* elem,
                                      grpc_channel_element_args* args) {
-  channel_data* channeld = (channel_data*)elem->channel_data;
+  channel_data* channeld = static_cast<channel_data*>(elem->channel_data);
 
   channeld->enabled_algorithms_bitset =
       grpc_channel_args_compression_algorithm_get_states(args->channel_args);
diff --git a/src/core/ext/filters/http/message_compress/message_compress_filter.h b/src/core/ext/filters/http/message_compress/message_compress_filter.h
index 6220791..e163e3c 100644
--- a/src/core/ext/filters/http/message_compress/message_compress_filter.h
+++ b/src/core/ext/filters/http/message_compress/message_compress_filter.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_HTTP_MESSAGE_COMPRESS_MESSAGE_COMPRESS_FILTER_H
 #define GRPC_CORE_EXT_FILTERS_HTTP_MESSAGE_COMPRESS_MESSAGE_COMPRESS_FILTER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/compression_types.h>
 
 #include "src/core/lib/channel/channel_stack.h"
diff --git a/src/core/ext/filters/http/server/http_server_filter.cc b/src/core/ext/filters/http/server/http_server_filter.cc
index 6ea942f..c202015 100644
--- a/src/core/ext/filters/http/server/http_server_filter.cc
+++ b/src/core/ext/filters/http/server/http_server_filter.cc
@@ -16,11 +16,14 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/http/server/http_server_filter.h"
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <string.h>
+#include "src/core/lib/gprpp/manual_constructor.h"
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/slice/b64.h"
 #include "src/core/lib/slice/percent_encoding.h"
@@ -51,9 +54,8 @@
    */
   grpc_closure* recv_message_ready;
   grpc_closure* on_complete;
-  grpc_byte_stream** pp_recv_message;
-  grpc_slice_buffer read_slice_buffer;
-  grpc_slice_buffer_stream read_stream;
+  grpc_core::OrphanablePtr<grpc_core::ByteStream>* pp_recv_message;
+  grpc_core::ManualConstructor<grpc_core::SliceBufferByteStream> read_stream;
 
   /** Receive closures are chained: we inject this closure as the on_done_recv
       up-call on transport_op, and remember to call our on_done_recv member
@@ -95,7 +97,7 @@
 
 static grpc_error* server_filter_incoming_metadata(grpc_call_element* elem,
                                                    grpc_metadata_batch* b) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   grpc_error* error = GRPC_ERROR_NONE;
   static const char* error_name = "Failed processing incoming headers";
 
@@ -204,7 +206,7 @@
      * query parameter which is base64 encoded request payload. */
     const char k_query_separator = '?';
     grpc_slice path_slice = GRPC_MDVALUE(b->idx.named.path->md);
-    uint8_t* path_ptr = (uint8_t*)GRPC_SLICE_START_PTR(path_slice);
+    uint8_t* path_ptr = GRPC_SLICE_START_PTR(path_slice);
     size_t path_length = GRPC_SLICE_LENGTH(path_slice);
     /* offset of the character '?' */
     size_t offset = 0;
@@ -224,12 +226,15 @@
 
       /* decode payload from query and add to the slice buffer to be returned */
       const int k_url_safe = 1;
-      grpc_slice_buffer_add(&calld->read_slice_buffer,
-                            grpc_base64_decode_with_len(
-                                (const char*)GRPC_SLICE_START_PTR(query_slice),
-                                GRPC_SLICE_LENGTH(query_slice), k_url_safe));
-      grpc_slice_buffer_stream_init(&calld->read_stream,
-                                    &calld->read_slice_buffer, 0);
+      grpc_slice_buffer read_slice_buffer;
+      grpc_slice_buffer_init(&read_slice_buffer);
+      grpc_slice_buffer_add(
+          &read_slice_buffer,
+          grpc_base64_decode_with_len(
+              reinterpret_cast<const char*> GRPC_SLICE_START_PTR(query_slice),
+              GRPC_SLICE_LENGTH(query_slice), k_url_safe));
+      calld->read_stream.Init(&read_slice_buffer, 0);
+      grpc_slice_buffer_destroy_internal(&read_slice_buffer);
       calld->seen_path_with_query = true;
       grpc_slice_unref_internal(query_slice);
     } else {
@@ -262,8 +267,8 @@
 }
 
 static void hs_on_recv(void* user_data, grpc_error* err) {
-  grpc_call_element* elem = (grpc_call_element*)user_data;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   if (err == GRPC_ERROR_NONE) {
     err = server_filter_incoming_metadata(elem, calld->recv_initial_metadata);
   } else {
@@ -273,13 +278,14 @@
 }
 
 static void hs_on_complete(void* user_data, grpc_error* err) {
-  grpc_call_element* elem = (grpc_call_element*)user_data;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   /* Call recv_message_ready if we got the payload via the path field */
   if (calld->seen_path_with_query && calld->recv_message_ready != nullptr) {
-    *calld->pp_recv_message = calld->payload_bin_delivered
-                                  ? nullptr
-                                  : (grpc_byte_stream*)&calld->read_stream;
+    calld->pp_recv_message->reset(
+        calld->payload_bin_delivered ? nullptr
+                                     : reinterpret_cast<grpc_core::ByteStream*>(
+                                           calld->read_stream.get()));
     // Re-enter call combiner for recv_message_ready, since the surface
     // code will release the call combiner for each callback it receives.
     GRPC_CALL_COMBINER_START(calld->call_combiner, calld->recv_message_ready,
@@ -292,8 +298,8 @@
 }
 
 static void hs_recv_message_ready(void* user_data, grpc_error* err) {
-  grpc_call_element* elem = (grpc_call_element*)user_data;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   if (calld->seen_path_with_query) {
     // Do nothing. This is probably a GET request, and payload will be
     // returned in hs_on_complete callback.
@@ -309,7 +315,7 @@
 static grpc_error* hs_mutate_op(grpc_call_element* elem,
                                 grpc_transport_stream_op_batch* op) {
   /* grab pointers to our data from the call element */
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
 
   if (op->send_initial_metadata) {
     grpc_error* error = GRPC_ERROR_NONE;
@@ -368,7 +374,7 @@
 static void hs_start_transport_stream_op_batch(
     grpc_call_element* elem, grpc_transport_stream_op_batch* op) {
   GPR_TIMER_SCOPE("hs_start_transport_stream_op_batch", 0);
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   grpc_error* error = hs_mutate_op(elem, op);
   if (error != GRPC_ERROR_NONE) {
     grpc_transport_stream_op_batch_finish_with_failure(op, error,
@@ -382,7 +388,7 @@
 static grpc_error* init_call_elem(grpc_call_element* elem,
                                   const grpc_call_element_args* args) {
   /* grab pointers to our data from the call element */
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   /* initialize members */
   calld->call_combiner = args->call_combiner;
   GRPC_CLOSURE_INIT(&calld->hs_on_recv, hs_on_recv, elem,
@@ -391,7 +397,6 @@
                     grpc_schedule_on_exec_ctx);
   GRPC_CLOSURE_INIT(&calld->hs_recv_message_ready, hs_recv_message_ready, elem,
                     grpc_schedule_on_exec_ctx);
-  grpc_slice_buffer_init(&calld->read_slice_buffer);
   return GRPC_ERROR_NONE;
 }
 
@@ -399,8 +404,10 @@
 static void destroy_call_elem(grpc_call_element* elem,
                               const grpc_call_final_info* final_info,
                               grpc_closure* ignored) {
-  call_data* calld = (call_data*)elem->call_data;
-  grpc_slice_buffer_destroy_internal(&calld->read_slice_buffer);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  if (calld->seen_path_with_query && !calld->payload_bin_delivered) {
+    calld->read_stream->Orphan();
+  }
 }
 
 /* Constructor for channel_data */
diff --git a/src/core/ext/filters/http/server/http_server_filter.h b/src/core/ext/filters/http/server/http_server_filter.h
index c0f678a..4eb130b 100644
--- a/src/core/ext/filters/http/server/http_server_filter.h
+++ b/src/core/ext/filters/http/server/http_server_filter.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_HTTP_SERVER_HTTP_SERVER_FILTER_H
 #define GRPC_CORE_EXT_FILTERS_HTTP_SERVER_HTTP_SERVER_FILTER_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/channel/channel_stack.h"
 
 /* Processes metadata on the client side for HTTP2 transports */
diff --git a/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc b/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc
index 4c87d97..0d349e2 100644
--- a/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc
+++ b/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <string.h>
 
 #include <grpc/load_reporting.h>
@@ -57,8 +59,8 @@
 }  // namespace
 
 static void on_initial_md_ready(void* user_data, grpc_error* err) {
-  grpc_call_element* elem = (grpc_call_element*)user_data;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
 
   if (err == GRPC_ERROR_NONE) {
     if (calld->recv_initial_metadata->idx.named.path != nullptr) {
@@ -88,7 +90,7 @@
 /* Constructor for call_data */
 static grpc_error* init_call_elem(grpc_call_element* elem,
                                   const grpc_call_element_args* args) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   calld->id = (intptr_t)args->call_stack;
   GRPC_CLOSURE_INIT(&calld->on_initial_md_ready, on_initial_md_ready, elem,
                     grpc_schedule_on_exec_ctx);
@@ -111,7 +113,7 @@
 static void destroy_call_elem(grpc_call_element* elem,
                               const grpc_call_final_info* final_info,
                               grpc_closure* ignored) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
 
   /* TODO(dgq): do something with the data
   channel_data *chand = elem->channel_data;
@@ -140,7 +142,7 @@
                                      grpc_channel_element_args* args) {
   GPR_ASSERT(!args->is_last);
 
-  channel_data* chand = (channel_data*)elem->channel_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   chand->id = (intptr_t)args->channel_stack;
 
   /* TODO(dgq): do something with the data
@@ -173,8 +175,8 @@
 
 static grpc_filtered_mdelem lr_trailing_md_filter(void* user_data,
                                                   grpc_mdelem md) {
-  grpc_call_element* elem = (grpc_call_element*)user_data;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_LB_COST_BIN)) {
     calld->trailing_md_string = GRPC_MDVALUE(md);
     return GRPC_FILTERED_REMOVE();
@@ -185,7 +187,7 @@
 static void lr_start_transport_stream_op_batch(
     grpc_call_element* elem, grpc_transport_stream_op_batch* op) {
   GPR_TIMER_SCOPE("lr_start_transport_stream_op_batch", 0);
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
 
   if (op->recv_initial_metadata) {
     /* substitute our callback for the higher callback */
diff --git a/src/core/ext/filters/load_reporting/server_load_reporting_filter.h b/src/core/ext/filters/load_reporting/server_load_reporting_filter.h
index 1baee5e..b459a8e 100644
--- a/src/core/ext/filters/load_reporting/server_load_reporting_filter.h
+++ b/src/core/ext/filters/load_reporting/server_load_reporting_filter.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_LOAD_REPORTING_SERVER_LOAD_REPORTING_FILTER_H
 #define GRPC_CORE_EXT_FILTERS_LOAD_REPORTING_SERVER_LOAD_REPORTING_FILTER_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/load_reporting/server_load_reporting_plugin.h"
 #include "src/core/lib/channel/channel_stack.h"
 
diff --git a/src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc b/src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc
index 9d1dfcb..667c0c5 100644
--- a/src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc
+++ b/src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc
@@ -41,7 +41,8 @@
     grpc_channel_stack_builder* builder, void* arg) {
   const grpc_channel_args* args =
       grpc_channel_stack_builder_get_channel_arguments(builder);
-  const grpc_channel_filter* filter = (const grpc_channel_filter*)arg;
+  const grpc_channel_filter* filter =
+      static_cast<const grpc_channel_filter*>(arg);
   grpc_channel_stack_builder_iterator* it =
       grpc_channel_stack_builder_iterator_find(builder, filter->name);
   const bool already_has_load_reporting_filter =
diff --git a/src/core/ext/filters/load_reporting/server_load_reporting_plugin.h b/src/core/ext/filters/load_reporting/server_load_reporting_plugin.h
index 4b694d3..c20aaa7 100644
--- a/src/core/ext/filters/load_reporting/server_load_reporting_plugin.h
+++ b/src/core/ext/filters/load_reporting/server_load_reporting_plugin.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_LOAD_REPORTING_SERVER_LOAD_REPORTING_PLUGIN_H
 #define GRPC_CORE_EXT_FILTERS_LOAD_REPORTING_SERVER_LOAD_REPORTING_PLUGIN_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/grpc_types.h>
 
 #include "src/core/lib/channel/channel_stack.h"
diff --git a/src/core/ext/filters/max_age/max_age_filter.cc b/src/core/ext/filters/max_age/max_age_filter.cc
index 7b86e4c..1fe8288 100644
--- a/src/core/ext/filters/max_age/max_age_filter.cc
+++ b/src/core/ext/filters/max_age/max_age_filter.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/max_age/max_age_filter.h"
 
 #include <limits.h>
@@ -37,6 +39,12 @@
 #define MAX_CONNECTION_IDLE_INTEGER_OPTIONS \
   { DEFAULT_MAX_CONNECTION_IDLE_MS, 1, INT_MAX }
 
+/* States for idle_state in channel_data */
+#define MAX_IDLE_STATE_INIT ((gpr_atm)0)
+#define MAX_IDLE_STATE_SEEN_EXIT_IDLE ((gpr_atm)1)
+#define MAX_IDLE_STATE_SEEN_ENTER_IDLE ((gpr_atm)2)
+#define MAX_IDLE_STATE_TIMER_SET ((gpr_atm)3)
+
 namespace {
 struct channel_data {
   /* We take a reference to the channel stack for the timer callback */
@@ -64,7 +72,7 @@
   grpc_millis max_connection_age_grace;
   /* Closure to run when the channel's idle duration reaches max_connection_idle
      and should be closed gracefully */
-  grpc_closure close_max_idle_channel;
+  grpc_closure max_idle_timer_cb;
   /* Closure to run when the channel reaches its max age and should be closed
      gracefully */
   grpc_closure close_max_age_channel;
@@ -85,31 +93,122 @@
   grpc_connectivity_state connectivity_state;
   /* Number of active calls */
   gpr_atm call_count;
+  /* TODO(zyc): C++lize this state machine */
+  /* 'idle_state' holds the states of max_idle_timer and channel idleness.
+      It can contain one of the following values:
+     +--------------------------------+----------------+---------+
+     |           idle_state           | max_idle_timer | channel |
+     +--------------------------------+----------------+---------+
+     | MAX_IDLE_STATE_INIT            | unset          | busy    |
+     | MAX_IDLE_STATE_TIMER_SET       | set, valid     | idle    |
+     | MAX_IDLE_STATE_SEEN_EXIT_IDLE  | set, invalid   | busy    |
+     | MAX_IDLE_STATE_SEEN_ENTER_IDLE | set, invalid   | idle    |
+     +--------------------------------+----------------+---------+
+
+     MAX_IDLE_STATE_INIT: The initial and final state of 'idle_state'. The
+     channel has 1 or 1+ active calls, and the the timer is not set. Note that
+     we may put a virtual call to hold this state at channel initialization or
+     shutdown, so that the channel won't enter other states.
+
+     MAX_IDLE_STATE_TIMER_SET: The state after the timer is set and no calls
+     have arrived after the timer is set. The channel must have 0 active call in
+     this state. If the timer is fired in this state, we will close the channel
+     due to idleness.
+
+     MAX_IDLE_STATE_SEEN_EXIT_IDLE: The state after the timer is set and at
+     least one call has arrived after the timer is set. The channel must have 1
+     or 1+ active calls in this state. If the timer is fired in this state, we
+     won't reschudle it.
+
+     MAX_IDLE_STATE_SEEN_ENTER_IDLE: The state after the timer is set and the at
+     least one call has arrived after the timer is set, BUT the channel
+     currently has 1 or 1+ active calls. If the timer is fired in this state, we
+     will reschudle it.
+
+     max_idle_timer will not be cancelled (unless the channel is shutting down).
+     If the timer callback is called when the max_idle_timer is valid (i.e.
+     idle_state is MAX_IDLE_STATE_TIMER_SET), the channel will be closed due to
+     idleness, otherwise the channel won't be changed.
+
+     State transitions:
+         MAX_IDLE_STATE_INIT <-------3------ MAX_IDLE_STATE_SEEN_EXIT_IDLE
+              ^    |                              ^     ^    |
+              |    |                              |     |    |
+              1    2     +-----------4------------+     6    7
+              |    |     |                              |    |
+              |    v     |                              |    v
+       MAX_IDLE_STATE_TIMER_SET <----5------ MAX_IDLE_STATE_SEEN_ENTER_IDLE
+
+     For 1, 3, 5 :  See max_idle_timer_cb() function
+     For 2, 7    :  See decrease_call_count() function
+     For 4, 6    :  See increase_call_count() function */
+  gpr_atm idle_state;
+  /* Time when the channel finished its last outstanding call, in grpc_millis */
+  gpr_atm last_enter_idle_time_millis;
 };
 }  // namespace
 
 /* Increase the nubmer of active calls. Before the increasement, if there are no
    calls, the max_idle_timer should be cancelled. */
 static void increase_call_count(channel_data* chand) {
+  /* Exit idle */
   if (gpr_atm_full_fetch_add(&chand->call_count, 1) == 0) {
-    grpc_timer_cancel(&chand->max_idle_timer);
+    while (true) {
+      gpr_atm idle_state = gpr_atm_acq_load(&chand->idle_state);
+      switch (idle_state) {
+        case MAX_IDLE_STATE_TIMER_SET:
+          /* max_idle_timer_cb may have already set idle_state to
+             MAX_IDLE_STATE_INIT, in this case, we don't need to set it to
+             MAX_IDLE_STATE_SEEN_EXIT_IDLE */
+          gpr_atm_rel_cas(&chand->idle_state, MAX_IDLE_STATE_TIMER_SET,
+                          MAX_IDLE_STATE_SEEN_EXIT_IDLE);
+          return;
+        case MAX_IDLE_STATE_SEEN_ENTER_IDLE:
+          gpr_atm_rel_store(&chand->idle_state, MAX_IDLE_STATE_SEEN_EXIT_IDLE);
+          return;
+        default:
+          /* try again */
+          break;
+      }
+    }
   }
 }
 
 /* Decrease the nubmer of active calls. After the decrement, if there are no
    calls, the max_idle_timer should be started. */
 static void decrease_call_count(channel_data* chand) {
+  /* Enter idle */
   if (gpr_atm_full_fetch_add(&chand->call_count, -1) == 1) {
-    GRPC_CHANNEL_STACK_REF(chand->channel_stack, "max_age max_idle_timer");
-    grpc_timer_init(
-        &chand->max_idle_timer,
-        grpc_core::ExecCtx::Get()->Now() + chand->max_connection_idle,
-        &chand->close_max_idle_channel);
+    gpr_atm_no_barrier_store(&chand->last_enter_idle_time_millis,
+                             (gpr_atm)grpc_core::ExecCtx::Get()->Now());
+    while (true) {
+      gpr_atm idle_state = gpr_atm_acq_load(&chand->idle_state);
+      switch (idle_state) {
+        case MAX_IDLE_STATE_INIT:
+          GRPC_CHANNEL_STACK_REF(chand->channel_stack,
+                                 "max_age max_idle_timer");
+          grpc_timer_init(
+              &chand->max_idle_timer,
+              grpc_core::ExecCtx::Get()->Now() + chand->max_connection_idle,
+              &chand->max_idle_timer_cb);
+          gpr_atm_rel_store(&chand->idle_state, MAX_IDLE_STATE_TIMER_SET);
+          return;
+        case MAX_IDLE_STATE_SEEN_EXIT_IDLE:
+          if (gpr_atm_rel_cas(&chand->idle_state, MAX_IDLE_STATE_SEEN_EXIT_IDLE,
+                              MAX_IDLE_STATE_SEEN_ENTER_IDLE)) {
+            return;
+          }
+          break;
+        default:
+          /* try again */
+          break;
+      }
+    }
   }
 }
 
 static void start_max_idle_timer_after_init(void* arg, grpc_error* error) {
-  channel_data* chand = (channel_data*)arg;
+  channel_data* chand = static_cast<channel_data*>(arg);
   /* Decrease call_count. If there are no active calls at this time,
      max_idle_timer will start here. If the number of active calls is not 0,
      max_idle_timer will start after all the active calls end. */
@@ -119,7 +218,7 @@
 }
 
 static void start_max_age_timer_after_init(void* arg, grpc_error* error) {
-  channel_data* chand = (channel_data*)arg;
+  channel_data* chand = static_cast<channel_data*>(arg);
   gpr_mu_lock(&chand->max_age_timer_mu);
   chand->max_age_timer_pending = true;
   GRPC_CHANNEL_STACK_REF(chand->channel_stack, "max_age max_age_timer");
@@ -137,7 +236,7 @@
 
 static void start_max_age_grace_timer_after_goaway_op(void* arg,
                                                       grpc_error* error) {
-  channel_data* chand = (channel_data*)arg;
+  channel_data* chand = static_cast<channel_data*>(arg);
   gpr_mu_lock(&chand->max_age_timer_mu);
   chand->max_age_grace_timer_pending = true;
   GRPC_CHANNEL_STACK_REF(chand->channel_stack, "max_age max_age_grace_timer");
@@ -152,26 +251,64 @@
                            "max_age start_max_age_grace_timer_after_goaway_op");
 }
 
-static void close_max_idle_channel(void* arg, grpc_error* error) {
-  channel_data* chand = (channel_data*)arg;
+static void close_max_idle_channel(channel_data* chand) {
+  /* Prevent the max idle timer from being set again */
+  gpr_atm_no_barrier_fetch_add(&chand->call_count, 1);
+  grpc_transport_op* op = grpc_make_transport_op(nullptr);
+  op->goaway_error =
+      grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("max_idle"),
+                         GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_NO_ERROR);
+  grpc_channel_element* elem =
+      grpc_channel_stack_element(chand->channel_stack, 0);
+  elem->filter->start_transport_op(elem, op);
+}
+
+static void max_idle_timer_cb(void* arg, grpc_error* error) {
+  channel_data* chand = static_cast<channel_data*>(arg);
   if (error == GRPC_ERROR_NONE) {
-    /* Prevent the max idle timer from being set again */
-    gpr_atm_no_barrier_fetch_add(&chand->call_count, 1);
-    grpc_transport_op* op = grpc_make_transport_op(nullptr);
-    op->goaway_error =
-        grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("max_idle"),
-                           GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_NO_ERROR);
-    grpc_channel_element* elem =
-        grpc_channel_stack_element(chand->channel_stack, 0);
-    elem->filter->start_transport_op(elem, op);
-  } else if (error != GRPC_ERROR_CANCELLED) {
-    GRPC_LOG_IF_ERROR("close_max_idle_channel", error);
+    bool try_again = true;
+    while (try_again) {
+      gpr_atm idle_state = gpr_atm_acq_load(&chand->idle_state);
+      switch (idle_state) {
+        case MAX_IDLE_STATE_TIMER_SET:
+          close_max_idle_channel(chand);
+          /* This MAX_IDLE_STATE_INIT is a final state, we don't have to check
+           * if idle_state has been changed */
+          gpr_atm_rel_store(&chand->idle_state, MAX_IDLE_STATE_INIT);
+          try_again = false;
+          break;
+        case MAX_IDLE_STATE_SEEN_EXIT_IDLE:
+          if (gpr_atm_rel_cas(&chand->idle_state, MAX_IDLE_STATE_SEEN_EXIT_IDLE,
+                              MAX_IDLE_STATE_INIT)) {
+            try_again = false;
+          }
+          break;
+        case MAX_IDLE_STATE_SEEN_ENTER_IDLE:
+          GRPC_CHANNEL_STACK_REF(chand->channel_stack,
+                                 "max_age max_idle_timer");
+          grpc_timer_init(&chand->max_idle_timer,
+                          static_cast<grpc_millis>(gpr_atm_no_barrier_load(
+                              &chand->last_enter_idle_time_millis)) +
+                              chand->max_connection_idle,
+                          &chand->max_idle_timer_cb);
+          /* idle_state may have already been set to
+             MAX_IDLE_STATE_SEEN_EXIT_IDLE by increase_call_count(), in this
+             case, we don't need to set it to MAX_IDLE_STATE_TIMER_SET */
+          gpr_atm_rel_cas(&chand->idle_state, MAX_IDLE_STATE_SEEN_ENTER_IDLE,
+                          MAX_IDLE_STATE_TIMER_SET);
+          try_again = false;
+          break;
+        default:
+          /* try again */
+          break;
+      }
+    }
   }
   GRPC_CHANNEL_STACK_UNREF(chand->channel_stack, "max_age max_idle_timer");
 }
 
 static void close_max_age_channel(void* arg, grpc_error* error) {
-  channel_data* chand = (channel_data*)arg;
+  channel_data* chand = static_cast<channel_data*>(arg);
   gpr_mu_lock(&chand->max_age_timer_mu);
   chand->max_age_timer_pending = false;
   gpr_mu_unlock(&chand->max_age_timer_mu);
@@ -193,7 +330,7 @@
 }
 
 static void force_close_max_age_channel(void* arg, grpc_error* error) {
-  channel_data* chand = (channel_data*)arg;
+  channel_data* chand = static_cast<channel_data*>(arg);
   gpr_mu_lock(&chand->max_age_timer_mu);
   chand->max_age_grace_timer_pending = false;
   gpr_mu_unlock(&chand->max_age_timer_mu);
@@ -211,7 +348,7 @@
 }
 
 static void channel_connectivity_changed(void* arg, grpc_error* error) {
-  channel_data* chand = (channel_data*)arg;
+  channel_data* chand = static_cast<channel_data*>(arg);
   if (chand->connectivity_state != GRPC_CHANNEL_SHUTDOWN) {
     grpc_transport_op* op = grpc_make_transport_op(nullptr);
     op->on_connectivity_state_change = &chand->channel_connectivity_changed;
@@ -233,6 +370,9 @@
        max_idle_timer, and prevent max_idle_timer from being started in the
        future. */
     increase_call_count(chand);
+    if (gpr_atm_acq_load(&chand->idle_state) == MAX_IDLE_STATE_SEEN_EXIT_IDLE) {
+      grpc_timer_cancel(&chand->max_idle_timer);
+    }
   }
 }
 
@@ -249,15 +389,15 @@
   double result = multiplier * value;
   /* INT_MAX - 0.5 converts the value to float, so that result will not be
      cast to int implicitly before the comparison. */
-  return result > ((double)GRPC_MILLIS_INF_FUTURE) - 0.5
+  return result > (static_cast<double>(GRPC_MILLIS_INF_FUTURE)) - 0.5
              ? GRPC_MILLIS_INF_FUTURE
-             : (grpc_millis)result;
+             : static_cast<grpc_millis>(result);
 }
 
 /* Constructor for call_data. */
 static grpc_error* init_call_elem(grpc_call_element* elem,
                                   const grpc_call_element_args* args) {
-  channel_data* chand = (channel_data*)elem->channel_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   increase_call_count(chand);
   return GRPC_ERROR_NONE;
 }
@@ -266,14 +406,14 @@
 static void destroy_call_elem(grpc_call_element* elem,
                               const grpc_call_final_info* final_info,
                               grpc_closure* ignored) {
-  channel_data* chand = (channel_data*)elem->channel_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   decrease_call_count(chand);
 }
 
 /* Constructor for channel_data. */
 static grpc_error* init_channel_elem(grpc_channel_element* elem,
                                      grpc_channel_element_args* args) {
-  channel_data* chand = (channel_data*)elem->channel_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   gpr_mu_init(&chand->max_age_timer_mu);
   chand->max_age_timer_pending = false;
   chand->max_age_grace_timer_pending = false;
@@ -288,6 +428,9 @@
   chand->max_connection_idle = DEFAULT_MAX_CONNECTION_IDLE_MS == INT_MAX
                                    ? GRPC_MILLIS_INF_FUTURE
                                    : DEFAULT_MAX_CONNECTION_IDLE_MS;
+  chand->idle_state = MAX_IDLE_STATE_INIT;
+  gpr_atm_no_barrier_store(&chand->last_enter_idle_time_millis,
+                           GRPC_MILLIS_INF_PAST);
   for (size_t i = 0; i < args->channel_args->num_args; ++i) {
     if (0 == strcmp(args->channel_args->args[i].key,
                     GRPC_ARG_MAX_CONNECTION_AGE_MS)) {
@@ -311,8 +454,8 @@
           value == INT_MAX ? GRPC_MILLIS_INF_FUTURE : value;
     }
   }
-  GRPC_CLOSURE_INIT(&chand->close_max_idle_channel, close_max_idle_channel,
-                    chand, grpc_schedule_on_exec_ctx);
+  GRPC_CLOSURE_INIT(&chand->max_idle_timer_cb, max_idle_timer_cb, chand,
+                    grpc_schedule_on_exec_ctx);
   GRPC_CLOSURE_INIT(&chand->close_max_age_channel, close_max_age_channel, chand,
                     grpc_schedule_on_exec_ctx);
   GRPC_CLOSURE_INIT(&chand->force_close_max_age_channel,
diff --git a/src/core/ext/filters/max_age/max_age_filter.h b/src/core/ext/filters/max_age/max_age_filter.h
index 68fb4a4..9893222 100644
--- a/src/core/ext/filters/max_age/max_age_filter.h
+++ b/src/core/ext/filters/max_age/max_age_filter.h
@@ -17,6 +17,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_MAX_AGE_MAX_AGE_FILTER_H
 #define GRPC_CORE_EXT_FILTERS_MAX_AGE_MAX_AGE_FILTER_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/channel/channel_stack.h"
 
 extern const grpc_channel_filter grpc_max_age_filter;
diff --git a/src/core/ext/filters/message_size/message_size_filter.cc b/src/core/ext/filters/message_size/message_size_filter.cc
index 8d76c4a..c7fc3f2 100644
--- a/src/core/ext/filters/message_size/message_size_filter.cc
+++ b/src/core/ext/filters/message_size/message_size_filter.cc
@@ -14,6 +14,8 @@
 // limitations under the License.
 //
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/message_size/message_size_filter.h"
 
 #include <limits.h>
@@ -27,6 +29,8 @@
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/channel_stack_builder.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/ref_counted.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/surface/channel_init.h"
 #include "src/core/lib/transport/service_config.h"
 
@@ -35,27 +39,29 @@
   int max_recv_size;
 } message_size_limits;
 
-typedef struct {
-  gpr_refcount refs;
-  message_size_limits limits;
-} refcounted_message_size_limits;
+namespace grpc_core {
+namespace {
 
-static void* refcounted_message_size_limits_ref(void* value) {
-  refcounted_message_size_limits* limits =
-      (refcounted_message_size_limits*)value;
-  gpr_ref(&limits->refs);
-  return value;
-}
+class MessageSizeLimits : public RefCounted<MessageSizeLimits> {
+ public:
+  static RefCountedPtr<MessageSizeLimits> CreateFromJson(const grpc_json* json);
 
-static void refcounted_message_size_limits_unref(void* value) {
-  refcounted_message_size_limits* limits =
-      (refcounted_message_size_limits*)value;
-  if (gpr_unref(&limits->refs)) {
-    gpr_free(value);
+  const message_size_limits& limits() const { return limits_; }
+
+ private:
+  // So New() can call our private ctor.
+  template <typename T, typename... Args>
+  friend T* grpc_core::New(Args&&... args);
+
+  MessageSizeLimits(int max_send_size, int max_recv_size) {
+    limits_.max_send_size = max_send_size;
+    limits_.max_recv_size = max_recv_size;
   }
-}
 
-static void* refcounted_message_size_limits_create_from_json(
+  message_size_limits limits_;
+};
+
+RefCountedPtr<MessageSizeLimits> MessageSizeLimits::CreateFromJson(
     const grpc_json* json) {
   int max_request_message_bytes = -1;
   int max_response_message_bytes = -1;
@@ -77,16 +83,15 @@
       if (max_response_message_bytes == -1) return nullptr;
     }
   }
-  refcounted_message_size_limits* value =
-      (refcounted_message_size_limits*)gpr_malloc(
-          sizeof(refcounted_message_size_limits));
-  gpr_ref_init(&value->refs, 1);
-  value->limits.max_send_size = max_request_message_bytes;
-  value->limits.max_recv_size = max_response_message_bytes;
-  return value;
+  return MakeRefCounted<MessageSizeLimits>(max_request_message_bytes,
+                                           max_response_message_bytes);
 }
 
+}  // namespace
+}  // namespace grpc_core
+
 namespace {
+
 struct call_data {
   grpc_call_combiner* call_combiner;
   message_size_limits limits;
@@ -95,7 +100,7 @@
   // call our next_recv_message_ready member after handling it.
   grpc_closure recv_message_ready;
   // Used by recv_message_ready.
-  grpc_byte_stream** recv_message;
+  grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message;
   // Original recv_message_ready callback, invoked after our own.
   grpc_closure* next_recv_message_ready;
 };
@@ -103,21 +108,25 @@
 struct channel_data {
   message_size_limits limits;
   // Maps path names to refcounted_message_size_limits structs.
-  grpc_slice_hash_table* method_limit_table;
+  grpc_core::RefCountedPtr<grpc_core::SliceHashTable<
+      grpc_core::RefCountedPtr<grpc_core::MessageSizeLimits>>>
+      method_limit_table;
 };
+
 }  // namespace
 
 // Callback invoked when we receive a message.  Here we check the max
 // receive message size.
 static void recv_message_ready(void* user_data, grpc_error* error) {
-  grpc_call_element* elem = (grpc_call_element*)user_data;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   if (*calld->recv_message != nullptr && calld->limits.max_recv_size >= 0 &&
-      (*calld->recv_message)->length > (size_t)calld->limits.max_recv_size) {
+      (*calld->recv_message)->length() >
+          static_cast<size_t>(calld->limits.max_recv_size)) {
     char* message_string;
     gpr_asprintf(&message_string,
                  "Received message larger than max (%u vs. %d)",
-                 (*calld->recv_message)->length, calld->limits.max_recv_size);
+                 (*calld->recv_message)->length(), calld->limits.max_recv_size);
     grpc_error* new_error = grpc_error_set_int(
         GRPC_ERROR_CREATE_FROM_COPIED_STRING(message_string),
         GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED);
@@ -138,14 +147,14 @@
 // Start transport stream op.
 static void start_transport_stream_op_batch(
     grpc_call_element* elem, grpc_transport_stream_op_batch* op) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   // Check max send message size.
   if (op->send_message && calld->limits.max_send_size >= 0 &&
-      op->payload->send_message.send_message->length >
-          (size_t)calld->limits.max_send_size) {
+      op->payload->send_message.send_message->length() >
+          static_cast<size_t>(calld->limits.max_send_size)) {
     char* message_string;
     gpr_asprintf(&message_string, "Sent message larger than max (%u vs. %d)",
-                 op->payload->send_message.send_message->length,
+                 op->payload->send_message.send_message->length(),
                  calld->limits.max_send_size);
     grpc_transport_stream_op_batch_finish_with_failure(
         op,
@@ -170,8 +179,8 @@
 // Constructor for call_data.
 static grpc_error* init_call_elem(grpc_call_element* elem,
                                   const grpc_call_element_args* args) {
-  channel_data* chand = (channel_data*)elem->channel_data;
-  call_data* calld = (call_data*)elem->call_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   calld->call_combiner = args->call_combiner;
   calld->next_recv_message_ready = nullptr;
   GRPC_CLOSURE_INIT(&calld->recv_message_ready, recv_message_ready, elem,
@@ -182,19 +191,19 @@
   // size to the receive limit.
   calld->limits = chand->limits;
   if (chand->method_limit_table != nullptr) {
-    refcounted_message_size_limits* limits =
-        (refcounted_message_size_limits*)grpc_method_config_table_get(
-            chand->method_limit_table, args->path);
+    grpc_core::RefCountedPtr<grpc_core::MessageSizeLimits> limits =
+        grpc_core::ServiceConfig::MethodConfigTableLookup(
+            *chand->method_limit_table, args->path);
     if (limits != nullptr) {
-      if (limits->limits.max_send_size >= 0 &&
-          (limits->limits.max_send_size < calld->limits.max_send_size ||
+      if (limits->limits().max_send_size >= 0 &&
+          (limits->limits().max_send_size < calld->limits.max_send_size ||
            calld->limits.max_send_size < 0)) {
-        calld->limits.max_send_size = limits->limits.max_send_size;
+        calld->limits.max_send_size = limits->limits().max_send_size;
       }
-      if (limits->limits.max_recv_size >= 0 &&
-          (limits->limits.max_recv_size < calld->limits.max_recv_size ||
+      if (limits->limits().max_recv_size >= 0 &&
+          (limits->limits().max_recv_size < calld->limits.max_recv_size ||
            calld->limits.max_recv_size < 0)) {
-        calld->limits.max_recv_size = limits->limits.max_recv_size;
+        calld->limits.max_recv_size = limits->limits().max_recv_size;
       }
     }
   }
@@ -242,22 +251,18 @@
 static grpc_error* init_channel_elem(grpc_channel_element* elem,
                                      grpc_channel_element_args* args) {
   GPR_ASSERT(!args->is_last);
-  channel_data* chand = (channel_data*)elem->channel_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   chand->limits = get_message_size_limits(args->channel_args);
   // Get method config table from channel args.
   const grpc_arg* channel_arg =
       grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG);
-  if (channel_arg != nullptr) {
-    GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
-    grpc_service_config* service_config =
-        grpc_service_config_create(channel_arg->value.string);
+  const char* service_config_str = grpc_channel_arg_get_string(channel_arg);
+  if (service_config_str != nullptr) {
+    grpc_core::UniquePtr<grpc_core::ServiceConfig> service_config =
+        grpc_core::ServiceConfig::Create(service_config_str);
     if (service_config != nullptr) {
-      chand->method_limit_table =
-          grpc_service_config_create_method_config_table(
-              service_config, refcounted_message_size_limits_create_from_json,
-              refcounted_message_size_limits_ref,
-              refcounted_message_size_limits_unref);
-      grpc_service_config_destroy(service_config);
+      chand->method_limit_table = service_config->CreateMethodConfigTable(
+          grpc_core::MessageSizeLimits::CreateFromJson);
     }
   }
   return GRPC_ERROR_NONE;
@@ -265,8 +270,8 @@
 
 // Destructor for channel_data.
 static void destroy_channel_elem(grpc_channel_element* elem) {
-  channel_data* chand = (channel_data*)elem->channel_data;
-  grpc_slice_hash_table_unref(chand->method_limit_table);
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  chand->method_limit_table.reset();
 }
 
 const grpc_channel_filter grpc_message_size_filter = {
diff --git a/src/core/ext/filters/message_size/message_size_filter.h b/src/core/ext/filters/message_size/message_size_filter.h
index d3667f7..f66636e 100644
--- a/src/core/ext/filters/message_size/message_size_filter.h
+++ b/src/core/ext/filters/message_size/message_size_filter.h
@@ -17,6 +17,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_MESSAGE_SIZE_MESSAGE_SIZE_FILTER_H
 #define GRPC_CORE_EXT_FILTERS_MESSAGE_SIZE_MESSAGE_SIZE_FILTER_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/channel/channel_stack.h"
 
 extern const grpc_channel_filter grpc_message_size_filter;
diff --git a/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.cc b/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.cc
index 88bb8c7..c7070d4 100644
--- a/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.cc
+++ b/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.cc
@@ -14,6 +14,8 @@
 // limitations under the License.
 //
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h"
 
 #include <string.h>
@@ -53,8 +55,8 @@
 
 // Callback invoked when we receive an initial metadata.
 static void recv_initial_metadata_ready(void* user_data, grpc_error* error) {
-  grpc_call_element* elem = (grpc_call_element*)user_data;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
 
   if (GRPC_ERROR_NONE == error) {
     grpc_mdelem md;
@@ -75,7 +77,7 @@
 // Start transport stream op.
 static void start_transport_stream_op_batch(
     grpc_call_element* elem, grpc_transport_stream_op_batch* op) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
 
   // Inject callback for receiving initial metadata
   if (op->recv_initial_metadata) {
@@ -91,7 +93,9 @@
     /* Send message happens after client's user-agent (initial metadata) is
      * received, so workaround_active must be set already */
     if (calld->workaround_active) {
-      op->payload->send_message.send_message->flags |= GRPC_WRITE_NO_COMPRESS;
+      op->payload->send_message.send_message->set_flags(
+          op->payload->send_message.send_message->flags() |
+          GRPC_WRITE_NO_COMPRESS);
     }
   }
 
@@ -102,7 +106,7 @@
 // Constructor for call_data.
 static grpc_error* init_call_elem(grpc_call_element* elem,
                                   const grpc_call_element_args* args) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   calld->next_recv_initial_metadata_ready = nullptr;
   calld->workaround_active = false;
   GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready,
diff --git a/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h b/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h
index 9dae4f0..94d20f0 100644
--- a/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h
+++ b/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h
@@ -17,6 +17,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_WORKAROUNDS_WORKAROUND_CRONET_COMPRESSION_FILTER_H
 #define GRPC_CORE_EXT_FILTERS_WORKAROUNDS_WORKAROUND_CRONET_COMPRESSION_FILTER_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/channel/channel_stack.h"
 
 extern const grpc_channel_filter grpc_workaround_cronet_compression_filter;
diff --git a/src/core/ext/filters/workarounds/workaround_utils.cc b/src/core/ext/filters/workarounds/workaround_utils.cc
index 9d76582..4dabe89 100644
--- a/src/core/ext/filters/workarounds/workaround_utils.cc
+++ b/src/core/ext/filters/workarounds/workaround_utils.cc
@@ -14,6 +14,8 @@
 // limitations under the License.
 //
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/workarounds/workaround_utils.h"
 
 #include <grpc/support/alloc.h>
@@ -27,14 +29,14 @@
 
 grpc_workaround_user_agent_md* grpc_parse_user_agent(grpc_mdelem md) {
   grpc_workaround_user_agent_md* user_agent_md =
-      (grpc_workaround_user_agent_md*)grpc_mdelem_get_user_data(
-          md, destroy_user_agent_md);
+      static_cast<grpc_workaround_user_agent_md*>(
+          grpc_mdelem_get_user_data(md, destroy_user_agent_md));
 
   if (nullptr != user_agent_md) {
     return user_agent_md;
   }
-  user_agent_md = (grpc_workaround_user_agent_md*)gpr_malloc(
-      sizeof(grpc_workaround_user_agent_md));
+  user_agent_md = static_cast<grpc_workaround_user_agent_md*>(
+      gpr_malloc(sizeof(grpc_workaround_user_agent_md)));
   for (int i = 0; i < GRPC_MAX_WORKAROUND_ID; i++) {
     if (ua_parser[i]) {
       user_agent_md->workaround_active[i] = ua_parser[i](md);
diff --git a/src/core/ext/filters/workarounds/workaround_utils.h b/src/core/ext/filters/workarounds/workaround_utils.h
index d6ef5e8..f172ccc 100644
--- a/src/core/ext/filters/workarounds/workaround_utils.h
+++ b/src/core/ext/filters/workarounds/workaround_utils.h
@@ -17,6 +17,8 @@
 #ifndef GRPC_CORE_EXT_FILTERS_WORKAROUNDS_WORKAROUND_UTILS_H
 #define GRPC_CORE_EXT_FILTERS_WORKAROUNDS_WORKAROUND_UTILS_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/workaround_list.h>
 
 #include "src/core/lib/transport/metadata.h"
diff --git a/src/core/ext/transport/chttp2/alpn/alpn.cc b/src/core/ext/transport/chttp2/alpn/alpn.cc
index 8989245..1fdab76 100644
--- a/src/core/ext/transport/chttp2/alpn/alpn.cc
+++ b/src/core/ext/transport/chttp2/alpn/alpn.cc
@@ -16,9 +16,12 @@
  *
  */
 
-#include "src/core/ext/transport/chttp2/alpn/alpn.h"
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
+#include "src/core/ext/transport/chttp2/alpn/alpn.h"
+
+#include "src/core/lib/gpr/useful.h"
 
 /* in order of preference */
 static const char* const supported_versions[] = {"grpc-exp", "h2"};
diff --git a/src/core/ext/transport/chttp2/alpn/alpn.h b/src/core/ext/transport/chttp2/alpn/alpn.h
index fd7513c..0042eaf 100644
--- a/src/core/ext/transport/chttp2/alpn/alpn.h
+++ b/src/core/ext/transport/chttp2/alpn/alpn.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_ALPN_ALPN_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_ALPN_ALPN_H
 
+#include <grpc/support/port_platform.h>
+
 #include <string.h>
 
 /* Retuns 1 if the version is supported, 0 otherwise. */
diff --git a/src/core/ext/transport/chttp2/client/chttp2_connector.cc b/src/core/ext/transport/chttp2/client/chttp2_connector.cc
index db5962e..e7522ff 100644
--- a/src/core/ext/transport/chttp2/client/chttp2_connector.cc
+++ b/src/core/ext/transport/chttp2/client/chttp2_connector.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/client/chttp2_connector.h"
 
 #include <grpc/grpc.h>
@@ -57,12 +59,12 @@
 } chttp2_connector;
 
 static void chttp2_connector_ref(grpc_connector* con) {
-  chttp2_connector* c = (chttp2_connector*)con;
+  chttp2_connector* c = reinterpret_cast<chttp2_connector*>(con);
   gpr_ref(&c->refs);
 }
 
 static void chttp2_connector_unref(grpc_connector* con) {
-  chttp2_connector* c = (chttp2_connector*)con;
+  chttp2_connector* c = reinterpret_cast<chttp2_connector*>(con);
   if (gpr_unref(&c->refs)) {
     gpr_mu_destroy(&c->mu);
     // If handshaking is not yet in progress, destroy the endpoint.
@@ -73,7 +75,7 @@
 }
 
 static void chttp2_connector_shutdown(grpc_connector* con, grpc_error* why) {
-  chttp2_connector* c = (chttp2_connector*)con;
+  chttp2_connector* c = reinterpret_cast<chttp2_connector*>(con);
   gpr_mu_lock(&c->mu);
   c->shutdown = true;
   if (c->handshake_mgr != nullptr) {
@@ -89,8 +91,8 @@
 }
 
 static void on_handshake_done(void* arg, grpc_error* error) {
-  grpc_handshaker_args* args = (grpc_handshaker_args*)arg;
-  chttp2_connector* c = (chttp2_connector*)args->user_data;
+  grpc_handshaker_args* args = static_cast<grpc_handshaker_args*>(arg);
+  chttp2_connector* c = static_cast<chttp2_connector*>(args->user_data);
   gpr_mu_lock(&c->mu);
   if (error != GRPC_ERROR_NONE || c->shutdown) {
     if (error == GRPC_ERROR_NONE) {
@@ -150,7 +152,7 @@
   grpc_handshake_manager_destroy(c->handshake_mgr);
   c->handshake_mgr = nullptr;
   gpr_mu_unlock(&c->mu);
-  chttp2_connector_unref((grpc_connector*)c);
+  chttp2_connector_unref(reinterpret_cast<grpc_connector*>(c));
 }
 
 static void start_handshake_locked(chttp2_connector* c) {
@@ -166,7 +168,7 @@
 }
 
 static void connected(void* arg, grpc_error* error) {
-  chttp2_connector* c = (chttp2_connector*)arg;
+  chttp2_connector* c = static_cast<chttp2_connector*>(arg);
   gpr_mu_lock(&c->mu);
   GPR_ASSERT(c->connecting);
   c->connecting = false;
@@ -184,7 +186,7 @@
       grpc_endpoint_shutdown(c->endpoint, GRPC_ERROR_REF(error));
     }
     gpr_mu_unlock(&c->mu);
-    chttp2_connector_unref((grpc_connector*)arg);
+    chttp2_connector_unref(static_cast<grpc_connector*>(arg));
   } else {
     GPR_ASSERT(c->endpoint != nullptr);
     start_handshake_locked(c);
@@ -196,7 +198,7 @@
                                      const grpc_connect_in_args* args,
                                      grpc_connect_out_args* result,
                                      grpc_closure* notify) {
-  chttp2_connector* c = (chttp2_connector*)con;
+  chttp2_connector* c = reinterpret_cast<chttp2_connector*>(con);
   grpc_resolved_address addr;
   grpc_get_subchannel_address_arg(args->channel_args, &addr);
   gpr_mu_lock(&c->mu);
@@ -219,7 +221,7 @@
     chttp2_connector_connect};
 
 grpc_connector* grpc_chttp2_connector_create() {
-  chttp2_connector* c = (chttp2_connector*)gpr_zalloc(sizeof(*c));
+  chttp2_connector* c = static_cast<chttp2_connector*>(gpr_zalloc(sizeof(*c)));
   c->base.vtable = &chttp2_connector_vtable;
   gpr_mu_init(&c->mu);
   gpr_ref_init(&c->refs, 1);
diff --git a/src/core/ext/transport/chttp2/client/chttp2_connector.h b/src/core/ext/transport/chttp2/client/chttp2_connector.h
index e258892..04da441 100644
--- a/src/core/ext/transport/chttp2/client/chttp2_connector.h
+++ b/src/core/ext/transport/chttp2/client/chttp2_connector.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_CLIENT_CHTTP2_CONNECTOR_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_CLIENT_CHTTP2_CONNECTOR_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/filters/client_channel/connector.h"
 
 grpc_connector* grpc_chttp2_connector_create();
diff --git a/src/core/ext/transport/chttp2/client/insecure/channel_create.cc b/src/core/ext/transport/chttp2/client/insecure/channel_create.cc
index 6a1b709..6080036 100644
--- a/src/core/ext/transport/chttp2/client/insecure/channel_create.cc
+++ b/src/core/ext/transport/chttp2/client/insecure/channel_create.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 
 #include <string.h>
@@ -52,13 +54,13 @@
     return nullptr;
   }
   // Add channel arg containing the server URI.
-  grpc_arg arg = grpc_channel_arg_string_create(
-      (char*)GRPC_ARG_SERVER_URI,
-      grpc_resolver_factory_add_default_prefix_if_needed(target));
+  grpc_core::UniquePtr<char> canonical_target =
+      grpc_core::ResolverRegistry::AddDefaultPrefixIfNeeded(target);
+  grpc_arg arg = grpc_channel_arg_string_create((char*)GRPC_ARG_SERVER_URI,
+                                                canonical_target.get());
   const char* to_remove[] = {GRPC_ARG_SERVER_URI};
   grpc_channel_args* new_args =
       grpc_channel_args_copy_and_add_and_remove(args, to_remove, 1, &arg, 1);
-  gpr_free(arg.value.string);
   grpc_channel* channel =
       grpc_channel_create(target, new_args, GRPC_CLIENT_CHANNEL, nullptr);
   grpc_channel_args_destroy(new_args);
diff --git a/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc b/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc
index 0cdea5a..b95c9da 100644
--- a/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc
+++ b/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc
@@ -16,10 +16,11 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 #include <grpc/grpc_posix.h>
 #include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
 
 #ifdef GPR_SUPPORT_CHANNELS_FROM_FD
 
@@ -28,7 +29,6 @@
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/endpoint.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/tcp_client_posix.h"
 #include "src/core/lib/iomgr/tcp_posix.h"
 #include "src/core/lib/surface/api_trace.h"
diff --git a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc
index 27c5b96..a82009f 100644
--- a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc
+++ b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 
 #include <string.h>
@@ -28,10 +30,11 @@
 #include "src/core/ext/filters/client_channel/uri_parser.h"
 #include "src/core/ext/transport/chttp2/client/chttp2_connector.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/security/credentials/credentials.h"
-#include "src/core/lib/security/transport/lb_targets_info.h"
-#include "src/core/lib/security/transport/security_connector.h"
+#include "src/core/lib/security/security_connector/security_connector.h"
+#include "src/core/lib/security/transport/target_authority_table.h"
 #include "src/core/lib/slice/slice_hash_table.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/surface/api_trace.h"
@@ -63,9 +66,7 @@
   // To which address are we connecting? By default, use the server URI.
   const grpc_arg* server_uri_arg =
       grpc_channel_args_find(args->args, GRPC_ARG_SERVER_URI);
-  GPR_ASSERT(server_uri_arg != nullptr);
-  GPR_ASSERT(server_uri_arg->type == GRPC_ARG_STRING);
-  const char* server_uri_str = server_uri_arg->value.string;
+  const char* server_uri_str = grpc_channel_arg_get_string(server_uri_arg);
   GPR_ASSERT(server_uri_str != nullptr);
   grpc_uri* server_uri =
       grpc_uri_parse(server_uri_str, true /* supress errors */);
@@ -73,11 +74,11 @@
   const char* server_uri_path;
   server_uri_path =
       server_uri->path[0] == '/' ? server_uri->path + 1 : server_uri->path;
-  const grpc_slice_hash_table* targets_info =
-      grpc_lb_targets_info_find_in_args(args->args);
-  char* target_name_to_check = nullptr;
-  if (targets_info != nullptr) {  // LB channel
-    // Find the balancer name for the target.
+  const grpc_core::TargetAuthorityTable* target_authority_table =
+      grpc_core::FindTargetAuthorityTableInArgs(args->args);
+  grpc_core::UniquePtr<char> authority;
+  if (target_authority_table != nullptr) {
+    // Find the authority for the target.
     const char* target_uri_str =
         grpc_get_subchannel_address_uri_arg(args->args);
     grpc_uri* target_uri =
@@ -86,37 +87,33 @@
     if (target_uri->path[0] != '\0') {  // "path" may be empty
       const grpc_slice key = grpc_slice_from_static_string(
           target_uri->path[0] == '/' ? target_uri->path + 1 : target_uri->path);
-      const char* value =
-          (const char*)grpc_slice_hash_table_get(targets_info, key);
-      if (value != nullptr) target_name_to_check = gpr_strdup(value);
+      const grpc_core::UniquePtr<char>* value =
+          target_authority_table->Get(key);
+      if (value != nullptr) authority.reset(gpr_strdup(value->get()));
       grpc_slice_unref_internal(key);
     }
-    if (target_name_to_check == nullptr) {
-      // If the target name to check hasn't already been set, fall back to using
-      // SERVER_URI
-      target_name_to_check = gpr_strdup(server_uri_path);
-    }
     grpc_uri_destroy(target_uri);
-  } else {  // regular channel: the secure name is the original server URI.
-    target_name_to_check = gpr_strdup(server_uri_path);
+  }
+  // If the authority hasn't already been set (either because no target
+  // authority table was present or because the target was not present
+  // in the table), fall back to using the original server URI.
+  if (authority == nullptr) {
+    authority.reset(gpr_strdup(server_uri_path));
   }
   grpc_uri_destroy(server_uri);
-  GPR_ASSERT(target_name_to_check != nullptr);
   grpc_channel_security_connector* subchannel_security_connector = nullptr;
   // Create the security connector using the credentials and target name.
   grpc_channel_args* new_args_from_connector = nullptr;
   const grpc_security_status security_status =
       grpc_channel_credentials_create_security_connector(
-          channel_credentials, target_name_to_check, args->args,
+          channel_credentials, authority.get(), args->args,
           &subchannel_security_connector, &new_args_from_connector);
   if (security_status != GRPC_SECURITY_OK) {
     gpr_log(GPR_ERROR,
             "Failed to create secure subchannel for secure name '%s'",
-            target_name_to_check);
-    gpr_free(target_name_to_check);
+            authority.get());
     return nullptr;
   }
-  gpr_free(target_name_to_check);
   grpc_arg new_security_connector_arg =
       grpc_security_connector_to_arg(&subchannel_security_connector->base);
 
@@ -129,7 +126,7 @@
     grpc_channel_args_destroy(new_args_from_connector);
   }
   grpc_subchannel_args* final_sc_args =
-      (grpc_subchannel_args*)gpr_malloc(sizeof(*final_sc_args));
+      static_cast<grpc_subchannel_args*>(gpr_malloc(sizeof(*final_sc_args)));
   memcpy(final_sc_args, args, sizeof(*args));
   final_sc_args->args = new_args;
   return final_sc_args;
@@ -148,7 +145,8 @@
   grpc_connector* connector = grpc_chttp2_connector_create();
   grpc_subchannel* s = grpc_subchannel_create(connector, subchannel_args);
   grpc_connector_unref(connector);
-  grpc_channel_args_destroy((grpc_channel_args*)subchannel_args->args);
+  grpc_channel_args_destroy(
+      const_cast<grpc_channel_args*>(subchannel_args->args));
   gpr_free(subchannel_args);
   return s;
 }
@@ -161,13 +159,13 @@
     return nullptr;
   }
   // Add channel arg containing the server URI.
-  grpc_arg arg = grpc_channel_arg_string_create(
-      (char*)GRPC_ARG_SERVER_URI,
-      grpc_resolver_factory_add_default_prefix_if_needed(target));
+  grpc_core::UniquePtr<char> canonical_target =
+      grpc_core::ResolverRegistry::AddDefaultPrefixIfNeeded(target);
+  grpc_arg arg = grpc_channel_arg_string_create((char*)GRPC_ARG_SERVER_URI,
+                                                canonical_target.get());
   const char* to_remove[] = {GRPC_ARG_SERVER_URI};
   grpc_channel_args* new_args =
       grpc_channel_args_copy_and_add_and_remove(args, to_remove, 1, &arg, 1);
-  gpr_free(arg.value.string);
   grpc_channel* channel =
       grpc_channel_create(target, new_args, GRPC_CLIENT_CHANNEL, nullptr);
   grpc_channel_args_destroy(new_args);
diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.cc b/src/core/ext/transport/chttp2/server/chttp2_server.cc
index 5669fa4..687cc48 100644
--- a/src/core/ext/transport/chttp2/server/chttp2_server.cc
+++ b/src/core/ext/transport/chttp2/server/chttp2_server.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/server/chttp2_server.h"
 
 #include <grpc/grpc.h>
@@ -28,7 +30,6 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
@@ -80,7 +81,8 @@
 }
 
 static void on_timeout(void* arg, grpc_error* error) {
-  server_connection_state* connection_state = (server_connection_state*)arg;
+  server_connection_state* connection_state =
+      static_cast<server_connection_state*>(arg);
   // Note that we may be called with GRPC_ERROR_NONE when the timer fires
   // or with an error indicating that the timer system is being shut down.
   if (error != GRPC_ERROR_CANCELLED) {
@@ -93,7 +95,8 @@
 }
 
 static void on_receive_settings(void* arg, grpc_error* error) {
-  server_connection_state* connection_state = (server_connection_state*)arg;
+  server_connection_state* connection_state =
+      static_cast<server_connection_state*>(arg);
   if (error == GRPC_ERROR_NONE) {
     grpc_timer_cancel(&connection_state->timer);
   }
@@ -101,9 +104,9 @@
 }
 
 static void on_handshake_done(void* arg, grpc_error* error) {
-  grpc_handshaker_args* args = (grpc_handshaker_args*)arg;
+  grpc_handshaker_args* args = static_cast<grpc_handshaker_args*>(arg);
   server_connection_state* connection_state =
-      (server_connection_state*)args->user_data;
+      static_cast<server_connection_state*>(args->user_data);
   gpr_mu_lock(&connection_state->svr_state->mu);
   if (error != GRPC_ERROR_NONE || connection_state->svr_state->shutdown) {
     const char* error_str = grpc_error_string(error);
@@ -133,7 +136,8 @@
           connection_state->accepting_pollset, args->args);
       // Use notify_on_receive_settings callback to enforce the
       // handshake deadline.
-      connection_state->transport = (grpc_chttp2_transport*)transport;
+      connection_state->transport =
+          reinterpret_cast<grpc_chttp2_transport*>(transport);
       gpr_ref(&connection_state->refs);
       GRPC_CLOSURE_INIT(&connection_state->on_receive_settings,
                         on_receive_settings, connection_state,
@@ -163,7 +167,7 @@
 static void on_accept(void* arg, grpc_endpoint* tcp,
                       grpc_pollset* accepting_pollset,
                       grpc_tcp_server_acceptor* acceptor) {
-  server_state* state = (server_state*)arg;
+  server_state* state = static_cast<server_state*>(arg);
   gpr_mu_lock(&state->mu);
   if (state->shutdown) {
     gpr_mu_unlock(&state->mu);
@@ -178,7 +182,8 @@
   gpr_mu_unlock(&state->mu);
   grpc_tcp_server_ref(state->tcp_server);
   server_connection_state* connection_state =
-      (server_connection_state*)gpr_zalloc(sizeof(*connection_state));
+      static_cast<server_connection_state*>(
+          gpr_zalloc(sizeof(*connection_state)));
   gpr_ref_init(&connection_state->refs, 1);
   connection_state->svr_state = state;
   connection_state->accepting_pollset = accepting_pollset;
@@ -202,7 +207,7 @@
 static void server_start_listener(grpc_server* server, void* arg,
                                   grpc_pollset** pollsets,
                                   size_t pollset_count) {
-  server_state* state = (server_state*)arg;
+  server_state* state = static_cast<server_state*>(arg);
   gpr_mu_lock(&state->mu);
   state->shutdown = false;
   gpr_mu_unlock(&state->mu);
@@ -211,7 +216,7 @@
 }
 
 static void tcp_server_shutdown_complete(void* arg, grpc_error* error) {
-  server_state* state = (server_state*)arg;
+  server_state* state = static_cast<server_state*>(arg);
   /* ensure all threads have unlocked */
   gpr_mu_lock(&state->mu);
   grpc_closure* destroy_done = state->server_destroy_listener_done;
@@ -235,7 +240,7 @@
    callbacks) */
 static void server_destroy_listener(grpc_server* server, void* arg,
                                     grpc_closure* destroy_done) {
-  server_state* state = (server_state*)arg;
+  server_state* state = static_cast<server_state*>(arg);
   gpr_mu_lock(&state->mu);
   state->shutdown = true;
   state->server_destroy_listener_done = destroy_done;
@@ -265,7 +270,7 @@
   if (err != GRPC_ERROR_NONE) {
     goto error;
   }
-  state = (server_state*)gpr_zalloc(sizeof(*state));
+  state = static_cast<server_state*>(gpr_zalloc(sizeof(*state)));
   GRPC_CLOSURE_INIT(&state->tcp_server_shutdown_complete,
                     tcp_server_shutdown_complete, state,
                     grpc_schedule_on_exec_ctx);
@@ -282,7 +287,7 @@
   gpr_mu_init(&state->mu);
 
   naddrs = resolved->naddrs;
-  errors = (grpc_error**)gpr_malloc(sizeof(*errors) * naddrs);
+  errors = static_cast<grpc_error**>(gpr_malloc(sizeof(*errors) * naddrs));
   for (i = 0; i < naddrs; i++) {
     errors[i] =
         grpc_tcp_server_add_port(tcp_server, &resolved->addrs[i], &port_temp);
diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.h b/src/core/ext/transport/chttp2/server/chttp2_server.h
index 7de859d..6e51001 100644
--- a/src/core/ext/transport/chttp2/server/chttp2_server.h
+++ b/src/core/ext/transport/chttp2/server/chttp2_server.h
@@ -19,9 +19,11 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_SERVER_CHTTP2_SERVER_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_SERVER_CHTTP2_SERVER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/grpc_types.h>
 
-#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/error.h"
 
 /// Adds a port to \a server.  Sets \a port_num to the port number.
 /// Takes ownership of \a args.
diff --git a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc
index 52c42d0..99f18cd 100644
--- a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc
+++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 
 #include <grpc/support/log.h>
@@ -39,6 +41,5 @@
 
     GRPC_ERROR_UNREF(err);
   }
-
   return port_num;
 }
diff --git a/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc
index dafd4af..371e463 100644
--- a/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc
+++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc
@@ -16,10 +16,11 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 #include <grpc/grpc_posix.h>
 #include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
 
 #ifdef GPR_SUPPORT_CHANNELS_FROM_FD
 
diff --git a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc
index 723af97..6689a17 100644
--- a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc
+++ b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 
 #include <string.h>
diff --git a/src/core/ext/transport/chttp2/transport/bin_decoder.cc b/src/core/ext/transport/chttp2/transport/bin_decoder.cc
index 74778ac..f0f32da 100644
--- a/src/core/ext/transport/chttp2/transport/bin_decoder.cc
+++ b/src/core/ext/transport/chttp2/transport/bin_decoder.cc
@@ -16,9 +16,11 @@
  *
  */
 
-#include "src/core/ext/transport/chttp2/transport/bin_decoder.h"
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include "src/core/ext/transport/chttp2/transport/bin_decoder.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
@@ -57,7 +59,7 @@
       gpr_log(GPR_ERROR,
               "Base64 decoding failed, invalid character '%c' in base64 "
               "input.\n",
-              (char)(*input_ptr));
+              static_cast<char>(*input_ptr));
       return false;
     }
   }
@@ -75,6 +77,32 @@
 #define COMPOSE_OUTPUT_BYTE_2(input_ptr) \
   (uint8_t)((decode_table[input_ptr[2]] << 6) | decode_table[input_ptr[3]])
 
+// By RFC 4648, if the length of the encoded string without padding is 4n+r,
+// the length of decoded string is: 1) 3n if r = 0, 2) 3n + 1 if r = 2, 3, or
+// 3) invalid if r = 1.
+size_t grpc_chttp2_base64_infer_length_after_decode(const grpc_slice& slice) {
+  size_t len = GRPC_SLICE_LENGTH(slice);
+  const uint8_t* bytes = GRPC_SLICE_START_PTR(slice);
+  while (len > 0 && bytes[len - 1] == '=') {
+    len--;
+  }
+  if (GRPC_SLICE_LENGTH(slice) - len > 2) {
+    gpr_log(GPR_ERROR,
+            "Base64 decoding failed. Input has more than 2 paddings.");
+    return 0;
+  }
+  size_t tuples = len / 4;
+  size_t tail_case = len % 4;
+  if (tail_case == 1) {
+    gpr_log(GPR_ERROR,
+            "Base64 decoding failed. Input has a length of %zu (without"
+            " padding), which is invalid.\n",
+            len);
+    return 0;
+  }
+  return tuples * 3 + tail_xtra[tail_case];
+}
+
 bool grpc_base64_decode_partial(struct grpc_base64_decode_context* ctx) {
   size_t input_tail;
 
@@ -94,7 +122,7 @@
   }
 
   // Process the tail of input data
-  input_tail = (size_t)(ctx->input_end - ctx->input_cur);
+  input_tail = static_cast<size_t>(ctx->input_end - ctx->input_cur);
   if (input_tail == 4) {
     // Process the input data with pad chars
     if (ctx->input_cur[3] == '=') {
@@ -141,7 +169,7 @@
             "Base64 decoding failed, input of "
             "grpc_chttp2_base64_decode has a length of %d, which is not a "
             "multiple of 4.\n",
-            (int)input_length);
+            static_cast<int>(input_length));
     return grpc_empty_slice();
   }
 
@@ -186,17 +214,18 @@
             "Base64 decoding failed, input of "
             "grpc_chttp2_base64_decode_with_length has a length of %d, which "
             "has a tail of 1 byte.\n",
-            (int)input_length);
+            static_cast<int>(input_length));
     grpc_slice_unref_internal(output);
     return grpc_empty_slice();
   }
 
   if (output_length > input_length / 4 * 3 + tail_xtra[input_length % 4]) {
-    gpr_log(GPR_ERROR,
-            "Base64 decoding failed, output_length %d is longer "
-            "than the max possible output length %d.\n",
-            (int)output_length,
-            (int)(input_length / 4 * 3 + tail_xtra[input_length % 4]));
+    gpr_log(
+        GPR_ERROR,
+        "Base64 decoding failed, output_length %d is longer "
+        "than the max possible output length %d.\n",
+        static_cast<int>(output_length),
+        static_cast<int>(input_length / 4 * 3 + tail_xtra[input_length % 4]));
     grpc_slice_unref_internal(output);
     return grpc_empty_slice();
   }
diff --git a/src/core/ext/transport/chttp2/transport/bin_decoder.h b/src/core/ext/transport/chttp2/transport/bin_decoder.h
index 9cb75cc..8a4d4a7 100644
--- a/src/core/ext/transport/chttp2/transport/bin_decoder.h
+++ b/src/core/ext/transport/chttp2/transport/bin_decoder.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_DECODER_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_DECODER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice.h>
 #include <stdbool.h>
 
@@ -48,4 +50,7 @@
 grpc_slice grpc_chttp2_base64_decode_with_length(grpc_slice input,
                                                  size_t output_length);
 
+/* Infer the length of decoded data from encoded data. */
+size_t grpc_chttp2_base64_infer_length_after_decode(const grpc_slice& slice);
+
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_DECODER_H */
diff --git a/src/core/ext/transport/chttp2/transport/bin_encoder.cc b/src/core/ext/transport/chttp2/transport/bin_encoder.cc
index 09f984d..bad29e3 100644
--- a/src/core/ext/transport/chttp2/transport/bin_encoder.cc
+++ b/src/core/ext/transport/chttp2/transport/bin_encoder.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
 
 #include <string.h>
@@ -53,7 +55,7 @@
   size_t output_length = input_triplets * 4 + tail_xtra[tail_case];
   grpc_slice output = GRPC_SLICE_MALLOC(output_length);
   uint8_t* in = GRPC_SLICE_START_PTR(input);
-  char* out = (char*)GRPC_SLICE_START_PTR(output);
+  char* out = reinterpret_cast<char*> GRPC_SLICE_START_PTR(output);
   size_t i;
 
   /* encode full triplets */
@@ -115,7 +117,7 @@
 
     while (temp_length > 8) {
       temp_length -= 8;
-      *out++ = (uint8_t)(temp >> temp_length);
+      *out++ = static_cast<uint8_t>(temp >> temp_length);
     }
   }
 
@@ -124,8 +126,9 @@
      * expanded form due to the "integral promotion" performed (see section
      * 3.2.1.1 of the C89 draft standard). A cast to the smaller container type
      * is then required to avoid the compiler warning */
-    *out++ = (uint8_t)((uint8_t)(temp << (8u - temp_length)) |
-                       (uint8_t)(0xffu >> temp_length));
+    *out++ =
+        static_cast<uint8_t>(static_cast<uint8_t>(temp << (8u - temp_length)) |
+                             static_cast<uint8_t>(0xffu >> temp_length));
   }
 
   GPR_ASSERT(out == GRPC_SLICE_END_PTR(output));
@@ -142,7 +145,7 @@
 static void enc_flush_some(huff_out* out) {
   while (out->temp_length > 8) {
     out->temp_length -= 8;
-    *out->out++ = (uint8_t)(out->temp >> out->temp_length);
+    *out->out++ = static_cast<uint8_t>(out->temp >> out->temp_length);
   }
 }
 
@@ -150,8 +153,9 @@
   b64_huff_sym sa = huff_alphabet[a];
   b64_huff_sym sb = huff_alphabet[b];
   out->temp = (out->temp << (sa.length + sb.length)) |
-              ((uint32_t)sa.bits << sb.length) | sb.bits;
-  out->temp_length += (uint32_t)sa.length + (uint32_t)sb.length;
+              (static_cast<uint32_t>(sa.bits) << sb.length) | sb.bits;
+  out->temp_length +=
+      static_cast<uint32_t>(sa.length) + static_cast<uint32_t>(sb.length);
   enc_flush_some(out);
 }
 
@@ -181,11 +185,11 @@
 
   /* encode full triplets */
   for (i = 0; i < input_triplets; i++) {
-    const uint8_t low_to_high = (uint8_t)((in[0] & 0x3) << 4);
+    const uint8_t low_to_high = static_cast<uint8_t>((in[0] & 0x3) << 4);
     const uint8_t high_to_low = in[1] >> 4;
     enc_add2(&out, in[0] >> 2, low_to_high | high_to_low);
 
-    const uint8_t a = (uint8_t)((in[1] & 0xf) << 2);
+    const uint8_t a = static_cast<uint8_t>((in[1] & 0xf) << 2);
     const uint8_t b = (in[2] >> 6);
     enc_add2(&out, a | b, in[2] & 0x3f);
     in += 3;
@@ -196,14 +200,14 @@
     case 0:
       break;
     case 1:
-      enc_add2(&out, in[0] >> 2, (uint8_t)((in[0] & 0x3) << 4));
+      enc_add2(&out, in[0] >> 2, static_cast<uint8_t>((in[0] & 0x3) << 4));
       in += 1;
       break;
     case 2: {
-      const uint8_t low_to_high = (uint8_t)((in[0] & 0x3) << 4);
+      const uint8_t low_to_high = static_cast<uint8_t>((in[0] & 0x3) << 4);
       const uint8_t high_to_low = in[1] >> 4;
       enc_add2(&out, in[0] >> 2, low_to_high | high_to_low);
-      enc_add1(&out, (uint8_t)((in[1] & 0xf) << 2));
+      enc_add1(&out, static_cast<uint8_t>((in[1] & 0xf) << 2));
       in += 2;
       break;
     }
@@ -214,8 +218,9 @@
      * expanded form due to the "integral promotion" performed (see section
      * 3.2.1.1 of the C89 draft standard). A cast to the smaller container type
      * is then required to avoid the compiler warning */
-    *out.out++ = (uint8_t)((uint8_t)(out.temp << (8u - out.temp_length)) |
-                           (uint8_t)(0xffu >> out.temp_length));
+    *out.out++ = static_cast<uint8_t>(
+        static_cast<uint8_t>(out.temp << (8u - out.temp_length)) |
+        static_cast<uint8_t>(0xffu >> out.temp_length));
   }
 
   GPR_ASSERT(out.out <= GRPC_SLICE_END_PTR(output));
diff --git a/src/core/ext/transport/chttp2/transport/bin_encoder.h b/src/core/ext/transport/chttp2/transport/bin_encoder.h
index 93ad0df..1b7bb15 100644
--- a/src/core/ext/transport/chttp2/transport/bin_encoder.h
+++ b/src/core/ext/transport/chttp2/transport/bin_encoder.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_ENCODER_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_ENCODER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice.h>
 
 /* base64 encode a slice. Returns a new slice, does not take ownership of the
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_plugin.cc b/src/core/ext/transport/chttp2/transport/chttp2_plugin.cc
index a699081..531ea73 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_plugin.cc
+++ b/src/core/ext/transport/chttp2/transport/chttp2_plugin.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/gpr/env.h"
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
index fe05e43..dc4e002 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
@@ -16,10 +16,10 @@
  *
  */
 
-#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
-
 #include <grpc/support/port_platform.h>
 
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+
 #include <inttypes.h>
 #include <limits.h>
 #include <math.h>
@@ -30,7 +30,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/ext/transport/chttp2/transport/frame_data.h"
 #include "src/core/ext/transport/chttp2/transport/internal.h"
@@ -40,6 +39,7 @@
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/http/parser.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/timer.h"
@@ -68,7 +68,7 @@
 
 #define DEFAULT_MIN_SENT_PING_INTERVAL_WITHOUT_DATA_MS 300000 /* 5 minutes */
 #define DEFAULT_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS 300000 /* 5 minutes */
-#define DEFAULT_MAX_PINGS_BETWEEN_DATA 0                      /* unlimited */
+#define DEFAULT_MAX_PINGS_BETWEEN_DATA 2
 #define DEFAULT_MAX_PING_STRIKES 2
 
 static int g_default_client_keepalive_time_ms =
@@ -118,12 +118,6 @@
                                    grpc_connectivity_state state,
                                    grpc_error* error, const char* reason);
 
-static void incoming_byte_stream_destroy_locked(void* byte_stream,
-                                                grpc_error* error_ignored);
-static void incoming_byte_stream_publish_error(
-    grpc_chttp2_incoming_byte_stream* bs, grpc_error* error);
-static void incoming_byte_stream_unref(grpc_chttp2_incoming_byte_stream* bs);
-
 static void benign_reclaimer_locked(void* t, grpc_error* error);
 static void destructive_reclaimer_locked(void* t, grpc_error* error);
 
@@ -379,7 +373,7 @@
                     GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER,
                     t->next_stream_id & 1, is_client ? "client" : "server");
           } else {
-            t->next_stream_id = (uint32_t)value;
+            t->next_stream_id = static_cast<uint32_t>(value);
           }
         }
       } else if (0 == strcmp(channel_args->args[i].key,
@@ -388,8 +382,8 @@
         const int value =
             grpc_channel_arg_get_integer(&channel_args->args[i], options);
         if (value >= 0) {
-          grpc_chttp2_hpack_compressor_set_max_usable_size(&t->hpack_compressor,
-                                                           (uint32_t)value);
+          grpc_chttp2_hpack_compressor_set_max_usable_size(
+              &t->hpack_compressor, static_cast<uint32_t>(value));
         }
       } else if (0 == strcmp(channel_args->args[i].key,
                              GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA)) {
@@ -422,8 +416,9 @@
                     INT_MAX});
       } else if (0 == strcmp(channel_args->args[i].key,
                              GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE)) {
-        t->write_buffer_size = (uint32_t)grpc_channel_arg_get_integer(
-            &channel_args->args[i], {0, 0, MAX_WRITE_BUFFER_SIZE});
+        t->write_buffer_size =
+            static_cast<uint32_t>(grpc_channel_arg_get_integer(
+                &channel_args->args[i], {0, 0, MAX_WRITE_BUFFER_SIZE}));
       } else if (0 ==
                  strcmp(channel_args->args[i].key, GRPC_ARG_HTTP2_BDP_PROBE)) {
         enable_bdp = grpc_channel_arg_get_bool(&channel_args->args[i], true);
@@ -448,9 +443,8 @@
             value == INT_MAX ? GRPC_MILLIS_INF_FUTURE : value;
       } else if (0 == strcmp(channel_args->args[i].key,
                              GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS)) {
-        t->keepalive_permit_without_calls =
-            (uint32_t)grpc_channel_arg_get_integer(&channel_args->args[i],
-                                                   {0, 0, 1});
+        t->keepalive_permit_without_calls = static_cast<uint32_t>(
+            grpc_channel_arg_get_integer(&channel_args->args[i], {0, 0, 1}));
       } else if (0 == strcmp(channel_args->args[i].key,
                              GRPC_ARG_OPTIMIZATION_TARGET)) {
         if (channel_args->args[i].type != GRPC_ARG_STRING) {
@@ -499,7 +493,7 @@
              GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
              {-1, 5, INT32_MAX},
              {true, true}}};
-        for (j = 0; j < (int)GPR_ARRAY_SIZE(settings_map); j++) {
+        for (j = 0; j < static_cast<int> GPR_ARRAY_SIZE(settings_map); j++) {
           if (0 == strcmp(channel_args->args[i].key,
                           settings_map[j].channel_arg_name)) {
             if (!settings_map[j].availability[is_client]) {
@@ -511,7 +505,7 @@
                   &channel_args->args[i], settings_map[j].integer_options);
               if (value >= 0) {
                 queue_setting_update(t, settings_map[j].setting_id,
-                                     (uint32_t)value);
+                                     static_cast<uint32_t>(value));
               }
             }
             break;
@@ -563,7 +557,7 @@
 }
 
 static void destroy_transport_locked(void* tp, grpc_error* error) {
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)tp;
+  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   t->destroying = 1;
   close_transport_locked(
       t, grpc_error_set_int(
@@ -573,7 +567,7 @@
 }
 
 static void destroy_transport(grpc_transport* gt) {
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)gt;
+  grpc_chttp2_transport* t = reinterpret_cast<grpc_chttp2_transport*>(gt);
   GRPC_CLOSURE_SCHED(GRPC_CLOSURE_CREATE(destroy_transport_locked, t,
                                          grpc_combiner_scheduler(t->combiner)),
                      GRPC_ERROR_NONE);
@@ -657,14 +651,14 @@
                        grpc_stream_refcount* refcount, const void* server_data,
                        gpr_arena* arena) {
   GPR_TIMER_SCOPE("init_stream", 0);
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)gt;
-  grpc_chttp2_stream* s = (grpc_chttp2_stream*)gs;
+  grpc_chttp2_transport* t = reinterpret_cast<grpc_chttp2_transport*>(gt);
+  grpc_chttp2_stream* s = reinterpret_cast<grpc_chttp2_stream*>(gs);
 
   s->t = t;
   s->refcount = refcount;
   /* We reserve one 'active stream' that's dropped when the stream is
-     read-closed. The others are for incoming_byte_streams that are actively
-     reading */
+     read-closed. The others are for Chttp2IncomingByteStreams that are
+     actively reading */
   GRPC_CHTTP2_STREAM_REF(s, "chttp2");
 
   grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[0], arena);
@@ -675,6 +669,7 @@
   GRPC_CLOSURE_INIT(&s->complete_fetch_locked, complete_fetch_locked, s,
                     grpc_schedule_on_exec_ctx);
   grpc_slice_buffer_init(&s->unprocessed_incoming_frames_buffer);
+  s->unprocessed_incoming_frames_buffer_cached_length = 0;
   grpc_slice_buffer_init(&s->frame_storage);
   grpc_slice_buffer_init(&s->compressed_data_buffer);
   grpc_slice_buffer_init(&s->decompressed_data_buffer);
@@ -686,7 +681,7 @@
   GRPC_CHTTP2_REF_TRANSPORT(t, "stream");
 
   if (server_data) {
-    s->id = (uint32_t)(uintptr_t)server_data;
+    s->id = static_cast<uint32_t>((uintptr_t)server_data);
     *t->accepting_stream = s;
     grpc_chttp2_stream_map_add(&t->stream_map, s->id, s);
     post_destructive_reclaimer(t);
@@ -706,7 +701,7 @@
 
 static void destroy_stream_locked(void* sp, grpc_error* error) {
   GPR_TIMER_SCOPE("destroy_stream", 0);
-  grpc_chttp2_stream* s = (grpc_chttp2_stream*)sp;
+  grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(sp);
   grpc_chttp2_transport* t = s->t;
 
   GPR_ASSERT((s->write_closed && s->read_closed) || s->id == 0);
@@ -754,8 +749,8 @@
 static void destroy_stream(grpc_transport* gt, grpc_stream* gs,
                            grpc_closure* then_schedule_closure) {
   GPR_TIMER_SCOPE("destroy_stream", 0);
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)gt;
-  grpc_chttp2_stream* s = (grpc_chttp2_stream*)gs;
+  grpc_chttp2_transport* t = reinterpret_cast<grpc_chttp2_transport*>(gt);
+  grpc_chttp2_stream* s = reinterpret_cast<grpc_chttp2_stream*>(gs);
 
   if (s->stream_compression_ctx != nullptr) {
     grpc_stream_compression_context_destroy(s->stream_compression_ctx);
@@ -775,7 +770,8 @@
 
 grpc_chttp2_stream* grpc_chttp2_parsing_lookup_stream(grpc_chttp2_transport* t,
                                                       uint32_t id) {
-  return (grpc_chttp2_stream*)grpc_chttp2_stream_map_find(&t->stream_map, id);
+  return static_cast<grpc_chttp2_stream*>(
+      grpc_chttp2_stream_map_find(&t->stream_map, id));
 }
 
 grpc_chttp2_stream* grpc_chttp2_parsing_accept_stream(grpc_chttp2_transport* t,
@@ -787,7 +783,8 @@
   GPR_ASSERT(t->accepting_stream == nullptr);
   t->accepting_stream = &accepting;
   t->channel_callback.accept_stream(t->channel_callback.accept_stream_user_data,
-                                    &t->base, (void*)(uintptr_t)id);
+                                    &t->base,
+                                    (void*)static_cast<uintptr_t>(id));
   t->accepting_stream = nullptr;
   return accepting;
 }
@@ -969,7 +966,7 @@
 
 static void write_action_begin_locked(void* gt, grpc_error* error_ignored) {
   GPR_TIMER_SCOPE("write_action_begin_locked", 0);
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)gt;
+  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(gt);
   GPR_ASSERT(t->write_state != GRPC_CHTTP2_WRITE_STATE_IDLE);
   grpc_chttp2_begin_write_result r;
   if (t->closed_with_error != GRPC_ERROR_NONE) {
@@ -1006,7 +1003,7 @@
 
 static void write_action(void* gt, grpc_error* error) {
   GPR_TIMER_SCOPE("write_action", 0);
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)gt;
+  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(gt);
   grpc_endpoint_write(
       t->ep, &t->outbuf,
       GRPC_CLOSURE_INIT(&t->write_action_end_locked, write_action_end_locked, t,
@@ -1015,7 +1012,7 @@
 
 static void write_action_end_locked(void* tp, grpc_error* error) {
   GPR_TIMER_SCOPE("terminate_writing_with_lock", 0);
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)tp;
+  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
 
   if (error != GRPC_ERROR_NONE) {
     close_transport_locked(t, GRPC_ERROR_REF(error));
@@ -1084,7 +1081,7 @@
   t->goaway_error = grpc_error_set_str(
       grpc_error_set_int(
           GRPC_ERROR_CREATE_FROM_STATIC_STRING("GOAWAY received"),
-          GRPC_ERROR_INT_HTTP2_ERROR, (intptr_t)goaway_error),
+          GRPC_ERROR_INT_HTTP2_ERROR, static_cast<intptr_t>(goaway_error)),
       GRPC_ERROR_STR_RAW_BYTES, goaway_text);
 
   /* When a client receives a GOAWAY with error code ENHANCE_YOUR_CALM and debug
@@ -1096,12 +1093,12 @@
     gpr_log(GPR_ERROR,
             "Received a GOAWAY with error code ENHANCE_YOUR_CALM and debug "
             "data equal to \"too_many_pings\"");
-    double current_keepalive_time_ms = (double)t->keepalive_time;
+    double current_keepalive_time_ms = static_cast<double>(t->keepalive_time);
     t->keepalive_time =
         current_keepalive_time_ms > INT_MAX / KEEPALIVE_TIME_BACKOFF_MULTIPLIER
             ? GRPC_MILLIS_INF_FUTURE
-            : (grpc_millis)(current_keepalive_time_ms *
-                            KEEPALIVE_TIME_BACKOFF_MULTIPLIER);
+            : static_cast<grpc_millis>(current_keepalive_time_ms *
+                                       KEEPALIVE_TIME_BACKOFF_MULTIPLIER);
   }
 
   /* lie: use transient failure from the transport to indicate goaway has been
@@ -1190,9 +1187,11 @@
         "complete_closure_step: t=%p %p refs=%d flags=0x%04x desc=%s err=%s "
         "write_state=%s",
         t, closure,
-        (int)(closure->next_data.scratch / CLOSURE_BARRIER_FIRST_REF_BIT),
-        (int)(closure->next_data.scratch % CLOSURE_BARRIER_FIRST_REF_BIT), desc,
-        errstr, write_state_name(t->write_state));
+        static_cast<int>(closure->next_data.scratch /
+                         CLOSURE_BARRIER_FIRST_REF_BIT),
+        static_cast<int>(closure->next_data.scratch %
+                         CLOSURE_BARRIER_FIRST_REF_BIT),
+        desc, errstr, write_state_name(t->write_state));
   }
   if (error != GRPC_ERROR_NONE) {
     if (closure->error_data.error == GRPC_ERROR_NONE) {
@@ -1240,7 +1239,7 @@
 static void add_fetched_slice_locked(grpc_chttp2_transport* t,
                                      grpc_chttp2_stream* s) {
   s->fetched_send_message_length +=
-      (uint32_t)GRPC_SLICE_LENGTH(s->fetching_slice);
+      static_cast<uint32_t> GRPC_SLICE_LENGTH(s->fetching_slice);
   grpc_slice_buffer_add(&s->flow_controlled_buffer, s->fetching_slice);
   maybe_become_writable_due_to_send_msg(t, s);
 }
@@ -1253,8 +1252,7 @@
       abort(); /* TODO(ctiller): what cleanup here? */
       return;  /* early out */
     }
-    if (s->fetched_send_message_length == s->fetching_send_message->length) {
-      grpc_byte_stream_destroy(s->fetching_send_message);
+    if (s->fetched_send_message_length == s->fetching_send_message->length()) {
       int64_t notify_offset = s->next_message_end_offset;
       if (notify_offset <= s->flow_controlled_bytes_written) {
         grpc_chttp2_complete_closure_step(
@@ -1263,7 +1261,7 @@
       } else {
         grpc_chttp2_write_cb* cb = t->write_cb_pool;
         if (cb == nullptr) {
-          cb = (grpc_chttp2_write_cb*)gpr_malloc(sizeof(*cb));
+          cb = static_cast<grpc_chttp2_write_cb*>(gpr_malloc(sizeof(*cb)));
         } else {
           t->write_cb_pool = cb->next;
         }
@@ -1271,20 +1269,19 @@
         cb->closure = s->fetching_send_message_finished;
         s->fetching_send_message_finished = nullptr;
         grpc_chttp2_write_cb** list =
-            s->fetching_send_message->flags & GRPC_WRITE_THROUGH
+            s->fetching_send_message->flags() & GRPC_WRITE_THROUGH
                 ? &s->on_write_finished_cbs
                 : &s->on_flow_controlled_cbs;
         cb->next = *list;
         *list = cb;
       }
-      s->fetching_send_message = nullptr;
+      s->fetching_send_message.reset();
       return; /* early out */
-    } else if (grpc_byte_stream_next(s->fetching_send_message, UINT32_MAX,
-                                     &s->complete_fetch_locked)) {
-      grpc_error* error =
-          grpc_byte_stream_pull(s->fetching_send_message, &s->fetching_slice);
+    } else if (s->fetching_send_message->Next(UINT32_MAX,
+                                              &s->complete_fetch_locked)) {
+      grpc_error* error = s->fetching_send_message->Pull(&s->fetching_slice);
       if (error != GRPC_ERROR_NONE) {
-        grpc_byte_stream_destroy(s->fetching_send_message);
+        s->fetching_send_message.reset();
         grpc_chttp2_cancel_stream(t, s, error);
       } else {
         add_fetched_slice_locked(t, s);
@@ -1294,17 +1291,17 @@
 }
 
 static void complete_fetch_locked(void* gs, grpc_error* error) {
-  grpc_chttp2_stream* s = (grpc_chttp2_stream*)gs;
+  grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(gs);
   grpc_chttp2_transport* t = s->t;
   if (error == GRPC_ERROR_NONE) {
-    error = grpc_byte_stream_pull(s->fetching_send_message, &s->fetching_slice);
+    error = s->fetching_send_message->Pull(&s->fetching_slice);
     if (error == GRPC_ERROR_NONE) {
       add_fetched_slice_locked(t, s);
       continue_fetching_send_locked(t, s);
     }
   }
   if (error != GRPC_ERROR_NONE) {
-    grpc_byte_stream_destroy(s->fetching_send_message);
+    s->fetching_send_message.reset();
     grpc_chttp2_cancel_stream(t, s, error);
   }
 }
@@ -1329,8 +1326,9 @@
   GPR_TIMER_SCOPE("perform_stream_op_locked", 0);
 
   grpc_transport_stream_op_batch* op =
-      (grpc_transport_stream_op_batch*)stream_op;
-  grpc_chttp2_stream* s = (grpc_chttp2_stream*)op->handler_private.extra_arg;
+      static_cast<grpc_transport_stream_op_batch*>(stream_op);
+  grpc_chttp2_stream* s =
+      static_cast<grpc_chttp2_stream*>(op->handler_private.extra_arg);
   grpc_transport_stream_op_batch_payload* op_payload = op->payload;
   grpc_chttp2_transport* t = s->t;
 
@@ -1409,8 +1407,9 @@
                                          "to-be-sent initial metadata size "
                                          "exceeds peer limit"),
                                      GRPC_ERROR_INT_SIZE,
-                                     (intptr_t)metadata_size),
-                  GRPC_ERROR_INT_LIMIT, (intptr_t)metadata_peer_limit),
+                                     static_cast<intptr_t>(metadata_size)),
+                  GRPC_ERROR_INT_LIMIT,
+                  static_cast<intptr_t>(metadata_peer_limit)),
               GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
     } else {
       if (contains_non_ok_status(s->send_initial_metadata)) {
@@ -1434,7 +1433,7 @@
           GPR_ASSERT(s->id != 0);
           grpc_chttp2_mark_stream_writable(t, s);
           if (!(op->send_message &&
-                (op->payload->send_message.send_message->flags &
+                (op->payload->send_message.send_message->flags() &
                  GRPC_WRITE_BUFFER_HINT))) {
             grpc_chttp2_initiate_write(
                 t, GRPC_CHTTP2_INITIATE_WRITE_SEND_INITIAL_METADATA);
@@ -1451,15 +1450,17 @@
       }
     }
     if (op_payload->send_initial_metadata.peer_string != nullptr) {
-      gpr_atm_rel_store(op_payload->send_initial_metadata.peer_string,
-                        (gpr_atm)gpr_strdup(t->peer_string));
+      char* old_peer_string = (char*)gpr_atm_full_xchg(
+          op_payload->send_initial_metadata.peer_string,
+          (gpr_atm)gpr_strdup(t->peer_string));
+      gpr_free(old_peer_string);
     }
   }
 
   if (op->send_message) {
     GRPC_STATS_INC_HTTP2_OP_SEND_MESSAGE();
     GRPC_STATS_INC_HTTP2_SEND_MESSAGE_SIZE(
-        op->payload->send_message.send_message->length);
+        op->payload->send_message.send_message->length());
     on_complete->next_data.scratch |= CLOSURE_BARRIER_MAY_COVER_WRITE;
     s->fetching_send_message_finished = add_closure_barrier(op->on_complete);
     if (s->write_closed) {
@@ -1468,6 +1469,7 @@
       // streaming call might send another message before getting a
       // recv_message failure, breaking out of its loop, and then
       // starting recv_trailing_metadata.
+      op->payload->send_message.send_message.reset();
       grpc_chttp2_complete_closure_step(
           t, s, &s->fetching_send_message_finished,
           t->is_client && s->received_trailing_metadata
@@ -1480,18 +1482,20 @@
       GPR_ASSERT(s->fetching_send_message == nullptr);
       uint8_t* frame_hdr = grpc_slice_buffer_tiny_add(
           &s->flow_controlled_buffer, GRPC_HEADER_SIZE_IN_BYTES);
-      uint32_t flags = op_payload->send_message.send_message->flags;
+      uint32_t flags = op_payload->send_message.send_message->flags();
       frame_hdr[0] = (flags & GRPC_WRITE_INTERNAL_COMPRESS) != 0;
-      size_t len = op_payload->send_message.send_message->length;
-      frame_hdr[1] = (uint8_t)(len >> 24);
-      frame_hdr[2] = (uint8_t)(len >> 16);
-      frame_hdr[3] = (uint8_t)(len >> 8);
-      frame_hdr[4] = (uint8_t)(len);
-      s->fetching_send_message = op_payload->send_message.send_message;
+      size_t len = op_payload->send_message.send_message->length();
+      frame_hdr[1] = static_cast<uint8_t>(len >> 24);
+      frame_hdr[2] = static_cast<uint8_t>(len >> 16);
+      frame_hdr[3] = static_cast<uint8_t>(len >> 8);
+      frame_hdr[4] = static_cast<uint8_t>(len);
+      s->fetching_send_message =
+          std::move(op_payload->send_message.send_message);
       s->fetched_send_message_length = 0;
-      s->next_message_end_offset = s->flow_controlled_bytes_written +
-                                   (int64_t)s->flow_controlled_buffer.length +
-                                   (int64_t)len;
+      s->next_message_end_offset =
+          s->flow_controlled_bytes_written +
+          static_cast<int64_t>(s->flow_controlled_buffer.length) +
+          static_cast<int64_t>(len);
       if (flags & GRPC_WRITE_BUFFER_HINT) {
         s->next_message_end_offset -= t->write_buffer_size;
         s->write_buffering = true;
@@ -1525,8 +1529,9 @@
                                          "to-be-sent trailing metadata size "
                                          "exceeds peer limit"),
                                      GRPC_ERROR_INT_SIZE,
-                                     (intptr_t)metadata_size),
-                  GRPC_ERROR_INT_LIMIT, (intptr_t)metadata_peer_limit),
+                                     static_cast<intptr_t>(metadata_size)),
+                  GRPC_ERROR_INT_LIMIT,
+                  static_cast<intptr_t>(metadata_peer_limit)),
               GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
     } else {
       if (contains_non_ok_status(s->send_trailing_metadata)) {
@@ -1563,28 +1568,37 @@
     s->trailing_metadata_available =
         op_payload->recv_initial_metadata.trailing_metadata_available;
     if (op_payload->recv_initial_metadata.peer_string != nullptr) {
-      gpr_atm_rel_store(op_payload->recv_initial_metadata.peer_string,
-                        (gpr_atm)gpr_strdup(t->peer_string));
+      char* old_peer_string = (char*)gpr_atm_full_xchg(
+          op_payload->recv_initial_metadata.peer_string,
+          (gpr_atm)gpr_strdup(t->peer_string));
+      gpr_free(old_peer_string);
     }
     grpc_chttp2_maybe_complete_recv_initial_metadata(t, s);
   }
 
   if (op->recv_message) {
     GRPC_STATS_INC_HTTP2_OP_RECV_MESSAGE();
-    size_t already_received;
+    size_t before = 0;
     GPR_ASSERT(s->recv_message_ready == nullptr);
     GPR_ASSERT(!s->pending_byte_stream);
     s->recv_message_ready = op_payload->recv_message.recv_message_ready;
     s->recv_message = op_payload->recv_message.recv_message;
     if (s->id != 0) {
       if (!s->read_closed) {
-        already_received = s->frame_storage.length;
-        s->flow_control->IncomingByteStreamUpdate(GRPC_HEADER_SIZE_IN_BYTES,
-                                                  already_received);
-        grpc_chttp2_act_on_flowctl_action(s->flow_control->MakeAction(), t, s);
+        before = s->frame_storage.length +
+                 s->unprocessed_incoming_frames_buffer.length;
       }
     }
     grpc_chttp2_maybe_complete_recv_message(t, s);
+    if (s->id != 0) {
+      if (!s->read_closed && s->frame_storage.length == 0) {
+        size_t after = s->frame_storage.length +
+                       s->unprocessed_incoming_frames_buffer_cached_length;
+        s->flow_control->IncomingByteStreamUpdate(GRPC_HEADER_SIZE_IN_BYTES,
+                                                  before - after);
+        grpc_chttp2_act_on_flowctl_action(s->flow_control->MakeAction(), t, s);
+      }
+    }
   }
 
   if (op->recv_trailing_metadata) {
@@ -1606,8 +1620,8 @@
 static void perform_stream_op(grpc_transport* gt, grpc_stream* gs,
                               grpc_transport_stream_op_batch* op) {
   GPR_TIMER_SCOPE("perform_stream_op", 0);
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)gt;
-  grpc_chttp2_stream* s = (grpc_chttp2_stream*)gs;
+  grpc_chttp2_transport* t = reinterpret_cast<grpc_chttp2_transport*>(gt);
+  grpc_chttp2_stream* s = reinterpret_cast<grpc_chttp2_stream*>(gs);
 
   if (!t->is_client) {
     if (op->send_initial_metadata) {
@@ -1663,11 +1677,12 @@
 }
 
 static void retry_initiate_ping_locked(void* tp, grpc_error* error) {
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)tp;
+  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   t->ping_state.is_delayed_ping_timer_set = false;
   if (error == GRPC_ERROR_NONE) {
     grpc_chttp2_initiate_write(t, GRPC_CHTTP2_INITIATE_WRITE_RETRY_SEND_PING);
   }
+  GRPC_CHTTP2_UNREF_TRANSPORT(t, "retry_initiate_ping_locked");
 }
 
 void grpc_chttp2_ack_ping(grpc_chttp2_transport* t, uint64_t id) {
@@ -1690,14 +1705,14 @@
   grpc_slice slice;
   grpc_error_get_status(error, GRPC_MILLIS_INF_FUTURE, nullptr, &slice,
                         &http_error, nullptr);
-  grpc_chttp2_goaway_append(t->last_new_stream_id, (uint32_t)http_error,
+  grpc_chttp2_goaway_append(t->last_new_stream_id,
+                            static_cast<uint32_t>(http_error),
                             grpc_slice_ref_internal(slice), &t->qbuf);
   grpc_chttp2_initiate_write(t, GRPC_CHTTP2_INITIATE_WRITE_GOAWAY_SENT);
   GRPC_ERROR_UNREF(error);
 }
 
 void grpc_chttp2_add_ping_strike(grpc_chttp2_transport* t) {
-  t->ping_recv_state.ping_strikes++;
   if (++t->ping_recv_state.ping_strikes > t->ping_policy.max_ping_strikes &&
       t->ping_policy.max_ping_strikes != 0) {
     send_goaway(t,
@@ -1714,9 +1729,9 @@
 
 static void perform_transport_op_locked(void* stream_op,
                                         grpc_error* error_ignored) {
-  grpc_transport_op* op = (grpc_transport_op*)stream_op;
+  grpc_transport_op* op = static_cast<grpc_transport_op*>(stream_op);
   grpc_chttp2_transport* t =
-      (grpc_chttp2_transport*)op->handler_private.extra_arg;
+      static_cast<grpc_chttp2_transport*>(op->handler_private.extra_arg);
 
   if (op->goaway_error) {
     send_goaway(t, op->goaway_error);
@@ -1757,7 +1772,7 @@
 }
 
 static void perform_transport_op(grpc_transport* gt, grpc_transport_op* op) {
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)gt;
+  grpc_chttp2_transport* t = reinterpret_cast<grpc_chttp2_transport*>(gt);
   char* msg = grpc_transport_op_string(op);
   gpr_free(msg);
   op->handler_private.extra_arg = gt;
@@ -1860,6 +1875,10 @@
         }
       }
     }
+    // save the length of the buffer before handing control back to application
+    // threads. Needed to support correct flow control bookkeeping
+    s->unprocessed_incoming_frames_buffer_cached_length =
+        s->unprocessed_incoming_frames_buffer.length;
     if (error == GRPC_ERROR_NONE && *s->recv_message != nullptr) {
       null_then_run_closure(&s->recv_message_ready, GRPC_ERROR_NONE);
     } else if (s->published_metadata[1] != GRPC_METADATA_NOT_PUBLISHED) {
@@ -1925,8 +1944,8 @@
 
 static void remove_stream(grpc_chttp2_transport* t, uint32_t id,
                           grpc_error* error) {
-  grpc_chttp2_stream* s =
-      (grpc_chttp2_stream*)grpc_chttp2_stream_map_delete(&t->stream_map, id);
+  grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(
+      grpc_chttp2_stream_map_delete(&t->stream_map, id));
   GPR_ASSERT(s);
   if (t->incoming_stream == s) {
     t->incoming_stream = nullptr;
@@ -1934,12 +1953,12 @@
   }
   if (s->pending_byte_stream) {
     if (s->on_next != nullptr) {
-      grpc_chttp2_incoming_byte_stream* bs = s->data_parser.parsing_frame;
+      grpc_core::Chttp2IncomingByteStream* bs = s->data_parser.parsing_frame;
       if (error == GRPC_ERROR_NONE) {
         error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message");
       }
-      incoming_byte_stream_publish_error(bs, error);
-      incoming_byte_stream_unref(bs);
+      bs->PublishError(error);
+      bs->Unref();
       s->data_parser.parsing_frame = nullptr;
     } else {
       GRPC_ERROR_UNREF(s->byte_stream_error);
@@ -1978,8 +1997,9 @@
       grpc_error_get_status(due_to_error, s->deadline, nullptr, nullptr,
                             &http_error, nullptr);
       grpc_slice_buffer_add(
-          &t->qbuf, grpc_chttp2_rst_stream_create(s->id, (uint32_t)http_error,
-                                                  &s->stats.outgoing));
+          &t->qbuf,
+          grpc_chttp2_rst_stream_create(
+              s->id, static_cast<uint32_t>(http_error), &s->stats.outgoing));
       grpc_chttp2_initiate_write(t, GRPC_CHTTP2_INITIATE_WRITE_RST_STREAM);
     }
   }
@@ -2082,7 +2102,7 @@
                                     GRPC_ERROR_REF(error),
                                     "send_trailing_metadata_finished");
 
-  s->fetching_send_message = nullptr;
+  s->fetching_send_message.reset();
   grpc_chttp2_complete_closure_step(t, s, &s->fetching_send_message_finished,
                                     GRPC_ERROR_REF(error),
                                     "fetching_send_message_finished");
@@ -2180,7 +2200,7 @@
     *p++ = '0';
     *p++ = '0';
     GPR_ASSERT(p == GRPC_SLICE_END_PTR(http_status_hdr));
-    len += (uint32_t)GRPC_SLICE_LENGTH(http_status_hdr);
+    len += static_cast<uint32_t> GRPC_SLICE_LENGTH(http_status_hdr);
 
     content_type_hdr = GRPC_SLICE_MALLOC(31);
     p = GRPC_SLICE_START_PTR(content_type_hdr);
@@ -2216,7 +2236,7 @@
     *p++ = 'p';
     *p++ = 'c';
     GPR_ASSERT(p == GRPC_SLICE_END_PTR(content_type_hdr));
-    len += (uint32_t)GRPC_SLICE_LENGTH(content_type_hdr);
+    len += static_cast<uint32_t> GRPC_SLICE_LENGTH(content_type_hdr);
   }
 
   status_hdr = GRPC_SLICE_MALLOC(15 + (grpc_status >= 10));
@@ -2236,14 +2256,14 @@
   *p++ = 's';
   if (grpc_status < 10) {
     *p++ = 1;
-    *p++ = (uint8_t)('0' + grpc_status);
+    *p++ = static_cast<uint8_t>('0' + grpc_status);
   } else {
     *p++ = 2;
-    *p++ = (uint8_t)('0' + (grpc_status / 10));
-    *p++ = (uint8_t)('0' + (grpc_status % 10));
+    *p++ = static_cast<uint8_t>('0' + (grpc_status / 10));
+    *p++ = static_cast<uint8_t>('0' + (grpc_status % 10));
   }
   GPR_ASSERT(p == GRPC_SLICE_END_PTR(status_hdr));
-  len += (uint32_t)GRPC_SLICE_LENGTH(status_hdr);
+  len += static_cast<uint32_t> GRPC_SLICE_LENGTH(status_hdr);
 
   size_t msg_len = GRPC_SLICE_LENGTH(slice);
   GPR_ASSERT(msg_len <= UINT32_MAX);
@@ -2267,20 +2287,20 @@
   GRPC_CHTTP2_WRITE_VARINT((uint32_t)msg_len, 1, 0, p, (uint32_t)msg_len_len);
   p += msg_len_len;
   GPR_ASSERT(p == GRPC_SLICE_END_PTR(message_pfx));
-  len += (uint32_t)GRPC_SLICE_LENGTH(message_pfx);
-  len += (uint32_t)msg_len;
+  len += static_cast<uint32_t> GRPC_SLICE_LENGTH(message_pfx);
+  len += static_cast<uint32_t>(msg_len);
 
   hdr = GRPC_SLICE_MALLOC(9);
   p = GRPC_SLICE_START_PTR(hdr);
-  *p++ = (uint8_t)(len >> 16);
-  *p++ = (uint8_t)(len >> 8);
-  *p++ = (uint8_t)(len);
+  *p++ = static_cast<uint8_t>(len >> 16);
+  *p++ = static_cast<uint8_t>(len >> 8);
+  *p++ = static_cast<uint8_t>(len);
   *p++ = GRPC_CHTTP2_FRAME_HEADER;
   *p++ = GRPC_CHTTP2_DATA_FLAG_END_STREAM | GRPC_CHTTP2_DATA_FLAG_END_HEADERS;
-  *p++ = (uint8_t)(s->id >> 24);
-  *p++ = (uint8_t)(s->id >> 16);
-  *p++ = (uint8_t)(s->id >> 8);
-  *p++ = (uint8_t)(s->id);
+  *p++ = static_cast<uint8_t>(s->id >> 24);
+  *p++ = static_cast<uint8_t>(s->id >> 16);
+  *p++ = static_cast<uint8_t>(s->id >> 8);
+  *p++ = static_cast<uint8_t>(s->id);
   GPR_ASSERT(p == GRPC_SLICE_END_PTR(hdr));
 
   grpc_slice_buffer_add(&t->qbuf, hdr);
@@ -2305,8 +2325,8 @@
 } cancel_stream_cb_args;
 
 static void cancel_stream_cb(void* user_data, uint32_t key, void* stream) {
-  cancel_stream_cb_args* args = (cancel_stream_cb_args*)user_data;
-  grpc_chttp2_stream* s = (grpc_chttp2_stream*)stream;
+  cancel_stream_cb_args* args = static_cast<cancel_stream_cb_args*>(user_data);
+  grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(stream);
   grpc_chttp2_cancel_stream(args->t, s, GRPC_ERROR_REF(args->error));
 }
 
@@ -2389,7 +2409,7 @@
 static void read_action_locked(void* tp, grpc_error* error) {
   GPR_TIMER_SCOPE("reading_action_locked", 0);
 
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)tp;
+  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
 
   GRPC_ERROR_REF(error);
 
@@ -2411,7 +2431,7 @@
       grpc_core::BdpEstimator* bdp_est = t->flow_control->bdp_estimator();
       if (bdp_est) {
         bdp_est->AddIncomingBytes(
-            (int64_t)GRPC_SLICE_LENGTH(t->read_buffer.slices[i]));
+            static_cast<int64_t> GRPC_SLICE_LENGTH(t->read_buffer.slices[i]));
       }
       errors[1] = grpc_chttp2_perform_read(t, t->read_buffer.slices[i]);
     }
@@ -2480,7 +2500,7 @@
 }
 
 static void start_bdp_ping_locked(void* tp, grpc_error* error) {
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)tp;
+  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   if (grpc_http_trace.enabled()) {
     gpr_log(GPR_DEBUG, "%s: Start BDP ping err=%s", t->peer_string,
             grpc_error_string(error));
@@ -2493,7 +2513,7 @@
 }
 
 static void finish_bdp_ping_locked(void* tp, grpc_error* error) {
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)tp;
+  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   if (grpc_http_trace.enabled()) {
     gpr_log(GPR_DEBUG, "%s: Complete BDP ping err=%s", t->peer_string,
             grpc_error_string(error));
@@ -2512,7 +2532,7 @@
 }
 
 static void next_bdp_ping_timer_expired_locked(void* tp, grpc_error* error) {
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)tp;
+  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   GPR_ASSERT(t->have_next_bdp_ping_timer);
   t->have_next_bdp_ping_timer = false;
   if (error != GRPC_ERROR_NONE) {
@@ -2550,11 +2570,11 @@
         }
       } else if (0 == strcmp(args->args[i].key,
                              GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS)) {
-        const bool value = (uint32_t)grpc_channel_arg_get_integer(
+        const bool value = static_cast<uint32_t>(grpc_channel_arg_get_integer(
             &args->args[i],
             {is_client ? g_default_client_keepalive_permit_without_calls
                        : g_default_server_keepalive_timeout_ms,
-             0, 1});
+             0, 1}));
         if (is_client) {
           g_default_client_keepalive_permit_without_calls = value;
         } else {
@@ -2590,7 +2610,7 @@
 }
 
 static void init_keepalive_ping_locked(void* arg, grpc_error* error) {
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)arg;
+  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   GPR_ASSERT(t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING);
   if (t->destroying || t->closed_with_error != GRPC_ERROR_NONE) {
     t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING;
@@ -2619,15 +2639,15 @@
 }
 
 static void start_keepalive_ping_locked(void* arg, grpc_error* error) {
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)arg;
+  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   GRPC_CHTTP2_REF_TRANSPORT(t, "keepalive watchdog");
   grpc_timer_init(&t->keepalive_watchdog_timer,
-                  grpc_core::ExecCtx::Get()->Now() + t->keepalive_time,
+                  grpc_core::ExecCtx::Get()->Now() + t->keepalive_timeout,
                   &t->keepalive_watchdog_fired_locked);
 }
 
 static void finish_keepalive_ping_locked(void* arg, grpc_error* error) {
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)arg;
+  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_PINGING) {
     if (error == GRPC_ERROR_NONE) {
       t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_WAITING;
@@ -2642,7 +2662,7 @@
 }
 
 static void keepalive_watchdog_fired_locked(void* arg, grpc_error* error) {
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)arg;
+  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_PINGING) {
     if (error == GRPC_ERROR_NONE) {
       t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING;
@@ -2682,13 +2702,13 @@
 
 static void set_pollset(grpc_transport* gt, grpc_stream* gs,
                         grpc_pollset* pollset) {
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)gt;
+  grpc_chttp2_transport* t = reinterpret_cast<grpc_chttp2_transport*>(gt);
   grpc_endpoint_add_to_pollset(t->ep, pollset);
 }
 
 static void set_pollset_set(grpc_transport* gt, grpc_stream* gs,
                             grpc_pollset_set* pollset_set) {
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)gt;
+  grpc_chttp2_transport* t = reinterpret_cast<grpc_chttp2_transport*>(gt);
   grpc_endpoint_add_to_pollset_set(t->ep, pollset_set);
 }
 
@@ -2697,8 +2717,7 @@
  */
 
 static void reset_byte_stream(void* arg, grpc_error* error) {
-  grpc_chttp2_stream* s = (grpc_chttp2_stream*)arg;
-
+  grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(arg);
   s->pending_byte_stream = false;
   if (error == GRPC_ERROR_NONE) {
     grpc_chttp2_maybe_complete_recv_message(s->t, s);
@@ -2714,22 +2733,56 @@
   }
 }
 
-static void incoming_byte_stream_unref(grpc_chttp2_incoming_byte_stream* bs) {
-  if (gpr_unref(&bs->refs)) {
-    gpr_free(bs);
+namespace grpc_core {
+
+Chttp2IncomingByteStream::Chttp2IncomingByteStream(
+    grpc_chttp2_transport* transport, grpc_chttp2_stream* stream,
+    uint32_t frame_size, uint32_t flags)
+    : ByteStream(frame_size, flags),
+      transport_(transport),
+      stream_(stream),
+      remaining_bytes_(frame_size) {
+  gpr_ref_init(&refs_, 2);
+  GRPC_ERROR_UNREF(stream->byte_stream_error);
+  stream->byte_stream_error = GRPC_ERROR_NONE;
+}
+
+void Chttp2IncomingByteStream::OrphanLocked(void* arg,
+                                            grpc_error* error_ignored) {
+  Chttp2IncomingByteStream* bs = static_cast<Chttp2IncomingByteStream*>(arg);
+  grpc_chttp2_stream* s = bs->stream_;
+  grpc_chttp2_transport* t = s->t;
+  bs->Unref();
+  s->pending_byte_stream = false;
+  grpc_chttp2_maybe_complete_recv_message(t, s);
+  grpc_chttp2_maybe_complete_recv_trailing_metadata(t, s);
+}
+
+void Chttp2IncomingByteStream::Orphan() {
+  GPR_TIMER_SCOPE("incoming_byte_stream_destroy", 0);
+  GRPC_CLOSURE_SCHED(
+      GRPC_CLOSURE_INIT(&destroy_action_,
+                        &Chttp2IncomingByteStream::OrphanLocked, this,
+                        grpc_combiner_scheduler(transport_->combiner)),
+      GRPC_ERROR_NONE);
+}
+
+void Chttp2IncomingByteStream::Unref() {
+  if (gpr_unref(&refs_)) {
+    Delete(this);
   }
 }
 
-static void incoming_byte_stream_next_locked(void* argp,
-                                             grpc_error* error_ignored) {
-  grpc_chttp2_incoming_byte_stream* bs =
-      (grpc_chttp2_incoming_byte_stream*)argp;
-  grpc_chttp2_transport* t = bs->transport;
-  grpc_chttp2_stream* s = bs->stream;
+void Chttp2IncomingByteStream::Ref() { gpr_ref(&refs_); }
 
+void Chttp2IncomingByteStream::NextLocked(void* arg,
+                                          grpc_error* error_ignored) {
+  Chttp2IncomingByteStream* bs = static_cast<Chttp2IncomingByteStream*>(arg);
+  grpc_chttp2_transport* t = bs->transport_;
+  grpc_chttp2_stream* s = bs->stream_;
   size_t cur_length = s->frame_storage.length;
   if (!s->read_closed) {
-    s->flow_control->IncomingByteStreamUpdate(bs->next_action.max_size_hint,
+    s->flow_control->IncomingByteStreamUpdate(bs->next_action_.max_size_hint,
                                               cur_length);
     grpc_chttp2_act_on_flowctl_action(s->flow_control->MakeAction(), t, s);
   }
@@ -2738,22 +2791,22 @@
     grpc_slice_buffer_swap(&s->frame_storage,
                            &s->unprocessed_incoming_frames_buffer);
     s->unprocessed_incoming_frames_decompressed = false;
-    GRPC_CLOSURE_SCHED(bs->next_action.on_complete, GRPC_ERROR_NONE);
+    GRPC_CLOSURE_SCHED(bs->next_action_.on_complete, GRPC_ERROR_NONE);
   } else if (s->byte_stream_error != GRPC_ERROR_NONE) {
-    GRPC_CLOSURE_SCHED(bs->next_action.on_complete,
+    GRPC_CLOSURE_SCHED(bs->next_action_.on_complete,
                        GRPC_ERROR_REF(s->byte_stream_error));
     if (s->data_parser.parsing_frame != nullptr) {
-      incoming_byte_stream_unref(s->data_parser.parsing_frame);
+      s->data_parser.parsing_frame->Unref();
       s->data_parser.parsing_frame = nullptr;
     }
   } else if (s->read_closed) {
-    if (bs->remaining_bytes != 0) {
+    if (bs->remaining_bytes_ != 0) {
       s->byte_stream_error =
           GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message");
-      GRPC_CLOSURE_SCHED(bs->next_action.on_complete,
+      GRPC_CLOSURE_SCHED(bs->next_action_.on_complete,
                          GRPC_ERROR_REF(s->byte_stream_error));
       if (s->data_parser.parsing_frame != nullptr) {
-        incoming_byte_stream_unref(s->data_parser.parsing_frame);
+        s->data_parser.parsing_frame->Unref();
         s->data_parser.parsing_frame = nullptr;
       }
     } else {
@@ -2761,122 +2814,94 @@
       GPR_ASSERT(false);
     }
   } else {
-    s->on_next = bs->next_action.on_complete;
+    s->on_next = bs->next_action_.on_complete;
   }
-  incoming_byte_stream_unref(bs);
+  bs->Unref();
 }
 
-static bool incoming_byte_stream_next(grpc_byte_stream* byte_stream,
-                                      size_t max_size_hint,
-                                      grpc_closure* on_complete) {
+bool Chttp2IncomingByteStream::Next(size_t max_size_hint,
+                                    grpc_closure* on_complete) {
   GPR_TIMER_SCOPE("incoming_byte_stream_next", 0);
-  grpc_chttp2_incoming_byte_stream* bs =
-      (grpc_chttp2_incoming_byte_stream*)byte_stream;
-  grpc_chttp2_stream* s = bs->stream;
-  if (s->unprocessed_incoming_frames_buffer.length > 0) {
+  if (stream_->unprocessed_incoming_frames_buffer.length > 0) {
     return true;
   } else {
-    gpr_ref(&bs->refs);
-    bs->next_action.max_size_hint = max_size_hint;
-    bs->next_action.on_complete = on_complete;
+    Ref();
+    next_action_.max_size_hint = max_size_hint;
+    next_action_.on_complete = on_complete;
     GRPC_CLOSURE_SCHED(
-        GRPC_CLOSURE_INIT(&bs->next_action.closure,
-                          incoming_byte_stream_next_locked, bs,
-                          grpc_combiner_scheduler(bs->transport->combiner)),
+        GRPC_CLOSURE_INIT(&next_action_.closure,
+                          &Chttp2IncomingByteStream::NextLocked, this,
+                          grpc_combiner_scheduler(transport_->combiner)),
         GRPC_ERROR_NONE);
     return false;
   }
 }
 
-static grpc_error* incoming_byte_stream_pull(grpc_byte_stream* byte_stream,
-                                             grpc_slice* slice) {
+grpc_error* Chttp2IncomingByteStream::Pull(grpc_slice* slice) {
   GPR_TIMER_SCOPE("incoming_byte_stream_pull", 0);
-  grpc_chttp2_incoming_byte_stream* bs =
-      (grpc_chttp2_incoming_byte_stream*)byte_stream;
-  grpc_chttp2_stream* s = bs->stream;
   grpc_error* error;
-
-  if (s->unprocessed_incoming_frames_buffer.length > 0) {
-    if (!s->unprocessed_incoming_frames_decompressed) {
+  if (stream_->unprocessed_incoming_frames_buffer.length > 0) {
+    if (!stream_->unprocessed_incoming_frames_decompressed) {
       bool end_of_context;
-      if (!s->stream_decompression_ctx) {
-        s->stream_decompression_ctx = grpc_stream_compression_context_create(
-            s->stream_decompression_method);
+      if (!stream_->stream_decompression_ctx) {
+        stream_->stream_decompression_ctx =
+            grpc_stream_compression_context_create(
+                stream_->stream_decompression_method);
       }
-      if (!grpc_stream_decompress(s->stream_decompression_ctx,
-                                  &s->unprocessed_incoming_frames_buffer,
-                                  &s->decompressed_data_buffer, nullptr,
+      if (!grpc_stream_decompress(stream_->stream_decompression_ctx,
+                                  &stream_->unprocessed_incoming_frames_buffer,
+                                  &stream_->decompressed_data_buffer, nullptr,
                                   MAX_SIZE_T, &end_of_context)) {
         error =
             GRPC_ERROR_CREATE_FROM_STATIC_STRING("Stream decompression error.");
         return error;
       }
-      GPR_ASSERT(s->unprocessed_incoming_frames_buffer.length == 0);
-      grpc_slice_buffer_swap(&s->unprocessed_incoming_frames_buffer,
-                             &s->decompressed_data_buffer);
-      s->unprocessed_incoming_frames_decompressed = true;
+      GPR_ASSERT(stream_->unprocessed_incoming_frames_buffer.length == 0);
+      grpc_slice_buffer_swap(&stream_->unprocessed_incoming_frames_buffer,
+                             &stream_->decompressed_data_buffer);
+      stream_->unprocessed_incoming_frames_decompressed = true;
       if (end_of_context) {
-        grpc_stream_compression_context_destroy(s->stream_decompression_ctx);
-        s->stream_decompression_ctx = nullptr;
+        grpc_stream_compression_context_destroy(
+            stream_->stream_decompression_ctx);
+        stream_->stream_decompression_ctx = nullptr;
       }
-      if (s->unprocessed_incoming_frames_buffer.length == 0) {
+      if (stream_->unprocessed_incoming_frames_buffer.length == 0) {
         *slice = grpc_empty_slice();
       }
     }
     error = grpc_deframe_unprocessed_incoming_frames(
-        &s->data_parser, s, &s->unprocessed_incoming_frames_buffer, slice,
-        nullptr);
+        &stream_->data_parser, stream_,
+        &stream_->unprocessed_incoming_frames_buffer, slice, nullptr);
     if (error != GRPC_ERROR_NONE) {
       return error;
     }
   } else {
     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message");
-    GRPC_CLOSURE_SCHED(&s->reset_byte_stream, GRPC_ERROR_REF(error));
+    GRPC_CLOSURE_SCHED(&stream_->reset_byte_stream, GRPC_ERROR_REF(error));
     return error;
   }
   return GRPC_ERROR_NONE;
 }
 
-static void incoming_byte_stream_destroy_locked(void* byte_stream,
-                                                grpc_error* error_ignored);
-
-static void incoming_byte_stream_destroy(grpc_byte_stream* byte_stream) {
-  GPR_TIMER_SCOPE("incoming_byte_stream_destroy", 0);
-  grpc_chttp2_incoming_byte_stream* bs =
-      (grpc_chttp2_incoming_byte_stream*)byte_stream;
-  GRPC_CLOSURE_SCHED(
-      GRPC_CLOSURE_INIT(&bs->destroy_action,
-                        incoming_byte_stream_destroy_locked, bs,
-                        grpc_combiner_scheduler(bs->transport->combiner)),
-      GRPC_ERROR_NONE);
-}
-
-static void incoming_byte_stream_publish_error(
-    grpc_chttp2_incoming_byte_stream* bs, grpc_error* error) {
-  grpc_chttp2_stream* s = bs->stream;
-
+void Chttp2IncomingByteStream::PublishError(grpc_error* error) {
   GPR_ASSERT(error != GRPC_ERROR_NONE);
-  GRPC_CLOSURE_SCHED(s->on_next, GRPC_ERROR_REF(error));
-  s->on_next = nullptr;
-  GRPC_ERROR_UNREF(s->byte_stream_error);
-  s->byte_stream_error = GRPC_ERROR_REF(error);
-  grpc_chttp2_cancel_stream(bs->transport, bs->stream, GRPC_ERROR_REF(error));
+  GRPC_CLOSURE_SCHED(stream_->on_next, GRPC_ERROR_REF(error));
+  stream_->on_next = nullptr;
+  GRPC_ERROR_UNREF(stream_->byte_stream_error);
+  stream_->byte_stream_error = GRPC_ERROR_REF(error);
+  grpc_chttp2_cancel_stream(transport_, stream_, GRPC_ERROR_REF(error));
 }
 
-grpc_error* grpc_chttp2_incoming_byte_stream_push(
-    grpc_chttp2_incoming_byte_stream* bs, grpc_slice slice,
-    grpc_slice* slice_out) {
-  grpc_chttp2_stream* s = bs->stream;
-
-  if (bs->remaining_bytes < GRPC_SLICE_LENGTH(slice)) {
+grpc_error* Chttp2IncomingByteStream::Push(grpc_slice slice,
+                                           grpc_slice* slice_out) {
+  if (remaining_bytes_ < GRPC_SLICE_LENGTH(slice)) {
     grpc_error* error =
         GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many bytes in stream");
-
-    GRPC_CLOSURE_SCHED(&s->reset_byte_stream, GRPC_ERROR_REF(error));
+    GRPC_CLOSURE_SCHED(&stream_->reset_byte_stream, GRPC_ERROR_REF(error));
     grpc_slice_unref_internal(slice);
     return error;
   } else {
-    bs->remaining_bytes -= (uint32_t)GRPC_SLICE_LENGTH(slice);
+    remaining_bytes_ -= static_cast<uint32_t> GRPC_SLICE_LENGTH(slice);
     if (slice_out != nullptr) {
       *slice_out = slice;
     }
@@ -2884,66 +2909,25 @@
   }
 }
 
-grpc_error* grpc_chttp2_incoming_byte_stream_finished(
-    grpc_chttp2_incoming_byte_stream* bs, grpc_error* error,
-    bool reset_on_error) {
-  grpc_chttp2_stream* s = bs->stream;
-
+grpc_error* Chttp2IncomingByteStream::Finished(grpc_error* error,
+                                               bool reset_on_error) {
   if (error == GRPC_ERROR_NONE) {
-    if (bs->remaining_bytes != 0) {
+    if (remaining_bytes_ != 0) {
       error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message");
     }
   }
   if (error != GRPC_ERROR_NONE && reset_on_error) {
-    GRPC_CLOSURE_SCHED(&s->reset_byte_stream, GRPC_ERROR_REF(error));
+    GRPC_CLOSURE_SCHED(&stream_->reset_byte_stream, GRPC_ERROR_REF(error));
   }
-  incoming_byte_stream_unref(bs);
+  Unref();
   return error;
 }
 
-static void incoming_byte_stream_shutdown(grpc_byte_stream* byte_stream,
-                                          grpc_error* error) {
-  grpc_chttp2_incoming_byte_stream* bs =
-      (grpc_chttp2_incoming_byte_stream*)byte_stream;
-  GRPC_ERROR_UNREF(grpc_chttp2_incoming_byte_stream_finished(
-      bs, error, true /* reset_on_error */));
+void Chttp2IncomingByteStream::Shutdown(grpc_error* error) {
+  GRPC_ERROR_UNREF(Finished(error, true /* reset_on_error */));
 }
 
-static const grpc_byte_stream_vtable grpc_chttp2_incoming_byte_stream_vtable = {
-    incoming_byte_stream_next, incoming_byte_stream_pull,
-    incoming_byte_stream_shutdown, incoming_byte_stream_destroy};
-
-static void incoming_byte_stream_destroy_locked(void* byte_stream,
-                                                grpc_error* error_ignored) {
-  grpc_chttp2_incoming_byte_stream* bs =
-      (grpc_chttp2_incoming_byte_stream*)byte_stream;
-  grpc_chttp2_stream* s = bs->stream;
-  grpc_chttp2_transport* t = s->t;
-
-  GPR_ASSERT(bs->base.vtable == &grpc_chttp2_incoming_byte_stream_vtable);
-  incoming_byte_stream_unref(bs);
-  s->pending_byte_stream = false;
-  grpc_chttp2_maybe_complete_recv_message(t, s);
-  grpc_chttp2_maybe_complete_recv_trailing_metadata(t, s);
-}
-
-grpc_chttp2_incoming_byte_stream* grpc_chttp2_incoming_byte_stream_create(
-    grpc_chttp2_transport* t, grpc_chttp2_stream* s, uint32_t frame_size,
-    uint32_t flags) {
-  grpc_chttp2_incoming_byte_stream* incoming_byte_stream =
-      (grpc_chttp2_incoming_byte_stream*)gpr_malloc(
-          sizeof(*incoming_byte_stream));
-  incoming_byte_stream->base.length = frame_size;
-  incoming_byte_stream->remaining_bytes = frame_size;
-  incoming_byte_stream->base.flags = flags;
-  incoming_byte_stream->base.vtable = &grpc_chttp2_incoming_byte_stream_vtable;
-  gpr_ref_init(&incoming_byte_stream->refs, 2);
-  incoming_byte_stream->transport = t;
-  incoming_byte_stream->stream = s;
-  GRPC_ERROR_UNREF(s->byte_stream_error);
-  s->byte_stream_error = GRPC_ERROR_NONE;
-  return incoming_byte_stream;
-}
+}  // namespace grpc_core
 
 /*******************************************************************************
  * RESOURCE QUOTAS
@@ -2968,7 +2952,7 @@
 }
 
 static void benign_reclaimer_locked(void* arg, grpc_error* error) {
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)arg;
+  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   if (error == GRPC_ERROR_NONE &&
       grpc_chttp2_stream_map_size(&t->stream_map) == 0) {
     /* Channel with no active streams: send a goaway to try and make it
@@ -2996,12 +2980,12 @@
 }
 
 static void destructive_reclaimer_locked(void* arg, grpc_error* error) {
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)arg;
+  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(arg);
   size_t n = grpc_chttp2_stream_map_size(&t->stream_map);
   t->destructive_reclaimer_registered = false;
   if (error == GRPC_ERROR_NONE && n > 0) {
-    grpc_chttp2_stream* s =
-        (grpc_chttp2_stream*)grpc_chttp2_stream_map_rand(&t->stream_map);
+    grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(
+        grpc_chttp2_stream_map_rand(&t->stream_map));
     if (grpc_resource_quota_trace.enabled()) {
       gpr_log(GPR_DEBUG, "HTTP2: %s - abandon stream id %d", t->peer_string,
               s->id);
@@ -3078,7 +3062,7 @@
 }
 
 static grpc_endpoint* chttp2_get_endpoint(grpc_transport* t) {
-  return ((grpc_chttp2_transport*)t)->ep;
+  return (reinterpret_cast<grpc_chttp2_transport*>(t))->ep;
 }
 
 static const grpc_transport_vtable vtable = {sizeof(grpc_chttp2_stream),
@@ -3096,8 +3080,8 @@
 
 grpc_transport* grpc_create_chttp2_transport(
     const grpc_channel_args* channel_args, grpc_endpoint* ep, bool is_client) {
-  grpc_chttp2_transport* t =
-      (grpc_chttp2_transport*)gpr_zalloc(sizeof(grpc_chttp2_transport));
+  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(
+      gpr_zalloc(sizeof(grpc_chttp2_transport)));
   init_transport(t, channel_args, ep, is_client);
   return &t->base;
 }
@@ -3105,7 +3089,8 @@
 void grpc_chttp2_transport_start_reading(
     grpc_transport* transport, grpc_slice_buffer* read_buffer,
     grpc_closure* notify_on_receive_settings) {
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)transport;
+  grpc_chttp2_transport* t =
+      reinterpret_cast<grpc_chttp2_transport*>(transport);
   GRPC_CHTTP2_REF_TRANSPORT(
       t, "reading_action"); /* matches unref inside reading_action */
   if (read_buffer != nullptr) {
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.h b/src/core/ext/transport/chttp2/transport/chttp2_transport.h
index 34519ce..9d55b3f 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.h
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_CHTTP2_TRANSPORT_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_CHTTP2_TRANSPORT_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/transport/transport.h"
diff --git a/src/core/ext/transport/chttp2/transport/flow_control.cc b/src/core/ext/transport/chttp2/transport/flow_control.cc
index 581241d..e89c363 100644
--- a/src/core/ext/transport/chttp2/transport/flow_control.cc
+++ b/src/core/ext/transport/chttp2/transport/flow_control.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/transport/flow_control.h"
 
 #include <inttypes.h>
@@ -26,7 +28,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/ext/transport/chttp2/transport/internal.h"
 #include "src/core/lib/gpr/string.h"
@@ -185,10 +186,11 @@
 
 uint32_t TransportFlowControl::MaybeSendUpdate(bool writing_anyway) {
   FlowControlTrace trace("t updt sent", this, nullptr);
-  const uint32_t target_announced_window = (const uint32_t)target_window();
+  const uint32_t target_announced_window =
+      static_cast<const uint32_t>(target_window());
   if ((writing_anyway || announced_window_ <= target_announced_window / 2) &&
       announced_window_ != target_announced_window) {
-    const uint32_t announce = (uint32_t)GPR_CLAMP(
+    const uint32_t announce = static_cast<uint32_t> GPR_CLAMP(
         target_announced_window - announced_window_, 0, UINT32_MAX);
     announced_window_ += announce;
     return announce;
@@ -262,7 +264,7 @@
 uint32_t StreamFlowControl::MaybeSendUpdate() {
   FlowControlTrace trace("s updt sent", tfc_, this);
   if (local_window_delta_ > announced_window_delta_) {
-    uint32_t announce = (uint32_t)GPR_CLAMP(
+    uint32_t announce = static_cast<uint32_t> GPR_CLAMP(
         local_window_delta_ - announced_window_delta_, 0, UINT32_MAX);
     UpdateAnnouncedWindowDelta(tfc_, announce);
     return announce;
@@ -282,12 +284,12 @@
   if (max_size_hint >= UINT32_MAX - sent_init_window) {
     max_recv_bytes = UINT32_MAX - sent_init_window;
   } else {
-    max_recv_bytes = (uint32_t)max_size_hint;
+    max_recv_bytes = static_cast<uint32_t>(max_size_hint);
   }
 
   /* account for bytes already received but unknown to higher layers */
   if (max_recv_bytes >= have_already) {
-    max_recv_bytes -= (uint32_t)have_already;
+    max_recv_bytes -= static_cast<uint32_t>(have_already);
   } else {
     max_recv_bytes = 0;
   }
@@ -296,7 +298,7 @@
   GPR_ASSERT(max_recv_bytes <= UINT32_MAX - sent_init_window);
   if (local_window_delta_ < max_recv_bytes) {
     uint32_t add_max_recv_bytes =
-        (uint32_t)(max_recv_bytes - local_window_delta_);
+        static_cast<uint32_t>(max_recv_bytes - local_window_delta_);
     local_window_delta_ += add_max_recv_bytes;
   }
 }
@@ -329,7 +331,7 @@
 double TransportFlowControl::SmoothLogBdp(double value) {
   grpc_millis now = grpc_core::ExecCtx::Get()->Now();
   double bdp_error = value - pid_controller_.last_control_value();
-  const double dt = (double)(now - last_pid_update_) * 1e-3;
+  const double dt = static_cast<double>(now - last_pid_update_) * 1e-3;
   last_pid_update_ = now;
   // Limit dt to 100ms
   const double kMaxDt = 0.1;
@@ -338,8 +340,8 @@
 
 FlowControlAction::Urgency TransportFlowControl::DeltaUrgency(
     int64_t value, grpc_chttp2_setting_id setting_id) {
-  int64_t delta =
-      (int64_t)value - (int64_t)t_->settings[GRPC_LOCAL_SETTINGS][setting_id];
+  int64_t delta = value - static_cast<int64_t>(
+                              t_->settings[GRPC_LOCAL_SETTINGS][setting_id]);
   // TODO(ncteisen): tune this
   if (delta != 0 && (delta <= -value / 5 || delta >= value / 5)) {
     return FlowControlAction::Urgency::QUEUE_UPDATE;
@@ -358,22 +360,24 @@
     const double target = pow(2, SmoothLogBdp(TargetLogBdp()));
 
     // Though initial window 'could' drop to 0, we keep the floor at 128
-    target_initial_window_size_ = (int32_t)GPR_CLAMP(target, 128, INT32_MAX);
+    target_initial_window_size_ =
+        static_cast<int32_t> GPR_CLAMP(target, 128, INT32_MAX);
 
     action.set_send_initial_window_update(
         DeltaUrgency(target_initial_window_size_,
                      GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE),
-        (uint32_t)target_initial_window_size_);
+        static_cast<uint32_t>(target_initial_window_size_));
 
     // get bandwidth estimate and update max_frame accordingly.
     double bw_dbl = bdp_estimator_.EstimateBandwidth();
     // we target the max of BDP or bandwidth in microseconds.
-    int32_t frame_size = (int32_t)GPR_CLAMP(
+    int32_t frame_size = static_cast<int32_t> GPR_CLAMP(
         GPR_MAX((int32_t)GPR_CLAMP(bw_dbl, 0, INT_MAX) / 1000,
                 target_initial_window_size_),
         16384, 16777215);
     action.set_send_max_frame_size_update(
-        DeltaUrgency((int64_t)frame_size, GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE),
+        DeltaUrgency(static_cast<int64_t>(frame_size),
+                     GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE),
         frame_size);
   }
   return UpdateAction(action);
diff --git a/src/core/ext/transport/chttp2/transport/flow_control.h b/src/core/ext/transport/chttp2/transport/flow_control.h
index 2ee1345..120fefc 100644
--- a/src/core/ext/transport/chttp2/transport/flow_control.h
+++ b/src/core/ext/transport/chttp2/transport/flow_control.h
@@ -20,10 +20,11 @@
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FLOW_CONTROL_H
 
 #include <grpc/support/port_platform.h>
+
 #include <stdint.h>
 
-#include <grpc/support/useful.h>
 #include "src/core/ext/transport/chttp2/transport/http2_settings.h"
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/gprpp/abstract.h"
 #include "src/core/lib/gprpp/manual_constructor.h"
 #include "src/core/lib/transport/bdp_estimator.h"
@@ -44,7 +45,7 @@
 namespace chttp2 {
 
 static constexpr uint32_t kDefaultWindow = 65535;
-static constexpr int64_t kMaxWindow = (int64_t)((1u << 31) - 1);
+static constexpr int64_t kMaxWindow = static_cast<int64_t>((1u << 31) - 1);
 // TODO(ncteisen): Tune this
 static constexpr uint32_t kFrameSize = 1024 * 1024;
 
@@ -271,9 +272,10 @@
   // See comment above announced_stream_total_over_incoming_window_ for the
   // logic behind this decision.
   int64_t target_window() const override {
-    return (uint32_t)GPR_MIN((int64_t)((1u << 31) - 1),
-                             announced_stream_total_over_incoming_window_ +
-                                 target_initial_window_size_);
+    return static_cast<uint32_t> GPR_MIN(
+        (int64_t)((1u << 31) - 1),
+        announced_stream_total_over_incoming_window_ +
+            target_initial_window_size_);
   }
 
   const grpc_chttp2_transport* transport() const { return t_; }
diff --git a/src/core/ext/transport/chttp2/transport/frame.h b/src/core/ext/transport/chttp2/transport/frame.h
index dba4c00..083c007 100644
--- a/src/core/ext/transport/chttp2/transport/frame.h
+++ b/src/core/ext/transport/chttp2/transport/frame.h
@@ -19,9 +19,10 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_H
 
-#include <grpc/slice.h>
 #include <grpc/support/port_platform.h>
 
+#include <grpc/slice.h>
+
 #include "src/core/lib/iomgr/error.h"
 
 /* defined in internal.h */
diff --git a/src/core/ext/transport/chttp2/transport/frame_data.cc b/src/core/ext/transport/chttp2/transport/frame_data.cc
index 043b80a..f8f06f6 100644
--- a/src/core/ext/transport/chttp2/transport/frame_data.cc
+++ b/src/core/ext/transport/chttp2/transport/frame_data.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/transport/frame_data.h"
 
 #include <string.h>
@@ -23,9 +25,9 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 #include "src/core/ext/transport/chttp2/transport/internal.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/transport/transport.h"
@@ -38,8 +40,7 @@
 
 void grpc_chttp2_data_parser_destroy(grpc_chttp2_data_parser* parser) {
   if (parser->parsing_frame != nullptr) {
-    GRPC_ERROR_UNREF(grpc_chttp2_incoming_byte_stream_finished(
-        parser->parsing_frame,
+    GRPC_ERROR_UNREF(parser->parsing_frame->Finished(
         GRPC_ERROR_CREATE_FROM_STATIC_STRING("Parser destroyed"), false));
   }
   GRPC_ERROR_UNREF(parser->error);
@@ -52,9 +53,9 @@
   if (flags & ~GRPC_CHTTP2_DATA_FLAG_END_STREAM) {
     char* msg;
     gpr_asprintf(&msg, "unsupported data flags: 0x%02x", flags);
-    grpc_error* err =
-        grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg),
-                           GRPC_ERROR_INT_STREAM_ID, (intptr_t)stream_id);
+    grpc_error* err = grpc_error_set_int(
+        GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg), GRPC_ERROR_INT_STREAM_ID,
+        static_cast<intptr_t>(stream_id));
     gpr_free(msg);
     return err;
   }
@@ -79,15 +80,15 @@
   hdr = GRPC_SLICE_MALLOC(header_size);
   p = GRPC_SLICE_START_PTR(hdr);
   GPR_ASSERT(write_bytes < (1 << 24));
-  *p++ = (uint8_t)(write_bytes >> 16);
-  *p++ = (uint8_t)(write_bytes >> 8);
-  *p++ = (uint8_t)(write_bytes);
+  *p++ = static_cast<uint8_t>(write_bytes >> 16);
+  *p++ = static_cast<uint8_t>(write_bytes >> 8);
+  *p++ = static_cast<uint8_t>(write_bytes);
   *p++ = GRPC_CHTTP2_FRAME_DATA;
   *p++ = is_eof ? GRPC_CHTTP2_DATA_FLAG_END_STREAM : 0;
-  *p++ = (uint8_t)(id >> 24);
-  *p++ = (uint8_t)(id >> 16);
-  *p++ = (uint8_t)(id >> 8);
-  *p++ = (uint8_t)(id);
+  *p++ = static_cast<uint8_t>(id >> 24);
+  *p++ = static_cast<uint8_t>(id >> 16);
+  *p++ = static_cast<uint8_t>(id >> 8);
+  *p++ = static_cast<uint8_t>(id);
   grpc_slice_buffer_add(outbuf, hdr);
 
   grpc_slice_buffer_move_first_no_ref(inbuf, write_bytes, outbuf);
@@ -99,7 +100,7 @@
 grpc_error* grpc_deframe_unprocessed_incoming_frames(
     grpc_chttp2_data_parser* p, grpc_chttp2_stream* s,
     grpc_slice_buffer* slices, grpc_slice* slice_out,
-    grpc_byte_stream** stream_out) {
+    grpc_core::OrphanablePtr<grpc_core::ByteStream>* stream_out) {
   grpc_error* error = GRPC_ERROR_NONE;
   grpc_chttp2_transport* t = s->t;
 
@@ -140,7 +141,7 @@
             gpr_asprintf(&msg, "Bad GRPC frame type 0x%02x", p->frame_type);
             p->error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
             p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_STREAM_ID,
-                                          (intptr_t)s->id);
+                                          static_cast<intptr_t>(s->id));
             gpr_free(msg);
             msg = grpc_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
             p->error = grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES,
@@ -160,7 +161,7 @@
       /* fallthrough */
       case GRPC_CHTTP2_DATA_FH_1:
         s->stats.incoming.framing_bytes++;
-        p->frame_size = ((uint32_t)*cur) << 24;
+        p->frame_size = (static_cast<uint32_t>(*cur)) << 24;
         if (++cur == end) {
           p->state = GRPC_CHTTP2_DATA_FH_2;
           grpc_slice_unref_internal(slice);
@@ -169,7 +170,7 @@
       /* fallthrough */
       case GRPC_CHTTP2_DATA_FH_2:
         s->stats.incoming.framing_bytes++;
-        p->frame_size |= ((uint32_t)*cur) << 16;
+        p->frame_size |= (static_cast<uint32_t>(*cur)) << 16;
         if (++cur == end) {
           p->state = GRPC_CHTTP2_DATA_FH_3;
           grpc_slice_unref_internal(slice);
@@ -178,7 +179,7 @@
       /* fallthrough */
       case GRPC_CHTTP2_DATA_FH_3:
         s->stats.incoming.framing_bytes++;
-        p->frame_size |= ((uint32_t)*cur) << 8;
+        p->frame_size |= (static_cast<uint32_t>(*cur)) << 8;
         if (++cur == end) {
           p->state = GRPC_CHTTP2_DATA_FH_4;
           grpc_slice_unref_internal(slice);
@@ -189,19 +190,18 @@
         s->stats.incoming.framing_bytes++;
         GPR_ASSERT(stream_out != nullptr);
         GPR_ASSERT(p->parsing_frame == nullptr);
-        p->frame_size |= ((uint32_t)*cur);
+        p->frame_size |= (static_cast<uint32_t>(*cur));
         p->state = GRPC_CHTTP2_DATA_FRAME;
         ++cur;
         message_flags = 0;
         if (p->is_frame_compressed) {
           message_flags |= GRPC_WRITE_INTERNAL_COMPRESS;
         }
-        p->parsing_frame = grpc_chttp2_incoming_byte_stream_create(
+        p->parsing_frame = grpc_core::New<grpc_core::Chttp2IncomingByteStream>(
             t, s, p->frame_size, message_flags);
-        *stream_out = &p->parsing_frame->base;
-        if (p->parsing_frame->remaining_bytes == 0) {
-          GRPC_ERROR_UNREF(grpc_chttp2_incoming_byte_stream_finished(
-              p->parsing_frame, GRPC_ERROR_NONE, true));
+        stream_out->reset(p->parsing_frame);
+        if (p->parsing_frame->remaining_bytes() == 0) {
+          GRPC_ERROR_UNREF(p->parsing_frame->Finished(GRPC_ERROR_NONE, true));
           p->parsing_frame = nullptr;
           p->state = GRPC_CHTTP2_DATA_FH_0;
         }
@@ -209,8 +209,8 @@
 
         if (cur != end) {
           grpc_slice_buffer_undo_take_first(
-              slices,
-              grpc_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
+              slices, grpc_slice_sub(slice, static_cast<size_t>(cur - beg),
+                                     static_cast<size_t>(end - beg)));
         }
         grpc_slice_unref_internal(slice);
         return GRPC_ERROR_NONE;
@@ -221,20 +221,19 @@
           grpc_slice_unref_internal(slice);
           continue;
         }
-        uint32_t remaining = (uint32_t)(end - cur);
+        uint32_t remaining = static_cast<uint32_t>(end - cur);
         if (remaining == p->frame_size) {
           s->stats.incoming.data_bytes += remaining;
-          if (GRPC_ERROR_NONE != (error = grpc_chttp2_incoming_byte_stream_push(
-                                      p->parsing_frame,
-                                      grpc_slice_sub(slice, (size_t)(cur - beg),
-                                                     (size_t)(end - beg)),
-                                      slice_out))) {
+          if (GRPC_ERROR_NONE !=
+              (error = p->parsing_frame->Push(
+                   grpc_slice_sub(slice, static_cast<size_t>(cur - beg),
+                                  static_cast<size_t>(end - beg)),
+                   slice_out))) {
             grpc_slice_unref_internal(slice);
             return error;
           }
           if (GRPC_ERROR_NONE !=
-              (error = grpc_chttp2_incoming_byte_stream_finished(
-                   p->parsing_frame, GRPC_ERROR_NONE, true))) {
+              (error = p->parsing_frame->Finished(GRPC_ERROR_NONE, true))) {
             grpc_slice_unref_internal(slice);
             return error;
           }
@@ -244,11 +243,11 @@
           return GRPC_ERROR_NONE;
         } else if (remaining < p->frame_size) {
           s->stats.incoming.data_bytes += remaining;
-          if (GRPC_ERROR_NONE != (error = grpc_chttp2_incoming_byte_stream_push(
-                                      p->parsing_frame,
-                                      grpc_slice_sub(slice, (size_t)(cur - beg),
-                                                     (size_t)(end - beg)),
-                                      slice_out))) {
+          if (GRPC_ERROR_NONE !=
+              (error = p->parsing_frame->Push(
+                   grpc_slice_sub(slice, static_cast<size_t>(cur - beg),
+                                  static_cast<size_t>(end - beg)),
+                   slice_out))) {
             return error;
           }
           p->frame_size -= remaining;
@@ -258,17 +257,16 @@
           GPR_ASSERT(remaining > p->frame_size);
           s->stats.incoming.data_bytes += p->frame_size;
           if (GRPC_ERROR_NONE !=
-              (grpc_chttp2_incoming_byte_stream_push(
-                  p->parsing_frame,
-                  grpc_slice_sub(slice, (size_t)(cur - beg),
-                                 (size_t)(cur + p->frame_size - beg)),
-                  slice_out))) {
+              p->parsing_frame->Push(
+                  grpc_slice_sub(
+                      slice, static_cast<size_t>(cur - beg),
+                      static_cast<size_t>(cur + p->frame_size - beg)),
+                  slice_out)) {
             grpc_slice_unref_internal(slice);
             return error;
           }
           if (GRPC_ERROR_NONE !=
-              (error = grpc_chttp2_incoming_byte_stream_finished(
-                   p->parsing_frame, GRPC_ERROR_NONE, true))) {
+              (error = p->parsing_frame->Finished(GRPC_ERROR_NONE, true))) {
             grpc_slice_unref_internal(slice);
             return error;
           }
@@ -276,8 +274,8 @@
           p->state = GRPC_CHTTP2_DATA_FH_0;
           cur += p->frame_size;
           grpc_slice_buffer_undo_take_first(
-              slices,
-              grpc_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
+              slices, grpc_slice_sub(slice, static_cast<size_t>(cur - beg),
+                                     static_cast<size_t>(end - beg)));
           grpc_slice_unref_internal(slice);
           return GRPC_ERROR_NONE;
         }
diff --git a/src/core/ext/transport/chttp2/transport/frame_data.h b/src/core/ext/transport/chttp2/transport/frame_data.h
index 964cc59..e5d01f7 100644
--- a/src/core/ext/transport/chttp2/transport/frame_data.h
+++ b/src/core/ext/transport/chttp2/transport/frame_data.h
@@ -21,10 +21,11 @@
 
 /* Parser for GRPC streams embedded in DATA frames */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice.h>
 #include <grpc/slice_buffer.h>
 #include "src/core/ext/transport/chttp2/transport/frame.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/transport/byte_stream.h"
 #include "src/core/lib/transport/transport.h"
 
@@ -38,8 +39,9 @@
   GRPC_CHTTP2_DATA_ERROR
 } grpc_chttp2_stream_state;
 
-typedef struct grpc_chttp2_incoming_byte_stream
-    grpc_chttp2_incoming_byte_stream;
+namespace grpc_core {
+class Chttp2IncomingByteStream;
+}  // namespace grpc_core
 
 typedef struct {
   grpc_chttp2_stream_state state;
@@ -48,7 +50,7 @@
   grpc_error* error;
 
   bool is_frame_compressed;
-  grpc_chttp2_incoming_byte_stream* parsing_frame;
+  grpc_core::Chttp2IncomingByteStream* parsing_frame;
 } grpc_chttp2_data_parser;
 
 /* initialize per-stream state for data frame parsing */
@@ -77,6 +79,6 @@
 grpc_error* grpc_deframe_unprocessed_incoming_frames(
     grpc_chttp2_data_parser* p, grpc_chttp2_stream* s,
     grpc_slice_buffer* slices, grpc_slice* slice_out,
-    grpc_byte_stream** stream_out);
+    grpc_core::OrphanablePtr<grpc_core::ByteStream>* stream_out);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_DATA_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_goaway.cc b/src/core/ext/transport/chttp2/transport/frame_goaway.cc
index b60b422..2a1dd3c 100644
--- a/src/core/ext/transport/chttp2/transport/frame_goaway.cc
+++ b/src/core/ext/transport/chttp2/transport/frame_goaway.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/transport/frame_goaway.h"
 #include "src/core/ext/transport/chttp2/transport/internal.h"
 
@@ -46,7 +48,7 @@
 
   gpr_free(p->debug_data);
   p->debug_length = length - 8;
-  p->debug_data = (char*)gpr_malloc(p->debug_length);
+  p->debug_data = static_cast<char*>(gpr_malloc(p->debug_length));
   p->debug_pos = 0;
   p->state = GRPC_CHTTP2_GOAWAY_LSI0;
   return GRPC_ERROR_NONE;
@@ -59,7 +61,8 @@
   uint8_t* const beg = GRPC_SLICE_START_PTR(slice);
   uint8_t* const end = GRPC_SLICE_END_PTR(slice);
   uint8_t* cur = beg;
-  grpc_chttp2_goaway_parser* p = (grpc_chttp2_goaway_parser*)parser;
+  grpc_chttp2_goaway_parser* p =
+      static_cast<grpc_chttp2_goaway_parser*>(parser);
 
   switch (p->state) {
     case GRPC_CHTTP2_GOAWAY_LSI0:
@@ -67,7 +70,7 @@
         p->state = GRPC_CHTTP2_GOAWAY_LSI0;
         return GRPC_ERROR_NONE;
       }
-      p->last_stream_id = ((uint32_t)*cur) << 24;
+      p->last_stream_id = (static_cast<uint32_t>(*cur)) << 24;
       ++cur;
     /* fallthrough */
     case GRPC_CHTTP2_GOAWAY_LSI1:
@@ -75,7 +78,7 @@
         p->state = GRPC_CHTTP2_GOAWAY_LSI1;
         return GRPC_ERROR_NONE;
       }
-      p->last_stream_id |= ((uint32_t)*cur) << 16;
+      p->last_stream_id |= (static_cast<uint32_t>(*cur)) << 16;
       ++cur;
     /* fallthrough */
     case GRPC_CHTTP2_GOAWAY_LSI2:
@@ -83,7 +86,7 @@
         p->state = GRPC_CHTTP2_GOAWAY_LSI2;
         return GRPC_ERROR_NONE;
       }
-      p->last_stream_id |= ((uint32_t)*cur) << 8;
+      p->last_stream_id |= (static_cast<uint32_t>(*cur)) << 8;
       ++cur;
     /* fallthrough */
     case GRPC_CHTTP2_GOAWAY_LSI3:
@@ -91,7 +94,7 @@
         p->state = GRPC_CHTTP2_GOAWAY_LSI3;
         return GRPC_ERROR_NONE;
       }
-      p->last_stream_id |= ((uint32_t)*cur);
+      p->last_stream_id |= (static_cast<uint32_t>(*cur));
       ++cur;
     /* fallthrough */
     case GRPC_CHTTP2_GOAWAY_ERR0:
@@ -99,7 +102,7 @@
         p->state = GRPC_CHTTP2_GOAWAY_ERR0;
         return GRPC_ERROR_NONE;
       }
-      p->error_code = ((uint32_t)*cur) << 24;
+      p->error_code = (static_cast<uint32_t>(*cur)) << 24;
       ++cur;
     /* fallthrough */
     case GRPC_CHTTP2_GOAWAY_ERR1:
@@ -107,7 +110,7 @@
         p->state = GRPC_CHTTP2_GOAWAY_ERR1;
         return GRPC_ERROR_NONE;
       }
-      p->error_code |= ((uint32_t)*cur) << 16;
+      p->error_code |= (static_cast<uint32_t>(*cur)) << 16;
       ++cur;
     /* fallthrough */
     case GRPC_CHTTP2_GOAWAY_ERR2:
@@ -115,7 +118,7 @@
         p->state = GRPC_CHTTP2_GOAWAY_ERR2;
         return GRPC_ERROR_NONE;
       }
-      p->error_code |= ((uint32_t)*cur) << 8;
+      p->error_code |= (static_cast<uint32_t>(*cur)) << 8;
       ++cur;
     /* fallthrough */
     case GRPC_CHTTP2_GOAWAY_ERR3:
@@ -123,18 +126,19 @@
         p->state = GRPC_CHTTP2_GOAWAY_ERR3;
         return GRPC_ERROR_NONE;
       }
-      p->error_code |= ((uint32_t)*cur);
+      p->error_code |= (static_cast<uint32_t>(*cur));
       ++cur;
     /* fallthrough */
     case GRPC_CHTTP2_GOAWAY_DEBUG:
       if (end != cur)
-        memcpy(p->debug_data + p->debug_pos, cur, (size_t)(end - cur));
+        memcpy(p->debug_data + p->debug_pos, cur,
+               static_cast<size_t>(end - cur));
       GPR_ASSERT((size_t)(end - cur) < UINT32_MAX - p->debug_pos);
-      p->debug_pos += (uint32_t)(end - cur);
+      p->debug_pos += static_cast<uint32_t>(end - cur);
       p->state = GRPC_CHTTP2_GOAWAY_DEBUG;
       if (is_last) {
         grpc_chttp2_add_incoming_goaway(
-            t, (uint32_t)p->error_code,
+            t, p->error_code,
             grpc_slice_new(p->debug_data, p->debug_length, gpr_free));
         p->debug_data = nullptr;
       }
@@ -151,12 +155,12 @@
   uint8_t* p = GRPC_SLICE_START_PTR(header);
   uint32_t frame_length;
   GPR_ASSERT(GRPC_SLICE_LENGTH(debug_data) < UINT32_MAX - 4 - 4);
-  frame_length = 4 + 4 + (uint32_t)GRPC_SLICE_LENGTH(debug_data);
+  frame_length = 4 + 4 + static_cast<uint32_t> GRPC_SLICE_LENGTH(debug_data);
 
   /* frame header: length */
-  *p++ = (uint8_t)(frame_length >> 16);
-  *p++ = (uint8_t)(frame_length >> 8);
-  *p++ = (uint8_t)(frame_length);
+  *p++ = static_cast<uint8_t>(frame_length >> 16);
+  *p++ = static_cast<uint8_t>(frame_length >> 8);
+  *p++ = static_cast<uint8_t>(frame_length);
   /* frame header: type */
   *p++ = GRPC_CHTTP2_FRAME_GOAWAY;
   /* frame header: flags */
@@ -167,15 +171,15 @@
   *p++ = 0;
   *p++ = 0;
   /* payload: last stream id */
-  *p++ = (uint8_t)(last_stream_id >> 24);
-  *p++ = (uint8_t)(last_stream_id >> 16);
-  *p++ = (uint8_t)(last_stream_id >> 8);
-  *p++ = (uint8_t)(last_stream_id);
+  *p++ = static_cast<uint8_t>(last_stream_id >> 24);
+  *p++ = static_cast<uint8_t>(last_stream_id >> 16);
+  *p++ = static_cast<uint8_t>(last_stream_id >> 8);
+  *p++ = static_cast<uint8_t>(last_stream_id);
   /* payload: error code */
-  *p++ = (uint8_t)(error_code >> 24);
-  *p++ = (uint8_t)(error_code >> 16);
-  *p++ = (uint8_t)(error_code >> 8);
-  *p++ = (uint8_t)(error_code);
+  *p++ = static_cast<uint8_t>(error_code >> 24);
+  *p++ = static_cast<uint8_t>(error_code >> 16);
+  *p++ = static_cast<uint8_t>(error_code >> 8);
+  *p++ = static_cast<uint8_t>(error_code);
   GPR_ASSERT(p == GRPC_SLICE_END_PTR(header));
   grpc_slice_buffer_add(slice_buffer, header);
   grpc_slice_buffer_add(slice_buffer, debug_data);
diff --git a/src/core/ext/transport/chttp2/transport/frame_goaway.h b/src/core/ext/transport/chttp2/transport/frame_goaway.h
index 064d39a..66c7a68 100644
--- a/src/core/ext/transport/chttp2/transport/frame_goaway.h
+++ b/src/core/ext/transport/chttp2/transport/frame_goaway.h
@@ -19,11 +19,11 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_GOAWAY_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_GOAWAY_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice.h>
 #include <grpc/slice_buffer.h>
-#include <grpc/support/port_platform.h>
 #include "src/core/ext/transport/chttp2/transport/frame.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
 
 typedef enum {
   GRPC_CHTTP2_GOAWAY_LSI0,
diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.cc b/src/core/ext/transport/chttp2/transport/frame_ping.cc
index 298a567..205826b 100644
--- a/src/core/ext/transport/chttp2/transport/frame_ping.cc
+++ b/src/core/ext/transport/chttp2/transport/frame_ping.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/transport/frame_ping.h"
 #include "src/core/ext/transport/chttp2/transport/internal.h"
 
@@ -40,14 +42,14 @@
   *p++ = 0;
   *p++ = 0;
   *p++ = 0;
-  *p++ = (uint8_t)(opaque_8bytes >> 56);
-  *p++ = (uint8_t)(opaque_8bytes >> 48);
-  *p++ = (uint8_t)(opaque_8bytes >> 40);
-  *p++ = (uint8_t)(opaque_8bytes >> 32);
-  *p++ = (uint8_t)(opaque_8bytes >> 24);
-  *p++ = (uint8_t)(opaque_8bytes >> 16);
-  *p++ = (uint8_t)(opaque_8bytes >> 8);
-  *p++ = (uint8_t)(opaque_8bytes);
+  *p++ = static_cast<uint8_t>(opaque_8bytes >> 56);
+  *p++ = static_cast<uint8_t>(opaque_8bytes >> 48);
+  *p++ = static_cast<uint8_t>(opaque_8bytes >> 40);
+  *p++ = static_cast<uint8_t>(opaque_8bytes >> 32);
+  *p++ = static_cast<uint8_t>(opaque_8bytes >> 24);
+  *p++ = static_cast<uint8_t>(opaque_8bytes >> 16);
+  *p++ = static_cast<uint8_t>(opaque_8bytes >> 8);
+  *p++ = static_cast<uint8_t>(opaque_8bytes);
 
   return slice;
 }
@@ -75,10 +77,10 @@
   uint8_t* const beg = GRPC_SLICE_START_PTR(slice);
   uint8_t* const end = GRPC_SLICE_END_PTR(slice);
   uint8_t* cur = beg;
-  grpc_chttp2_ping_parser* p = (grpc_chttp2_ping_parser*)parser;
+  grpc_chttp2_ping_parser* p = static_cast<grpc_chttp2_ping_parser*>(parser);
 
   while (p->byte != 8 && cur != end) {
-    p->opaque_8bytes |= (((uint64_t)*cur) << (56 - 8 * p->byte));
+    p->opaque_8bytes |= ((static_cast<uint64_t>(*cur)) << (56 - 8 * p->byte));
     cur++;
     p->byte++;
   }
@@ -112,8 +114,8 @@
       if (!g_disable_ping_ack) {
         if (t->ping_ack_count == t->ping_ack_capacity) {
           t->ping_ack_capacity = GPR_MAX(t->ping_ack_capacity * 3 / 2, 3);
-          t->ping_acks = (uint64_t*)gpr_realloc(
-              t->ping_acks, t->ping_ack_capacity * sizeof(*t->ping_acks));
+          t->ping_acks = static_cast<uint64_t*>(gpr_realloc(
+              t->ping_acks, t->ping_ack_capacity * sizeof(*t->ping_acks)));
         }
         t->ping_acks[t->ping_ack_count++] = p->opaque_8bytes;
         grpc_chttp2_initiate_write(t, GRPC_CHTTP2_INITIATE_WRITE_PING_RESPONSE);
diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.h b/src/core/ext/transport/chttp2/transport/frame_ping.h
index 75bacfb..55a4499 100644
--- a/src/core/ext/transport/chttp2/transport/frame_ping.h
+++ b/src/core/ext/transport/chttp2/transport/frame_ping.h
@@ -19,9 +19,10 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_PING_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_PING_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice.h>
 #include "src/core/ext/transport/chttp2/transport/frame.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
 
 typedef struct {
   uint8_t byte;
diff --git a/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc b/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc
index fee5766..4bdd430 100644
--- a/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc
+++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/transport/frame_rst_stream.h"
 #include "src/core/ext/transport/chttp2/transport/internal.h"
 
@@ -42,15 +44,15 @@
   // Flags.
   *p++ = 0;
   // Stream ID.
-  *p++ = (uint8_t)(id >> 24);
-  *p++ = (uint8_t)(id >> 16);
-  *p++ = (uint8_t)(id >> 8);
-  *p++ = (uint8_t)(id);
+  *p++ = static_cast<uint8_t>(id >> 24);
+  *p++ = static_cast<uint8_t>(id >> 16);
+  *p++ = static_cast<uint8_t>(id >> 8);
+  *p++ = static_cast<uint8_t>(id);
   // Error code.
-  *p++ = (uint8_t)(code >> 24);
-  *p++ = (uint8_t)(code >> 16);
-  *p++ = (uint8_t)(code >> 8);
-  *p++ = (uint8_t)(code);
+  *p++ = static_cast<uint8_t>(code >> 24);
+  *p++ = static_cast<uint8_t>(code >> 16);
+  *p++ = static_cast<uint8_t>(code >> 8);
+  *p++ = static_cast<uint8_t>(code);
 
   return slice;
 }
@@ -76,21 +78,22 @@
   uint8_t* const beg = GRPC_SLICE_START_PTR(slice);
   uint8_t* const end = GRPC_SLICE_END_PTR(slice);
   uint8_t* cur = beg;
-  grpc_chttp2_rst_stream_parser* p = (grpc_chttp2_rst_stream_parser*)parser;
+  grpc_chttp2_rst_stream_parser* p =
+      static_cast<grpc_chttp2_rst_stream_parser*>(parser);
 
   while (p->byte != 4 && cur != end) {
     p->reason_bytes[p->byte] = *cur;
     cur++;
     p->byte++;
   }
-  s->stats.incoming.framing_bytes += (uint64_t)(end - cur);
+  s->stats.incoming.framing_bytes += static_cast<uint64_t>(end - cur);
 
   if (p->byte == 4) {
     GPR_ASSERT(is_last);
-    uint32_t reason = (((uint32_t)p->reason_bytes[0]) << 24) |
-                      (((uint32_t)p->reason_bytes[1]) << 16) |
-                      (((uint32_t)p->reason_bytes[2]) << 8) |
-                      (((uint32_t)p->reason_bytes[3]));
+    uint32_t reason = ((static_cast<uint32_t>(p->reason_bytes[0])) << 24) |
+                      ((static_cast<uint32_t>(p->reason_bytes[1])) << 16) |
+                      ((static_cast<uint32_t>(p->reason_bytes[2])) << 8) |
+                      ((static_cast<uint32_t>(p->reason_bytes[3])));
     grpc_error* error = GRPC_ERROR_NONE;
     if (reason != GRPC_HTTP2_NO_ERROR || s->metadata_buffer[1].size == 0) {
       char* message;
@@ -99,7 +102,7 @@
           grpc_error_set_str(GRPC_ERROR_CREATE_FROM_STATIC_STRING("RST_STREAM"),
                              GRPC_ERROR_STR_GRPC_MESSAGE,
                              grpc_slice_from_copied_string(message)),
-          GRPC_ERROR_INT_HTTP2_ERROR, (intptr_t)reason);
+          GRPC_ERROR_INT_HTTP2_ERROR, static_cast<intptr_t>(reason));
       gpr_free(message);
     }
     grpc_chttp2_mark_stream_closed(t, s, true, true, error);
diff --git a/src/core/ext/transport/chttp2/transport/frame_rst_stream.h b/src/core/ext/transport/chttp2/transport/frame_rst_stream.h
index e76a3ca..6bcf9c4 100644
--- a/src/core/ext/transport/chttp2/transport/frame_rst_stream.h
+++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.h
@@ -19,9 +19,10 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_RST_STREAM_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_RST_STREAM_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice.h>
 #include "src/core/ext/transport/chttp2/transport/frame.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/transport/transport.h"
 
 typedef struct {
diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.cc b/src/core/ext/transport/chttp2/transport/frame_settings.cc
index 0d245f4..9ea27dc 100644
--- a/src/core/ext/transport/chttp2/transport/frame_settings.cc
+++ b/src/core/ext/transport/chttp2/transport/frame_settings.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/transport/frame_settings.h"
 #include "src/core/ext/transport/chttp2/transport/internal.h"
 
@@ -24,7 +26,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/ext/transport/chttp2/transport/frame.h"
@@ -32,9 +33,9 @@
 #include "src/core/lib/transport/http2_errors.h"
 
 static uint8_t* fill_header(uint8_t* out, uint32_t length, uint8_t flags) {
-  *out++ = (uint8_t)(length >> 16);
-  *out++ = (uint8_t)(length >> 8);
-  *out++ = (uint8_t)(length);
+  *out++ = static_cast<uint8_t>(length >> 16);
+  *out++ = static_cast<uint8_t>(length >> 8);
+  *out++ = static_cast<uint8_t>(length);
   *out++ = GRPC_CHTTP2_FRAME_SETTINGS;
   *out++ = flags;
   *out++ = 0;
@@ -61,12 +62,12 @@
 
   for (i = 0; i < count; i++) {
     if (new_settings[i] != old_settings[i] || (force_mask & (1u << i)) != 0) {
-      *p++ = (uint8_t)(grpc_setting_id_to_wire_id[i] >> 8);
-      *p++ = (uint8_t)(grpc_setting_id_to_wire_id[i]);
-      *p++ = (uint8_t)(new_settings[i] >> 24);
-      *p++ = (uint8_t)(new_settings[i] >> 16);
-      *p++ = (uint8_t)(new_settings[i] >> 8);
-      *p++ = (uint8_t)(new_settings[i]);
+      *p++ = static_cast<uint8_t>(grpc_setting_id_to_wire_id[i] >> 8);
+      *p++ = static_cast<uint8_t>(grpc_setting_id_to_wire_id[i]);
+      *p++ = static_cast<uint8_t>(new_settings[i] >> 24);
+      *p++ = static_cast<uint8_t>(new_settings[i] >> 16);
+      *p++ = static_cast<uint8_t>(new_settings[i] >> 8);
+      *p++ = static_cast<uint8_t>(new_settings[i]);
       old_settings[i] = new_settings[i];
     }
   }
@@ -111,7 +112,8 @@
 grpc_error* grpc_chttp2_settings_parser_parse(void* p, grpc_chttp2_transport* t,
                                               grpc_chttp2_stream* s,
                                               grpc_slice slice, int is_last) {
-  grpc_chttp2_settings_parser* parser = (grpc_chttp2_settings_parser*)p;
+  grpc_chttp2_settings_parser* parser =
+      static_cast<grpc_chttp2_settings_parser*>(p);
   const uint8_t* cur = GRPC_SLICE_START_PTR(slice);
   const uint8_t* end = GRPC_SLICE_END_PTR(slice);
   char* msg;
@@ -138,7 +140,7 @@
           }
           return GRPC_ERROR_NONE;
         }
-        parser->id = (uint16_t)(((uint16_t)*cur) << 8);
+        parser->id = static_cast<uint16_t>((static_cast<uint16_t>(*cur)) << 8);
         cur++;
       /* fallthrough */
       case GRPC_CHTTP2_SPS_ID1:
@@ -146,7 +148,7 @@
           parser->state = GRPC_CHTTP2_SPS_ID1;
           return GRPC_ERROR_NONE;
         }
-        parser->id = (uint16_t)(parser->id | (*cur));
+        parser->id = static_cast<uint16_t>(parser->id | (*cur));
         cur++;
       /* fallthrough */
       case GRPC_CHTTP2_SPS_VAL0:
@@ -154,7 +156,7 @@
           parser->state = GRPC_CHTTP2_SPS_VAL0;
           return GRPC_ERROR_NONE;
         }
-        parser->value = ((uint32_t)*cur) << 24;
+        parser->value = (static_cast<uint32_t>(*cur)) << 24;
         cur++;
       /* fallthrough */
       case GRPC_CHTTP2_SPS_VAL1:
@@ -162,7 +164,7 @@
           parser->state = GRPC_CHTTP2_SPS_VAL1;
           return GRPC_ERROR_NONE;
         }
-        parser->value |= ((uint32_t)*cur) << 16;
+        parser->value |= (static_cast<uint32_t>(*cur)) << 16;
         cur++;
       /* fallthrough */
       case GRPC_CHTTP2_SPS_VAL2:
@@ -170,7 +172,7 @@
           parser->state = GRPC_CHTTP2_SPS_VAL2;
           return GRPC_ERROR_NONE;
         }
-        parser->value |= ((uint32_t)*cur) << 8;
+        parser->value |= (static_cast<uint32_t>(*cur)) << 8;
         cur++;
       /* fallthrough */
       case GRPC_CHTTP2_SPS_VAL3:
@@ -212,12 +214,12 @@
           }
           if (id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE &&
               parser->incoming_settings[id] != parser->value) {
-            t->initial_window_update +=
-                (int64_t)parser->value - parser->incoming_settings[id];
+            t->initial_window_update += static_cast<int64_t>(parser->value) -
+                                        parser->incoming_settings[id];
             if (grpc_http_trace.enabled() || grpc_flowctl_trace.enabled()) {
               gpr_log(GPR_DEBUG, "%p[%s] adding %d for initial_window change",
                       t, t->is_client ? "cli" : "svr",
-                      (int)t->initial_window_update);
+                      static_cast<int>(t->initial_window_update));
             }
           }
           parser->incoming_settings[id] = parser->value;
diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.h b/src/core/ext/transport/chttp2/transport/frame_settings.h
index ce65402..8d8d9b1 100644
--- a/src/core/ext/transport/chttp2/transport/frame_settings.h
+++ b/src/core/ext/transport/chttp2/transport/frame_settings.h
@@ -19,11 +19,11 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_SETTINGS_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_SETTINGS_H
 
-#include <grpc/slice.h>
 #include <grpc/support/port_platform.h>
+
+#include <grpc/slice.h>
 #include "src/core/ext/transport/chttp2/transport/frame.h"
 #include "src/core/ext/transport/chttp2/transport/http2_settings.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
 
 typedef enum {
   GRPC_CHTTP2_SPS_ID0,
diff --git a/src/core/ext/transport/chttp2/transport/frame_window_update.cc b/src/core/ext/transport/chttp2/transport/frame_window_update.cc
index 418ca14..4b586dc 100644
--- a/src/core/ext/transport/chttp2/transport/frame_window_update.cc
+++ b/src/core/ext/transport/chttp2/transport/frame_window_update.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/transport/frame_window_update.h"
 #include "src/core/ext/transport/chttp2/transport/internal.h"
 
@@ -37,14 +39,14 @@
   *p++ = 4;
   *p++ = GRPC_CHTTP2_FRAME_WINDOW_UPDATE;
   *p++ = 0;
-  *p++ = (uint8_t)(id >> 24);
-  *p++ = (uint8_t)(id >> 16);
-  *p++ = (uint8_t)(id >> 8);
-  *p++ = (uint8_t)(id);
-  *p++ = (uint8_t)(window_update >> 24);
-  *p++ = (uint8_t)(window_update >> 16);
-  *p++ = (uint8_t)(window_update >> 8);
-  *p++ = (uint8_t)(window_update);
+  *p++ = static_cast<uint8_t>(id >> 24);
+  *p++ = static_cast<uint8_t>(id >> 16);
+  *p++ = static_cast<uint8_t>(id >> 8);
+  *p++ = static_cast<uint8_t>(id);
+  *p++ = static_cast<uint8_t>(window_update >> 24);
+  *p++ = static_cast<uint8_t>(window_update >> 16);
+  *p++ = static_cast<uint8_t>(window_update >> 8);
+  *p++ = static_cast<uint8_t>(window_update);
 
   return slice;
 }
@@ -73,16 +75,16 @@
   uint8_t* const end = GRPC_SLICE_END_PTR(slice);
   uint8_t* cur = beg;
   grpc_chttp2_window_update_parser* p =
-      (grpc_chttp2_window_update_parser*)parser;
+      static_cast<grpc_chttp2_window_update_parser*>(parser);
 
   while (p->byte != 4 && cur != end) {
-    p->amount |= ((uint32_t)*cur) << (8 * (3 - p->byte));
+    p->amount |= (static_cast<uint32_t>(*cur)) << (8 * (3 - p->byte));
     cur++;
     p->byte++;
   }
 
   if (s != nullptr) {
-    s->stats.incoming.framing_bytes += (uint32_t)(end - cur);
+    s->stats.incoming.framing_bytes += static_cast<uint32_t>(end - cur);
   }
 
   if (p->byte == 4) {
diff --git a/src/core/ext/transport/chttp2/transport/frame_window_update.h b/src/core/ext/transport/chttp2/transport/frame_window_update.h
index a32f1a9..3d2391f 100644
--- a/src/core/ext/transport/chttp2/transport/frame_window_update.h
+++ b/src/core/ext/transport/chttp2/transport/frame_window_update.h
@@ -19,9 +19,10 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_WINDOW_UPDATE_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_WINDOW_UPDATE_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice.h>
 #include "src/core/ext/transport/chttp2/transport/frame.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/transport/transport.h"
 
 typedef struct {
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
index 3a5692a..e4f3c1b 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/transport/hpack_encoder.h"
 
 #include <assert.h>
@@ -28,7 +30,6 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
 #include "src/core/ext/transport/chttp2/transport/hpack_table.h"
@@ -79,15 +80,15 @@
 static void fill_header(uint8_t* p, uint8_t type, uint32_t id, size_t len,
                         uint8_t flags) {
   GPR_ASSERT(len < 16777316);
-  *p++ = (uint8_t)(len >> 16);
-  *p++ = (uint8_t)(len >> 8);
-  *p++ = (uint8_t)(len);
+  *p++ = static_cast<uint8_t>(len >> 16);
+  *p++ = static_cast<uint8_t>(len >> 8);
+  *p++ = static_cast<uint8_t>(len);
   *p++ = type;
   *p++ = flags;
-  *p++ = (uint8_t)(id >> 24);
-  *p++ = (uint8_t)(id >> 16);
-  *p++ = (uint8_t)(id >> 8);
-  *p++ = (uint8_t)(id);
+  *p++ = static_cast<uint8_t>(id >> 24);
+  *p++ = static_cast<uint8_t>(id >> 16);
+  *p++ = static_cast<uint8_t>(id >> 8);
+  *p++ = static_cast<uint8_t>(id);
 }
 
 /* finish a frame - fill in the previously reserved header */
@@ -99,8 +100,9 @@
   fill_header(
       GRPC_SLICE_START_PTR(st->output->slices[st->header_idx]), type,
       st->stream_id, st->output->length - st->output_length_at_start_of_frame,
-      (uint8_t)((is_last_in_stream ? GRPC_CHTTP2_DATA_FLAG_END_STREAM : 0) |
-                (is_header_boundary ? GRPC_CHTTP2_DATA_FLAG_END_HEADERS : 0)));
+      static_cast<uint8_t>(
+          (is_last_in_stream ? GRPC_CHTTP2_DATA_FLAG_END_STREAM : 0) |
+          (is_header_boundary ? GRPC_CHTTP2_DATA_FLAG_END_HEADERS : 0)));
   st->stats->framing_bytes += 9;
   st->is_first_frame = 0;
 }
@@ -170,9 +172,9 @@
   GPR_ASSERT(c->table_size >=
              c->table_elem_size[c->tail_remote_index % c->cap_table_elems]);
   GPR_ASSERT(c->table_elems > 0);
-  c->table_size =
-      (uint16_t)(c->table_size -
-                 c->table_elem_size[c->tail_remote_index % c->cap_table_elems]);
+  c->table_size = static_cast<uint16_t>(
+      c->table_size -
+      c->table_elem_size[c->tail_remote_index % c->cap_table_elems]);
   c->table_elems--;
 }
 
@@ -198,8 +200,9 @@
     evict_entry(c);
   }
   GPR_ASSERT(c->table_elems < c->max_table_size);
-  c->table_elem_size[new_index % c->cap_table_elems] = (uint16_t)elem_size;
-  c->table_size = (uint16_t)(c->table_size + elem_size);
+  c->table_elem_size[new_index % c->cap_table_elems] =
+      static_cast<uint16_t>(elem_size);
+  c->table_size = static_cast<uint16_t>(c->table_size + elem_size);
   c->table_elems++;
 
   return new_index;
@@ -395,9 +398,9 @@
   GPR_ASSERT(unused_index == 0);
   GRPC_STATS_INC_HPACK_SEND_LITHDR_INCIDX_V();
   GRPC_STATS_INC_HPACK_SEND_UNCOMPRESSED();
-  uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
+  uint32_t len_key = static_cast<uint32_t> GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
   wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
-  uint32_t len_val = (uint32_t)wire_value_length(value);
+  uint32_t len_val = static_cast<uint32_t>(wire_value_length(value));
   uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
   uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
   GPR_ASSERT(len_key <= UINT32_MAX);
@@ -417,9 +420,9 @@
   GPR_ASSERT(unused_index == 0);
   GRPC_STATS_INC_HPACK_SEND_LITHDR_NOTIDX_V();
   GRPC_STATS_INC_HPACK_SEND_UNCOMPRESSED();
-  uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
+  uint32_t len_key = static_cast<uint32_t> GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
   wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
-  uint32_t len_val = (uint32_t)wire_value_length(value);
+  uint32_t len_val = static_cast<uint32_t>(wire_value_length(value));
   uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
   uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
   GPR_ASSERT(len_key <= UINT32_MAX);
@@ -584,8 +587,8 @@
   c->cap_table_elems = elems_for_bytes(c->max_table_size);
   c->max_table_elems = c->cap_table_elems;
   c->max_usable_size = GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE;
-  c->table_elem_size =
-      (uint16_t*)gpr_malloc(sizeof(*c->table_elem_size) * c->cap_table_elems);
+  c->table_elem_size = static_cast<uint16_t*>(
+      gpr_malloc(sizeof(*c->table_elem_size) * c->cap_table_elems));
   memset(c->table_elem_size, 0,
          sizeof(*c->table_elem_size) * c->cap_table_elems);
   for (size_t i = 0; i < GPR_ARRAY_SIZE(c->entries_keys); i++) {
@@ -613,7 +616,7 @@
 
 static void rebuild_elems(grpc_chttp2_hpack_compressor* c, uint32_t new_cap) {
   uint16_t* table_elem_size =
-      (uint16_t*)gpr_malloc(sizeof(*table_elem_size) * new_cap);
+      static_cast<uint16_t*>(gpr_malloc(sizeof(*table_elem_size) * new_cap));
   uint32_t i;
 
   memset(table_elem_size, 0, sizeof(*table_elem_size) * new_cap);
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.h b/src/core/ext/transport/chttp2/transport/hpack_encoder.h
index a26514c..b370932 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.h
@@ -19,9 +19,10 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_ENCODER_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_ENCODER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice.h>
 #include <grpc/slice_buffer.h>
-#include <grpc/support/port_platform.h>
 #include "src/core/ext/transport/chttp2/transport/frame.h"
 #include "src/core/lib/transport/metadata.h"
 #include "src/core/lib/transport/metadata_batch.h"
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.cc b/src/core/ext/transport/chttp2/transport/hpack_parser.cc
index 8d1c57a..fc96a8b 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_parser.cc
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
 #include "src/core/ext/transport/chttp2/transport/internal.h"
 
@@ -25,9 +27,7 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
 #include "src/core/lib/debug/stats.h"
@@ -758,8 +758,9 @@
     return grpc_error_set_int(
         grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
                                "Invalid HPACK index received"),
-                           GRPC_ERROR_INT_INDEX, (intptr_t)p->index),
-        GRPC_ERROR_INT_SIZE, (intptr_t)p->table.num_ents);
+                           GRPC_ERROR_INT_INDEX,
+                           static_cast<intptr_t>(p->index)),
+        GRPC_ERROR_INT_SIZE, static_cast<intptr_t>(p->table.num_ents));
   }
   GRPC_MDELEM_REF(md);
   GRPC_STATS_INC_HPACK_RECV_INDEXED();
@@ -1088,7 +1089,7 @@
     return GRPC_ERROR_NONE;
   }
 
-  *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 7;
+  *p->parsing.value += ((static_cast<uint32_t>(*cur)) & 0x7f) << 7;
 
   if ((*cur) & 0x80) {
     return parse_value2(p, cur + 1, end);
@@ -1106,7 +1107,7 @@
     return GRPC_ERROR_NONE;
   }
 
-  *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 14;
+  *p->parsing.value += ((static_cast<uint32_t>(*cur)) & 0x7f) << 14;
 
   if ((*cur) & 0x80) {
     return parse_value3(p, cur + 1, end);
@@ -1124,7 +1125,7 @@
     return GRPC_ERROR_NONE;
   }
 
-  *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 21;
+  *p->parsing.value += ((static_cast<uint32_t>(*cur)) & 0x7f) << 21;
 
   if ((*cur) & 0x80) {
     return parse_value4(p, cur + 1, end);
@@ -1153,7 +1154,7 @@
   }
 
   cur_value = *p->parsing.value;
-  add_value = ((uint32_t)c) << 28;
+  add_value = (static_cast<uint32_t>(c)) << 28;
   if (add_value > 0xffffffffu - cur_value) {
     goto error;
   }
@@ -1228,13 +1229,14 @@
   if (length == 0) return;
   if (length + str->data.copied.length > str->data.copied.capacity) {
     GPR_ASSERT(str->data.copied.length + length <= UINT32_MAX);
-    str->data.copied.capacity = (uint32_t)(str->data.copied.length + length);
-    str->data.copied.str =
-        (char*)gpr_realloc(str->data.copied.str, str->data.copied.capacity);
+    str->data.copied.capacity =
+        static_cast<uint32_t>(str->data.copied.length + length);
+    str->data.copied.str = static_cast<char*>(
+        gpr_realloc(str->data.copied.str, str->data.copied.capacity));
   }
   memcpy(str->data.copied.str + str->data.copied.length, data, length);
   GPR_ASSERT(length <= UINT32_MAX - str->data.copied.length);
-  str->data.copied.length += (uint32_t)length;
+  str->data.copied.length += static_cast<uint32_t>(length);
 }
 
 static grpc_error* append_string(grpc_chttp2_hpack_parser* p,
@@ -1242,9 +1244,9 @@
   grpc_chttp2_hpack_parser_string* str = p->parsing.str;
   uint32_t bits;
   uint8_t decoded[3];
-  switch ((binary_state)p->binary) {
+  switch (static_cast<binary_state>(p->binary)) {
     case NOT_BINARY:
-      append_bytes(str, cur, (size_t)(end - cur));
+      append_bytes(str, cur, static_cast<size_t>(end - cur));
       return GRPC_ERROR_NONE;
     case BINARY_BEGIN:
       if (cur == end) {
@@ -1256,7 +1258,7 @@
         ++cur;
         p->binary = NOT_BINARY;
         GRPC_STATS_INC_HPACK_RECV_BINARY();
-        append_bytes(str, cur, (size_t)(end - cur));
+        append_bytes(str, cur, static_cast<size_t>(end - cur));
         return GRPC_ERROR_NONE;
       }
       GRPC_STATS_INC_HPACK_RECV_BINARY_BASE64();
@@ -1325,9 +1327,9 @@
         goto b64_byte3;
       p->base64_buffer |= bits;
       bits = p->base64_buffer;
-      decoded[0] = (uint8_t)(bits >> 16);
-      decoded[1] = (uint8_t)(bits >> 8);
-      decoded[2] = (uint8_t)(bits);
+      decoded[0] = static_cast<uint8_t>(bits >> 16);
+      decoded[1] = static_cast<uint8_t>(bits >> 8);
+      decoded[2] = static_cast<uint8_t>(bits);
       append_bytes(str, decoded, 3);
       goto b64_byte0;
   }
@@ -1341,7 +1343,7 @@
   uint8_t decoded[2];
   uint32_t bits;
   grpc_chttp2_hpack_parser_string* str = p->parsing.str;
-  switch ((binary_state)p->binary) {
+  switch (static_cast<binary_state>(p->binary)) {
     case NOT_BINARY:
       break;
     case BINARY_BEGIN:
@@ -1362,7 +1364,7 @@
         gpr_free(msg);
         return parse_error(p, cur, end, err);
       }
-      decoded[0] = (uint8_t)(bits >> 16);
+      decoded[0] = static_cast<uint8_t>(bits >> 16);
       append_bytes(str, decoded, 1);
       break;
     case B64_BYTE3:
@@ -1375,8 +1377,8 @@
         gpr_free(msg);
         return parse_error(p, cur, end, err);
       }
-      decoded[0] = (uint8_t)(bits >> 16);
-      decoded[1] = (uint8_t)(bits >> 8);
+      decoded[0] = static_cast<uint8_t>(bits >> 16);
+      decoded[1] = static_cast<uint8_t>(bits >> 8);
       append_bytes(str, decoded, 2);
       break;
   }
@@ -1389,7 +1391,7 @@
   int16_t next = next_sub_tbl[16 * next_tbl[p->huff_state] + nibble];
   if (emit != -1) {
     if (emit >= 0 && emit < 256) {
-      uint8_t c = (uint8_t)emit;
+      uint8_t c = static_cast<uint8_t>(emit);
       grpc_error* err = append_string(p, &c, (&c) + 1);
       if (err != GRPC_ERROR_NONE) return err;
     } else {
@@ -1427,7 +1429,7 @@
 static grpc_error* parse_string(grpc_chttp2_hpack_parser* p, const uint8_t* cur,
                                 const uint8_t* end) {
   size_t remaining = p->strlen - p->strgot;
-  size_t given = (size_t)(end - cur);
+  size_t given = static_cast<size_t>(end - cur);
   if (remaining <= given) {
     grpc_error* err = add_str_bytes(p, cur, cur + remaining);
     if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
@@ -1438,7 +1440,7 @@
     grpc_error* err = add_str_bytes(p, cur, cur + given);
     if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
     GPR_ASSERT(given <= UINT32_MAX - p->strgot);
-    p->strgot += (uint32_t)given;
+    p->strgot += static_cast<uint32_t>(given);
     p->state = parse_string;
     return GRPC_ERROR_NONE;
   }
@@ -1449,12 +1451,13 @@
                                       const uint8_t* cur, const uint8_t* end,
                                       uint8_t binary,
                                       grpc_chttp2_hpack_parser_string* str) {
-  if (!p->huff && binary == NOT_BINARY && (end - cur) >= (intptr_t)p->strlen &&
+  if (!p->huff && binary == NOT_BINARY &&
+      (end - cur) >= static_cast<intptr_t>(p->strlen) &&
       p->current_slice_refcount != nullptr) {
     GRPC_STATS_INC_HPACK_RECV_UNCOMPRESSED();
     str->copied = false;
     str->data.referenced.refcount = p->current_slice_refcount;
-    str->data.referenced.data.refcounted.bytes = (uint8_t*)cur;
+    str->data.referenced.data.refcounted.bytes = const_cast<uint8_t*>(cur);
     str->data.referenced.data.refcounted.length = p->strlen;
     grpc_slice_ref_internal(str->data.referenced);
     return parse_next(p, cur + p->strlen, end);
@@ -1504,8 +1507,9 @@
     return grpc_error_set_int(
         grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
                                "Invalid HPACK index received"),
-                           GRPC_ERROR_INT_INDEX, (intptr_t)p->index),
-        GRPC_ERROR_INT_SIZE, (intptr_t)p->table.num_ents);
+                           GRPC_ERROR_INT_INDEX,
+                           static_cast<intptr_t>(p->index)),
+        GRPC_ERROR_INT_SIZE, static_cast<intptr_t>(p->table.num_ents));
   }
   *is = grpc_is_binary_header(GRPC_MDKEY(elem));
   return GRPC_ERROR_NONE;
@@ -1590,7 +1594,7 @@
     grpc_chttp2_maybe_complete_recv_trailing_metadata};
 
 static void force_client_rst_stream(void* sp, grpc_error* error) {
-  grpc_chttp2_stream* s = (grpc_chttp2_stream*)sp;
+  grpc_chttp2_stream* s = static_cast<grpc_chttp2_stream*>(sp);
   grpc_chttp2_transport* t = s->t;
   if (!s->write_closed) {
     grpc_slice_buffer_add(
@@ -1619,7 +1623,8 @@
                                             grpc_chttp2_stream* s,
                                             grpc_slice slice, int is_last) {
   GPR_TIMER_SCOPE("grpc_chttp2_hpack_parser_parse", 0);
-  grpc_chttp2_hpack_parser* parser = (grpc_chttp2_hpack_parser*)hpack_parser;
+  grpc_chttp2_hpack_parser* parser =
+      static_cast<grpc_chttp2_hpack_parser*>(hpack_parser);
   if (s != nullptr) {
     s->stats.incoming.header_bytes += GRPC_SLICE_LENGTH(slice);
   }
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.h b/src/core/ext/transport/chttp2/transport/hpack_parser.h
index 060bc5c..3e05de4 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_parser.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.h
@@ -19,12 +19,12 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_PARSER_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_PARSER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stddef.h>
 
-#include <grpc/support/port_platform.h>
 #include "src/core/ext/transport/chttp2/transport/frame.h"
 #include "src/core/ext/transport/chttp2/transport/hpack_table.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/transport/metadata.h"
 
 typedef struct grpc_chttp2_hpack_parser grpc_chttp2_hpack_parser;
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.cc b/src/core/ext/transport/chttp2/transport/hpack_table.cc
index 9fad158..f050f50 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_table.cc
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/transport/hpack_table.h"
 
 #include <assert.h>
@@ -173,7 +175,8 @@
       GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE;
   tbl->max_entries = tbl->cap_entries =
       entries_for_bytes(tbl->current_table_bytes);
-  tbl->ents = (grpc_mdelem*)gpr_malloc(sizeof(*tbl->ents) * tbl->cap_entries);
+  tbl->ents = static_cast<grpc_mdelem*>(
+      gpr_malloc(sizeof(*tbl->ents) * tbl->cap_entries));
   memset(tbl->ents, 0, sizeof(*tbl->ents) * tbl->cap_entries);
   for (i = 1; i <= GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
     tbl->static_ents[i - 1] = grpc_mdelem_from_slices(
@@ -218,14 +221,15 @@
                       GRPC_SLICE_LENGTH(GRPC_MDVALUE(first_ent)) +
                       GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
   GPR_ASSERT(elem_bytes <= tbl->mem_used);
-  tbl->mem_used -= (uint32_t)elem_bytes;
+  tbl->mem_used -= static_cast<uint32_t>(elem_bytes);
   tbl->first_ent = ((tbl->first_ent + 1) % tbl->cap_entries);
   tbl->num_ents--;
   GRPC_MDELEM_UNREF(first_ent);
 }
 
 static void rebuild_ents(grpc_chttp2_hptbl* tbl, uint32_t new_cap) {
-  grpc_mdelem* ents = (grpc_mdelem*)gpr_malloc(sizeof(*ents) * new_cap);
+  grpc_mdelem* ents =
+      static_cast<grpc_mdelem*>(gpr_malloc(sizeof(*ents) * new_cap));
   uint32_t i;
 
   for (i = 0; i < tbl->num_ents; i++) {
@@ -320,7 +324,8 @@
   }
 
   /* evict entries to ensure no overflow */
-  while (elem_bytes > (size_t)tbl->current_table_bytes - tbl->mem_used) {
+  while (elem_bytes >
+         static_cast<size_t>(tbl->current_table_bytes) - tbl->mem_used) {
     evict1(tbl);
   }
 
@@ -330,7 +335,7 @@
 
   /* update accounting values */
   tbl->num_ents++;
-  tbl->mem_used += (uint32_t)elem_bytes;
+  tbl->mem_used += static_cast<uint32_t>(elem_bytes);
   return GRPC_ERROR_NONE;
 }
 
@@ -350,8 +355,8 @@
 
   /* Scan the dynamic table */
   for (i = 0; i < tbl->num_ents; i++) {
-    uint32_t idx =
-        (uint32_t)(tbl->num_ents - i + GRPC_CHTTP2_LAST_STATIC_ENTRY);
+    uint32_t idx = static_cast<uint32_t>(tbl->num_ents - i +
+                                         GRPC_CHTTP2_LAST_STATIC_ENTRY);
     grpc_mdelem ent = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries];
     if (!grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDKEY(ent))) continue;
     r.index = idx;
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.h b/src/core/ext/transport/chttp2/transport/hpack_table.h
index 189ad1c..98026a4 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_table.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.h
@@ -19,8 +19,9 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_TABLE_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_TABLE_H
 
-#include <grpc/slice.h>
 #include <grpc/support/port_platform.h>
+
+#include <grpc/slice.h>
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/transport/metadata.h"
 
diff --git a/src/core/ext/transport/chttp2/transport/http2_settings.cc b/src/core/ext/transport/chttp2/transport/http2_settings.cc
index 0aab864..294ee8e 100644
--- a/src/core/ext/transport/chttp2/transport/http2_settings.cc
+++ b/src/core/ext/transport/chttp2/transport/http2_settings.cc
@@ -18,9 +18,11 @@
  * Automatically generated by tools/codegen/core/gen_settings_ids.py
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/transport/http2_settings.h"
 
-#include <grpc/support/useful.h>
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/transport/http2_errors.h"
 
 const uint16_t grpc_setting_id_to_wire_id[] = {1, 2, 3, 4, 5, 6, 65027};
@@ -35,7 +37,7 @@
       h += 4;
       break;
   }
-  *out = (grpc_chttp2_setting_id)h;
+  *out = static_cast<grpc_chttp2_setting_id>(h);
   return h < GPR_ARRAY_SIZE(grpc_setting_id_to_wire_id) &&
          grpc_setting_id_to_wire_id[h] == wire_id;
 }
diff --git a/src/core/ext/transport/chttp2/transport/http2_settings.h b/src/core/ext/transport/chttp2/transport/http2_settings.h
index fd15b69..07ce062 100644
--- a/src/core/ext/transport/chttp2/transport/http2_settings.h
+++ b/src/core/ext/transport/chttp2/transport/http2_settings.h
@@ -21,6 +21,8 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stdbool.h>
 #include <stdint.h>
 
diff --git a/src/core/ext/transport/chttp2/transport/huffsyms.cc b/src/core/ext/transport/chttp2/transport/huffsyms.cc
index f28d8cc..813e4c9 100644
--- a/src/core/ext/transport/chttp2/transport/huffsyms.cc
+++ b/src/core/ext/transport/chttp2/transport/huffsyms.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/transport/huffsyms.h"
 
 /* Constants pulled from the HPACK spec, and converted to C using the vim
diff --git a/src/core/ext/transport/chttp2/transport/incoming_metadata.cc b/src/core/ext/transport/chttp2/transport/incoming_metadata.cc
index ef0c9ed..4d7dfd9 100644
--- a/src/core/ext/transport/chttp2/transport/incoming_metadata.cc
+++ b/src/core/ext/transport/chttp2/transport/incoming_metadata.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/transport/incoming_metadata.h"
 
 #include <string.h>
@@ -42,8 +44,8 @@
   buffer->size += GRPC_MDELEM_LENGTH(elem);
   return grpc_metadata_batch_add_tail(
       &buffer->batch,
-      (grpc_linked_mdelem*)gpr_arena_alloc(buffer->arena,
-                                           sizeof(grpc_linked_mdelem)),
+      static_cast<grpc_linked_mdelem*>(
+          gpr_arena_alloc(buffer->arena, sizeof(grpc_linked_mdelem))),
       elem);
 }
 
@@ -67,6 +69,5 @@
 
 void grpc_chttp2_incoming_metadata_buffer_publish(
     grpc_chttp2_incoming_metadata_buffer* buffer, grpc_metadata_batch* batch) {
-  *batch = buffer->batch;
-  grpc_metadata_batch_init(&buffer->batch);
+  grpc_metadata_batch_move(&buffer->batch, batch);
 }
diff --git a/src/core/ext/transport/chttp2/transport/incoming_metadata.h b/src/core/ext/transport/chttp2/transport/incoming_metadata.h
index b84cd48..d029cf0 100644
--- a/src/core/ext/transport/chttp2/transport/incoming_metadata.h
+++ b/src/core/ext/transport/chttp2/transport/incoming_metadata.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INCOMING_METADATA_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INCOMING_METADATA_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/transport/transport.h"
 
 typedef struct {
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index 6b6c0b2..ca6e715 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H
 
+#include <grpc/support/port_platform.h>
+
 #include <assert.h>
 #include <stdbool.h>
 
@@ -201,18 +203,58 @@
   struct grpc_chttp2_write_cb* next;
 } grpc_chttp2_write_cb;
 
-/* forward declared in frame_data.h */
-struct grpc_chttp2_incoming_byte_stream {
-  grpc_byte_stream base;
-  gpr_refcount refs;
+namespace grpc_core {
 
-  grpc_chttp2_transport* transport; /* immutable */
-  grpc_chttp2_stream* stream;       /* immutable */
+class Chttp2IncomingByteStream : public ByteStream {
+ public:
+  Chttp2IncomingByteStream(grpc_chttp2_transport* transport,
+                           grpc_chttp2_stream* stream, uint32_t frame_size,
+                           uint32_t flags);
+
+  void Orphan() override;
+
+  bool Next(size_t max_size_hint, grpc_closure* on_complete) override;
+  grpc_error* Pull(grpc_slice* slice) override;
+  void Shutdown(grpc_error* error) override;
+
+  // TODO(roth): When I converted this class to C++, I wanted to make it
+  // inherit from RefCounted or InternallyRefCounted instead of continuing
+  // to use its own custom ref-counting code.  However, that would require
+  // using multiple inheritence, which sucks in general.  And to make matters
+  // worse, it causes problems with our New<> and Delete<> wrappers.
+  // Specifically, unless RefCounted is first in the list of parent classes,
+  // it will see a different value of the address of the object than the one
+  // we actually allocated, in which case gpr_free() will be called on a
+  // different address than the one we got from gpr_malloc(), thus causing a
+  // crash.  Given the fragility of depending on that, as well as a desire to
+  // avoid multiple inheritence in general, I've decided to leave this
+  // alone for now.  We can revisit this once we're able to link against
+  // libc++, at which point we can eliminate New<> and Delete<> and
+  // switch to std::shared_ptr<>.
+  void Ref();
+  void Unref();
+
+  void PublishError(grpc_error* error);
+
+  grpc_error* Push(grpc_slice slice, grpc_slice* slice_out);
+
+  grpc_error* Finished(grpc_error* error, bool reset_on_error);
+
+  uint32_t remaining_bytes() const { return remaining_bytes_; }
+
+ private:
+  static void NextLocked(void* arg, grpc_error* error_ignored);
+  static void OrphanLocked(void* arg, grpc_error* error_ignored);
+
+  grpc_chttp2_transport* transport_;  // Immutable.
+  grpc_chttp2_stream* stream_;        // Immutable.
+
+  gpr_refcount refs_;
 
   /* Accessed only by transport thread when stream->pending_byte_stream == false
    * Accessed only by application thread when stream->pending_byte_stream ==
    * true */
-  uint32_t remaining_bytes;
+  uint32_t remaining_bytes_;
 
   /* Accessed only by transport thread when stream->pending_byte_stream == false
    * Accessed only by application thread when stream->pending_byte_stream ==
@@ -221,11 +263,12 @@
     grpc_closure closure;
     size_t max_size_hint;
     grpc_closure* on_complete;
-  } next_action;
-  grpc_closure destroy_action;
-  grpc_closure finished_action;
+  } next_action_;
+  grpc_closure destroy_action_;
 };
 
+}  // namespace grpc_core
+
 typedef enum {
   GRPC_CHTTP2_KEEPALIVE_STATE_WAITING,
   GRPC_CHTTP2_KEEPALIVE_STATE_PINGING,
@@ -454,7 +497,7 @@
   grpc_metadata_batch* send_trailing_metadata;
   grpc_closure* send_trailing_metadata_finished;
 
-  grpc_byte_stream* fetching_send_message;
+  grpc_core::OrphanablePtr<grpc_core::ByteStream> fetching_send_message;
   uint32_t fetched_send_message_length;
   grpc_slice fetching_slice;
   int64_t next_message_end_offset;
@@ -466,7 +509,7 @@
   grpc_metadata_batch* recv_initial_metadata;
   grpc_closure* recv_initial_metadata_ready;
   bool* trailing_metadata_available;
-  grpc_byte_stream** recv_message;
+  grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message;
   grpc_closure* recv_message_ready;
   grpc_metadata_batch* recv_trailing_metadata;
   grpc_closure* recv_trailing_metadata_finished;
@@ -507,6 +550,11 @@
   grpc_slice_buffer unprocessed_incoming_frames_buffer;
   grpc_closure* on_next;    /* protected by t combiner */
   bool pending_byte_stream; /* protected by t combiner */
+  // cached length of buffer to be used by the transport thread in cases where
+  // stream->pending_byte_stream == true. The value is saved before
+  // application threads are allowed to modify
+  // unprocessed_incoming_frames_buffer
+  size_t unprocessed_incoming_frames_buffer_cached_length;
   grpc_closure reset_byte_stream;
   grpc_error* byte_stream_error; /* protected by t combiner */
   bool received_last_frame;      /* protected by t combiner */
@@ -717,18 +765,6 @@
 void grpc_chttp2_ref_transport(grpc_chttp2_transport* t);
 #endif
 
-grpc_chttp2_incoming_byte_stream* grpc_chttp2_incoming_byte_stream_create(
-    grpc_chttp2_transport* t, grpc_chttp2_stream* s, uint32_t frame_size,
-    uint32_t flags);
-grpc_error* grpc_chttp2_incoming_byte_stream_push(
-    grpc_chttp2_incoming_byte_stream* bs, grpc_slice slice,
-    grpc_slice* slice_out);
-grpc_error* grpc_chttp2_incoming_byte_stream_finished(
-    grpc_chttp2_incoming_byte_stream* bs, grpc_error* error,
-    bool reset_on_error);
-void grpc_chttp2_incoming_byte_stream_notify(
-    grpc_chttp2_incoming_byte_stream* bs, grpc_error* error);
-
 void grpc_chttp2_ack_ping(grpc_chttp2_transport* t, uint64_t id);
 
 /** Add a new ping strike to ping_recv_state.ping_strikes. If
diff --git a/src/core/ext/transport/chttp2/transport/parsing.cc b/src/core/ext/transport/chttp2/transport/parsing.cc
index fb6d30b..a10c9ad 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.cc
+++ b/src/core/ext/transport/chttp2/transport/parsing.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/transport/internal.h"
 
 #include <string.h>
@@ -88,15 +90,16 @@
               "Connect string mismatch: expected '%c' (%d) got '%c' (%d) "
               "at byte %d",
               GRPC_CHTTP2_CLIENT_CONNECT_STRING[t->deframe_state],
-              (int)(uint8_t)GRPC_CHTTP2_CLIENT_CONNECT_STRING[t->deframe_state],
-              *cur, (int)*cur, t->deframe_state);
+              static_cast<int>(static_cast<uint8_t>(
+                  GRPC_CHTTP2_CLIENT_CONNECT_STRING[t->deframe_state])),
+              *cur, static_cast<int>(*cur), t->deframe_state);
           err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
           gpr_free(msg);
           return err;
         }
         ++cur;
-        t->deframe_state =
-            (grpc_chttp2_deframe_transport_state)(1 + (int)t->deframe_state);
+        t->deframe_state = static_cast<grpc_chttp2_deframe_transport_state>(
+            1 + static_cast<int>(t->deframe_state));
       }
       if (cur == end) {
         return GRPC_ERROR_NONE;
@@ -105,7 +108,7 @@
     dts_fh_0:
     case GRPC_DTS_FH_0:
       GPR_ASSERT(cur < end);
-      t->incoming_frame_size = ((uint32_t)*cur) << 16;
+      t->incoming_frame_size = (static_cast<uint32_t>(*cur)) << 16;
       if (++cur == end) {
         t->deframe_state = GRPC_DTS_FH_1;
         return GRPC_ERROR_NONE;
@@ -113,7 +116,7 @@
     /* fallthrough */
     case GRPC_DTS_FH_1:
       GPR_ASSERT(cur < end);
-      t->incoming_frame_size |= ((uint32_t)*cur) << 8;
+      t->incoming_frame_size |= (static_cast<uint32_t>(*cur)) << 8;
       if (++cur == end) {
         t->deframe_state = GRPC_DTS_FH_2;
         return GRPC_ERROR_NONE;
@@ -145,7 +148,7 @@
     /* fallthrough */
     case GRPC_DTS_FH_5:
       GPR_ASSERT(cur < end);
-      t->incoming_stream_id = (((uint32_t)*cur) & 0x7f) << 24;
+      t->incoming_stream_id = ((static_cast<uint32_t>(*cur)) & 0x7f) << 24;
       if (++cur == end) {
         t->deframe_state = GRPC_DTS_FH_6;
         return GRPC_ERROR_NONE;
@@ -153,7 +156,7 @@
     /* fallthrough */
     case GRPC_DTS_FH_6:
       GPR_ASSERT(cur < end);
-      t->incoming_stream_id |= ((uint32_t)*cur) << 16;
+      t->incoming_stream_id |= (static_cast<uint32_t>(*cur)) << 16;
       if (++cur == end) {
         t->deframe_state = GRPC_DTS_FH_7;
         return GRPC_ERROR_NONE;
@@ -161,7 +164,7 @@
     /* fallthrough */
     case GRPC_DTS_FH_7:
       GPR_ASSERT(cur < end);
-      t->incoming_stream_id |= ((uint32_t)*cur) << 8;
+      t->incoming_stream_id |= (static_cast<uint32_t>(*cur)) << 8;
       if (++cur == end) {
         t->deframe_state = GRPC_DTS_FH_8;
         return GRPC_ERROR_NONE;
@@ -169,7 +172,7 @@
     /* fallthrough */
     case GRPC_DTS_FH_8:
       GPR_ASSERT(cur < end);
-      t->incoming_stream_id |= ((uint32_t)*cur);
+      t->incoming_stream_id |= (static_cast<uint32_t>(*cur));
       t->deframe_state = GRPC_DTS_FRAME;
       err = init_frame_parser(t);
       if (err != GRPC_ERROR_NONE) {
@@ -205,20 +208,20 @@
     /* fallthrough */
     case GRPC_DTS_FRAME:
       GPR_ASSERT(cur < end);
-      if ((uint32_t)(end - cur) == t->incoming_frame_size) {
-        err =
-            parse_frame_slice(t,
-                              grpc_slice_sub_no_ref(slice, (size_t)(cur - beg),
-                                                    (size_t)(end - beg)),
-                              1);
+      if (static_cast<uint32_t>(end - cur) == t->incoming_frame_size) {
+        err = parse_frame_slice(
+            t,
+            grpc_slice_sub_no_ref(slice, static_cast<size_t>(cur - beg),
+                                  static_cast<size_t>(end - beg)),
+            1);
         if (err != GRPC_ERROR_NONE) {
           return err;
         }
         t->deframe_state = GRPC_DTS_FH_0;
         t->incoming_stream = nullptr;
         return GRPC_ERROR_NONE;
-      } else if ((uint32_t)(end - cur) > t->incoming_frame_size) {
-        size_t cur_offset = (size_t)(cur - beg);
+      } else if (static_cast<uint32_t>(end - cur) > t->incoming_frame_size) {
+        size_t cur_offset = static_cast<size_t>(cur - beg);
         err = parse_frame_slice(
             t,
             grpc_slice_sub_no_ref(slice, cur_offset,
@@ -231,15 +234,15 @@
         t->incoming_stream = nullptr;
         goto dts_fh_0; /* loop */
       } else {
-        err =
-            parse_frame_slice(t,
-                              grpc_slice_sub_no_ref(slice, (size_t)(cur - beg),
-                                                    (size_t)(end - beg)),
-                              0);
+        err = parse_frame_slice(
+            t,
+            grpc_slice_sub_no_ref(slice, static_cast<size_t>(cur - beg),
+                                  static_cast<size_t>(end - beg)),
+            0);
         if (err != GRPC_ERROR_NONE) {
           return err;
         }
-        t->incoming_frame_size -= (uint32_t)(end - cur);
+        t->incoming_frame_size -= static_cast<uint32_t>(end - cur);
         return GRPC_ERROR_NONE;
       }
       GPR_UNREACHABLE_CODE(return nullptr);
@@ -325,7 +328,7 @@
     t->hpack_parser.on_header = skip_header;
     t->hpack_parser.on_header_user_data = nullptr;
     t->hpack_parser.is_boundary = is_eoh;
-    t->hpack_parser.is_eof = (uint8_t)(is_eoh ? t->header_eof : 0);
+    t->hpack_parser.is_eof = static_cast<uint8_t>(is_eoh ? t->header_eof : 0);
   } else {
     t->parser = skip_parser;
   }
@@ -370,8 +373,6 @@
     /* t->parser = grpc_chttp2_data_parser_parse;*/
     t->parser = grpc_chttp2_data_parser_parse;
     t->parser_data = &s->data_parser;
-    t->ping_state.pings_before_data_required =
-        t->ping_policy.max_pings_without_data;
     t->ping_state.last_ping_sent_time = GRPC_MILLIS_INF_PAST;
     return GRPC_ERROR_NONE;
   } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, nullptr)) {
@@ -394,7 +395,7 @@
 static void on_initial_header(void* tp, grpc_mdelem md) {
   GPR_TIMER_SCOPE("on_initial_header", 0);
 
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)tp;
+  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   grpc_chttp2_stream* s = t->incoming_stream;
   GPR_ASSERT(s != nullptr);
 
@@ -429,7 +430,8 @@
       }
       if (GRPC_MDELEM_IS_INTERNED(md)) {
         /* store the result */
-        cached_timeout = (grpc_millis*)gpr_malloc(sizeof(grpc_millis));
+        cached_timeout =
+            static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis)));
         *cached_timeout = timeout;
         grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
       }
@@ -474,7 +476,7 @@
 static void on_trailing_header(void* tp, grpc_mdelem md) {
   GPR_TIMER_SCOPE("on_trailing_header", 0);
 
-  grpc_chttp2_transport* t = (grpc_chttp2_transport*)tp;
+  grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
   grpc_chttp2_stream* s = t->incoming_stream;
   GPR_ASSERT(s != nullptr);
 
@@ -543,8 +545,6 @@
         (t->incoming_frame_flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) != 0;
   }
 
-  t->ping_state.pings_before_data_required =
-      t->ping_policy.max_pings_without_data;
   t->ping_state.last_ping_sent_time = GRPC_MILLIS_INF_PAST;
 
   /* could be a new grpc_chttp2_stream or an existing grpc_chttp2_stream */
@@ -634,7 +634,7 @@
   }
   t->hpack_parser.on_header_user_data = t;
   t->hpack_parser.is_boundary = is_eoh;
-  t->hpack_parser.is_eof = (uint8_t)(is_eoh ? t->header_eof : 0);
+  t->hpack_parser.is_eof = static_cast<uint8_t>(is_eoh ? t->header_eof : 0);
   if (!is_continuation &&
       (t->incoming_frame_flags & GRPC_CHTTP2_FLAG_HAS_PRIORITY)) {
     grpc_chttp2_hpack_parser_set_has_priority(&t->hpack_parser);
diff --git a/src/core/ext/transport/chttp2/transport/stream_lists.cc b/src/core/ext/transport/chttp2/transport/stream_lists.cc
index 3aad8c5..5d3ec4b 100644
--- a/src/core/ext/transport/chttp2/transport/stream_lists.cc
+++ b/src/core/ext/transport/chttp2/transport/stream_lists.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/ext/transport/chttp2/transport/internal.h"
 
diff --git a/src/core/ext/transport/chttp2/transport/stream_map.cc b/src/core/ext/transport/chttp2/transport/stream_map.cc
index e4f08f5..f300e23 100644
--- a/src/core/ext/transport/chttp2/transport/stream_map.cc
+++ b/src/core/ext/transport/chttp2/transport/stream_map.cc
@@ -16,19 +16,22 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/transport/stream_map.h"
 
 #include <string.h>
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
 
 void grpc_chttp2_stream_map_init(grpc_chttp2_stream_map* map,
                                  size_t initial_capacity) {
   GPR_ASSERT(initial_capacity > 1);
-  map->keys = (uint32_t*)gpr_malloc(sizeof(uint32_t) * initial_capacity);
-  map->values = (void**)gpr_malloc(sizeof(void*) * initial_capacity);
+  map->keys =
+      static_cast<uint32_t*>(gpr_malloc(sizeof(uint32_t) * initial_capacity));
+  map->values =
+      static_cast<void**>(gpr_malloc(sizeof(void*) * initial_capacity));
   map->count = 0;
   map->free = 0;
   map->capacity = initial_capacity;
@@ -72,10 +75,10 @@
       /* resize when less than 25% of the table is free, because compaction
          won't help much */
       map->capacity = capacity = 3 * capacity / 2;
-      map->keys = keys =
-          (uint32_t*)gpr_realloc(keys, capacity * sizeof(uint32_t));
+      map->keys = keys = static_cast<uint32_t*>(
+          gpr_realloc(keys, capacity * sizeof(uint32_t)));
       map->values = values =
-          (void**)gpr_realloc(values, capacity * sizeof(void*));
+          static_cast<void**>(gpr_realloc(values, capacity * sizeof(void*)));
     }
   }
 
@@ -147,7 +150,7 @@
     map->free = 0;
     GPR_ASSERT(map->count > 0);
   }
-  return map->values[((size_t)rand()) % map->count];
+  return map->values[(static_cast<size_t>(rand())) % map->count];
 }
 
 void grpc_chttp2_stream_map_for_each(grpc_chttp2_stream_map* map,
diff --git a/src/core/ext/transport/chttp2/transport/varint.cc b/src/core/ext/transport/chttp2/transport/varint.cc
index 0d94ddc..d4b0178 100644
--- a/src/core/ext/transport/chttp2/transport/varint.cc
+++ b/src/core/ext/transport/chttp2/transport/varint.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/transport/varint.h"
 
 uint32_t grpc_chttp2_hpack_varint_length(uint32_t tail_value) {
@@ -36,19 +38,19 @@
                                          uint32_t tail_length) {
   switch (tail_length) {
     case 5:
-      target[4] = (uint8_t)((tail_value >> 28) | 0x80);
+      target[4] = static_cast<uint8_t>((tail_value >> 28) | 0x80);
     /* fallthrough */
     case 4:
-      target[3] = (uint8_t)((tail_value >> 21) | 0x80);
+      target[3] = static_cast<uint8_t>((tail_value >> 21) | 0x80);
     /* fallthrough */
     case 3:
-      target[2] = (uint8_t)((tail_value >> 14) | 0x80);
+      target[2] = static_cast<uint8_t>((tail_value >> 14) | 0x80);
     /* fallthrough */
     case 2:
-      target[1] = (uint8_t)((tail_value >> 7) | 0x80);
+      target[1] = static_cast<uint8_t>((tail_value >> 7) | 0x80);
     /* fallthrough */
     case 1:
-      target[0] = (uint8_t)((tail_value) | 0x80);
+      target[0] = static_cast<uint8_t>((tail_value) | 0x80);
   }
   target[tail_length - 1] &= 0x7f;
 }
diff --git a/src/core/ext/transport/chttp2/transport/writing.cc b/src/core/ext/transport/chttp2/transport/writing.cc
index 95358ab..6f32397 100644
--- a/src/core/ext/transport/chttp2/transport/writing.cc
+++ b/src/core/ext/transport/chttp2/transport/writing.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/chttp2/transport/internal.h"
 
 #include <limits.h>
@@ -83,11 +85,12 @@
               "%s: Ping delayed [%p]: not enough time elapsed since last ping. "
               " Last ping %f: Next ping %f: Now %f",
               t->is_client ? "CLIENT" : "SERVER", t->peer_string,
-              (double)t->ping_state.last_ping_sent_time,
-              (double)next_allowed_ping, (double)now);
+              static_cast<double>(t->ping_state.last_ping_sent_time),
+              static_cast<double>(next_allowed_ping), static_cast<double>(now));
     }
     if (!t->ping_state.is_delayed_ping_timer_set) {
       t->ping_state.is_delayed_ping_timer_set = true;
+      GRPC_CHTTP2_REF_TRANSPORT(t, "retry_initiate_ping_locked");
       grpc_timer_init(&t->ping_state.delayed_ping_timer, next_allowed_ping,
                       &t->retry_initiate_ping_locked);
     }
@@ -146,7 +149,7 @@
       t->settings[GRPC_ACKED_SETTINGS]
                  [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
       t->flow_control->remote_window(),
-      (uint32_t)GPR_MAX(
+      static_cast<uint32_t> GPR_MAX(
           0,
           s->flow_control->remote_window_delta() +
               (int64_t)t->settings[GRPC_PEER_SETTINGS]
@@ -221,7 +224,7 @@
       grpc_slice_buffer_add(
           &t_->outbuf, grpc_chttp2_window_update_create(0, transport_announce,
                                                         &throwaway_stats));
-      ResetPingRecvClock();
+      ResetPingClock();
     }
   }
 
@@ -266,11 +269,13 @@
     return s;
   }
 
-  void ResetPingRecvClock() {
+  void ResetPingClock() {
     if (!t_->is_client) {
       t_->ping_recv_state.last_ping_recv_time = GRPC_MILLIS_INF_PAST;
       t_->ping_recv_state.ping_strikes = 0;
     }
+    t_->ping_state.pings_before_data_required =
+        t_->ping_policy.max_pings_without_data;
   }
 
   void IncInitialMetadataWrites() { ++initial_metadata_writes_; }
@@ -309,14 +314,14 @@
         sending_bytes_before_(s_->sending_bytes) {}
 
   uint32_t stream_remote_window() const {
-    return (uint32_t)GPR_MAX(
+    return static_cast<uint32_t> GPR_MAX(
         0, s_->flow_control->remote_window_delta() +
                (int64_t)t_->settings[GRPC_PEER_SETTINGS]
                                     [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]);
   }
 
   uint32_t max_outgoing() const {
-    return (uint32_t)GPR_MIN(
+    return static_cast<uint32_t> GPR_MIN(
         t_->settings[GRPC_PEER_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE],
         GPR_MIN(stream_remote_window(), t_->flow_control->remote_window()));
   }
@@ -324,8 +329,8 @@
   bool AnyOutgoing() const { return max_outgoing() > 0; }
 
   void FlushCompressedBytes() {
-    uint32_t send_bytes =
-        (uint32_t)GPR_MIN(max_outgoing(), s_->compressed_data_buffer.length);
+    uint32_t send_bytes = static_cast<uint32_t> GPR_MIN(
+        max_outgoing(), s_->compressed_data_buffer.length);
     bool is_last_data_frame =
         (send_bytes == s_->compressed_data_buffer.length &&
          s_->flow_controlled_buffer.length == 0 &&
@@ -374,10 +379,11 @@
   bool is_last_frame() const { return is_last_frame_; }
 
   void CallCallbacks() {
-    if (update_list(t_, s_,
-                    (int64_t)(s_->sending_bytes - sending_bytes_before_),
-                    &s_->on_flow_controlled_cbs,
-                    &s_->flow_controlled_bytes_flowed, GRPC_ERROR_NONE)) {
+    if (update_list(
+            t_, s_,
+            static_cast<int64_t>(s_->sending_bytes - sending_bytes_before_),
+            &s_->on_flow_controlled_cbs, &s_->flow_controlled_bytes_flowed,
+            GRPC_ERROR_NONE)) {
       write_context_->NoteScheduledResults();
     }
   }
@@ -431,7 +437,7 @@
       };
       grpc_chttp2_encode_header(&t_->hpack_compressor, nullptr, 0,
                                 s_->send_initial_metadata, &hopt, &t_->outbuf);
-      write_context_->ResetPingRecvClock();
+      write_context_->ResetPingClock();
       write_context_->IncInitialMetadataWrites();
     }
 
@@ -451,7 +457,7 @@
     grpc_slice_buffer_add(
         &t_->outbuf, grpc_chttp2_window_update_create(s_->id, stream_announce,
                                                       &s_->stats.outgoing));
-    write_context_->ResetPingRecvClock();
+    write_context_->ResetPingClock();
     write_context_->IncWindowUpdateWrites();
   }
 
@@ -485,7 +491,7 @@
         data_send_context.CompressMoreBytes();
       }
     }
-    write_context_->ResetPingRecvClock();
+    write_context_->ResetPingClock();
     if (data_send_context.is_last_frame()) {
       SentLastFrame();
     }
@@ -526,7 +532,7 @@
                                 s_->send_trailing_metadata, &hopt, &t_->outbuf);
     }
     write_context_->IncTrailingMetadataWrites();
-    write_context_->ResetPingRecvClock();
+    write_context_->ResetPingClock();
     SentLastFrame();
 
     write_context_->NoteScheduledResults();
@@ -623,8 +629,9 @@
 
   while (grpc_chttp2_list_pop_writing_stream(t, &s)) {
     if (s->sending_bytes != 0) {
-      update_list(t, s, (int64_t)s->sending_bytes, &s->on_write_finished_cbs,
-                  &s->flow_controlled_bytes_written, GRPC_ERROR_REF(error));
+      update_list(t, s, static_cast<int64_t>(s->sending_bytes),
+                  &s->on_write_finished_cbs, &s->flow_controlled_bytes_written,
+                  GRPC_ERROR_REF(error));
       s->sending_bytes = 0;
     }
     GRPC_CHTTP2_STREAM_UNREF(s, "chttp2_writing:end");
diff --git a/src/core/ext/transport/cronet/transport/cronet_api_dummy.cc b/src/core/ext/transport/cronet/transport/cronet_api_dummy.cc
index 578cbb8..1a6bded 100644
--- a/src/core/ext/transport/cronet/transport/cronet_api_dummy.cc
+++ b/src/core/ext/transport/cronet/transport/cronet_api_dummy.cc
@@ -19,6 +19,8 @@
 /* This file has empty implementation of all the functions exposed by the cronet
 library, so we can build it in all environments */
 
+#include <grpc/support/port_platform.h>
+
 #include <stdbool.h>
 
 #include <grpc/support/log.h>
diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.cc b/src/core/ext/transport/cronet/transport/cronet_transport.cc
index 5b1c6ab..8e3ea05 100644
--- a/src/core/ext/transport/cronet/transport/cronet_transport.cc
+++ b/src/core/ext/transport/cronet/transport/cronet_transport.cc
@@ -16,19 +16,22 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <string.h>
 
-#include <grpc/impl/codegen/port_platform.h>
 #include <grpc/slice_buffer.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 
+#include "src/core/ext/transport/chttp2/transport/bin_decoder.h"
+#include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
 #include "src/core/ext/transport/chttp2/transport/incoming_metadata.h"
 #include "src/core/ext/transport/cronet/transport/cronet_transport.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/manual_constructor.h"
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/slice/slice_internal.h"
@@ -120,7 +123,7 @@
   bool read_stream_closed;
 
   /* vars for holding data destined for the application */
-  struct grpc_slice_buffer_stream sbs;
+  grpc_core::ManualConstructor<grpc_core::SliceBufferByteStream> sbs;
   grpc_slice_buffer read_slice_buffer;
 
   /* vars for trailing metadata */
@@ -285,7 +288,8 @@
       CRONET_LOG(GPR_DEBUG, "%p: Flush read", s);
       s->state.flush_read = true;
       null_and_maybe_free_read_buffer(s);
-      s->state.rs.read_buffer = (char*)gpr_malloc(GRPC_FLUSH_READ_SIZE);
+      s->state.rs.read_buffer =
+          static_cast<char*>(gpr_malloc(GRPC_FLUSH_READ_SIZE));
       if (!s->state.pending_read_from_cronet) {
         CRONET_LOG(GPR_DEBUG, "bidirectional_stream_read(%p)", s->cbs);
         bidirectional_stream_read(s->cbs, s->state.rs.read_buffer,
@@ -310,8 +314,8 @@
   struct op_storage* storage = &s->storage;
   /* add new op at the beginning of the linked list. The memory is freed
   in remove_from_storage */
-  struct op_and_state* new_op =
-      (struct op_and_state*)gpr_malloc(sizeof(struct op_and_state));
+  struct op_and_state* new_op = static_cast<struct op_and_state*>(
+      gpr_malloc(sizeof(struct op_and_state)));
   memcpy(&new_op->op, op, sizeof(grpc_transport_stream_op_batch));
   memset(&new_op->state, 0, sizeof(new_op->state));
   new_op->s = s;
@@ -393,6 +397,29 @@
   gpr_mu_unlock(&s->mu);
 }
 
+static void convert_cronet_array_to_metadata(
+    const bidirectional_stream_header_array* header_array,
+    grpc_chttp2_incoming_metadata_buffer* mds) {
+  for (size_t i = 0; i < header_array->count; i++) {
+    CRONET_LOG(GPR_DEBUG, "header key=%s, value=%s",
+               header_array->headers[i].key, header_array->headers[i].value);
+    grpc_slice key = grpc_slice_intern(
+        grpc_slice_from_static_string(header_array->headers[i].key));
+    grpc_slice value;
+    if (grpc_is_binary_header(key)) {
+      value = grpc_slice_from_static_string(header_array->headers[i].value);
+      value = grpc_slice_intern(grpc_chttp2_base64_decode_with_length(
+          value, grpc_chttp2_base64_infer_length_after_decode(value)));
+    } else {
+      value = grpc_slice_intern(
+          grpc_slice_from_static_string(header_array->headers[i].value));
+    }
+    GRPC_LOG_IF_ERROR("convert_cronet_array_to_metadata",
+                      grpc_chttp2_incoming_metadata_buffer_add(
+                          mds, grpc_mdelem_from_slices(key, value)));
+  }
+}
+
 /*
   Cronet callback
 */
@@ -400,7 +427,7 @@
   gpr_log(GPR_ERROR, "on_failed(%p, %d)", stream, net_error);
   grpc_core::ExecCtx exec_ctx;
 
-  stream_obj* s = (stream_obj*)stream->annotation;
+  stream_obj* s = static_cast<stream_obj*>(stream->annotation);
   gpr_mu_lock(&s->mu);
   bidirectional_stream_destroy(s->cbs);
   s->state.state_callback_received[OP_FAILED] = true;
@@ -426,7 +453,7 @@
   CRONET_LOG(GPR_DEBUG, "on_canceled(%p)", stream);
   grpc_core::ExecCtx exec_ctx;
 
-  stream_obj* s = (stream_obj*)stream->annotation;
+  stream_obj* s = static_cast<stream_obj*>(stream->annotation);
   gpr_mu_lock(&s->mu);
   bidirectional_stream_destroy(s->cbs);
   s->state.state_callback_received[OP_CANCELED] = true;
@@ -452,7 +479,7 @@
   CRONET_LOG(GPR_DEBUG, "on_succeeded(%p)", stream);
   grpc_core::ExecCtx exec_ctx;
 
-  stream_obj* s = (stream_obj*)stream->annotation;
+  stream_obj* s = static_cast<stream_obj*>(stream->annotation);
   gpr_mu_lock(&s->mu);
   bidirectional_stream_destroy(s->cbs);
   s->state.state_callback_received[OP_SUCCEEDED] = true;
@@ -469,8 +496,8 @@
 static void on_stream_ready(bidirectional_stream* stream) {
   CRONET_LOG(GPR_DEBUG, "W: on_stream_ready(%p)", stream);
   grpc_core::ExecCtx exec_ctx;
-  stream_obj* s = (stream_obj*)stream->annotation;
-  grpc_cronet_transport* t = (grpc_cronet_transport*)s->curr_ct;
+  stream_obj* s = static_cast<stream_obj*>(stream->annotation);
+  grpc_cronet_transport* t = s->curr_ct;
   gpr_mu_lock(&s->mu);
   s->state.state_op_done[OP_SEND_INITIAL_METADATA] = true;
   s->state.state_callback_received[OP_SEND_INITIAL_METADATA] = true;
@@ -501,7 +528,7 @@
   grpc_core::ExecCtx exec_ctx;
   CRONET_LOG(GPR_DEBUG, "R: on_response_headers_received(%p, %p, %s)", stream,
              headers, negotiated_protocol);
-  stream_obj* s = (stream_obj*)stream->annotation;
+  stream_obj* s = static_cast<stream_obj*>(stream->annotation);
 
   /* Identify if this is a header or a trailer (in a trailer-only response case)
    */
@@ -517,16 +544,7 @@
          sizeof(s->state.rs.initial_metadata));
   grpc_chttp2_incoming_metadata_buffer_init(&s->state.rs.initial_metadata,
                                             s->arena);
-  for (size_t i = 0; i < headers->count; i++) {
-    GRPC_LOG_IF_ERROR("on_response_headers_received",
-                      grpc_chttp2_incoming_metadata_buffer_add(
-                          &s->state.rs.initial_metadata,
-                          grpc_mdelem_from_slices(
-                              grpc_slice_intern(grpc_slice_from_static_string(
-                                  headers->headers[i].key)),
-                              grpc_slice_intern(grpc_slice_from_static_string(
-                                  headers->headers[i].value)))));
-  }
+  convert_cronet_array_to_metadata(headers, &s->state.rs.initial_metadata);
   s->state.state_callback_received[OP_RECV_INITIAL_METADATA] = true;
   if (!(s->state.state_op_done[OP_CANCEL_ERROR] ||
         s->state.state_callback_received[OP_FAILED])) {
@@ -551,7 +569,7 @@
 */
 static void on_write_completed(bidirectional_stream* stream, const char* data) {
   grpc_core::ExecCtx exec_ctx;
-  stream_obj* s = (stream_obj*)stream->annotation;
+  stream_obj* s = static_cast<stream_obj*>(stream->annotation);
   CRONET_LOG(GPR_DEBUG, "W: on_write_completed(%p, %s)", stream, data);
   gpr_mu_lock(&s->mu);
   if (s->state.ws.write_buffer) {
@@ -569,7 +587,7 @@
 static void on_read_completed(bidirectional_stream* stream, char* data,
                               int count) {
   grpc_core::ExecCtx exec_ctx;
-  stream_obj* s = (stream_obj*)stream->annotation;
+  stream_obj* s = static_cast<stream_obj*>(stream->annotation);
   CRONET_LOG(GPR_DEBUG, "R: on_read_completed(%p, %p, %d)", stream, data,
              count);
   gpr_mu_lock(&s->mu);
@@ -613,26 +631,19 @@
   grpc_core::ExecCtx exec_ctx;
   CRONET_LOG(GPR_DEBUG, "R: on_response_trailers_received(%p,%p)", stream,
              trailers);
-  stream_obj* s = (stream_obj*)stream->annotation;
-  grpc_cronet_transport* t = (grpc_cronet_transport*)s->curr_ct;
+  stream_obj* s = static_cast<stream_obj*>(stream->annotation);
+  grpc_cronet_transport* t = s->curr_ct;
   gpr_mu_lock(&s->mu);
   memset(&s->state.rs.trailing_metadata, 0,
          sizeof(s->state.rs.trailing_metadata));
   s->state.rs.trailing_metadata_valid = false;
   grpc_chttp2_incoming_metadata_buffer_init(&s->state.rs.trailing_metadata,
                                             s->arena);
-  for (size_t i = 0; i < trailers->count; i++) {
-    CRONET_LOG(GPR_DEBUG, "trailer key=%s, value=%s", trailers->headers[i].key,
-               trailers->headers[i].value);
-    GRPC_LOG_IF_ERROR("on_response_trailers_received",
-                      grpc_chttp2_incoming_metadata_buffer_add(
-                          &s->state.rs.trailing_metadata,
-                          grpc_mdelem_from_slices(
-                              grpc_slice_intern(grpc_slice_from_static_string(
-                                  trailers->headers[i].key)),
-                              grpc_slice_intern(grpc_slice_from_static_string(
-                                  trailers->headers[i].value)))));
+  convert_cronet_array_to_metadata(trailers, &s->state.rs.trailing_metadata);
+  if (trailers->count > 0) {
     s->state.rs.trailing_metadata_valid = true;
+  }
+  for (size_t i = 0; i < trailers->count; i++) {
     if (0 == strcmp(trailers->headers[i].key, "grpc-status") &&
         0 != strcmp(trailers->headers[i].value, "0")) {
       s->state.fail_state = true;
@@ -672,17 +683,18 @@
   size_t length = GRPC_SLICE_LENGTH(slice);
   *p_write_buffer_size = length + GRPC_HEADER_SIZE_IN_BYTES;
   /* This is freed in the on_write_completed callback */
-  char* write_buffer = (char*)gpr_malloc(length + GRPC_HEADER_SIZE_IN_BYTES);
+  char* write_buffer =
+      static_cast<char*>(gpr_malloc(length + GRPC_HEADER_SIZE_IN_BYTES));
   *pp_write_buffer = write_buffer;
-  uint8_t* p = (uint8_t*)write_buffer;
+  uint8_t* p = reinterpret_cast<uint8_t*>(write_buffer);
   /* Append 5 byte header */
   /* Compressed flag */
-  *p++ = (uint8_t)((flags & GRPC_WRITE_INTERNAL_COMPRESS) ? 1 : 0);
+  *p++ = static_cast<uint8_t>((flags & GRPC_WRITE_INTERNAL_COMPRESS) ? 1 : 0);
   /* Message length */
-  *p++ = (uint8_t)(length >> 24);
-  *p++ = (uint8_t)(length >> 16);
-  *p++ = (uint8_t)(length >> 8);
-  *p++ = (uint8_t)(length);
+  *p++ = static_cast<uint8_t>(length >> 24);
+  *p++ = static_cast<uint8_t>(length >> 16);
+  *p++ = static_cast<uint8_t>(length >> 8);
+  *p++ = static_cast<uint8_t>(length);
   /* append actual data */
   memcpy(p, GRPC_SLICE_START_PTR(slice), length);
   grpc_slice_unref_internal(slice);
@@ -705,8 +717,8 @@
   /* Allocate enough memory. It is freed in the on_stream_ready callback
    */
   bidirectional_stream_header* headers =
-      (bidirectional_stream_header*)gpr_malloc(
-          sizeof(bidirectional_stream_header) * num_headers_available);
+      static_cast<bidirectional_stream_header*>(gpr_malloc(
+          sizeof(bidirectional_stream_header) * num_headers_available));
   *pp_headers = headers;
 
   /* Walk the linked list again, this time copying the header fields.
@@ -720,7 +732,14 @@
     grpc_mdelem mdelem = curr->md;
     curr = curr->next;
     char* key = grpc_slice_to_c_string(GRPC_MDKEY(mdelem));
-    char* value = grpc_slice_to_c_string(GRPC_MDVALUE(mdelem));
+    char* value;
+    if (grpc_is_binary_header(GRPC_MDKEY(mdelem))) {
+      grpc_slice wire_value = grpc_chttp2_base64_encode(GRPC_MDVALUE(mdelem));
+      value = grpc_slice_to_c_string(wire_value);
+      grpc_slice_unref(wire_value);
+    } else {
+      value = grpc_slice_to_c_string(GRPC_MDVALUE(mdelem));
+    }
     if (grpc_slice_eq(GRPC_MDKEY(mdelem), GRPC_MDSTR_SCHEME) ||
         grpc_slice_eq(GRPC_MDKEY(mdelem), GRPC_MDSTR_AUTHORITY)) {
       /* Cronet populates these fields on its own */
@@ -754,7 +773,7 @@
       break;
     }
   }
-  *p_num_headers = (size_t)num_headers;
+  *p_num_headers = num_headers;
 }
 
 static void parse_grpc_header(const uint8_t* data, int* length,
@@ -763,10 +782,10 @@
   const uint8_t* p = data + 1;
   *compressed = ((c & 0x01) == 0x01);
   *length = 0;
-  *length |= ((uint8_t)*p++) << 24;
-  *length |= ((uint8_t)*p++) << 16;
-  *length |= ((uint8_t)*p++) << 8;
-  *length |= ((uint8_t)*p++);
+  *length |= (*p++) << 24;
+  *length |= (*p++) << 16;
+  *length |= (*p++) << 8;
+  *length |= (*p++);
 }
 
 static bool header_has_authority(grpc_linked_mdelem* head) {
@@ -969,7 +988,7 @@
 static enum e_op_result execute_stream_op(struct op_and_state* oas) {
   grpc_transport_stream_op_batch* stream_op = &oas->op;
   struct stream_obj* s = oas->s;
-  grpc_cronet_transport* t = (grpc_cronet_transport*)s->curr_ct;
+  grpc_cronet_transport* t = s->curr_ct;
   struct op_state* stream_state = &s->state;
   enum e_op_result result = NO_ACTION_POSSIBLE;
   if (stream_op->send_initial_metadata &&
@@ -1023,16 +1042,14 @@
       grpc_slice_buffer write_slice_buffer;
       grpc_slice slice;
       grpc_slice_buffer_init(&write_slice_buffer);
-      if (1 != grpc_byte_stream_next(
-                   stream_op->payload->send_message.send_message,
-                   stream_op->payload->send_message.send_message->length,
+      if (1 != stream_op->payload->send_message.send_message->Next(
+                   stream_op->payload->send_message.send_message->length(),
                    nullptr)) {
         /* Should never reach here */
         GPR_ASSERT(false);
       }
       if (GRPC_ERROR_NONE !=
-          grpc_byte_stream_pull(stream_op->payload->send_message.send_message,
-                                &slice)) {
+          stream_op->payload->send_message.send_message->Pull(&slice)) {
         /* Should never reach here */
         GPR_ASSERT(false);
       }
@@ -1044,14 +1061,15 @@
       }
       if (write_slice_buffer.count > 0) {
         size_t write_buffer_size;
-        create_grpc_frame(&write_slice_buffer, &stream_state->ws.write_buffer,
-                          &write_buffer_size,
-                          stream_op->payload->send_message.send_message->flags);
+        create_grpc_frame(
+            &write_slice_buffer, &stream_state->ws.write_buffer,
+            &write_buffer_size,
+            stream_op->payload->send_message.send_message->flags());
         CRONET_LOG(GPR_DEBUG, "bidirectional_stream_write (%p, %p)", s->cbs,
                    stream_state->ws.write_buffer);
         stream_state->state_callback_received[OP_SEND_MESSAGE] = false;
         bidirectional_stream_write(s->cbs, stream_state->ws.write_buffer,
-                                   (int)write_buffer_size, false);
+                                   static_cast<int>(write_buffer_size), false);
         grpc_slice_buffer_destroy_internal(&write_slice_buffer);
         if (t->use_packet_coalescing) {
           if (!stream_op->send_trailing_metadata) {
@@ -1071,6 +1089,7 @@
     }
     stream_state->state_op_done[OP_SEND_MESSAGE] = true;
     oas->state.state_op_done[OP_SEND_MESSAGE] = true;
+    stream_op->payload->send_message.send_message.reset();
   } else if (stream_op->send_trailing_metadata &&
              op_can_be_run(stream_op, s, &oas->state,
                            OP_SEND_TRAILING_METADATA)) {
@@ -1152,14 +1171,14 @@
           stream_state->rs.remaining_bytes == 0) {
         /* Start a read operation for data */
         stream_state->rs.length_field_received = true;
-        parse_grpc_header((const uint8_t*)stream_state->rs.read_buffer,
-                          &stream_state->rs.length_field,
-                          &stream_state->rs.compressed);
+        parse_grpc_header(
+            reinterpret_cast<const uint8_t*>(stream_state->rs.read_buffer),
+            &stream_state->rs.length_field, &stream_state->rs.compressed);
         CRONET_LOG(GPR_DEBUG, "length field = %d",
                    stream_state->rs.length_field);
         if (stream_state->rs.length_field > 0) {
-          stream_state->rs.read_buffer =
-              (char*)gpr_malloc((size_t)stream_state->rs.length_field);
+          stream_state->rs.read_buffer = static_cast<char*>(
+              gpr_malloc(static_cast<size_t>(stream_state->rs.length_field)));
           GPR_ASSERT(stream_state->rs.read_buffer);
           stream_state->rs.remaining_bytes = stream_state->rs.length_field;
           stream_state->rs.received_bytes = 0;
@@ -1177,13 +1196,13 @@
           grpc_slice_buffer_destroy_internal(
               &stream_state->rs.read_slice_buffer);
           grpc_slice_buffer_init(&stream_state->rs.read_slice_buffer);
-          grpc_slice_buffer_stream_init(&stream_state->rs.sbs,
-                                        &stream_state->rs.read_slice_buffer, 0);
+          uint32_t flags = 0;
           if (stream_state->rs.compressed) {
-            stream_state->rs.sbs.base.flags |= GRPC_WRITE_INTERNAL_COMPRESS;
+            flags |= GRPC_WRITE_INTERNAL_COMPRESS;
           }
-          *((grpc_byte_buffer**)stream_op->payload->recv_message.recv_message) =
-              (grpc_byte_buffer*)&stream_state->rs.sbs;
+          stream_state->rs.sbs.Init(&stream_state->rs.read_slice_buffer, flags);
+          stream_op->payload->recv_message.recv_message->reset(
+              stream_state->rs.sbs.get());
           GRPC_CLOSURE_SCHED(
               stream_op->payload->recv_message.recv_message_ready,
               GRPC_ERROR_NONE);
@@ -1226,20 +1245,20 @@
           GRPC_SLICE_MALLOC((uint32_t)stream_state->rs.length_field);
       uint8_t* dst_p = GRPC_SLICE_START_PTR(read_data_slice);
       memcpy(dst_p, stream_state->rs.read_buffer,
-             (size_t)stream_state->rs.length_field);
+             static_cast<size_t>(stream_state->rs.length_field));
       null_and_maybe_free_read_buffer(s);
       /* Clean up read_slice_buffer in case there is unread data. */
       grpc_slice_buffer_destroy_internal(&stream_state->rs.read_slice_buffer);
       grpc_slice_buffer_init(&stream_state->rs.read_slice_buffer);
       grpc_slice_buffer_add(&stream_state->rs.read_slice_buffer,
                             read_data_slice);
-      grpc_slice_buffer_stream_init(&stream_state->rs.sbs,
-                                    &stream_state->rs.read_slice_buffer, 0);
+      uint32_t flags = 0;
       if (stream_state->rs.compressed) {
-        stream_state->rs.sbs.base.flags = GRPC_WRITE_INTERNAL_COMPRESS;
+        flags = GRPC_WRITE_INTERNAL_COMPRESS;
       }
-      *((grpc_byte_buffer**)stream_op->payload->recv_message.recv_message) =
-          (grpc_byte_buffer*)&stream_state->rs.sbs;
+      stream_state->rs.sbs.Init(&stream_state->rs.read_slice_buffer, flags);
+      stream_op->payload->recv_message.recv_message->reset(
+          stream_state->rs.sbs.get());
       GRPC_CLOSURE_SCHED(stream_op->payload->recv_message.recv_message_ready,
                          GRPC_ERROR_NONE);
       stream_state->state_op_done[OP_RECV_MESSAGE] = true;
@@ -1326,7 +1345,7 @@
 static int init_stream(grpc_transport* gt, grpc_stream* gs,
                        grpc_stream_refcount* refcount, const void* server_data,
                        gpr_arena* arena) {
-  stream_obj* s = (stream_obj*)gs;
+  stream_obj* s = reinterpret_cast<stream_obj*>(gs);
 
   s->refcount = refcount;
   GRPC_CRONET_STREAM_REF(s, "cronet transport");
@@ -1349,7 +1368,7 @@
   s->state.pending_read_from_cronet = false;
 
   s->curr_gs = gs;
-  s->curr_ct = (grpc_cronet_transport*)gt;
+  s->curr_ct = reinterpret_cast<grpc_cronet_transport*>(gt);
   s->arena = arena;
 
   gpr_mu_init(&s->mu);
@@ -1382,14 +1401,14 @@
     GRPC_CLOSURE_SCHED(op->on_complete, GRPC_ERROR_CANCELLED);
     return;
   }
-  stream_obj* s = (stream_obj*)gs;
+  stream_obj* s = reinterpret_cast<stream_obj*>(gs);
   add_to_storage(s, op);
   execute_from_storage(s);
 }
 
 static void destroy_stream(grpc_transport* gt, grpc_stream* gs,
                            grpc_closure* then_schedule_closure) {
-  stream_obj* s = (stream_obj*)gs;
+  stream_obj* s = reinterpret_cast<stream_obj*>(gs);
   null_and_maybe_free_read_buffer(s);
   /* Clean up read_slice_buffer in case there is unread data. */
   grpc_slice_buffer_destroy_internal(&s->state.rs.read_slice_buffer);
@@ -1418,14 +1437,14 @@
 grpc_transport* grpc_create_cronet_transport(void* engine, const char* target,
                                              const grpc_channel_args* args,
                                              void* reserved) {
-  grpc_cronet_transport* ct =
-      (grpc_cronet_transport*)gpr_malloc(sizeof(grpc_cronet_transport));
+  grpc_cronet_transport* ct = static_cast<grpc_cronet_transport*>(
+      gpr_malloc(sizeof(grpc_cronet_transport)));
   if (!ct) {
     goto error;
   }
   ct->base.vtable = &grpc_cronet_vtable;
-  ct->engine = (stream_engine*)engine;
-  ct->host = (char*)gpr_malloc(strlen(target) + 1);
+  ct->engine = static_cast<stream_engine*>(engine);
+  ct->host = static_cast<char*>(gpr_malloc(strlen(target) + 1));
   if (!ct->host) {
     goto error;
   }
diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.h b/src/core/ext/transport/cronet/transport/cronet_transport.h
index d9ff913..fb7e149 100644
--- a/src/core/ext/transport/cronet/transport/cronet_transport.h
+++ b/src/core/ext/transport/cronet/transport/cronet_transport.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CRONET_TRANSPORT_CRONET_TRANSPORT_H
 #define GRPC_CORE_EXT_TRANSPORT_CRONET_TRANSPORT_CRONET_TRANSPORT_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/transport/transport.h"
 
 grpc_transport* grpc_create_cronet_transport(void* engine, const char* target,
diff --git a/src/core/ext/transport/inproc/inproc_plugin.cc b/src/core/ext/transport/inproc/inproc_plugin.cc
index 83a7d8d..8e251fa 100644
--- a/src/core/ext/transport/inproc/inproc_plugin.cc
+++ b/src/core/ext/transport/inproc/inproc_plugin.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/ext/transport/inproc/inproc_transport.h"
 #include "src/core/lib/debug/trace.h"
 
diff --git a/src/core/ext/transport/inproc/inproc_transport.cc b/src/core/ext/transport/inproc/inproc_transport.cc
index 8dd0b7d..67a3800 100644
--- a/src/core/ext/transport/inproc/inproc_transport.cc
+++ b/src/core/ext/transport/inproc/inproc_transport.cc
@@ -16,13 +16,16 @@
  *
  */
 
-#include "src/core/ext/transport/inproc/inproc_transport.h"
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 #include <string.h>
+#include "src/core/ext/transport/inproc/inproc_transport.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gprpp/manual_constructor.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/surface/channel.h"
@@ -97,7 +100,7 @@
   grpc_transport_stream_op_batch* recv_trailing_md_op;
 
   grpc_slice_buffer recv_message;
-  grpc_slice_buffer_stream recv_stream;
+  grpc_core::ManualConstructor<grpc_core::SliceBufferByteStream> recv_stream;
   bool recv_inited;
 
   bool initial_md_sent;
@@ -208,8 +211,8 @@
   grpc_error* error = GRPC_ERROR_NONE;
   for (grpc_linked_mdelem* elem = metadata->list.head;
        (elem != nullptr) && (error == GRPC_ERROR_NONE); elem = elem->next) {
-    grpc_linked_mdelem* nelem =
-        (grpc_linked_mdelem*)gpr_arena_alloc(s->arena, sizeof(*nelem));
+    grpc_linked_mdelem* nelem = static_cast<grpc_linked_mdelem*>(
+        gpr_arena_alloc(s->arena, sizeof(*nelem)));
     nelem->md =
         grpc_mdelem_from_slices(grpc_slice_intern(GRPC_MDKEY(elem->md)),
                                 grpc_slice_intern(GRPC_MDVALUE(elem->md)));
@@ -223,8 +226,8 @@
                        grpc_stream_refcount* refcount, const void* server_data,
                        gpr_arena* arena) {
   INPROC_LOG(GPR_DEBUG, "init_stream %p %p %p", gt, gs, server_data);
-  inproc_transport* t = (inproc_transport*)gt;
-  inproc_stream* s = (inproc_stream*)gs;
+  inproc_transport* t = reinterpret_cast<inproc_transport*>(gt);
+  inproc_stream* s = reinterpret_cast<inproc_stream*>(gs);
   s->arena = arena;
 
   s->refs = refcount;
@@ -368,11 +371,11 @@
 static void complete_if_batch_end_locked(inproc_stream* s, grpc_error* error,
                                          grpc_transport_stream_op_batch* op,
                                          const char* msg) {
-  int is_sm = (int)(op == s->send_message_op);
-  int is_stm = (int)(op == s->send_trailing_md_op);
-  int is_rim = (int)(op == s->recv_initial_md_op);
-  int is_rm = (int)(op == s->recv_message_op);
-  int is_rtm = (int)(op == s->recv_trailing_md_op);
+  int is_sm = static_cast<int>(op == s->send_message_op);
+  int is_stm = static_cast<int>(op == s->send_trailing_md_op);
+  int is_rim = static_cast<int>(op == s->recv_initial_md_op);
+  int is_rm = static_cast<int>(op == s->recv_message_op);
+  int is_rtm = static_cast<int>(op == s->recv_trailing_md_op);
 
   if ((is_sm + is_stm + is_rim + is_rm + is_rtm) == 1) {
     INPROC_LOG(GPR_DEBUG, "%s %p %p %p", msg, s, op, error);
@@ -425,13 +428,13 @@
       // since it expects that as well as no error yet
       grpc_metadata_batch fake_md;
       grpc_metadata_batch_init(&fake_md);
-      grpc_linked_mdelem* path_md =
-          (grpc_linked_mdelem*)gpr_arena_alloc(s->arena, sizeof(*path_md));
+      grpc_linked_mdelem* path_md = static_cast<grpc_linked_mdelem*>(
+          gpr_arena_alloc(s->arena, sizeof(*path_md)));
       path_md->md = grpc_mdelem_from_slices(g_fake_path_key, g_fake_path_value);
       GPR_ASSERT(grpc_metadata_batch_link_tail(&fake_md, path_md) ==
                  GRPC_ERROR_NONE);
-      grpc_linked_mdelem* auth_md =
-          (grpc_linked_mdelem*)gpr_arena_alloc(s->arena, sizeof(*auth_md));
+      grpc_linked_mdelem* auth_md = static_cast<grpc_linked_mdelem*>(
+          gpr_arena_alloc(s->arena, sizeof(*auth_md)));
       auth_md->md = grpc_mdelem_from_slices(g_fake_auth_key, g_fake_auth_value);
       GPR_ASSERT(grpc_metadata_batch_link_tail(&fake_md, auth_md) ==
                  GRPC_ERROR_NONE);
@@ -480,6 +483,7 @@
     s->recv_message_op = nullptr;
   }
   if (s->send_message_op) {
+    s->send_message_op->payload->send_message.send_message.reset();
     complete_if_batch_end_locked(
         s, error, s->send_message_op,
         "fail_helper scheduling send-message-on-complete");
@@ -506,10 +510,18 @@
   GRPC_ERROR_UNREF(error);
 }
 
+// TODO(vjpai): It should not be necessary to drain the incoming byte
+// stream and create a new one; instead, we should simply pass the byte
+// stream from the sender directly to the receiver as-is.
+//
+// Note that fixing this will also avoid the assumption in this code
+// that the incoming byte stream's next() call will always return
+// synchronously.  That assumption is true today but may not always be
+// true in the future.
 static void message_transfer_locked(inproc_stream* sender,
                                     inproc_stream* receiver) {
   size_t remaining =
-      sender->send_message_op->payload->send_message.send_message->length;
+      sender->send_message_op->payload->send_message.send_message->length();
   if (receiver->recv_inited) {
     grpc_slice_buffer_destroy_internal(&receiver->recv_message);
   }
@@ -518,12 +530,12 @@
   do {
     grpc_slice message_slice;
     grpc_closure unused;
-    GPR_ASSERT(grpc_byte_stream_next(
-        sender->send_message_op->payload->send_message.send_message, SIZE_MAX,
-        &unused));
-    grpc_error* error = grpc_byte_stream_pull(
-        sender->send_message_op->payload->send_message.send_message,
-        &message_slice);
+    GPR_ASSERT(
+        sender->send_message_op->payload->send_message.send_message->Next(
+            SIZE_MAX, &unused));
+    grpc_error* error =
+        sender->send_message_op->payload->send_message.send_message->Pull(
+            &message_slice);
     if (error != GRPC_ERROR_NONE) {
       cancel_stream_locked(sender, GRPC_ERROR_REF(error));
       break;
@@ -532,11 +544,11 @@
     remaining -= GRPC_SLICE_LENGTH(message_slice);
     grpc_slice_buffer_add(&receiver->recv_message, message_slice);
   } while (remaining > 0);
+  sender->send_message_op->payload->send_message.send_message.reset();
 
-  grpc_slice_buffer_stream_init(&receiver->recv_stream, &receiver->recv_message,
-                                0);
-  *receiver->recv_message_op->payload->recv_message.recv_message =
-      &receiver->recv_stream.base;
+  receiver->recv_stream.Init(&receiver->recv_message, 0);
+  receiver->recv_message_op->payload->recv_message.recv_message->reset(
+      receiver->recv_stream.get());
   INPROC_LOG(GPR_DEBUG, "message_transfer_locked %p scheduling message-ready",
              receiver);
   GRPC_CLOSURE_SCHED(
@@ -566,7 +578,7 @@
   bool needs_close = false;
 
   INPROC_LOG(GPR_DEBUG, "op_state_machine %p", arg);
-  inproc_stream* s = (inproc_stream*)arg;
+  inproc_stream* s = static_cast<inproc_stream*>(arg);
   gpr_mu* mu = &s->t->mu->mu;  // keep aside in case s gets closed
   gpr_mu_lock(mu);
   s->op_closure_scheduled = false;
@@ -592,6 +604,7 @@
                (s->trailing_md_sent || other->recv_trailing_md_op)) {
       // A server send will never be matched if the client is waiting
       // for trailing metadata already
+      s->send_message_op->payload->send_message.send_message.reset();
       complete_if_batch_end_locked(
           s, GRPC_ERROR_NONE, s->send_message_op,
           "op_state_machine scheduling send-message-on-complete");
@@ -728,6 +741,7 @@
     if ((s->trailing_md_sent || s->t->is_client) && s->send_message_op) {
       // Nothing further will try to receive from this stream, so finish off
       // any outstanding send_message op
+      s->send_message_op->payload->send_message.send_message.reset();
       complete_if_batch_end_locked(
           s, new_err, s->send_message_op,
           "op_state_machine scheduling send-message-on-complete");
@@ -785,6 +799,7 @@
       s->send_message_op) {
     // Nothing further will try to receive from this stream, so finish off
     // any outstanding send_message op
+    s->send_message_op->payload->send_message.send_message.reset();
     complete_if_batch_end_locked(
         s, new_err, s->send_message_op,
         "op_state_machine scheduling send-message-on-complete");
@@ -863,7 +878,7 @@
 static void perform_stream_op(grpc_transport* gt, grpc_stream* gs,
                               grpc_transport_stream_op_batch* op) {
   INPROC_LOG(GPR_DEBUG, "perform_stream_op %p %p %p", gt, gs, op);
-  inproc_stream* s = (inproc_stream*)gs;
+  inproc_stream* s = reinterpret_cast<inproc_stream*>(gs);
   gpr_mu* mu = &s->t->mu->mu;  // save aside in case s gets closed
   gpr_mu_lock(mu);
 
@@ -1047,7 +1062,7 @@
 }
 
 static void perform_transport_op(grpc_transport* gt, grpc_transport_op* op) {
-  inproc_transport* t = (inproc_transport*)gt;
+  inproc_transport* t = reinterpret_cast<inproc_transport*>(gt);
   INPROC_LOG(GPR_DEBUG, "perform_transport_op %p %p", t, op);
   gpr_mu_lock(&t->mu->mu);
   if (op->on_connectivity_state_change) {
@@ -1082,13 +1097,13 @@
 static void destroy_stream(grpc_transport* gt, grpc_stream* gs,
                            grpc_closure* then_schedule_closure) {
   INPROC_LOG(GPR_DEBUG, "destroy_stream %p %p", gs, then_schedule_closure);
-  inproc_stream* s = (inproc_stream*)gs;
+  inproc_stream* s = reinterpret_cast<inproc_stream*>(gs);
   s->closure_at_destroy = then_schedule_closure;
   really_destroy_stream(s);
 }
 
 static void destroy_transport(grpc_transport* gt) {
-  inproc_transport* t = (inproc_transport*)gt;
+  inproc_transport* t = reinterpret_cast<inproc_transport*>(gt);
   INPROC_LOG(GPR_DEBUG, "destroy_transport %p", t);
   gpr_mu_lock(&t->mu->mu);
   close_transport_locked(t);
@@ -1151,10 +1166,12 @@
                                      grpc_transport** client_transport,
                                      const grpc_channel_args* client_args) {
   INPROC_LOG(GPR_DEBUG, "inproc_transports_create");
-  inproc_transport* st = (inproc_transport*)gpr_zalloc(sizeof(*st));
-  inproc_transport* ct = (inproc_transport*)gpr_zalloc(sizeof(*ct));
+  inproc_transport* st =
+      static_cast<inproc_transport*>(gpr_zalloc(sizeof(*st)));
+  inproc_transport* ct =
+      static_cast<inproc_transport*>(gpr_zalloc(sizeof(*ct)));
   // Share one lock between both sides since both sides get affected
-  st->mu = ct->mu = (shared_mu*)gpr_malloc(sizeof(*st->mu));
+  st->mu = ct->mu = static_cast<shared_mu*>(gpr_malloc(sizeof(*st->mu)));
   gpr_mu_init(&st->mu->mu);
   gpr_ref_init(&st->mu->refs, 2);
   st->base.vtable = &inproc_vtable;
@@ -1173,8 +1190,8 @@
   ct->other_side = st;
   st->stream_list = nullptr;
   ct->stream_list = nullptr;
-  *server_transport = (grpc_transport*)st;
-  *client_transport = (grpc_transport*)ct;
+  *server_transport = reinterpret_cast<grpc_transport*>(st);
+  *client_transport = reinterpret_cast<grpc_transport*>(ct);
 }
 
 grpc_channel* grpc_inproc_channel_create(grpc_server* server,
diff --git a/src/core/ext/transport/inproc/inproc_transport.h b/src/core/ext/transport/inproc/inproc_transport.h
index 7c0453e..049d140 100644
--- a/src/core/ext/transport/inproc/inproc_transport.h
+++ b/src/core/ext/transport/inproc/inproc_transport.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_INPROC_INPROC_TRANSPORT_H
 #define GRPC_CORE_EXT_TRANSPORT_INPROC_INPROC_TRANSPORT_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/transport/transport_impl.h"
 
 grpc_channel* grpc_inproc_channel_create(grpc_server* server,
diff --git a/src/core/lib/gpr/avl.cc b/src/core/lib/avl/avl.cc
similarity index 66%
rename from src/core/lib/gpr/avl.cc
rename to src/core/lib/avl/avl.cc
index 0b67a21..ec106dd 100644
--- a/src/core/lib/gpr/avl.cc
+++ b/src/core/lib/avl/avl.cc
@@ -16,30 +16,33 @@
  *
  */
 
-#include <grpc/support/avl.h>
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/avl/avl.h"
 
 #include <assert.h>
 #include <stdlib.h>
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 
-gpr_avl gpr_avl_create(const gpr_avl_vtable* vtable) {
-  gpr_avl out;
+#include "src/core/lib/gpr/useful.h"
+
+grpc_avl grpc_avl_create(const grpc_avl_vtable* vtable) {
+  grpc_avl out;
   out.vtable = vtable;
   out.root = nullptr;
   return out;
 }
 
-static gpr_avl_node* ref_node(gpr_avl_node* node) {
+static grpc_avl_node* ref_node(grpc_avl_node* node) {
   if (node) {
     gpr_ref(&node->refs);
   }
   return node;
 }
 
-static void unref_node(const gpr_avl_vtable* vtable, gpr_avl_node* node,
+static void unref_node(const grpc_avl_vtable* vtable, grpc_avl_node* node,
                        void* user_data) {
   if (node == nullptr) {
     return;
@@ -53,18 +56,18 @@
   }
 }
 
-static long node_height(gpr_avl_node* node) {
+static long node_height(grpc_avl_node* node) {
   return node == nullptr ? 0 : node->height;
 }
 
 #ifndef NDEBUG
-static long calculate_height(gpr_avl_node* node) {
+static long calculate_height(grpc_avl_node* node) {
   return node == nullptr ? 0
                          : 1 + GPR_MAX(calculate_height(node->left),
                                        calculate_height(node->right));
 }
 
-static gpr_avl_node* assert_invariants(gpr_avl_node* n) {
+static grpc_avl_node* assert_invariants(grpc_avl_node* n) {
   if (n == nullptr) return nullptr;
   assert_invariants(n->left);
   assert_invariants(n->right);
@@ -73,12 +76,12 @@
   return n;
 }
 #else
-static gpr_avl_node* assert_invariants(gpr_avl_node* n) { return n; }
+static grpc_avl_node* assert_invariants(grpc_avl_node* n) { return n; }
 #endif
 
-gpr_avl_node* new_node(void* key, void* value, gpr_avl_node* left,
-                       gpr_avl_node* right) {
-  gpr_avl_node* node = (gpr_avl_node*)gpr_malloc(sizeof(*node));
+grpc_avl_node* new_node(void* key, void* value, grpc_avl_node* left,
+                        grpc_avl_node* right) {
+  grpc_avl_node* node = static_cast<grpc_avl_node*>(gpr_malloc(sizeof(*node)));
   gpr_ref_init(&node->refs, 1);
   node->key = key;
   node->value = value;
@@ -88,8 +91,8 @@
   return node;
 }
 
-static gpr_avl_node* get(const gpr_avl_vtable* vtable, gpr_avl_node* node,
-                         void* key, void* user_data) {
+static grpc_avl_node* get(const grpc_avl_vtable* vtable, grpc_avl_node* node,
+                          void* key, void* user_data) {
   long cmp;
 
   if (node == nullptr) {
@@ -106,13 +109,13 @@
   }
 }
 
-void* gpr_avl_get(gpr_avl avl, void* key, void* user_data) {
-  gpr_avl_node* node = get(avl.vtable, avl.root, key, user_data);
+void* grpc_avl_get(grpc_avl avl, void* key, void* user_data) {
+  grpc_avl_node* node = get(avl.vtable, avl.root, key, user_data);
   return node ? node->value : nullptr;
 }
 
-int gpr_avl_maybe_get(gpr_avl avl, void* key, void** value, void* user_data) {
-  gpr_avl_node* node = get(avl.vtable, avl.root, key, user_data);
+int grpc_avl_maybe_get(grpc_avl avl, void* key, void** value, void* user_data) {
+  grpc_avl_node* node = get(avl.vtable, avl.root, key, user_data);
   if (node != nullptr) {
     *value = node->value;
     return 1;
@@ -120,21 +123,21 @@
   return 0;
 }
 
-static gpr_avl_node* rotate_left(const gpr_avl_vtable* vtable, void* key,
-                                 void* value, gpr_avl_node* left,
-                                 gpr_avl_node* right, void* user_data) {
-  gpr_avl_node* n = new_node(vtable->copy_key(right->key, user_data),
-                             vtable->copy_value(right->value, user_data),
-                             new_node(key, value, left, ref_node(right->left)),
-                             ref_node(right->right));
+static grpc_avl_node* rotate_left(const grpc_avl_vtable* vtable, void* key,
+                                  void* value, grpc_avl_node* left,
+                                  grpc_avl_node* right, void* user_data) {
+  grpc_avl_node* n = new_node(vtable->copy_key(right->key, user_data),
+                              vtable->copy_value(right->value, user_data),
+                              new_node(key, value, left, ref_node(right->left)),
+                              ref_node(right->right));
   unref_node(vtable, right, user_data);
   return n;
 }
 
-static gpr_avl_node* rotate_right(const gpr_avl_vtable* vtable, void* key,
-                                  void* value, gpr_avl_node* left,
-                                  gpr_avl_node* right, void* user_data) {
-  gpr_avl_node* n =
+static grpc_avl_node* rotate_right(const grpc_avl_vtable* vtable, void* key,
+                                   void* value, grpc_avl_node* left,
+                                   grpc_avl_node* right, void* user_data) {
+  grpc_avl_node* n =
       new_node(vtable->copy_key(left->key, user_data),
                vtable->copy_value(left->value, user_data), ref_node(left->left),
                new_node(key, value, ref_node(left->right), right));
@@ -142,11 +145,12 @@
   return n;
 }
 
-static gpr_avl_node* rotate_left_right(const gpr_avl_vtable* vtable, void* key,
-                                       void* value, gpr_avl_node* left,
-                                       gpr_avl_node* right, void* user_data) {
+static grpc_avl_node* rotate_left_right(const grpc_avl_vtable* vtable,
+                                        void* key, void* value,
+                                        grpc_avl_node* left,
+                                        grpc_avl_node* right, void* user_data) {
   /* rotate_right(..., rotate_left(left), right) */
-  gpr_avl_node* n =
+  grpc_avl_node* n =
       new_node(vtable->copy_key(left->right->key, user_data),
                vtable->copy_value(left->right->value, user_data),
                new_node(vtable->copy_key(left->key, user_data),
@@ -157,11 +161,12 @@
   return n;
 }
 
-static gpr_avl_node* rotate_right_left(const gpr_avl_vtable* vtable, void* key,
-                                       void* value, gpr_avl_node* left,
-                                       gpr_avl_node* right, void* user_data) {
+static grpc_avl_node* rotate_right_left(const grpc_avl_vtable* vtable,
+                                        void* key, void* value,
+                                        grpc_avl_node* left,
+                                        grpc_avl_node* right, void* user_data) {
   /* rotate_left(..., left, rotate_right(right)) */
-  gpr_avl_node* n =
+  grpc_avl_node* n =
       new_node(vtable->copy_key(right->left->key, user_data),
                vtable->copy_value(right->left->value, user_data),
                new_node(key, value, left, ref_node(right->left->left)),
@@ -172,9 +177,9 @@
   return n;
 }
 
-static gpr_avl_node* rebalance(const gpr_avl_vtable* vtable, void* key,
-                               void* value, gpr_avl_node* left,
-                               gpr_avl_node* right, void* user_data) {
+static grpc_avl_node* rebalance(const grpc_avl_vtable* vtable, void* key,
+                                void* value, grpc_avl_node* left,
+                                grpc_avl_node* right, void* user_data) {
   switch (node_height(left) - node_height(right)) {
     case 2:
       if (node_height(left->left) - node_height(left->right) == -1) {
@@ -197,8 +202,9 @@
   }
 }
 
-static gpr_avl_node* add_key(const gpr_avl_vtable* vtable, gpr_avl_node* node,
-                             void* key, void* value, void* user_data) {
+static grpc_avl_node* add_key(const grpc_avl_vtable* vtable,
+                              grpc_avl_node* node, void* key, void* value,
+                              void* user_data) {
   long cmp;
   if (node == nullptr) {
     return new_node(key, value, nullptr, nullptr);
@@ -219,31 +225,31 @@
   }
 }
 
-gpr_avl gpr_avl_add(gpr_avl avl, void* key, void* value, void* user_data) {
-  gpr_avl_node* old_root = avl.root;
+grpc_avl grpc_avl_add(grpc_avl avl, void* key, void* value, void* user_data) {
+  grpc_avl_node* old_root = avl.root;
   avl.root = add_key(avl.vtable, avl.root, key, value, user_data);
   assert_invariants(avl.root);
   unref_node(avl.vtable, old_root, user_data);
   return avl;
 }
 
-static gpr_avl_node* in_order_head(gpr_avl_node* node) {
+static grpc_avl_node* in_order_head(grpc_avl_node* node) {
   while (node->left != nullptr) {
     node = node->left;
   }
   return node;
 }
 
-static gpr_avl_node* in_order_tail(gpr_avl_node* node) {
+static grpc_avl_node* in_order_tail(grpc_avl_node* node) {
   while (node->right != nullptr) {
     node = node->right;
   }
   return node;
 }
 
-static gpr_avl_node* remove_key(const gpr_avl_vtable* vtable,
-                                gpr_avl_node* node, void* key,
-                                void* user_data) {
+static grpc_avl_node* remove_key(const grpc_avl_vtable* vtable,
+                                 grpc_avl_node* node, void* key,
+                                 void* user_data) {
   long cmp;
   if (node == nullptr) {
     return nullptr;
@@ -255,13 +261,13 @@
     } else if (node->right == nullptr) {
       return ref_node(node->left);
     } else if (node->left->height < node->right->height) {
-      gpr_avl_node* h = in_order_head(node->right);
+      grpc_avl_node* h = in_order_head(node->right);
       return rebalance(
           vtable, vtable->copy_key(h->key, user_data),
           vtable->copy_value(h->value, user_data), ref_node(node->left),
           remove_key(vtable, node->right, h->key, user_data), user_data);
     } else {
-      gpr_avl_node* h = in_order_tail(node->left);
+      grpc_avl_node* h = in_order_tail(node->left);
       return rebalance(vtable, vtable->copy_key(h->key, user_data),
                        vtable->copy_value(h->value, user_data),
                        remove_key(vtable, node->left, h->key, user_data),
@@ -280,21 +286,21 @@
   }
 }
 
-gpr_avl gpr_avl_remove(gpr_avl avl, void* key, void* user_data) {
-  gpr_avl_node* old_root = avl.root;
+grpc_avl grpc_avl_remove(grpc_avl avl, void* key, void* user_data) {
+  grpc_avl_node* old_root = avl.root;
   avl.root = remove_key(avl.vtable, avl.root, key, user_data);
   assert_invariants(avl.root);
   unref_node(avl.vtable, old_root, user_data);
   return avl;
 }
 
-gpr_avl gpr_avl_ref(gpr_avl avl, void* user_data) {
+grpc_avl grpc_avl_ref(grpc_avl avl, void* user_data) {
   ref_node(avl.root);
   return avl;
 }
 
-void gpr_avl_unref(gpr_avl avl, void* user_data) {
+void grpc_avl_unref(grpc_avl avl, void* user_data) {
   unref_node(avl.vtable, avl.root, user_data);
 }
 
-int gpr_avl_is_empty(gpr_avl avl) { return avl.root == nullptr; }
+int grpc_avl_is_empty(grpc_avl avl) { return avl.root == nullptr; }
diff --git a/include/grpc/support/avl.h b/src/core/lib/avl/avl.h
similarity index 66%
rename from include/grpc/support/avl.h
rename to src/core/lib/avl/avl.h
index b5a8c0f..15a9d56 100644
--- a/include/grpc/support/avl.h
+++ b/src/core/lib/avl/avl.h
@@ -16,31 +16,29 @@
  *
  */
 
-#ifndef GRPC_SUPPORT_AVL_H
-#define GRPC_SUPPORT_AVL_H
+#ifndef GRPC_CORE_LIB_AVL_AVL_H
+#define GRPC_CORE_LIB_AVL_AVL_H
+
+#include <grpc/support/port_platform.h>
 
 #include <grpc/support/sync.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /** internal node of an AVL tree */
-typedef struct gpr_avl_node {
+typedef struct grpc_avl_node {
   gpr_refcount refs;
   void* key;
   void* value;
-  struct gpr_avl_node* left;
-  struct gpr_avl_node* right;
+  struct grpc_avl_node* left;
+  struct grpc_avl_node* right;
   long height;
-} gpr_avl_node;
+} grpc_avl_node;
 
 /** vtable for the AVL tree
- * The optional user_data is propagated from the top level gpr_avl_XXX API.
+ * The optional user_data is propagated from the top level grpc_avl_XXX API.
  * From the same API call, multiple vtable functions may be called multiple
  * times.
  */
-typedef struct gpr_avl_vtable {
+typedef struct grpc_avl_vtable {
   /** destroy a key */
   void (*destroy_key)(void* key, void* user_data);
   /** copy a key, returning new value */
@@ -52,51 +50,45 @@
   void (*destroy_value)(void* value, void* user_data);
   /** copy a value */
   void* (*copy_value)(void* value, void* user_data);
-} gpr_avl_vtable;
+} grpc_avl_vtable;
 
 /** "pointer" to an AVL tree - this is a reference
-    counted object - use gpr_avl_ref to add a reference,
-    gpr_avl_unref when done with a reference */
-typedef struct gpr_avl {
-  const gpr_avl_vtable* vtable;
-  gpr_avl_node* root;
-} gpr_avl;
+    counted object - use grpc_avl_ref to add a reference,
+    grpc_avl_unref when done with a reference */
+typedef struct grpc_avl {
+  const grpc_avl_vtable* vtable;
+  grpc_avl_node* root;
+} grpc_avl;
 
 /** Create an immutable AVL tree. */
-GPRAPI gpr_avl gpr_avl_create(const gpr_avl_vtable* vtable);
+grpc_avl grpc_avl_create(const grpc_avl_vtable* vtable);
 /** Add a reference to an existing tree - returns
     the tree as a convenience. The optional user_data will be passed to vtable
     functions. */
-GPRAPI gpr_avl gpr_avl_ref(gpr_avl avl, void* user_data);
+grpc_avl grpc_avl_ref(grpc_avl avl, void* user_data);
 /** Remove a reference to a tree - destroying it if there
     are no references left. The optional user_data will be passed to vtable
     functions. */
-GPRAPI void gpr_avl_unref(gpr_avl avl, void* user_data);
+void grpc_avl_unref(grpc_avl avl, void* user_data);
 /** Return a new tree with (key, value) added to avl.
     implicitly unrefs avl to allow easy chaining.
     if key exists in avl, the new tree's key entry updated
     (i.e. a duplicate is not created). The optional user_data will be passed to
     vtable functions. */
-GPRAPI gpr_avl gpr_avl_add(gpr_avl avl, void* key, void* value,
-                           void* user_data);
+grpc_avl grpc_avl_add(grpc_avl avl, void* key, void* value, void* user_data);
 /** Return a new tree with key deleted
     implicitly unrefs avl to allow easy chaining. The optional user_data will be
     passed to vtable functions. */
-GPRAPI gpr_avl gpr_avl_remove(gpr_avl avl, void* key, void* user_data);
+grpc_avl grpc_avl_remove(grpc_avl avl, void* key, void* user_data);
 /** Lookup key, and return the associated value.
     Does not mutate avl.
     Returns NULL if key is not found. The optional user_data will be passed to
     vtable functions.*/
-GPRAPI void* gpr_avl_get(gpr_avl avl, void* key, void* user_data);
+void* grpc_avl_get(grpc_avl avl, void* key, void* user_data);
 /** Return 1 if avl contains key, 0 otherwise; if it has the key, sets *value to
-    its value. THe optional user_data will be passed to vtable functions. */
-GPRAPI int gpr_avl_maybe_get(gpr_avl avl, void* key, void** value,
-                             void* user_data);
+    its value. The optional user_data will be passed to vtable functions. */
+int grpc_avl_maybe_get(grpc_avl avl, void* key, void** value, void* user_data);
 /** Return 1 if avl is empty, 0 otherwise */
-GPRAPI int gpr_avl_is_empty(gpr_avl avl);
+int grpc_avl_is_empty(grpc_avl avl);
 
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_SUPPORT_AVL_H */
+#endif /* GRPC_CORE_LIB_AVL_AVL_H */
diff --git a/src/core/lib/backoff/backoff.cc b/src/core/lib/backoff/backoff.cc
index d561fc7..e536abd 100644
--- a/src/core/lib/backoff/backoff.cc
+++ b/src/core/lib/backoff/backoff.cc
@@ -16,11 +16,13 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/backoff/backoff.h"
 
 #include <algorithm>
 
-#include <grpc/support/useful.h>
+#include "src/core/lib/gpr/useful.h"
 
 namespace grpc_core {
 
@@ -55,13 +57,14 @@
     initial_ = false;
     return current_backoff_ + grpc_core::ExecCtx::Get()->Now();
   }
-  current_backoff_ =
-      (grpc_millis)(std::min(current_backoff_ * options_.multiplier(),
-                             (double)options_.max_backoff()));
+  current_backoff_ = static_cast<grpc_millis>(
+      std::min(current_backoff_ * options_.multiplier(),
+               static_cast<double>(options_.max_backoff())));
   const double jitter = generate_uniform_random_number_between(
       &rng_state_, -options_.jitter() * current_backoff_,
       options_.jitter() * current_backoff_);
-  const grpc_millis next_timeout = (grpc_millis)(current_backoff_ + jitter);
+  const grpc_millis next_timeout =
+      static_cast<grpc_millis>(current_backoff_ + jitter);
   return next_timeout + grpc_core::ExecCtx::Get()->Now();
 }
 
diff --git a/src/core/lib/backoff/backoff.h b/src/core/lib/backoff/backoff.h
index de30e52..e769d15 100644
--- a/src/core/lib/backoff/backoff.h
+++ b/src/core/lib/backoff/backoff.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_BACKOFF_BACKOFF_H
 #define GRPC_CORE_LIB_BACKOFF_BACKOFF_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/exec_ctx.h"
 
 namespace grpc_core {
diff --git a/src/core/lib/channel/channel_args.cc b/src/core/lib/channel/channel_args.cc
index 101a6ff..66a86c2 100644
--- a/src/core/lib/channel/channel_args.cc
+++ b/src/core/lib/channel/channel_args.cc
@@ -26,10 +26,10 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
 
 static grpc_arg copy_arg(const grpc_arg* src) {
   grpc_arg dst;
@@ -87,13 +87,14 @@
   }
   // Create result.
   grpc_channel_args* dst =
-      (grpc_channel_args*)gpr_malloc(sizeof(grpc_channel_args));
+      static_cast<grpc_channel_args*>(gpr_malloc(sizeof(grpc_channel_args)));
   dst->num_args = num_args_to_copy + num_to_add;
   if (dst->num_args == 0) {
     dst->args = nullptr;
     return dst;
   }
-  dst->args = (grpc_arg*)gpr_malloc(sizeof(grpc_arg) * dst->num_args);
+  dst->args =
+      static_cast<grpc_arg*>(gpr_malloc(sizeof(grpc_arg) * dst->num_args));
   // Copy args from src that are not being removed.
   size_t dst_idx = 0;
   if (src != nullptr) {
@@ -118,7 +119,8 @@
 grpc_channel_args* grpc_channel_args_union(const grpc_channel_args* a,
                                            const grpc_channel_args* b) {
   const size_t max_out = (a->num_args + b->num_args);
-  grpc_arg* uniques = (grpc_arg*)gpr_malloc(sizeof(*uniques) * max_out);
+  grpc_arg* uniques =
+      static_cast<grpc_arg*>(gpr_malloc(sizeof(*uniques) * max_out));
   for (size_t i = 0; i < a->num_args; ++i) uniques[i] = a->args[i];
 
   size_t uniques_idx = a->num_args;
@@ -161,15 +163,16 @@
 /* stabilizing comparison function: since channel_args ordering matters for
  * keys with the same name, we need to preserve that ordering */
 static int cmp_key_stable(const void* ap, const void* bp) {
-  const grpc_arg* const* a = (const grpc_arg* const*)ap;
-  const grpc_arg* const* b = (const grpc_arg* const*)bp;
+  const grpc_arg* const* a = static_cast<const grpc_arg* const*>(ap);
+  const grpc_arg* const* b = static_cast<const grpc_arg* const*>(bp);
   int c = strcmp((*a)->key, (*b)->key);
   if (c == 0) c = GPR_ICMP(*a, *b);
   return c;
 }
 
 grpc_channel_args* grpc_channel_args_normalize(const grpc_channel_args* a) {
-  grpc_arg** args = (grpc_arg**)gpr_malloc(sizeof(grpc_arg*) * a->num_args);
+  grpc_arg** args =
+      static_cast<grpc_arg**>(gpr_malloc(sizeof(grpc_arg*) * a->num_args));
   for (size_t i = 0; i < a->num_args; i++) {
     args[i] = &a->args[i];
   }
@@ -177,9 +180,9 @@
     qsort(args, a->num_args, sizeof(grpc_arg*), cmp_key_stable);
 
   grpc_channel_args* b =
-      (grpc_channel_args*)gpr_malloc(sizeof(grpc_channel_args));
+      static_cast<grpc_channel_args*>(gpr_malloc(sizeof(grpc_channel_args)));
   b->num_args = a->num_args;
-  b->args = (grpc_arg*)gpr_malloc(sizeof(grpc_arg) * b->num_args);
+  b->args = static_cast<grpc_arg*>(gpr_malloc(sizeof(grpc_arg) * b->num_args));
   for (size_t i = 0; i < a->num_args; i++) {
     b->args[i] = copy_arg(args[i]);
   }
@@ -215,7 +218,7 @@
   for (i = 0; i < a->num_args; ++i) {
     if (a->args[i].type == GRPC_ARG_INTEGER &&
         !strcmp(GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM, a->args[i].key)) {
-      return (grpc_compression_algorithm)a->args[i].value.integer;
+      return static_cast<grpc_compression_algorithm>(a->args[i].value.integer);
       break;
     }
   }
@@ -296,7 +299,7 @@
     const grpc_channel_args* a) {
   int* states_arg;
   if (find_compression_algorithm_states_bitset(a, &states_arg)) {
-    return (uint32_t)*states_arg;
+    return static_cast<uint32_t>(*states_arg);
   } else {
     return (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1; /* All algs. enabled */
   }
@@ -351,6 +354,15 @@
   return arg->value.integer;
 }
 
+char* grpc_channel_arg_get_string(const grpc_arg* arg) {
+  if (arg == nullptr) return nullptr;
+  if (arg->type != GRPC_ARG_STRING) {
+    gpr_log(GPR_ERROR, "%s ignored: it must be an string", arg->key);
+    return nullptr;
+  }
+  return arg->value.string;
+}
+
 bool grpc_channel_arg_get_bool(const grpc_arg* arg, bool default_value) {
   if (arg == nullptr) return default_value;
   if (arg->type != GRPC_ARG_INTEGER) {
diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h
index 73e9122..c0d6a17 100644
--- a/src/core/lib/channel/channel_args.h
+++ b/src/core/lib/channel/channel_args.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_CHANNEL_CHANNEL_ARGS_H
 #define GRPC_CORE_LIB_CHANNEL_CHANNEL_ARGS_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/compression.h>
 #include <grpc/grpc.h>
 #include "src/core/lib/iomgr/socket_mutator.h"
@@ -109,6 +111,11 @@
 int grpc_channel_arg_get_integer(const grpc_arg* arg,
                                  const grpc_integer_options options);
 
+/** Returns the value of \a arg if \a arg is of type GRPC_ARG_STRING.
+    Otherwise, emits a warning log, and returns nullptr.
+    If arg is nullptr, returns nullptr, and does not emit a warning. */
+char* grpc_channel_arg_get_string(const grpc_arg* arg);
+
 bool grpc_channel_arg_get_bool(const grpc_arg* arg, bool default_value);
 
 // Helpers for creating channel args.
diff --git a/src/core/lib/channel/channel_stack.cc b/src/core/lib/channel/channel_stack.cc
index 195fe0b..a9459b1 100644
--- a/src/core/lib/channel/channel_stack.cc
+++ b/src/core/lib/channel/channel_stack.cc
@@ -16,9 +16,11 @@
  *
  */
 
-#include "src/core/lib/channel/channel_stack.h"
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include "src/core/lib/channel/channel_stack.h"
 
 #include <stdlib.h>
 #include <string.h>
@@ -104,8 +106,9 @@
   GRPC_STREAM_REF_INIT(&stack->refcount, initial_refs, destroy, destroy_arg,
                        name);
   elems = CHANNEL_ELEMS_FROM_STACK(stack);
-  user_data = ((char*)elems) + ROUND_UP_TO_ALIGNMENT_SIZE(
-                                   filter_count * sizeof(grpc_channel_element));
+  user_data =
+      (reinterpret_cast<char*>(elems)) +
+      ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_channel_element));
 
   /* init per-filter data */
   grpc_error* first_error = GRPC_ERROR_NONE;
@@ -162,7 +165,7 @@
   GRPC_STREAM_REF_INIT(&elem_args->call_stack->refcount, initial_refs, destroy,
                        destroy_arg, "CALL_STACK");
   call_elems = CALL_ELEMS_FROM_STACK(elem_args->call_stack);
-  user_data = ((char*)call_elems) +
+  user_data = (reinterpret_cast<char*>(call_elems)) +
               ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element));
 
   /* init per-filter data */
@@ -194,7 +197,7 @@
   size_t i;
 
   call_elems = CALL_ELEMS_FROM_STACK(call_stack);
-  user_data = ((char*)call_elems) +
+  user_data = (reinterpret_cast<char*>(call_elems)) +
               ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element));
 
   /* init per-filter data */
@@ -243,11 +246,13 @@
 
 grpc_channel_stack* grpc_channel_stack_from_top_element(
     grpc_channel_element* elem) {
-  return (grpc_channel_stack*)((char*)(elem)-ROUND_UP_TO_ALIGNMENT_SIZE(
-      sizeof(grpc_channel_stack)));
+  return reinterpret_cast<grpc_channel_stack*>(
+      reinterpret_cast<char*>(elem) -
+      ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_channel_stack)));
 }
 
 grpc_call_stack* grpc_call_stack_from_top_element(grpc_call_element* elem) {
-  return (grpc_call_stack*)((char*)(elem)-ROUND_UP_TO_ALIGNMENT_SIZE(
-      sizeof(grpc_call_stack)));
+  return reinterpret_cast<grpc_call_stack*>(
+      reinterpret_cast<char*>(elem) -
+      ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)));
 }
diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h
index b9f9748..4bf8218 100644
--- a/src/core/lib/channel/channel_stack.h
+++ b/src/core/lib/channel/channel_stack.h
@@ -33,6 +33,8 @@
    Call stacks are created by channel stacks and represent the per-call data
    for that stack. */
 
+#include <grpc/support/port_platform.h>
+
 #include <stddef.h>
 
 #include <grpc/grpc.h>
diff --git a/src/core/lib/channel/channel_stack_builder.cc b/src/core/lib/channel/channel_stack_builder.cc
index fcba826..8a72449 100644
--- a/src/core/lib/channel/channel_stack_builder.cc
+++ b/src/core/lib/channel/channel_stack_builder.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/channel/channel_stack_builder.h"
 
 #include <string.h>
@@ -52,7 +54,7 @@
 
 grpc_channel_stack_builder* grpc_channel_stack_builder_create(void) {
   grpc_channel_stack_builder* b =
-      (grpc_channel_stack_builder*)gpr_zalloc(sizeof(*b));
+      static_cast<grpc_channel_stack_builder*>(gpr_zalloc(sizeof(*b)));
 
   b->begin.filter = nullptr;
   b->end.filter = nullptr;
@@ -78,7 +80,8 @@
 static grpc_channel_stack_builder_iterator* create_iterator_at_filter_node(
     grpc_channel_stack_builder* builder, filter_node* node) {
   grpc_channel_stack_builder_iterator* it =
-      (grpc_channel_stack_builder_iterator*)gpr_malloc(sizeof(*it));
+      static_cast<grpc_channel_stack_builder_iterator*>(
+          gpr_malloc(sizeof(*it)));
   it->builder = builder;
   it->node = node;
   return it;
@@ -213,7 +216,8 @@
 static void add_after(filter_node* before, const grpc_channel_filter* filter,
                       grpc_post_filter_create_init_func post_init_func,
                       void* user_data) {
-  filter_node* new_node = (filter_node*)gpr_malloc(sizeof(*new_node));
+  filter_node* new_node =
+      static_cast<filter_node*>(gpr_malloc(sizeof(*new_node)));
   new_node->next = before->next;
   new_node->prev = before;
   new_node->next->prev = new_node->prev->next = new_node;
@@ -265,7 +269,8 @@
 
   // create an array of filters
   const grpc_channel_filter** filters =
-      (const grpc_channel_filter**)gpr_malloc(sizeof(*filters) * num_filters);
+      static_cast<const grpc_channel_filter**>(
+          gpr_malloc(sizeof(*filters) * num_filters));
   size_t i = 0;
   for (filter_node* p = builder->begin.next; p != &builder->end; p = p->next) {
     filters[i++] = p->filter;
@@ -277,8 +282,8 @@
   // allocate memory, with prefix_bytes followed by channel_stack_size
   *result = gpr_zalloc(prefix_bytes + channel_stack_size);
   // fetch a pointer to the channel stack
-  grpc_channel_stack* channel_stack =
-      (grpc_channel_stack*)((char*)(*result) + prefix_bytes);
+  grpc_channel_stack* channel_stack = reinterpret_cast<grpc_channel_stack*>(
+      static_cast<char*>(*result) + prefix_bytes);
   // and initialize it
   grpc_error* error = grpc_channel_stack_init(
       initial_refs, destroy, destroy_arg == nullptr ? *result : destroy_arg,
@@ -303,7 +308,7 @@
   }
 
   grpc_channel_stack_builder_destroy(builder);
-  gpr_free((grpc_channel_filter**)filters);
+  gpr_free(const_cast<grpc_channel_filter**>(filters));
 
   return error;
 }
diff --git a/src/core/lib/channel/channel_stack_builder.h b/src/core/lib/channel/channel_stack_builder.h
index d00ddc6..c9a170b 100644
--- a/src/core/lib/channel/channel_stack_builder.h
+++ b/src/core/lib/channel/channel_stack_builder.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_CHANNEL_CHANNEL_STACK_BUILDER_H
 #define GRPC_CORE_LIB_CHANNEL_CHANNEL_STACK_BUILDER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stdbool.h>
 
 #include "src/core/lib/channel/channel_args.h"
diff --git a/src/core/lib/channel/channel_trace.cc b/src/core/lib/channel/channel_trace.cc
new file mode 100644
index 0000000..654300c
--- /dev/null
+++ b/src/core/lib/channel/channel_trace.cc
@@ -0,0 +1,239 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/impl/codegen/port_platform.h>
+
+#include "src/core/lib/channel/channel_trace.h"
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "src/core/lib/channel/channel_trace_registry.h"
+#include "src/core/lib/channel/status_util.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/transport/connectivity_state.h"
+#include "src/core/lib/transport/error_utils.h"
+
+namespace grpc_core {
+
+ChannelTrace::TraceEvent::TraceEvent(
+    Severity severity, grpc_slice data,
+    RefCountedPtr<ChannelTrace> referenced_tracer, ReferencedType type)
+    : severity_(severity),
+      data_(data),
+      timestamp_(grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(),
+                                         GPR_CLOCK_REALTIME)),
+      next_(nullptr),
+      referenced_tracer_(std::move(referenced_tracer)),
+      referenced_type_(type) {}
+
+ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data)
+    : severity_(severity),
+      data_(data),
+      timestamp_(grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(),
+                                         GPR_CLOCK_REALTIME)),
+      next_(nullptr) {}
+
+ChannelTrace::TraceEvent::~TraceEvent() { grpc_slice_unref_internal(data_); }
+
+ChannelTrace::ChannelTrace(size_t max_events)
+    : channel_uuid_(-1),
+      num_events_logged_(0),
+      list_size_(0),
+      max_list_size_(max_events),
+      head_trace_(nullptr),
+      tail_trace_(nullptr) {
+  if (max_list_size_ == 0) return;  // tracing is disabled if max_events == 0
+  gpr_mu_init(&tracer_mu_);
+  channel_uuid_ = grpc_channel_trace_registry_register_channel_trace(this);
+  time_created_ = grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(),
+                                          GPR_CLOCK_REALTIME);
+}
+
+ChannelTrace::~ChannelTrace() {
+  if (max_list_size_ == 0) return;  // tracing is disabled if max_events == 0
+  TraceEvent* it = head_trace_;
+  while (it != nullptr) {
+    TraceEvent* to_free = it;
+    it = it->next();
+    Delete<TraceEvent>(to_free);
+  }
+  grpc_channel_trace_registry_unregister_channel_trace(channel_uuid_);
+  gpr_mu_destroy(&tracer_mu_);
+}
+
+intptr_t ChannelTrace::GetUuid() const { return channel_uuid_; }
+
+void ChannelTrace::AddTraceEventHelper(TraceEvent* new_trace_event) {
+  ++num_events_logged_;
+  // first event case
+  if (head_trace_ == nullptr) {
+    head_trace_ = tail_trace_ = new_trace_event;
+  }
+  // regular event add case
+  else {
+    tail_trace_->set_next(new_trace_event);
+    tail_trace_ = tail_trace_->next();
+  }
+  ++list_size_;
+  // maybe garbage collect the end
+  if (list_size_ > max_list_size_) {
+    TraceEvent* to_free = head_trace_;
+    head_trace_ = head_trace_->next();
+    Delete<TraceEvent>(to_free);
+    --list_size_;
+  }
+}
+
+void ChannelTrace::AddTraceEvent(Severity severity, grpc_slice data) {
+  if (max_list_size_ == 0) return;  // tracing is disabled if max_events == 0
+  AddTraceEventHelper(New<TraceEvent>(severity, data));
+}
+
+void ChannelTrace::AddTraceEventReferencingChannel(
+    Severity severity, grpc_slice data,
+    RefCountedPtr<ChannelTrace> referenced_tracer) {
+  if (max_list_size_ == 0) return;  // tracing is disabled if max_events == 0
+  // create and fill up the new event
+  AddTraceEventHelper(
+      New<TraceEvent>(severity, data, std::move(referenced_tracer), Channel));
+}
+
+void ChannelTrace::AddTraceEventReferencingSubchannel(
+    Severity severity, grpc_slice data,
+    RefCountedPtr<ChannelTrace> referenced_tracer) {
+  if (max_list_size_ == 0) return;  // tracing is disabled if max_events == 0
+  // create and fill up the new event
+  AddTraceEventHelper(New<TraceEvent>(
+      severity, data, std::move(referenced_tracer), Subchannel));
+}
+
+namespace {
+
+// returns an allocated string that represents tm according to RFC-3339, and,
+// more specifically, follows:
+// https://developers.google.com/protocol-buffers/docs/proto3#json
+//
+// "Uses RFC 3339, where generated output will always be Z-normalized and uses
+// 0, 3, 6 or 9 fractional digits."
+char* fmt_time(gpr_timespec tm) {
+  char time_buffer[35];
+  char ns_buffer[11];  // '.' + 9 digits of precision
+  struct tm* tm_info = localtime((const time_t*)&tm.tv_sec);
+  strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%dT%H:%M:%S", tm_info);
+  snprintf(ns_buffer, 11, ".%09d", tm.tv_nsec);
+  // This loop trims off trailing zeros by inserting a null character that the
+  // right point. We iterate in chunks of three because we want 0, 3, 6, or 9
+  // fractional digits.
+  for (int i = 7; i >= 1; i -= 3) {
+    if (ns_buffer[i] == '0' && ns_buffer[i + 1] == '0' &&
+        ns_buffer[i + 2] == '0') {
+      ns_buffer[i] = '\0';
+      // Edge case in which all fractional digits were 0.
+      if (i == 1) {
+        ns_buffer[0] = '\0';
+      }
+    } else {
+      break;
+    }
+  }
+  char* full_time_str;
+  gpr_asprintf(&full_time_str, "%s%sZ", time_buffer, ns_buffer);
+  return full_time_str;
+}
+
+const char* severity_string(ChannelTrace::Severity severity) {
+  switch (severity) {
+    case ChannelTrace::Severity::Info:
+      return "CT_INFO";
+    case ChannelTrace::Severity::Warning:
+      return "CT_WARNING";
+    case ChannelTrace::Severity::Error:
+      return "CT_ERROR";
+    default:
+      GPR_UNREACHABLE_CODE(return "CT_UNKNOWN");
+  }
+}
+
+}  // anonymous namespace
+
+void ChannelTrace::TraceEvent::RenderTraceEvent(grpc_json* json) const {
+  grpc_json* json_iterator = nullptr;
+  json_iterator = grpc_json_create_child(json_iterator, json, "description",
+                                         grpc_slice_to_c_string(data_),
+                                         GRPC_JSON_STRING, true);
+  json_iterator = grpc_json_create_child(json_iterator, json, "severity",
+                                         severity_string(severity_),
+                                         GRPC_JSON_STRING, false);
+  json_iterator =
+      grpc_json_create_child(json_iterator, json, "timestamp",
+                             fmt_time(timestamp_), GRPC_JSON_STRING, true);
+  if (referenced_tracer_ != nullptr) {
+    char* uuid_str;
+    gpr_asprintf(&uuid_str, "%" PRIdPTR, referenced_tracer_->channel_uuid_);
+    grpc_json* child_ref = grpc_json_create_child(
+        json_iterator, json,
+        (referenced_type_ == Channel) ? "channelRef" : "subchannelRef", nullptr,
+        GRPC_JSON_OBJECT, false);
+    json_iterator = grpc_json_create_child(
+        nullptr, child_ref,
+        (referenced_type_ == Channel) ? "channelId" : "subchannelId", uuid_str,
+        GRPC_JSON_STRING, true);
+    json_iterator = child_ref;
+  }
+}
+
+char* ChannelTrace::RenderTrace() const {
+  if (!max_list_size_)
+    return nullptr;  // tracing is disabled if max_events == 0
+  grpc_json* json = grpc_json_create(GRPC_JSON_OBJECT);
+  char* num_events_logged_str;
+  gpr_asprintf(&num_events_logged_str, "%" PRId64, num_events_logged_);
+  grpc_json* json_iterator = nullptr;
+  json_iterator =
+      grpc_json_create_child(json_iterator, json, "numEventsLogged",
+                             num_events_logged_str, GRPC_JSON_STRING, true);
+  json_iterator =
+      grpc_json_create_child(json_iterator, json, "creationTime",
+                             fmt_time(time_created_), GRPC_JSON_STRING, true);
+  grpc_json* events = grpc_json_create_child(json_iterator, json, "events",
+                                             nullptr, GRPC_JSON_ARRAY, false);
+  json_iterator = nullptr;
+  TraceEvent* it = head_trace_;
+  while (it != nullptr) {
+    json_iterator = grpc_json_create_child(json_iterator, events, nullptr,
+                                           nullptr, GRPC_JSON_OBJECT, false);
+    it->RenderTraceEvent(json_iterator);
+    it = it->next();
+  }
+  char* json_str = grpc_json_dump_to_string(json, 0);
+  grpc_json_destroy(json);
+  return json_str;
+}
+
+}  // namespace grpc_core
diff --git a/src/core/lib/channel/channel_trace.h b/src/core/lib/channel/channel_trace.h
new file mode 100644
index 0000000..1df1e58
--- /dev/null
+++ b/src/core/lib/channel/channel_trace.h
@@ -0,0 +1,133 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACE_H
+#define GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACE_H
+
+#include <grpc/impl/codegen/port_platform.h>
+
+#include <grpc/grpc.h>
+#include "src/core/lib/gprpp/ref_counted.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/json/json.h"
+
+namespace grpc_core {
+
+// Object used to hold live data for a channel. This data is exposed via the
+// channelz service:
+// https://github.com/grpc/proposal/blob/master/A14-channelz.md
+class ChannelTrace : public RefCounted<ChannelTrace> {
+ public:
+  ChannelTrace(size_t max_events);
+  ~ChannelTrace();
+
+  // returns the tracer's uuid
+  intptr_t GetUuid() const;
+
+  enum Severity {
+    Unset = 0,  // never to be used
+    Info,       // we start at 1 to avoid using proto default values
+    Warning,
+    Error
+  };
+
+  // Adds a new trace event to the tracing object
+  //
+  // TODO(ncteisen): as this call is used more and more throughout the gRPC
+  // stack, determine if it makes more sense to accept a char* instead of a
+  // slice.
+  void AddTraceEvent(Severity severity, grpc_slice data);
+
+  // Adds a new trace event to the tracing object. This trace event refers to a
+  // an event on a child of the channel. For example, if this channel has
+  // created a new subchannel, then it would record that with a TraceEvent
+  // referencing the new subchannel.
+  //
+  // TODO(ncteisen): Once channelz is implemented, the events should reference
+  // the overall channelz object, not just the ChannelTrace object.
+  // TODO(ncteisen): as this call is used more and more throughout the gRPC
+  // stack, determine if it makes more sense to accept a char* instead of a
+  // slice.
+  void AddTraceEventReferencingChannel(
+      Severity severity, grpc_slice data,
+      RefCountedPtr<ChannelTrace> referenced_tracer);
+  void AddTraceEventReferencingSubchannel(
+      Severity severity, grpc_slice data,
+      RefCountedPtr<ChannelTrace> referenced_tracer);
+
+  // Returns the tracing data rendered as a grpc json string.
+  // The string is owned by the caller and must be freed.
+  char* RenderTrace() const;
+
+ private:
+  // Types of objects that can be references by trace events.
+  enum ReferencedType { Channel, Subchannel };
+  // Private class to encapsulate all the data and bookkeeping needed for a
+  // a trace event.
+  class TraceEvent {
+   public:
+    // Constructor for a TraceEvent that references a different channel.
+    // TODO(ncteisen): once channelz is implemented, this should reference the
+    // overall channelz object, not just the ChannelTrace object
+    TraceEvent(Severity severity, grpc_slice data,
+               RefCountedPtr<ChannelTrace> referenced_tracer,
+               ReferencedType type);
+
+    // Constructor for a TraceEvent that does not reverence a different
+    // channel.
+    TraceEvent(Severity severity, grpc_slice data);
+
+    ~TraceEvent();
+
+    // Renders the data inside of this TraceEvent into a json object. This is
+    // used by the ChannelTrace, when it is rendering itself.
+    void RenderTraceEvent(grpc_json* json) const;
+
+    // set and get for the next_ pointer.
+    TraceEvent* next() const { return next_; }
+    void set_next(TraceEvent* next) { next_ = next; }
+
+   private:
+    Severity severity_;
+    grpc_slice data_;
+    gpr_timespec timestamp_;
+    TraceEvent* next_;
+    // the tracer object for the (sub)channel that this trace event refers to.
+    RefCountedPtr<ChannelTrace> referenced_tracer_;
+    // the type that the referenced tracer points to. Unused if this trace
+    // does not point to any channel or subchannel
+    ReferencedType referenced_type_;
+  };  // TraceEvent
+
+  // Internal helper to add and link in a trace event
+  void AddTraceEventHelper(TraceEvent* new_trace_event);
+
+  gpr_mu tracer_mu_;
+  intptr_t channel_uuid_;
+  uint64_t num_events_logged_;
+  size_t list_size_;
+  size_t max_list_size_;
+  TraceEvent* head_trace_;
+  TraceEvent* tail_trace_;
+  gpr_timespec time_created_;
+};
+
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACE_H */
diff --git a/src/core/lib/channel/channel_trace_registry.cc b/src/core/lib/channel/channel_trace_registry.cc
new file mode 100644
index 0000000..6c82431
--- /dev/null
+++ b/src/core/lib/channel/channel_trace_registry.cc
@@ -0,0 +1,80 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/impl/codegen/port_platform.h>
+
+#include "src/core/lib/avl/avl.h"
+#include "src/core/lib/channel/channel_trace.h"
+#include "src/core/lib/channel/channel_trace_registry.h"
+#include "src/core/lib/gpr/useful.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+// file global lock and avl.
+static gpr_mu g_mu;
+static grpc_avl g_avl;
+static gpr_atm g_uuid = 0;
+
+// avl vtable for uuid (intptr_t) -> ChannelTrace
+// this table is only looking, it does not own anything.
+static void destroy_intptr(void* not_used, void* user_data) {}
+static void* copy_intptr(void* key, void* user_data) { return key; }
+static long compare_intptr(void* key1, void* key2, void* user_data) {
+  return GPR_ICMP(key1, key2);
+}
+
+static void destroy_channel_trace(void* trace, void* user_data) {}
+static void* copy_channel_trace(void* trace, void* user_data) { return trace; }
+static const grpc_avl_vtable avl_vtable = {
+    destroy_intptr, copy_intptr, compare_intptr, destroy_channel_trace,
+    copy_channel_trace};
+
+void grpc_channel_trace_registry_init() {
+  gpr_mu_init(&g_mu);
+  g_avl = grpc_avl_create(&avl_vtable);
+}
+
+void grpc_channel_trace_registry_shutdown() {
+  grpc_avl_unref(g_avl, nullptr);
+  gpr_mu_destroy(&g_mu);
+}
+
+intptr_t grpc_channel_trace_registry_register_channel_trace(
+    grpc_core::ChannelTrace* channel_trace) {
+  intptr_t prior = gpr_atm_no_barrier_fetch_add(&g_uuid, 1);
+  gpr_mu_lock(&g_mu);
+  g_avl = grpc_avl_add(g_avl, (void*)prior, channel_trace, nullptr);
+  gpr_mu_unlock(&g_mu);
+  return prior;
+}
+
+void grpc_channel_trace_registry_unregister_channel_trace(intptr_t uuid) {
+  gpr_mu_lock(&g_mu);
+  g_avl = grpc_avl_remove(g_avl, (void*)uuid, nullptr);
+  gpr_mu_unlock(&g_mu);
+}
+
+grpc_core::ChannelTrace* grpc_channel_trace_registry_get_channel_trace(
+    intptr_t uuid) {
+  gpr_mu_lock(&g_mu);
+  grpc_core::ChannelTrace* ret = static_cast<grpc_core::ChannelTrace*>(
+      grpc_avl_get(g_avl, (void*)uuid, nullptr));
+  gpr_mu_unlock(&g_mu);
+  return ret;
+}
diff --git a/src/core/lib/channel/channel_trace_registry.h b/src/core/lib/channel/channel_trace_registry.h
new file mode 100644
index 0000000..391ecba
--- /dev/null
+++ b/src/core/lib/channel/channel_trace_registry.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACE_REGISTRY_H
+#define GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACE_REGISTRY_H
+
+#include <grpc/impl/codegen/port_platform.h>
+
+#include "src/core/lib/channel/channel_trace.h"
+
+#include <stdint.h>
+
+// TODO(ncteisen): convert this file to C++
+
+void grpc_channel_trace_registry_init();
+void grpc_channel_trace_registry_shutdown();
+
+// globally registers a ChannelTrace. Returns its unique uuid
+intptr_t grpc_channel_trace_registry_register_channel_trace(
+    grpc_core::ChannelTrace* channel_trace);
+// globally unregisters the ChannelTrace that is associated to uuid.
+void grpc_channel_trace_registry_unregister_channel_trace(intptr_t uuid);
+// if object with uuid has previously been registered, returns the ChannelTrace
+// associated with that uuid. Else returns nullptr.
+grpc_core::ChannelTrace* grpc_channel_trace_registry_get_channel_trace(
+    intptr_t uuid);
+
+#endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACE_REGISTRY_H */
diff --git a/src/core/lib/channel/connected_channel.cc b/src/core/lib/channel/connected_channel.cc
index fb26bdf..ddd3029 100644
--- a/src/core/lib/channel/connected_channel.cc
+++ b/src/core/lib/channel/connected_channel.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/channel/connected_channel.h"
 
 #include <stdarg.h>
@@ -52,7 +54,7 @@
 } call_data;
 
 static void run_in_call_combiner(void* arg, grpc_error* error) {
-  callback_state* state = (callback_state*)arg;
+  callback_state* state = static_cast<callback_state*>(arg);
   GRPC_CALL_COMBINER_START(state->call_combiner, state->original_closure,
                            GRPC_ERROR_REF(error), state->reason);
 }
@@ -96,8 +98,8 @@
    into transport stream operations */
 static void con_start_transport_stream_op_batch(
     grpc_call_element* elem, grpc_transport_stream_op_batch* batch) {
-  call_data* calld = (call_data*)elem->call_data;
-  channel_data* chand = (channel_data*)elem->channel_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   if (batch->recv_initial_metadata) {
     callback_state* state = &calld->recv_initial_metadata_ready;
     intercept_callback(
@@ -115,7 +117,8 @@
     // calld->on_complete like we can for the other ops.  However,
     // cancellation isn't in the fast path, so we just allocate a new
     // closure for each one.
-    callback_state* state = (callback_state*)gpr_malloc(sizeof(*state));
+    callback_state* state =
+        static_cast<callback_state*>(gpr_malloc(sizeof(*state)));
     intercept_callback(calld, state, true, "on_complete (cancel_stream)",
                        &batch->on_complete);
   } else {
@@ -129,15 +132,15 @@
 
 static void con_start_transport_op(grpc_channel_element* elem,
                                    grpc_transport_op* op) {
-  channel_data* chand = (channel_data*)elem->channel_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   grpc_transport_perform_op(chand->transport, op);
 }
 
 /* Constructor for call_data */
 static grpc_error* init_call_elem(grpc_call_element* elem,
                                   const grpc_call_element_args* args) {
-  call_data* calld = (call_data*)elem->call_data;
-  channel_data* chand = (channel_data*)elem->channel_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   calld->call_combiner = args->call_combiner;
   int r = grpc_transport_init_stream(
       chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld),
@@ -149,8 +152,8 @@
 
 static void set_pollset_or_pollset_set(grpc_call_element* elem,
                                        grpc_polling_entity* pollent) {
-  call_data* calld = (call_data*)elem->call_data;
-  channel_data* chand = (channel_data*)elem->channel_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   grpc_transport_set_pops(chand->transport,
                           TRANSPORT_STREAM_FROM_CALL_DATA(calld), pollent);
 }
@@ -159,8 +162,8 @@
 static void destroy_call_elem(grpc_call_element* elem,
                               const grpc_call_final_info* final_info,
                               grpc_closure* then_schedule_closure) {
-  call_data* calld = (call_data*)elem->call_data;
-  channel_data* chand = (channel_data*)elem->channel_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   grpc_transport_destroy_stream(chand->transport,
                                 TRANSPORT_STREAM_FROM_CALL_DATA(calld),
                                 then_schedule_closure);
@@ -169,7 +172,7 @@
 /* Constructor for channel_data */
 static grpc_error* init_channel_elem(grpc_channel_element* elem,
                                      grpc_channel_element_args* args) {
-  channel_data* cd = (channel_data*)elem->channel_data;
+  channel_data* cd = static_cast<channel_data*>(elem->channel_data);
   GPR_ASSERT(args->is_last);
   cd->transport = nullptr;
   return GRPC_ERROR_NONE;
@@ -177,7 +180,7 @@
 
 /* Destructor for channel_data */
 static void destroy_channel_elem(grpc_channel_element* elem) {
-  channel_data* cd = (channel_data*)elem->channel_data;
+  channel_data* cd = static_cast<channel_data*>(elem->channel_data);
   if (cd->transport) {
     grpc_transport_destroy(cd->transport);
   }
@@ -203,10 +206,10 @@
 
 static void bind_transport(grpc_channel_stack* channel_stack,
                            grpc_channel_element* elem, void* t) {
-  channel_data* cd = (channel_data*)elem->channel_data;
+  channel_data* cd = static_cast<channel_data*>(elem->channel_data);
   GPR_ASSERT(elem->filter == &grpc_connected_filter);
   GPR_ASSERT(cd->transport == nullptr);
-  cd->transport = (grpc_transport*)t;
+  cd->transport = static_cast<grpc_transport*>(t);
 
   /* HACK(ctiller): increase call stack size for the channel to make space
      for channel data. We need a cleaner (but performant) way to do this,
@@ -215,7 +218,7 @@
      the last call element, and the last call element MUST be the connected
      channel. */
   channel_stack->call_stack_size +=
-      grpc_transport_stream_size((grpc_transport*)t);
+      grpc_transport_stream_size(static_cast<grpc_transport*>(t));
 }
 
 bool grpc_add_connected_filter(grpc_channel_stack_builder* builder,
@@ -228,6 +231,6 @@
 }
 
 grpc_stream* grpc_connected_channel_get_stream(grpc_call_element* elem) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   return TRANSPORT_STREAM_FROM_CALL_DATA(calld);
 }
diff --git a/src/core/lib/channel/connected_channel.h b/src/core/lib/channel/connected_channel.h
index 91de802..faa1c73 100644
--- a/src/core/lib/channel/connected_channel.h
+++ b/src/core/lib/channel/connected_channel.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_CHANNEL_CONNECTED_CHANNEL_H
 #define GRPC_CORE_LIB_CHANNEL_CONNECTED_CHANNEL_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/channel/channel_stack_builder.h"
 
 extern const grpc_channel_filter grpc_connected_filter;
diff --git a/src/core/lib/channel/handshaker.cc b/src/core/lib/channel/handshaker.cc
index dcb149c..9b1af8d 100644
--- a/src/core/lib/channel/handshaker.cc
+++ b/src/core/lib/channel/handshaker.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <string.h>
 
 #include <grpc/support/alloc.h>
@@ -81,8 +83,8 @@
 };
 
 grpc_handshake_manager* grpc_handshake_manager_create() {
-  grpc_handshake_manager* mgr =
-      (grpc_handshake_manager*)gpr_zalloc(sizeof(grpc_handshake_manager));
+  grpc_handshake_manager* mgr = static_cast<grpc_handshake_manager*>(
+      gpr_zalloc(sizeof(grpc_handshake_manager)));
   gpr_mu_init(&mgr->mu);
   gpr_ref_init(&mgr->refs, 1);
   return mgr;
@@ -135,8 +137,8 @@
     realloc_count = mgr->count * 2;
   }
   if (realloc_count > 0) {
-    mgr->handshakers = (grpc_handshaker**)gpr_realloc(
-        mgr->handshakers, realloc_count * sizeof(grpc_handshaker*));
+    mgr->handshakers = static_cast<grpc_handshaker**>(gpr_realloc(
+        mgr->handshakers, realloc_count * sizeof(grpc_handshaker*)));
   }
   mgr->handshakers[mgr->count++] = handshaker;
   gpr_mu_unlock(&mgr->mu);
@@ -197,7 +199,7 @@
 // A function used as the handshaker-done callback when chaining
 // handshakers together.
 static void call_next_handshaker(void* arg, grpc_error* error) {
-  grpc_handshake_manager* mgr = (grpc_handshake_manager*)arg;
+  grpc_handshake_manager* mgr = static_cast<grpc_handshake_manager*>(arg);
   gpr_mu_lock(&mgr->mu);
   bool done = call_next_handshaker_locked(mgr, GRPC_ERROR_REF(error));
   gpr_mu_unlock(&mgr->mu);
@@ -211,7 +213,7 @@
 
 // Callback invoked when deadline is exceeded.
 static void on_timeout(void* arg, grpc_error* error) {
-  grpc_handshake_manager* mgr = (grpc_handshake_manager*)arg;
+  grpc_handshake_manager* mgr = static_cast<grpc_handshake_manager*>(arg);
   if (error == GRPC_ERROR_NONE) {  // Timer fired, rather than being cancelled.
     grpc_handshake_manager_shutdown(
         mgr, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshake timed out"));
@@ -233,8 +235,8 @@
   mgr->args.endpoint = endpoint;
   mgr->args.args = grpc_channel_args_copy(channel_args);
   mgr->args.user_data = user_data;
-  mgr->args.read_buffer =
-      (grpc_slice_buffer*)gpr_malloc(sizeof(*mgr->args.read_buffer));
+  mgr->args.read_buffer = static_cast<grpc_slice_buffer*>(
+      gpr_malloc(sizeof(*mgr->args.read_buffer)));
   grpc_slice_buffer_init(mgr->args.read_buffer);
   // Initialize state needed for calling handshakers.
   mgr->acceptor = acceptor;
diff --git a/src/core/lib/channel/handshaker.h b/src/core/lib/channel/handshaker.h
index 68e5463..dfecd81 100644
--- a/src/core/lib/channel/handshaker.h
+++ b/src/core/lib/channel/handshaker.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_CHANNEL_HANDSHAKER_H
 #define GRPC_CORE_LIB_CHANNEL_HANDSHAKER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/grpc_types.h>
 
 #include "src/core/lib/iomgr/closure.h"
diff --git a/src/core/lib/channel/handshaker_factory.cc b/src/core/lib/channel/handshaker_factory.cc
index 2380d98..4fd4363 100644
--- a/src/core/lib/channel/handshaker_factory.cc
+++ b/src/core/lib/channel/handshaker_factory.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/channel/handshaker_factory.h"
 
 #include <grpc/support/log.h>
diff --git a/src/core/lib/channel/handshaker_factory.h b/src/core/lib/channel/handshaker_factory.h
index 8a7c015..3e45fcf 100644
--- a/src/core/lib/channel/handshaker_factory.h
+++ b/src/core/lib/channel/handshaker_factory.h
@@ -19,10 +19,11 @@
 #ifndef GRPC_CORE_LIB_CHANNEL_HANDSHAKER_FACTORY_H
 #define GRPC_CORE_LIB_CHANNEL_HANDSHAKER_FACTORY_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/grpc_types.h>
 
 #include "src/core/lib/channel/handshaker.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
 
 // A handshaker factory is used to create handshakers.
 
diff --git a/src/core/lib/channel/handshaker_registry.cc b/src/core/lib/channel/handshaker_registry.cc
index 098eabf..eec3e1b 100644
--- a/src/core/lib/channel/handshaker_registry.cc
+++ b/src/core/lib/channel/handshaker_registry.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/channel/handshaker_registry.h"
 
 #include <string.h>
@@ -34,8 +36,9 @@
 static void grpc_handshaker_factory_list_register(
     grpc_handshaker_factory_list* list, bool at_start,
     grpc_handshaker_factory* factory) {
-  list->list = (grpc_handshaker_factory**)gpr_realloc(
-      list->list, (list->num_factories + 1) * sizeof(grpc_handshaker_factory*));
+  list->list = static_cast<grpc_handshaker_factory**>(gpr_realloc(
+      list->list,
+      (list->num_factories + 1) * sizeof(grpc_handshaker_factory*)));
   if (at_start) {
     memmove(list->list + 1, list->list,
             sizeof(grpc_handshaker_factory*) * list->num_factories);
diff --git a/src/core/lib/channel/handshaker_registry.h b/src/core/lib/channel/handshaker_registry.h
index 0b05531..82ad9c5 100644
--- a/src/core/lib/channel/handshaker_registry.h
+++ b/src/core/lib/channel/handshaker_registry.h
@@ -19,10 +19,11 @@
 #ifndef GRPC_CORE_LIB_CHANNEL_HANDSHAKER_REGISTRY_H
 #define GRPC_CORE_LIB_CHANNEL_HANDSHAKER_REGISTRY_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/grpc_types.h>
 
 #include "src/core/lib/channel/handshaker_factory.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
 
 typedef enum {
   HANDSHAKER_CLIENT = 0,
diff --git a/src/core/lib/channel/status_util.cc b/src/core/lib/channel/status_util.cc
new file mode 100644
index 0000000..563db40
--- /dev/null
+++ b/src/core/lib/channel/status_util.cc
@@ -0,0 +1,100 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/lib/channel/status_util.h"
+
+#include "src/core/lib/gpr/useful.h"
+
+typedef struct {
+  const char* str;
+  grpc_status_code status;
+} status_string_entry;
+
+static const status_string_entry g_status_string_entries[] = {
+    {"OK", GRPC_STATUS_OK},
+    {"CANCELLED", GRPC_STATUS_CANCELLED},
+    {"UNKNOWN", GRPC_STATUS_UNKNOWN},
+    {"INVALID_ARGUMENT", GRPC_STATUS_INVALID_ARGUMENT},
+    {"DEADLINE_EXCEEDED", GRPC_STATUS_DEADLINE_EXCEEDED},
+    {"NOT_FOUND", GRPC_STATUS_NOT_FOUND},
+    {"ALREADY_EXISTS", GRPC_STATUS_ALREADY_EXISTS},
+    {"PERMISSION_DENIED", GRPC_STATUS_PERMISSION_DENIED},
+    {"UNAUTHENTICATED", GRPC_STATUS_UNAUTHENTICATED},
+    {"RESOURCE_EXHAUSTED", GRPC_STATUS_RESOURCE_EXHAUSTED},
+    {"FAILED_PRECONDITION", GRPC_STATUS_FAILED_PRECONDITION},
+    {"ABORTED", GRPC_STATUS_ABORTED},
+    {"OUT_OF_RANGE", GRPC_STATUS_OUT_OF_RANGE},
+    {"UNIMPLEMENTED", GRPC_STATUS_UNIMPLEMENTED},
+    {"INTERNAL", GRPC_STATUS_INTERNAL},
+    {"UNAVAILABLE", GRPC_STATUS_UNAVAILABLE},
+    {"DATA_LOSS", GRPC_STATUS_DATA_LOSS},
+};
+
+bool grpc_status_code_from_string(const char* status_str,
+                                  grpc_status_code* status) {
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(g_status_string_entries); ++i) {
+    if (strcmp(status_str, g_status_string_entries[i].str) == 0) {
+      *status = g_status_string_entries[i].status;
+      return true;
+    }
+  }
+  return false;
+}
+
+const char* grpc_status_code_to_string(grpc_status_code status) {
+  switch (status) {
+    case GRPC_STATUS_OK:
+      return "OK";
+    case GRPC_STATUS_CANCELLED:
+      return "CANCELLED";
+    case GRPC_STATUS_UNKNOWN:
+      return "UNKNOWN";
+    case GRPC_STATUS_INVALID_ARGUMENT:
+      return "INVALID_ARGUMENT";
+    case GRPC_STATUS_DEADLINE_EXCEEDED:
+      return "DEADLINE_EXCEEDED";
+    case GRPC_STATUS_NOT_FOUND:
+      return "NOT_FOUND";
+    case GRPC_STATUS_ALREADY_EXISTS:
+      return "ALREADY_EXISTS";
+    case GRPC_STATUS_PERMISSION_DENIED:
+      return "PERMISSION_DENIED";
+    case GRPC_STATUS_UNAUTHENTICATED:
+      return "UNAUTHENTICATED";
+    case GRPC_STATUS_RESOURCE_EXHAUSTED:
+      return "RESOURCE_EXHAUSTED";
+    case GRPC_STATUS_FAILED_PRECONDITION:
+      return "FAILED_PRECONDITION";
+    case GRPC_STATUS_ABORTED:
+      return "ABORTED";
+    case GRPC_STATUS_OUT_OF_RANGE:
+      return "OUT_OF_RANGE";
+    case GRPC_STATUS_UNIMPLEMENTED:
+      return "UNIMPLEMENTED";
+    case GRPC_STATUS_INTERNAL:
+      return "INTERNAL";
+    case GRPC_STATUS_UNAVAILABLE:
+      return "UNAVAILABLE";
+    case GRPC_STATUS_DATA_LOSS:
+      return "DATA_LOSS";
+    default:
+      return "UNKNOWN";
+  }
+}
diff --git a/src/core/lib/channel/status_util.h b/src/core/lib/channel/status_util.h
new file mode 100644
index 0000000..5409de6
--- /dev/null
+++ b/src/core/lib/channel/status_util.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_LIB_CHANNEL_STATUS_UTIL_H
+#define GRPC_CORE_LIB_CHANNEL_STATUS_UTIL_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/status.h>
+
+#include <stdbool.h>
+#include <string.h>
+
+/// If \a status_str is a valid status string, sets \a status to the
+/// corresponding status value and returns true.
+bool grpc_status_code_from_string(const char* status_str,
+                                  grpc_status_code* status);
+
+/// Returns the string form of \a status, or "UNKNOWN" if invalid.
+const char* grpc_status_code_to_string(grpc_status_code status);
+
+namespace grpc_core {
+namespace internal {
+
+/// A set of grpc_status_code values.
+class StatusCodeSet {
+ public:
+  bool Empty() const { return status_code_mask_ == 0; }
+
+  void Add(grpc_status_code status) { status_code_mask_ |= (1 << status); }
+
+  bool Contains(grpc_status_code status) const {
+    return status_code_mask_ & (1 << status);
+  }
+
+ private:
+  int status_code_mask_ = 0;  // A bitfield of status codes in the set.
+};
+
+}  // namespace internal
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_CHANNEL_STATUS_UTIL_H */
diff --git a/src/core/lib/compression/algorithm_metadata.h b/src/core/lib/compression/algorithm_metadata.h
index 7db771e..1be79e5 100644
--- a/src/core/lib/compression/algorithm_metadata.h
+++ b/src/core/lib/compression/algorithm_metadata.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_COMPRESSION_ALGORITHM_METADATA_H
 #define GRPC_CORE_LIB_COMPRESSION_ALGORITHM_METADATA_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/compression.h>
 #include "src/core/lib/compression/compression_internal.h"
 #include "src/core/lib/transport/metadata.h"
diff --git a/src/core/lib/compression/compression.cc b/src/core/lib/compression/compression.cc
index 99e6014..4871754 100644
--- a/src/core/lib/compression/compression.cc
+++ b/src/core/lib/compression/compression.cc
@@ -16,21 +16,22 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <stdlib.h>
 #include <string.h>
 
 #include <grpc/compression.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/compression/algorithm_metadata.h"
 #include "src/core/lib/compression/compression_internal.h"
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/transport/static_metadata.h"
 
 int grpc_compression_algorithm_is_message(
     grpc_compression_algorithm algorithm) {
-  return (algorithm >= GRPC_COMPRESS_MESSAGE_DEFLATE &&
-          algorithm <= GRPC_COMPRESS_MESSAGE_GZIP)
+  return (algorithm >= GRPC_COMPRESS_DEFLATE && algorithm <= GRPC_COMPRESS_GZIP)
              ? 1
              : 0;
 }
@@ -44,11 +45,11 @@
   if (grpc_slice_eq(name, GRPC_MDSTR_IDENTITY)) {
     *algorithm = GRPC_COMPRESS_NONE;
     return 1;
-  } else if (grpc_slice_eq(name, GRPC_MDSTR_MESSAGE_SLASH_DEFLATE)) {
-    *algorithm = GRPC_COMPRESS_MESSAGE_DEFLATE;
+  } else if (grpc_slice_eq(name, GRPC_MDSTR_DEFLATE)) {
+    *algorithm = GRPC_COMPRESS_DEFLATE;
     return 1;
-  } else if (grpc_slice_eq(name, GRPC_MDSTR_MESSAGE_SLASH_GZIP)) {
-    *algorithm = GRPC_COMPRESS_MESSAGE_GZIP;
+  } else if (grpc_slice_eq(name, GRPC_MDSTR_GZIP)) {
+    *algorithm = GRPC_COMPRESS_GZIP;
     return 1;
   } else if (grpc_slice_eq(name, GRPC_MDSTR_STREAM_SLASH_GZIP)) {
     *algorithm = GRPC_COMPRESS_STREAM_GZIP;
@@ -67,11 +68,11 @@
     case GRPC_COMPRESS_NONE:
       *name = "identity";
       return 1;
-    case GRPC_COMPRESS_MESSAGE_DEFLATE:
-      *name = "message/deflate";
+    case GRPC_COMPRESS_DEFLATE:
+      *name = "deflate";
       return 1;
-    case GRPC_COMPRESS_MESSAGE_GZIP:
-      *name = "message/gzip";
+    case GRPC_COMPRESS_GZIP:
+      *name = "gzip";
       return 1;
     case GRPC_COMPRESS_STREAM_GZIP:
       *name = "stream/gzip";
@@ -133,10 +134,10 @@
   switch (algorithm) {
     case GRPC_COMPRESS_NONE:
       return GRPC_MDSTR_IDENTITY;
-    case GRPC_COMPRESS_MESSAGE_DEFLATE:
-      return GRPC_MDSTR_MESSAGE_SLASH_DEFLATE;
-    case GRPC_COMPRESS_MESSAGE_GZIP:
-      return GRPC_MDSTR_MESSAGE_SLASH_GZIP;
+    case GRPC_COMPRESS_DEFLATE:
+      return GRPC_MDSTR_DEFLATE;
+    case GRPC_COMPRESS_GZIP:
+      return GRPC_MDSTR_GZIP;
     case GRPC_COMPRESS_STREAM_GZIP:
       return GRPC_MDSTR_STREAM_SLASH_GZIP;
     case GRPC_COMPRESS_ALGORITHMS_COUNT:
@@ -148,10 +149,8 @@
 grpc_compression_algorithm grpc_compression_algorithm_from_slice(
     grpc_slice str) {
   if (grpc_slice_eq(str, GRPC_MDSTR_IDENTITY)) return GRPC_COMPRESS_NONE;
-  if (grpc_slice_eq(str, GRPC_MDSTR_MESSAGE_SLASH_DEFLATE))
-    return GRPC_COMPRESS_MESSAGE_DEFLATE;
-  if (grpc_slice_eq(str, GRPC_MDSTR_MESSAGE_SLASH_GZIP))
-    return GRPC_COMPRESS_MESSAGE_GZIP;
+  if (grpc_slice_eq(str, GRPC_MDSTR_DEFLATE)) return GRPC_COMPRESS_DEFLATE;
+  if (grpc_slice_eq(str, GRPC_MDSTR_GZIP)) return GRPC_COMPRESS_GZIP;
   if (grpc_slice_eq(str, GRPC_MDSTR_STREAM_SLASH_GZIP))
     return GRPC_COMPRESS_STREAM_GZIP;
   return GRPC_COMPRESS_ALGORITHMS_COUNT;
@@ -162,9 +161,9 @@
   switch (algorithm) {
     case GRPC_COMPRESS_NONE:
       return GRPC_MDELEM_GRPC_ENCODING_IDENTITY;
-    case GRPC_COMPRESS_MESSAGE_DEFLATE:
+    case GRPC_COMPRESS_DEFLATE:
       return GRPC_MDELEM_GRPC_ENCODING_DEFLATE;
-    case GRPC_COMPRESS_MESSAGE_GZIP:
+    case GRPC_COMPRESS_GZIP:
       return GRPC_MDELEM_GRPC_ENCODING_GZIP;
     case GRPC_COMPRESS_STREAM_GZIP:
       return GRPC_MDELEM_GRPC_ENCODING_GZIP;
diff --git a/src/core/lib/compression/compression_internal.cc b/src/core/lib/compression/compression_internal.cc
index 263cdf0..538514c 100644
--- a/src/core/lib/compression/compression_internal.cc
+++ b/src/core/lib/compression/compression_internal.cc
@@ -16,14 +16,16 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <stdlib.h>
 #include <string.h>
 
 #include <grpc/compression.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/compression/algorithm_metadata.h"
 #include "src/core/lib/compression/compression_internal.h"
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/transport/static_metadata.h"
 
@@ -80,9 +82,9 @@
 grpc_compression_algorithm_to_message_compression_algorithm(
     grpc_compression_algorithm algo) {
   switch (algo) {
-    case GRPC_COMPRESS_MESSAGE_DEFLATE:
+    case GRPC_COMPRESS_DEFLATE:
       return GRPC_MESSAGE_COMPRESS_DEFLATE;
-    case GRPC_COMPRESS_MESSAGE_GZIP:
+    case GRPC_COMPRESS_GZIP:
       return GRPC_MESSAGE_COMPRESS_GZIP;
     default:
       return GRPC_MESSAGE_COMPRESS_NONE;
@@ -147,10 +149,10 @@
         *algorithm = GRPC_COMPRESS_NONE;
         return 1;
       case GRPC_MESSAGE_COMPRESS_DEFLATE:
-        *algorithm = GRPC_COMPRESS_MESSAGE_DEFLATE;
+        *algorithm = GRPC_COMPRESS_DEFLATE;
         return 1;
       case GRPC_MESSAGE_COMPRESS_GZIP:
-        *algorithm = GRPC_COMPRESS_MESSAGE_GZIP;
+        *algorithm = GRPC_COMPRESS_GZIP;
         return 1;
       default:
         *algorithm = GRPC_COMPRESS_NONE;
@@ -190,7 +192,8 @@
   GRPC_API_TRACE("grpc_message_compression_algorithm_for_level(level=%d)", 1,
                  ((int)level));
   if (level > GRPC_COMPRESS_LEVEL_HIGH) {
-    gpr_log(GPR_ERROR, "Unknown message compression level %d.", (int)level);
+    gpr_log(GPR_ERROR, "Unknown message compression level %d.",
+            static_cast<int>(level));
     abort();
   }
 
diff --git a/src/core/lib/compression/compression_internal.h b/src/core/lib/compression/compression_internal.h
index 72f01dd..da00736 100644
--- a/src/core/lib/compression/compression_internal.h
+++ b/src/core/lib/compression/compression_internal.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_COMPRESSION_COMPRESSION_INTERNAL_H
 #define GRPC_CORE_LIB_COMPRESSION_COMPRESSION_INTERNAL_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/compression_types.h>
 
 #ifdef __cplusplus
diff --git a/src/core/lib/compression/compression_ruby.cc b/src/core/lib/compression/compression_ruby.cc
deleted file mode 100644
index 293062f..0000000
--- a/src/core/lib/compression/compression_ruby.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- *
- * Copyright 2017 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <grpc/compression_ruby.h>
-#include <grpc/support/useful.h>
-
-#include "src/core/lib/surface/api_trace.h"
-#include "src/core/lib/transport/static_metadata.h"
-
-int grpc_compression_algorithm_parse_ruby(
-    grpc_slice name, grpc_compression_algorithm* algorithm) {
-  if (grpc_slice_eq(name, GRPC_MDSTR_IDENTITY)) {
-    *algorithm = GRPC_COMPRESS_NONE;
-    return 1;
-  } else if (grpc_slice_eq(name, GRPC_MDSTR_DEFLATE)) {
-    *algorithm = GRPC_COMPRESS_MESSAGE_DEFLATE;
-    return 1;
-  } else if (grpc_slice_eq(name, GRPC_MDSTR_GZIP)) {
-    *algorithm = GRPC_COMPRESS_MESSAGE_GZIP;
-    return 1;
-  } else if (grpc_slice_eq(name, GRPC_MDSTR_STREAM_SLASH_GZIP)) {
-    *algorithm = GRPC_COMPRESS_STREAM_GZIP;
-    return 1;
-  } else {
-    return 0;
-  }
-  return 0;
-}
-
-int grpc_compression_algorithm_name_ruby(grpc_compression_algorithm algorithm,
-                                         const char** name) {
-  GRPC_API_TRACE("grpc_compression_algorithm_parse(algorithm=%d, name=%p)", 2,
-                 ((int)algorithm, name));
-  switch (algorithm) {
-    case GRPC_COMPRESS_NONE:
-      *name = "identity";
-      return 1;
-    case GRPC_COMPRESS_MESSAGE_DEFLATE:
-      *name = "deflate";
-      return 1;
-    case GRPC_COMPRESS_MESSAGE_GZIP:
-      *name = "gzip";
-      return 1;
-    case GRPC_COMPRESS_STREAM_GZIP:
-      *name = "stream/gzip";
-      return 1;
-    case GRPC_COMPRESS_ALGORITHMS_COUNT:
-      return 0;
-  }
-  return 0;
-}
diff --git a/src/core/lib/compression/message_compress.cc b/src/core/lib/compression/message_compress.cc
index 1e9b0f1..e06454f 100644
--- a/src/core/lib/compression/message_compress.cc
+++ b/src/core/lib/compression/message_compress.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/compression/message_compress.h"
 
 #include <string.h>
@@ -36,23 +38,23 @@
   int flush;
   size_t i;
   grpc_slice outbuf = GRPC_SLICE_MALLOC(OUTPUT_BLOCK_SIZE);
-  const uInt uint_max = ~(uInt)0;
+  const uInt uint_max = ~static_cast<uInt>(0);
 
   GPR_ASSERT(GRPC_SLICE_LENGTH(outbuf) <= uint_max);
-  zs->avail_out = (uInt)GRPC_SLICE_LENGTH(outbuf);
+  zs->avail_out = static_cast<uInt> GRPC_SLICE_LENGTH(outbuf);
   zs->next_out = GRPC_SLICE_START_PTR(outbuf);
   flush = Z_NO_FLUSH;
   for (i = 0; i < input->count; i++) {
     if (i == input->count - 1) flush = Z_FINISH;
     GPR_ASSERT(GRPC_SLICE_LENGTH(input->slices[i]) <= uint_max);
-    zs->avail_in = (uInt)GRPC_SLICE_LENGTH(input->slices[i]);
+    zs->avail_in = static_cast<uInt> GRPC_SLICE_LENGTH(input->slices[i]);
     zs->next_in = GRPC_SLICE_START_PTR(input->slices[i]);
     do {
       if (zs->avail_out == 0) {
         grpc_slice_buffer_add_indexed(output, outbuf);
         outbuf = GRPC_SLICE_MALLOC(OUTPUT_BLOCK_SIZE);
         GPR_ASSERT(GRPC_SLICE_LENGTH(outbuf) <= uint_max);
-        zs->avail_out = (uInt)GRPC_SLICE_LENGTH(outbuf);
+        zs->avail_out = static_cast<uInt> GRPC_SLICE_LENGTH(outbuf);
         zs->next_out = GRPC_SLICE_START_PTR(outbuf);
       }
       r = flate(zs, flush);
diff --git a/src/core/lib/compression/message_compress.h b/src/core/lib/compression/message_compress.h
index ed9e5bf..91654e4 100644
--- a/src/core/lib/compression/message_compress.h
+++ b/src/core/lib/compression/message_compress.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_COMPRESSION_MESSAGE_COMPRESS_H
 #define GRPC_CORE_LIB_COMPRESSION_MESSAGE_COMPRESS_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice_buffer.h>
 
 #include "src/core/lib/compression/compression_internal.h"
diff --git a/src/core/lib/compression/stream_compression.cc b/src/core/lib/compression/stream_compression.cc
index b4b3e52..46cb3da 100644
--- a/src/core/lib/compression/stream_compression.cc
+++ b/src/core/lib/compression/stream_compression.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/log.h>
 
 #include "src/core/lib/compression/stream_compression.h"
diff --git a/src/core/lib/compression/stream_compression.h b/src/core/lib/compression/stream_compression.h
index 8322835..c80f2f8 100644
--- a/src/core/lib/compression/stream_compression.h
+++ b/src/core/lib/compression/stream_compression.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_COMPRESSION_STREAM_COMPRESSION_H
 #define GRPC_CORE_LIB_COMPRESSION_STREAM_COMPRESSION_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stdbool.h>
 
 #include <grpc/slice_buffer.h>
diff --git a/src/core/lib/compression/stream_compression_gzip.cc b/src/core/lib/compression/stream_compression_gzip.cc
index 897f391..682f712 100644
--- a/src/core/lib/compression/stream_compression_gzip.cc
+++ b/src/core/lib/compression/stream_compression_gzip.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
@@ -48,11 +50,11 @@
     size_t slice_size = max_output_size < OUTPUT_BLOCK_SIZE ? max_output_size
                                                             : OUTPUT_BLOCK_SIZE;
     grpc_slice slice_out = GRPC_SLICE_MALLOC(slice_size);
-    ctx->zs.avail_out = (uInt)slice_size;
+    ctx->zs.avail_out = static_cast<uInt>(slice_size);
     ctx->zs.next_out = GRPC_SLICE_START_PTR(slice_out);
     while (ctx->zs.avail_out > 0 && in->length > 0 && !eoc) {
       grpc_slice slice = grpc_slice_buffer_take_first(in);
-      ctx->zs.avail_in = (uInt)GRPC_SLICE_LENGTH(slice);
+      ctx->zs.avail_in = static_cast<uInt> GRPC_SLICE_LENGTH(slice);
       ctx->zs.next_in = GRPC_SLICE_START_PTR(slice);
       r = ctx->flate(&ctx->zs, Z_NO_FLUSH);
       if (r < 0 && r != Z_BUF_ERROR) {
@@ -142,7 +144,7 @@
     return false;
   }
   grpc_stream_compression_context_gzip* gzip_ctx =
-      (grpc_stream_compression_context_gzip*)ctx;
+      reinterpret_cast<grpc_stream_compression_context_gzip*>(ctx);
   GPR_ASSERT(gzip_ctx->flate == deflate);
   int gzip_flush;
   switch (flush) {
@@ -172,7 +174,7 @@
     return false;
   }
   grpc_stream_compression_context_gzip* gzip_ctx =
-      (grpc_stream_compression_context_gzip*)ctx;
+      reinterpret_cast<grpc_stream_compression_context_gzip*>(ctx);
   GPR_ASSERT(gzip_ctx->flate == inflate);
   return gzip_flate(gzip_ctx, in, out, output_size, max_output_size,
                     Z_SYNC_FLUSH, end_of_context);
@@ -184,8 +186,8 @@
   GPR_ASSERT(method == GRPC_STREAM_COMPRESSION_GZIP_COMPRESS ||
              method == GRPC_STREAM_COMPRESSION_GZIP_DECOMPRESS);
   grpc_stream_compression_context_gzip* gzip_ctx =
-      (grpc_stream_compression_context_gzip*)gpr_zalloc(
-          sizeof(grpc_stream_compression_context_gzip));
+      static_cast<grpc_stream_compression_context_gzip*>(
+          gpr_zalloc(sizeof(grpc_stream_compression_context_gzip)));
   int r;
   if (gzip_ctx == nullptr) {
     return nullptr;
@@ -204,7 +206,7 @@
   }
 
   gzip_ctx->base.vtable = &grpc_stream_compression_gzip_vtable;
-  return (grpc_stream_compression_context*)gzip_ctx;
+  return reinterpret_cast<grpc_stream_compression_context*>(gzip_ctx);
 }
 
 static void grpc_stream_compression_context_destroy_gzip(
@@ -213,7 +215,7 @@
     return;
   }
   grpc_stream_compression_context_gzip* gzip_ctx =
-      (grpc_stream_compression_context_gzip*)ctx;
+      reinterpret_cast<grpc_stream_compression_context_gzip*>(ctx);
   if (gzip_ctx->flate == inflate) {
     inflateEnd(&gzip_ctx->zs);
   } else {
diff --git a/src/core/lib/compression/stream_compression_gzip.h b/src/core/lib/compression/stream_compression_gzip.h
index 7cf49a0..740f097 100644
--- a/src/core/lib/compression/stream_compression_gzip.h
+++ b/src/core/lib/compression/stream_compression_gzip.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_COMPRESSION_STREAM_COMPRESSION_GZIP_H
 #define GRPC_CORE_LIB_COMPRESSION_STREAM_COMPRESSION_GZIP_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/compression/stream_compression.h"
 
 extern const grpc_stream_compression_vtable grpc_stream_compression_gzip_vtable;
diff --git a/src/core/lib/compression/stream_compression_identity.cc b/src/core/lib/compression/stream_compression_identity.cc
index af40511..b798139 100644
--- a/src/core/lib/compression/stream_compression_identity.cc
+++ b/src/core/lib/compression/stream_compression_identity.cc
@@ -16,11 +16,12 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
 #include "src/core/lib/compression/stream_compression_identity.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/slice/slice_internal.h"
 
 #define OUTPUT_BLOCK_SIZE (1024)
@@ -79,7 +80,7 @@
   GPR_ASSERT(method == GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS ||
              method == GRPC_STREAM_COMPRESSION_IDENTITY_DECOMPRESS);
   /* No context needed in this case. Use fake context instead. */
-  return (grpc_stream_compression_context*)&identity_ctx;
+  return &identity_ctx;
 }
 
 static void grpc_stream_compression_context_destroy_identity(
diff --git a/src/core/lib/compression/stream_compression_identity.h b/src/core/lib/compression/stream_compression_identity.h
index 41926e9..cc77b63 100644
--- a/src/core/lib/compression/stream_compression_identity.h
+++ b/src/core/lib/compression/stream_compression_identity.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_COMPRESSION_STREAM_COMPRESSION_IDENTITY_H
 #define GRPC_CORE_LIB_COMPRESSION_STREAM_COMPRESSION_IDENTITY_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/compression/stream_compression.h"
 
 extern const grpc_stream_compression_vtable
diff --git a/src/core/lib/debug/stats.cc b/src/core/lib/debug/stats.cc
index 465c761..d8ddf03 100644
--- a/src/core/lib/debug/stats.cc
+++ b/src/core/lib/debug/stats.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/debug/stats.h"
 
 #include <inttypes.h>
@@ -23,17 +25,17 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
 
 grpc_stats_data* grpc_stats_per_cpu_storage = nullptr;
 static size_t g_num_cores;
 
 void grpc_stats_init(void) {
   g_num_cores = GPR_MAX(1, gpr_cpu_num_cores());
-  grpc_stats_per_cpu_storage =
-      (grpc_stats_data*)gpr_zalloc(sizeof(grpc_stats_data) * g_num_cores);
+  grpc_stats_per_cpu_storage = static_cast<grpc_stats_data*>(
+      gpr_zalloc(sizeof(grpc_stats_data) * g_num_cores));
 }
 
 void grpc_stats_shutdown(void) { gpr_free(grpc_stats_per_cpu_storage); }
@@ -76,14 +78,15 @@
       table_size = step;
     }
   }
-  return (int)(table - start) - 1;
+  return static_cast<int>(table - start) - 1;
 }
 
 size_t grpc_stats_histo_count(const grpc_stats_data* stats,
                               grpc_stats_histograms histogram) {
   size_t sum = 0;
   for (int i = 0; i < grpc_stats_histo_buckets[histogram]; i++) {
-    sum += (size_t)stats->histograms[grpc_stats_histo_start[histogram] + i];
+    sum += static_cast<size_t>(
+        stats->histograms[grpc_stats_histo_start[histogram] + i]);
   }
   return sum;
 }
@@ -100,7 +103,7 @@
   /* find the lowest bucket that gets us above count_below */
   count_so_far = 0.0;
   for (lower_idx = 0; lower_idx < num_buckets; lower_idx++) {
-    count_so_far += (double)bucket_counts[lower_idx];
+    count_so_far += static_cast<double>(bucket_counts[lower_idx]);
     if (count_so_far >= count_below) {
       break;
     }
@@ -121,7 +124,7 @@
     upper_bound = bucket_boundaries[lower_idx + 1];
     return upper_bound - (upper_bound - lower_bound) *
                              (count_so_far - count_below) /
-                             (double)bucket_counts[lower_idx];
+                             static_cast<double>(bucket_counts[lower_idx]);
   }
 }
 
@@ -133,7 +136,8 @@
   return threshold_for_count_below(
       stats->histograms + grpc_stats_histo_start[histogram],
       grpc_stats_histo_bucket_boundaries[histogram],
-      grpc_stats_histo_buckets[histogram], (double)count * percentile / 100.0);
+      grpc_stats_histo_buckets[histogram],
+      static_cast<double>(count) * percentile / 100.0);
 }
 
 char* grpc_stats_data_as_json(const grpc_stats_data* data) {
diff --git a/src/core/lib/debug/stats.h b/src/core/lib/debug/stats.h
index 02eed5e..7496652 100644
--- a/src/core/lib/debug/stats.h
+++ b/src/core/lib/debug/stats.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_DEBUG_STATS_H
 #define GRPC_CORE_LIB_DEBUG_STATS_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/atm.h>
 #include "src/core/lib/debug/stats_data.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
diff --git a/src/core/lib/debug/stats_data.cc b/src/core/lib/debug/stats_data.cc
index 996ed3d..309ece9 100644
--- a/src/core/lib/debug/stats_data.cc
+++ b/src/core/lib/debug/stats_data.cc
@@ -18,10 +18,13 @@
  * Automatically generated by tools/codegen/core/gen_stats_data.py
  */
 
-#include "src/core/lib/debug/stats_data.h"
-#include <grpc/support/useful.h>
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/debug/stats.h"
+#include "src/core/lib/debug/stats_data.h"
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
+
 const char* grpc_stats_counter_name[GRPC_STATS_COUNTER_COUNT] = {
     "client_calls_created",
     "server_calls_created",
diff --git a/src/core/lib/debug/stats_data.h b/src/core/lib/debug/stats_data.h
index 4504be3..da1266a 100644
--- a/src/core/lib/debug/stats_data.h
+++ b/src/core/lib/debug/stats_data.h
@@ -21,6 +21,8 @@
 #ifndef GRPC_CORE_LIB_DEBUG_STATS_DATA_H
 #define GRPC_CORE_LIB_DEBUG_STATS_DATA_H
 
+#include <grpc/support/port_platform.h>
+
 #include <inttypes.h>
 #include "src/core/lib/iomgr/exec_ctx.h"
 
diff --git a/src/core/lib/debug/trace.cc b/src/core/lib/debug/trace.cc
index d870bbc..b0e0f2b 100644
--- a/src/core/lib/debug/trace.cc
+++ b/src/core/lib/debug/trace.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/debug/trace.h"
 
 #include <string.h>
@@ -88,11 +90,11 @@
   char* s;
   size_t len;
   GPR_ASSERT(end >= beg);
-  len = (size_t)(end - beg);
-  s = (char*)gpr_malloc(len + 1);
+  len = static_cast<size_t>(end - beg);
+  s = static_cast<char*>(gpr_malloc(len + 1));
   memcpy(s, beg, len);
   s[len] = 0;
-  *ss = (char**)gpr_realloc(*ss, sizeof(char**) * np);
+  *ss = static_cast<char**>(gpr_realloc(*ss, sizeof(char**) * np));
   (*ss)[n] = s;
   *ns = np;
 }
diff --git a/src/core/lib/debug/trace.h b/src/core/lib/debug/trace.h
index 69ddd80..bfec92c 100644
--- a/src/core/lib/debug/trace.h
+++ b/src/core/lib/debug/trace.h
@@ -19,8 +19,9 @@
 #ifndef GRPC_CORE_LIB_DEBUG_TRACE_H
 #define GRPC_CORE_LIB_DEBUG_TRACE_H
 
-#include <grpc/support/atm.h>
 #include <grpc/support/port_platform.h>
+
+#include <grpc/support/atm.h>
 #include <stdbool.h>
 
 void grpc_tracer_init(const char* env_var_name);
diff --git a/src/core/lib/gpr/alloc.cc b/src/core/lib/gpr/alloc.cc
index b1d1550..611e4cc 100644
--- a/src/core/lib/gpr/alloc.cc
+++ b/src/core/lib/gpr/alloc.cc
@@ -16,10 +16,11 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/alloc.h>
 
 #include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
 #include <stdlib.h>
 #include <string.h>
 #include "src/core/lib/profiling/timers.h"
@@ -95,4 +96,4 @@
   return (void*)ret;
 }
 
-void gpr_free_aligned(void* ptr) { gpr_free(((void**)ptr)[-1]); }
+void gpr_free_aligned(void* ptr) { gpr_free((static_cast<void**>(ptr))[-1]); }
diff --git a/src/core/lib/gpr/arena.cc b/src/core/lib/gpr/arena.cc
index 687592a..b02c5b9 100644
--- a/src/core/lib/gpr/arena.cc
+++ b/src/core/lib/gpr/arena.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/gpr/arena.h"
 
 #include <string.h>
@@ -23,7 +25,49 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/atm.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
+
+// Uncomment this to use a simple arena that simply allocates the
+// requested amount of memory for each call to gpr_arena_alloc().  This
+// effectively eliminates the efficiency gain of using an arena, but it
+// may be useful for debugging purposes.
+//#define SIMPLE_ARENA_FOR_DEBUGGING
+
+#ifdef SIMPLE_ARENA_FOR_DEBUGGING
+
+#include <grpc/support/sync.h>
+
+struct gpr_arena {
+  gpr_mu mu;
+  void** ptrs;
+  size_t num_ptrs;
+};
+
+gpr_arena* gpr_arena_create(size_t ignored_initial_size) {
+  gpr_arena* arena = (gpr_arena*)gpr_zalloc(sizeof(*arena));
+  gpr_mu_init(&arena->mu);
+  return arena;
+}
+
+size_t gpr_arena_destroy(gpr_arena* arena) {
+  gpr_mu_destroy(&arena->mu);
+  for (size_t i = 0; i < arena->num_ptrs; ++i) {
+    gpr_free(arena->ptrs[i]);
+  }
+  gpr_free(arena->ptrs);
+  gpr_free(arena);
+  return 1;  // Value doesn't matter, since it won't be used.
+}
+
+void* gpr_arena_alloc(gpr_arena* arena, size_t size) {
+  gpr_mu_lock(&arena->mu);
+  arena->ptrs =
+      (void**)gpr_realloc(arena->ptrs, sizeof(void*) * (arena->num_ptrs + 1));
+  void* retval = arena->ptrs[arena->num_ptrs++] = gpr_zalloc(size);
+  gpr_mu_unlock(&arena->mu);
+  return retval;
+}
+
+#else  // SIMPLE_ARENA_FOR_DEBUGGING
 
 // TODO(roth): We currently assume that all callers need alignment of 16
 // bytes, which may be wrong in some cases.  As part of converting the
@@ -52,8 +96,8 @@
 
 gpr_arena* gpr_arena_create(size_t initial_size) {
   initial_size = ROUND_UP_TO_ALIGNMENT_SIZE(initial_size);
-  gpr_arena* a = (gpr_arena*)zalloc_aligned(
-      ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(gpr_arena)) + initial_size);
+  gpr_arena* a = static_cast<gpr_arena*>(zalloc_aligned(
+      ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(gpr_arena)) + initial_size));
   a->initial_zone.size_end = initial_size;
   return a;
 }
@@ -67,23 +111,25 @@
     gpr_free_aligned(z);
     z = next_z;
   }
-  return (size_t)size;
+  return static_cast<size_t>(size);
 }
 
 void* gpr_arena_alloc(gpr_arena* arena, size_t size) {
   size = ROUND_UP_TO_ALIGNMENT_SIZE(size);
-  size_t start =
-      (size_t)gpr_atm_no_barrier_fetch_add(&arena->size_so_far, size);
+  size_t start = static_cast<size_t>(
+      gpr_atm_no_barrier_fetch_add(&arena->size_so_far, size));
   zone* z = &arena->initial_zone;
   while (start > z->size_end) {
     zone* next_z = (zone*)gpr_atm_acq_load(&z->next_atm);
     if (next_z == nullptr) {
-      size_t next_z_size = (size_t)gpr_atm_no_barrier_load(&arena->size_so_far);
-      next_z = (zone*)zalloc_aligned(ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone)) +
-                                     next_z_size);
+      size_t next_z_size =
+          static_cast<size_t>(gpr_atm_no_barrier_load(&arena->size_so_far));
+      next_z = static_cast<zone*>(zalloc_aligned(
+          ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone)) + next_z_size));
       next_z->size_begin = z->size_end;
       next_z->size_end = z->size_end + next_z_size;
-      if (!gpr_atm_rel_cas(&z->next_atm, (gpr_atm)NULL, (gpr_atm)next_z)) {
+      if (!gpr_atm_rel_cas(&z->next_atm, static_cast<gpr_atm>(NULL),
+                           (gpr_atm)next_z)) {
         gpr_free_aligned(next_z);
         next_z = (zone*)gpr_atm_acq_load(&z->next_atm);
       }
@@ -96,7 +142,11 @@
   GPR_ASSERT(start >= z->size_begin);
   GPR_ASSERT(start + size <= z->size_end);
   char* ptr = (z == &arena->initial_zone)
-                  ? (char*)arena + ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(gpr_arena))
-                  : (char*)z + ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone));
+                  ? reinterpret_cast<char*>(arena) +
+                        ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(gpr_arena))
+                  : reinterpret_cast<char*>(z) +
+                        ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone));
   return ptr + start - z->size_begin;
 }
+
+#endif  // SIMPLE_ARENA_FOR_DEBUGGING
diff --git a/src/core/lib/gpr/arena.h b/src/core/lib/gpr/arena.h
index 339771c..6d2a073 100644
--- a/src/core/lib/gpr/arena.h
+++ b/src/core/lib/gpr/arena.h
@@ -25,6 +25,8 @@
 #ifndef GRPC_CORE_LIB_GPR_ARENA_H
 #define GRPC_CORE_LIB_GPR_ARENA_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stddef.h>
 
 typedef struct gpr_arena gpr_arena;
diff --git a/src/core/lib/gpr/atm.cc b/src/core/lib/gpr/atm.cc
index 15bfe52..649d400 100644
--- a/src/core/lib/gpr/atm.cc
+++ b/src/core/lib/gpr/atm.cc
@@ -16,8 +16,11 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/atm.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
 
 gpr_atm gpr_atm_no_barrier_clamped_add(gpr_atm* value, gpr_atm delta,
                                        gpr_atm min, gpr_atm max) {
diff --git a/src/core/lib/gpr/cpu_linux.cc b/src/core/lib/gpr/cpu_linux.cc
index 21b1a71..9fc2f0b 100644
--- a/src/core/lib/gpr/cpu_linux.cc
+++ b/src/core/lib/gpr/cpu_linux.cc
@@ -45,7 +45,7 @@
 #endif
   /* This must be signed. sysconf returns -1 when the number cannot be
      determined */
-  ncpus = (int)sysconf(_SC_NPROCESSORS_ONLN);
+  ncpus = static_cast<int>(sysconf(_SC_NPROCESSORS_CONF));
   if (ncpus < 1) {
     gpr_log(GPR_ERROR, "Cannot determine number of CPUs: assuming 1");
     ncpus = 1;
@@ -55,7 +55,7 @@
 unsigned gpr_cpu_num_cores(void) {
   static gpr_once once = GPR_ONCE_INIT;
   gpr_once_init(&once, init_num_cpus);
-  return (unsigned)ncpus;
+  return static_cast<unsigned>(ncpus);
 }
 
 unsigned gpr_cpu_current_cpu(void) {
@@ -71,7 +71,11 @@
     gpr_log(GPR_ERROR, "Error determining current CPU: %s\n", strerror(errno));
     return 0;
   }
-  return (unsigned)cpu;
+  if (static_cast<unsigned>(cpu) >= gpr_cpu_num_cores()) {
+    gpr_log(GPR_ERROR, "Cannot handle hot-plugged CPUs");
+    return 0;
+  }
+  return static_cast<unsigned>(cpu);
 #endif
 }
 
diff --git a/src/core/lib/gpr/cpu_posix.cc b/src/core/lib/gpr/cpu_posix.cc
index bca14a0..915fd49 100644
--- a/src/core/lib/gpr/cpu_posix.cc
+++ b/src/core/lib/gpr/cpu_posix.cc
@@ -29,14 +29,15 @@
 #include <grpc/support/cpu.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
 
 static long ncpus = 0;
 
 static pthread_key_t thread_id_key;
 
 static void init_ncpus() {
-  ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+  ncpus = sysconf(_SC_NPROCESSORS_CONF);
   if (ncpus < 1 || ncpus > INT32_MAX) {
     gpr_log(GPR_ERROR, "Cannot determine number of CPUs: assuming 1");
     ncpus = 1;
diff --git a/src/core/lib/gpr/env.h b/src/core/lib/gpr/env.h
index 7f35104..aec8a31 100644
--- a/src/core/lib/gpr/env.h
+++ b/src/core/lib/gpr/env.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_GPR_ENV_H
 #define GRPC_CORE_LIB_GPR_ENV_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stdio.h>
 
 /* Env utility functions */
@@ -29,7 +31,7 @@
    variable exists). */
 char* gpr_getenv(const char* name);
 
-/* Sets the the environment with the specified name to the specified value. */
+/* Sets the environment with the specified name to the specified value. */
 void gpr_setenv(const char* name, const char* value);
 
 /* This is a version of gpr_getenv that does not produce any output if it has to
diff --git a/src/core/lib/gpr/env_linux.cc b/src/core/lib/gpr/env_linux.cc
index 17902c3..fadc42f 100644
--- a/src/core/lib/gpr/env_linux.cc
+++ b/src/core/lib/gpr/env_linux.cc
@@ -34,9 +34,9 @@
 
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
 
 const char* gpr_getenv_silent(const char* name, char** dst) {
   const char* insecure_func_used = nullptr;
diff --git a/src/core/lib/gpr/env_windows.cc b/src/core/lib/gpr/env_windows.cc
index 9ca1e02..cf8ed60 100644
--- a/src/core/lib/gpr/env_windows.cc
+++ b/src/core/lib/gpr/env_windows.cc
@@ -22,14 +22,14 @@
 
 #include <windows.h>
 
-#include "src/core/lib/gpr/env.h"
-#include "src/core/lib/gpr/string.h"
-#include "src/core/lib/gpr/string_windows.h"
-
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
+#include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/string_windows.h"
+
 const char* gpr_getenv_silent(const char* name, char** dst) {
   *dst = gpr_getenv(name);
   return NULL;
diff --git a/src/core/lib/gpr/fork.cc b/src/core/lib/gpr/fork.cc
index 92023f4..812522b 100644
--- a/src/core/lib/gpr/fork.cc
+++ b/src/core/lib/gpr/fork.cc
@@ -16,14 +16,16 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/gpr/fork.h"
 
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/useful.h"
 
 /*
  * NOTE: FORKING IS NOT GENERALLY SUPPORTED, THIS IS ONLY INTENDED TO WORK
diff --git a/src/core/lib/gpr/host_port.cc b/src/core/lib/gpr/host_port.cc
index 2917827..a34e01c 100644
--- a/src/core/lib/gpr/host_port.cc
+++ b/src/core/lib/gpr/host_port.cc
@@ -16,13 +16,16 @@
  *
  */
 
-#include <grpc/support/host_port.h>
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/gpr/host_port.h"
 
 #include <string.h>
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
+
 #include "src/core/lib/gpr/string.h"
 
 int gpr_join_host_port(char** out, const char* host, int port) {
@@ -61,7 +64,7 @@
       return 0;
     }
     host_start = name + 1;
-    host_len = (size_t)(rbracket - host_start);
+    host_len = static_cast<size_t>(rbracket - host_start);
     if (memchr(host_start, ':', host_len) == nullptr) {
       /* Require all bracketed hosts to contain a colon, because a hostname or
          IPv4 address should never use brackets. */
@@ -72,7 +75,7 @@
     if (colon != nullptr && strchr(colon + 1, ':') == nullptr) {
       /* Exactly 1 colon.  Split into host:port. */
       host_start = name;
-      host_len = (size_t)(colon - name);
+      host_len = static_cast<size_t>(colon - name);
       port_start = colon + 1;
     } else {
       /* 0 or 2+ colons.  Bare hostname or IPv6 litearal. */
@@ -83,7 +86,7 @@
   }
 
   /* Allocate return values. */
-  *host = (char*)gpr_malloc(host_len + 1);
+  *host = static_cast<char*>(gpr_malloc(host_len + 1));
   memcpy(*host, host_start, host_len);
   (*host)[host_len] = '\0';
 
diff --git a/include/grpc/support/host_port.h b/src/core/lib/gpr/host_port.h
similarity index 81%
rename from include/grpc/support/host_port.h
rename to src/core/lib/gpr/host_port.h
index 9805811..0bf0960 100644
--- a/include/grpc/support/host_port.h
+++ b/src/core/lib/gpr/host_port.h
@@ -16,15 +16,11 @@
  *
  */
 
-#ifndef GRPC_SUPPORT_HOST_PORT_H
-#define GRPC_SUPPORT_HOST_PORT_H
+#ifndef GRPC_CORE_LIB_GPR_HOST_PORT_H
+#define GRPC_CORE_LIB_GPR_HOST_PORT_H
 
 #include <grpc/support/port_platform.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /** Given a host and port, creates a newly-allocated string of the form
    "host:port" or "[ho:st]:port", depending on whether the host contains colons
    like an IPv6 literal.  If the host is already bracketed, then additional
@@ -35,17 +31,13 @@
    destroyed using gpr_free().
 
    In the unlikely event of an error, returns -1 and sets *out to NULL. */
-GPRAPI int gpr_join_host_port(char** out, const char* host, int port);
+int gpr_join_host_port(char** out, const char* host, int port);
 
 /** Given a name in the form "host:port" or "[ho:st]:port", split into hostname
    and port number, into newly allocated strings, which must later be
    destroyed using gpr_free().
    Return 1 on success, 0 on failure. Guarantees *host and *port == NULL on
    failure. */
-GPRAPI int gpr_split_host_port(const char* name, char** host, char** port);
+int gpr_split_host_port(const char* name, char** host, char** port);
 
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_SUPPORT_HOST_PORT_H */
+#endif /* GRPC_CORE_LIB_GPR_HOST_PORT_H */
diff --git a/src/core/lib/gpr/log.cc b/src/core/lib/gpr/log.cc
index 19c0f6c..72787ab 100644
--- a/src/core/lib/gpr/log.cc
+++ b/src/core/lib/gpr/log.cc
@@ -16,10 +16,11 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/alloc.h>
 #include <grpc/support/atm.h>
 #include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
 
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/string.h"
@@ -45,7 +46,8 @@
 
 void gpr_log_message(const char* file, int line, gpr_log_severity severity,
                      const char* message) {
-  if ((gpr_atm)severity < gpr_atm_no_barrier_load(&g_min_severity_to_print)) {
+  if (static_cast<gpr_atm>(severity) <
+      gpr_atm_no_barrier_load(&g_min_severity_to_print)) {
     return;
   }
 
@@ -70,11 +72,11 @@
   gpr_atm min_severity_to_print = GPR_LOG_SEVERITY_ERROR;
   if (verbosity != nullptr) {
     if (gpr_stricmp(verbosity, "DEBUG") == 0) {
-      min_severity_to_print = (gpr_atm)GPR_LOG_SEVERITY_DEBUG;
+      min_severity_to_print = static_cast<gpr_atm>(GPR_LOG_SEVERITY_DEBUG);
     } else if (gpr_stricmp(verbosity, "INFO") == 0) {
-      min_severity_to_print = (gpr_atm)GPR_LOG_SEVERITY_INFO;
+      min_severity_to_print = static_cast<gpr_atm>(GPR_LOG_SEVERITY_INFO);
     } else if (gpr_stricmp(verbosity, "ERROR") == 0) {
-      min_severity_to_print = (gpr_atm)GPR_LOG_SEVERITY_ERROR;
+      min_severity_to_print = static_cast<gpr_atm>(GPR_LOG_SEVERITY_ERROR);
     }
     gpr_free(verbosity);
   }
diff --git a/src/core/lib/gpr/log_linux.cc b/src/core/lib/gpr/log_linux.cc
index 6b1f1c7..e4417d9 100644
--- a/src/core/lib/gpr/log_linux.cc
+++ b/src/core/lib/gpr/log_linux.cc
@@ -32,6 +32,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
+#include <inttypes.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
@@ -67,7 +68,7 @@
   static __thread long tid = 0;
   if (tid == 0) tid = gettid();
 
-  timer = (time_t)now.tv_sec;
+  timer = static_cast<time_t>(now.tv_sec);
   final_slash = strrchr(args->file, '/');
   if (final_slash == nullptr)
     display_file = args->file;
diff --git a/src/core/lib/gpr/mpscq.cc b/src/core/lib/gpr/mpscq.cc
index 34fc050..076a6bb 100644
--- a/src/core/lib/gpr/mpscq.cc
+++ b/src/core/lib/gpr/mpscq.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/gpr/mpscq.h"
 
 #include <grpc/support/log.h>
@@ -71,6 +73,7 @@
   gpr_mpscq_push(q, &q->stub);
   next = (gpr_mpscq_node*)gpr_atm_acq_load(&tail->next);
   if (next != nullptr) {
+    *empty = false;
     q->tail = next;
     return tail;
   }
diff --git a/src/core/lib/gpr/mpscq.h b/src/core/lib/gpr/mpscq.h
index 4409c5c..6b67880 100644
--- a/src/core/lib/gpr/mpscq.h
+++ b/src/core/lib/gpr/mpscq.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_GPR_MPSCQ_H
 #define GRPC_CORE_LIB_GPR_MPSCQ_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/atm.h>
 #include <grpc/support/sync.h>
 #include <stdbool.h>
diff --git a/src/core/lib/gpr/murmur_hash.cc b/src/core/lib/gpr/murmur_hash.cc
index 3f5e04d..cf25abf 100644
--- a/src/core/lib/gpr/murmur_hash.cc
+++ b/src/core/lib/gpr/murmur_hash.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/gpr/murmur_hash.h"
 
 #include <string.h>
@@ -36,7 +38,7 @@
   const uint32_t c1 = 0xcc9e2d51;
   const uint32_t c2 = 0x1b873593;
 
-  const uint8_t* keyptr = (const uint8_t*)key;
+  const uint8_t* keyptr = static_cast<const uint8_t*>(key);
   const size_t bsize = sizeof(k1);
   const size_t nblocks = len / bsize;
 
@@ -58,10 +60,10 @@
   /* tail */
   switch (len & 3) {
     case 3:
-      k1 ^= ((uint32_t)keyptr[2]) << 16;
+      k1 ^= (static_cast<uint32_t>(keyptr[2])) << 16;
     /* fallthrough */
     case 2:
-      k1 ^= ((uint32_t)keyptr[1]) << 8;
+      k1 ^= (static_cast<uint32_t>(keyptr[1])) << 8;
     /* fallthrough */
     case 1:
       k1 ^= keyptr[0];
@@ -72,7 +74,7 @@
   };
 
   /* finalization */
-  h1 ^= (uint32_t)len;
+  h1 ^= static_cast<uint32_t>(len);
   FMIX32(h1);
   return h1;
 }
diff --git a/src/core/lib/gpr/spinlock.h b/src/core/lib/gpr/spinlock.h
index f03be1d..9f35530 100644
--- a/src/core/lib/gpr/spinlock.h
+++ b/src/core/lib/gpr/spinlock.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_GPR_SPINLOCK_H
 #define GRPC_CORE_LIB_GPR_SPINLOCK_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/atm.h>
 
 /* Simple spinlock. No backoff strategy, gpr_spinlock_lock is almost always
diff --git a/src/core/lib/gpr/string.cc b/src/core/lib/gpr/string.cc
index 919d957..ef2a690 100644
--- a/src/core/lib/gpr/string.cc
+++ b/src/core/lib/gpr/string.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/gpr/string.h"
 
 #include <ctype.h>
@@ -26,9 +28,9 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
 
 char* gpr_strdup(const char* src) {
   char* dst;
@@ -39,7 +41,7 @@
   }
 
   len = strlen(src) + 1;
-  dst = (char*)gpr_malloc(len);
+  dst = static_cast<char*>(gpr_malloc(len));
 
   memcpy(dst, src, len);
 
@@ -60,7 +62,7 @@
 static void dump_out_append(dump_out* out, char c) {
   if (out->length == out->capacity) {
     out->capacity = GPR_MAX(8, 2 * out->capacity);
-    out->data = (char*)gpr_realloc(out->data, out->capacity);
+    out->data = static_cast<char*>(gpr_realloc(out->data, out->capacity));
   }
   out->data[out->length++] = c;
 }
@@ -68,7 +70,7 @@
 static void hexdump(dump_out* out, const char* buf, size_t len) {
   static const char* hex = "0123456789abcdef";
 
-  const uint8_t* const beg = (const uint8_t*)buf;
+  const uint8_t* const beg = reinterpret_cast<const uint8_t*>(buf);
   const uint8_t* const end = beg + len;
   const uint8_t* cur;
 
@@ -80,7 +82,7 @@
 }
 
 static void asciidump(dump_out* out, const char* buf, size_t len) {
-  const uint8_t* const beg = (const uint8_t*)buf;
+  const uint8_t* const beg = reinterpret_cast<const uint8_t*>(buf);
   const uint8_t* const end = beg + len;
   const uint8_t* cur;
   int out_was_empty = (out->length == 0);
@@ -89,7 +91,7 @@
     dump_out_append(out, '\'');
   }
   for (cur = beg; cur != end; ++cur) {
-    dump_out_append(out, (char)(isprint(*cur) ? *(char*)cur : '.'));
+    dump_out_append(out, (isprint(*cur) ? *(char*)cur : '.'));
   }
   if (!out_was_empty) {
     dump_out_append(out, '\'');
@@ -117,7 +119,7 @@
 
   for (i = 0; i < len; i++) {
     if (buf[i] < '0' || buf[i] > '9') return 0; /* bad char */
-    new_val = 10 * out + (uint32_t)(buf[i] - '0');
+    new_val = 10 * out + static_cast<uint32_t>(buf[i] - '0');
     if (new_val < out) return 0; /* overflow */
     out = new_val;
   }
@@ -147,7 +149,7 @@
 
   sign = value < 0 ? -1 : 1;
   while (value) {
-    string[i++] = (char)('0' + sign * (value % 10));
+    string[i++] = static_cast<char>('0' + sign * (value % 10));
     value /= 10;
   }
   if (sign < 0) string[i++] = '-';
@@ -168,7 +170,7 @@
 
   sign = value < 0 ? -1 : 1;
   while (value) {
-    string[i++] = (char)('0' + sign * (value % 10));
+    string[i++] = static_cast<char>('0' + sign * (value % 10));
     value /= 10;
   }
   if (sign < 0) string[i++] = '-';
@@ -181,13 +183,13 @@
   char* end;
   long result = strtol(value, &end, 0);
   if (*end != '\0' || result < 0 || result > INT_MAX) return -1;
-  return (int)result;
+  return static_cast<int>(result);
 }
 
 char* gpr_leftpad(const char* str, char flag, size_t length) {
   const size_t str_length = strlen(str);
   const size_t out_length = str_length > length ? str_length : length;
-  char* out = (char*)gpr_malloc(out_length + 1);
+  char* out = static_cast<char*>(gpr_malloc(out_length + 1));
   memset(out, flag, out_length - str_length);
   memcpy(out + out_length - str_length, str, str_length);
   out[out_length] = 0;
@@ -211,7 +213,7 @@
   if (nstrs > 0) {
     out_length += sep_len * (nstrs - 1); /* separators */
   }
-  out = (char*)gpr_malloc(out_length);
+  out = static_cast<char*>(gpr_malloc(out_length));
   out_length = 0;
   for (i = 0; i < nstrs; i++) {
     const size_t slen = strlen(strs[i]);
@@ -242,7 +244,8 @@
 void gpr_strvec_add(gpr_strvec* sv, char* str) {
   if (sv->count == sv->capacity) {
     sv->capacity = GPR_MAX(sv->capacity + 8, sv->capacity * 2);
-    sv->strs = (char**)gpr_realloc(sv->strs, sizeof(char*) * sv->capacity);
+    sv->strs = static_cast<char**>(
+        gpr_realloc(sv->strs, sizeof(char*) * sv->capacity));
   }
   sv->strs[sv->count++] = str;
 }
@@ -264,12 +267,13 @@
 
 static void add_string_to_split(const char* beg, const char* end, char*** strs,
                                 size_t* nstrs, size_t* capstrs) {
-  char* out = (char*)gpr_malloc((size_t)(end - beg) + 1);
-  memcpy(out, beg, (size_t)(end - beg));
+  char* out =
+      static_cast<char*>(gpr_malloc(static_cast<size_t>(end - beg) + 1));
+  memcpy(out, beg, static_cast<size_t>(end - beg));
   out[end - beg] = 0;
   if (*nstrs == *capstrs) {
     *capstrs = GPR_MAX(8, 2 * *capstrs);
-    *strs = (char**)gpr_realloc(*strs, sizeof(*strs) * *capstrs);
+    *strs = static_cast<char**>(gpr_realloc(*strs, sizeof(*strs) * *capstrs));
   }
   (*strs)[*nstrs] = out;
   ++*nstrs;
diff --git a/src/core/lib/gpr/string.h b/src/core/lib/gpr/string.h
index ef3a8c6..2e8a489 100644
--- a/src/core/lib/gpr/string.h
+++ b/src/core/lib/gpr/string.h
@@ -19,11 +19,11 @@
 #ifndef GRPC_CORE_LIB_GPR_STRING_H
 #define GRPC_CORE_LIB_GPR_STRING_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stdbool.h>
 #include <stddef.h>
 
-#include <grpc/support/port_platform.h>
-
 /* String utility functions */
 
 /* Flags for gpr_dump function. */
diff --git a/src/core/lib/gpr/string_posix.cc b/src/core/lib/gpr/string_posix.cc
index 8b818e3..d32775f 100644
--- a/src/core/lib/gpr/string_posix.cc
+++ b/src/core/lib/gpr/string_posix.cc
@@ -43,8 +43,8 @@
   }
 
   /* Allocate a new buffer, with space for the NUL terminator. */
-  strp_buflen = (size_t)ret + 1;
-  if ((*strp = (char*)gpr_malloc(strp_buflen)) == nullptr) {
+  strp_buflen = static_cast<size_t>(ret) + 1;
+  if ((*strp = static_cast<char*>(gpr_malloc(strp_buflen))) == nullptr) {
     /* This shouldn't happen, because gpr_malloc() calls abort(). */
     return -1;
   }
@@ -59,7 +59,7 @@
   va_start(args, format);
   ret = vsnprintf(*strp, strp_buflen, format, args);
   va_end(args);
-  if ((size_t)ret == strp_buflen - 1) {
+  if (static_cast<size_t>(ret) == strp_buflen - 1) {
     return ret;
   }
 
diff --git a/src/core/lib/gpr/sync.cc b/src/core/lib/gpr/sync.cc
index 347ffcd..2f18fc5 100644
--- a/src/core/lib/gpr/sync.cc
+++ b/src/core/lib/gpr/sync.cc
@@ -18,6 +18,8 @@
 
 /* Generic implementation of synchronization primitives. */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/atm.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
diff --git a/src/core/lib/gpr/sync_posix.cc b/src/core/lib/gpr/sync_posix.cc
index f23a8b2..848d237 100644
--- a/src/core/lib/gpr/sync_posix.cc
+++ b/src/core/lib/gpr/sync_posix.cc
@@ -84,7 +84,7 @@
 #else
     abs_deadline = gpr_convert_clock_type(abs_deadline, GPR_CLOCK_REALTIME);
 #endif  // GPR_LINUX
-    abs_deadline_ts.tv_sec = (time_t)abs_deadline.tv_sec;
+    abs_deadline_ts.tv_sec = static_cast<time_t>(abs_deadline.tv_sec);
     abs_deadline_ts.tv_nsec = abs_deadline.tv_nsec;
     err = pthread_cond_timedwait(cv, mu, &abs_deadline_ts);
   }
diff --git a/src/core/lib/gpr/thd.cc b/src/core/lib/gpr/thd.cc
deleted file mode 100644
index ca62615..0000000
--- a/src/core/lib/gpr/thd.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-/* Posix implementation for gpr threads. */
-
-#include <string.h>
-
-#include <grpc/support/thd.h>
-
-enum { GPR_THD_JOINABLE = 1 };
-
-gpr_thd_options gpr_thd_options_default(void) {
-  gpr_thd_options options;
-  memset(&options, 0, sizeof(options));
-  return options;
-}
-
-void gpr_thd_options_set_detached(gpr_thd_options* options) {
-  options->flags &= ~GPR_THD_JOINABLE;
-}
-
-void gpr_thd_options_set_joinable(gpr_thd_options* options) {
-  options->flags |= GPR_THD_JOINABLE;
-}
-
-int gpr_thd_options_is_detached(const gpr_thd_options* options) {
-  if (!options) return 1;
-  return (options->flags & GPR_THD_JOINABLE) == 0;
-}
-
-int gpr_thd_options_is_joinable(const gpr_thd_options* options) {
-  if (!options) return 0;
-  return (options->flags & GPR_THD_JOINABLE) == GPR_THD_JOINABLE;
-}
diff --git a/src/core/lib/gpr/thd_posix.cc b/src/core/lib/gpr/thd_posix.cc
deleted file mode 100644
index cfff0df..0000000
--- a/src/core/lib/gpr/thd_posix.cc
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-/* Posix implementation for gpr threads. */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_POSIX_SYNC
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "src/core/lib/gpr/fork.h"
-
-static gpr_mu g_mu;
-static gpr_cv g_cv;
-static int g_thread_count;
-static int g_awaiting_threads;
-
-struct thd_arg {
-  void (*body)(void* arg); /* body of a thread */
-  void* arg;               /* argument to a thread */
-  const char* name;        /* name of thread. Can be nullptr. */
-};
-
-static void inc_thd_count();
-static void dec_thd_count();
-
-/* Body of every thread started via gpr_thd_new. */
-static void* thread_body(void* v) {
-  struct thd_arg a = *(struct thd_arg*)v;
-  free(v);
-  if (a.name != nullptr) {
-#if GPR_APPLE_PTHREAD_NAME
-    /* Apple supports 64 characters, and will truncate if it's longer. */
-    pthread_setname_np(a.name);
-#elif GPR_LINUX_PTHREAD_NAME
-    /* Linux supports 16 characters max, and will error if it's longer. */
-    char buf[16];
-    size_t buf_len = GPR_ARRAY_SIZE(buf) - 1;
-    strncpy(buf, a.name, buf_len);
-    buf[buf_len] = '\0';
-    pthread_setname_np(pthread_self(), buf);
-#endif  // GPR_APPLE_PTHREAD_NAME
-  }
-  (*a.body)(a.arg);
-  dec_thd_count();
-  return nullptr;
-}
-
-int gpr_thd_new(gpr_thd_id* t, const char* thd_name,
-                void (*thd_body)(void* arg), void* arg,
-                const gpr_thd_options* options) {
-  int thread_started;
-  pthread_attr_t attr;
-  pthread_t p;
-  /* don't use gpr_malloc as we may cause an infinite recursion with
-   * the profiling code */
-  struct thd_arg* a = (struct thd_arg*)malloc(sizeof(*a));
-  GPR_ASSERT(a != nullptr);
-  a->body = thd_body;
-  a->arg = arg;
-  a->name = thd_name;
-  inc_thd_count();
-
-  GPR_ASSERT(pthread_attr_init(&attr) == 0);
-  if (gpr_thd_options_is_detached(options)) {
-    GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) ==
-               0);
-  } else {
-    GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) ==
-               0);
-  }
-  thread_started = (pthread_create(&p, &attr, &thread_body, a) == 0);
-  GPR_ASSERT(pthread_attr_destroy(&attr) == 0);
-  if (!thread_started) {
-    /* don't use gpr_free, as this was allocated using malloc (see above) */
-    free(a);
-    dec_thd_count();
-  }
-  *t = (gpr_thd_id)p;
-  return thread_started;
-}
-
-gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)pthread_self(); }
-
-void gpr_thd_join(gpr_thd_id t) { pthread_join((pthread_t)t, nullptr); }
-
-/*****************************************
- * Only used when fork support is enabled
- */
-
-static void inc_thd_count() {
-  if (grpc_fork_support_enabled()) {
-    gpr_mu_lock(&g_mu);
-    g_thread_count++;
-    gpr_mu_unlock(&g_mu);
-  }
-}
-
-static void dec_thd_count() {
-  if (grpc_fork_support_enabled()) {
-    gpr_mu_lock(&g_mu);
-    g_thread_count--;
-    if (g_awaiting_threads && g_thread_count == 0) {
-      gpr_cv_signal(&g_cv);
-    }
-    gpr_mu_unlock(&g_mu);
-  }
-}
-
-void gpr_thd_init() {
-  gpr_mu_init(&g_mu);
-  gpr_cv_init(&g_cv);
-  g_thread_count = 0;
-  g_awaiting_threads = 0;
-}
-
-int gpr_await_threads(gpr_timespec deadline) {
-  gpr_mu_lock(&g_mu);
-  g_awaiting_threads = 1;
-  int res = 0;
-  if (g_thread_count > 0) {
-    res = gpr_cv_wait(&g_cv, &g_mu, deadline);
-  }
-  g_awaiting_threads = 0;
-  gpr_mu_unlock(&g_mu);
-  return res == 0;
-}
-
-#endif /* GPR_POSIX_SYNC */
diff --git a/src/core/lib/gpr/thd_windows.cc b/src/core/lib/gpr/thd_windows.cc
deleted file mode 100644
index f920770..0000000
--- a/src/core/lib/gpr/thd_windows.cc
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-/* Windows implementation for gpr threads. */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_WINDOWS
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/thd.h>
-#include <string.h>
-
-#if defined(_MSC_VER)
-#define thread_local __declspec(thread)
-#elif defined(__GNUC__)
-#define thread_local __thread
-#else
-#error "Unknown compiler - please file a bug report"
-#endif
-
-struct thd_info {
-  void (*body)(void* arg); /* body of a thread */
-  void* arg;               /* argument to a thread */
-  HANDLE join_event;       /* if joinable, the join event */
-  int joinable;            /* true if not detached */
-};
-
-static thread_local struct thd_info* g_thd_info;
-
-/* Destroys a thread info */
-static void destroy_thread(struct thd_info* t) {
-  if (t->joinable) CloseHandle(t->join_event);
-  gpr_free(t);
-}
-
-void gpr_thd_init(void) {}
-
-/* Body of every thread started via gpr_thd_new. */
-static DWORD WINAPI thread_body(void* v) {
-  g_thd_info = (struct thd_info*)v;
-  g_thd_info->body(g_thd_info->arg);
-  if (g_thd_info->joinable) {
-    BOOL ret = SetEvent(g_thd_info->join_event);
-    GPR_ASSERT(ret);
-  } else {
-    destroy_thread(g_thd_info);
-  }
-  return 0;
-}
-
-int gpr_thd_new(gpr_thd_id* t, const char* thd_name,
-                void (*thd_body)(void* arg), void* arg,
-                const gpr_thd_options* options) {
-  HANDLE handle;
-  struct thd_info* info = (struct thd_info*)gpr_malloc(sizeof(*info));
-  info->body = thd_body;
-  info->arg = arg;
-  *t = 0;
-  if (gpr_thd_options_is_joinable(options)) {
-    info->joinable = 1;
-    info->join_event = CreateEvent(NULL, FALSE, FALSE, NULL);
-    if (info->join_event == NULL) {
-      gpr_free(info);
-      return 0;
-    }
-  } else {
-    info->joinable = 0;
-  }
-  handle = CreateThread(NULL, 64 * 1024, thread_body, info, 0, NULL);
-  if (handle == NULL) {
-    destroy_thread(info);
-  } else {
-    *t = (gpr_thd_id)info;
-    CloseHandle(handle);
-  }
-  return handle != NULL;
-}
-
-gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)g_thd_info; }
-
-void gpr_thd_join(gpr_thd_id t) {
-  struct thd_info* info = (struct thd_info*)t;
-  DWORD ret = WaitForSingleObject(info->join_event, INFINITE);
-  GPR_ASSERT(ret == WAIT_OBJECT_0);
-  destroy_thread(info);
-}
-
-#endif /* GPR_WINDOWS */
diff --git a/src/core/lib/gpr/time.cc b/src/core/lib/gpr/time.cc
index 6903674..64c1c98 100644
--- a/src/core/lib/gpr/time.cc
+++ b/src/core/lib/gpr/time.cc
@@ -18,6 +18,8 @@
 
 /* Generic implementation of time calls. */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include <limits.h>
@@ -81,8 +83,9 @@
                     units_per_sec) -
                    1;
     }
-    out.tv_nsec = (int32_t)((time_in_units - out.tv_sec * units_per_sec) *
-                            GPR_NS_PER_SEC / units_per_sec);
+    out.tv_nsec =
+        static_cast<int32_t>((time_in_units - out.tv_sec * units_per_sec) *
+                             GPR_NS_PER_SEC / units_per_sec);
     out.clock_type = type;
   }
   return out;
@@ -216,12 +219,13 @@
        care?) */
     return -2147483647;
   } else {
-    return (int32_t)(t.tv_sec * GPR_MS_PER_SEC + t.tv_nsec / GPR_NS_PER_MS);
+    return static_cast<int32_t>(t.tv_sec * GPR_MS_PER_SEC +
+                                t.tv_nsec / GPR_NS_PER_MS);
   }
 }
 
 double gpr_timespec_to_micros(gpr_timespec t) {
-  return (double)t.tv_sec * GPR_US_PER_SEC + t.tv_nsec * 1e-3;
+  return static_cast<double>(t.tv_sec) * GPR_US_PER_SEC + t.tv_nsec * 1e-3;
 }
 
 gpr_timespec gpr_convert_clock_type(gpr_timespec t, gpr_clock_type clock_type) {
diff --git a/src/core/lib/gpr/time_posix.cc b/src/core/lib/gpr/time_posix.cc
index 9c7e86b..28836bf 100644
--- a/src/core/lib/gpr/time_posix.cc
+++ b/src/core/lib/gpr/time_posix.cc
@@ -17,6 +17,7 @@
  */
 
 #include <grpc/support/port_platform.h>
+
 #include "src/core/lib/gpr/time_precise.h"
 
 #ifdef GPR_POSIX_TIME
@@ -37,7 +38,7 @@
     /* fine to assert, as this is only used in gpr_sleep_until */
     GPR_ASSERT(gts.tv_sec <= INT32_MAX && gts.tv_sec >= INT32_MIN);
   }
-  rv.tv_sec = (time_t)gts.tv_sec;
+  rv.tv_sec = static_cast<time_t>(gts.tv_sec);
   rv.tv_nsec = gts.tv_nsec;
   return rv;
 }
@@ -52,7 +53,7 @@
    */
   gpr_timespec rv;
   rv.tv_sec = ts.tv_sec;
-  rv.tv_nsec = (int32_t)ts.tv_nsec;
+  rv.tv_nsec = static_cast<int32_t>(ts.tv_nsec);
   rv.clock_type = clock_type;
   return rv;
 }
diff --git a/src/core/lib/gpr/time_precise.cc b/src/core/lib/gpr/time_precise.cc
index 3c7aaab..1b34fd7 100644
--- a/src/core/lib/gpr/time_precise.cc
+++ b/src/core/lib/gpr/time_precise.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include <stdio.h>
diff --git a/src/core/lib/gpr/time_precise.h b/src/core/lib/gpr/time_precise.h
index acc4ee3..a63ea9d 100644
--- a/src/core/lib/gpr/time_precise.h
+++ b/src/core/lib/gpr/time_precise.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_GPR_TIME_PRECISE_H
 #define GRPC_CORE_LIB_GPR_TIME_PRECISE_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/time.h>
 
 void gpr_precise_clock_init(void);
diff --git a/include/grpc/support/tls.h b/src/core/lib/gpr/tls.h
similarity index 87%
rename from include/grpc/support/tls.h
rename to src/core/lib/gpr/tls.h
index 4c9e79b..aee8f4d 100644
--- a/include/grpc/support/tls.h
+++ b/src/core/lib/gpr/tls.h
@@ -16,8 +16,8 @@
  *
  */
 
-#ifndef GRPC_SUPPORT_TLS_H
-#define GRPC_SUPPORT_TLS_H
+#ifndef GRPC_CORE_LIB_GPR_TLS_H
+#define GRPC_CORE_LIB_GPR_TLS_H
 
 #include <grpc/support/port_platform.h>
 
@@ -54,15 +54,15 @@
    ALL functions here may be implemented as macros. */
 
 #ifdef GPR_GCC_TLS
-#include <grpc/support/tls_gcc.h>
+#include "src/core/lib/gpr/tls_gcc.h"
 #endif
 
 #ifdef GPR_MSVC_TLS
-#include <grpc/support/tls_msvc.h>
+#include "src/core/lib/gpr/tls_msvc.h"
 #endif
 
 #ifdef GPR_PTHREAD_TLS
-#include <grpc/support/tls_pthread.h>
+#include "src/core/lib/gpr/tls_pthread.h"
 #endif
 
-#endif /* GRPC_SUPPORT_TLS_H */
+#endif /* GRPC_CORE_LIB_GPR_TLS_H */
diff --git a/include/grpc/support/tls_gcc.h b/src/core/lib/gpr/tls_gcc.h
similarity index 89%
rename from include/grpc/support/tls_gcc.h
rename to src/core/lib/gpr/tls_gcc.h
index b44f0f1..72b360b 100644
--- a/include/grpc/support/tls_gcc.h
+++ b/src/core/lib/gpr/tls_gcc.h
@@ -16,8 +16,10 @@
  *
  */
 
-#ifndef GRPC_SUPPORT_TLS_GCC_H
-#define GRPC_SUPPORT_TLS_GCC_H
+#ifndef GRPC_CORE_LIB_GPR_TLS_GCC_H
+#define GRPC_CORE_LIB_GPR_TLS_GCC_H
+
+#include <grpc/support/port_platform.h>
 
 #include <stdbool.h>
 
@@ -47,4 +49,4 @@
 #define gpr_tls_set(tls, new_value) (((tls)->value) = (new_value))
 #define gpr_tls_get(tls) ((tls)->value)
 
-#endif /* GRPC_SUPPORT_TLS_GCC_H */
+#endif /* GRPC_CORE_LIB_GPR_TLS_GCC_H */
diff --git a/include/grpc/support/tls_msvc.h b/src/core/lib/gpr/tls_msvc.h
similarity index 90%
rename from include/grpc/support/tls_msvc.h
rename to src/core/lib/gpr/tls_msvc.h
index 68a411f..f4b3f0f 100644
--- a/include/grpc/support/tls_msvc.h
+++ b/src/core/lib/gpr/tls_msvc.h
@@ -16,10 +16,12 @@
  *
  */
 
-#ifndef GRPC_SUPPORT_TLS_MSVC_H
-#define GRPC_SUPPORT_TLS_MSVC_H
+#ifndef GRPC_CORE_LIB_GPR_TLS_MSVC_H
+#define GRPC_CORE_LIB_GPR_TLS_MSVC_H
 
 /** Thread local storage based on ms visual c compiler primitives.
+#include <grpc/support/port_platform.h>
+
    #include tls.h to use this - and see that file for documentation */
 
 struct gpr_msvc_thread_local {
@@ -47,4 +49,4 @@
 #define gpr_tls_set(tls, new_value) (((tls)->value) = (new_value))
 #define gpr_tls_get(tls) ((tls)->value)
 
-#endif /* GRPC_SUPPORT_TLS_MSVC_H */
+#endif /* GRPC_CORE_LIB_GPR_TLS_MSVC_H */
diff --git a/src/core/lib/gpr/tls_pthread.cc b/src/core/lib/gpr/tls_pthread.cc
index ebeef2a..2e5b306 100644
--- a/src/core/lib/gpr/tls_pthread.cc
+++ b/src/core/lib/gpr/tls_pthread.cc
@@ -20,7 +20,7 @@
 
 #ifdef GPR_PTHREAD_TLS
 
-#include <grpc/support/tls.h>
+#include "src/core/lib/gpr/tls.h"
 
 intptr_t gpr_tls_set(struct gpr_pthread_thread_local* tls, intptr_t value) {
   GPR_ASSERT(0 == pthread_setspecific(tls->key, (void*)value));
diff --git a/include/grpc/support/tls_pthread.h b/src/core/lib/gpr/tls_pthread.h
similarity index 91%
rename from include/grpc/support/tls_pthread.h
rename to src/core/lib/gpr/tls_pthread.h
index 249c8b1..a15f2f3 100644
--- a/include/grpc/support/tls_pthread.h
+++ b/src/core/lib/gpr/tls_pthread.h
@@ -16,8 +16,10 @@
  *
  */
 
-#ifndef GRPC_SUPPORT_TLS_PTHREAD_H
-#define GRPC_SUPPORT_TLS_PTHREAD_H
+#ifndef GRPC_CORE_LIB_GPR_TLS_PTHREAD_H
+#define GRPC_CORE_LIB_GPR_TLS_PTHREAD_H
+
+#include <grpc/support/port_platform.h>
 
 #include <grpc/support/log.h> /* for GPR_ASSERT */
 #include <pthread.h>
@@ -51,4 +53,4 @@
 }
 #endif
 
-#endif /* GRPC_SUPPORT_TLS_PTHREAD_H */
+#endif /* GRPC_CORE_LIB_GPR_TLS_PTHREAD_H */
diff --git a/src/core/lib/gpr/tmpfile.h b/src/core/lib/gpr/tmpfile.h
index f47ec7a..3ce3ff5 100644
--- a/src/core/lib/gpr/tmpfile.h
+++ b/src/core/lib/gpr/tmpfile.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_GPR_TMPFILE_H
 #define GRPC_CORE_LIB_GPR_TMPFILE_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stdio.h>
 
 /* Creates a temporary file from a prefix.
diff --git a/include/grpc/support/useful.h b/src/core/lib/gpr/useful.h
similarity index 94%
rename from include/grpc/support/useful.h
rename to src/core/lib/gpr/useful.h
index bd66d3b..a4e73b9 100644
--- a/include/grpc/support/useful.h
+++ b/src/core/lib/gpr/useful.h
@@ -16,8 +16,8 @@
  *
  */
 
-#ifndef GRPC_SUPPORT_USEFUL_H
-#define GRPC_SUPPORT_USEFUL_H
+#ifndef GRPC_CORE_LIB_GPR_USEFUL_H
+#define GRPC_CORE_LIB_GPR_USEFUL_H
 
 /** useful macros that don't belong anywhere else */
 
@@ -62,4 +62,4 @@
 #define GPR_HASH_POINTER(x, range) \
   ((((size_t)x) >> 4) ^ (((size_t)x) >> 9) ^ (((size_t)x) >> 14)) % (range)
 
-#endif /* GRPC_SUPPORT_USEFUL_H */
+#endif /* GRPC_CORE_LIB_GPR_USEFUL_H */
diff --git a/src/core/lib/gprpp/atomic_with_atm.h b/src/core/lib/gprpp/atomic_with_atm.h
index 6abf0bc..3d0021b 100644
--- a/src/core/lib/gprpp/atomic_with_atm.h
+++ b/src/core/lib/gprpp/atomic_with_atm.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_GPRPP_ATOMIC_WITH_ATM_H
 #define GRPC_CORE_LIB_GPRPP_ATOMIC_WITH_ATM_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/atm.h>
 
 namespace grpc_core {
diff --git a/src/core/lib/gprpp/atomic_with_std.h b/src/core/lib/gprpp/atomic_with_std.h
index 83322b8..a4ad16e 100644
--- a/src/core/lib/gprpp/atomic_with_std.h
+++ b/src/core/lib/gprpp/atomic_with_std.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_GPRPP_ATOMIC_WITH_STD_H
 #define GRPC_CORE_LIB_GPRPP_ATOMIC_WITH_STD_H
 
+#include <grpc/support/port_platform.h>
+
 #include <atomic>
 
 namespace grpc_core {
diff --git a/src/core/lib/gprpp/inlined_vector.h b/src/core/lib/gprpp/inlined_vector.h
index 2ced3d7..ca95aec 100644
--- a/src/core/lib/gprpp/inlined_vector.h
+++ b/src/core/lib/gprpp/inlined_vector.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_GPRPP_INLINED_VECTOR_H
 #define GRPC_CORE_LIB_GPRPP_INLINED_VECTOR_H
 
+#include <grpc/support/port_platform.h>
+
 #include <cassert>
 
 #include "src/core/lib/gprpp/memory.h"
diff --git a/src/core/lib/gprpp/manual_constructor.h b/src/core/lib/gprpp/manual_constructor.h
index cee38ab..7f827ca 100644
--- a/src/core/lib/gprpp/manual_constructor.h
+++ b/src/core/lib/gprpp/manual_constructor.h
@@ -21,6 +21,8 @@
 
 // manually construct a region of memory with some type
 
+#include <grpc/support/port_platform.h>
+
 #include <stddef.h>
 #include <stdlib.h>
 #include <new>
@@ -154,7 +156,7 @@
     static_assert(
         manual_ctor_impl::is_one_of<DerivedType, DerivedTypes...>::value,
         "DerivedType must be one of the predeclared DerivedTypes");
-    GPR_ASSERT(reinterpret_cast<BaseType*>(static_cast<DerivedType*>(p)) == p);
+    GPR_ASSERT(static_cast<BaseType*>(p) == p);
   }
 
   typename std::aligned_storage<
diff --git a/src/core/lib/gprpp/memory.h b/src/core/lib/gprpp/memory.h
index 17f42f5..ba2f546 100644
--- a/src/core/lib/gprpp/memory.h
+++ b/src/core/lib/gprpp/memory.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_GPRPP_MEMORY_H
 #define GRPC_CORE_LIB_GPRPP_MEMORY_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/alloc.h>
 
 #include <limits>
@@ -27,10 +29,15 @@
 
 namespace grpc_core {
 
+// The alignment of memory returned by gpr_malloc().
+constexpr size_t kAlignmentForDefaultAllocationInBytes = 8;
+
 // Alternative to new, since we cannot use it (for fear of libstdc++)
 template <typename T, typename... Args>
 inline T* New(Args&&... args) {
-  void* p = gpr_malloc(sizeof(T));
+  void* p = alignof(T) > kAlignmentForDefaultAllocationInBytes
+                ? gpr_malloc_aligned(sizeof(T), alignof(T))
+                : gpr_malloc(sizeof(T));
   return new (p) T(std::forward<Args>(args)...);
 }
 
@@ -38,7 +45,11 @@
 template <typename T>
 inline void Delete(T* p) {
   p->~T();
-  gpr_free(p);
+  if (alignof(T) > kAlignmentForDefaultAllocationInBytes) {
+    gpr_free_aligned(p);
+  } else {
+    gpr_free(p);
+  }
 }
 
 template <typename T>
diff --git a/src/core/lib/gprpp/orphanable.h b/src/core/lib/gprpp/orphanable.h
index 5019973..a5bc8d8 100644
--- a/src/core/lib/gprpp/orphanable.h
+++ b/src/core/lib/gprpp/orphanable.h
@@ -19,15 +19,19 @@
 #ifndef GRPC_CORE_LIB_GPRPP_ORPHANABLE_H
 #define GRPC_CORE_LIB_GPRPP_ORPHANABLE_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 
+#include <cinttypes>
 #include <memory>
 
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/gprpp/abstract.h"
 #include "src/core/lib/gprpp/debug_location.h"
 #include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
 
 namespace grpc_core {
 
@@ -69,6 +73,7 @@
 }
 
 // A type of Orphanable with internal ref-counting.
+template <typename Child>
 class InternallyRefCounted : public Orphanable {
  public:
   // Not copyable nor movable.
@@ -78,10 +83,20 @@
   GRPC_ABSTRACT_BASE_CLASS
 
  protected:
+  // Allow Delete() to access destructor.
+  template <typename T>
+  friend void Delete(T*);
+
+  // Allow RefCountedPtr<> to access Unref() and IncrementRefCount().
+  friend class RefCountedPtr<Child>;
+
   InternallyRefCounted() { gpr_ref_init(&refs_, 1); }
   virtual ~InternallyRefCounted() {}
 
-  void Ref() { gpr_ref(&refs_); }
+  RefCountedPtr<Child> Ref() GRPC_MUST_USE_RESULT {
+    IncrementRefCount();
+    return RefCountedPtr<Child>(static_cast<Child*>(this));
+  }
 
   void Unref() {
     if (gpr_unref(&refs_)) {
@@ -89,11 +104,9 @@
     }
   }
 
-  // Allow Delete() to access destructor.
-  template <typename T>
-  friend void Delete(T*);
-
  private:
+  void IncrementRefCount() { gpr_ref(&refs_); }
+
   gpr_refcount refs_;
 };
 
@@ -103,6 +116,7 @@
 // pointers and legacy code that is manually calling Ref() and Unref().
 // Once all of our code is converted to idiomatic C++, we may be able to
 // eliminate this class.
+template <typename Child>
 class InternallyRefCountedWithTracing : public Orphanable {
  public:
   // Not copyable nor movable.
@@ -118,6 +132,9 @@
   template <typename T>
   friend void Delete(T*);
 
+  // Allow RefCountedPtr<> to access Unref() and IncrementRefCount().
+  friend class RefCountedPtr<Child>;
+
   InternallyRefCountedWithTracing()
       : InternallyRefCountedWithTracing(static_cast<TraceFlag*>(nullptr)) {}
 
@@ -133,18 +150,27 @@
 
   virtual ~InternallyRefCountedWithTracing() {}
 
-  void Ref() { gpr_ref(&refs_); }
+  RefCountedPtr<Child> Ref() GRPC_MUST_USE_RESULT {
+    IncrementRefCount();
+    return RefCountedPtr<Child>(static_cast<Child*>(this));
+  }
 
-  void Ref(const DebugLocation& location, const char* reason) {
+  RefCountedPtr<Child> Ref(const DebugLocation& location,
+                           const char* reason) GRPC_MUST_USE_RESULT {
     if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) {
       gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count);
       gpr_log(GPR_DEBUG, "%s:%p %s:%d ref %" PRIdPTR " -> %" PRIdPTR " %s",
               trace_flag_->name(), this, location.file(), location.line(),
               old_refs, old_refs + 1, reason);
     }
-    Ref();
+    return Ref();
   }
 
+  // TODO(roth): Once all of our code is converted to C++ and can use
+  // RefCountedPtr<> instead of manual ref-counting, make the Unref() methods
+  // private, since they will only be used by RefCountedPtr<>, which is a
+  // friend of this class.
+
   void Unref() {
     if (gpr_unref(&refs_)) {
       Delete(this);
@@ -162,6 +188,8 @@
   }
 
  private:
+  void IncrementRefCount() { gpr_ref(&refs_); }
+
   TraceFlag* trace_flag_ = nullptr;
   gpr_refcount refs_;
 };
diff --git a/src/core/lib/gprpp/ref_counted.h b/src/core/lib/gprpp/ref_counted.h
index c68118a..46bfaf7 100644
--- a/src/core/lib/gprpp/ref_counted.h
+++ b/src/core/lib/gprpp/ref_counted.h
@@ -19,23 +19,39 @@
 #ifndef GRPC_CORE_LIB_GPRPP_REF_COUNTED_H
 #define GRPC_CORE_LIB_GPRPP_REF_COUNTED_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 
+#include <cinttypes>
+
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/gprpp/abstract.h"
 #include "src/core/lib/gprpp/debug_location.h"
 #include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
 
 namespace grpc_core {
 
 // A base class for reference-counted objects.
 // New objects should be created via New() and start with a refcount of 1.
 // When the refcount reaches 0, the object will be deleted via Delete().
+//
+// This will commonly be used by CRTP (curiously-recurring template pattern)
+// e.g., class MyClass : public RefCounted<MyClass>
+template <typename Child>
 class RefCounted {
  public:
-  void Ref() { gpr_ref(&refs_); }
+  RefCountedPtr<Child> Ref() GRPC_MUST_USE_RESULT {
+    IncrementRefCount();
+    return RefCountedPtr<Child>(static_cast<Child*>(this));
+  }
 
+  // TODO(roth): Once all of our code is converted to C++ and can use
+  // RefCountedPtr<> instead of manual ref-counting, make this method
+  // private, since it will only be used by RefCountedPtr<>, which is a
+  // friend of this class.
   void Unref() {
     if (gpr_unref(&refs_)) {
       Delete(this);
@@ -58,6 +74,11 @@
   virtual ~RefCounted() {}
 
  private:
+  // Allow RefCountedPtr<> to access IncrementRefCount().
+  friend class RefCountedPtr<Child>;
+
+  void IncrementRefCount() { gpr_ref(&refs_); }
+
   gpr_refcount refs_;
 };
 
@@ -67,20 +88,30 @@
 // pointers and legacy code that is manually calling Ref() and Unref().
 // Once all of our code is converted to idiomatic C++, we may be able to
 // eliminate this class.
+template <typename Child>
 class RefCountedWithTracing {
  public:
-  void Ref() { gpr_ref(&refs_); }
+  RefCountedPtr<Child> Ref() GRPC_MUST_USE_RESULT {
+    IncrementRefCount();
+    return RefCountedPtr<Child>(static_cast<Child*>(this));
+  }
 
-  void Ref(const DebugLocation& location, const char* reason) {
+  RefCountedPtr<Child> Ref(const DebugLocation& location,
+                           const char* reason) GRPC_MUST_USE_RESULT {
     if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) {
       gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count);
       gpr_log(GPR_DEBUG, "%s:%p %s:%d ref %" PRIdPTR " -> %" PRIdPTR " %s",
               trace_flag_->name(), this, location.file(), location.line(),
               old_refs, old_refs + 1, reason);
     }
-    Ref();
+    return Ref();
   }
 
+  // TODO(roth): Once all of our code is converted to C++ and can use
+  // RefCountedPtr<> instead of manual ref-counting, make the Unref() methods
+  // private, since they will only be used by RefCountedPtr<>, which is a
+  // friend of this class.
+
   void Unref() {
     if (gpr_unref(&refs_)) {
       Delete(this);
@@ -124,6 +155,11 @@
   virtual ~RefCountedWithTracing() {}
 
  private:
+  // Allow RefCountedPtr<> to access IncrementRefCount().
+  friend class RefCountedPtr<Child>;
+
+  void IncrementRefCount() { gpr_ref(&refs_); }
+
   TraceFlag* trace_flag_ = nullptr;
   gpr_refcount refs_;
 };
diff --git a/src/core/lib/gprpp/ref_counted_ptr.h b/src/core/lib/gprpp/ref_counted_ptr.h
index dda0f00..388e2ec 100644
--- a/src/core/lib/gprpp/ref_counted_ptr.h
+++ b/src/core/lib/gprpp/ref_counted_ptr.h
@@ -19,18 +19,21 @@
 #ifndef GRPC_CORE_LIB_GPRPP_REF_COUNTED_PTR_H
 #define GRPC_CORE_LIB_GPRPP_REF_COUNTED_PTR_H
 
+#include <grpc/support/port_platform.h>
+
 #include <utility>
 
 #include "src/core/lib/gprpp/memory.h"
 
 namespace grpc_core {
 
-// A smart pointer class for objects that provide Ref() and Unref() methods,
-// such as those provided by the RefCounted base class.
+// A smart pointer class for objects that provide IncrementRefCount() and
+// Unref() methods, such as those provided by the RefCounted base class.
 template <typename T>
 class RefCountedPtr {
  public:
   RefCountedPtr() {}
+  RefCountedPtr(std::nullptr_t) {}
 
   // If value is non-null, we take ownership of a ref to it.
   explicit RefCountedPtr(T* value) { value_ = value; }
@@ -49,13 +52,13 @@
 
   // Copy support.
   RefCountedPtr(const RefCountedPtr& other) {
-    if (other.value_ != nullptr) other.value_->Ref();
+    if (other.value_ != nullptr) other.value_->IncrementRefCount();
     value_ = other.value_;
   }
   RefCountedPtr& operator=(const RefCountedPtr& other) {
     // Note: Order of reffing and unreffing is important here in case value_
     // and other.value_ are the same object.
-    if (other.value_ != nullptr) other.value_->Ref();
+    if (other.value_ != nullptr) other.value_->IncrementRefCount();
     if (value_ != nullptr) value_->Unref();
     value_ = other.value_;
     return *this;
@@ -71,6 +74,16 @@
     value_ = value;
   }
 
+  // TODO(roth): This method exists solely as a transition mechanism to allow
+  // us to pass a ref to idiomatic C code that does not use RefCountedPtr<>.
+  // Once all of our code has been converted to idiomatic C++, this
+  // method should go away.
+  T* release() {
+    T* value = value_;
+    value_ = nullptr;
+    return value;
+  }
+
   T* get() const { return value_; }
 
   T& operator*() const { return *value_; }
diff --git a/src/core/lib/gprpp/thd.h b/src/core/lib/gprpp/thd.h
new file mode 100644
index 0000000..05c7ded
--- /dev/null
+++ b/src/core/lib/gprpp/thd.h
@@ -0,0 +1,135 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_LIB_GPRPP_THD_H
+#define GRPC_CORE_LIB_GPRPP_THD_H
+
+/** Internal thread interface. */
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd_id.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/gprpp/abstract.h"
+#include "src/core/lib/gprpp/memory.h"
+
+namespace grpc_core {
+namespace internal {
+
+/// Base class for platform-specific thread-state
+class ThreadInternalsInterface {
+ public:
+  virtual ~ThreadInternalsInterface() {}
+  virtual void Start() GRPC_ABSTRACT;
+  virtual void Join() GRPC_ABSTRACT;
+  GRPC_ABSTRACT_BASE_CLASS
+};
+
+}  // namespace internal
+
+class Thread {
+ public:
+  /// Default constructor only to allow use in structs that lack constructors
+  /// Does not produce a validly-constructed thread; must later
+  /// use placement new to construct a real thread. Does not init mu_ and cv_
+  Thread() : state_(FAKE), impl_(nullptr) {}
+
+  /// Normal constructor to create a thread with name \a thd_name,
+  /// which will execute a thread based on function \a thd_body
+  /// with argument \a arg once it is started.
+  /// The optional \a success argument indicates whether the thread
+  /// is successfully created.
+  Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg,
+         bool* success = nullptr);
+
+  /// Move constructor for thread. After this is called, the other thread
+  /// no longer represents a living thread object
+  Thread(Thread&& other) : state_(other.state_), impl_(other.impl_) {
+    other.state_ = MOVED;
+    other.impl_ = nullptr;
+  }
+
+  /// Move assignment operator for thread. After this is called, the other
+  /// thread no longer represents a living thread object. Not allowed if this
+  /// thread actually exists
+  Thread& operator=(Thread&& other) {
+    if (this != &other) {
+      // TODO(vjpai): if we can be sure that all Thread's are actually
+      // constructed, then we should assert GPR_ASSERT(impl_ == nullptr) here.
+      // However, as long as threads come in structures that are
+      // allocated via gpr_malloc, this will not be the case, so we cannot
+      // assert it for the time being.
+      state_ = other.state_;
+      impl_ = other.impl_;
+      other.state_ = MOVED;
+      other.impl_ = nullptr;
+    }
+    return *this;
+  }
+
+  /// The destructor is strictly optional; either the thread never came to life
+  /// and the constructor itself killed it or it has already been joined and
+  /// the Join function kills it. The destructor shouldn't have to do anything.
+  ~Thread() { GPR_ASSERT(impl_ == nullptr); }
+
+  void Start() {
+    if (impl_ != nullptr) {
+      GPR_ASSERT(state_ == ALIVE);
+      state_ = STARTED;
+      impl_->Start();
+    } else {
+      GPR_ASSERT(state_ == FAILED);
+    }
+  };
+
+  void Join() {
+    if (impl_ != nullptr) {
+      impl_->Join();
+      grpc_core::Delete(impl_);
+      state_ = DONE;
+      impl_ = nullptr;
+    } else {
+      GPR_ASSERT(state_ == FAILED);
+    }
+  };
+
+  static void Init();
+  static bool AwaitAll(gpr_timespec deadline);
+
+ private:
+  Thread(const Thread&) = delete;
+  Thread& operator=(const Thread&) = delete;
+
+  /// The thread states are as follows:
+  /// FAKE -- just a dummy placeholder Thread created by the default constructor
+  /// ALIVE -- an actual thread of control exists associated with this thread
+  /// STARTED -- the thread of control has been started
+  /// DONE -- the thread of control has completed and been joined
+  /// FAILED -- the thread of control never came alive
+  /// MOVED -- contents were moved out and we're no longer tracking them
+  enum ThreadState { FAKE, ALIVE, STARTED, DONE, FAILED, MOVED };
+  ThreadState state_;
+  internal::ThreadInternalsInterface* impl_;
+};
+
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_GPRPP_THD_H */
diff --git a/src/core/lib/gprpp/thd_posix.cc b/src/core/lib/gprpp/thd_posix.cc
new file mode 100644
index 0000000..2f6c2ed
--- /dev/null
+++ b/src/core/lib/gprpp/thd_posix.cc
@@ -0,0 +1,209 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/* Posix implementation for gpr threads. */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_SYNC
+
+#include "src/core/lib/gprpp/thd.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd_id.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "src/core/lib/gpr/fork.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/memory.h"
+
+namespace grpc_core {
+namespace {
+gpr_mu g_mu;
+gpr_cv g_cv;
+int g_thread_count;
+int g_awaiting_threads;
+
+class ThreadInternalsPosix;
+struct thd_arg {
+  ThreadInternalsPosix* thread;
+  void (*body)(void* arg); /* body of a thread */
+  void* arg;               /* argument to a thread */
+  const char* name;        /* name of thread. Can be nullptr. */
+};
+
+class ThreadInternalsPosix
+    : public grpc_core::internal::ThreadInternalsInterface {
+ public:
+  ThreadInternalsPosix(const char* thd_name, void (*thd_body)(void* arg),
+                       void* arg, bool* success)
+      : started_(false) {
+    gpr_mu_init(&mu_);
+    gpr_cv_init(&ready_);
+    pthread_attr_t attr;
+    /* don't use gpr_malloc as we may cause an infinite recursion with
+     * the profiling code */
+    thd_arg* info = static_cast<thd_arg*>(malloc(sizeof(*info)));
+    GPR_ASSERT(info != nullptr);
+    info->thread = this;
+    info->body = thd_body;
+    info->arg = arg;
+    info->name = thd_name;
+    inc_thd_count();
+
+    GPR_ASSERT(pthread_attr_init(&attr) == 0);
+    GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) ==
+               0);
+
+    *success =
+        (pthread_create(&pthread_id_, &attr,
+                        [](void* v) -> void* {
+                          thd_arg arg = *static_cast<thd_arg*>(v);
+                          free(v);
+                          if (arg.name != nullptr) {
+#if GPR_APPLE_PTHREAD_NAME
+                            /* Apple supports 64 characters, and will
+                             * truncate if it's longer. */
+                            pthread_setname_np(arg.name);
+#elif GPR_LINUX_PTHREAD_NAME
+                            /* Linux supports 16 characters max, and will
+                             * error if it's longer. */
+                            char buf[16];
+                            size_t buf_len = GPR_ARRAY_SIZE(buf) - 1;
+                            strncpy(buf, arg.name, buf_len);
+                            buf[buf_len] = '\0';
+                            pthread_setname_np(pthread_self(), buf);
+#endif  // GPR_APPLE_PTHREAD_NAME
+                          }
+
+                          gpr_mu_lock(&arg.thread->mu_);
+                          while (!arg.thread->started_) {
+                            gpr_cv_wait(&arg.thread->ready_, &arg.thread->mu_,
+                                        gpr_inf_future(GPR_CLOCK_MONOTONIC));
+                          }
+                          gpr_mu_unlock(&arg.thread->mu_);
+
+                          (*arg.body)(arg.arg);
+                          dec_thd_count();
+                          return nullptr;
+                        },
+                        info) == 0);
+
+    GPR_ASSERT(pthread_attr_destroy(&attr) == 0);
+
+    if (!success) {
+      /* don't use gpr_free, as this was allocated using malloc (see above) */
+      free(info);
+      dec_thd_count();
+    }
+  };
+
+  ~ThreadInternalsPosix() override {
+    gpr_mu_destroy(&mu_);
+    gpr_cv_destroy(&ready_);
+  }
+
+  void Start() override {
+    gpr_mu_lock(&mu_);
+    started_ = true;
+    gpr_cv_signal(&ready_);
+    gpr_mu_unlock(&mu_);
+  }
+
+  void Join() override { pthread_join(pthread_id_, nullptr); }
+
+ private:
+  /*****************************************
+   * Only used when fork support is enabled
+   */
+
+  static void inc_thd_count() {
+    if (grpc_fork_support_enabled()) {
+      gpr_mu_lock(&g_mu);
+      g_thread_count++;
+      gpr_mu_unlock(&g_mu);
+    }
+  }
+
+  static void dec_thd_count() {
+    if (grpc_fork_support_enabled()) {
+      gpr_mu_lock(&g_mu);
+      g_thread_count--;
+      if (g_awaiting_threads && g_thread_count == 0) {
+        gpr_cv_signal(&g_cv);
+      }
+      gpr_mu_unlock(&g_mu);
+    }
+  }
+
+  gpr_mu mu_;
+  gpr_cv ready_;
+  bool started_;
+  pthread_t pthread_id_;
+};
+
+}  // namespace
+
+Thread::Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg,
+               bool* success) {
+  bool outcome = false;
+  impl_ =
+      grpc_core::New<ThreadInternalsPosix>(thd_name, thd_body, arg, &outcome);
+  if (outcome) {
+    state_ = ALIVE;
+  } else {
+    state_ = FAILED;
+    grpc_core::Delete(impl_);
+    impl_ = nullptr;
+  }
+
+  if (success != nullptr) {
+    *success = outcome;
+  }
+}
+
+void Thread::Init() {
+  gpr_mu_init(&g_mu);
+  gpr_cv_init(&g_cv);
+  g_thread_count = 0;
+  g_awaiting_threads = 0;
+}
+
+bool Thread::AwaitAll(gpr_timespec deadline) {
+  gpr_mu_lock(&g_mu);
+  g_awaiting_threads = 1;
+  int res = 0;
+  while ((g_thread_count > 0) &&
+         (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0)) {
+    res = gpr_cv_wait(&g_cv, &g_mu, deadline);
+  }
+  g_awaiting_threads = 0;
+  gpr_mu_unlock(&g_mu);
+  return res == 0;
+}
+
+}  // namespace grpc_core
+
+// The following is in the external namespace as it is exposed as C89 API
+gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)pthread_self(); }
+
+#endif /* GPR_POSIX_SYNC */
diff --git a/src/core/lib/gprpp/thd_windows.cc b/src/core/lib/gprpp/thd_windows.cc
new file mode 100644
index 0000000..59ea02f
--- /dev/null
+++ b/src/core/lib/gprpp/thd_windows.cc
@@ -0,0 +1,162 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/* Windows implementation for gpr threads. */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WINDOWS
+
+#include "src/core/lib/gprpp/thd.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/thd_id.h>
+#include <string.h>
+
+#include "src/core/lib/gprpp/memory.h"
+
+#if defined(_MSC_VER)
+#define thread_local __declspec(thread)
+#define WIN_LAMBDA
+#elif defined(__GNUC__)
+#define thread_local __thread
+#define WIN_LAMBDA WINAPI
+#else
+#error "Unknown compiler - please file a bug report"
+#endif
+
+namespace {
+class ThreadInternalsWindows;
+struct thd_info {
+  ThreadInternalsWindows* thread;
+  void (*body)(void* arg); /* body of a thread */
+  void* arg;               /* argument to a thread */
+  HANDLE join_event;       /* the join event */
+};
+
+thread_local struct thd_info* g_thd_info;
+
+class ThreadInternalsWindows
+    : public grpc_core::internal::ThreadInternalsInterface {
+ public:
+  ThreadInternalsWindows(void (*thd_body)(void* arg), void* arg, bool* success)
+      : started_(false) {
+    gpr_mu_init(&mu_);
+    gpr_cv_init(&ready_);
+
+    HANDLE handle;
+    info_ = (struct thd_info*)gpr_malloc(sizeof(*info_));
+    info_->thread = this;
+    info_->body = thd_body;
+    info_->arg = arg;
+
+    info_->join_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+    if (info_->join_event == nullptr) {
+      gpr_free(info_);
+      *success = false;
+    } else {
+      handle = CreateThread(
+          nullptr, 64 * 1024,
+          [](void* v) WIN_LAMBDA -> DWORD {
+            g_thd_info = static_cast<thd_info*>(v);
+            gpr_mu_lock(&g_thd_info->thread->mu_);
+            while (!g_thd_info->thread->started_) {
+              gpr_cv_wait(&g_thd_info->thread->ready_, &g_thd_info->thread->mu_,
+                          gpr_inf_future(GPR_CLOCK_MONOTONIC));
+            }
+            gpr_mu_unlock(&g_thd_info->thread->mu_);
+            g_thd_info->body(g_thd_info->arg);
+            BOOL ret = SetEvent(g_thd_info->join_event);
+            GPR_ASSERT(ret);
+            return 0;
+          },
+          info_, 0, nullptr);
+      if (handle == nullptr) {
+        destroy_thread();
+        *success = false;
+      } else {
+        CloseHandle(handle);
+        *success = true;
+      }
+    }
+  }
+
+  ~ThreadInternalsWindows() override {
+    gpr_mu_destroy(&mu_);
+    gpr_cv_destroy(&ready_);
+  }
+
+  void Start() override {
+    gpr_mu_lock(&mu_);
+    started_ = true;
+    gpr_cv_signal(&ready_);
+    gpr_mu_unlock(&mu_);
+  }
+
+  void Join() override {
+    DWORD ret = WaitForSingleObject(info_->join_event, INFINITE);
+    GPR_ASSERT(ret == WAIT_OBJECT_0);
+    destroy_thread();
+  }
+
+ private:
+  void destroy_thread() {
+    CloseHandle(info_->join_event);
+    gpr_free(info_);
+  }
+
+  gpr_mu mu_;
+  gpr_cv ready_;
+  bool started_;
+  thd_info* info_;
+};
+
+}  // namespace
+
+namespace grpc_core {
+
+void Thread::Init() {}
+
+bool Thread::AwaitAll(gpr_timespec deadline) {
+  // TODO: Consider adding this if needed
+  return false;
+}
+
+Thread::Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg,
+               bool* success) {
+  bool outcome = false;
+  impl_ = grpc_core::New<ThreadInternalsWindows>(thd_body, arg, &outcome);
+  if (outcome) {
+    state_ = ALIVE;
+  } else {
+    state_ = FAILED;
+    grpc_core::Delete(impl_);
+    impl_ = nullptr;
+  }
+
+  if (success != nullptr) {
+    *success = outcome;
+  }
+}
+
+}  // namespace grpc_core
+
+gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)g_thd_info; }
+
+#endif /* GPR_WINDOWS */
diff --git a/src/core/lib/http/format_request.cc b/src/core/lib/http/format_request.cc
index 473fa71..1712344 100644
--- a/src/core/lib/http/format_request.cc
+++ b/src/core/lib/http/format_request.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/http/format_request.h"
 
 #include <stdarg.h>
@@ -25,7 +27,6 @@
 #include <grpc/slice.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 #include "src/core/lib/gpr/string.h"
 
 static void fill_common_header(const grpc_httpcli_request* request,
@@ -90,7 +91,8 @@
     if (!has_content_type) {
       gpr_strvec_add(&out, gpr_strdup("Content-Type: text/plain\r\n"));
     }
-    gpr_asprintf(&tmp, "Content-Length: %lu\r\n", (unsigned long)body_size);
+    gpr_asprintf(&tmp, "Content-Length: %lu\r\n",
+                 static_cast<unsigned long>(body_size));
     gpr_strvec_add(&out, tmp);
   }
   gpr_strvec_add(&out, gpr_strdup("\r\n"));
@@ -98,7 +100,7 @@
   gpr_strvec_destroy(&out);
 
   if (body_bytes) {
-    tmp = (char*)gpr_realloc(tmp, out_len + body_size);
+    tmp = static_cast<char*>(gpr_realloc(tmp, out_len + body_size));
     memcpy(tmp + out_len, body_bytes, body_size);
     out_len += body_size;
   }
diff --git a/src/core/lib/http/format_request.h b/src/core/lib/http/format_request.h
index c191965..bcc332f 100644
--- a/src/core/lib/http/format_request.h
+++ b/src/core/lib/http/format_request.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_HTTP_FORMAT_REQUEST_H
 #define GRPC_CORE_LIB_HTTP_FORMAT_REQUEST_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice.h>
 #include "src/core/lib/http/httpcli.h"
 
diff --git a/src/core/lib/http/httpcli.cc b/src/core/lib/http/httpcli.cc
index c43c92b..1206007 100644
--- a/src/core/lib/http/httpcli.cc
+++ b/src/core/lib/http/httpcli.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/http/httpcli.h"
 
 #include <string.h>
@@ -23,7 +25,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
@@ -124,7 +125,7 @@
 }
 
 static void on_read(void* user_data, grpc_error* error) {
-  internal_request* req = (internal_request*)user_data;
+  internal_request* req = static_cast<internal_request*>(user_data);
   size_t i;
 
   for (i = 0; i < req->incoming.count; i++) {
@@ -151,7 +152,7 @@
 static void on_written(internal_request* req) { do_read(req); }
 
 static void done_write(void* arg, grpc_error* error) {
-  internal_request* req = (internal_request*)arg;
+  internal_request* req = static_cast<internal_request*>(arg);
   if (error == GRPC_ERROR_NONE) {
     on_written(req);
   } else {
@@ -166,7 +167,7 @@
 }
 
 static void on_handshake_done(void* arg, grpc_endpoint* ep) {
-  internal_request* req = (internal_request*)arg;
+  internal_request* req = static_cast<internal_request*>(arg);
 
   if (!ep) {
     next_address(req, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -179,7 +180,7 @@
 }
 
 static void on_connected(void* arg, grpc_error* error) {
-  internal_request* req = (internal_request*)arg;
+  internal_request* req = static_cast<internal_request*>(arg);
 
   if (!req->ep) {
     next_address(req, GRPC_ERROR_REF(error));
@@ -213,7 +214,7 @@
 }
 
 static void on_resolved(void* arg, grpc_error* error) {
-  internal_request* req = (internal_request*)arg;
+  internal_request* req = static_cast<internal_request*>(arg);
   if (error != GRPC_ERROR_NONE) {
     finish(req, GRPC_ERROR_REF(error));
     return;
@@ -230,7 +231,7 @@
                                    grpc_httpcli_response* response,
                                    const char* name, grpc_slice request_text) {
   internal_request* req =
-      (internal_request*)gpr_malloc(sizeof(internal_request));
+      static_cast<internal_request*>(gpr_malloc(sizeof(internal_request)));
   memset(req, 0, sizeof(*req));
   req->request_text = request_text;
   grpc_http_parser_init(&req->parser, GRPC_HTTP_RESPONSE, response);
diff --git a/src/core/lib/http/httpcli.h b/src/core/lib/http/httpcli.h
index 72d20cc..b073508 100644
--- a/src/core/lib/http/httpcli.h
+++ b/src/core/lib/http/httpcli.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_HTTP_HTTPCLI_H
 #define GRPC_CORE_LIB_HTTP_HTTPCLI_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stddef.h>
 
 #include <grpc/support/time.h>
diff --git a/src/core/lib/http/httpcli_security_connector.cc b/src/core/lib/http/httpcli_security_connector.cc
index 8664418..0b53d63 100644
--- a/src/core/lib/http/httpcli_security_connector.cc
+++ b/src/core/lib/http/httpcli_security_connector.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/http/httpcli.h"
 
 #include <string.h>
@@ -40,7 +42,7 @@
 
 static void httpcli_ssl_destroy(grpc_security_connector* sc) {
   grpc_httpcli_ssl_channel_security_connector* c =
-      (grpc_httpcli_ssl_channel_security_connector*)sc;
+      reinterpret_cast<grpc_httpcli_ssl_channel_security_connector*>(sc);
   if (c->handshaker_factory != nullptr) {
     tsi_ssl_client_handshaker_factory_unref(c->handshaker_factory);
     c->handshaker_factory = nullptr;
@@ -52,7 +54,7 @@
 static void httpcli_ssl_add_handshakers(grpc_channel_security_connector* sc,
                                         grpc_handshake_manager* handshake_mgr) {
   grpc_httpcli_ssl_channel_security_connector* c =
-      (grpc_httpcli_ssl_channel_security_connector*)sc;
+      reinterpret_cast<grpc_httpcli_ssl_channel_security_connector*>(sc);
   tsi_handshaker* handshaker = nullptr;
   if (c->handshaker_factory != nullptr) {
     tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker(
@@ -71,7 +73,7 @@
                                    grpc_auth_context** auth_context,
                                    grpc_closure* on_peer_checked) {
   grpc_httpcli_ssl_channel_security_connector* c =
-      (grpc_httpcli_ssl_channel_security_connector*)sc;
+      reinterpret_cast<grpc_httpcli_ssl_channel_security_connector*>(sc);
   grpc_error* error = GRPC_ERROR_NONE;
 
   /* Check the peer name. */
@@ -90,9 +92,9 @@
 static int httpcli_ssl_cmp(grpc_security_connector* sc1,
                            grpc_security_connector* sc2) {
   grpc_httpcli_ssl_channel_security_connector* c1 =
-      (grpc_httpcli_ssl_channel_security_connector*)sc1;
+      reinterpret_cast<grpc_httpcli_ssl_channel_security_connector*>(sc1);
   grpc_httpcli_ssl_channel_security_connector* c2 =
-      (grpc_httpcli_ssl_channel_security_connector*)sc2;
+      reinterpret_cast<grpc_httpcli_ssl_channel_security_connector*>(sc2);
   return strcmp(c1->secure_peer_name, c2->secure_peer_name);
 }
 
@@ -100,8 +102,8 @@
     httpcli_ssl_destroy, httpcli_ssl_check_peer, httpcli_ssl_cmp};
 
 static grpc_security_status httpcli_ssl_channel_security_connector_create(
-    const char* pem_root_certs, const char* secure_peer_name,
-    grpc_channel_security_connector** sc) {
+    const char* pem_root_certs, const tsi_ssl_root_certs_store* root_store,
+    const char* secure_peer_name, grpc_channel_security_connector** sc) {
   tsi_result result = TSI_OK;
   grpc_httpcli_ssl_channel_security_connector* c;
 
@@ -111,16 +113,20 @@
     return GRPC_SECURITY_ERROR;
   }
 
-  c = (grpc_httpcli_ssl_channel_security_connector*)gpr_zalloc(
-      sizeof(grpc_httpcli_ssl_channel_security_connector));
+  c = static_cast<grpc_httpcli_ssl_channel_security_connector*>(
+      gpr_zalloc(sizeof(grpc_httpcli_ssl_channel_security_connector)));
 
   gpr_ref_init(&c->base.base.refcount, 1);
   c->base.base.vtable = &httpcli_ssl_vtable;
   if (secure_peer_name != nullptr) {
     c->secure_peer_name = gpr_strdup(secure_peer_name);
   }
-  result = tsi_create_ssl_client_handshaker_factory(
-      nullptr, pem_root_certs, nullptr, nullptr, 0, &c->handshaker_factory);
+  tsi_ssl_client_handshaker_options options;
+  memset(&options, 0, sizeof(options));
+  options.pem_root_certs = pem_root_certs;
+  options.root_store = root_store;
+  result = tsi_create_ssl_client_handshaker_factory_with_options(
+      &options, &c->handshaker_factory);
   if (result != TSI_OK) {
     gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
             tsi_result_to_string(result));
@@ -146,8 +152,8 @@
 } on_done_closure;
 
 static void on_handshake_done(void* arg, grpc_error* error) {
-  grpc_handshaker_args* args = (grpc_handshaker_args*)arg;
-  on_done_closure* c = (on_done_closure*)args->user_data;
+  grpc_handshaker_args* args = static_cast<grpc_handshaker_args*>(arg);
+  on_done_closure* c = static_cast<on_done_closure*>(args->user_data);
   if (error != GRPC_ERROR_NONE) {
     const char* msg = grpc_error_string(error);
     gpr_log(GPR_ERROR, "Secure transport setup failed: %s", msg);
@@ -166,9 +172,12 @@
 static void ssl_handshake(void* arg, grpc_endpoint* tcp, const char* host,
                           grpc_millis deadline,
                           void (*on_done)(void* arg, grpc_endpoint* endpoint)) {
-  on_done_closure* c = (on_done_closure*)gpr_malloc(sizeof(*c));
-  const char* pem_root_certs = grpc_get_default_ssl_roots();
-  if (pem_root_certs == nullptr) {
+  on_done_closure* c = static_cast<on_done_closure*>(gpr_malloc(sizeof(*c)));
+  const char* pem_root_certs =
+      grpc_core::DefaultSslRootStore::GetPemRootCerts();
+  const tsi_ssl_root_certs_store* root_store =
+      grpc_core::DefaultSslRootStore::GetRootStore();
+  if (root_store == nullptr) {
     gpr_log(GPR_ERROR, "Could not get default pem root certs.");
     on_done(arg, nullptr);
     gpr_free(c);
@@ -178,7 +187,7 @@
   c->arg = arg;
   grpc_channel_security_connector* sc = nullptr;
   GPR_ASSERT(httpcli_ssl_channel_security_connector_create(
-                 pem_root_certs, host, &sc) == GRPC_SECURITY_OK);
+                 pem_root_certs, root_store, host, &sc) == GRPC_SECURITY_OK);
   grpc_arg channel_arg = grpc_security_connector_to_arg(&sc->base);
   grpc_channel_args args = {1, &channel_arg};
   c->handshake_mgr = grpc_handshake_manager_create();
diff --git a/src/core/lib/http/parser.cc b/src/core/lib/http/parser.cc
index fb4eb23..a37fdda 100644
--- a/src/core/lib/http/parser.cc
+++ b/src/core/lib/http/parser.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/http/parser.h"
 
 #include <stdbool.h>
@@ -23,12 +25,13 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
 
 grpc_core::TraceFlag grpc_http1_trace(false, "http1");
 
 static char* buf2str(void* buffer, size_t length) {
-  char* out = (char*)gpr_malloc(length + 1);
+  char* out = static_cast<char*>(gpr_malloc(length + 1));
   memcpy(out, buffer, length);
   out[length] = 0;
   return out;
@@ -87,14 +90,15 @@
   if (cur == end)
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "No method on HTTP request line");
-  parser->http.request->method = buf2str(beg, (size_t)(cur - beg - 1));
+  parser->http.request->method =
+      buf2str(beg, static_cast<size_t>(cur - beg - 1));
 
   beg = cur;
   while (cur != end && *cur++ != ' ')
     ;
   if (cur == end)
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("No path on HTTP request line");
-  parser->http.request->path = buf2str(beg, (size_t)(cur - beg - 1));
+  parser->http.request->path = buf2str(beg, static_cast<size_t>(cur - beg - 1));
 
   if (cur == end || *cur++ != 'H')
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'H'");
@@ -106,12 +110,12 @@
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'P'");
   if (cur == end || *cur++ != '/')
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected '/'");
-  vers_major = (uint8_t)(*cur++ - '1' + 1);
+  vers_major = static_cast<uint8_t>(*cur++ - '1' + 1);
   ++cur;
   if (cur == end)
     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
         "End of line in HTTP version string");
-  vers_minor = (uint8_t)(*cur++ - '1' + 1);
+  vers_minor = static_cast<uint8_t>(*cur++ - '1' + 1);
 
   if (vers_major == 1) {
     if (vers_minor == 0) {
@@ -174,14 +178,15 @@
     goto done;
   }
   GPR_ASSERT(cur >= beg);
-  hdr.key = buf2str(beg, (size_t)(cur - beg));
+  hdr.key = buf2str(beg, static_cast<size_t>(cur - beg));
   cur++; /* skip : */
 
   while (cur != end && (*cur == ' ' || *cur == '\t')) {
     cur++;
   }
   GPR_ASSERT((size_t)(end - cur) >= parser->cur_line_end_length);
-  hdr.value = buf2str(cur, (size_t)(end - cur) - parser->cur_line_end_length);
+  hdr.value = buf2str(
+      cur, static_cast<size_t>(end - cur) - parser->cur_line_end_length);
 
   switch (parser->type) {
     case GRPC_HTTP_RESPONSE:
@@ -197,8 +202,8 @@
   if (*hdr_count == parser->hdr_capacity) {
     parser->hdr_capacity =
         GPR_MAX(parser->hdr_capacity + 1, parser->hdr_capacity * 3 / 2);
-    *hdrs = (grpc_http_header*)gpr_realloc(
-        *hdrs, parser->hdr_capacity * sizeof(**hdrs));
+    *hdrs = static_cast<grpc_http_header*>(
+        gpr_realloc(*hdrs, parser->hdr_capacity * sizeof(**hdrs)));
   }
   (*hdrs)[(*hdr_count)++] = hdr;
 
@@ -256,9 +261,10 @@
 
   if (*body_length == parser->body_capacity) {
     parser->body_capacity = GPR_MAX(8, parser->body_capacity * 3 / 2);
-    *body = (char*)gpr_realloc((void*)*body, parser->body_capacity);
+    *body =
+        static_cast<char*>(gpr_realloc((void*)*body, parser->body_capacity));
   }
-  (*body)[*body_length] = (char)byte;
+  (*body)[*body_length] = static_cast<char>(byte);
   (*body_length)++;
 
   return GRPC_ERROR_NONE;
diff --git a/src/core/lib/http/parser.h b/src/core/lib/http/parser.h
index 5fef448..1d2e13e 100644
--- a/src/core/lib/http/parser.h
+++ b/src/core/lib/http/parser.h
@@ -19,8 +19,9 @@
 #ifndef GRPC_CORE_LIB_HTTP_PARSER_H
 #define GRPC_CORE_LIB_HTTP_PARSER_H
 
-#include <grpc/slice.h>
 #include <grpc/support/port_platform.h>
+
+#include <grpc/slice.h>
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/iomgr/error.h"
 
diff --git a/src/core/lib/iomgr/call_combiner.cc b/src/core/lib/iomgr/call_combiner.cc
index 0e4c9cb..24e11b6 100644
--- a/src/core/lib/iomgr/call_combiner.cc
+++ b/src/core/lib/iomgr/call_combiner.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/call_combiner.h"
 
 #include <inttypes.h>
@@ -28,13 +30,13 @@
 
 static grpc_error* decode_cancel_state_error(gpr_atm cancel_state) {
   if (cancel_state & 1) {
-    return (grpc_error*)(cancel_state & ~(gpr_atm)1);
+    return (grpc_error*)(cancel_state & ~static_cast<gpr_atm>(1));
   }
   return GRPC_ERROR_NONE;
 }
 
 static gpr_atm encode_cancel_state_error(grpc_error* error) {
-  return (gpr_atm)1 | (gpr_atm)error;
+  return static_cast<gpr_atm>(1) | (gpr_atm)error;
 }
 
 void grpc_call_combiner_init(grpc_call_combiner* call_combiner) {
@@ -68,8 +70,8 @@
             call_combiner, closure DEBUG_FMT_ARGS, reason,
             grpc_error_string(error));
   }
-  size_t prev_size =
-      (size_t)gpr_atm_full_fetch_add(&call_combiner->size, (gpr_atm)1);
+  size_t prev_size = static_cast<size_t>(
+      gpr_atm_full_fetch_add(&call_combiner->size, (gpr_atm)1));
   if (grpc_call_combiner_trace.enabled()) {
     gpr_log(GPR_DEBUG, "  size: %" PRIdPTR " -> %" PRIdPTR, prev_size,
             prev_size + 1);
@@ -90,7 +92,8 @@
     }
     // Queue was not empty, so add closure to queue.
     closure->error_data.error = error;
-    gpr_mpscq_push(&call_combiner->queue, (gpr_mpscq_node*)closure);
+    gpr_mpscq_push(&call_combiner->queue,
+                   reinterpret_cast<gpr_mpscq_node*>(closure));
   }
 }
 
@@ -102,8 +105,8 @@
             "==> grpc_call_combiner_stop() [%p] [" DEBUG_FMT_STR "%s]",
             call_combiner DEBUG_FMT_ARGS, reason);
   }
-  size_t prev_size =
-      (size_t)gpr_atm_full_fetch_add(&call_combiner->size, (gpr_atm)-1);
+  size_t prev_size = static_cast<size_t>(
+      gpr_atm_full_fetch_add(&call_combiner->size, (gpr_atm)-1));
   if (grpc_call_combiner_trace.enabled()) {
     gpr_log(GPR_DEBUG, "  size: %" PRIdPTR " -> %" PRIdPTR, prev_size,
             prev_size - 1);
@@ -115,8 +118,8 @@
         gpr_log(GPR_DEBUG, "  checking queue");
       }
       bool empty;
-      grpc_closure* closure = (grpc_closure*)gpr_mpscq_pop_and_check_end(
-          &call_combiner->queue, &empty);
+      grpc_closure* closure = reinterpret_cast<grpc_closure*>(
+          gpr_mpscq_pop_and_check_end(&call_combiner->queue, &empty));
       if (closure == nullptr) {
         // This can happen either due to a race condition within the mpscq
         // code or because of a race with grpc_call_combiner_start().
diff --git a/src/core/lib/iomgr/call_combiner.h b/src/core/lib/iomgr/call_combiner.h
index 4814dbf..0ccd08e 100644
--- a/src/core/lib/iomgr/call_combiner.h
+++ b/src/core/lib/iomgr/call_combiner.h
@@ -19,13 +19,14 @@
 #ifndef GRPC_CORE_LIB_IOMGR_CALL_COMBINER_H
 #define GRPC_CORE_LIB_IOMGR_CALL_COMBINER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stddef.h>
 
 #include <grpc/support/atm.h>
 
 #include "src/core/lib/gpr/mpscq.h"
 #include "src/core/lib/iomgr/closure.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
 
 // A simple, lock-free mechanism for serializing activity related to a
 // single call.  This is similar to a combiner but is more lightweight.
diff --git a/src/core/lib/iomgr/closure.h b/src/core/lib/iomgr/closure.h
index 2bf2578..64527d6 100644
--- a/src/core/lib/iomgr/closure.h
+++ b/src/core/lib/iomgr/closure.h
@@ -143,7 +143,7 @@
 } wrapped_closure;
 
 inline void closure_wrapper(void* arg, grpc_error* error) {
-  wrapped_closure* wc = (wrapped_closure*)arg;
+  wrapped_closure* wc = static_cast<wrapped_closure*>(arg);
   grpc_iomgr_cb_func cb = wc->cb;
   void* cb_arg = wc->cb_arg;
   gpr_free(wc);
@@ -161,7 +161,7 @@
                                          grpc_closure_scheduler* scheduler) {
 #endif
   closure_impl::wrapped_closure* wc =
-      (closure_impl::wrapped_closure*)gpr_malloc(sizeof(*wc));
+      static_cast<closure_impl::wrapped_closure*>(gpr_malloc(sizeof(*wc)));
   wc->cb = cb;
   wc->cb_arg = cb_arg;
 #ifndef NDEBUG
diff --git a/src/core/lib/iomgr/combiner.cc b/src/core/lib/iomgr/combiner.cc
index 2965d80..e66df03 100644
--- a/src/core/lib/iomgr/combiner.cc
+++ b/src/core/lib/iomgr/combiner.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/combiner.h"
 
 #include <assert.h>
@@ -72,7 +74,7 @@
 static void offload(void* arg, grpc_error* error);
 
 grpc_combiner* grpc_combiner_create(void) {
-  grpc_combiner* lock = (grpc_combiner*)gpr_zalloc(sizeof(*lock));
+  grpc_combiner* lock = static_cast<grpc_combiner*>(gpr_zalloc(sizeof(*lock)));
   gpr_ref_init(&lock->refs, 1);
   lock->scheduler.vtable = &scheduler;
   lock->finally_scheduler.vtable = &finally_scheduler;
@@ -194,7 +196,7 @@
 }
 
 static void offload(void* arg, grpc_error* error) {
-  grpc_combiner* lock = (grpc_combiner*)arg;
+  grpc_combiner* lock = static_cast<grpc_combiner*>(arg);
   push_last_on_exec_ctx(lock);
 }
 
@@ -249,7 +251,7 @@
       return true;
     }
     GPR_TIMER_SCOPE("combiner.exec1", 0);
-    grpc_closure* cl = (grpc_closure*)n;
+    grpc_closure* cl = reinterpret_cast<grpc_closure*>(n);
     grpc_error* cl_err = cl->error_data.error;
 #ifndef NDEBUG
     cl->scheduled = false;
@@ -342,7 +344,8 @@
 }
 
 static void enqueue_finally(void* closure, grpc_error* error) {
-  combiner_finally_exec((grpc_closure*)closure, GRPC_ERROR_REF(error));
+  combiner_finally_exec(static_cast<grpc_closure*>(closure),
+                        GRPC_ERROR_REF(error));
 }
 
 grpc_closure_scheduler* grpc_combiner_scheduler(grpc_combiner* combiner) {
diff --git a/src/core/lib/iomgr/combiner.h b/src/core/lib/iomgr/combiner.h
index c62d21a..0d63e46 100644
--- a/src/core/lib/iomgr/combiner.h
+++ b/src/core/lib/iomgr/combiner.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_COMBINER_H
 #define GRPC_CORE_LIB_IOMGR_COMBINER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stddef.h>
 
 #include <grpc/support/atm.h>
diff --git a/src/core/lib/iomgr/endpoint.cc b/src/core/lib/iomgr/endpoint.cc
index 9d4b102..92e7930 100644
--- a/src/core/lib/iomgr/endpoint.cc
+++ b/src/core/lib/iomgr/endpoint.cc
@@ -16,8 +16,12 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/endpoint.h"
 
+grpc_core::TraceFlag grpc_tcp_trace(false, "tcp");
+
 void grpc_endpoint_read(grpc_endpoint* ep, grpc_slice_buffer* slices,
                         grpc_closure* cb) {
   ep->vtable->read(ep, slices, cb);
diff --git a/src/core/lib/iomgr/endpoint.h b/src/core/lib/iomgr/endpoint.h
index cd53099..15db164 100644
--- a/src/core/lib/iomgr/endpoint.h
+++ b/src/core/lib/iomgr/endpoint.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_ENDPOINT_H
 #define GRPC_CORE_LIB_IOMGR_ENDPOINT_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice.h>
 #include <grpc/slice_buffer.h>
 #include <grpc/support/time.h>
diff --git a/src/core/lib/iomgr/endpoint_pair.h b/src/core/lib/iomgr/endpoint_pair.h
index 506ffc8..08f9e3c 100644
--- a/src/core/lib/iomgr/endpoint_pair.h
+++ b/src/core/lib/iomgr/endpoint_pair.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_ENDPOINT_PAIR_H
 #define GRPC_CORE_LIB_IOMGR_ENDPOINT_PAIR_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/endpoint.h"
 
 typedef struct {
diff --git a/src/core/lib/iomgr/endpoint_pair_posix.cc b/src/core/lib/iomgr/endpoint_pair_posix.cc
index 3ad6b47..49850ab 100644
--- a/src/core/lib/iomgr/endpoint_pair_posix.cc
+++ b/src/core/lib/iomgr/endpoint_pair_posix.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_POSIX_SOCKET
diff --git a/src/core/lib/iomgr/endpoint_pair_uv.cc b/src/core/lib/iomgr/endpoint_pair_uv.cc
index 128a947..b99d178 100644
--- a/src/core/lib/iomgr/endpoint_pair_uv.cc
+++ b/src/core/lib/iomgr/endpoint_pair_uv.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_UV
diff --git a/src/core/lib/iomgr/endpoint_pair_windows.cc b/src/core/lib/iomgr/endpoint_pair_windows.cc
index cc07ac0..177331d 100644
--- a/src/core/lib/iomgr/endpoint_pair_windows.cc
+++ b/src/core/lib/iomgr/endpoint_pair_windows.cc
@@ -16,10 +16,13 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_WINSOCK_SOCKET
 #include "src/core/lib/iomgr/endpoint_pair.h"
+#include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
 
 #include <errno.h>
@@ -44,19 +47,19 @@
   memset(&addr, 0, sizeof(addr));
   addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
   addr.sin_family = AF_INET;
-  GPR_ASSERT(bind(lst_sock, (struct sockaddr*)&addr, sizeof(addr)) !=
+  GPR_ASSERT(bind(lst_sock, (grpc_sockaddr*)&addr, sizeof(addr)) !=
              SOCKET_ERROR);
   GPR_ASSERT(listen(lst_sock, SOMAXCONN) != SOCKET_ERROR);
-  GPR_ASSERT(getsockname(lst_sock, (struct sockaddr*)&addr, &addr_len) !=
+  GPR_ASSERT(getsockname(lst_sock, (grpc_sockaddr*)&addr, &addr_len) !=
              SOCKET_ERROR);
 
   cli_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
                        WSA_FLAG_OVERLAPPED);
   GPR_ASSERT(cli_sock != INVALID_SOCKET);
 
-  GPR_ASSERT(WSAConnect(cli_sock, (struct sockaddr*)&addr, addr_len, NULL, NULL,
+  GPR_ASSERT(WSAConnect(cli_sock, (grpc_sockaddr*)&addr, addr_len, NULL, NULL,
                         NULL, NULL) == 0);
-  svr_sock = accept(lst_sock, (struct sockaddr*)&addr, &addr_len);
+  svr_sock = accept(lst_sock, (grpc_sockaddr*)&addr, &addr_len);
   GPR_ASSERT(svr_sock != INVALID_SOCKET);
 
   closesocket(lst_sock);
diff --git a/src/core/lib/iomgr/error.cc b/src/core/lib/iomgr/error.cc
index 0e27ad4..4088cf6 100644
--- a/src/core/lib/iomgr/error.cc
+++ b/src/core/lib/iomgr/error.cc
@@ -26,13 +26,13 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 
 #ifdef GPR_WINDOWS
 #include <grpc/support/log_windows.h>
 #endif
 
 #include "src/core/lib/debug/trace.h"
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/error_internal.h"
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/slice/slice_internal.h"
@@ -148,7 +148,8 @@
 static void unref_errs(grpc_error* err) {
   uint8_t slot = err->first_err;
   while (slot != UINT8_MAX) {
-    grpc_linked_error* lerr = (grpc_linked_error*)(err->arena + slot);
+    grpc_linked_error* lerr =
+        reinterpret_cast<grpc_linked_error*>(err->arena + slot);
     GRPC_ERROR_UNREF(lerr->err);
     GPR_ASSERT(err->last_err == slot ? lerr->next == UINT8_MAX
                                      : lerr->next != UINT8_MAX);
@@ -162,7 +163,7 @@
   for (size_t which = 0; which < GRPC_ERROR_STR_MAX; ++which) {
     uint8_t slot = err->strs[which];
     if (slot != UINT8_MAX) {
-      unref_slice(*(grpc_slice*)(err->arena + slot));
+      unref_slice(*reinterpret_cast<grpc_slice*>(err->arena + slot));
     }
   }
 }
@@ -198,18 +199,18 @@
 
 static uint8_t get_placement(grpc_error** err, size_t size) {
   GPR_ASSERT(*err);
-  uint8_t slots = (uint8_t)(size / sizeof(intptr_t));
+  uint8_t slots = static_cast<uint8_t>(size / sizeof(intptr_t));
   if ((*err)->arena_size + slots > (*err)->arena_capacity) {
-    (*err)->arena_capacity =
-        (uint8_t)GPR_MIN(UINT8_MAX - 1, (3 * (*err)->arena_capacity / 2));
+    (*err)->arena_capacity = static_cast<uint8_t> GPR_MIN(
+        UINT8_MAX - 1, (3 * (*err)->arena_capacity / 2));
     if ((*err)->arena_size + slots > (*err)->arena_capacity) {
       return UINT8_MAX;
     }
 #ifndef NDEBUG
     grpc_error* orig = *err;
 #endif
-    *err = (grpc_error*)gpr_realloc(
-        *err, sizeof(grpc_error) + (*err)->arena_capacity * sizeof(intptr_t));
+    *err = static_cast<grpc_error*>(gpr_realloc(
+        *err, sizeof(grpc_error) + (*err)->arena_capacity * sizeof(intptr_t)));
 #ifndef NDEBUG
     if (grpc_trace_error_refcount.enabled()) {
       if (*err != orig) {
@@ -219,7 +220,7 @@
 #endif
   }
   uint8_t placement = (*err)->arena_size;
-  (*err)->arena_size = (uint8_t)((*err)->arena_size + slots);
+  (*err)->arena_size = static_cast<uint8_t>((*err)->arena_size + slots);
   return placement;
 }
 
@@ -251,7 +252,7 @@
       return;
     }
   } else {
-    unref_slice(*(grpc_slice*)((*err)->arena + slot));
+    unref_slice(*reinterpret_cast<grpc_slice*>((*err)->arena + slot));
   }
   (*err)->strs[which] = slot;
   memcpy((*err)->arena + slot, &value, sizeof(value));
@@ -291,7 +292,7 @@
   } else {
     GPR_ASSERT((*err)->last_err != UINT8_MAX);
     grpc_linked_error* old_last =
-        (grpc_linked_error*)((*err)->arena + (*err)->last_err);
+        reinterpret_cast<grpc_linked_error*>((*err)->arena + (*err)->last_err);
     old_last->next = slot;
     (*err)->last_err = slot;
   }
@@ -315,11 +316,12 @@
                               grpc_error** referencing,
                               size_t num_referencing) {
   GPR_TIMER_SCOPE("grpc_error_create", 0);
-  uint8_t initial_arena_capacity = (uint8_t)(
+  uint8_t initial_arena_capacity = static_cast<uint8_t>(
       DEFAULT_ERROR_CAPACITY +
-      (uint8_t)(num_referencing * SLOTS_PER_LINKED_ERROR) + SURPLUS_CAPACITY);
-  grpc_error* err = (grpc_error*)gpr_malloc(
-      sizeof(*err) + initial_arena_capacity * sizeof(intptr_t));
+      static_cast<uint8_t>(num_referencing * SLOTS_PER_LINKED_ERROR) +
+      SURPLUS_CAPACITY);
+  grpc_error* err = static_cast<grpc_error*>(
+      gpr_malloc(sizeof(*err) + initial_arena_capacity * sizeof(intptr_t)));
   if (err == nullptr) {  // TODO(ctiller): make gpr_malloc return NULL
     return GRPC_ERROR_OOM;
   }
@@ -362,7 +364,8 @@
   for (size_t i = 0; i < GRPC_ERROR_STR_MAX; ++i) {
     uint8_t slot = err->strs[i];
     if (slot != UINT8_MAX) {
-      grpc_slice_ref_internal(*(grpc_slice*)(err->arena + slot));
+      grpc_slice_ref_internal(
+          *reinterpret_cast<grpc_slice*>(err->arena + slot));
     }
   }
 }
@@ -370,7 +373,8 @@
 static void ref_errs(grpc_error* err) {
   uint8_t slot = err->first_err;
   while (slot != UINT8_MAX) {
-    grpc_linked_error* lerr = (grpc_linked_error*)(err->arena + slot);
+    grpc_linked_error* lerr =
+        reinterpret_cast<grpc_linked_error*>(err->arena + slot);
     GRPC_ERROR_REF(lerr->err);
     slot = lerr->next;
   }
@@ -399,11 +403,12 @@
     uint8_t new_arena_capacity = in->arena_capacity;
     // the returned err will be added to, so we ensure this is room to avoid
     // unneeded allocations.
-    if (in->arena_capacity - in->arena_size < (uint8_t)SLOTS_PER_STR) {
-      new_arena_capacity = (uint8_t)(3 * new_arena_capacity / 2);
+    if (in->arena_capacity - in->arena_size <
+        static_cast<uint8_t> SLOTS_PER_STR) {
+      new_arena_capacity = static_cast<uint8_t>(3 * new_arena_capacity / 2);
     }
-    out = (grpc_error*)gpr_malloc(sizeof(*in) +
-                                  new_arena_capacity * sizeof(intptr_t));
+    out = static_cast<grpc_error*>(
+        gpr_malloc(sizeof(*in) + new_arena_capacity * sizeof(intptr_t)));
 #ifndef NDEBUG
     if (grpc_trace_error_refcount.enabled()) {
       gpr_log(GPR_DEBUG, "%p create copying %p", out, in);
@@ -487,7 +492,7 @@
   }
   uint8_t slot = err->strs[which];
   if (slot != UINT8_MAX) {
-    *str = *(grpc_slice*)(err->arena + slot);
+    *str = *reinterpret_cast<grpc_slice*>(err->arena + slot);
     return true;
   } else {
     return false;
@@ -519,7 +524,7 @@
 static void append_chr(char c, char** s, size_t* sz, size_t* cap) {
   if (*sz == *cap) {
     *cap = GPR_MAX(8, 3 * *cap / 2);
-    *s = (char*)gpr_realloc(*s, *cap);
+    *s = static_cast<char*>(gpr_realloc(*s, *cap));
   }
   (*s)[(*sz)++] = c;
 }
@@ -562,7 +567,7 @@
           break;
       }
     } else {
-      append_chr((char)*str, s, sz, cap);
+      append_chr(static_cast<char>(*str), s, sz, cap);
     }
   }
   append_chr('"', s, sz, cap);
@@ -571,8 +576,8 @@
 static void append_kv(kv_pairs* kvs, char* key, char* value) {
   if (kvs->num_kvs == kvs->cap_kvs) {
     kvs->cap_kvs = GPR_MAX(3 * kvs->cap_kvs / 2, 4);
-    kvs->kvs =
-        (kv_pair*)gpr_realloc(kvs->kvs, sizeof(*kvs->kvs) * kvs->cap_kvs);
+    kvs->kvs = static_cast<kv_pair*>(
+        gpr_realloc(kvs->kvs, sizeof(*kvs->kvs) * kvs->cap_kvs));
   }
   kvs->kvs[kvs->num_kvs].key = key;
   kvs->kvs[kvs->num_kvs].value = value;
@@ -593,7 +598,7 @@
   for (size_t which = 0; which < GRPC_ERROR_INT_MAX; ++which) {
     uint8_t slot = err->ints[which];
     if (slot != UINT8_MAX) {
-      append_kv(kvs, key_int((grpc_error_ints)which),
+      append_kv(kvs, key_int(static_cast<grpc_error_ints>(which)),
                 fmt_int(err->arena[slot]));
     }
   }
@@ -617,8 +622,8 @@
   for (size_t which = 0; which < GRPC_ERROR_STR_MAX; ++which) {
     uint8_t slot = err->strs[which];
     if (slot != UINT8_MAX) {
-      append_kv(kvs, key_str((grpc_error_strs)which),
-                fmt_str(*(grpc_slice*)(err->arena + slot)));
+      append_kv(kvs, key_str(static_cast<grpc_error_strs>(which)),
+                fmt_str(*reinterpret_cast<grpc_slice*>(err->arena + slot)));
     }
   }
 }
@@ -652,8 +657,8 @@
   for (size_t which = 0; which < GRPC_ERROR_TIME_MAX; ++which) {
     uint8_t slot = err->times[which];
     if (slot != UINT8_MAX) {
-      append_kv(kvs, key_time((grpc_error_times)which),
-                fmt_time(*(gpr_timespec*)(err->arena + slot)));
+      append_kv(kvs, key_time(static_cast<grpc_error_times>(which)),
+                fmt_time(*reinterpret_cast<gpr_timespec*>(err->arena + slot)));
     }
   }
 }
@@ -662,7 +667,8 @@
   uint8_t slot = err->first_err;
   bool first = true;
   while (slot != UINT8_MAX) {
-    grpc_linked_error* lerr = (grpc_linked_error*)(err->arena + slot);
+    grpc_linked_error* lerr =
+        reinterpret_cast<grpc_linked_error*>(err->arena + slot);
     if (!first) append_chr(',', s, sz, cap);
     first = false;
     const char* e = grpc_error_string(lerr->err);
@@ -685,8 +691,8 @@
 }
 
 static int cmp_kvs(const void* a, const void* b) {
-  const kv_pair* ka = (const kv_pair*)a;
-  const kv_pair* kb = (const kv_pair*)b;
+  const kv_pair* ka = static_cast<const kv_pair*>(a);
+  const kv_pair* kb = static_cast<const kv_pair*>(b);
   return strcmp(ka->key, kb->key);
 }
 
@@ -698,8 +704,8 @@
   append_chr('{', &s, &sz, &cap);
   for (size_t i = 0; i < kvs->num_kvs; i++) {
     if (i != 0) append_chr(',', &s, &sz, &cap);
-    append_esc_str((const uint8_t*)kvs->kvs[i].key, strlen(kvs->kvs[i].key), &s,
-                   &sz, &cap);
+    append_esc_str(reinterpret_cast<const uint8_t*>(kvs->kvs[i].key),
+                   strlen(kvs->kvs[i].key), &s, &sz, &cap);
     gpr_free(kvs->kvs[i].key);
     append_chr(':', &s, &sz, &cap);
     append_str(kvs->kvs[i].value, &s, &sz, &cap);
@@ -720,7 +726,7 @@
 
   void* p = (void*)gpr_atm_acq_load(&err->atomics.error_string);
   if (p != nullptr) {
-    return (const char*)p;
+    return static_cast<const char*>(p);
   }
 
   kv_pairs kvs;
diff --git a/src/core/lib/iomgr/error.h b/src/core/lib/iomgr/error.h
index 8c72a43..f8cae4d 100644
--- a/src/core/lib/iomgr/error.h
+++ b/src/core/lib/iomgr/error.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_ERROR_H
 #define GRPC_CORE_LIB_IOMGR_ERROR_H
 
+#include <grpc/support/port_platform.h>
+
 #include <inttypes.h>
 #include <stdbool.h>
 
diff --git a/src/core/lib/iomgr/error_internal.h b/src/core/lib/iomgr/error_internal.h
index 6cb09c2..7fde347 100644
--- a/src/core/lib/iomgr/error_internal.h
+++ b/src/core/lib/iomgr/error_internal.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_ERROR_INTERNAL_H
 #define GRPC_CORE_LIB_IOMGR_ERROR_INTERNAL_H
 
+#include <grpc/support/port_platform.h>
+
 #include <inttypes.h>
 #include <stdbool.h>  // TODO, do we need this?
 
diff --git a/src/core/lib/iomgr/ev_epoll1_linux.cc b/src/core/lib/iomgr/ev_epoll1_linux.cc
index 1ef70d2..3ebaf18 100644
--- a/src/core/lib/iomgr/ev_epoll1_linux.cc
+++ b/src/core/lib/iomgr/ev_epoll1_linux.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #include <grpc/support/log.h>
@@ -39,11 +41,11 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/cpu.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/tls.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/tls.h"
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/gprpp/manual_constructor.h"
 #include "src/core/lib/iomgr/block_annotate.h"
 #include "src/core/lib/iomgr/ev_posix.h"
@@ -281,7 +283,7 @@
   gpr_mu_unlock(&fd_freelist_mu);
 
   if (new_fd == nullptr) {
-    new_fd = (grpc_fd*)gpr_malloc(sizeof(grpc_fd));
+    new_fd = static_cast<grpc_fd*>(gpr_malloc(sizeof(grpc_fd)));
     new_fd->read_closure.Init();
     new_fd->write_closure.Init();
   }
@@ -304,7 +306,7 @@
   gpr_free(fd_name);
 
   struct epoll_event ev;
-  ev.events = (uint32_t)(EPOLLIN | EPOLLOUT | EPOLLET);
+  ev.events = static_cast<uint32_t>(EPOLLIN | EPOLLOUT | EPOLLET);
   ev.data.ptr = new_fd;
   if (epoll_ctl(g_epoll_set.epfd, EPOLL_CTL_ADD, fd, &ev) != 0) {
     gpr_log(GPR_ERROR, "epoll_ctl failed: %s", strerror(errno));
@@ -440,7 +442,7 @@
 }
 
 static size_t choose_neighborhood(void) {
-  return (size_t)gpr_cpu_current_cpu() % g_num_neighborhoods;
+  return static_cast<size_t>(gpr_cpu_current_cpu()) % g_num_neighborhoods;
 }
 
 static grpc_error* pollset_global_init(void) {
@@ -451,15 +453,15 @@
   grpc_error* err = grpc_wakeup_fd_init(&global_wakeup_fd);
   if (err != GRPC_ERROR_NONE) return err;
   struct epoll_event ev;
-  ev.events = (uint32_t)(EPOLLIN | EPOLLET);
+  ev.events = static_cast<uint32_t>(EPOLLIN | EPOLLET);
   ev.data.ptr = &global_wakeup_fd;
   if (epoll_ctl(g_epoll_set.epfd, EPOLL_CTL_ADD, global_wakeup_fd.read_fd,
                 &ev) != 0) {
     return GRPC_OS_ERROR(errno, "epoll_ctl");
   }
   g_num_neighborhoods = GPR_CLAMP(gpr_cpu_num_cores(), 1, MAX_NEIGHBORHOODS);
-  g_neighborhoods = (pollset_neighborhood*)gpr_zalloc(sizeof(*g_neighborhoods) *
-                                                      g_num_neighborhoods);
+  g_neighborhoods = static_cast<pollset_neighborhood*>(
+      gpr_zalloc(sizeof(*g_neighborhoods) * g_num_neighborhoods));
   for (size_t i = 0; i < g_num_neighborhoods; i++) {
     gpr_mu_init(&g_neighborhoods[i].mu);
   }
@@ -579,7 +581,7 @@
   } else if (delta < 0) {
     return 0;
   } else {
-    return (int)delta;
+    return static_cast<int>(delta);
   }
 }
 
@@ -609,7 +611,7 @@
       append_error(&error, grpc_wakeup_fd_consume_wakeup(&global_wakeup_fd),
                    err_desc);
     } else {
-      grpc_fd* fd = (grpc_fd*)(data_ptr);
+      grpc_fd* fd = static_cast<grpc_fd*>(data_ptr);
       bool cancel = (ev->events & (EPOLLERR | EPOLLHUP)) != 0;
       bool read_ev = (ev->events & (EPOLLIN | EPOLLPRI)) != 0;
       bool write_ev = (ev->events & EPOLLOUT) != 0;
@@ -881,7 +883,7 @@
     } else {
       gpr_atm_no_barrier_store(&g_active_poller, 0);
       size_t poller_neighborhood_idx =
-          (size_t)(pollset->neighborhood - g_neighborhoods);
+          static_cast<size_t>(pollset->neighborhood - g_neighborhoods);
       gpr_mu_unlock(&pollset->mu);
       bool found_worker = false;
       bool scan_state[MAX_NEIGHBORHOODS];
@@ -1150,7 +1152,7 @@
  */
 
 static grpc_pollset_set* pollset_set_create(void) {
-  return (grpc_pollset_set*)((intptr_t)0xdeafbeef);
+  return (grpc_pollset_set*)(static_cast<intptr_t>(0xdeafbeef));
 }
 
 static void pollset_set_destroy(grpc_pollset_set* pss) {}
diff --git a/src/core/lib/iomgr/ev_epoll1_linux.h b/src/core/lib/iomgr/ev_epoll1_linux.h
index 9a1b96b..ca0db72 100644
--- a/src/core/lib/iomgr/ev_epoll1_linux.h
+++ b/src/core/lib/iomgr/ev_epoll1_linux.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_EV_EPOLL1_LINUX_H
 #define GRPC_CORE_LIB_IOMGR_EV_EPOLL1_LINUX_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/port.h"
 
diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc
index 178ebd8..0ef7c03 100644
--- a/src/core/lib/iomgr/ev_epollex_linux.cc
+++ b/src/core/lib/iomgr/ev_epollex_linux.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #include <grpc/support/log.h>
@@ -37,11 +39,11 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/tls.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/gpr/spinlock.h"
+#include "src/core/lib/gpr/tls.h"
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/gprpp/manual_constructor.h"
 #include "src/core/lib/iomgr/block_annotate.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
@@ -57,7 +59,7 @@
 //#define GRPC_EPOLLEX_CREATE_WORKERS_ON_HEAP 1
 
 #define MAX_EPOLL_EVENTS 100
-#define MAX_EPOLL_EVENTS_HANDLED_EACH_POLL_CALL 5
+#define MAX_EPOLL_EVENTS_HANDLED_EACH_POLL_CALL 1
 
 grpc_core::DebugOnlyTraceFlag grpc_trace_pollable_refcount(false,
                                                            "pollable_refcount");
@@ -276,7 +278,7 @@
 }
 
 static void fd_destroy(void* arg, grpc_error* error) {
-  grpc_fd* fd = (grpc_fd*)arg;
+  grpc_fd* fd = static_cast<grpc_fd*>(arg);
   /* Add the fd to the freelist */
   grpc_iomgr_unregister_object(&fd->iomgr_object);
   POLLABLE_UNREF(fd->pollable_obj, "fd_pollable");
@@ -338,7 +340,7 @@
   gpr_mu_unlock(&fd_freelist_mu);
 
   if (new_fd == nullptr) {
-    new_fd = (grpc_fd*)gpr_malloc(sizeof(grpc_fd));
+    new_fd = static_cast<grpc_fd*>(gpr_malloc(sizeof(grpc_fd)));
     new_fd->read_closure.Init();
     new_fd->write_closure.Init();
   }
@@ -441,7 +443,7 @@
   if (epfd == -1) {
     return GRPC_OS_ERROR(errno, "epoll_create1");
   }
-  *p = (pollable*)gpr_malloc(sizeof(**p));
+  *p = static_cast<pollable*>(gpr_malloc(sizeof(**p)));
   grpc_error* err = grpc_wakeup_fd_init(&(*p)->wakeup);
   if (err != GRPC_ERROR_NONE) {
     close(epfd);
@@ -450,7 +452,7 @@
     return err;
   }
   struct epoll_event ev;
-  ev.events = (uint32_t)(EPOLLIN | EPOLLET);
+  ev.events = static_cast<uint32_t>(EPOLLIN | EPOLLET);
   ev.data.ptr = (void*)(1 | (intptr_t) & (*p)->wakeup);
   if (epoll_ctl(epfd, EPOLL_CTL_ADD, (*p)->wakeup.read_fd, &ev) != 0) {
     err = GRPC_OS_ERROR(errno, "epoll_ctl");
@@ -479,7 +481,7 @@
 #else
 static pollable* pollable_ref(pollable* p, int line, const char* reason) {
   if (grpc_trace_pollable_refcount.enabled()) {
-    int r = (int)gpr_atm_no_barrier_load(&p->refs.count);
+    int r = static_cast<int> gpr_atm_no_barrier_load(&p->refs.count);
     gpr_log(__FILE__, line, GPR_LOG_SEVERITY_DEBUG,
             "POLLABLE:%p   ref %d->%d %s", p, r, r + 1, reason);
   }
@@ -494,7 +496,7 @@
 static void pollable_unref(pollable* p, int line, const char* reason) {
   if (p == nullptr) return;
   if (grpc_trace_pollable_refcount.enabled()) {
-    int r = (int)gpr_atm_no_barrier_load(&p->refs.count);
+    int r = static_cast<int> gpr_atm_no_barrier_load(&p->refs.count);
     gpr_log(__FILE__, line, GPR_LOG_SEVERITY_DEBUG,
             "POLLABLE:%p unref %d->%d %s", p, r, r - 1, reason);
   }
@@ -516,7 +518,8 @@
   }
 
   struct epoll_event ev_fd;
-  ev_fd.events = (uint32_t)(EPOLLET | EPOLLIN | EPOLLOUT | EPOLLEXCLUSIVE);
+  ev_fd.events =
+      static_cast<uint32_t>(EPOLLET | EPOLLIN | EPOLLOUT | EPOLLEXCLUSIVE);
   ev_fd.data.ptr = fd;
   if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd->fd, &ev_fd) != 0) {
     switch (errno) {
@@ -699,7 +702,7 @@
   else if (delta < 0)
     return 0;
   else
-    return (int)delta;
+    return static_cast<int>(delta);
 }
 
 static void fd_become_readable(grpc_fd* fd, grpc_pollset* notifier) {
@@ -768,10 +771,11 @@
       }
       append_error(&error,
                    grpc_wakeup_fd_consume_wakeup(
-                       (grpc_wakeup_fd*)((~(intptr_t)1) & (intptr_t)data_ptr)),
+                       (grpc_wakeup_fd*)((~static_cast<intptr_t>(1)) &
+                                         (intptr_t)data_ptr)),
                    err_desc);
     } else {
-      grpc_fd* fd = (grpc_fd*)data_ptr;
+      grpc_fd* fd = static_cast<grpc_fd*>(data_ptr);
       bool cancel = (ev->events & (EPOLLERR | EPOLLHUP)) != 0;
       bool read_ev = (ev->events & (EPOLLIN | EPOLLPRI)) != 0;
       bool write_ev = (ev->events & EPOLLOUT) != 0;
@@ -797,6 +801,7 @@
 static void pollset_destroy(grpc_pollset* pollset) {
   POLLABLE_UNREF(pollset->active_pollable, "pollset");
   pollset->active_pollable = nullptr;
+  gpr_mu_destroy(&pollset->mu);
 }
 
 static grpc_error* pollable_epoll(pollable* p, grpc_millis deadline) {
@@ -1170,7 +1175,8 @@
 }
 
 static grpc_pollset_set* pollset_set_create(void) {
-  grpc_pollset_set* pss = (grpc_pollset_set*)gpr_zalloc(sizeof(*pss));
+  grpc_pollset_set* pss =
+      static_cast<grpc_pollset_set*>(gpr_zalloc(sizeof(*pss)));
   gpr_mu_init(&pss->mu);
   gpr_ref_init(&pss->refs, 1);
   return pss;
@@ -1210,8 +1216,8 @@
   }
   if (pss->fd_count == pss->fd_capacity) {
     pss->fd_capacity = GPR_MAX(pss->fd_capacity * 2, 8);
-    pss->fds =
-        (grpc_fd**)gpr_realloc(pss->fds, pss->fd_capacity * sizeof(*pss->fds));
+    pss->fds = static_cast<grpc_fd**>(
+        gpr_realloc(pss->fds, pss->fd_capacity * sizeof(*pss->fds)));
   }
   REF_BY(fd, 2, "pollset_set");
   pss->fds[pss->fd_count++] = fd;
@@ -1319,8 +1325,8 @@
                err_desc);
   if (pss->pollset_count == pss->pollset_capacity) {
     pss->pollset_capacity = GPR_MAX(pss->pollset_capacity * 2, 8);
-    pss->pollsets = (grpc_pollset**)gpr_realloc(
-        pss->pollsets, pss->pollset_capacity * sizeof(*pss->pollsets));
+    pss->pollsets = static_cast<grpc_pollset**>(gpr_realloc(
+        pss->pollsets, pss->pollset_capacity * sizeof(*pss->pollsets)));
   }
   pss->pollsets[pss->pollset_count++] = ps;
   gpr_mu_unlock(&pss->mu);
@@ -1373,7 +1379,8 @@
   b->parent = a;
   if (a->fd_capacity < a->fd_count + b->fd_count) {
     a->fd_capacity = GPR_MAX(2 * a->fd_capacity, a->fd_count + b->fd_count);
-    a->fds = (grpc_fd**)gpr_realloc(a->fds, a->fd_capacity * sizeof(*a->fds));
+    a->fds = static_cast<grpc_fd**>(
+        gpr_realloc(a->fds, a->fd_capacity * sizeof(*a->fds)));
   }
   size_t initial_a_fd_count = a->fd_count;
   a->fd_count = 0;
@@ -1390,8 +1397,8 @@
   if (a->pollset_capacity < a->pollset_count + b->pollset_count) {
     a->pollset_capacity =
         GPR_MAX(2 * a->pollset_capacity, a->pollset_count + b->pollset_count);
-    a->pollsets = (grpc_pollset**)gpr_realloc(
-        a->pollsets, a->pollset_capacity * sizeof(*a->pollsets));
+    a->pollsets = static_cast<grpc_pollset**>(
+        gpr_realloc(a->pollsets, a->pollset_capacity * sizeof(*a->pollsets)));
   }
   if (b->pollset_count > 0) {
     memcpy(a->pollsets + a->pollset_count, b->pollsets,
@@ -1452,10 +1459,6 @@
 
 const grpc_event_engine_vtable* grpc_init_epollex_linux(
     bool explicitly_requested) {
-  if (!explicitly_requested) {
-    return nullptr;
-  }
-
   if (!grpc_has_wakeup_fd()) {
     gpr_log(GPR_ERROR, "Skipping epollex because of no wakeup fd.");
     return nullptr;
diff --git a/src/core/lib/iomgr/ev_epollex_linux.h b/src/core/lib/iomgr/ev_epollex_linux.h
index ffa7fc7..e70ba72 100644
--- a/src/core/lib/iomgr/ev_epollex_linux.h
+++ b/src/core/lib/iomgr/ev_epollex_linux.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_EV_EPOLLEX_LINUX_H
 #define GRPC_CORE_LIB_IOMGR_EV_EPOLLEX_LINUX_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/port.h"
 
diff --git a/src/core/lib/iomgr/ev_epollsig_linux.cc b/src/core/lib/iomgr/ev_epollsig_linux.cc
index c895489..1e30f66 100644
--- a/src/core/lib/iomgr/ev_epollsig_linux.cc
+++ b/src/core/lib/iomgr/ev_epollsig_linux.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #include <grpc/grpc_posix.h>
@@ -39,10 +41,10 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/tls.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/debug/stats.h"
+#include "src/core/lib/gpr/tls.h"
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/gprpp/manual_constructor.h"
 #include "src/core/lib/iomgr/block_annotate.h"
 #include "src/core/lib/iomgr/ev_posix.h"
@@ -349,7 +351,7 @@
 #endif /* defined(GRPC_TSAN) */
 
   for (i = 0; i < fd_count; i++) {
-    ev.events = (uint32_t)(EPOLLIN | EPOLLOUT | EPOLLET);
+    ev.events = static_cast<uint32_t>(EPOLLIN | EPOLLOUT | EPOLLET);
     ev.data.ptr = fds[i];
     err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_ADD, fds[i]->fd, &ev);
 
@@ -368,8 +370,8 @@
 
     if (pi->fd_cnt == pi->fd_capacity) {
       pi->fd_capacity = GPR_MAX(pi->fd_capacity + 8, pi->fd_cnt * 3 / 2);
-      pi->fds =
-          (grpc_fd**)gpr_realloc(pi->fds, sizeof(grpc_fd*) * pi->fd_capacity);
+      pi->fds = static_cast<grpc_fd**>(
+          gpr_realloc(pi->fds, sizeof(grpc_fd*) * pi->fd_capacity));
     }
 
     pi->fds[pi->fd_cnt++] = fds[i];
@@ -388,7 +390,7 @@
   char* err_msg;
   const char* err_desc = "polling_island_add_wakeup_fd";
 
-  ev.events = (uint32_t)(EPOLLIN | EPOLLET);
+  ev.events = static_cast<uint32_t>(EPOLLIN | EPOLLET);
   ev.data.ptr = wakeup_fd;
   err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_ADD,
                   GRPC_WAKEUP_FD_GET_READ_FD(wakeup_fd), &ev);
@@ -471,7 +473,7 @@
 
   *error = GRPC_ERROR_NONE;
 
-  pi = (polling_island*)gpr_malloc(sizeof(*pi));
+  pi = static_cast<polling_island*>(gpr_malloc(sizeof(*pi)));
   gpr_mu_init(&pi->mu);
   pi->fd_cnt = 0;
   pi->fd_capacity = 0;
@@ -815,7 +817,7 @@
   gpr_mu_unlock(&fd_freelist_mu);
 
   if (new_fd == nullptr) {
-    new_fd = (grpc_fd*)gpr_malloc(sizeof(grpc_fd));
+    new_fd = static_cast<grpc_fd*>(gpr_malloc(sizeof(grpc_fd)));
     gpr_mu_init(&new_fd->po.mu);
     new_fd->read_closure.Init();
     new_fd->write_closure.Init();
@@ -976,7 +978,8 @@
   grpc_error* err = GRPC_ERROR_NONE;
 
   /* Kick the worker only if it was not already kicked */
-  if (gpr_atm_no_barrier_cas(&worker->is_kicked, (gpr_atm)0, (gpr_atm)1)) {
+  if (gpr_atm_no_barrier_cas(&worker->is_kicked, static_cast<gpr_atm>(0),
+                             static_cast<gpr_atm>(1))) {
     GRPC_POLLING_TRACE(
         "pollset_worker_kick: Kicking worker: %p (thread id: %ld)",
         (void*)worker, (long int)worker->pt_id);
@@ -1096,7 +1099,7 @@
   else if (delta < 0)
     return 0;
   else
-    return (int)delta;
+    return static_cast<int>(delta);
 }
 
 static void fd_become_readable(grpc_fd* fd, grpc_pollset* notifier) {
@@ -1251,7 +1254,7 @@
          to the function pollset_work_and_unlock() will pick up the correct
          epoll_fd */
     } else {
-      grpc_fd* fd = (grpc_fd*)data_ptr;
+      grpc_fd* fd = static_cast<grpc_fd*>(data_ptr);
       int cancel = ep_ev[i].events & (EPOLLERR | EPOLLHUP);
       int read_ev = ep_ev[i].events & (EPOLLIN | EPOLLPRI);
       int write_ev = ep_ev[i].events & EPOLLOUT;
@@ -1538,7 +1541,8 @@
  */
 
 static grpc_pollset_set* pollset_set_create(void) {
-  grpc_pollset_set* pss = (grpc_pollset_set*)gpr_malloc(sizeof(*pss));
+  grpc_pollset_set* pss =
+      static_cast<grpc_pollset_set*>(gpr_malloc(sizeof(*pss)));
   gpr_mu_init(&pss->po.mu);
   pss->po.pi = nullptr;
 #ifndef NDEBUG
@@ -1607,8 +1611,8 @@
 }
 
 bool grpc_are_polling_islands_equal(void* p, void* q) {
-  polling_island* p1 = (polling_island*)p;
-  polling_island* p2 = (polling_island*)q;
+  polling_island* p1 = static_cast<polling_island*>(p);
+  polling_island* p2 = static_cast<polling_island*>(q);
 
   /* Note: polling_island_lock_pair() may change p1 and p2 to point to the
      latest polling islands in their respective linked lists */
diff --git a/src/core/lib/iomgr/ev_epollsig_linux.h b/src/core/lib/iomgr/ev_epollsig_linux.h
index 48178d3..2ba2f0a 100644
--- a/src/core/lib/iomgr/ev_epollsig_linux.h
+++ b/src/core/lib/iomgr/ev_epollsig_linux.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H
 #define GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/port.h"
 
diff --git a/src/core/lib/iomgr/ev_poll_posix.cc b/src/core/lib/iomgr/ev_poll_posix.cc
index ad92a93..2e375b4 100644
--- a/src/core/lib/iomgr/ev_poll_posix.cc
+++ b/src/core/lib/iomgr/ev_poll_posix.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_POSIX_SOCKET
@@ -33,12 +35,12 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/tls.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/gpr/murmur_hash.h"
+#include "src/core/lib/gpr/tls.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/block_annotate.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/wakeup_fd_cv.h"
@@ -175,7 +177,6 @@
   int called_shutdown;
   int kicked_without_pollers;
   grpc_closure* shutdown_done;
-  grpc_closure_list idle_jobs;
   int pollset_set_count;
   /* all polled fds */
   size_t fd_count;
@@ -253,8 +254,13 @@
 } poll_result;
 
 typedef struct poll_args {
+  grpc_core::Thread poller_thd;
   gpr_cv trigger;
   int trigger_set;
+  bool harvestable;
+  gpr_cv harvest;
+  bool joinable;
+  gpr_cv join;
   struct pollfd* fds;
   nfds_t nfds;
   poll_result* result;
@@ -264,15 +270,17 @@
 
 // This is a 2-tiered cache, we mantain a hash table
 // of active poll calls, so we can wait on the result
-// of that call.  We also maintain a freelist of inactive
-// poll threads.
+// of that call.  We also maintain freelists of inactive
+// poll args and of dead poller threads.
 typedef struct poll_hash_table {
   poll_args* free_pollers;
   poll_args** active_pollers;
+  poll_args* dead_pollers;
   unsigned int size;
   unsigned int count;
 } poll_hash_table;
 
+// TODO(kpayson64): Eliminate use of global non-POD variables
 poll_hash_table poll_cache;
 grpc_cv_fd_table g_cvfds;
 
@@ -323,7 +331,7 @@
 }
 
 static grpc_fd* fd_create(int fd, const char* name) {
-  grpc_fd* r = (grpc_fd*)gpr_malloc(sizeof(*r));
+  grpc_fd* r = static_cast<grpc_fd*>(gpr_malloc(sizeof(*r)));
   gpr_mu_init(&r->mu);
   gpr_atm_rel_store(&r->refst, 1);
   r->shutdown = 0;
@@ -457,16 +465,20 @@
   if (!fd->shutdown) {
     return GRPC_ERROR_NONE;
   } else {
-    return GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-        "FD shutdown", &fd->shutdown_error, 1);
+    return grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+                                  "FD shutdown", &fd->shutdown_error, 1),
+                              GRPC_ERROR_INT_GRPC_STATUS,
+                              GRPC_STATUS_UNAVAILABLE);
   }
 }
 
 static void notify_on_locked(grpc_fd* fd, grpc_closure** st,
                              grpc_closure* closure) {
   if (fd->shutdown || gpr_atm_no_barrier_load(&fd->pollhup)) {
-    GRPC_CLOSURE_SCHED(closure,
-                       GRPC_ERROR_CREATE_FROM_STATIC_STRING("FD shutdown"));
+    GRPC_CLOSURE_SCHED(
+        closure, grpc_error_set_int(
+                     GRPC_ERROR_CREATE_FROM_STATIC_STRING("FD shutdown"),
+                     GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
   } else if (*st == CLOSURE_NOT_READY) {
     /* not ready ==> switch to a waiting state by setting the closure */
     *st = closure;
@@ -799,7 +811,6 @@
   pollset->shutting_down = 0;
   pollset->called_shutdown = 0;
   pollset->kicked_without_pollers = 0;
-  pollset->idle_jobs.head = pollset->idle_jobs.tail = nullptr;
   pollset->local_wakeup_cache = nullptr;
   pollset->kicked_without_pollers = 0;
   pollset->fd_count = 0;
@@ -810,7 +821,6 @@
 
 static void pollset_destroy(grpc_pollset* pollset) {
   GPR_ASSERT(!pollset_has_workers(pollset));
-  GPR_ASSERT(pollset->idle_jobs.head == pollset->idle_jobs.tail);
   while (pollset->local_wakeup_cache) {
     grpc_cached_wakeup_fd* next = pollset->local_wakeup_cache->next;
     grpc_wakeup_fd_destroy(&pollset->local_wakeup_cache->fd);
@@ -831,8 +841,8 @@
   if (pollset->fd_count == pollset->fd_capacity) {
     pollset->fd_capacity =
         GPR_MAX(pollset->fd_capacity + 8, pollset->fd_count * 3 / 2);
-    pollset->fds = (grpc_fd**)gpr_realloc(
-        pollset->fds, sizeof(grpc_fd*) * pollset->fd_capacity);
+    pollset->fds = static_cast<grpc_fd**>(
+        gpr_realloc(pollset->fds, sizeof(grpc_fd*) * pollset->fd_capacity));
   }
   pollset->fds[pollset->fd_count++] = fd;
   GRPC_FD_REF(fd, "multipoller");
@@ -842,7 +852,6 @@
 }
 
 static void finish_shutdown(grpc_pollset* pollset) {
-  GPR_ASSERT(grpc_closure_list_empty(pollset->idle_jobs));
   size_t i;
   for (i = 0; i < pollset->fd_count; i++) {
     GRPC_FD_UNREF(pollset->fds[i], "multipoller");
@@ -863,7 +872,6 @@
                                 grpc_pollset_worker** worker_hdl,
                                 grpc_millis deadline) {
   GPR_TIMER_SCOPE("pollset_work", 0);
-
   grpc_pollset_worker worker;
   if (worker_hdl) *worker_hdl = &worker;
   grpc_error* error = GRPC_ERROR_NONE;
@@ -885,8 +893,8 @@
     worker.wakeup_fd = pollset->local_wakeup_cache;
     pollset->local_wakeup_cache = worker.wakeup_fd->next;
   } else {
-    worker.wakeup_fd =
-        (grpc_cached_wakeup_fd*)gpr_malloc(sizeof(*worker.wakeup_fd));
+    worker.wakeup_fd = static_cast<grpc_cached_wakeup_fd*>(
+        gpr_malloc(sizeof(*worker.wakeup_fd)));
     error = grpc_wakeup_fd_init(&worker.wakeup_fd->fd);
     if (error != GRPC_ERROR_NONE) {
       GRPC_LOG_IF_ERROR("pollset_work", GRPC_ERROR_REF(error));
@@ -894,14 +902,6 @@
     }
   }
   worker.kicked_specifically = 0;
-  /* If there's work waiting for the pollset to be idle, and the
-     pollset is idle, then do that work */
-  if (!pollset_has_workers(pollset) &&
-      !grpc_closure_list_empty(pollset->idle_jobs)) {
-    GPR_TIMER_MARK("pollset_work.idle_jobs", 0);
-    GRPC_CLOSURE_LIST_SCHED(&pollset->idle_jobs);
-    goto done;
-  }
   /* If we're shutting down then we don't execute any extended work */
   if (pollset->shutting_down) {
     GPR_TIMER_MARK("pollset_work.shutting_down", 0);
@@ -914,7 +914,8 @@
   gpr_tls_set(&g_current_thread_poller, (intptr_t)pollset);
   while (keep_polling) {
     keep_polling = 0;
-    if (!pollset->kicked_without_pollers) {
+    if (!pollset->kicked_without_pollers ||
+        deadline <= grpc_core::ExecCtx::Get()->Now()) {
       if (!added_worker) {
         push_front_worker(pollset, &worker);
         added_worker = 1;
@@ -941,8 +942,9 @@
         const size_t pfd_size = sizeof(*pfds) * (pollset->fd_count + 2);
         const size_t watch_size = sizeof(*watchers) * (pollset->fd_count + 2);
         void* buf = gpr_malloc(pfd_size + watch_size);
-        pfds = (struct pollfd*)buf;
-        watchers = (grpc_fd_watcher*)(void*)((char*)buf + pfd_size);
+        pfds = static_cast<struct pollfd*>(buf);
+        watchers = static_cast<grpc_fd_watcher*>(
+            (void*)(static_cast<char*>(buf) + pfd_size));
       }
 
       fd_count = 0;
@@ -968,8 +970,8 @@
 
       for (i = 1; i < pfd_count; i++) {
         grpc_fd* fd = watchers[i].fd;
-        pfds[i].events = (short)fd_begin_poll(fd, pollset, &worker, POLLIN,
-                                              POLLOUT, &watchers[i]);
+        pfds[i].events = static_cast<short>(
+            fd_begin_poll(fd, pollset, &worker, POLLIN, POLLOUT, &watchers[i]));
         GRPC_FD_UNREF(fd, "multipoller_start");
       }
 
@@ -1087,11 +1089,6 @@
        * pollset_work.
        * TODO(dklempner): Can we refactor the shutdown logic to avoid this? */
       gpr_mu_lock(&pollset->mu);
-    } else if (!grpc_closure_list_empty(pollset->idle_jobs)) {
-      GRPC_CLOSURE_LIST_SCHED(&pollset->idle_jobs);
-      gpr_mu_unlock(&pollset->mu);
-      grpc_core::ExecCtx::Get()->Flush();
-      gpr_mu_lock(&pollset->mu);
     }
   }
   if (worker_hdl) *worker_hdl = nullptr;
@@ -1104,9 +1101,6 @@
   pollset->shutting_down = 1;
   pollset->shutdown_done = closure;
   pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);
-  if (!pollset_has_workers(pollset)) {
-    GRPC_CLOSURE_LIST_SCHED(&pollset->idle_jobs);
-  }
   if (!pollset->called_shutdown && !pollset_has_observers(pollset)) {
     pollset->called_shutdown = 1;
     finish_shutdown(pollset);
@@ -1119,7 +1113,7 @@
   grpc_millis n = deadline - grpc_core::ExecCtx::Get()->Now();
   if (n < 0) return 0;
   if (n > INT_MAX) return -1;
-  return (int)n;
+  return static_cast<int>(n);
 }
 
 /*******************************************************************************
@@ -1128,7 +1122,7 @@
 
 static grpc_pollset_set* pollset_set_create(void) {
   grpc_pollset_set* pollset_set =
-      (grpc_pollset_set*)gpr_zalloc(sizeof(*pollset_set));
+      static_cast<grpc_pollset_set*>(gpr_zalloc(sizeof(*pollset_set)));
   gpr_mu_init(&pollset_set->mu);
   return pollset_set;
 }
@@ -1169,9 +1163,9 @@
   if (pollset_set->pollset_count == pollset_set->pollset_capacity) {
     pollset_set->pollset_capacity =
         GPR_MAX(8, 2 * pollset_set->pollset_capacity);
-    pollset_set->pollsets = (grpc_pollset**)gpr_realloc(
+    pollset_set->pollsets = static_cast<grpc_pollset**>(gpr_realloc(
         pollset_set->pollsets,
-        pollset_set->pollset_capacity * sizeof(*pollset_set->pollsets));
+        pollset_set->pollset_capacity * sizeof(*pollset_set->pollsets)));
   }
   pollset_set->pollsets[pollset_set->pollset_count++] = pollset;
   for (i = 0, j = 0; i < pollset_set->fd_count; i++) {
@@ -1218,9 +1212,9 @@
   gpr_mu_lock(&bag->mu);
   if (bag->pollset_set_count == bag->pollset_set_capacity) {
     bag->pollset_set_capacity = GPR_MAX(8, 2 * bag->pollset_set_capacity);
-    bag->pollset_sets = (grpc_pollset_set**)gpr_realloc(
-        bag->pollset_sets,
-        bag->pollset_set_capacity * sizeof(*bag->pollset_sets));
+    bag->pollset_sets = static_cast<grpc_pollset_set**>(
+        gpr_realloc(bag->pollset_sets,
+                    bag->pollset_set_capacity * sizeof(*bag->pollset_sets)));
   }
   bag->pollset_sets[bag->pollset_set_count++] = item;
   for (i = 0, j = 0; i < bag->fd_count; i++) {
@@ -1255,8 +1249,9 @@
   gpr_mu_lock(&pollset_set->mu);
   if (pollset_set->fd_count == pollset_set->fd_capacity) {
     pollset_set->fd_capacity = GPR_MAX(8, 2 * pollset_set->fd_capacity);
-    pollset_set->fds = (grpc_fd**)gpr_realloc(
-        pollset_set->fds, pollset_set->fd_capacity * sizeof(*pollset_set->fds));
+    pollset_set->fds = static_cast<grpc_fd**>(
+        gpr_realloc(pollset_set->fds,
+                    pollset_set->fd_capacity * sizeof(*pollset_set->fds)));
   }
   GRPC_FD_REF(fd, "pollset_set");
   pollset_set->fds[pollset_set->fd_count++] = fd;
@@ -1293,6 +1288,7 @@
 
 static void run_poll(void* args);
 static void cache_poller_locked(poll_args* args);
+static void cache_harvest_locked();
 
 static void cache_insert_locked(poll_args* args) {
   uint32_t key = gpr_murmur_hash3(args->fds, args->nfds * sizeof(struct pollfd),
@@ -1308,12 +1304,12 @@
 }
 
 static void init_result(poll_args* pargs) {
-  pargs->result = (poll_result*)gpr_malloc(sizeof(poll_result));
+  pargs->result = static_cast<poll_result*>(gpr_malloc(sizeof(poll_result)));
   gpr_ref_init(&pargs->result->refcount, 1);
   pargs->result->watchers = nullptr;
   pargs->result->watchcount = 0;
-  pargs->result->fds =
-      (struct pollfd*)gpr_malloc(sizeof(struct pollfd) * pargs->nfds);
+  pargs->result->fds = static_cast<struct pollfd*>(
+      gpr_malloc(sizeof(struct pollfd) * pargs->nfds));
   memcpy(pargs->result->fds, pargs->fds, sizeof(struct pollfd) * pargs->nfds);
   pargs->result->nfds = pargs->nfds;
   pargs->result->retval = 0;
@@ -1352,8 +1348,13 @@
     return pargs;
   }
 
-  poll_args* pargs = (poll_args*)gpr_malloc(sizeof(struct poll_args));
+  poll_args* pargs =
+      static_cast<poll_args*>(gpr_malloc(sizeof(struct poll_args)));
   gpr_cv_init(&pargs->trigger);
+  gpr_cv_init(&pargs->harvest);
+  gpr_cv_init(&pargs->join);
+  pargs->harvestable = false;
+  pargs->joinable = false;
   pargs->fds = fds;
   pargs->nfds = count;
   pargs->next = nullptr;
@@ -1361,11 +1362,9 @@
   pargs->trigger_set = 0;
   init_result(pargs);
   cache_poller_locked(pargs);
-  gpr_thd_id t_id;
-  gpr_thd_options opt = gpr_thd_options_default();
   gpr_ref(&g_cvfds.pollcount);
-  gpr_thd_options_set_detached(&opt);
-  GPR_ASSERT(gpr_thd_new(&t_id, "grpc_poller", &run_poll, pargs, &opt));
+  pargs->poller_thd = grpc_core::Thread("grpc_poller", &run_poll, pargs);
+  pargs->poller_thd.Start();
   return pargs;
 }
 
@@ -1400,7 +1399,7 @@
     poll_cache.size = poll_cache.size * 2;
     poll_cache.count = 0;
     poll_cache.active_pollers =
-        (poll_args**)gpr_malloc(sizeof(void*) * poll_cache.size);
+        static_cast<poll_args**>(gpr_malloc(sizeof(void*) * poll_cache.size));
     for (unsigned int i = 0; i < poll_cache.size; i++) {
       poll_cache.active_pollers[i] = nullptr;
     }
@@ -1430,7 +1429,33 @@
     poll_cache.free_pollers = args->next;
   }
 
-  gpr_free(args);
+  // Now move this args to the dead poller list for later join
+  if (poll_cache.dead_pollers != nullptr) {
+    poll_cache.dead_pollers->prev = args;
+  }
+  args->prev = nullptr;
+  args->next = poll_cache.dead_pollers;
+  poll_cache.dead_pollers = args;
+}
+
+static void cache_harvest_locked() {
+  while (poll_cache.dead_pollers) {
+    poll_args* args = poll_cache.dead_pollers;
+    poll_cache.dead_pollers = poll_cache.dead_pollers->next;
+    // Keep the list consistent in case new dead pollers get added when we
+    // release the lock below to wait on joining
+    if (poll_cache.dead_pollers) {
+      poll_cache.dead_pollers->prev = nullptr;
+    }
+    args->harvestable = true;
+    gpr_cv_signal(&args->harvest);
+    while (!args->joinable) {
+      gpr_cv_wait(&args->join, &g_cvfds.mu,
+                  gpr_inf_future(GPR_CLOCK_MONOTONIC));
+    }
+    args->poller_thd.Join();
+    gpr_free(args);
+  }
 }
 
 static void decref_poll_result(poll_result* res) {
@@ -1457,11 +1482,12 @@
 
 // Poll in a background thread
 static void run_poll(void* args) {
-  poll_args* pargs = (poll_args*)args;
+  poll_args* pargs = static_cast<poll_args*>(args);
   while (1) {
     poll_result* result = pargs->result;
     int retval = g_cvfds.poll(result->fds, result->nfds, CV_POLL_PERIOD_MS);
     gpr_mu_lock(&g_cvfds.mu);
+    cache_harvest_locked();
     if (retval != 0) {
       result->completed = 1;
       result->retval = retval;
@@ -1481,6 +1507,7 @@
       deadline = gpr_time_add(deadline, thread_grace);
       pargs->trigger_set = 0;
       gpr_cv_wait(&pargs->trigger, &g_cvfds.mu, deadline);
+      cache_harvest_locked();
       if (!pargs->trigger_set) {
         cache_destroy_locked(pargs);
         break;
@@ -1489,10 +1516,15 @@
     gpr_mu_unlock(&g_cvfds.mu);
   }
 
-  // We still have the lock here
   if (gpr_unref(&g_cvfds.pollcount)) {
     gpr_cv_signal(&g_cvfds.shutdown_cv);
   }
+  while (!pargs->harvestable) {
+    gpr_cv_wait(&pargs->harvest, &g_cvfds.mu,
+                gpr_inf_future(GPR_CLOCK_MONOTONIC));
+  }
+  pargs->joinable = true;
+  gpr_cv_signal(&pargs->join);
   gpr_mu_unlock(&g_cvfds.mu);
 }
 
@@ -1505,12 +1537,14 @@
   nfds_t nsockfds = 0;
   poll_result* result = nullptr;
   gpr_mu_lock(&g_cvfds.mu);
-  pollcv = (grpc_cv_node*)gpr_malloc(sizeof(grpc_cv_node));
+  cache_harvest_locked();
+  pollcv = static_cast<grpc_cv_node*>(gpr_malloc(sizeof(grpc_cv_node)));
   pollcv->next = nullptr;
   gpr_cv pollcv_cv;
   gpr_cv_init(&pollcv_cv);
   pollcv->cv = &pollcv_cv;
-  grpc_cv_node* fd_cvs = (grpc_cv_node*)gpr_malloc(nfds * sizeof(grpc_cv_node));
+  grpc_cv_node* fd_cvs =
+      static_cast<grpc_cv_node*>(gpr_malloc(nfds * sizeof(grpc_cv_node)));
 
   for (i = 0; i < nfds; i++) {
     fds[i].revents = 0;
@@ -1542,8 +1576,8 @@
 
   res = 0;
   if (!skip_poll && nsockfds > 0) {
-    struct pollfd* pollfds =
-        (struct pollfd*)gpr_malloc(sizeof(struct pollfd) * nsockfds);
+    struct pollfd* pollfds = static_cast<struct pollfd*>(
+        gpr_malloc(sizeof(struct pollfd) * nsockfds));
     idx = 0;
     for (i = 0; i < nfds; i++) {
       if (fds[i].fd >= 0) {
@@ -1567,12 +1601,14 @@
     pargs->trigger_set = 1;
     gpr_cv_signal(&pargs->trigger);
     gpr_cv_wait(&pollcv_cv, &g_cvfds.mu, deadline);
+    cache_harvest_locked();
     res = result->retval;
     errno = result->err;
     result->watchcount--;
     remove_cvn(&result->watchers, pollcv);
   } else if (!skip_poll) {
     gpr_cv_wait(&pollcv_cv, &g_cvfds.mu, deadline);
+    cache_harvest_locked();
   }
 
   idx = 0;
@@ -1606,8 +1642,8 @@
   gpr_cv_init(&g_cvfds.shutdown_cv);
   gpr_ref_init(&g_cvfds.pollcount, 1);
   g_cvfds.size = CV_DEFAULT_TABLE_SIZE;
-  g_cvfds.cvfds =
-      (grpc_fd_node*)gpr_malloc(sizeof(grpc_fd_node) * CV_DEFAULT_TABLE_SIZE);
+  g_cvfds.cvfds = static_cast<grpc_fd_node*>(
+      gpr_malloc(sizeof(grpc_fd_node) * CV_DEFAULT_TABLE_SIZE));
   g_cvfds.free_fds = nullptr;
   thread_grace = gpr_time_from_millis(POLLCV_THREAD_GRACE_MS, GPR_TIMESPAN);
   for (int i = 0; i < CV_DEFAULT_TABLE_SIZE; i++) {
@@ -1624,10 +1660,12 @@
   poll_cache.size = 32;
   poll_cache.count = 0;
   poll_cache.free_pollers = nullptr;
-  poll_cache.active_pollers = (poll_args**)gpr_malloc(sizeof(void*) * 32);
+  poll_cache.active_pollers =
+      static_cast<poll_args**>(gpr_malloc(sizeof(void*) * 32));
   for (unsigned int i = 0; i < poll_cache.size; i++) {
     poll_cache.active_pollers[i] = nullptr;
   }
+  poll_cache.dead_pollers = nullptr;
 
   gpr_mu_unlock(&g_cvfds.mu);
 }
@@ -1646,6 +1684,7 @@
   grpc_poll_function = g_cvfds.poll;
   gpr_free(g_cvfds.cvfds);
 
+  cache_harvest_locked();
   gpr_free(poll_cache.active_pollers);
 
   gpr_mu_unlock(&g_cvfds.mu);
diff --git a/src/core/lib/iomgr/ev_poll_posix.h b/src/core/lib/iomgr/ev_poll_posix.h
index f6bc624..ab3cd90 100644
--- a/src/core/lib/iomgr/ev_poll_posix.h
+++ b/src/core/lib/iomgr/ev_poll_posix.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_EV_POLL_POSIX_H
 #define GRPC_CORE_LIB_IOMGR_EV_POLL_POSIX_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/ev_posix.h"
 
 const grpc_event_engine_vtable* grpc_init_poll_posix(bool explicit_request);
diff --git a/src/core/lib/iomgr/ev_posix.cc b/src/core/lib/iomgr/ev_posix.cc
index 8100bec..8b80070 100644
--- a/src/core/lib/iomgr/ev_posix.cc
+++ b/src/core/lib/iomgr/ev_posix.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_POSIX_SOCKET
@@ -27,10 +29,10 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/ev_epoll1_linux.h"
 #include "src/core/lib/iomgr/ev_epollex_linux.h"
 #include "src/core/lib/iomgr/ev_epollsig_linux.h"
@@ -108,11 +110,11 @@
   char* s;
   size_t len;
   GPR_ASSERT(end >= beg);
-  len = (size_t)(end - beg);
-  s = (char*)gpr_malloc(len + 1);
+  len = static_cast<size_t>(end - beg);
+  s = static_cast<char*>(gpr_malloc(len + 1));
   memcpy(s, beg, len);
   s[len] = 0;
-  *ss = (char**)gpr_realloc(*ss, sizeof(char**) * np);
+  *ss = static_cast<char**>(gpr_realloc(*ss, sizeof(char**) * np));
   (*ss)[n] = s;
   *ns = np;
 }
@@ -222,26 +224,26 @@
   g_event_engine->fd_notify_on_write(fd, closure);
 }
 
-size_t grpc_pollset_size(void) { return g_event_engine->pollset_size; }
+static size_t pollset_size(void) { return g_event_engine->pollset_size; }
 
-void grpc_pollset_init(grpc_pollset* pollset, gpr_mu** mu) {
+static void pollset_init(grpc_pollset* pollset, gpr_mu** mu) {
   GRPC_POLLING_API_TRACE("pollset_init(%p)", pollset);
   g_event_engine->pollset_init(pollset, mu);
 }
 
-void grpc_pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) {
+static void pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) {
   GRPC_POLLING_API_TRACE("pollset_shutdown(%p)", pollset);
   g_event_engine->pollset_shutdown(pollset, closure);
 }
 
-void grpc_pollset_destroy(grpc_pollset* pollset) {
+static void pollset_destroy(grpc_pollset* pollset) {
   GRPC_POLLING_API_TRACE("pollset_destroy(%p)", pollset);
   g_event_engine->pollset_destroy(pollset);
 }
 
-grpc_error* grpc_pollset_work(grpc_pollset* pollset,
-                              grpc_pollset_worker** worker,
-                              grpc_millis deadline) {
+static grpc_error* pollset_work(grpc_pollset* pollset,
+                                grpc_pollset_worker** worker,
+                                grpc_millis deadline) {
   GRPC_POLLING_API_TRACE("pollset_work(%p, %" PRIdPTR ") begin", pollset,
                          deadline);
   grpc_error* err = g_event_engine->pollset_work(pollset, worker, deadline);
@@ -250,8 +252,8 @@
   return err;
 }
 
-grpc_error* grpc_pollset_kick(grpc_pollset* pollset,
-                              grpc_pollset_worker* specific_worker) {
+static grpc_error* pollset_kick(grpc_pollset* pollset,
+                                grpc_pollset_worker* specific_worker) {
   GRPC_POLLING_API_TRACE("pollset_kick(%p, %p)", pollset, specific_worker);
   return g_event_engine->pollset_kick(pollset, specific_worker);
 }
@@ -262,43 +264,57 @@
   g_event_engine->pollset_add_fd(pollset, fd);
 }
 
-grpc_pollset_set* grpc_pollset_set_create(void) {
+void pollset_global_init() {}
+void pollset_global_shutdown() {}
+
+grpc_pollset_vtable grpc_posix_pollset_vtable = {
+    pollset_global_init, pollset_global_shutdown,
+    pollset_init,        pollset_shutdown,
+    pollset_destroy,     pollset_work,
+    pollset_kick,        pollset_size};
+
+static grpc_pollset_set* pollset_set_create(void) {
   grpc_pollset_set* pss = g_event_engine->pollset_set_create();
   GRPC_POLLING_API_TRACE("pollset_set_create(%p)", pss);
   return pss;
 }
 
-void grpc_pollset_set_destroy(grpc_pollset_set* pollset_set) {
+static void pollset_set_destroy(grpc_pollset_set* pollset_set) {
   GRPC_POLLING_API_TRACE("pollset_set_destroy(%p)", pollset_set);
   g_event_engine->pollset_set_destroy(pollset_set);
 }
 
-void grpc_pollset_set_add_pollset(grpc_pollset_set* pollset_set,
-                                  grpc_pollset* pollset) {
+static void pollset_set_add_pollset(grpc_pollset_set* pollset_set,
+                                    grpc_pollset* pollset) {
   GRPC_POLLING_API_TRACE("pollset_set_add_pollset(%p, %p)", pollset_set,
                          pollset);
   g_event_engine->pollset_set_add_pollset(pollset_set, pollset);
 }
 
-void grpc_pollset_set_del_pollset(grpc_pollset_set* pollset_set,
-                                  grpc_pollset* pollset) {
+static void pollset_set_del_pollset(grpc_pollset_set* pollset_set,
+                                    grpc_pollset* pollset) {
   GRPC_POLLING_API_TRACE("pollset_set_del_pollset(%p, %p)", pollset_set,
                          pollset);
   g_event_engine->pollset_set_del_pollset(pollset_set, pollset);
 }
 
-void grpc_pollset_set_add_pollset_set(grpc_pollset_set* bag,
-                                      grpc_pollset_set* item) {
+static void pollset_set_add_pollset_set(grpc_pollset_set* bag,
+                                        grpc_pollset_set* item) {
   GRPC_POLLING_API_TRACE("pollset_set_add_pollset_set(%p, %p)", bag, item);
   g_event_engine->pollset_set_add_pollset_set(bag, item);
 }
 
-void grpc_pollset_set_del_pollset_set(grpc_pollset_set* bag,
-                                      grpc_pollset_set* item) {
+static void pollset_set_del_pollset_set(grpc_pollset_set* bag,
+                                        grpc_pollset_set* item) {
   GRPC_POLLING_API_TRACE("pollset_set_del_pollset_set(%p, %p)", bag, item);
   g_event_engine->pollset_set_del_pollset_set(bag, item);
 }
 
+grpc_pollset_set_vtable grpc_posix_pollset_set_vtable = {
+    pollset_set_create,          pollset_set_destroy,
+    pollset_set_add_pollset,     pollset_set_del_pollset,
+    pollset_set_add_pollset_set, pollset_set_del_pollset_set};
+
 void grpc_pollset_set_add_fd(grpc_pollset_set* pollset_set, grpc_fd* fd) {
   GRPC_POLLING_API_TRACE("pollset_set_add_fd(%p, %d)", pollset_set,
                          grpc_fd_wrapped_fd(fd));
diff --git a/src/core/lib/iomgr/ev_posix.h b/src/core/lib/iomgr/ev_posix.h
index 62f1162..6a5129a 100644
--- a/src/core/lib/iomgr/ev_posix.h
+++ b/src/core/lib/iomgr/ev_posix.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_EV_POSIX_H
 #define GRPC_CORE_LIB_IOMGR_EV_POSIX_H
 
+#include <grpc/support/port_platform.h>
+
 #include <poll.h>
 
 #include "src/core/lib/debug/trace.h"
diff --git a/src/core/lib/iomgr/ev_windows.cc b/src/core/lib/iomgr/ev_windows.cc
index 697697d..32c62b7 100644
--- a/src/core/lib/iomgr/ev_windows.cc
+++ b/src/core/lib/iomgr/ev_windows.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_WINSOCK_SOCKET
diff --git a/src/core/lib/iomgr/exec_ctx.cc b/src/core/lib/iomgr/exec_ctx.cc
index 03c833f..2f544b2 100644
--- a/src/core/lib/iomgr/exec_ctx.cc
+++ b/src/core/lib/iomgr/exec_ctx.cc
@@ -16,12 +16,14 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/exec_ctx.h"
 
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
 
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/profiling/timers.h"
 
@@ -53,21 +55,22 @@
 
 static gpr_atm timespec_to_atm_round_down(gpr_timespec ts) {
   ts = gpr_time_sub(ts, g_start_time);
-  double x =
-      GPR_MS_PER_SEC * (double)ts.tv_sec + (double)ts.tv_nsec / GPR_NS_PER_MS;
+  double x = GPR_MS_PER_SEC * static_cast<double>(ts.tv_sec) +
+             static_cast<double>(ts.tv_nsec) / GPR_NS_PER_MS;
   if (x < 0) return 0;
   if (x > GPR_ATM_MAX) return GPR_ATM_MAX;
-  return (gpr_atm)x;
+  return static_cast<gpr_atm>(x);
 }
 
 static gpr_atm timespec_to_atm_round_up(gpr_timespec ts) {
   ts = gpr_time_sub(ts, g_start_time);
-  double x = GPR_MS_PER_SEC * (double)ts.tv_sec +
-             (double)ts.tv_nsec / GPR_NS_PER_MS +
-             (double)(GPR_NS_PER_SEC - 1) / (double)GPR_NS_PER_SEC;
+  double x = GPR_MS_PER_SEC * static_cast<double>(ts.tv_sec) +
+             static_cast<double>(ts.tv_nsec) / GPR_NS_PER_MS +
+             static_cast<double>(GPR_NS_PER_SEC - 1) /
+                 static_cast<double>(GPR_NS_PER_SEC);
   if (x < 0) return 0;
   if (x > GPR_ATM_MAX) return GPR_ATM_MAX;
-  return (gpr_atm)x;
+  return static_cast<gpr_atm>(x);
 }
 
 gpr_timespec grpc_millis_to_timespec(grpc_millis millis,
diff --git a/src/core/lib/iomgr/exec_ctx.h b/src/core/lib/iomgr/exec_ctx.h
index 2e71482..72d0ae5 100644
--- a/src/core/lib/iomgr/exec_ctx.h
+++ b/src/core/lib/iomgr/exec_ctx.h
@@ -19,11 +19,13 @@
 #ifndef GRPC_CORE_LIB_IOMGR_EXEC_CTX_H
 #define GRPC_CORE_LIB_IOMGR_EXEC_CTX_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/atm.h>
 #include <grpc/support/cpu.h>
 #include <grpc/support/log.h>
-#include <grpc/support/tls.h>
 
+#include "src/core/lib/gpr/tls.h"
 #include "src/core/lib/iomgr/closure.h"
 
 typedef gpr_atm grpc_millis;
@@ -52,23 +54,32 @@
 namespace grpc_core {
 /** Execution context.
  *  A bag of data that collects information along a callstack.
- *  Generally created at public API entry points, and passed down as
- *  pointer to child functions that manipulate it.
+ *  It is created on the stack at public API entry points, and stored internally
+ *  as a thread-local variable.
+ *
+ *  Generally, to create an exec_ctx instance, add the following line at the top
+ *  of the public API entry point or at the start of a thread's work function :
+ *
+ *  grpc_core::ExecCtx exec_ctx;
+ *
+ *  Access the created ExecCtx instance using :
+ *  grpc_core::ExecCtx::Get()
  *
  *  Specific responsibilities (this may grow in the future):
  *  - track a list of work that needs to be delayed until the top of the
  *    call stack (this provides a convenient mechanism to run callbacks
  *    without worrying about locking issues)
- *  - provide a decision maker (via grpc_exec_ctx_ready_to_finish) that provides
+ *  - provide a decision maker (via IsReadyToFinish) that provides a
  *    signal as to whether a borrowed thread should continue to do work or
  *    should actively try to finish up and get this thread back to its owner
  *
  *  CONVENTIONS:
  *  - Instance of this must ALWAYS be constructed on the stack, never
  *    heap allocated.
- *  - Instances and pointers to them must always be called exec_ctx.
- *  - Instances are always passed as the first argument to a function that
- *    takes it, and always as a pointer (grpc_exec_ctx is never copied).
+ *  - Exactly one instance of ExecCtx must be created per thread. Instances must
+ *    always be called exec_ctx.
+ *  - Do not pass exec_ctx as a parameter to a function. Always access it using
+ *    grpc_core::ExecCtx::Get()
  */
 class ExecCtx {
  public:
@@ -169,6 +180,10 @@
     return reinterpret_cast<ExecCtx*>(gpr_tls_get(&exec_ctx_));
   }
 
+  static void Set(ExecCtx* exec_ctx) {
+    gpr_tls_set(&exec_ctx_, reinterpret_cast<intptr_t>(exec_ctx));
+  }
+
  protected:
   /** Check if ready to finish */
   virtual bool CheckReadyToFinish() { return false; }
@@ -178,9 +193,6 @@
 
  private:
   /** Set exec_ctx_ to exec_ctx */
-  void Set(ExecCtx* exec_ctx) {
-    gpr_tls_set(&exec_ctx_, reinterpret_cast<intptr_t>(exec_ctx));
-  }
 
   grpc_closure_list closure_list_ = GRPC_CLOSURE_LIST_INIT;
   CombinerData combiner_data_ = {nullptr, nullptr};
diff --git a/src/core/lib/iomgr/executor.cc b/src/core/lib/iomgr/executor.cc
index 835dc9d..b017db5 100644
--- a/src/core/lib/iomgr/executor.cc
+++ b/src/core/lib/iomgr/executor.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/executor.h"
 
 #include <string.h>
@@ -24,12 +26,12 @@
 #include <grpc/support/cpu.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/tls.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/gpr/spinlock.h"
+#include "src/core/lib/gpr/tls.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 
 #define MAX_DEPTH 2
@@ -41,7 +43,7 @@
   size_t depth;
   bool shutdown;
   bool queued_long_job;
-  gpr_thd_id id;
+  grpc_core::Thread thd;
 } thread_state;
 
 static thread_state* g_thread_state;
@@ -94,18 +96,18 @@
     g_max_threads = GPR_MAX(1, 2 * gpr_cpu_num_cores());
     gpr_atm_no_barrier_store(&g_cur_threads, 1);
     gpr_tls_init(&g_this_thread_state);
-    g_thread_state =
-        (thread_state*)gpr_zalloc(sizeof(thread_state) * g_max_threads);
+    g_thread_state = static_cast<thread_state*>(
+        gpr_zalloc(sizeof(thread_state) * g_max_threads));
     for (size_t i = 0; i < g_max_threads; i++) {
       gpr_mu_init(&g_thread_state[i].mu);
       gpr_cv_init(&g_thread_state[i].cv);
+      g_thread_state[i].thd = grpc_core::Thread();
       g_thread_state[i].elems = GRPC_CLOSURE_LIST_INIT;
     }
 
-    gpr_thd_options opt = gpr_thd_options_default();
-    gpr_thd_options_set_joinable(&opt);
-    gpr_thd_new(&g_thread_state[0].id, "grpc_executor", executor_thread,
-                &g_thread_state[0], &opt);
+    g_thread_state[0].thd =
+        grpc_core::Thread("grpc_executor", executor_thread, &g_thread_state[0]);
+    g_thread_state[0].thd.Start();
   } else {
     if (cur_threads == 0) return;
     for (size_t i = 0; i < g_max_threads; i++) {
@@ -119,7 +121,7 @@
     gpr_spinlock_lock(&g_adding_thread_lock);
     gpr_spinlock_unlock(&g_adding_thread_lock);
     for (gpr_atm i = 0; i < g_cur_threads; i++) {
-      gpr_thd_join(g_thread_state[i].id);
+      g_thread_state[i].thd.Join();
     }
     gpr_atm_no_barrier_store(&g_cur_threads, 0);
     for (size_t i = 0; i < g_max_threads; i++) {
@@ -140,7 +142,7 @@
 void grpc_executor_shutdown() { grpc_executor_set_threading(false); }
 
 static void executor_thread(void* arg) {
-  thread_state* ts = (thread_state*)arg;
+  thread_state* ts = static_cast<thread_state*>(arg);
   gpr_tls_set(&g_this_thread_state, (intptr_t)ts);
 
   grpc_core::ExecCtx exec_ctx(0);
@@ -149,7 +151,7 @@
   for (;;) {
     if (executor_trace.enabled()) {
       gpr_log(GPR_DEBUG, "EXECUTOR[%d]: step (sub_depth=%" PRIdPTR ")",
-              (int)(ts - g_thread_state), subtract_depth);
+              static_cast<int>(ts - g_thread_state), subtract_depth);
     }
     gpr_mu_lock(&ts->mu);
     ts->depth -= subtract_depth;
@@ -160,7 +162,7 @@
     if (ts->shutdown) {
       if (executor_trace.enabled()) {
         gpr_log(GPR_DEBUG, "EXECUTOR[%d]: shutdown",
-                (int)(ts - g_thread_state));
+                static_cast<int>(ts - g_thread_state));
       }
       gpr_mu_unlock(&ts->mu);
       break;
@@ -170,7 +172,8 @@
     ts->elems = GRPC_CLOSURE_LIST_INIT;
     gpr_mu_unlock(&ts->mu);
     if (executor_trace.enabled()) {
-      gpr_log(GPR_DEBUG, "EXECUTOR[%d]: execute", (int)(ts - g_thread_state));
+      gpr_log(GPR_DEBUG, "EXECUTOR[%d]: execute",
+              static_cast<int>(ts - g_thread_state));
     }
 
     grpc_core::ExecCtx::Get()->InvalidateNow();
@@ -188,7 +191,8 @@
   }
   do {
     retry_push = false;
-    size_t cur_thread_count = (size_t)gpr_atm_no_barrier_load(&g_cur_threads);
+    size_t cur_thread_count =
+        static_cast<size_t>(gpr_atm_no_barrier_load(&g_cur_threads));
     if (cur_thread_count == 0) {
       if (executor_trace.enabled()) {
 #ifndef NDEBUG
@@ -219,7 +223,7 @@
             GPR_DEBUG,
             "EXECUTOR: try to schedule %p (%s) (created %s:%d) to thread %d",
             closure, is_short ? "short" : "long", closure->file_created,
-            closure->line_created, (int)(ts - g_thread_state));
+            closure->line_created, static_cast<int>(ts - g_thread_state));
 #else
         gpr_log(GPR_DEBUG, "EXECUTOR: try to schedule %p (%s) to thread %d",
                 closure, is_short ? "short" : "long",
@@ -233,7 +237,7 @@
         // guarantee no starvation)
         // ... spin through queues and try again
         gpr_mu_unlock(&ts->mu);
-        size_t idx = (size_t)(ts - g_thread_state);
+        size_t idx = static_cast<size_t>(ts - g_thread_state);
         ts = &g_thread_state[(idx + 1) % cur_thread_count];
         if (ts == orig_ts) {
           retry_push = true;
@@ -255,14 +259,15 @@
       break;
     }
     if (try_new_thread && gpr_spinlock_trylock(&g_adding_thread_lock)) {
-      cur_thread_count = (size_t)gpr_atm_no_barrier_load(&g_cur_threads);
+      cur_thread_count =
+          static_cast<size_t>(gpr_atm_no_barrier_load(&g_cur_threads));
       if (cur_thread_count < g_max_threads) {
         gpr_atm_no_barrier_store(&g_cur_threads, cur_thread_count + 1);
 
-        gpr_thd_options opt = gpr_thd_options_default();
-        gpr_thd_options_set_joinable(&opt);
-        gpr_thd_new(&g_thread_state[cur_thread_count].id, "gpr_executor",
-                    executor_thread, &g_thread_state[cur_thread_count], &opt);
+        g_thread_state[cur_thread_count].thd =
+            grpc_core::Thread("grpc_executor", executor_thread,
+                              &g_thread_state[cur_thread_count]);
+        g_thread_state[cur_thread_count].thd.Start();
       }
       gpr_spinlock_unlock(&g_adding_thread_lock);
     }
diff --git a/src/core/lib/iomgr/executor.h b/src/core/lib/iomgr/executor.h
index e16f11a..68d540a 100644
--- a/src/core/lib/iomgr/executor.h
+++ b/src/core/lib/iomgr/executor.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_EXECUTOR_H
 #define GRPC_CORE_LIB_IOMGR_EXECUTOR_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/closure.h"
 
 typedef enum {
diff --git a/src/core/lib/iomgr/fork_posix.cc b/src/core/lib/iomgr/fork_posix.cc
index 9bfa792..f8645ab 100644
--- a/src/core/lib/iomgr/fork_posix.cc
+++ b/src/core/lib/iomgr/fork_posix.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_POSIX_FORK
@@ -24,12 +26,10 @@
 
 #include <grpc/fork.h>
 #include <grpc/support/log.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/fork.h"
-#include "src/core/lib/gpr/thd_internal.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/timer_manager.h"
@@ -53,7 +53,7 @@
     grpc_timer_manager_set_threading(false);
     grpc_executor_set_threading(false);
     grpc_core::ExecCtx::Get()->Flush();
-    if (!gpr_await_threads(
+    if (!grpc_core::Thread::AwaitAll(
             gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
                          gpr_time_from_seconds(3, GPR_TIMESPAN)))) {
       gpr_log(GPR_ERROR, "gRPC thread still active! Cannot fork!");
diff --git a/src/core/lib/iomgr/fork_windows.cc b/src/core/lib/iomgr/fork_windows.cc
index f9986f3..798f671 100644
--- a/src/core/lib/iomgr/fork_windows.cc
+++ b/src/core/lib/iomgr/fork_windows.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifndef GRPC_POSIX_FORK
diff --git a/src/core/lib/iomgr/gethostname_fallback.cc b/src/core/lib/iomgr/gethostname_fallback.cc
index 81e2c7a..65ae818 100644
--- a/src/core/lib/iomgr/gethostname_fallback.cc
+++ b/src/core/lib/iomgr/gethostname_fallback.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/gethostname.h"
 #include "src/core/lib/iomgr/port.h"
 
diff --git a/src/core/lib/iomgr/gethostname_host_name_max.cc b/src/core/lib/iomgr/gethostname_host_name_max.cc
index 2487160..79f5daa 100644
--- a/src/core/lib/iomgr/gethostname_host_name_max.cc
+++ b/src/core/lib/iomgr/gethostname_host_name_max.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/gethostname.h"
 #include "src/core/lib/iomgr/port.h"
 
@@ -27,7 +29,7 @@
 #include <grpc/support/alloc.h>
 
 char* grpc_gethostname() {
-  char* hostname = (char*)gpr_malloc(HOST_NAME_MAX);
+  char* hostname = static_cast<char*>(gpr_malloc(HOST_NAME_MAX));
   if (gethostname(hostname, HOST_NAME_MAX) != 0) {
     gpr_free(hostname);
     return nullptr;
diff --git a/src/core/lib/iomgr/gethostname_sysconf.cc b/src/core/lib/iomgr/gethostname_sysconf.cc
index 3d74e03..92c5de3 100644
--- a/src/core/lib/iomgr/gethostname_sysconf.cc
+++ b/src/core/lib/iomgr/gethostname_sysconf.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/gethostname.h"
 #include "src/core/lib/iomgr/port.h"
 
diff --git a/src/core/lib/iomgr/iocp_windows.cc b/src/core/lib/iomgr/iocp_windows.cc
index 0b6e682..ce77231 100644
--- a/src/core/lib/iomgr/iocp_windows.cc
+++ b/src/core/lib/iomgr/iocp_windows.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_WINSOCK_SOCKET
@@ -26,10 +28,9 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/log_windows.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/debug/stats.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/iocp_windows.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/socket_windows.h"
diff --git a/src/core/lib/iomgr/iocp_windows.h b/src/core/lib/iomgr/iocp_windows.h
index 75b0ff4..68d9de6 100644
--- a/src/core/lib/iomgr/iocp_windows.h
+++ b/src/core/lib/iomgr/iocp_windows.h
@@ -19,12 +19,15 @@
 #ifndef GRPC_CORE_LIB_IOMGR_IOCP_WINDOWS_H
 #define GRPC_CORE_LIB_IOMGR_IOCP_WINDOWS_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/sync.h>
 
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_WINSOCK_SOCKET
 
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/socket_windows.h"
 
 typedef enum {
diff --git a/src/core/lib/iomgr/iomgr.cc b/src/core/lib/iomgr/iomgr.cc
index 4cd0a4f..468814e 100644
--- a/src/core/lib/iomgr/iomgr.cc
+++ b/src/core/lib/iomgr/iomgr.cc
@@ -28,11 +28,11 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
@@ -47,6 +47,7 @@
 
 void grpc_iomgr_init() {
   grpc_core::ExecCtx exec_ctx;
+  grpc_determine_iomgr_platform();
   g_shutdown = 0;
   gpr_mu_init(&g_mu);
   gpr_cv_init(&g_rcv);
diff --git a/src/core/lib/iomgr/iomgr.h b/src/core/lib/iomgr/iomgr.h
index c7cde7e..e6d66e5 100644
--- a/src/core/lib/iomgr/iomgr.h
+++ b/src/core/lib/iomgr/iomgr.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_IOMGR_H
 #define GRPC_CORE_LIB_IOMGR_IOMGR_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 /** Initializes the iomgr. */
diff --git a/src/core/lib/iomgr/iomgr_custom.cc b/src/core/lib/iomgr/iomgr_custom.cc
new file mode 100644
index 0000000..d34c8e7
--- /dev/null
+++ b/src/core/lib/iomgr/iomgr_custom.cc
@@ -0,0 +1,63 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+
+#include <grpc/support/thd_id.h>
+
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/executor.h"
+#include "src/core/lib/iomgr/iomgr_custom.h"
+#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/pollset_custom.h"
+#include "src/core/lib/iomgr/pollset_set_custom.h"
+#include "src/core/lib/iomgr/resolve_address_custom.h"
+
+gpr_thd_id g_init_thread;
+
+static void iomgr_platform_init(void) {
+  grpc_core::ExecCtx exec_ctx;
+  grpc_executor_set_threading(false);
+  g_init_thread = gpr_thd_currentid();
+  grpc_pollset_global_init();
+}
+static void iomgr_platform_flush(void) {}
+static void iomgr_platform_shutdown(void) { grpc_pollset_global_shutdown(); }
+
+static grpc_iomgr_platform_vtable vtable = {
+    iomgr_platform_init, iomgr_platform_flush, iomgr_platform_shutdown};
+
+void grpc_custom_iomgr_init(grpc_socket_vtable* socket,
+                            grpc_custom_resolver_vtable* resolver,
+                            grpc_custom_timer_vtable* timer,
+                            grpc_custom_poller_vtable* poller) {
+  grpc_custom_endpoint_init(socket);
+  grpc_custom_timer_init(timer);
+  grpc_custom_pollset_init(poller);
+  grpc_custom_pollset_set_init();
+  grpc_custom_resolver_init(resolver);
+  grpc_set_iomgr_platform_vtable(&vtable);
+}
+
+#ifdef GRPC_CUSTOM_SOCKET
+grpc_iomgr_platform_vtable* grpc_default_iomgr_platform_vtable() {
+  return &vtable;
+}
+#endif
diff --git a/src/core/lib/iomgr/iomgr_custom.h b/src/core/lib/iomgr/iomgr_custom.h
new file mode 100644
index 0000000..ceb6c65
--- /dev/null
+++ b/src/core/lib/iomgr/iomgr_custom.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_LIB_IOMGR_IOMGR_CUSTOM_H
+#define GRPC_CORE_LIB_IOMGR_IOMGR_CUSTOM_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/pollset_custom.h"
+#include "src/core/lib/iomgr/resolve_address_custom.h"
+#include "src/core/lib/iomgr/tcp_custom.h"
+#include "src/core/lib/iomgr/timer_custom.h"
+
+#include <grpc/support/thd_id.h>
+
+/* The thread ID of the thread on which grpc was initialized. Used to verify
+ * that all calls into the custom iomgr are made on that same thread */
+extern gpr_thd_id g_init_thread;
+
+#ifdef GRPC_CUSTOM_IOMGR_THREAD_CHECK
+#define GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD() \
+  GPR_ASSERT(gpr_thd_currentid() == g_init_thread)
+#else
+#define GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD()
+#endif /* GRPC_UV_THREAD_CHECK */
+
+void grpc_custom_iomgr_init(grpc_socket_vtable* socket,
+                            grpc_custom_resolver_vtable* resolver,
+                            grpc_custom_timer_vtable* timer,
+                            grpc_custom_poller_vtable* poller);
+
+#endif /* GRPC_CORE_LIB_IOMGR_IOMGR_CUSTOM_H */
diff --git a/src/core/lib/iomgr/iomgr_internal.cc b/src/core/lib/iomgr/iomgr_internal.cc
new file mode 100644
index 0000000..32dbabb
--- /dev/null
+++ b/src/core/lib/iomgr/iomgr_internal.cc
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include <stddef.h>
+
+#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/iomgr/timer_manager.h"
+
+static grpc_iomgr_platform_vtable* iomgr_platform_vtable = nullptr;
+
+void grpc_set_iomgr_platform_vtable(grpc_iomgr_platform_vtable* vtable) {
+  iomgr_platform_vtable = vtable;
+}
+
+void grpc_determine_iomgr_platform() {
+  if (iomgr_platform_vtable == nullptr) {
+    grpc_set_default_iomgr_platform();
+  }
+}
+
+void grpc_iomgr_platform_init() { iomgr_platform_vtable->init(); }
+
+void grpc_iomgr_platform_flush() { iomgr_platform_vtable->flush(); }
+
+void grpc_iomgr_platform_shutdown() { iomgr_platform_vtable->shutdown(); }
diff --git a/src/core/lib/iomgr/iomgr_internal.h b/src/core/lib/iomgr/iomgr_internal.h
index 20b3cb7..b011d9c 100644
--- a/src/core/lib/iomgr/iomgr_internal.h
+++ b/src/core/lib/iomgr/iomgr_internal.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_IOMGR_INTERNAL_H
 #define GRPC_CORE_LIB_IOMGR_IOMGR_INTERNAL_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stdbool.h>
 
 #include "src/core/lib/iomgr/iomgr.h"
@@ -29,9 +31,21 @@
   struct grpc_iomgr_object* prev;
 } grpc_iomgr_object;
 
+typedef struct grpc_iomgr_platform_vtable {
+  void (*init)(void);
+  void (*flush)(void);
+  void (*shutdown)(void);
+} grpc_iomgr_platform_vtable;
+
 void grpc_iomgr_register_object(grpc_iomgr_object* obj, const char* name);
 void grpc_iomgr_unregister_object(grpc_iomgr_object* obj);
 
+void grpc_determine_iomgr_platform();
+
+void grpc_set_iomgr_platform_vtable(grpc_iomgr_platform_vtable* vtable);
+
+void grpc_set_default_iomgr_platform();
+
 void grpc_iomgr_platform_init(void);
 /** flush any globally queued work from iomgr */
 void grpc_iomgr_platform_flush(void);
diff --git a/src/core/lib/iomgr/iomgr_posix.cc b/src/core/lib/iomgr/iomgr_posix.cc
index f8f6fe2..66c9cb7 100644
--- a/src/core/lib/iomgr/iomgr_posix.cc
+++ b/src/core/lib/iomgr/iomgr_posix.cc
@@ -16,25 +16,52 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_POSIX_SOCKET
 
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/iomgr/ev_posix.h"
+#include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/iomgr_posix.h"
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/tcp_client.h"
 #include "src/core/lib/iomgr/tcp_posix.h"
+#include "src/core/lib/iomgr/tcp_server.h"
+#include "src/core/lib/iomgr/timer.h"
 
-void grpc_iomgr_platform_init(void) {
+extern grpc_tcp_server_vtable grpc_posix_tcp_server_vtable;
+extern grpc_tcp_client_vtable grpc_posix_tcp_client_vtable;
+extern grpc_timer_vtable grpc_generic_timer_vtable;
+extern grpc_pollset_vtable grpc_posix_pollset_vtable;
+extern grpc_pollset_set_vtable grpc_posix_pollset_set_vtable;
+extern grpc_address_resolver_vtable grpc_posix_resolver_vtable;
+
+static void iomgr_platform_init(void) {
   grpc_wakeup_fd_global_init();
   grpc_event_engine_init();
 }
 
-void grpc_iomgr_platform_flush(void) {}
+static void iomgr_platform_flush(void) {}
 
-void grpc_iomgr_platform_shutdown(void) {
+static void iomgr_platform_shutdown(void) {
   grpc_event_engine_shutdown();
   grpc_wakeup_fd_global_destroy();
 }
 
+static grpc_iomgr_platform_vtable vtable = {
+    iomgr_platform_init, iomgr_platform_flush, iomgr_platform_shutdown};
+
+void grpc_set_default_iomgr_platform() {
+  grpc_set_tcp_client_impl(&grpc_posix_tcp_client_vtable);
+  grpc_set_tcp_server_impl(&grpc_posix_tcp_server_vtable);
+  grpc_set_timer_impl(&grpc_generic_timer_vtable);
+  grpc_set_pollset_vtable(&grpc_posix_pollset_vtable);
+  grpc_set_pollset_set_vtable(&grpc_posix_pollset_set_vtable);
+  grpc_set_resolver_impl(&grpc_posix_resolver_vtable);
+  grpc_set_iomgr_platform_vtable(&vtable);
+}
+
 #endif /* GRPC_POSIX_SOCKET */
diff --git a/src/core/lib/iomgr/iomgr_posix.h b/src/core/lib/iomgr/iomgr_posix.h
index f7a4af6..54ec46e 100644
--- a/src/core/lib/iomgr/iomgr_posix.h
+++ b/src/core/lib/iomgr/iomgr_posix.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_IOMGR_POSIX_H
 #define GRPC_CORE_LIB_IOMGR_IOMGR_POSIX_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/iomgr_internal.h"
 
 #endif /* GRPC_CORE_LIB_IOMGR_IOMGR_POSIX_H */
diff --git a/src/core/lib/iomgr/iomgr_uv.cc b/src/core/lib/iomgr/iomgr_uv.cc
index 9614c2e..4a98444 100644
--- a/src/core/lib/iomgr/iomgr_uv.cc
+++ b/src/core/lib/iomgr/iomgr_uv.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,26 +16,25 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
-#ifdef GRPC_UV
+#if defined(GRPC_CUSTOM_SOCKET) && defined(GRPC_UV)
 
-#include "src/core/lib/debug/trace.h"
-#include "src/core/lib/iomgr/executor.h"
-#include "src/core/lib/iomgr/iomgr_uv.h"
-#include "src/core/lib/iomgr/pollset_uv.h"
-#include "src/core/lib/iomgr/tcp_uv.h"
+#include "src/core/lib/iomgr/iomgr_custom.h"
+#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/pollset_custom.h"
+#include "src/core/lib/iomgr/tcp_custom.h"
+#include "src/core/lib/iomgr/timer_custom.h"
 
-gpr_thd_id g_init_thread;
+extern grpc_socket_vtable grpc_uv_socket_vtable;
+extern grpc_custom_resolver_vtable uv_resolver_vtable;
+extern grpc_custom_timer_vtable uv_timer_vtable;
+extern grpc_custom_poller_vtable uv_pollset_vtable;
 
-void grpc_iomgr_platform_init(void) {
-  grpc_core::ExecCtx exec_ctx;
-  grpc_pollset_global_init();
-
-  grpc_executor_set_threading(false);
-  g_init_thread = gpr_thd_currentid();
+void grpc_set_default_iomgr_platform() {
+  grpc_custom_iomgr_init(&grpc_uv_socket_vtable, &uv_resolver_vtable,
+                         &uv_timer_vtable, &uv_pollset_vtable);
 }
-void grpc_iomgr_platform_flush(void) {}
-void grpc_iomgr_platform_shutdown(void) { grpc_pollset_global_shutdown(); }
-
-#endif /* GRPC_UV */
+#endif
diff --git a/src/core/lib/iomgr/iomgr_uv.h b/src/core/lib/iomgr/iomgr_uv.h
deleted file mode 100644
index 3b4daaa..0000000
--- a/src/core/lib/iomgr/iomgr_uv.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- *
- * Copyright 2017 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 GRPC_CORE_LIB_IOMGR_IOMGR_UV_H
-#define GRPC_CORE_LIB_IOMGR_IOMGR_UV_H
-
-#include "src/core/lib/iomgr/iomgr_internal.h"
-
-#include <grpc/support/thd.h>
-
-/* The thread ID of the thread on which grpc was initialized. Used to verify
- * that all calls into libuv are made on that same thread */
-extern gpr_thd_id g_init_thread;
-
-#ifdef GRPC_UV_THREAD_CHECK
-#define GRPC_UV_ASSERT_SAME_THREAD() \
-  GPR_ASSERT(gpr_thd_currentid() == g_init_thread)
-#else
-#define GRPC_UV_ASSERT_SAME_THREAD()
-#endif /* GRPC_UV_THREAD_CHECK */
-
-#endif /* GRPC_CORE_LIB_IOMGR_IOMGR_UV_H */
diff --git a/src/core/lib/iomgr/iomgr_windows.cc b/src/core/lib/iomgr/iomgr_windows.cc
index 6303701..cdef89c 100644
--- a/src/core/lib/iomgr/iomgr_windows.cc
+++ b/src/core/lib/iomgr/iomgr_windows.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_WINSOCK_SOCKET
@@ -27,7 +29,18 @@
 #include "src/core/lib/iomgr/iocp_windows.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/iomgr/pollset_windows.h"
+#include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/socket_windows.h"
+#include "src/core/lib/iomgr/tcp_client.h"
+#include "src/core/lib/iomgr/tcp_server.h"
+#include "src/core/lib/iomgr/timer.h"
+
+extern grpc_tcp_server_vtable grpc_windows_tcp_server_vtable;
+extern grpc_tcp_client_vtable grpc_windows_tcp_client_vtable;
+extern grpc_timer_vtable grpc_generic_timer_vtable;
+extern grpc_pollset_vtable grpc_windows_pollset_vtable;
+extern grpc_pollset_set_vtable grpc_windows_pollset_set_vtable;
+extern grpc_address_resolver_vtable grpc_windows_resolver_vtable;
 
 /* Windows' io manager is going to be fully designed using IO completion
    ports. All of what we're doing here is basically make sure that
@@ -44,18 +57,31 @@
   GPR_ASSERT(status == 0);
 }
 
-void grpc_iomgr_platform_init(void) {
+static void iomgr_platform_init(void) {
   winsock_init();
   grpc_iocp_init();
   grpc_pollset_global_init();
 }
 
-void grpc_iomgr_platform_flush(void) { grpc_iocp_flush(); }
+static void iomgr_platform_flush(void) { grpc_iocp_flush(); }
 
-void grpc_iomgr_platform_shutdown(void) {
+static void iomgr_platform_shutdown(void) {
   grpc_pollset_global_shutdown();
   grpc_iocp_shutdown();
   winsock_shutdown();
 }
 
+static grpc_iomgr_platform_vtable vtable = {
+    iomgr_platform_init, iomgr_platform_flush, iomgr_platform_shutdown};
+
+void grpc_set_default_iomgr_platform() {
+  grpc_set_tcp_client_impl(&grpc_windows_tcp_client_vtable);
+  grpc_set_tcp_server_impl(&grpc_windows_tcp_server_vtable);
+  grpc_set_timer_impl(&grpc_generic_timer_vtable);
+  grpc_set_pollset_vtable(&grpc_windows_pollset_vtable);
+  grpc_set_pollset_set_vtable(&grpc_windows_pollset_set_vtable);
+  grpc_set_resolver_impl(&grpc_windows_resolver_vtable);
+  grpc_set_iomgr_platform_vtable(&vtable);
+}
+
 #endif /* GRPC_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/is_epollexclusive_available.cc b/src/core/lib/iomgr/is_epollexclusive_available.cc
index 08f9cf2..036b778 100644
--- a/src/core/lib/iomgr/is_epollexclusive_available.cc
+++ b/src/core/lib/iomgr/is_epollexclusive_available.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #include "src/core/lib/iomgr/is_epollexclusive_available.h"
@@ -37,7 +39,7 @@
   int fd = epoll_create1(EPOLL_CLOEXEC);
   if (fd < 0) {
     if (!logged_why_not) {
-      gpr_log(GPR_ERROR,
+      gpr_log(GPR_DEBUG,
               "epoll_create1 failed with error: %d. Not using epollex polling "
               "engine.",
               fd);
@@ -48,7 +50,7 @@
   int evfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
   if (evfd < 0) {
     if (!logged_why_not) {
-      gpr_log(GPR_ERROR,
+      gpr_log(GPR_DEBUG,
               "eventfd failed with error: %d. Not using epollex polling "
               "engine.",
               fd);
@@ -61,7 +63,8 @@
   /* choose events that should cause an error on
      EPOLLEXCLUSIVE enabled kernels - specifically the combination of
      EPOLLONESHOT and EPOLLEXCLUSIVE */
-  ev.events = (uint32_t)(EPOLLET | EPOLLIN | EPOLLEXCLUSIVE | EPOLLONESHOT);
+  ev.events =
+      static_cast<uint32_t>(EPOLLET | EPOLLIN | EPOLLEXCLUSIVE | EPOLLONESHOT);
   ev.data.ptr = nullptr;
   if (epoll_ctl(fd, EPOLL_CTL_ADD, evfd, &ev) != 0) {
     if (errno != EINVAL) {
@@ -79,7 +82,7 @@
     }
   } else {
     if (!logged_why_not) {
-      gpr_log(GPR_ERROR,
+      gpr_log(GPR_DEBUG,
               "epoll_ctl with EPOLLEXCLUSIVE | EPOLLONESHOT succeeded. This is "
               "evidence of no EPOLLEXCLUSIVE support. Not using "
               "epollex polling engine.");
diff --git a/src/core/lib/iomgr/is_epollexclusive_available.h b/src/core/lib/iomgr/is_epollexclusive_available.h
index 9ae9c5c..8a44113 100644
--- a/src/core/lib/iomgr/is_epollexclusive_available.h
+++ b/src/core/lib/iomgr/is_epollexclusive_available.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_IS_EPOLLEXCLUSIVE_AVAILABLE_H
 #define GRPC_CORE_LIB_IOMGR_IS_EPOLLEXCLUSIVE_AVAILABLE_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stdbool.h>
 
 #ifdef __cplusplus
diff --git a/src/core/lib/iomgr/load_file.cc b/src/core/lib/iomgr/load_file.cc
index b6586fb..f6431d0 100644
--- a/src/core/lib/iomgr/load_file.cc
+++ b/src/core/lib/iomgr/load_file.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/load_file.h"
 
 #include <errno.h>
@@ -45,10 +47,10 @@
   }
   fseek(file, 0, SEEK_END);
   /* Converting to size_t on the assumption that it will not fail */
-  contents_size = (size_t)ftell(file);
+  contents_size = static_cast<size_t>(ftell(file));
   fseek(file, 0, SEEK_SET);
-  contents =
-      (unsigned char*)gpr_malloc(contents_size + (add_null_terminator ? 1 : 0));
+  contents = static_cast<unsigned char*>(
+      gpr_malloc(contents_size + (add_null_terminator ? 1 : 0)));
   bytes_read = fread(contents, 1, contents_size, file);
   if (bytes_read < contents_size) {
     error = GRPC_OS_ERROR(errno, "fread");
diff --git a/src/core/lib/iomgr/load_file.h b/src/core/lib/iomgr/load_file.h
index a733652..1cb2b5d 100644
--- a/src/core/lib/iomgr/load_file.h
+++ b/src/core/lib/iomgr/load_file.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_LOAD_FILE_H
 #define GRPC_CORE_LIB_IOMGR_LOAD_FILE_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stdio.h>
 
 #include <grpc/slice.h>
diff --git a/src/core/lib/iomgr/lockfree_event.cc b/src/core/lib/iomgr/lockfree_event.cc
index 7b194e3..5b6b79f 100644
--- a/src/core/lib/iomgr/lockfree_event.cc
+++ b/src/core/lib/iomgr/lockfree_event.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/lockfree_event.h"
 
 #include <grpc/support/log.h>
diff --git a/src/core/lib/iomgr/lockfree_event.h b/src/core/lib/iomgr/lockfree_event.h
index 3bd3fd7..b507b94 100644
--- a/src/core/lib/iomgr/lockfree_event.h
+++ b/src/core/lib/iomgr/lockfree_event.h
@@ -21,9 +21,11 @@
 
 /* Lock free event notification for file descriptors */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/atm.h>
 
-#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/closure.h"
 
 namespace grpc_core {
 
diff --git a/src/core/lib/iomgr/nameser.h b/src/core/lib/iomgr/nameser.h
index daed6de..22a00cd 100644
--- a/src/core/lib/iomgr/nameser.h
+++ b/src/core/lib/iomgr/nameser.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_NAMESER_H
 #define GRPC_CORE_LIB_IOMGR_NAMESER_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_HAVE_ARPA_NAMESER
diff --git a/src/core/lib/iomgr/network_status_tracker.cc b/src/core/lib/iomgr/network_status_tracker.cc
index 73f8fbf..d4b7f4a 100644
--- a/src/core/lib/iomgr/network_status_tracker.cc
+++ b/src/core/lib/iomgr/network_status_tracker.cc
@@ -16,8 +16,10 @@
  *
  */
 
-#include "src/core/lib/iomgr/network_status_tracker.h"
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/network_status_tracker.h"
 
 void grpc_network_status_shutdown(void) {}
 
diff --git a/src/core/lib/iomgr/network_status_tracker.h b/src/core/lib/iomgr/network_status_tracker.h
index 32244d9..198877f 100644
--- a/src/core/lib/iomgr/network_status_tracker.h
+++ b/src/core/lib/iomgr/network_status_tracker.h
@@ -18,6 +18,8 @@
 
 #ifndef GRPC_CORE_LIB_IOMGR_NETWORK_STATUS_TRACKER_H
 #define GRPC_CORE_LIB_IOMGR_NETWORK_STATUS_TRACKER_H
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/endpoint.h"
 
 void grpc_network_status_init(void);
diff --git a/src/core/lib/iomgr/polling_entity.cc b/src/core/lib/iomgr/polling_entity.cc
index 126f6f4..9f164f6 100644
--- a/src/core/lib/iomgr/polling_entity.cc
+++ b/src/core/lib/iomgr/polling_entity.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
diff --git a/src/core/lib/iomgr/polling_entity.h b/src/core/lib/iomgr/polling_entity.h
index 0102d32..a95e085 100644
--- a/src/core/lib/iomgr/polling_entity.h
+++ b/src/core/lib/iomgr/polling_entity.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_POLLING_ENTITY_H
 #define GRPC_CORE_LIB_IOMGR_POLLING_ENTITY_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/pollset.h"
 #include "src/core/lib/iomgr/pollset_set.h"
 
diff --git a/src/core/lib/iomgr/pollset.cc b/src/core/lib/iomgr/pollset.cc
new file mode 100644
index 0000000..ebfef1d
--- /dev/null
+++ b/src/core/lib/iomgr/pollset.cc
@@ -0,0 +1,56 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/pollset.h"
+
+grpc_pollset_vtable* grpc_pollset_impl;
+
+void grpc_set_pollset_vtable(grpc_pollset_vtable* vtable) {
+  grpc_pollset_impl = vtable;
+}
+
+void grpc_pollset_global_init() { grpc_pollset_impl->global_init(); }
+
+void grpc_pollset_global_shutdown() { grpc_pollset_impl->global_shutdown(); }
+
+void grpc_pollset_init(grpc_pollset* pollset, gpr_mu** mu) {
+  grpc_pollset_impl->init(pollset, mu);
+}
+
+void grpc_pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) {
+  grpc_pollset_impl->shutdown(pollset, closure);
+}
+
+void grpc_pollset_destroy(grpc_pollset* pollset) {
+  grpc_pollset_impl->destroy(pollset);
+}
+
+grpc_error* grpc_pollset_work(grpc_pollset* pollset,
+                              grpc_pollset_worker** worker,
+                              grpc_millis deadline) {
+  return grpc_pollset_impl->work(pollset, worker, deadline);
+}
+
+grpc_error* grpc_pollset_kick(grpc_pollset* pollset,
+                              grpc_pollset_worker* specific_worker) {
+  return grpc_pollset_impl->kick(pollset, specific_worker);
+}
+
+size_t grpc_pollset_size(void) { return grpc_pollset_impl->pollset_size(); }
diff --git a/src/core/lib/iomgr/pollset.h b/src/core/lib/iomgr/pollset.h
index 6bb3cd3..28472b3 100644
--- a/src/core/lib/iomgr/pollset.h
+++ b/src/core/lib/iomgr/pollset.h
@@ -20,6 +20,7 @@
 #define GRPC_CORE_LIB_IOMGR_POLLSET_H
 
 #include <grpc/support/port_platform.h>
+
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 
@@ -37,6 +38,24 @@
 typedef struct grpc_pollset grpc_pollset;
 typedef struct grpc_pollset_worker grpc_pollset_worker;
 
+typedef struct grpc_pollset_vtable {
+  void (*global_init)(void);
+  void (*global_shutdown)(void);
+  void (*init)(grpc_pollset* pollset, gpr_mu** mu);
+  void (*shutdown)(grpc_pollset* pollset, grpc_closure* closure);
+  void (*destroy)(grpc_pollset* pollset);
+  grpc_error* (*work)(grpc_pollset* pollset, grpc_pollset_worker** worker,
+                      grpc_millis deadline);
+  grpc_error* (*kick)(grpc_pollset* pollset,
+                      grpc_pollset_worker* specific_worker);
+  size_t (*pollset_size)(void);
+} grpc_pollset_vtable;
+
+void grpc_set_pollset_vtable(grpc_pollset_vtable* vtable);
+
+void grpc_pollset_global_init(void);
+void grpc_pollset_global_shutdown(void);
+
 size_t grpc_pollset_size(void);
 /* Initialize a pollset: assumes *pollset contains all zeros */
 void grpc_pollset_init(grpc_pollset* pollset, gpr_mu** mu);
diff --git a/src/core/lib/iomgr/pollset_custom.cc b/src/core/lib/iomgr/pollset_custom.cc
new file mode 100644
index 0000000..04bd104
--- /dev/null
+++ b/src/core/lib/iomgr/pollset_custom.cc
@@ -0,0 +1,106 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+
+#include "src/core/lib/iomgr/closure.h"
+#include "src/core/lib/iomgr/iomgr_custom.h"
+#include "src/core/lib/iomgr/pollset.h"
+#include "src/core/lib/iomgr/pollset_custom.h"
+#include "src/core/lib/iomgr/timer.h"
+
+#include "src/core/lib/debug/trace.h"
+
+static grpc_custom_poller_vtable* poller_vtable;
+
+struct grpc_pollset {
+  gpr_mu mu;
+};
+
+static size_t pollset_size() { return sizeof(grpc_pollset); }
+
+static void pollset_global_init() { poller_vtable->init(); }
+
+static void pollset_global_shutdown() { poller_vtable->shutdown(); }
+
+static void pollset_init(grpc_pollset* pollset, gpr_mu** mu) {
+  GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+  gpr_mu_init(&pollset->mu);
+  *mu = &pollset->mu;
+}
+
+static void pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) {
+  GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+  GRPC_CLOSURE_SCHED(closure, GRPC_ERROR_NONE);
+}
+
+static void pollset_destroy(grpc_pollset* pollset) {
+  GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+  gpr_mu_destroy(&pollset->mu);
+}
+
+static grpc_error* pollset_work(grpc_pollset* pollset,
+                                grpc_pollset_worker** worker_hdl,
+                                grpc_millis deadline) {
+  GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+  gpr_mu_unlock(&pollset->mu);
+  grpc_millis now = grpc_core::ExecCtx::Get()->Now();
+  size_t timeout = 0;
+  if (deadline > now) {
+    timeout = deadline - now;
+  }
+  // We yield here because the poll() call might yield
+  // control back to the application
+  grpc_core::ExecCtx* curr = grpc_core::ExecCtx::Get();
+  grpc_core::ExecCtx::Set(nullptr);
+  poller_vtable->poll(timeout);
+  grpc_core::ExecCtx::Set(curr);
+  grpc_core::ExecCtx::Get()->InvalidateNow();
+  if (grpc_core::ExecCtx::Get()->HasWork()) {
+    grpc_core::ExecCtx::Get()->Flush();
+  }
+  gpr_mu_lock(&pollset->mu);
+  return GRPC_ERROR_NONE;
+}
+
+static grpc_error* pollset_kick(grpc_pollset* pollset,
+                                grpc_pollset_worker* specific_worker) {
+  GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+  poller_vtable->kick();
+  return GRPC_ERROR_NONE;
+}
+
+grpc_pollset_vtable custom_pollset_vtable = {
+    pollset_global_init, pollset_global_shutdown,
+    pollset_init,        pollset_shutdown,
+    pollset_destroy,     pollset_work,
+    pollset_kick,        pollset_size};
+
+void grpc_custom_pollset_init(grpc_custom_poller_vtable* vtable) {
+  poller_vtable = vtable;
+  grpc_set_pollset_vtable(&custom_pollset_vtable);
+}
diff --git a/src/core/lib/iomgr/pollset_custom.h b/src/core/lib/iomgr/pollset_custom.h
new file mode 100644
index 0000000..9e2027f
--- /dev/null
+++ b/src/core/lib/iomgr/pollset_custom.h
@@ -0,0 +1,35 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_LIB_IOMGR_POLLSET_CUSTOM_H
+#define GRPC_CORE_LIB_IOMGR_POLLSET_CUSTOM_H
+
+#include <grpc/support/port_platform.h>
+
+#include <stddef.h>
+
+typedef struct grpc_custom_poller_vtable {
+  void (*init)();
+  void (*poll)(size_t timeout_ms);
+  void (*kick)();
+  void (*shutdown)();
+} grpc_custom_poller_vtable;
+
+void grpc_custom_pollset_init(grpc_custom_poller_vtable* vtable);
+
+#endif /* GRPC_CORE_LIB_IOMGR_POLLSET_CUSTOM_H */
diff --git a/src/core/lib/iomgr/pollset_set.cc b/src/core/lib/iomgr/pollset_set.cc
new file mode 100644
index 0000000..42a647a
--- /dev/null
+++ b/src/core/lib/iomgr/pollset_set.cc
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/pollset_set.h"
+
+grpc_pollset_set_vtable* grpc_pollset_set_impl;
+
+void grpc_set_pollset_set_vtable(grpc_pollset_set_vtable* vtable) {
+  grpc_pollset_set_impl = vtable;
+}
+
+grpc_pollset_set* grpc_pollset_set_create() {
+  return grpc_pollset_set_impl->create();
+}
+
+void grpc_pollset_set_destroy(grpc_pollset_set* pollset_set) {
+  grpc_pollset_set_impl->destroy(pollset_set);
+}
+
+void grpc_pollset_set_add_pollset(grpc_pollset_set* pollset_set,
+                                  grpc_pollset* pollset) {
+  grpc_pollset_set_impl->add_pollset(pollset_set, pollset);
+}
+
+void grpc_pollset_set_del_pollset(grpc_pollset_set* pollset_set,
+                                  grpc_pollset* pollset) {
+  grpc_pollset_set_impl->del_pollset(pollset_set, pollset);
+}
+
+void grpc_pollset_set_add_pollset_set(grpc_pollset_set* bag,
+                                      grpc_pollset_set* item) {
+  grpc_pollset_set_impl->add_pollset_set(bag, item);
+}
+
+void grpc_pollset_set_del_pollset_set(grpc_pollset_set* bag,
+                                      grpc_pollset_set* item) {
+  grpc_pollset_set_impl->del_pollset_set(bag, item);
+}
diff --git a/src/core/lib/iomgr/pollset_set.h b/src/core/lib/iomgr/pollset_set.h
index a94d0af..d3355b8 100644
--- a/src/core/lib/iomgr/pollset_set.h
+++ b/src/core/lib/iomgr/pollset_set.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_POLLSET_SET_H
 #define GRPC_CORE_LIB_IOMGR_POLLSET_SET_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/pollset.h"
 
 /* A grpc_pollset_set is a set of pollsets that are interested in an
@@ -28,6 +30,17 @@
 
 typedef struct grpc_pollset_set grpc_pollset_set;
 
+typedef struct grpc_pollset_set_vtable {
+  grpc_pollset_set* (*create)(void);
+  void (*destroy)(grpc_pollset_set* pollset_set);
+  void (*add_pollset)(grpc_pollset_set* pollset_set, grpc_pollset* pollset);
+  void (*del_pollset)(grpc_pollset_set* pollset_set, grpc_pollset* pollset);
+  void (*add_pollset_set)(grpc_pollset_set* bag, grpc_pollset_set* item);
+  void (*del_pollset_set)(grpc_pollset_set* bag, grpc_pollset_set* item);
+} grpc_pollset_set_vtable;
+
+void grpc_set_pollset_set_vtable(grpc_pollset_set_vtable* vtable);
+
 grpc_pollset_set* grpc_pollset_set_create(void);
 void grpc_pollset_set_destroy(grpc_pollset_set* pollset_set);
 void grpc_pollset_set_add_pollset(grpc_pollset_set* pollset_set,
diff --git a/src/core/lib/iomgr/pollset_set_custom.cc b/src/core/lib/iomgr/pollset_set_custom.cc
new file mode 100644
index 0000000..b1ee660
--- /dev/null
+++ b/src/core/lib/iomgr/pollset_set_custom.cc
@@ -0,0 +1,48 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+
+#include "src/core/lib/iomgr/pollset_set.h"
+
+grpc_pollset_set* pollset_set_create(void) {
+  return (grpc_pollset_set*)((intptr_t)0xdeafbeef);
+}
+
+void pollset_set_destroy(grpc_pollset_set* pollset_set) {}
+
+void pollset_set_add_pollset(grpc_pollset_set* pollset_set,
+                             grpc_pollset* pollset) {}
+
+void pollset_set_del_pollset(grpc_pollset_set* pollset_set,
+                             grpc_pollset* pollset) {}
+
+void pollset_set_add_pollset_set(grpc_pollset_set* bag,
+                                 grpc_pollset_set* item) {}
+
+void pollset_set_del_pollset_set(grpc_pollset_set* bag,
+                                 grpc_pollset_set* item) {}
+
+static grpc_pollset_set_vtable vtable = {
+    pollset_set_create,          pollset_set_destroy,
+    pollset_set_add_pollset,     pollset_set_del_pollset,
+    pollset_set_add_pollset_set, pollset_set_del_pollset_set};
+
+void grpc_custom_pollset_set_init() { grpc_set_pollset_set_vtable(&vtable); }
diff --git a/src/core/lib/iomgr/timer_uv.h b/src/core/lib/iomgr/pollset_set_custom.h
similarity index 60%
copy from src/core/lib/iomgr/timer_uv.h
copy to src/core/lib/iomgr/pollset_set_custom.h
index 214aaa6..80e19a1 100644
--- a/src/core/lib/iomgr/timer_uv.h
+++ b/src/core/lib/iomgr/pollset_set_custom.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,17 +16,11 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_IOMGR_TIMER_UV_H
-#define GRPC_CORE_LIB_IOMGR_TIMER_UV_H
+#ifndef GRPC_CORE_LIB_IOMGR_POLLSET_SET_CUSTOM_H
+#define GRPC_CORE_LIB_IOMGR_POLLSET_SET_CUSTOM_H
 
-#include "src/core/lib/iomgr/exec_ctx.h"
+#include <grpc/support/port_platform.h>
 
-struct grpc_timer {
-  grpc_closure* closure;
-  /* This is actually a uv_timer_t*, but we want to keep platform-specific
-     types out of headers */
-  void* uv_timer;
-  int pending;
-};
+void grpc_custom_pollset_set_init();
 
-#endif /* GRPC_CORE_LIB_IOMGR_TIMER_UV_H */
+#endif /* GRPC_CORE_LIB_IOMGR_POLLSET_SET_CUSTOM_H */
diff --git a/src/core/lib/iomgr/pollset_set_uv.cc b/src/core/lib/iomgr/pollset_set_uv.cc
deleted file mode 100644
index ac5dade..0000000
--- a/src/core/lib/iomgr/pollset_set_uv.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- *
- * Copyright 2016 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "src/core/lib/iomgr/port.h"
-
-#ifdef GRPC_UV
-
-#include "src/core/lib/iomgr/pollset_set.h"
-
-grpc_pollset_set* grpc_pollset_set_create(void) {
-  return (grpc_pollset_set*)((intptr_t)0xdeafbeef);
-}
-
-void grpc_pollset_set_destroy(grpc_pollset_set* pollset_set) {}
-
-void grpc_pollset_set_add_pollset(grpc_pollset_set* pollset_set,
-                                  grpc_pollset* pollset) {}
-
-void grpc_pollset_set_del_pollset(grpc_pollset_set* pollset_set,
-                                  grpc_pollset* pollset) {}
-
-void grpc_pollset_set_add_pollset_set(grpc_pollset_set* bag,
-                                      grpc_pollset_set* item) {}
-
-void grpc_pollset_set_del_pollset_set(grpc_pollset_set* bag,
-                                      grpc_pollset_set* item) {}
-
-#endif /* GRPC_UV */
diff --git a/src/core/lib/iomgr/pollset_set_windows.cc b/src/core/lib/iomgr/pollset_set_windows.cc
index 85edc9d..bb9e7f5 100644
--- a/src/core/lib/iomgr/pollset_set_windows.cc
+++ b/src/core/lib/iomgr/pollset_set_windows.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <stdint.h>
 #include "src/core/lib/iomgr/port.h"
 
@@ -23,22 +25,27 @@
 
 #include "src/core/lib/iomgr/pollset_set_windows.h"
 
-grpc_pollset_set* grpc_pollset_set_create(void) {
+static grpc_pollset_set* pollset_set_create(void) {
   return (grpc_pollset_set*)((intptr_t)0xdeafbeef);
 }
 
-void grpc_pollset_set_destroy(grpc_pollset_set* pollset_set) {}
+static void pollset_set_destroy(grpc_pollset_set* pollset_set) {}
 
-void grpc_pollset_set_add_pollset(grpc_pollset_set* pollset_set,
-                                  grpc_pollset* pollset) {}
+static void pollset_set_add_pollset(grpc_pollset_set* pollset_set,
+                                    grpc_pollset* pollset) {}
 
-void grpc_pollset_set_del_pollset(grpc_pollset_set* pollset_set,
-                                  grpc_pollset* pollset) {}
+static void pollset_set_del_pollset(grpc_pollset_set* pollset_set,
+                                    grpc_pollset* pollset) {}
 
-void grpc_pollset_set_add_pollset_set(grpc_pollset_set* bag,
-                                      grpc_pollset_set* item) {}
+static void pollset_set_add_pollset_set(grpc_pollset_set* bag,
+                                        grpc_pollset_set* item) {}
 
-void grpc_pollset_set_del_pollset_set(grpc_pollset_set* bag,
-                                      grpc_pollset_set* item) {}
+static void pollset_set_del_pollset_set(grpc_pollset_set* bag,
+                                        grpc_pollset_set* item) {}
+
+grpc_pollset_set_vtable grpc_windows_pollset_set_vtable = {
+    pollset_set_create,          pollset_set_destroy,
+    pollset_set_add_pollset,     pollset_set_del_pollset,
+    pollset_set_add_pollset_set, pollset_set_del_pollset_set};
 
 #endif /* GRPC_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/pollset_set_windows.h b/src/core/lib/iomgr/pollset_set_windows.h
index 1173f76..5ac9d18 100644
--- a/src/core/lib/iomgr/pollset_set_windows.h
+++ b/src/core/lib/iomgr/pollset_set_windows.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_POLLSET_SET_WINDOWS_H
 #define GRPC_CORE_LIB_IOMGR_POLLSET_SET_WINDOWS_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/pollset_set.h"
 
 #endif /* GRPC_CORE_LIB_IOMGR_POLLSET_SET_WINDOWS_H */
diff --git a/src/core/lib/iomgr/pollset_uv.cc b/src/core/lib/iomgr/pollset_uv.cc
index d9e5ad8..bade6ea 100644
--- a/src/core/lib/iomgr/pollset_uv.cc
+++ b/src/core/lib/iomgr/pollset_uv.cc
@@ -16,141 +16,78 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_UV
 
-#include <uv.h>
-
-#include <string.h>
-
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/sync.h>
+#include "src/core/lib/iomgr/pollset_custom.h"
 
-#include "src/core/lib/iomgr/iomgr_uv.h"
-#include "src/core/lib/iomgr/pollset.h"
-#include "src/core/lib/iomgr/pollset_uv.h"
-
-#include "src/core/lib/debug/trace.h"
-
-grpc_core::DebugOnlyTraceFlag grpc_trace_fd_refcount(false, "fd_refcount");
-
-struct grpc_pollset {
-  uv_timer_t* timer;
-  int shutting_down;
-};
+#include <uv.h>
 
 /* Indicates that grpc_pollset_work should run an iteration of the UV loop
    before running callbacks. This defaults to 1, and should be disabled if
    grpc_pollset_work will be called within the callstack of uv_run */
-int grpc_pollset_work_run_loop;
+int grpc_pollset_work_run_loop = 1;
 
-gpr_mu grpc_polling_mu;
+static bool g_kicked = false;
 
-/* This is used solely to kick the uv loop, by setting a callback to be run
-   immediately in the next loop iteration.
-   Note: In the future, if there is a bug that involves missing wakeups in the
-   future, try adding a uv_async_t to kick the loop differently */
-uv_timer_t* dummy_uv_handle;
+typedef struct uv_poller_handle {
+  uv_timer_t poll_timer;
+  uv_timer_t kick_timer;
+  int refs;
+} uv_poller_handle;
 
-size_t grpc_pollset_size() { return sizeof(grpc_pollset); }
+static uv_poller_handle* g_handle;
 
-void dummy_timer_cb(uv_timer_t* handle) {}
-
-void dummy_handle_close_cb(uv_handle_t* handle) { gpr_free(handle); }
-
-void grpc_pollset_global_init(void) {
-  gpr_mu_init(&grpc_polling_mu);
-  dummy_uv_handle = (uv_timer_t*)gpr_malloc(sizeof(uv_timer_t));
-  uv_timer_init(uv_default_loop(), dummy_uv_handle);
-  grpc_pollset_work_run_loop = 1;
+static void init() {
+  g_handle = (uv_poller_handle*)gpr_malloc(sizeof(uv_poller_handle));
+  g_handle->refs = 2;
+  uv_timer_init(uv_default_loop(), &g_handle->poll_timer);
+  uv_timer_init(uv_default_loop(), &g_handle->kick_timer);
 }
 
-void grpc_pollset_global_shutdown(void) {
-  GRPC_UV_ASSERT_SAME_THREAD();
-  gpr_mu_destroy(&grpc_polling_mu);
-  uv_close((uv_handle_t*)dummy_uv_handle, dummy_handle_close_cb);
-}
+static void empty_timer_cb(uv_timer_t* handle) {}
 
-static void timer_run_cb(uv_timer_t* timer) {}
+static void kick_timer_cb(uv_timer_t* handle) { g_kicked = false; }
 
-static void timer_close_cb(uv_handle_t* handle) {
-  handle->data = (void*)1;
-  gpr_free(handle);
-}
-
-void grpc_pollset_init(grpc_pollset* pollset, gpr_mu** mu) {
-  GRPC_UV_ASSERT_SAME_THREAD();
-  *mu = &grpc_polling_mu;
-  pollset->timer = (uv_timer_t*)gpr_malloc(sizeof(uv_timer_t));
-  uv_timer_init(uv_default_loop(), pollset->timer);
-  pollset->shutting_down = 0;
-}
-
-void grpc_pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) {
-  GPR_ASSERT(!pollset->shutting_down);
-  GRPC_UV_ASSERT_SAME_THREAD();
-  pollset->shutting_down = 1;
+static void run_loop(size_t timeout) {
   if (grpc_pollset_work_run_loop) {
-    // Drain any pending UV callbacks without blocking
-    uv_run(uv_default_loop(), UV_RUN_NOWAIT);
-  } else {
-    // kick the loop once
-    uv_timer_start(dummy_uv_handle, dummy_timer_cb, 0, 0);
-  }
-  GRPC_CLOSURE_SCHED(closure, GRPC_ERROR_NONE);
-}
-
-void grpc_pollset_destroy(grpc_pollset* pollset) {
-  GRPC_UV_ASSERT_SAME_THREAD();
-  uv_close((uv_handle_t*)pollset->timer, timer_close_cb);
-  // timer.data is a boolean indicating that the timer has finished closing
-  pollset->timer->data = (void*)0;
-  if (grpc_pollset_work_run_loop) {
-    while (!pollset->timer->data) {
+    if (timeout == 0) {
       uv_run(uv_default_loop(), UV_RUN_NOWAIT);
-    }
-  }
-}
-
-grpc_error* grpc_pollset_work(grpc_pollset* pollset,
-                              grpc_pollset_worker** worker_hdl,
-                              grpc_millis deadline) {
-  uint64_t timeout;
-  GRPC_UV_ASSERT_SAME_THREAD();
-  gpr_mu_unlock(&grpc_polling_mu);
-  if (grpc_pollset_work_run_loop) {
-    grpc_millis now = grpc_core::ExecCtx::Get()->Now();
-    if (deadline >= now) {
-      timeout = deadline - now;
     } else {
-      timeout = 0;
-    }
-    /* We special-case timeout=0 so that we don't bother with the timer when
-       the loop won't block anyway */
-    if (timeout > 0) {
-      uv_timer_start(pollset->timer, timer_run_cb, timeout, 0);
-      /* Run until there is some I/O activity or the timer triggers. It doesn't
-         matter which happens */
+      uv_timer_start(&g_handle->poll_timer, empty_timer_cb, timeout, 0);
       uv_run(uv_default_loop(), UV_RUN_ONCE);
-      uv_timer_stop(pollset->timer);
-    } else {
-      uv_run(uv_default_loop(), UV_RUN_NOWAIT);
+      uv_timer_stop(&g_handle->poll_timer);
     }
   }
-  if (!grpc_closure_list_empty(*grpc_core::ExecCtx::Get()->closure_list())) {
-    grpc_core::ExecCtx::Get()->Flush();
-  }
-  gpr_mu_lock(&grpc_polling_mu);
-  return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_pollset_kick(grpc_pollset* pollset,
-                              grpc_pollset_worker* specific_worker) {
-  GRPC_UV_ASSERT_SAME_THREAD();
-  uv_timer_start(dummy_uv_handle, dummy_timer_cb, 0, 0);
-  return GRPC_ERROR_NONE;
+static void kick() {
+  if (!g_kicked) {
+    g_kicked = true;
+    uv_timer_start(&g_handle->kick_timer, kick_timer_cb, 0, 0);
+  }
 }
 
+static void close_timer_cb(uv_handle_t* handle) {
+  g_handle->refs--;
+  if (g_handle->refs == 0) {
+    gpr_free(g_handle);
+  }
+}
+
+static void shutdown() {
+  uv_close((uv_handle_t*)&g_handle->poll_timer, close_timer_cb);
+  uv_close((uv_handle_t*)&g_handle->kick_timer, close_timer_cb);
+  if (grpc_pollset_work_run_loop) {
+    GPR_ASSERT(uv_run(uv_default_loop(), UV_RUN_DEFAULT) == 0);
+  }
+}
+
+grpc_custom_poller_vtable uv_pollset_vtable = {init, run_loop, kick, shutdown};
+
 #endif /* GRPC_UV */
diff --git a/src/core/lib/iomgr/pollset_uv.h b/src/core/lib/iomgr/pollset_uv.h
index 566c110..de82bcc 100644
--- a/src/core/lib/iomgr/pollset_uv.h
+++ b/src/core/lib/iomgr/pollset_uv.h
@@ -21,7 +21,12 @@
 
 extern int grpc_pollset_work_run_loop;
 
-void grpc_pollset_global_init(void);
-void grpc_pollset_global_shutdown(void);
+typedef struct grpc_custom_poller_vtable {
+  void (*init)(void);
+  void (*run_loop)(int blocking);
+} grpc_custom_poller_vtable;
+
+void grpc_custom_pollset_global_init(grpc_custom_poller_vtable* vtable);
+void grpc_custom_pollset_global_shutdown(void);
 
 #endif /* GRPC_CORE_LIB_IOMGR_POLLSET_UV_H */
diff --git a/src/core/lib/iomgr/pollset_windows.cc b/src/core/lib/iomgr/pollset_windows.cc
index 6ef949a..e9a808d 100644
--- a/src/core/lib/iomgr/pollset_windows.cc
+++ b/src/core/lib/iomgr/pollset_windows.cc
@@ -16,13 +16,15 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_WINSOCK_SOCKET
 
 #include <grpc/support/log.h>
-#include <grpc/support/thd.h>
 
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/iocp_windows.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/pollset.h"
@@ -36,7 +38,7 @@
 static grpc_pollset_worker* g_active_poller;
 static grpc_pollset_worker g_global_root_worker;
 
-void grpc_pollset_global_init(void) {
+static void pollset_global_init(void) {
   gpr_mu_init(&grpc_polling_mu);
   g_active_poller = NULL;
   g_global_root_worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].next =
@@ -44,7 +46,7 @@
           &g_global_root_worker;
 }
 
-void grpc_pollset_global_shutdown(void) { gpr_mu_destroy(&grpc_polling_mu); }
+static void pollset_global_shutdown(void) { gpr_mu_destroy(&grpc_polling_mu); }
 
 static void remove_worker(grpc_pollset_worker* worker,
                           grpc_pollset_worker_link_type type) {
@@ -78,21 +80,21 @@
       worker->links[type].next->links[type].prev = worker;
 }
 
-size_t grpc_pollset_size(void) { return sizeof(grpc_pollset); }
+static size_t pollset_size(void) { return sizeof(grpc_pollset); }
 
 /* There isn't really any such thing as a pollset under Windows, due to the
    nature of the IO completion ports. We're still going to provide a minimal
    set of features for the sake of the rest of grpc. But grpc_pollset_work
    won't actually do any polling, and return as quickly as possible. */
 
-void grpc_pollset_init(grpc_pollset* pollset, gpr_mu** mu) {
+static void pollset_init(grpc_pollset* pollset, gpr_mu** mu) {
   *mu = &grpc_polling_mu;
   pollset->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next =
       pollset->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].prev =
           &pollset->root_worker;
 }
 
-void grpc_pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) {
+static void pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) {
   pollset->shutting_down = 1;
   grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);
   if (!pollset->is_iocp_worker) {
@@ -102,11 +104,11 @@
   }
 }
 
-void grpc_pollset_destroy(grpc_pollset* pollset) {}
+static void pollset_destroy(grpc_pollset* pollset) {}
 
-grpc_error* grpc_pollset_work(grpc_pollset* pollset,
-                              grpc_pollset_worker** worker_hdl,
-                              grpc_millis deadline) {
+static grpc_error* pollset_work(grpc_pollset* pollset,
+                                grpc_pollset_worker** worker_hdl,
+                                grpc_millis deadline) {
   grpc_pollset_worker worker;
   if (worker_hdl) *worker_hdl = &worker;
 
@@ -180,8 +182,8 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_pollset_kick(grpc_pollset* p,
-                              grpc_pollset_worker* specific_worker) {
+static grpc_error* pollset_kick(grpc_pollset* p,
+                                grpc_pollset_worker* specific_worker) {
   if (specific_worker != NULL) {
     if (specific_worker == GRPC_POLLSET_KICK_BROADCAST) {
       for (specific_worker =
@@ -218,4 +220,10 @@
   return GRPC_ERROR_NONE;
 }
 
+grpc_pollset_vtable grpc_windows_pollset_vtable = {
+    pollset_global_init, pollset_global_shutdown,
+    pollset_init,        pollset_shutdown,
+    pollset_destroy,     pollset_work,
+    pollset_kick,        pollset_size};
+
 #endif /* GRPC_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/pollset_windows.h b/src/core/lib/iomgr/pollset_windows.h
index 93fe7d6..e89758c 100644
--- a/src/core/lib/iomgr/pollset_windows.h
+++ b/src/core/lib/iomgr/pollset_windows.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_POLLSET_WINDOWS_H
 #define GRPC_CORE_LIB_IOMGR_POLLSET_WINDOWS_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/sync.h>
 
 #include "src/core/lib/iomgr/port.h"
diff --git a/src/core/lib/iomgr/port.h b/src/core/lib/iomgr/port.h
index 2509089..c1dcc52 100644
--- a/src/core/lib/iomgr/port.h
+++ b/src/core/lib/iomgr/port.h
@@ -21,8 +21,11 @@
 #ifndef GRPC_CORE_LIB_IOMGR_PORT_H
 #define GRPC_CORE_LIB_IOMGR_PORT_H
 
-#if defined(GRPC_UV)
-// Do nothing
+#ifdef GRPC_UV
+#define GRPC_CUSTOM_SOCKET
+#endif
+#if defined(GRPC_CUSTOM_SOCKET)
+// Do Nothing
 #elif defined(GPR_MANYLINUX1)
 #define GRPC_HAVE_ARPA_NAMESER 1
 #define GRPC_HAVE_IFADDRS 1
@@ -33,13 +36,10 @@
 #define GRPC_POSIX_FORK 1
 #define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
 #define GRPC_POSIX_SOCKET 1
-#define GRPC_POSIX_SOCKETADDR 1
 #define GRPC_POSIX_SOCKETUTILS 1
 #define GRPC_POSIX_WAKEUP_FD 1
-#define GRPC_TIMER_USE_GENERIC 1
 #define GRPC_LINUX_EPOLL 1
 #elif defined(GPR_WINDOWS)
-#define GRPC_TIMER_USE_GENERIC 1
 #define GRPC_WINSOCK_SOCKET 1
 #define GRPC_WINDOWS_SOCKETUTILS 1
 #elif defined(GPR_ANDROID)
@@ -49,10 +49,8 @@
 #define GRPC_HAVE_UNIX_SOCKET 1
 #define GRPC_LINUX_EVENTFD 1
 #define GRPC_POSIX_SOCKET 1
-#define GRPC_POSIX_SOCKETADDR 1
 #define GRPC_POSIX_SOCKETUTILS 1
 #define GRPC_POSIX_WAKEUP_FD 1
-#define GRPC_TIMER_USE_GENERIC 1
 #elif defined(GPR_LINUX)
 #define GRPC_HAVE_ARPA_NAMESER 1
 #define GRPC_HAVE_IFADDRS 1
@@ -64,9 +62,7 @@
 #define GRPC_POSIX_FORK 1
 #define GRPC_POSIX_HOST_NAME_MAX 1
 #define GRPC_POSIX_SOCKET 1
-#define GRPC_POSIX_SOCKETADDR 1
 #define GRPC_POSIX_WAKEUP_FD 1
-#define GRPC_TIMER_USE_GENERIC 1
 #ifdef __GLIBC_PREREQ
 #if __GLIBC_PREREQ(2, 4)
 #define GRPC_LINUX_EPOLL 1
@@ -100,11 +96,9 @@
 #define GRPC_POSIX_FORK 1
 #define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
 #define GRPC_POSIX_SOCKET 1
-#define GRPC_POSIX_SOCKETADDR 1
 #define GRPC_POSIX_SOCKETUTILS 1
 #define GRPC_POSIX_SYSCONF 1
 #define GRPC_POSIX_WAKEUP_FD 1
-#define GRPC_TIMER_USE_GENERIC 1
 #elif defined(GPR_FREEBSD)
 #define GRPC_HAVE_ARPA_NAMESER 1
 #define GRPC_HAVE_IFADDRS 1
@@ -114,36 +108,31 @@
 #define GRPC_POSIX_FORK 1
 #define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
 #define GRPC_POSIX_SOCKET 1
-#define GRPC_POSIX_SOCKETADDR 1
 #define GRPC_POSIX_SOCKETUTILS 1
 #define GRPC_POSIX_WAKEUP_FD 1
-#define GRPC_TIMER_USE_GENERIC 1
 #elif defined(GPR_OPENBSD)
 #define GRPC_HAVE_IFADDRS 1
 #define GRPC_HAVE_IPV6_RECVPKTINFO 1
 #define GRPC_HAVE_UNIX_SOCKET 1
 #define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
 #define GRPC_POSIX_SOCKET 1
-#define GRPC_POSIX_SOCKETADDR 1
 #define GRPC_POSIX_SOCKETUTILS 1
 #define GRPC_POSIX_WAKEUP_FD 1
-#define GRPC_TIMER_USE_GENERIC 1
 #elif defined(GPR_NACL)
 #define GRPC_HAVE_ARPA_NAMESER 1
 #define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
 #define GRPC_POSIX_SOCKET 1
-#define GRPC_POSIX_SOCKETADDR 1
 #define GRPC_POSIX_SOCKETUTILS 1
 #define GRPC_POSIX_WAKEUP_FD 1
-#define GRPC_TIMER_USE_GENERIC 1
 #elif !defined(GPR_NO_AUTODETECT_PLATFORM)
 #error "Platform not recognized"
 #endif
 
 #if defined(GRPC_POSIX_SOCKET) + defined(GRPC_WINSOCK_SOCKET) + \
-        defined(GRPC_CUSTOM_SOCKET) + defined(GRPC_UV) !=       \
+        defined(GRPC_CUSTOM_SOCKET) !=                          \
     1
-#error Must define exactly one of GRPC_POSIX_SOCKET, GRPC_WINSOCK_SOCKET, GPR_CUSTOM_SOCKET
+#error \
+    "Must define exactly one of GRPC_POSIX_SOCKET, GRPC_WINSOCK_SOCKET, GRPC_CUSTOM_SOCKET"
 #endif
 
 #if defined(GRPC_POSIX_HOST_NAME_MAX) && defined(GRPC_POSIX_SYSCONF)
diff --git a/src/core/lib/iomgr/resolve_address.cc b/src/core/lib/iomgr/resolve_address.cc
new file mode 100644
index 0000000..f2a4676
--- /dev/null
+++ b/src/core/lib/iomgr/resolve_address.cc
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include <grpc/support/alloc.h>
+#include "src/core/lib/iomgr/resolve_address.h"
+
+grpc_address_resolver_vtable* grpc_resolve_address_impl;
+
+void grpc_set_resolver_impl(grpc_address_resolver_vtable* vtable) {
+  grpc_resolve_address_impl = vtable;
+}
+
+void grpc_resolve_address(const char* addr, const char* default_port,
+                          grpc_pollset_set* interested_parties,
+                          grpc_closure* on_done,
+                          grpc_resolved_addresses** addresses) {
+  grpc_resolve_address_impl->resolve_address(
+      addr, default_port, interested_parties, on_done, addresses);
+}
+
+void grpc_resolved_addresses_destroy(grpc_resolved_addresses* addrs) {
+  if (addrs != nullptr) {
+    gpr_free(addrs->addrs);
+  }
+  gpr_free(addrs);
+}
+
+grpc_error* grpc_blocking_resolve_address(const char* name,
+                                          const char* default_port,
+                                          grpc_resolved_addresses** addresses) {
+  return grpc_resolve_address_impl->blocking_resolve_address(name, default_port,
+                                                             addresses);
+}
diff --git a/src/core/lib/iomgr/resolve_address.h b/src/core/lib/iomgr/resolve_address.h
index 12fc2ed..fe0d834 100644
--- a/src/core/lib/iomgr/resolve_address.h
+++ b/src/core/lib/iomgr/resolve_address.h
@@ -19,15 +19,31 @@
 #ifndef GRPC_CORE_LIB_IOMGR_RESOLVE_ADDRESS_H
 #define GRPC_CORE_LIB_IOMGR_RESOLVE_ADDRESS_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stddef.h>
-#include "src/core/lib/iomgr/exec_ctx.h"
+
+#include "src/core/lib/iomgr/port.h"
+
+#ifdef GRPC_UV
+#include <uv.h>
+#endif
+
+#ifdef GRPC_WINSOCK_SOCKET
+#include <ws2tcpip.h>
+#endif
+
+#ifdef GRPC_POSIX_SOCKET
+#include <sys/socket.h>
+#endif
+
 #include "src/core/lib/iomgr/pollset_set.h"
 
 #define GRPC_MAX_SOCKADDR_SIZE 128
 
 typedef struct {
   char addr[GRPC_MAX_SOCKADDR_SIZE];
-  size_t len;
+  socklen_t len;
 } grpc_resolved_address;
 
 typedef struct {
@@ -35,20 +51,33 @@
   grpc_resolved_address* addrs;
 } grpc_resolved_addresses;
 
+typedef struct grpc_address_resolver_vtable {
+  void (*resolve_address)(const char* addr, const char* default_port,
+                          grpc_pollset_set* interested_parties,
+                          grpc_closure* on_done,
+                          grpc_resolved_addresses** addresses);
+  grpc_error* (*blocking_resolve_address)(const char* name,
+                                          const char* default_port,
+                                          grpc_resolved_addresses** addresses);
+} grpc_address_resolver_vtable;
+
+void grpc_set_resolver_impl(grpc_address_resolver_vtable* vtable);
+
 /* Asynchronously resolve addr. Use default_port if a port isn't designated
    in addr, otherwise use the port in addr. */
 /* TODO(ctiller): add a timeout here */
-extern void (*grpc_resolve_address)(const char* addr, const char* default_port,
-                                    grpc_pollset_set* interested_parties,
-                                    grpc_closure* on_done,
-                                    grpc_resolved_addresses** addresses);
+void grpc_resolve_address(const char* addr, const char* default_port,
+                          grpc_pollset_set* interested_parties,
+                          grpc_closure* on_done,
+                          grpc_resolved_addresses** addresses);
+
 /* Destroy resolved addresses */
 void grpc_resolved_addresses_destroy(grpc_resolved_addresses* addresses);
 
-/* Resolve addr in a blocking fashion. Returns NULL on failure. On success,
+/* Resolve addr in a blocking fashion. On success,
    result must be freed with grpc_resolved_addresses_destroy. */
-extern grpc_error* (*grpc_blocking_resolve_address)(
-    const char* name, const char* default_port,
-    grpc_resolved_addresses** addresses);
+grpc_error* grpc_blocking_resolve_address(const char* name,
+                                          const char* default_port,
+                                          grpc_resolved_addresses** addresses);
 
 #endif /* GRPC_CORE_LIB_IOMGR_RESOLVE_ADDRESS_H */
diff --git a/src/core/lib/iomgr/resolve_address_custom.cc b/src/core/lib/iomgr/resolve_address_custom.cc
new file mode 100644
index 0000000..9cf7817
--- /dev/null
+++ b/src/core/lib/iomgr/resolve_address_custom.cc
@@ -0,0 +1,187 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+
+#include <grpc/support/log.h>
+#include "src/core/lib/gpr/host_port.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+
+#include "src/core/lib/iomgr/iomgr_custom.h"
+#include "src/core/lib/iomgr/resolve_address_custom.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+
+#include <string.h>
+
+typedef struct grpc_custom_resolver {
+  grpc_closure* on_done;
+  grpc_resolved_addresses** addresses;
+  char* host;
+  char* port;
+} grpc_custom_resolver;
+
+static grpc_custom_resolver_vtable* resolve_address_vtable = nullptr;
+
+static int retry_named_port_failure(grpc_custom_resolver* r,
+                                    grpc_resolved_addresses** res) {
+  // This loop is copied from resolve_address_posix.c
+  const char* svc[][2] = {{"http", "80"}, {"https", "443"}};
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(svc); i++) {
+    if (strcmp(r->port, svc[i][0]) == 0) {
+      gpr_free(r->port);
+      r->port = gpr_strdup(svc[i][1]);
+      if (res) {
+        grpc_error* error =
+            resolve_address_vtable->resolve(r->host, r->port, res);
+        if (error != GRPC_ERROR_NONE) {
+          GRPC_ERROR_UNREF(error);
+          return 0;
+        }
+      } else {
+        resolve_address_vtable->resolve_async(r, r->host, r->port);
+      }
+      return 1;
+    }
+  }
+  return 0;
+}
+
+void grpc_custom_resolve_callback(grpc_custom_resolver* r,
+                                  grpc_resolved_addresses* result,
+                                  grpc_error* error) {
+  GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+  grpc_core::ExecCtx exec_ctx;
+  if (error == GRPC_ERROR_NONE) {
+    *r->addresses = result;
+  } else if (retry_named_port_failure(r, nullptr)) {
+    return;
+  }
+  if (r->on_done) {
+    GRPC_CLOSURE_SCHED(r->on_done, error);
+  }
+  gpr_free(r->host);
+  gpr_free(r->port);
+  gpr_free(r);
+}
+
+static grpc_error* try_split_host_port(const char* name,
+                                       const char* default_port, char** host,
+                                       char** port) {
+  /* parse name, splitting it into host and port parts */
+  grpc_error* error;
+  gpr_split_host_port(name, host, port);
+  if (*host == nullptr) {
+    char* msg;
+    gpr_asprintf(&msg, "unparseable host:port: '%s'", name);
+    error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
+    gpr_free(msg);
+    return error;
+  }
+  if (*port == nullptr) {
+    // TODO(murgatroid99): add tests for this case
+    if (default_port == nullptr) {
+      char* msg;
+      gpr_asprintf(&msg, "no port in name '%s'", name);
+      error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
+      gpr_free(msg);
+      return error;
+    }
+    *port = gpr_strdup(default_port);
+  }
+  return GRPC_ERROR_NONE;
+}
+
+static grpc_error* blocking_resolve_address_impl(
+    const char* name, const char* default_port,
+    grpc_resolved_addresses** addresses) {
+  char* host;
+  char* port;
+  grpc_error* err;
+
+  GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+
+  err = try_split_host_port(name, default_port, &host, &port);
+  if (err != GRPC_ERROR_NONE) {
+    gpr_free(host);
+    gpr_free(port);
+    return err;
+  }
+
+  /* Call getaddrinfo */
+  grpc_custom_resolver resolver;
+  resolver.host = host;
+  resolver.port = port;
+
+  grpc_resolved_addresses* addrs;
+  grpc_core::ExecCtx* curr = grpc_core::ExecCtx::Get();
+  grpc_core::ExecCtx::Set(nullptr);
+  err = resolve_address_vtable->resolve(host, port, &addrs);
+  if (err != GRPC_ERROR_NONE) {
+    if (retry_named_port_failure(&resolver, &addrs)) {
+      GRPC_ERROR_UNREF(err);
+      err = GRPC_ERROR_NONE;
+    }
+  }
+  grpc_core::ExecCtx::Set(curr);
+  if (err == GRPC_ERROR_NONE) {
+    *addresses = addrs;
+  }
+  gpr_free(resolver.host);
+  gpr_free(resolver.port);
+  return err;
+}
+
+static void resolve_address_impl(const char* name, const char* default_port,
+                                 grpc_pollset_set* interested_parties,
+                                 grpc_closure* on_done,
+                                 grpc_resolved_addresses** addrs) {
+  grpc_custom_resolver* r = nullptr;
+  char* host = nullptr;
+  char* port = nullptr;
+  grpc_error* err;
+  GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+  err = try_split_host_port(name, default_port, &host, &port);
+  if (err != GRPC_ERROR_NONE) {
+    GRPC_CLOSURE_SCHED(on_done, err);
+    gpr_free(host);
+    gpr_free(port);
+    return;
+  }
+  r = (grpc_custom_resolver*)gpr_malloc(sizeof(grpc_custom_resolver));
+  r->on_done = on_done;
+  r->addresses = addrs;
+  r->host = host;
+  r->port = port;
+
+  /* Call getaddrinfo */
+  resolve_address_vtable->resolve_async(r, r->host, r->port);
+}
+
+static grpc_address_resolver_vtable custom_resolver_vtable = {
+    resolve_address_impl, blocking_resolve_address_impl};
+
+void grpc_custom_resolver_init(grpc_custom_resolver_vtable* impl) {
+  resolve_address_vtable = impl;
+  grpc_set_resolver_impl(&custom_resolver_vtable);
+}
diff --git a/src/core/lib/iomgr/resolve_address_custom.h b/src/core/lib/iomgr/resolve_address_custom.h
new file mode 100644
index 0000000..e0c6714
--- /dev/null
+++ b/src/core/lib/iomgr/resolve_address_custom.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_LIB_IOMGR_RESOLVE_ADDRESS_CUSTOM_H
+#define GRPC_CORE_LIB_IOMGR_RESOLVE_ADDRESS_CUSTOM_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+
+typedef struct grpc_custom_resolver grpc_custom_resolver;
+
+typedef struct grpc_custom_resolver_vtable {
+  grpc_error* (*resolve)(char* host, char* port, grpc_resolved_addresses** res);
+  void (*resolve_async)(grpc_custom_resolver* resolver, char* host, char* port);
+} grpc_custom_resolver_vtable;
+
+void grpc_custom_resolve_callback(grpc_custom_resolver* resolver,
+                                  grpc_resolved_addresses* result,
+                                  grpc_error* error);
+
+/* Internal APIs */
+void grpc_custom_resolver_init(grpc_custom_resolver_vtable* impl);
+
+#endif /* GRPC_CORE_LIB_IOMGR_RESOLVE_ADDRESS_CUSTOM_H */
diff --git a/src/core/lib/iomgr/resolve_address_posix.cc b/src/core/lib/iomgr/resolve_address_posix.cc
index 176caee..a820755 100644
--- a/src/core/lib/iomgr/resolve_address_posix.cc
+++ b/src/core/lib/iomgr/resolve_address_posix.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 #ifdef GRPC_POSIX_SOCKET
 
@@ -27,19 +29,20 @@
 #include <sys/types.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/block_annotate.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
 
-static grpc_error* blocking_resolve_address_impl(
+static grpc_error* posix_blocking_resolve_address(
     const char* name, const char* default_port,
     grpc_resolved_addresses** addresses) {
   grpc_core::ExecCtx exec_ctx;
@@ -113,14 +116,14 @@
   }
 
   /* Success path: set addrs non-NULL, fill it in */
-  *addresses =
-      (grpc_resolved_addresses*)gpr_malloc(sizeof(grpc_resolved_addresses));
+  *addresses = static_cast<grpc_resolved_addresses*>(
+      gpr_malloc(sizeof(grpc_resolved_addresses)));
   (*addresses)->naddrs = 0;
   for (resp = result; resp != nullptr; resp = resp->ai_next) {
     (*addresses)->naddrs++;
   }
-  (*addresses)->addrs = (grpc_resolved_address*)gpr_malloc(
-      sizeof(grpc_resolved_address) * (*addresses)->naddrs);
+  (*addresses)->addrs = static_cast<grpc_resolved_address*>(
+      gpr_malloc(sizeof(grpc_resolved_address) * (*addresses)->naddrs));
   i = 0;
   for (resp = result; resp != nullptr; resp = resp->ai_next) {
     memcpy(&(*addresses)->addrs[i].addr, resp->ai_addr, resp->ai_addrlen);
@@ -138,10 +141,6 @@
   return err;
 }
 
-grpc_error* (*grpc_blocking_resolve_address)(
-    const char* name, const char* default_port,
-    grpc_resolved_addresses** addresses) = blocking_resolve_address_impl;
-
 typedef struct {
   char* name;
   char* default_port;
@@ -154,7 +153,7 @@
 /* Callback to be passed to grpc_executor to asynch-ify
  * grpc_blocking_resolve_address */
 static void do_request_thread(void* rp, grpc_error* error) {
-  request* r = (request*)rp;
+  request* r = static_cast<request*>(rp);
   GRPC_CLOSURE_SCHED(r->on_done, grpc_blocking_resolve_address(
                                      r->name, r->default_port, r->addrs_out));
   gpr_free(r->name);
@@ -162,18 +161,11 @@
   gpr_free(r);
 }
 
-void grpc_resolved_addresses_destroy(grpc_resolved_addresses* addrs) {
-  if (addrs != nullptr) {
-    gpr_free(addrs->addrs);
-  }
-  gpr_free(addrs);
-}
-
-static void resolve_address_impl(const char* name, const char* default_port,
-                                 grpc_pollset_set* interested_parties,
-                                 grpc_closure* on_done,
-                                 grpc_resolved_addresses** addrs) {
-  request* r = (request*)gpr_malloc(sizeof(request));
+static void posix_resolve_address(const char* name, const char* default_port,
+                                  grpc_pollset_set* interested_parties,
+                                  grpc_closure* on_done,
+                                  grpc_resolved_addresses** addrs) {
+  request* r = static_cast<request*>(gpr_malloc(sizeof(request)));
   GRPC_CLOSURE_INIT(&r->request_closure, do_request_thread, r,
                     grpc_executor_scheduler(GRPC_EXECUTOR_SHORT));
   r->name = gpr_strdup(name);
@@ -183,9 +175,6 @@
   GRPC_CLOSURE_SCHED(&r->request_closure, GRPC_ERROR_NONE);
 }
 
-void (*grpc_resolve_address)(
-    const char* name, const char* default_port,
-    grpc_pollset_set* interested_parties, grpc_closure* on_done,
-    grpc_resolved_addresses** addrs) = resolve_address_impl;
-
+grpc_address_resolver_vtable grpc_posix_resolver_vtable = {
+    posix_resolve_address, posix_blocking_resolve_address};
 #endif
diff --git a/src/core/lib/iomgr/resolve_address_uv.cc b/src/core/lib/iomgr/resolve_address_uv.cc
deleted file mode 100644
index 3eab04f..0000000
--- a/src/core/lib/iomgr/resolve_address_uv.cc
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- *
- * Copyright 2016 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "src/core/lib/iomgr/port.h"
-#ifdef GRPC_UV
-
-#include <uv.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
-
-#include "src/core/lib/iomgr/closure.h"
-#include "src/core/lib/iomgr/error.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
-#include "src/core/lib/iomgr/iomgr_uv.h"
-#include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
-
-#include <string.h>
-
-typedef struct request {
-  grpc_closure* on_done;
-  grpc_resolved_addresses** addresses;
-  struct addrinfo* hints;
-  char* host;
-  char* port;
-} request;
-
-static int retry_named_port_failure(int status, request* r,
-                                    uv_getaddrinfo_cb getaddrinfo_cb) {
-  if (status != 0) {
-    // This loop is copied from resolve_address_posix.c
-    const char* svc[][2] = {{"http", "80"}, {"https", "443"}};
-    for (size_t i = 0; i < GPR_ARRAY_SIZE(svc); i++) {
-      if (strcmp(r->port, svc[i][0]) == 0) {
-        int retry_status;
-        uv_getaddrinfo_t* req =
-            (uv_getaddrinfo_t*)gpr_malloc(sizeof(uv_getaddrinfo_t));
-        req->data = r;
-        r->port = gpr_strdup(svc[i][1]);
-        retry_status = uv_getaddrinfo(uv_default_loop(), req, getaddrinfo_cb,
-                                      r->host, r->port, r->hints);
-        if (retry_status < 0 || getaddrinfo_cb == NULL) {
-          // The callback will not be called
-          gpr_free(req);
-        }
-        return retry_status;
-      }
-    }
-  }
-  /* If this function calls uv_getaddrinfo, it will return that function's
-     return value. That function only returns numbers <=0, so we can safely
-     return 1 to indicate that we never retried */
-  return 1;
-}
-
-static grpc_error* handle_addrinfo_result(int status, struct addrinfo* result,
-                                          grpc_resolved_addresses** addresses) {
-  struct addrinfo* resp;
-  size_t i;
-  if (status != 0) {
-    grpc_error* error;
-    *addresses = NULL;
-    error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("getaddrinfo failed");
-    error =
-        grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
-                           grpc_slice_from_static_string(uv_strerror(status)));
-    return error;
-  }
-  (*addresses) =
-      (grpc_resolved_addresses*)gpr_malloc(sizeof(grpc_resolved_addresses));
-  (*addresses)->naddrs = 0;
-  for (resp = result; resp != NULL; resp = resp->ai_next) {
-    (*addresses)->naddrs++;
-  }
-  (*addresses)->addrs = (grpc_resolved_address*)gpr_malloc(
-      sizeof(grpc_resolved_address) * (*addresses)->naddrs);
-  i = 0;
-  for (resp = result; resp != NULL; resp = resp->ai_next) {
-    memcpy(&(*addresses)->addrs[i].addr, resp->ai_addr, resp->ai_addrlen);
-    (*addresses)->addrs[i].len = resp->ai_addrlen;
-    i++;
-  }
-
-  {
-    for (i = 0; i < (*addresses)->naddrs; i++) {
-      char* buf;
-      grpc_sockaddr_to_string(&buf, &(*addresses)->addrs[i], 0);
-      gpr_free(buf);
-    }
-  }
-  return GRPC_ERROR_NONE;
-}
-
-static void getaddrinfo_callback(uv_getaddrinfo_t* req, int status,
-                                 struct addrinfo* res) {
-  request* r = (request*)req->data;
-  grpc_core::ExecCtx exec_ctx;
-  grpc_error* error;
-  int retry_status;
-  char* port = r->port;
-
-  gpr_free(req);
-  retry_status = retry_named_port_failure(status, r, getaddrinfo_callback);
-  if (retry_status == 0) {
-    /* The request is being retried. It is using its own port string, so we free
-     * the original one */
-    gpr_free(port);
-    return;
-  }
-  /* Either no retry was attempted, or the retry failed. Either way, the
-     original error probably has more interesting information */
-  error = handle_addrinfo_result(status, res, r->addresses);
-  GRPC_CLOSURE_SCHED(r->on_done, error);
-
-  gpr_free(r->hints);
-  gpr_free(r->host);
-  gpr_free(r->port);
-  gpr_free(r);
-  uv_freeaddrinfo(res);
-}
-
-static grpc_error* try_split_host_port(const char* name,
-                                       const char* default_port, char** host,
-                                       char** port) {
-  /* parse name, splitting it into host and port parts */
-  grpc_error* error;
-  gpr_split_host_port(name, host, port);
-  if (*host == NULL) {
-    char* msg;
-    gpr_asprintf(&msg, "unparseable host:port: '%s'", name);
-    error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
-    gpr_free(msg);
-    return error;
-  }
-  if (*port == NULL) {
-    // TODO(murgatroid99): add tests for this case
-    if (default_port == NULL) {
-      char* msg;
-      gpr_asprintf(&msg, "no port in name '%s'", name);
-      error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
-      gpr_free(msg);
-      return error;
-    }
-    *port = gpr_strdup(default_port);
-  }
-  return GRPC_ERROR_NONE;
-}
-
-static grpc_error* blocking_resolve_address_impl(
-    const char* name, const char* default_port,
-    grpc_resolved_addresses** addresses) {
-  char* host;
-  char* port;
-  struct addrinfo hints;
-  uv_getaddrinfo_t req;
-  int s;
-  grpc_error* err;
-  int retry_status;
-  request r;
-
-  GRPC_UV_ASSERT_SAME_THREAD();
-
-  req.addrinfo = NULL;
-
-  err = try_split_host_port(name, default_port, &host, &port);
-  if (err != GRPC_ERROR_NONE) {
-    goto done;
-  }
-
-  /* Call getaddrinfo */
-  memset(&hints, 0, sizeof(hints));
-  hints.ai_family = AF_UNSPEC;     /* ipv4 or ipv6 */
-  hints.ai_socktype = SOCK_STREAM; /* stream socket */
-  hints.ai_flags = AI_PASSIVE;     /* for wildcard IP address */
-
-  s = uv_getaddrinfo(uv_default_loop(), &req, NULL, host, port, &hints);
-  r.addresses = addresses;
-  r.hints = &hints;
-  r.host = host;
-  r.port = port;
-  retry_status = retry_named_port_failure(s, &r, NULL);
-  if (retry_status <= 0) {
-    s = retry_status;
-  }
-  err = handle_addrinfo_result(s, req.addrinfo, addresses);
-
-done:
-  gpr_free(host);
-  gpr_free(port);
-  if (req.addrinfo) {
-    uv_freeaddrinfo(req.addrinfo);
-  }
-  return err;
-}
-
-grpc_error* (*grpc_blocking_resolve_address)(
-    const char* name, const char* default_port,
-    grpc_resolved_addresses** addresses) = blocking_resolve_address_impl;
-
-void grpc_resolved_addresses_destroy(grpc_resolved_addresses* addrs) {
-  if (addrs != NULL) {
-    gpr_free(addrs->addrs);
-  }
-  gpr_free(addrs);
-}
-
-static void resolve_address_impl(const char* name, const char* default_port,
-                                 grpc_pollset_set* interested_parties,
-                                 grpc_closure* on_done,
-                                 grpc_resolved_addresses** addrs) {
-  uv_getaddrinfo_t* req = NULL;
-  request* r = NULL;
-  struct addrinfo* hints = NULL;
-  char* host = NULL;
-  char* port = NULL;
-  grpc_error* err;
-  int s;
-  GRPC_UV_ASSERT_SAME_THREAD();
-  err = try_split_host_port(name, default_port, &host, &port);
-  if (err != GRPC_ERROR_NONE) {
-    GRPC_CLOSURE_SCHED(on_done, err);
-    gpr_free(host);
-    gpr_free(port);
-    return;
-  }
-  r = (request*)gpr_malloc(sizeof(request));
-  r->on_done = on_done;
-  r->addresses = addrs;
-  r->host = host;
-  r->port = port;
-  req = (uv_getaddrinfo_t*)gpr_malloc(sizeof(uv_getaddrinfo_t));
-  req->data = r;
-
-  /* Call getaddrinfo */
-  hints = (addrinfo*)gpr_malloc(sizeof(struct addrinfo));
-  memset(hints, 0, sizeof(struct addrinfo));
-  hints->ai_family = AF_UNSPEC;     /* ipv4 or ipv6 */
-  hints->ai_socktype = SOCK_STREAM; /* stream socket */
-  hints->ai_flags = AI_PASSIVE;     /* for wildcard IP address */
-  r->hints = hints;
-
-  s = uv_getaddrinfo(uv_default_loop(), req, getaddrinfo_callback, host, port,
-                     hints);
-
-  if (s != 0) {
-    *addrs = NULL;
-    err = GRPC_ERROR_CREATE_FROM_STATIC_STRING("getaddrinfo failed");
-    err = grpc_error_set_str(err, GRPC_ERROR_STR_OS_ERROR,
-                             grpc_slice_from_static_string(uv_strerror(s)));
-    GRPC_CLOSURE_SCHED(on_done, err);
-    gpr_free(r);
-    gpr_free(req);
-    gpr_free(hints);
-    gpr_free(host);
-    gpr_free(port);
-  }
-}
-
-void (*grpc_resolve_address)(
-    const char* name, const char* default_port,
-    grpc_pollset_set* interested_parties, grpc_closure* on_done,
-    grpc_resolved_addresses** addrs) = resolve_address_impl;
-
-#endif /* GRPC_UV */
diff --git a/src/core/lib/iomgr/resolve_address_windows.cc b/src/core/lib/iomgr/resolve_address_windows.cc
index e44ab39..71c9261 100644
--- a/src/core/lib/iomgr/resolve_address_windows.cc
+++ b/src/core/lib/iomgr/resolve_address_windows.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 #ifdef GRPC_WINSOCK_SOCKET
 
@@ -28,13 +30,14 @@
 #include <sys/types.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/log_windows.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
+
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/block_annotate.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
@@ -48,7 +51,7 @@
   grpc_resolved_addresses** addresses;
 } request;
 
-static grpc_error* blocking_resolve_address_impl(
+static grpc_error* windows_blocking_resolve_address(
     const char* name, const char* default_port,
     grpc_resolved_addresses** addresses) {
   grpc_core::ExecCtx exec_ctx;
@@ -127,10 +130,6 @@
   return error;
 }
 
-grpc_error* (*grpc_blocking_resolve_address)(
-    const char* name, const char* default_port,
-    grpc_resolved_addresses** addresses) = blocking_resolve_address_impl;
-
 /* Callback to be passed to grpc_executor to asynch-ify
  * grpc_blocking_resolve_address */
 static void do_request_thread(void* rp, grpc_error* error) {
@@ -147,17 +146,10 @@
   gpr_free(r);
 }
 
-void grpc_resolved_addresses_destroy(grpc_resolved_addresses* addrs) {
-  if (addrs != NULL) {
-    gpr_free(addrs->addrs);
-  }
-  gpr_free(addrs);
-}
-
-static void resolve_address_impl(const char* name, const char* default_port,
-                                 grpc_pollset_set* interested_parties,
-                                 grpc_closure* on_done,
-                                 grpc_resolved_addresses** addresses) {
+static void windows_resolve_address(const char* name, const char* default_port,
+                                    grpc_pollset_set* interested_parties,
+                                    grpc_closure* on_done,
+                                    grpc_resolved_addresses** addresses) {
   request* r = (request*)gpr_malloc(sizeof(request));
   GRPC_CLOSURE_INIT(&r->request_closure, do_request_thread, r,
                     grpc_executor_scheduler(GRPC_EXECUTOR_SHORT));
@@ -168,9 +160,6 @@
   GRPC_CLOSURE_SCHED(&r->request_closure, GRPC_ERROR_NONE);
 }
 
-void (*grpc_resolve_address)(
-    const char* name, const char* default_port,
-    grpc_pollset_set* interested_parties, grpc_closure* on_done,
-    grpc_resolved_addresses** addresses) = resolve_address_impl;
-
+grpc_address_resolver_vtable grpc_windows_resolver_vtable = {
+    windows_resolve_address, windows_blocking_resolve_address};
 #endif
diff --git a/src/core/lib/iomgr/resource_quota.cc b/src/core/lib/iomgr/resource_quota.cc
index eaf2f5d..8c42dd7 100644
--- a/src/core/lib/iomgr/resource_quota.cc
+++ b/src/core/lib/iomgr/resource_quota.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/resource_quota.h"
 
 #include <inttypes.h>
@@ -27,8 +29,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/combiner.h"
 
 grpc_core::TraceFlag grpc_resource_quota_trace(false, "resource_quota");
@@ -244,7 +246,7 @@
 static bool rq_reclaim(grpc_resource_quota* resource_quota, bool destructive);
 
 static void rq_step(void* rq, grpc_error* error) {
-  grpc_resource_quota* resource_quota = (grpc_resource_quota*)rq;
+  grpc_resource_quota* resource_quota = static_cast<grpc_resource_quota*>(rq);
   resource_quota->step_scheduled = false;
   do {
     if (rq_alloc(resource_quota)) goto done;
@@ -303,7 +305,7 @@
       resource_user->free_pool += aborted_allocations;
       GRPC_CLOSURE_LIST_SCHED(&resource_user->on_allocated);
       gpr_mu_unlock(&resource_user->mu);
-      ru_unref_by(resource_user, (gpr_atm)aborted_allocations);
+      ru_unref_by(resource_user, static_cast<gpr_atm>(aborted_allocations));
       continue;
     }
     if (resource_user->free_pool < 0 &&
@@ -401,12 +403,12 @@
 } ru_slice_refcount;
 
 static void ru_slice_ref(void* p) {
-  ru_slice_refcount* rc = (ru_slice_refcount*)p;
+  ru_slice_refcount* rc = static_cast<ru_slice_refcount*>(p);
   gpr_ref(&rc->refs);
 }
 
 static void ru_slice_unref(void* p) {
-  ru_slice_refcount* rc = (ru_slice_refcount*)p;
+  ru_slice_refcount* rc = static_cast<ru_slice_refcount*>(p);
   if (gpr_unref(&rc->refs)) {
     grpc_resource_user_free(rc->resource_user, rc->size);
     gpr_free(rc);
@@ -419,8 +421,8 @@
 
 static grpc_slice ru_slice_create(grpc_resource_user* resource_user,
                                   size_t size) {
-  ru_slice_refcount* rc =
-      (ru_slice_refcount*)gpr_malloc(sizeof(ru_slice_refcount) + size);
+  ru_slice_refcount* rc = static_cast<ru_slice_refcount*>(
+      gpr_malloc(sizeof(ru_slice_refcount) + size));
   rc->base.vtable = &ru_slice_vtable;
   rc->base.sub_refcount = &rc->base;
   gpr_ref_init(&rc->refs, 1);
@@ -428,7 +430,7 @@
   rc->size = size;
   grpc_slice slice;
   slice.refcount = &rc->base;
-  slice.data.refcounted.bytes = (uint8_t*)(rc + 1);
+  slice.data.refcounted.bytes = reinterpret_cast<uint8_t*>(rc + 1);
   slice.data.refcounted.length = size;
   return slice;
 }
@@ -439,7 +441,7 @@
  */
 
 static void ru_allocate(void* ru, grpc_error* error) {
-  grpc_resource_user* resource_user = (grpc_resource_user*)ru;
+  grpc_resource_user* resource_user = static_cast<grpc_resource_user*>(ru);
   if (rulist_empty(resource_user->resource_quota,
                    GRPC_RULIST_AWAITING_ALLOCATION)) {
     rq_step_sched(resource_user->resource_quota);
@@ -448,7 +450,7 @@
 }
 
 static void ru_add_to_free_pool(void* ru, grpc_error* error) {
-  grpc_resource_user* resource_user = (grpc_resource_user*)ru;
+  grpc_resource_user* resource_user = static_cast<grpc_resource_user*>(ru);
   if (!rulist_empty(resource_user->resource_quota,
                     GRPC_RULIST_AWAITING_ALLOCATION) &&
       rulist_empty(resource_user->resource_quota,
@@ -473,7 +475,7 @@
 }
 
 static void ru_post_benign_reclaimer(void* ru, grpc_error* error) {
-  grpc_resource_user* resource_user = (grpc_resource_user*)ru;
+  grpc_resource_user* resource_user = static_cast<grpc_resource_user*>(ru);
   if (!ru_post_reclaimer(resource_user, false)) return;
   if (!rulist_empty(resource_user->resource_quota,
                     GRPC_RULIST_AWAITING_ALLOCATION) &&
@@ -487,7 +489,7 @@
 }
 
 static void ru_post_destructive_reclaimer(void* ru, grpc_error* error) {
-  grpc_resource_user* resource_user = (grpc_resource_user*)ru;
+  grpc_resource_user* resource_user = static_cast<grpc_resource_user*>(ru);
   if (!ru_post_reclaimer(resource_user, true)) return;
   if (!rulist_empty(resource_user->resource_quota,
                     GRPC_RULIST_AWAITING_ALLOCATION) &&
@@ -506,7 +508,7 @@
   if (grpc_resource_quota_trace.enabled()) {
     gpr_log(GPR_DEBUG, "RU shutdown %p", ru);
   }
-  grpc_resource_user* resource_user = (grpc_resource_user*)ru;
+  grpc_resource_user* resource_user = static_cast<grpc_resource_user*>(ru);
   gpr_mu_lock(&resource_user->mu);
   GRPC_CLOSURE_SCHED(resource_user->reclaimers[0], GRPC_ERROR_CANCELLED);
   GRPC_CLOSURE_SCHED(resource_user->reclaimers[1], GRPC_ERROR_CANCELLED);
@@ -521,10 +523,10 @@
 }
 
 static void ru_destroy(void* ru, grpc_error* error) {
-  grpc_resource_user* resource_user = (grpc_resource_user*)ru;
+  grpc_resource_user* resource_user = static_cast<grpc_resource_user*>(ru);
   GPR_ASSERT(gpr_atm_no_barrier_load(&resource_user->refs) == 0);
   for (int i = 0; i < GRPC_RULIST_COUNT; i++) {
-    rulist_remove(resource_user, (grpc_rulist)i);
+    rulist_remove(resource_user, static_cast<grpc_rulist>(i));
   }
   GRPC_CLOSURE_SCHED(resource_user->reclaimers[0], GRPC_ERROR_CANCELLED);
   GRPC_CLOSURE_SCHED(resource_user->reclaimers[1], GRPC_ERROR_CANCELLED);
@@ -540,7 +542,7 @@
 
 static void ru_allocated_slices(void* arg, grpc_error* error) {
   grpc_resource_user_slice_allocator* slice_allocator =
-      (grpc_resource_user_slice_allocator*)arg;
+      static_cast<grpc_resource_user_slice_allocator*>(arg);
   if (error == GRPC_ERROR_NONE) {
     for (size_t i = 0; i < slice_allocator->count; i++) {
       grpc_slice_buffer_add_indexed(
@@ -563,7 +565,7 @@
 } rq_resize_args;
 
 static void rq_resize(void* args, grpc_error* error) {
-  rq_resize_args* a = (rq_resize_args*)args;
+  rq_resize_args* a = static_cast<rq_resize_args*>(args);
   int64_t delta = a->size - a->resource_quota->size;
   a->resource_quota->size += delta;
   a->resource_quota->free_pool += delta;
@@ -574,7 +576,7 @@
 }
 
 static void rq_reclamation_done(void* rq, grpc_error* error) {
-  grpc_resource_quota* resource_quota = (grpc_resource_quota*)rq;
+  grpc_resource_quota* resource_quota = static_cast<grpc_resource_quota*>(rq);
   resource_quota->reclaiming = false;
   rq_step_sched(resource_quota);
   grpc_resource_quota_unref_internal(resource_quota);
@@ -587,7 +589,7 @@
 /* Public API */
 grpc_resource_quota* grpc_resource_quota_create(const char* name) {
   grpc_resource_quota* resource_quota =
-      (grpc_resource_quota*)gpr_malloc(sizeof(*resource_quota));
+      static_cast<grpc_resource_quota*>(gpr_malloc(sizeof(*resource_quota)));
   gpr_ref_init(&resource_quota->refs, 1);
   resource_quota->combiner = grpc_combiner_create();
   resource_quota->free_pool = INT64_MAX;
@@ -640,18 +642,18 @@
 
 double grpc_resource_quota_get_memory_pressure(
     grpc_resource_quota* resource_quota) {
-  return ((double)(gpr_atm_no_barrier_load(
+  return (static_cast<double>(gpr_atm_no_barrier_load(
              &resource_quota->memory_usage_estimation))) /
-         ((double)MEMORY_USAGE_ESTIMATION_MAX);
+         (static_cast<double>(MEMORY_USAGE_ESTIMATION_MAX));
 }
 
 /* Public API */
 void grpc_resource_quota_resize(grpc_resource_quota* resource_quota,
                                 size_t size) {
   grpc_core::ExecCtx exec_ctx;
-  rq_resize_args* a = (rq_resize_args*)gpr_malloc(sizeof(*a));
+  rq_resize_args* a = static_cast<rq_resize_args*>(gpr_malloc(sizeof(*a)));
   a->resource_quota = grpc_resource_quota_ref_internal(resource_quota);
-  a->size = (int64_t)size;
+  a->size = static_cast<int64_t>(size);
   gpr_atm_no_barrier_store(&resource_quota->last_size,
                            (gpr_atm)GPR_MIN((size_t)GPR_ATM_MAX, size));
   GRPC_CLOSURE_INIT(&a->closure, rq_resize, a, grpc_schedule_on_exec_ctx);
@@ -659,7 +661,8 @@
 }
 
 size_t grpc_resource_quota_peek_size(grpc_resource_quota* resource_quota) {
-  return (size_t)gpr_atm_no_barrier_load(&resource_quota->last_size);
+  return static_cast<size_t>(
+      gpr_atm_no_barrier_load(&resource_quota->last_size));
 }
 
 /*******************************************************************************
@@ -672,7 +675,8 @@
     if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
       if (channel_args->args[i].type == GRPC_ARG_POINTER) {
         return grpc_resource_quota_ref_internal(
-            (grpc_resource_quota*)channel_args->args[i].value.pointer.p);
+            static_cast<grpc_resource_quota*>(
+                channel_args->args[i].value.pointer.p));
       } else {
         gpr_log(GPR_DEBUG, GRPC_ARG_RESOURCE_QUOTA " should be a pointer");
       }
@@ -682,12 +686,12 @@
 }
 
 static void* rq_copy(void* rq) {
-  grpc_resource_quota_ref((grpc_resource_quota*)rq);
+  grpc_resource_quota_ref(static_cast<grpc_resource_quota*>(rq));
   return rq;
 }
 
 static void rq_destroy(void* rq) {
-  grpc_resource_quota_unref_internal((grpc_resource_quota*)rq);
+  grpc_resource_quota_unref_internal(static_cast<grpc_resource_quota*>(rq));
 }
 
 static int rq_cmp(void* a, void* b) { return GPR_ICMP(a, b); }
@@ -704,7 +708,7 @@
 grpc_resource_user* grpc_resource_user_create(
     grpc_resource_quota* resource_quota, const char* name) {
   grpc_resource_user* resource_user =
-      (grpc_resource_user*)gpr_malloc(sizeof(*resource_user));
+      static_cast<grpc_resource_user*>(gpr_malloc(sizeof(*resource_user)));
   resource_user->resource_quota =
       grpc_resource_quota_ref_internal(resource_quota);
   GRPC_CLOSURE_INIT(&resource_user->allocate_closure, &ru_allocate,
@@ -785,9 +789,9 @@
 void grpc_resource_user_alloc(grpc_resource_user* resource_user, size_t size,
                               grpc_closure* optional_on_done) {
   gpr_mu_lock(&resource_user->mu);
-  ru_ref_by(resource_user, (gpr_atm)size);
-  resource_user->free_pool -= (int64_t)size;
-  resource_user->outstanding_allocations += (int64_t)size;
+  ru_ref_by(resource_user, static_cast<gpr_atm>(size));
+  resource_user->free_pool -= static_cast<int64_t>(size);
+  resource_user->outstanding_allocations += static_cast<int64_t>(size);
   if (grpc_resource_quota_trace.enabled()) {
     gpr_log(GPR_DEBUG, "RQ %s %s: alloc %" PRIdPTR "; free_pool -> %" PRId64,
             resource_user->resource_quota->name, resource_user->name, size,
@@ -801,7 +805,7 @@
       GRPC_CLOSURE_SCHED(&resource_user->allocate_closure, GRPC_ERROR_NONE);
     }
   } else {
-    resource_user->outstanding_allocations -= (int64_t)size;
+    resource_user->outstanding_allocations -= static_cast<int64_t>(size);
     GRPC_CLOSURE_SCHED(optional_on_done, GRPC_ERROR_NONE);
   }
   gpr_mu_unlock(&resource_user->mu);
@@ -810,7 +814,7 @@
 void grpc_resource_user_free(grpc_resource_user* resource_user, size_t size) {
   gpr_mu_lock(&resource_user->mu);
   bool was_zero_or_negative = resource_user->free_pool <= 0;
-  resource_user->free_pool += (int64_t)size;
+  resource_user->free_pool += static_cast<int64_t>(size);
   if (grpc_resource_quota_trace.enabled()) {
     gpr_log(GPR_DEBUG, "RQ %s %s: free %" PRIdPTR "; free_pool -> %" PRId64,
             resource_user->resource_quota->name, resource_user->name, size,
@@ -824,7 +828,7 @@
                        GRPC_ERROR_NONE);
   }
   gpr_mu_unlock(&resource_user->mu);
-  ru_unref_by(resource_user, (gpr_atm)size);
+  ru_unref_by(resource_user, static_cast<gpr_atm>(size));
 }
 
 void grpc_resource_user_post_reclaimer(grpc_resource_user* resource_user,
diff --git a/src/core/lib/iomgr/resource_quota.h b/src/core/lib/iomgr/resource_quota.h
index 39e3aab..937daf8 100644
--- a/src/core/lib/iomgr/resource_quota.h
+++ b/src/core/lib/iomgr/resource_quota.h
@@ -19,10 +19,12 @@
 #ifndef GRPC_CORE_LIB_IOMGR_RESOURCE_QUOTA_H
 #define GRPC_CORE_LIB_IOMGR_RESOURCE_QUOTA_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 
 #include "src/core/lib/debug/trace.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/closure.h"
 
 /** \file Tracks resource usage against a pool.
 
@@ -137,8 +139,4 @@
     grpc_resource_user_slice_allocator* slice_allocator, size_t length,
     size_t count, grpc_slice_buffer* dest);
 
-/* Allocate one slice of length \a size synchronously. */
-grpc_slice grpc_resource_user_slice_malloc(grpc_resource_user* resource_user,
-                                           size_t size);
-
 #endif /* GRPC_CORE_LIB_IOMGR_RESOURCE_QUOTA_H */
diff --git a/src/core/lib/iomgr/sockaddr.h b/src/core/lib/iomgr/sockaddr.h
index 206d596..5edf735 100644
--- a/src/core/lib/iomgr/sockaddr.h
+++ b/src/core/lib/iomgr/sockaddr.h
@@ -23,18 +23,10 @@
 #ifndef GRPC_CORE_LIB_IOMGR_SOCKADDR_H
 #define GRPC_CORE_LIB_IOMGR_SOCKADDR_H
 
-#include "src/core/lib/iomgr/port.h"
+#include <grpc/support/port_platform.h>
 
-#ifdef GRPC_UV
-#include <uv.h>
-#endif
-
-#ifdef GPR_WINDOWS
-#include "src/core/lib/iomgr/sockaddr_windows.h"
-#endif
-
-#ifdef GRPC_POSIX_SOCKETADDR
+#include "src/core/lib/iomgr/sockaddr_custom.h"
 #include "src/core/lib/iomgr/sockaddr_posix.h"
-#endif
+#include "src/core/lib/iomgr/sockaddr_windows.h"
 
 #endif /* GRPC_CORE_LIB_IOMGR_SOCKADDR_H */
diff --git a/src/core/lib/iomgr/sockaddr_custom.h b/src/core/lib/iomgr/sockaddr_custom.h
new file mode 100644
index 0000000..d85cc50
--- /dev/null
+++ b/src/core/lib/iomgr/sockaddr_custom.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_LIB_IOMGR_SOCKADDR_CUSTOM_H
+#define GRPC_CORE_LIB_IOMGR_SOCKADDR_CUSTOM_H
+
+#include <grpc/support/port_platform.h>
+
+#include <stddef.h>
+#include "src/core/lib/iomgr/port.h"
+
+#ifdef GRPC_UV
+
+#include <uv.h>
+
+// TODO(kpayson)  It would be nice to abstract this so we don't
+// depend on anything uv specific
+typedef struct sockaddr grpc_sockaddr;
+typedef struct sockaddr_in grpc_sockaddr_in;
+typedef struct in_addr grpc_in_addr;
+typedef struct sockaddr_in6 grpc_sockaddr_in6;
+typedef struct in6_addr grpc_in6_addr;
+
+#define GRPC_INET_ADDRSTRLEN INET_ADDRSTRLEN
+#define GRPC_INET6_ADDRSTRLEN INET6_ADDRSTRLEN
+
+#define GRPC_SOCK_STREAM SOCK_STREAM
+#define GRPC_SOCK_DGRAM SOCK_DGRAM
+
+#define GRPC_AF_UNSPEC AF_UNSPEC
+#define GRPC_AF_UNIX AF_UNIX
+#define GRPC_AF_INET AF_INET
+#define GRPC_AF_INET6 AF_INET6
+
+#define GRPC_AI_PASSIVE AI_PASSIVE
+
+#endif  // GRPC_UV
+
+#endif /* GRPC_CORE_LIB_IOMGR_SOCKADDR_CUSTOM_H */
diff --git a/src/core/lib/iomgr/sockaddr_posix.h b/src/core/lib/iomgr/sockaddr_posix.h
index 22d57ca..5b18bbc 100644
--- a/src/core/lib/iomgr/sockaddr_posix.h
+++ b/src/core/lib/iomgr/sockaddr_posix.h
@@ -19,6 +19,11 @@
 #ifndef GRPC_CORE_LIB_IOMGR_SOCKADDR_POSIX_H
 #define GRPC_CORE_LIB_IOMGR_SOCKADDR_POSIX_H
 
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+
+#ifdef GRPC_POSIX_SOCKET
 #include <arpa/inet.h>
 #include <netdb.h>
 #include <netinet/in.h>
@@ -26,4 +31,25 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+typedef struct sockaddr grpc_sockaddr;
+typedef struct sockaddr_in grpc_sockaddr_in;
+typedef struct in_addr grpc_in_addr;
+typedef struct sockaddr_in6 grpc_sockaddr_in6;
+typedef struct in6_addr grpc_in6_addr;
+
+#define GRPC_INET_ADDRSTRLEN INET_ADDRSTRLEN
+#define GRPC_INET6_ADDRSTRLEN INET6_ADDRSTRLEN
+
+#define GRPC_SOCK_STREAM SOCK_STREAM
+#define GRPC_SOCK_DGRAM SOCK_DGRAM
+
+#define GRPC_AF_UNSPEC AF_UNSPEC
+#define GRPC_AF_UNIX AF_UNIX
+#define GRPC_AF_INET AF_INET
+#define GRPC_AF_INET6 AF_INET6
+
+#define GRPC_AI_PASSIVE AI_PASSIVE
+
+#endif
+
 #endif /* GRPC_CORE_LIB_IOMGR_SOCKADDR_POSIX_H */
diff --git a/src/core/lib/iomgr/sockaddr_utils.cc b/src/core/lib/iomgr/sockaddr_utils.cc
index 71e3e38..df25f77 100644
--- a/src/core/lib/iomgr/sockaddr_utils.cc
+++ b/src/core/lib/iomgr/sockaddr_utils.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/sockaddr_utils.h"
 
 #include <errno.h>
@@ -23,11 +25,10 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
 #include <grpc/support/string_util.h>
 
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/iomgr/socket_utils.h"
@@ -39,23 +40,26 @@
 int grpc_sockaddr_is_v4mapped(const grpc_resolved_address* resolved_addr,
                               grpc_resolved_address* resolved_addr4_out) {
   GPR_ASSERT(resolved_addr != resolved_addr4_out);
-  const struct sockaddr* addr = (const struct sockaddr*)resolved_addr->addr;
-  struct sockaddr_in* addr4_out =
+  const grpc_sockaddr* addr =
+      reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
+  grpc_sockaddr_in* addr4_out =
       resolved_addr4_out == nullptr
           ? nullptr
-          : (struct sockaddr_in*)resolved_addr4_out->addr;
-  if (addr->sa_family == AF_INET6) {
-    const struct sockaddr_in6* addr6 = (const struct sockaddr_in6*)addr;
+          : reinterpret_cast<grpc_sockaddr_in*>(resolved_addr4_out->addr);
+  if (addr->sa_family == GRPC_AF_INET6) {
+    const grpc_sockaddr_in6* addr6 =
+        reinterpret_cast<const grpc_sockaddr_in6*>(addr);
     if (memcmp(addr6->sin6_addr.s6_addr, kV4MappedPrefix,
                sizeof(kV4MappedPrefix)) == 0) {
       if (resolved_addr4_out != nullptr) {
         /* Normalize ::ffff:0.0.0.0/96 to IPv4. */
         memset(resolved_addr4_out, 0, sizeof(*resolved_addr4_out));
-        addr4_out->sin_family = AF_INET;
+        addr4_out->sin_family = GRPC_AF_INET;
         /* s6_addr32 would be nice, but it's non-standard. */
         memcpy(&addr4_out->sin_addr, &addr6->sin6_addr.s6_addr[12], 4);
         addr4_out->sin_port = addr6->sin6_port;
-        resolved_addr4_out->len = sizeof(struct sockaddr_in);
+        resolved_addr4_out->len =
+            static_cast<socklen_t>(sizeof(grpc_sockaddr_in));
       }
       return 1;
     }
@@ -66,17 +70,19 @@
 int grpc_sockaddr_to_v4mapped(const grpc_resolved_address* resolved_addr,
                               grpc_resolved_address* resolved_addr6_out) {
   GPR_ASSERT(resolved_addr != resolved_addr6_out);
-  const struct sockaddr* addr = (const struct sockaddr*)resolved_addr->addr;
-  struct sockaddr_in6* addr6_out =
-      (struct sockaddr_in6*)resolved_addr6_out->addr;
-  if (addr->sa_family == AF_INET) {
-    const struct sockaddr_in* addr4 = (const struct sockaddr_in*)addr;
+  const grpc_sockaddr* addr =
+      reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
+  grpc_sockaddr_in6* addr6_out =
+      reinterpret_cast<grpc_sockaddr_in6*>(resolved_addr6_out->addr);
+  if (addr->sa_family == GRPC_AF_INET) {
+    const grpc_sockaddr_in* addr4 =
+        reinterpret_cast<const grpc_sockaddr_in*>(addr);
     memset(resolved_addr6_out, 0, sizeof(*resolved_addr6_out));
-    addr6_out->sin6_family = AF_INET6;
+    addr6_out->sin6_family = GRPC_AF_INET6;
     memcpy(&addr6_out->sin6_addr.s6_addr[0], kV4MappedPrefix, 12);
     memcpy(&addr6_out->sin6_addr.s6_addr[12], &addr4->sin_addr, 4);
     addr6_out->sin6_port = addr4->sin_port;
-    resolved_addr6_out->len = sizeof(struct sockaddr_in6);
+    resolved_addr6_out->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in6));
     return 1;
   }
   return 0;
@@ -84,30 +90,32 @@
 
 int grpc_sockaddr_is_wildcard(const grpc_resolved_address* resolved_addr,
                               int* port_out) {
-  const struct sockaddr* addr;
+  const grpc_sockaddr* addr;
   grpc_resolved_address addr4_normalized;
   if (grpc_sockaddr_is_v4mapped(resolved_addr, &addr4_normalized)) {
     resolved_addr = &addr4_normalized;
   }
-  addr = (const struct sockaddr*)resolved_addr->addr;
-  if (addr->sa_family == AF_INET) {
+  addr = reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
+  if (addr->sa_family == GRPC_AF_INET) {
     /* Check for 0.0.0.0 */
-    const struct sockaddr_in* addr4 = (const struct sockaddr_in*)addr;
+    const grpc_sockaddr_in* addr4 =
+        reinterpret_cast<const grpc_sockaddr_in*>(addr);
     if (addr4->sin_addr.s_addr != 0) {
       return 0;
     }
-    *port_out = ntohs(addr4->sin_port);
+    *port_out = grpc_ntohs(addr4->sin_port);
     return 1;
-  } else if (addr->sa_family == AF_INET6) {
+  } else if (addr->sa_family == GRPC_AF_INET6) {
     /* Check for :: */
-    const struct sockaddr_in6* addr6 = (const struct sockaddr_in6*)addr;
+    const grpc_sockaddr_in6* addr6 =
+        reinterpret_cast<const grpc_sockaddr_in6*>(addr);
     int i;
     for (i = 0; i < 16; i++) {
       if (addr6->sin6_addr.s6_addr[i] != 0) {
         return 0;
       }
     }
-    *port_out = ntohs(addr6->sin6_port);
+    *port_out = grpc_ntohs(addr6->sin6_port);
     return 1;
   } else {
     return 0;
@@ -122,31 +130,33 @@
 
 void grpc_sockaddr_make_wildcard4(int port,
                                   grpc_resolved_address* resolved_wild_out) {
-  struct sockaddr_in* wild_out = (struct sockaddr_in*)resolved_wild_out->addr;
+  grpc_sockaddr_in* wild_out =
+      reinterpret_cast<grpc_sockaddr_in*>(resolved_wild_out->addr);
   GPR_ASSERT(port >= 0 && port < 65536);
   memset(resolved_wild_out, 0, sizeof(*resolved_wild_out));
-  wild_out->sin_family = AF_INET;
-  wild_out->sin_port = htons((uint16_t)port);
-  resolved_wild_out->len = sizeof(struct sockaddr_in);
+  wild_out->sin_family = GRPC_AF_INET;
+  wild_out->sin_port = grpc_htons(static_cast<uint16_t>(port));
+  resolved_wild_out->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in));
 }
 
 void grpc_sockaddr_make_wildcard6(int port,
                                   grpc_resolved_address* resolved_wild_out) {
-  struct sockaddr_in6* wild_out = (struct sockaddr_in6*)resolved_wild_out->addr;
+  grpc_sockaddr_in6* wild_out =
+      reinterpret_cast<grpc_sockaddr_in6*>(resolved_wild_out->addr);
   GPR_ASSERT(port >= 0 && port < 65536);
   memset(resolved_wild_out, 0, sizeof(*resolved_wild_out));
-  wild_out->sin6_family = AF_INET6;
-  wild_out->sin6_port = htons((uint16_t)port);
-  resolved_wild_out->len = sizeof(struct sockaddr_in6);
+  wild_out->sin6_family = GRPC_AF_INET6;
+  wild_out->sin6_port = grpc_htons(static_cast<uint16_t>(port));
+  resolved_wild_out->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in6));
 }
 
 int grpc_sockaddr_to_string(char** out,
                             const grpc_resolved_address* resolved_addr,
                             int normalize) {
-  const struct sockaddr* addr;
+  const grpc_sockaddr* addr;
   const int save_errno = errno;
   grpc_resolved_address addr_normalized;
-  char ntop_buf[INET6_ADDRSTRLEN];
+  char ntop_buf[GRPC_INET6_ADDRSTRLEN];
   const void* ip = nullptr;
   int port = 0;
   uint32_t sin6_scope_id = 0;
@@ -156,15 +166,17 @@
   if (normalize && grpc_sockaddr_is_v4mapped(resolved_addr, &addr_normalized)) {
     resolved_addr = &addr_normalized;
   }
-  addr = (const struct sockaddr*)resolved_addr->addr;
-  if (addr->sa_family == AF_INET) {
-    const struct sockaddr_in* addr4 = (const struct sockaddr_in*)addr;
+  addr = reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
+  if (addr->sa_family == GRPC_AF_INET) {
+    const grpc_sockaddr_in* addr4 =
+        reinterpret_cast<const grpc_sockaddr_in*>(addr);
     ip = &addr4->sin_addr;
-    port = ntohs(addr4->sin_port);
-  } else if (addr->sa_family == AF_INET6) {
-    const struct sockaddr_in6* addr6 = (const struct sockaddr_in6*)addr;
+    port = grpc_ntohs(addr4->sin_port);
+  } else if (addr->sa_family == GRPC_AF_INET6) {
+    const grpc_sockaddr_in6* addr6 =
+        reinterpret_cast<const grpc_sockaddr_in6*>(addr);
     ip = &addr6->sin6_addr;
-    port = ntohs(addr6->sin6_port);
+    port = grpc_ntohs(addr6->sin6_port);
     sin6_scope_id = addr6->sin6_scope_id;
   }
   if (ip != nullptr && grpc_inet_ntop(addr->sa_family, ip, ntop_buf,
@@ -186,6 +198,22 @@
   return ret;
 }
 
+void grpc_string_to_sockaddr(grpc_resolved_address* out, char* addr, int port) {
+  grpc_sockaddr_in6* addr6 = (grpc_sockaddr_in6*)out->addr;
+  grpc_sockaddr_in* addr4 = (grpc_sockaddr_in*)out->addr;
+
+  if (grpc_inet_pton(GRPC_AF_INET6, addr, &addr6->sin6_addr) == 1) {
+    addr6->sin6_family = GRPC_AF_INET6;
+    out->len = sizeof(grpc_sockaddr_in6);
+  } else if (grpc_inet_pton(GRPC_AF_INET, addr, &addr4->sin_addr) == 1) {
+    addr4->sin_family = GRPC_AF_INET;
+    out->len = sizeof(grpc_sockaddr_in);
+  } else {
+    GPR_ASSERT(0);
+  }
+  grpc_sockaddr_set_port(out, port);
+}
+
 char* grpc_sockaddr_to_uri(const grpc_resolved_address* resolved_addr) {
   grpc_resolved_address addr_normalized;
   if (grpc_sockaddr_is_v4mapped(resolved_addr, &addr_normalized)) {
@@ -208,30 +236,33 @@
 
 const char* grpc_sockaddr_get_uri_scheme(
     const grpc_resolved_address* resolved_addr) {
-  const struct sockaddr* addr = (const struct sockaddr*)resolved_addr->addr;
+  const grpc_sockaddr* addr =
+      reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
   switch (addr->sa_family) {
-    case AF_INET:
+    case GRPC_AF_INET:
       return "ipv4";
-    case AF_INET6:
+    case GRPC_AF_INET6:
       return "ipv6";
-    case AF_UNIX:
+    case GRPC_AF_UNIX:
       return "unix";
   }
   return nullptr;
 }
 
 int grpc_sockaddr_get_family(const grpc_resolved_address* resolved_addr) {
-  const struct sockaddr* addr = (const struct sockaddr*)resolved_addr->addr;
+  const grpc_sockaddr* addr =
+      reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
   return addr->sa_family;
 }
 
 int grpc_sockaddr_get_port(const grpc_resolved_address* resolved_addr) {
-  const struct sockaddr* addr = (const struct sockaddr*)resolved_addr->addr;
+  const grpc_sockaddr* addr =
+      reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
   switch (addr->sa_family) {
-    case AF_INET:
-      return ntohs(((struct sockaddr_in*)addr)->sin_port);
-    case AF_INET6:
-      return ntohs(((struct sockaddr_in6*)addr)->sin6_port);
+    case GRPC_AF_INET:
+      return grpc_ntohs(((grpc_sockaddr_in*)addr)->sin_port);
+    case GRPC_AF_INET6:
+      return grpc_ntohs(((grpc_sockaddr_in6*)addr)->sin6_port);
     default:
       if (grpc_is_unix_socket(resolved_addr)) {
         return 1;
@@ -244,15 +275,18 @@
 
 int grpc_sockaddr_set_port(const grpc_resolved_address* resolved_addr,
                            int port) {
-  const struct sockaddr* addr = (const struct sockaddr*)resolved_addr->addr;
+  const grpc_sockaddr* addr =
+      reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
   switch (addr->sa_family) {
-    case AF_INET:
+    case GRPC_AF_INET:
       GPR_ASSERT(port >= 0 && port < 65536);
-      ((struct sockaddr_in*)addr)->sin_port = htons((uint16_t)port);
+      ((grpc_sockaddr_in*)addr)->sin_port =
+          grpc_htons(static_cast<uint16_t>(port));
       return 1;
-    case AF_INET6:
+    case GRPC_AF_INET6:
       GPR_ASSERT(port >= 0 && port < 65536);
-      ((struct sockaddr_in6*)addr)->sin6_port = htons((uint16_t)port);
+      ((grpc_sockaddr_in6*)addr)->sin6_port =
+          grpc_htons(static_cast<uint16_t>(port));
       return 1;
     default:
       gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_set_port",
diff --git a/src/core/lib/iomgr/sockaddr_utils.h b/src/core/lib/iomgr/sockaddr_utils.h
index e3bd51a..a4e90a7 100644
--- a/src/core/lib/iomgr/sockaddr_utils.h
+++ b/src/core/lib/iomgr/sockaddr_utils.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_SOCKADDR_UTILS_H
 #define GRPC_CORE_LIB_IOMGR_SOCKADDR_UTILS_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/resolve_address.h"
 
 /* Returns true if addr is an IPv4-mapped IPv6 address within the
@@ -69,6 +71,8 @@
 int grpc_sockaddr_to_string(char** out, const grpc_resolved_address* addr,
                             int normalize);
 
+void grpc_string_to_sockaddr(grpc_resolved_address* out, char* addr, int port);
+
 /* Returns the URI string corresponding to \a addr */
 char* grpc_sockaddr_to_uri(const grpc_resolved_address* addr);
 
diff --git a/src/core/lib/iomgr/sockaddr_windows.h b/src/core/lib/iomgr/sockaddr_windows.h
index 20e37c9..4d63725 100644
--- a/src/core/lib/iomgr/sockaddr_windows.h
+++ b/src/core/lib/iomgr/sockaddr_windows.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_SOCKADDR_WINDOWS_H
 #define GRPC_CORE_LIB_IOMGR_SOCKADDR_WINDOWS_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_WINSOCK_SOCKET
@@ -29,6 +31,25 @@
 // must be included after the above
 #include <mswsock.h>
 
+typedef struct sockaddr grpc_sockaddr;
+typedef struct sockaddr_in grpc_sockaddr_in;
+typedef struct in_addr grpc_in_addr;
+typedef struct sockaddr_in6 grpc_sockaddr_in6;
+typedef struct in6_addr grpc_in6_addr;
+
+#define GRPC_INET_ADDRSTRLEN INET_ADDRSTRLEN
+#define GRPC_INET6_ADDRSTRLEN INET6_ADDRSTRLEN
+
+#define GRPC_SOCK_STREAM SOCK_STREAM
+#define GRPC_SOCK_DGRAM SOCK_DGRAM
+
+#define GRPC_AF_UNSPEC AF_UNSPEC
+#define GRPC_AF_UNIX AF_UNIX
+#define GRPC_AF_INET AF_INET
+#define GRPC_AF_INET6 AF_INET6
+
+#define GRPC_AI_PASSIVE AI_PASSIVE
+
 #endif
 
 #endif /* GRPC_CORE_LIB_IOMGR_SOCKADDR_WINDOWS_H */
diff --git a/src/core/lib/iomgr/socket_factory_posix.cc b/src/core/lib/iomgr/socket_factory_posix.cc
index bc7d0b1..1d1e36c 100644
--- a/src/core/lib/iomgr/socket_factory_posix.cc
+++ b/src/core/lib/iomgr/socket_factory_posix.cc
@@ -16,16 +16,18 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_POSIX_SOCKET
 
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/socket_factory_posix.h"
 
 #include <grpc/impl/codegen/grpc_types.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/useful.h>
 
 void grpc_socket_factory_init(grpc_socket_factory* factory,
                               const grpc_socket_factory_vtable* vtable) {
@@ -69,16 +71,16 @@
 }
 
 static void* socket_factory_arg_copy(void* p) {
-  return grpc_socket_factory_ref((grpc_socket_factory*)p);
+  return grpc_socket_factory_ref(static_cast<grpc_socket_factory*>(p));
 }
 
 static void socket_factory_arg_destroy(void* p) {
-  grpc_socket_factory_unref((grpc_socket_factory*)p);
+  grpc_socket_factory_unref(static_cast<grpc_socket_factory*>(p));
 }
 
 static int socket_factory_cmp(void* a, void* b) {
-  return grpc_socket_factory_compare((grpc_socket_factory*)a,
-                                     (grpc_socket_factory*)b);
+  return grpc_socket_factory_compare(static_cast<grpc_socket_factory*>(a),
+                                     static_cast<grpc_socket_factory*>(b));
 }
 
 static const grpc_arg_pointer_vtable socket_factory_arg_vtable = {
diff --git a/src/core/lib/iomgr/socket_factory_posix.h b/src/core/lib/iomgr/socket_factory_posix.h
index af57cc5..9a52f4e 100644
--- a/src/core/lib/iomgr/socket_factory_posix.h
+++ b/src/core/lib/iomgr/socket_factory_posix.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_SOCKET_FACTORY_POSIX_H
 #define GRPC_CORE_LIB_IOMGR_SOCKET_FACTORY_POSIX_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/grpc_types.h>
 #include <grpc/support/sync.h>
 #include "src/core/lib/iomgr/resolve_address.h"
diff --git a/src/core/lib/iomgr/socket_mutator.cc b/src/core/lib/iomgr/socket_mutator.cc
index 9d30e46..b9b8eaf 100644
--- a/src/core/lib/iomgr/socket_mutator.cc
+++ b/src/core/lib/iomgr/socket_mutator.cc
@@ -16,13 +16,15 @@
  *
  */
 
-#include "src/core/lib/iomgr/socket_mutator.h"
+#include <grpc/support/port_platform.h>
 
-#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/socket_mutator.h"
 
 #include <grpc/impl/codegen/grpc_types.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/useful.h"
 
 void grpc_socket_mutator_init(grpc_socket_mutator* mutator,
                               const grpc_socket_mutator_vtable* vtable) {
@@ -60,16 +62,16 @@
 }
 
 static void* socket_mutator_arg_copy(void* p) {
-  return grpc_socket_mutator_ref((grpc_socket_mutator*)p);
+  return grpc_socket_mutator_ref(static_cast<grpc_socket_mutator*>(p));
 }
 
 static void socket_mutator_arg_destroy(void* p) {
-  grpc_socket_mutator_unref((grpc_socket_mutator*)p);
+  grpc_socket_mutator_unref(static_cast<grpc_socket_mutator*>(p));
 }
 
 static int socket_mutator_cmp(void* a, void* b) {
-  return grpc_socket_mutator_compare((grpc_socket_mutator*)a,
-                                     (grpc_socket_mutator*)b);
+  return grpc_socket_mutator_compare(static_cast<grpc_socket_mutator*>(a),
+                                     static_cast<grpc_socket_mutator*>(b));
 }
 
 static const grpc_arg_pointer_vtable socket_mutator_arg_vtable = {
diff --git a/src/core/lib/iomgr/socket_mutator.h b/src/core/lib/iomgr/socket_mutator.h
index f8fd21d..6c7781c 100644
--- a/src/core/lib/iomgr/socket_mutator.h
+++ b/src/core/lib/iomgr/socket_mutator.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_SOCKET_MUTATOR_H
 #define GRPC_CORE_LIB_IOMGR_SOCKET_MUTATOR_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/grpc_types.h>
 #include <grpc/support/sync.h>
 
diff --git a/src/core/lib/iomgr/socket_utils.h b/src/core/lib/iomgr/socket_utils.h
index 9fd141b..cf1a7be 100644
--- a/src/core/lib/iomgr/socket_utils.h
+++ b/src/core/lib/iomgr/socket_utils.h
@@ -19,8 +19,19 @@
 #ifndef GRPC_CORE_LIB_IOMGR_SOCKET_UTILS_H
 #define GRPC_CORE_LIB_IOMGR_SOCKET_UTILS_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stddef.h>
 
+/* A wrapper for htons on POSIX and Windows */
+uint16_t grpc_htons(uint16_t hostshort);
+
+/* A wrapper for ntohs on POSIX and WINDOWS */
+uint16_t grpc_ntohs(uint16_t netshort);
+
+/* A wrapper for inet_pton on POSIX and WINDOWS */
+int grpc_inet_pton(int af, const char* src, void* dst);
+
 /* A wrapper for inet_ntop on POSIX systems and InetNtop on Windows systems */
 const char* grpc_inet_ntop(int af, const void* src, char* dst, size_t size);
 
diff --git a/src/core/lib/iomgr/socket_utils_common_posix.cc b/src/core/lib/iomgr/socket_utils_common_posix.cc
index 5068a80..c52e237 100644
--- a/src/core/lib/iomgr/socket_utils_common_posix.cc
+++ b/src/core/lib/iomgr/socket_utils_common_posix.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_POSIX_SOCKET
@@ -36,11 +38,12 @@
 #include <unistd.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
 #include <grpc/support/sync.h>
+
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
 
 /* set a socket to non blocking mode */
@@ -213,11 +216,11 @@
   if (fd < 0) {
     gpr_log(GPR_INFO, "Disabling AF_INET6 sockets because socket() failed.");
   } else {
-    struct sockaddr_in6 addr;
+    grpc_sockaddr_in6 addr;
     memset(&addr, 0, sizeof(addr));
     addr.sin6_family = AF_INET6;
     addr.sin6_addr.s6_addr[15] = 1; /* [::1]:0 */
-    if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
+    if (bind(fd, reinterpret_cast<grpc_sockaddr*>(&addr), sizeof(addr)) == 0) {
       g_ipv6_loopback_available = 1;
     } else {
       gpr_log(GPR_INFO,
@@ -277,7 +280,8 @@
 grpc_error* grpc_create_dualstack_socket_using_factory(
     grpc_socket_factory* factory, const grpc_resolved_address* resolved_addr,
     int type, int protocol, grpc_dualstack_mode* dsmode, int* newfd) {
-  const struct sockaddr* addr = (const struct sockaddr*)resolved_addr->addr;
+  const grpc_sockaddr* addr =
+      reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
   int family = addr->sa_family;
   if (family == AF_INET6) {
     if (grpc_ipv6_loopback_available()) {
@@ -307,9 +311,17 @@
   return error_for_fd(*newfd, resolved_addr);
 }
 
+uint16_t grpc_htons(uint16_t hostshort) { return htons(hostshort); }
+
+uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); }
+
+int grpc_inet_pton(int af, const char* src, void* dst) {
+  return inet_pton(af, src, dst);
+}
+
 const char* grpc_inet_ntop(int af, const void* src, char* dst, size_t size) {
   GPR_ASSERT(size <= (socklen_t)-1);
-  return inet_ntop(af, src, dst, (socklen_t)size);
+  return inet_ntop(af, src, dst, static_cast<socklen_t>(size));
 }
 
 #endif
diff --git a/src/core/lib/iomgr/socket_utils_linux.cc b/src/core/lib/iomgr/socket_utils_linux.cc
index 12199c5..f506329 100644
--- a/src/core/lib/iomgr/socket_utils_linux.cc
+++ b/src/core/lib/iomgr/socket_utils_linux.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_LINUX_SOCKETUTILS
@@ -35,8 +37,8 @@
   GPR_ASSERT(resolved_addr->len <= (socklen_t)-1);
   flags |= nonblock ? SOCK_NONBLOCK : 0;
   flags |= cloexec ? SOCK_CLOEXEC : 0;
-  return accept4(sockfd, (struct sockaddr*)resolved_addr->addr,
-                 (socklen_t*)&resolved_addr->len, flags);
+  return accept4(sockfd, reinterpret_cast<grpc_sockaddr*>(resolved_addr->addr),
+                 &resolved_addr->len, flags);
 }
 
 #endif
diff --git a/src/core/lib/iomgr/socket_utils_posix.cc b/src/core/lib/iomgr/socket_utils_posix.cc
index c49cbb2..d5d00af 100644
--- a/src/core/lib/iomgr/socket_utils_posix.cc
+++ b/src/core/lib/iomgr/socket_utils_posix.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_POSIX_SOCKETUTILS
@@ -34,7 +36,7 @@
   int fd, flags;
   GPR_ASSERT(sizeof(socklen_t) <= sizeof(size_t));
   GPR_ASSERT(resolved_addr->len <= (socklen_t)-1);
-  fd = accept(sockfd, (struct sockaddr*)resolved_addr->addr,
+  fd = accept(sockfd, (grpc_sockaddr*)resolved_addr->addr,
               (socklen_t*)&resolved_addr->len);
   if (fd >= 0) {
     if (nonblock) {
diff --git a/src/core/lib/iomgr/socket_utils_posix.h b/src/core/lib/iomgr/socket_utils_posix.h
index 77df420..1f50e8d 100644
--- a/src/core/lib/iomgr/socket_utils_posix.h
+++ b/src/core/lib/iomgr/socket_utils_posix.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_SOCKET_UTILS_POSIX_H
 #define GRPC_CORE_LIB_IOMGR_SOCKET_UTILS_POSIX_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/resolve_address.h"
 
 #include <sys/socket.h>
diff --git a/src/core/lib/iomgr/socket_utils_uv.cc b/src/core/lib/iomgr/socket_utils_uv.cc
index 75316d8..8538abc 100644
--- a/src/core/lib/iomgr/socket_utils_uv.cc
+++ b/src/core/lib/iomgr/socket_utils_uv.cc
@@ -16,19 +16,30 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_UV
 
-#include <uv.h>
-
+#include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/iomgr/socket_utils.h"
 
 #include <grpc/support/log.h>
 
+#include <uv.h>
+
+uint16_t grpc_htons(uint16_t hostshort) { return htons(hostshort); }
+
+uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); }
+
+int grpc_inet_pton(int af, const char* src, void* dst) {
+  return inet_pton(af, src, dst);
+}
+
 const char* grpc_inet_ntop(int af, const void* src, char* dst, size_t size) {
-  uv_inet_ntop(af, src, dst, size);
-  return dst;
+  /* Windows InetNtopA wants a mutable ip pointer */
+  return inet_ntop(af, src, dst, (socklen_t)size);
 }
 
 #endif /* GRPC_UV */
diff --git a/src/core/lib/iomgr/socket_utils_windows.cc b/src/core/lib/iomgr/socket_utils_windows.cc
index 0482a17..3e7b5b8 100644
--- a/src/core/lib/iomgr/socket_utils_windows.cc
+++ b/src/core/lib/iomgr/socket_utils_windows.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_WINDOWS_SOCKETUTILS
@@ -25,6 +27,14 @@
 
 #include <grpc/support/log.h>
 
+uint16_t grpc_htons(uint16_t hostshort) { return htons(hostshort); }
+
+uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); }
+
+int grpc_inet_pton(int af, const char* src, void* dst) {
+  return inet_pton(af, src, dst);
+}
+
 const char* grpc_inet_ntop(int af, const void* src, char* dst, size_t size) {
   /* Windows InetNtopA wants a mutable ip pointer */
   return InetNtopA(af, (void*)src, dst, size);
diff --git a/src/core/lib/iomgr/socket_windows.cc b/src/core/lib/iomgr/socket_windows.cc
index 9bb6a75..2e23409 100644
--- a/src/core/lib/iomgr/socket_windows.cc
+++ b/src/core/lib/iomgr/socket_windows.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_WINSOCK_SOCKET
diff --git a/src/core/lib/iomgr/socket_windows.h b/src/core/lib/iomgr/socket_windows.h
index cb28f2b..7bd01ed 100644
--- a/src/core/lib/iomgr/socket_windows.h
+++ b/src/core/lib/iomgr/socket_windows.h
@@ -20,6 +20,7 @@
 #define GRPC_CORE_LIB_IOMGR_SOCKET_WINDOWS_H
 
 #include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_WINSOCK_SOCKET
@@ -28,7 +29,7 @@
 #include <grpc/support/atm.h>
 #include <grpc/support/sync.h>
 
-#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/closure.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 
 /* This holds the data for an outstanding read or write on a socket.
diff --git a/src/core/lib/iomgr/sys_epoll_wrapper.h b/src/core/lib/iomgr/sys_epoll_wrapper.h
index 3fa5357..d21d853 100644
--- a/src/core/lib/iomgr/sys_epoll_wrapper.h
+++ b/src/core/lib/iomgr/sys_epoll_wrapper.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_SYS_EPOLL_WRAPPER_H
 #define GRPC_CORE_LIB_IOMGR_SYS_EPOLL_WRAPPER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <sys/epoll.h>
 
 #ifndef EPOLLEXCLUSIVE
diff --git a/src/core/lib/iomgr/tcp_client.cc b/src/core/lib/iomgr/tcp_client.cc
new file mode 100644
index 0000000..6c0ba40
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_client.cc
@@ -0,0 +1,36 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/tcp_client.h"
+
+grpc_tcp_client_vtable* grpc_tcp_client_impl;
+
+void grpc_tcp_client_connect(grpc_closure* closure, grpc_endpoint** ep,
+                             grpc_pollset_set* interested_parties,
+                             const grpc_channel_args* channel_args,
+                             const grpc_resolved_address* addr,
+                             grpc_millis deadline) {
+  grpc_tcp_client_impl->connect(closure, ep, interested_parties, channel_args,
+                                addr, deadline);
+}
+
+void grpc_set_tcp_client_impl(grpc_tcp_client_vtable* impl) {
+  grpc_tcp_client_impl = impl;
+}
diff --git a/src/core/lib/iomgr/tcp_client.h b/src/core/lib/iomgr/tcp_client.h
index 5f55d30..d209eeb 100644
--- a/src/core/lib/iomgr/tcp_client.h
+++ b/src/core/lib/iomgr/tcp_client.h
@@ -19,12 +19,21 @@
 #ifndef GRPC_CORE_LIB_IOMGR_TCP_CLIENT_H
 #define GRPC_CORE_LIB_IOMGR_TCP_CLIENT_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/impl/codegen/grpc_types.h>
 #include <grpc/support/time.h>
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/pollset_set.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 
+typedef struct grpc_tcp_client_vtable {
+  void (*connect)(grpc_closure* on_connect, grpc_endpoint** endpoint,
+                  grpc_pollset_set* interested_parties,
+                  const grpc_channel_args* channel_args,
+                  const grpc_resolved_address* addr, grpc_millis deadline);
+} grpc_tcp_client_vtable;
+
 /* Asynchronously connect to an address (specified as (addr, len)), and call
    cb with arg and the completed connection when done (or call cb with arg and
    NULL on failure).
@@ -36,4 +45,8 @@
                              const grpc_resolved_address* addr,
                              grpc_millis deadline);
 
+void grpc_tcp_client_global_init();
+
+void grpc_set_tcp_client_impl(grpc_tcp_client_vtable* impl);
+
 #endif /* GRPC_CORE_LIB_IOMGR_TCP_CLIENT_H */
diff --git a/src/core/lib/iomgr/tcp_client_custom.cc b/src/core/lib/iomgr/tcp_client_custom.cc
new file mode 100644
index 0000000..55632a5
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_client_custom.cc
@@ -0,0 +1,151 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/iomgr/iomgr_custom.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/iomgr/tcp_client.h"
+#include "src/core/lib/iomgr/tcp_custom.h"
+#include "src/core/lib/iomgr/timer.h"
+
+extern grpc_core::TraceFlag grpc_tcp_trace;
+extern grpc_socket_vtable* grpc_custom_socket_vtable;
+
+struct grpc_custom_tcp_connect {
+  grpc_custom_socket* socket;
+  grpc_timer alarm;
+  grpc_closure on_alarm;
+  grpc_closure* closure;
+  grpc_endpoint** endpoint;
+  int refs;
+  char* addr_name;
+  grpc_resource_quota* resource_quota;
+};
+
+static void custom_tcp_connect_cleanup(grpc_custom_tcp_connect* connect) {
+  grpc_custom_socket* socket = connect->socket;
+  grpc_resource_quota_unref_internal(connect->resource_quota);
+  gpr_free(connect->addr_name);
+  gpr_free(connect);
+  socket->refs--;
+  if (socket->refs == 0) {
+    grpc_custom_socket_vtable->destroy(socket);
+    gpr_free(socket);
+  }
+}
+
+static void custom_close_callback(grpc_custom_socket* socket) {}
+
+static void on_alarm(void* acp, grpc_error* error) {
+  int done;
+  grpc_custom_socket* socket = (grpc_custom_socket*)acp;
+  grpc_custom_tcp_connect* connect = socket->connector;
+  if (grpc_tcp_trace.enabled()) {
+    const char* str = grpc_error_string(error);
+    gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_alarm: error=%s",
+            connect->addr_name, str);
+  }
+  if (error == GRPC_ERROR_NONE) {
+    /* error == NONE implies that the timer ran out, and wasn't cancelled. If
+       it was cancelled, then the handler that cancelled it also should close
+       the handle, if applicable */
+    grpc_custom_socket_vtable->close(socket, custom_close_callback);
+  }
+  done = (--connect->refs == 0);
+  if (done) {
+    custom_tcp_connect_cleanup(connect);
+  }
+}
+
+static void custom_connect_callback(grpc_custom_socket* socket,
+                                    grpc_error* error) {
+  grpc_core::ExecCtx exec_ctx;
+  grpc_custom_tcp_connect* connect = socket->connector;
+  int done;
+  grpc_closure* closure = connect->closure;
+  grpc_timer_cancel(&connect->alarm);
+  if (error == GRPC_ERROR_NONE) {
+    *connect->endpoint = custom_tcp_endpoint_create(
+        socket, connect->resource_quota, connect->addr_name);
+  }
+  done = (--connect->refs == 0);
+  if (done) {
+    grpc_core::ExecCtx::Get()->Flush();
+    custom_tcp_connect_cleanup(connect);
+  }
+  GRPC_CLOSURE_SCHED(closure, error);
+}
+
+static void tcp_connect(grpc_closure* closure, grpc_endpoint** ep,
+                        grpc_pollset_set* interested_parties,
+                        const grpc_channel_args* channel_args,
+                        const grpc_resolved_address* resolved_addr,
+                        grpc_millis deadline) {
+  GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+  (void)channel_args;
+  (void)interested_parties;
+  grpc_custom_tcp_connect* connect;
+  grpc_resource_quota* resource_quota = grpc_resource_quota_create(nullptr);
+  if (channel_args != nullptr) {
+    for (size_t i = 0; i < channel_args->num_args; i++) {
+      if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
+        grpc_resource_quota_unref_internal(resource_quota);
+        resource_quota = grpc_resource_quota_ref_internal(
+            (grpc_resource_quota*)channel_args->args[i].value.pointer.p);
+      }
+    }
+  }
+  grpc_custom_socket* socket =
+      (grpc_custom_socket*)gpr_malloc(sizeof(grpc_custom_socket));
+  socket->refs = 2;
+  grpc_custom_socket_vtable->init(socket, GRPC_AF_UNSPEC);
+  connect =
+      (grpc_custom_tcp_connect*)gpr_malloc(sizeof(grpc_custom_tcp_connect));
+  connect->closure = closure;
+  connect->endpoint = ep;
+  connect->addr_name = grpc_sockaddr_to_uri(resolved_addr);
+  connect->resource_quota = resource_quota;
+  connect->socket = socket;
+  socket->connector = connect;
+  socket->endpoint = nullptr;
+  socket->listener = nullptr;
+  connect->refs = 2;
+
+  if (grpc_tcp_trace.enabled()) {
+    gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %p %s: asynchronously connecting",
+            socket, connect->addr_name);
+  }
+
+  grpc_custom_socket_vtable->connect(
+      socket, (const grpc_sockaddr*)resolved_addr->addr, resolved_addr->len,
+      custom_connect_callback);
+  GRPC_CLOSURE_INIT(&connect->on_alarm, on_alarm, socket,
+                    grpc_schedule_on_exec_ctx);
+  grpc_timer_init(&connect->alarm, deadline, &connect->on_alarm);
+}
+
+grpc_tcp_client_vtable custom_tcp_client_vtable = {tcp_connect};
diff --git a/src/core/lib/iomgr/tcp_client_posix.cc b/src/core/lib/iomgr/tcp_client_posix.cc
index 3dff624..9f19b83 100644
--- a/src/core/lib/iomgr/tcp_client_posix.cc
+++ b/src/core/lib/iomgr/tcp_client_posix.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_POSIX_SOCKET
@@ -36,6 +38,7 @@
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/iomgr_posix.h"
+#include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/socket_mutator.h"
 #include "src/core/lib/iomgr/socket_utils_posix.h"
@@ -79,8 +82,8 @@
     for (size_t i = 0; i < channel_args->num_args; i++) {
       if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_SOCKET_MUTATOR)) {
         GPR_ASSERT(channel_args->args[i].type == GRPC_ARG_POINTER);
-        grpc_socket_mutator* mutator =
-            (grpc_socket_mutator*)channel_args->args[i].value.pointer.p;
+        grpc_socket_mutator* mutator = static_cast<grpc_socket_mutator*>(
+            channel_args->args[i].value.pointer.p);
         err = grpc_set_socket_with_mutator(fd, mutator);
         if (err != GRPC_ERROR_NONE) goto error;
       }
@@ -98,7 +101,7 @@
 
 static void tc_on_alarm(void* acp, grpc_error* error) {
   int done;
-  async_connect* ac = (async_connect*)acp;
+  async_connect* ac = static_cast<async_connect*>(acp);
   if (grpc_tcp_trace.enabled()) {
     const char* str = grpc_error_string(error);
     gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_alarm: error=%s", ac->addr_str,
@@ -125,7 +128,7 @@
 }
 
 static void on_writable(void* acp, grpc_error* error) {
-  async_connect* ac = (async_connect*)acp;
+  async_connect* ac = static_cast<async_connect*>(acp);
   int so_error = 0;
   socklen_t so_error_size;
   int err;
@@ -290,8 +293,8 @@
   int err;
   async_connect* ac;
   do {
-    GPR_ASSERT(addr->len < ~(socklen_t)0);
-    err = connect(fd, (const struct sockaddr*)addr->addr, (socklen_t)addr->len);
+    err = connect(fd, reinterpret_cast<const grpc_sockaddr*>(addr->addr),
+                  addr->len);
   } while (err < 0 && errno == EINTR);
   if (err >= 0) {
     char* addr_str = grpc_sockaddr_to_uri(addr);
@@ -309,7 +312,7 @@
 
   grpc_pollset_set_add_fd(interested_parties, fdobj);
 
-  ac = (async_connect*)gpr_malloc(sizeof(async_connect));
+  ac = static_cast<async_connect*>(gpr_malloc(sizeof(async_connect)));
   ac->closure = closure;
   ac->ep = ep;
   ac->fd = fdobj;
@@ -333,11 +336,11 @@
   gpr_mu_unlock(&ac->mu);
 }
 
-static void tcp_client_connect_impl(grpc_closure* closure, grpc_endpoint** ep,
-                                    grpc_pollset_set* interested_parties,
-                                    const grpc_channel_args* channel_args,
-                                    const grpc_resolved_address* addr,
-                                    grpc_millis deadline) {
+static void tcp_connect(grpc_closure* closure, grpc_endpoint** ep,
+                        grpc_pollset_set* interested_parties,
+                        const grpc_channel_args* channel_args,
+                        const grpc_resolved_address* addr,
+                        grpc_millis deadline) {
   grpc_resolved_address mapped_addr;
   grpc_fd* fdobj = nullptr;
   grpc_error* error;
@@ -352,20 +355,5 @@
                                           ep);
 }
 
-// overridden by api_fuzzer.c
-void (*grpc_tcp_client_connect_impl)(
-    grpc_closure* closure, grpc_endpoint** ep,
-    grpc_pollset_set* interested_parties, const grpc_channel_args* channel_args,
-    const grpc_resolved_address* addr,
-    grpc_millis deadline) = tcp_client_connect_impl;
-
-void grpc_tcp_client_connect(grpc_closure* closure, grpc_endpoint** ep,
-                             grpc_pollset_set* interested_parties,
-                             const grpc_channel_args* channel_args,
-                             const grpc_resolved_address* addr,
-                             grpc_millis deadline) {
-  grpc_tcp_client_connect_impl(closure, ep, interested_parties, channel_args,
-                               addr, deadline);
-}
-
+grpc_tcp_client_vtable grpc_posix_tcp_client_vtable = {tcp_connect};
 #endif
diff --git a/src/core/lib/iomgr/tcp_client_posix.h b/src/core/lib/iomgr/tcp_client_posix.h
index 57e50a6..d0168ef 100644
--- a/src/core/lib/iomgr/tcp_client_posix.h
+++ b/src/core/lib/iomgr/tcp_client_posix.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_TCP_CLIENT_POSIX_H
 #define GRPC_CORE_LIB_IOMGR_TCP_CLIENT_POSIX_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/tcp_client.h"
diff --git a/src/core/lib/iomgr/tcp_client_uv.cc b/src/core/lib/iomgr/tcp_client_uv.cc
deleted file mode 100644
index 4e9c7cc..0000000
--- a/src/core/lib/iomgr/tcp_client_uv.cc
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- *
- * Copyright 2016 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "src/core/lib/iomgr/port.h"
-
-#ifdef GRPC_UV
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-#include "src/core/lib/iomgr/error.h"
-#include "src/core/lib/iomgr/iomgr_uv.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
-#include "src/core/lib/iomgr/tcp_client.h"
-#include "src/core/lib/iomgr/tcp_uv.h"
-#include "src/core/lib/iomgr/timer.h"
-
-extern grpc_core::TraceFlag grpc_tcp_trace;
-
-typedef struct grpc_uv_tcp_connect {
-  uv_connect_t connect_req;
-  grpc_timer alarm;
-  grpc_closure on_alarm;
-  uv_tcp_t* tcp_handle;
-  grpc_closure* closure;
-  grpc_endpoint** endpoint;
-  int refs;
-  char* addr_name;
-  grpc_resource_quota* resource_quota;
-} grpc_uv_tcp_connect;
-
-static void uv_tcp_connect_cleanup(grpc_uv_tcp_connect* connect) {
-  grpc_resource_quota_unref_internal(connect->resource_quota);
-  gpr_free(connect->addr_name);
-  gpr_free(connect);
-}
-
-static void tcp_close_callback(uv_handle_t* handle) { gpr_free(handle); }
-
-static void uv_tc_on_alarm(void* acp, grpc_error* error) {
-  int done;
-  grpc_uv_tcp_connect* connect = (grpc_uv_tcp_connect*)acp;
-  if (grpc_tcp_trace.enabled()) {
-    const char* str = grpc_error_string(error);
-    gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_alarm: error=%s",
-            connect->addr_name, str);
-  }
-  if (error == GRPC_ERROR_NONE) {
-    /* error == NONE implies that the timer ran out, and wasn't cancelled. If
-       it was cancelled, then the handler that cancelled it also should close
-       the handle, if applicable */
-    uv_close((uv_handle_t*)connect->tcp_handle, tcp_close_callback);
-  }
-  done = (--connect->refs == 0);
-  if (done) {
-    uv_tcp_connect_cleanup(connect);
-  }
-}
-
-static void uv_tc_on_connect(uv_connect_t* req, int status) {
-  grpc_uv_tcp_connect* connect = (grpc_uv_tcp_connect*)req->data;
-  grpc_core::ExecCtx exec_ctx;
-  grpc_error* error = GRPC_ERROR_NONE;
-  int done;
-  grpc_closure* closure = connect->closure;
-  grpc_timer_cancel(&connect->alarm);
-  if (status == 0) {
-    *connect->endpoint = grpc_tcp_create(
-        connect->tcp_handle, connect->resource_quota, connect->addr_name);
-  } else {
-    error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-        "Failed to connect to remote host");
-    error = grpc_error_set_int(error, GRPC_ERROR_INT_ERRNO, -status);
-    error =
-        grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
-                           grpc_slice_from_static_string(uv_strerror(status)));
-    if (status == UV_ECANCELED) {
-      error =
-          grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
-                             grpc_slice_from_static_string("Timeout occurred"));
-      // This should only happen if the handle is already closed
-    } else {
-      error = grpc_error_set_str(
-          error, GRPC_ERROR_STR_OS_ERROR,
-          grpc_slice_from_static_string(uv_strerror(status)));
-      uv_close((uv_handle_t*)connect->tcp_handle, tcp_close_callback);
-    }
-  }
-  done = (--connect->refs == 0);
-  if (done) {
-    grpc_core::ExecCtx::Get()->Flush();
-    uv_tcp_connect_cleanup(connect);
-  }
-  GRPC_CLOSURE_SCHED(closure, error);
-}
-
-static void tcp_client_connect_impl(grpc_closure* closure, grpc_endpoint** ep,
-                                    grpc_pollset_set* interested_parties,
-                                    const grpc_channel_args* channel_args,
-                                    const grpc_resolved_address* resolved_addr,
-                                    grpc_millis deadline) {
-  grpc_uv_tcp_connect* connect;
-  grpc_resource_quota* resource_quota = grpc_resource_quota_create(NULL);
-  (void)channel_args;
-  (void)interested_parties;
-
-  GRPC_UV_ASSERT_SAME_THREAD();
-
-  if (channel_args != NULL) {
-    for (size_t i = 0; i < channel_args->num_args; i++) {
-      if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
-        grpc_resource_quota_unref_internal(resource_quota);
-        resource_quota = grpc_resource_quota_ref_internal(
-            (grpc_resource_quota*)channel_args->args[i].value.pointer.p);
-      }
-    }
-  }
-
-  connect = (grpc_uv_tcp_connect*)gpr_zalloc(sizeof(grpc_uv_tcp_connect));
-  connect->closure = closure;
-  connect->endpoint = ep;
-  connect->tcp_handle = (uv_tcp_t*)gpr_malloc(sizeof(uv_tcp_t));
-  connect->addr_name = grpc_sockaddr_to_uri(resolved_addr);
-  connect->resource_quota = resource_quota;
-  uv_tcp_init(uv_default_loop(), connect->tcp_handle);
-  connect->connect_req.data = connect;
-  connect->refs = 2;  // One for the connect operation, one for the timer.
-
-  if (grpc_tcp_trace.enabled()) {
-    gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting",
-            connect->addr_name);
-  }
-
-  // TODO(murgatroid99): figure out what the return value here means
-  uv_tcp_connect(&connect->connect_req, connect->tcp_handle,
-                 (const struct sockaddr*)resolved_addr->addr, uv_tc_on_connect);
-  GRPC_CLOSURE_INIT(&connect->on_alarm, uv_tc_on_alarm, connect,
-                    grpc_schedule_on_exec_ctx);
-  grpc_timer_init(&connect->alarm, deadline, &connect->on_alarm);
-}
-
-// overridden by api_fuzzer.c
-void (*grpc_tcp_client_connect_impl)(
-    grpc_closure* closure, grpc_endpoint** ep,
-    grpc_pollset_set* interested_parties, const grpc_channel_args* channel_args,
-    const grpc_resolved_address* addr,
-    grpc_millis deadline) = tcp_client_connect_impl;
-
-void grpc_tcp_client_connect(grpc_closure* closure, grpc_endpoint** ep,
-                             grpc_pollset_set* interested_parties,
-                             const grpc_channel_args* channel_args,
-                             const grpc_resolved_address* addr,
-                             grpc_millis deadline) {
-  grpc_tcp_client_connect_impl(closure, ep, interested_parties, channel_args,
-                               addr, deadline);
-}
-
-#endif /* GRPC_UV */
diff --git a/src/core/lib/iomgr/tcp_client_windows.cc b/src/core/lib/iomgr/tcp_client_windows.cc
index 97aa923..e5b5502 100644
--- a/src/core/lib/iomgr/tcp_client_windows.cc
+++ b/src/core/lib/iomgr/tcp_client_windows.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #include <inttypes.h>
@@ -28,7 +30,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/log_windows.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/iocp_windows.h"
@@ -121,12 +122,11 @@
 
 /* Tries to issue one async connection, then schedules both an IOCP
    notification request for the connection, and one timeout alert. */
-static void tcp_client_connect_impl(grpc_closure* on_done,
-                                    grpc_endpoint** endpoint,
-                                    grpc_pollset_set* interested_parties,
-                                    const grpc_channel_args* channel_args,
-                                    const grpc_resolved_address* addr,
-                                    grpc_millis deadline) {
+static void tcp_connect(grpc_closure* on_done, grpc_endpoint** endpoint,
+                        grpc_pollset_set* interested_parties,
+                        const grpc_channel_args* channel_args,
+                        const grpc_resolved_address* addr,
+                        grpc_millis deadline) {
   SOCKET sock = INVALID_SOCKET;
   BOOL success;
   int status;
@@ -174,7 +174,7 @@
   grpc_sockaddr_make_wildcard6(0, &local_address);
 
   status =
-      bind(sock, (struct sockaddr*)&local_address.addr, (int)local_address.len);
+      bind(sock, (grpc_sockaddr*)&local_address.addr, (int)local_address.len);
   if (status != 0) {
     error = GRPC_WSA_ERROR(WSAGetLastError(), "bind");
     goto failure;
@@ -182,7 +182,7 @@
 
   socket = grpc_winsocket_create(sock, "client");
   info = &socket->write_info;
-  success = ConnectEx(sock, (struct sockaddr*)&addr->addr, (int)addr->len, NULL,
+  success = ConnectEx(sock, (grpc_sockaddr*)&addr->addr, (int)addr->len, NULL,
                       0, NULL, &info->overlapped);
 
   /* It wouldn't be unusual to get a success immediately. But we'll still get
@@ -226,20 +226,6 @@
   GRPC_CLOSURE_SCHED(on_done, final_error);
 }
 
-// overridden by api_fuzzer.c
-void (*grpc_tcp_client_connect_impl)(
-    grpc_closure* closure, grpc_endpoint** ep,
-    grpc_pollset_set* interested_parties, const grpc_channel_args* channel_args,
-    const grpc_resolved_address* addr,
-    grpc_millis deadline) = tcp_client_connect_impl;
-
-void grpc_tcp_client_connect(grpc_closure* closure, grpc_endpoint** ep,
-                             grpc_pollset_set* interested_parties,
-                             const grpc_channel_args* channel_args,
-                             const grpc_resolved_address* addr,
-                             grpc_millis deadline) {
-  grpc_tcp_client_connect_impl(closure, ep, interested_parties, channel_args,
-                               addr, deadline);
-}
+grpc_tcp_client_vtable grpc_windows_tcp_client_vtable = {tcp_connect};
 
 #endif /* GRPC_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/tcp_custom.cc b/src/core/lib/iomgr/tcp_custom.cc
new file mode 100644
index 0000000..2b1fc93
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_custom.cc
@@ -0,0 +1,365 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+
+#include <limits.h>
+#include <string.h>
+
+#include <grpc/slice_buffer.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/iomgr/iomgr_custom.h"
+#include "src/core/lib/iomgr/network_status_tracker.h"
+#include "src/core/lib/iomgr/resource_quota.h"
+#include "src/core/lib/iomgr/tcp_client.h"
+#include "src/core/lib/iomgr/tcp_custom.h"
+#include "src/core/lib/iomgr/tcp_server.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
+
+#define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192
+
+extern grpc_core::TraceFlag grpc_tcp_trace;
+
+grpc_socket_vtable* grpc_custom_socket_vtable = nullptr;
+extern grpc_tcp_server_vtable custom_tcp_server_vtable;
+extern grpc_tcp_client_vtable custom_tcp_client_vtable;
+
+void grpc_custom_endpoint_init(grpc_socket_vtable* impl) {
+  grpc_custom_socket_vtable = impl;
+  grpc_set_tcp_client_impl(&custom_tcp_client_vtable);
+  grpc_set_tcp_server_impl(&custom_tcp_server_vtable);
+}
+
+typedef struct {
+  grpc_endpoint base;
+  gpr_refcount refcount;
+  grpc_custom_socket* socket;
+
+  grpc_closure* read_cb;
+  grpc_closure* write_cb;
+
+  grpc_slice_buffer* read_slices;
+  grpc_slice_buffer* write_slices;
+
+  grpc_resource_user* resource_user;
+  grpc_resource_user_slice_allocator slice_allocator;
+
+  bool shutting_down;
+
+  char* peer_string;
+} custom_tcp_endpoint;
+
+static void tcp_free(grpc_custom_socket* s) {
+  custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)s->endpoint;
+  grpc_resource_user_unref(tcp->resource_user);
+  gpr_free(tcp->peer_string);
+  gpr_free(tcp);
+  s->refs--;
+  if (s->refs == 0) {
+    grpc_custom_socket_vtable->destroy(s);
+    gpr_free(s);
+  }
+}
+
+#ifndef NDEBUG
+#define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__)
+#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__)
+static void tcp_unref(custom_tcp_endpoint* tcp, const char* reason,
+                      const char* file, int line) {
+  if (grpc_tcp_trace.enabled()) {
+    gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count);
+    gpr_log(file, line, GPR_LOG_SEVERITY_ERROR,
+            "TCP unref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp->socket, reason,
+            val, val - 1);
+  }
+  if (gpr_unref(&tcp->refcount)) {
+    tcp_free(tcp->socket);
+  }
+}
+
+static void tcp_ref(custom_tcp_endpoint* tcp, const char* reason,
+                    const char* file, int line) {
+  if (grpc_tcp_trace.enabled()) {
+    gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count);
+    gpr_log(file, line, GPR_LOG_SEVERITY_ERROR,
+            "TCP   ref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp->socket, reason,
+            val, val + 1);
+  }
+  gpr_ref(&tcp->refcount);
+}
+#else
+#define TCP_UNREF(tcp, reason) tcp_unref((tcp))
+#define TCP_REF(tcp, reason) tcp_ref((tcp))
+static void tcp_unref(custom_tcp_endpoint* tcp) {
+  if (gpr_unref(&tcp->refcount)) {
+    tcp_free(tcp->socket);
+  }
+}
+
+static void tcp_ref(custom_tcp_endpoint* tcp) { gpr_ref(&tcp->refcount); }
+#endif
+
+static void call_read_cb(custom_tcp_endpoint* tcp, grpc_error* error) {
+  grpc_closure* cb = tcp->read_cb;
+  if (grpc_tcp_trace.enabled()) {
+    gpr_log(GPR_DEBUG, "TCP:%p call_cb %p %p:%p", tcp->socket, cb, cb->cb,
+            cb->cb_arg);
+    size_t i;
+    const char* str = grpc_error_string(error);
+    gpr_log(GPR_DEBUG, "read: error=%s", str);
+
+    for (i = 0; i < tcp->read_slices->count; i++) {
+      char* dump = grpc_dump_slice(tcp->read_slices->slices[i],
+                                   GPR_DUMP_HEX | GPR_DUMP_ASCII);
+      gpr_log(GPR_DEBUG, "READ %p (peer=%s): %s", tcp, tcp->peer_string, dump);
+      gpr_free(dump);
+    }
+  }
+  TCP_UNREF(tcp, "read");
+  tcp->read_slices = nullptr;
+  tcp->read_cb = nullptr;
+  GRPC_CLOSURE_RUN(cb, error);
+}
+
+static void custom_read_callback(grpc_custom_socket* socket, size_t nread,
+                                 grpc_error* error) {
+  grpc_core::ExecCtx exec_ctx;
+  grpc_slice_buffer garbage;
+  custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)socket->endpoint;
+  if (error == GRPC_ERROR_NONE && nread == 0) {
+    error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("EOF");
+  }
+  if (error == GRPC_ERROR_NONE) {
+    // Successful read
+    if ((size_t)nread < tcp->read_slices->length) {
+      /* TODO(murgatroid99): Instead of discarding the unused part of the read
+       * buffer, reuse it as the next read buffer. */
+      grpc_slice_buffer_init(&garbage);
+      grpc_slice_buffer_trim_end(
+          tcp->read_slices, tcp->read_slices->length - (size_t)nread, &garbage);
+      grpc_slice_buffer_reset_and_unref_internal(&garbage);
+    }
+  } else {
+    grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices);
+  }
+  call_read_cb(tcp, error);
+}
+
+static void tcp_read_allocation_done(void* tcpp, grpc_error* error) {
+  custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)tcpp;
+  if (grpc_tcp_trace.enabled()) {
+    gpr_log(GPR_DEBUG, "TCP:%p read_allocation_done: %s", tcp->socket,
+            grpc_error_string(error));
+  }
+  if (error == GRPC_ERROR_NONE) {
+    /* Before calling read, we allocate a buffer with exactly one slice
+     * to tcp->read_slices and wait for the callback indicating that the
+     * allocation was successful. So slices[0] should always exist here */
+    char* buffer = (char*)GRPC_SLICE_START_PTR(tcp->read_slices->slices[0]);
+    size_t len = GRPC_SLICE_LENGTH(tcp->read_slices->slices[0]);
+    grpc_custom_socket_vtable->read(tcp->socket, buffer, len,
+                                    custom_read_callback);
+  } else {
+    grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices);
+    call_read_cb(tcp, GRPC_ERROR_REF(error));
+  }
+  if (grpc_tcp_trace.enabled()) {
+    const char* str = grpc_error_string(error);
+    gpr_log(GPR_DEBUG, "Initiating read on %p: error=%s", tcp->socket, str);
+  }
+}
+
+static void endpoint_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices,
+                          grpc_closure* cb) {
+  custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep;
+  GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+  GPR_ASSERT(tcp->read_cb == nullptr);
+  tcp->read_cb = cb;
+  tcp->read_slices = read_slices;
+  grpc_slice_buffer_reset_and_unref_internal(read_slices);
+  TCP_REF(tcp, "read");
+  grpc_resource_user_alloc_slices(&tcp->slice_allocator,
+                                  GRPC_TCP_DEFAULT_READ_SLICE_SIZE, 1,
+                                  tcp->read_slices);
+}
+
+static void custom_write_callback(grpc_custom_socket* socket,
+                                  grpc_error* error) {
+  grpc_core::ExecCtx exec_ctx;
+  custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)socket->endpoint;
+  grpc_closure* cb = tcp->write_cb;
+  tcp->write_cb = nullptr;
+  if (grpc_tcp_trace.enabled()) {
+    const char* str = grpc_error_string(error);
+    gpr_log(GPR_DEBUG, "write complete on %p: error=%s", tcp->socket, str);
+  }
+  TCP_UNREF(tcp, "write");
+  GRPC_CLOSURE_SCHED(cb, error);
+}
+
+static void endpoint_write(grpc_endpoint* ep, grpc_slice_buffer* write_slices,
+                           grpc_closure* cb) {
+  custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep;
+  GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+
+  if (grpc_tcp_trace.enabled()) {
+    size_t j;
+
+    for (j = 0; j < write_slices->count; j++) {
+      char* data = grpc_dump_slice(write_slices->slices[j],
+                                   GPR_DUMP_HEX | GPR_DUMP_ASCII);
+      gpr_log(GPR_DEBUG, "WRITE %p (peer=%s): %s", tcp->socket,
+              tcp->peer_string, data);
+      gpr_free(data);
+    }
+  }
+
+  if (tcp->shutting_down) {
+    GRPC_CLOSURE_SCHED(cb, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                               "TCP socket is shutting down"));
+    return;
+  }
+
+  GPR_ASSERT(tcp->write_cb == nullptr);
+  tcp->write_slices = write_slices;
+  GPR_ASSERT(tcp->write_slices->count <= UINT_MAX);
+  if (tcp->write_slices->count == 0) {
+    // No slices means we don't have to do anything,
+    // and libuv doesn't like empty writes
+    GRPC_CLOSURE_SCHED(cb, GRPC_ERROR_NONE);
+    return;
+  }
+  tcp->write_cb = cb;
+  TCP_REF(tcp, "write");
+  grpc_custom_socket_vtable->write(tcp->socket, tcp->write_slices,
+                                   custom_write_callback);
+}
+
+static void endpoint_add_to_pollset(grpc_endpoint* ep, grpc_pollset* pollset) {
+  // No-op. We're ignoring pollsets currently
+  (void)ep;
+  (void)pollset;
+}
+
+static void endpoint_add_to_pollset_set(grpc_endpoint* ep,
+                                        grpc_pollset_set* pollset) {
+  // No-op. We're ignoring pollsets currently
+  (void)ep;
+  (void)pollset;
+}
+
+static void endpoint_delete_from_pollset_set(grpc_endpoint* ep,
+                                             grpc_pollset_set* pollset) {
+  // No-op. We're ignoring pollsets currently
+  (void)ep;
+  (void)pollset;
+}
+
+static void endpoint_shutdown(grpc_endpoint* ep, grpc_error* why) {
+  custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep;
+  if (!tcp->shutting_down) {
+    if (grpc_tcp_trace.enabled()) {
+      const char* str = grpc_error_string(why);
+      gpr_log(GPR_DEBUG, "TCP %p shutdown why=%s", tcp->socket, str);
+    }
+    tcp->shutting_down = true;
+    // GRPC_CLOSURE_SCHED(tcp->read_cb, GRPC_ERROR_REF(why));
+    // GRPC_CLOSURE_SCHED(tcp->write_cb, GRPC_ERROR_REF(why));
+    // tcp->read_cb = nullptr;
+    // tcp->write_cb = nullptr;
+    grpc_resource_user_shutdown(tcp->resource_user);
+    grpc_custom_socket_vtable->shutdown(tcp->socket);
+  }
+  GRPC_ERROR_UNREF(why);
+}
+
+static void custom_close_callback(grpc_custom_socket* socket) {
+  socket->refs--;
+  if (socket->refs == 0) {
+    grpc_custom_socket_vtable->destroy(socket);
+    gpr_free(socket);
+  } else if (socket->endpoint) {
+    grpc_core::ExecCtx exec_ctx;
+    custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)socket->endpoint;
+    TCP_UNREF(tcp, "destroy");
+  }
+}
+
+static void endpoint_destroy(grpc_endpoint* ep) {
+  grpc_network_status_unregister_endpoint(ep);
+  custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep;
+  grpc_custom_socket_vtable->close(tcp->socket, custom_close_callback);
+}
+
+static char* endpoint_get_peer(grpc_endpoint* ep) {
+  custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep;
+  return gpr_strdup(tcp->peer_string);
+}
+
+static grpc_resource_user* endpoint_get_resource_user(grpc_endpoint* ep) {
+  custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep;
+  return tcp->resource_user;
+}
+
+static int endpoint_get_fd(grpc_endpoint* ep) { return -1; }
+
+static grpc_endpoint_vtable vtable = {endpoint_read,
+                                      endpoint_write,
+                                      endpoint_add_to_pollset,
+                                      endpoint_add_to_pollset_set,
+                                      endpoint_delete_from_pollset_set,
+                                      endpoint_shutdown,
+                                      endpoint_destroy,
+                                      endpoint_get_resource_user,
+                                      endpoint_get_peer,
+                                      endpoint_get_fd};
+
+grpc_endpoint* custom_tcp_endpoint_create(grpc_custom_socket* socket,
+                                          grpc_resource_quota* resource_quota,
+                                          char* peer_string) {
+  custom_tcp_endpoint* tcp =
+      (custom_tcp_endpoint*)gpr_malloc(sizeof(custom_tcp_endpoint));
+  grpc_core::ExecCtx exec_ctx;
+
+  if (grpc_tcp_trace.enabled()) {
+    gpr_log(GPR_DEBUG, "Creating TCP endpoint %p", socket);
+  }
+  memset(tcp, 0, sizeof(custom_tcp_endpoint));
+  socket->refs++;
+  socket->endpoint = (grpc_endpoint*)tcp;
+  tcp->socket = socket;
+  tcp->base.vtable = &vtable;
+  gpr_ref_init(&tcp->refcount, 1);
+  tcp->peer_string = gpr_strdup(peer_string);
+  tcp->shutting_down = false;
+  tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string);
+  grpc_resource_user_slice_allocator_init(
+      &tcp->slice_allocator, tcp->resource_user, tcp_read_allocation_done, tcp);
+  /* Tell network status tracking code about the new endpoint */
+  grpc_network_status_register_endpoint(&tcp->base);
+
+  return &tcp->base;
+}
diff --git a/src/core/lib/iomgr/tcp_custom.h b/src/core/lib/iomgr/tcp_custom.h
new file mode 100644
index 0000000..22caa14
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_custom.h
@@ -0,0 +1,83 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_LIB_IOMGR_TCP_CUSTOM_H
+#define GRPC_CORE_LIB_IOMGR_TCP_CUSTOM_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+
+typedef struct grpc_tcp_listener grpc_tcp_listener;
+typedef struct grpc_custom_tcp_connect grpc_custom_tcp_connect;
+
+typedef struct grpc_custom_socket {
+  // Implementation defined
+  void* impl;
+  grpc_endpoint* endpoint;
+  grpc_tcp_listener* listener;
+  grpc_custom_tcp_connect* connector;
+  int refs;
+} grpc_custom_socket;
+
+typedef void (*grpc_custom_connect_callback)(grpc_custom_socket* socket,
+                                             grpc_error* error);
+typedef void (*grpc_custom_write_callback)(grpc_custom_socket* socket,
+                                           grpc_error* error);
+typedef void (*grpc_custom_read_callback)(grpc_custom_socket* socket,
+                                          size_t nread, grpc_error* error);
+typedef void (*grpc_custom_accept_callback)(grpc_custom_socket* socket,
+                                            grpc_custom_socket* client,
+                                            grpc_error* error);
+typedef void (*grpc_custom_close_callback)(grpc_custom_socket* socket);
+
+typedef struct grpc_socket_vtable {
+  grpc_error* (*init)(grpc_custom_socket* socket, int domain);
+  void (*connect)(grpc_custom_socket* socket, const grpc_sockaddr* addr,
+                  size_t len, grpc_custom_connect_callback cb);
+  void (*destroy)(grpc_custom_socket* socket);
+  void (*shutdown)(grpc_custom_socket* socket);
+  void (*close)(grpc_custom_socket* socket, grpc_custom_close_callback cb);
+  void (*write)(grpc_custom_socket* socket, grpc_slice_buffer* slices,
+                grpc_custom_write_callback cb);
+  void (*read)(grpc_custom_socket* socket, char* buffer, size_t length,
+               grpc_custom_read_callback cb);
+  grpc_error* (*getpeername)(grpc_custom_socket* socket,
+                             const grpc_sockaddr* addr, int* len);
+  grpc_error* (*getsockname)(grpc_custom_socket* socket,
+                             const grpc_sockaddr* addr, int* len);
+  grpc_error* (*setsockopt)(grpc_custom_socket* socket, int level, int optname,
+                            const void* optval, uint32_t optlen);
+  grpc_error* (*bind)(grpc_custom_socket* socket, const grpc_sockaddr* addr,
+                      size_t len, int flags);
+  grpc_error* (*listen)(grpc_custom_socket* socket);
+  void (*accept)(grpc_custom_socket* socket, grpc_custom_socket* client,
+                 grpc_custom_accept_callback cb);
+} grpc_socket_vtable;
+
+/* Internal APIs */
+void grpc_custom_endpoint_init(grpc_socket_vtable* impl);
+
+void grpc_custom_close_server_callback(grpc_tcp_listener* listener);
+
+grpc_endpoint* custom_tcp_endpoint_create(grpc_custom_socket* socket,
+                                          grpc_resource_quota* resource_quota,
+                                          char* peer_string);
+
+#endif /* GRPC_CORE_LIB_IOMGR_TCP_CUSTOM_H */
diff --git a/src/core/lib/iomgr/tcp_posix.cc b/src/core/lib/iomgr/tcp_posix.cc
index 07aed2d..205af22 100644
--- a/src/core/lib/iomgr/tcp_posix.cc
+++ b/src/core/lib/iomgr/tcp_posix.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_POSIX_SOCKET
@@ -37,12 +39,12 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/profiling/timers.h"
@@ -61,7 +63,7 @@
 typedef size_t msg_iovlen_type;
 #endif
 
-grpc_core::TraceFlag grpc_tcp_trace(false, "tcp");
+extern grpc_core::TraceFlag grpc_tcp_trace;
 
 namespace {
 struct grpc_tcp {
@@ -116,7 +118,7 @@
                                                  grpc_error* error);
 
 static void done_poller(void* bp, grpc_error* error_ignored) {
-  backup_poller* p = (backup_poller*)bp;
+  backup_poller* p = static_cast<backup_poller*>(bp);
   if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "BACKUP_POLLER:%p destroy", p);
   }
@@ -125,7 +127,7 @@
 }
 
 static void run_poller(void* bp, grpc_error* error_ignored) {
-  backup_poller* p = (backup_poller*)bp;
+  backup_poller* p = static_cast<backup_poller*>(bp);
   if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "BACKUP_POLLER:%p run", p);
   }
@@ -165,8 +167,8 @@
   gpr_atm old_count =
       gpr_atm_no_barrier_fetch_add(&g_uncovered_notifications_pending, -1);
   if (grpc_tcp_trace.enabled()) {
-    gpr_log(GPR_DEBUG, "BACKUP_POLLER:%p uncover cnt %d->%d", p, (int)old_count,
-            (int)old_count - 1);
+    gpr_log(GPR_DEBUG, "BACKUP_POLLER:%p uncover cnt %d->%d", p,
+            static_cast<int>(old_count), static_cast<int>(old_count) - 1);
   }
   GPR_ASSERT(old_count != 1);
 }
@@ -176,12 +178,13 @@
   gpr_atm old_count =
       gpr_atm_no_barrier_fetch_add(&g_uncovered_notifications_pending, 2);
   if (grpc_tcp_trace.enabled()) {
-    gpr_log(GPR_DEBUG, "BACKUP_POLLER: cover cnt %d->%d", (int)old_count,
-            2 + (int)old_count);
+    gpr_log(GPR_DEBUG, "BACKUP_POLLER: cover cnt %d->%d",
+            static_cast<int>(old_count), 2 + static_cast<int>(old_count));
   }
   if (old_count == 0) {
     GRPC_STATS_INC_TCP_BACKUP_POLLERS_CREATED();
-    p = (backup_poller*)gpr_zalloc(sizeof(*p) + grpc_pollset_size());
+    p = static_cast<backup_poller*>(
+        gpr_zalloc(sizeof(*p) + grpc_pollset_size()));
     if (grpc_tcp_trace.enabled()) {
       gpr_log(GPR_DEBUG, "BACKUP_POLLER:%p create", p);
     }
@@ -230,12 +233,12 @@
   if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "TCP:%p got_write: %s", arg, grpc_error_string(error));
   }
-  drop_uncovered((grpc_tcp*)arg);
+  drop_uncovered(static_cast<grpc_tcp*>(arg));
   tcp_handle_write(arg, error);
 }
 
 static void add_to_estimate(grpc_tcp* tcp, size_t bytes) {
-  tcp->bytes_read_this_round += (double)bytes;
+  tcp->bytes_read_this_round += static_cast<double>(bytes);
 }
 
 static void finish_estimate(grpc_tcp* tcp) {
@@ -257,10 +260,10 @@
   double pressure = grpc_resource_quota_get_memory_pressure(rq);
   double target =
       tcp->target_length * (pressure > 0.8 ? (1.0 - pressure) / 0.2 : 1.0);
-  size_t sz = (((size_t)GPR_CLAMP(target, tcp->min_read_chunk_size,
-                                  tcp->max_read_chunk_size)) +
+  size_t sz = ((static_cast<size_t> GPR_CLAMP(target, tcp->min_read_chunk_size,
+                                              tcp->max_read_chunk_size)) +
                255) &
-              ~(size_t)255;
+              ~static_cast<size_t>(255);
   /* don't use more than 1/16th of the overall resource quota for a single read
    * alloc */
   size_t rqmax = grpc_resource_quota_peek_size(rq);
@@ -285,7 +288,7 @@
 static void tcp_handle_write(void* arg /* grpc_tcp */, grpc_error* error);
 
 static void tcp_shutdown(grpc_endpoint* ep, grpc_error* why) {
-  grpc_tcp* tcp = (grpc_tcp*)ep;
+  grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
   grpc_fd_shutdown(tcp->em_fd, why);
   grpc_resource_user_shutdown(tcp->resource_user);
 }
@@ -339,7 +342,7 @@
 
 static void tcp_destroy(grpc_endpoint* ep) {
   grpc_network_status_unregister_endpoint(ep);
-  grpc_tcp* tcp = (grpc_tcp*)ep;
+  grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
   grpc_slice_buffer_reset_and_unref_internal(&tcp->last_read_buffer);
   TCP_UNREF(tcp, "destroy");
 }
@@ -385,7 +388,7 @@
   msg.msg_name = nullptr;
   msg.msg_namelen = 0;
   msg.msg_iov = iov;
-  msg.msg_iovlen = (msg_iovlen_type)tcp->incoming_buffer->count;
+  msg.msg_iovlen = static_cast<msg_iovlen_type>(tcp->incoming_buffer->count);
   msg.msg_control = nullptr;
   msg.msg_controllen = 0;
   msg.msg_flags = 0;
@@ -421,12 +424,12 @@
     TCP_UNREF(tcp, "read");
   } else {
     GRPC_STATS_INC_TCP_READ_SIZE(read_bytes);
-    add_to_estimate(tcp, (size_t)read_bytes);
+    add_to_estimate(tcp, static_cast<size_t>(read_bytes));
     GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length);
-    if ((size_t)read_bytes < tcp->incoming_buffer->length) {
+    if (static_cast<size_t>(read_bytes) < tcp->incoming_buffer->length) {
       grpc_slice_buffer_trim_end(
           tcp->incoming_buffer,
-          tcp->incoming_buffer->length - (size_t)read_bytes,
+          tcp->incoming_buffer->length - static_cast<size_t>(read_bytes),
           &tcp->last_read_buffer);
     }
     GPR_ASSERT((size_t)read_bytes == tcp->incoming_buffer->length);
@@ -436,7 +439,7 @@
 }
 
 static void tcp_read_allocation_done(void* tcpp, grpc_error* error) {
-  grpc_tcp* tcp = (grpc_tcp*)tcpp;
+  grpc_tcp* tcp = static_cast<grpc_tcp*>(tcpp);
   if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "TCP:%p read_allocation_done: %s", tcp,
             grpc_error_string(error));
@@ -469,7 +472,7 @@
 }
 
 static void tcp_handle_read(void* arg /* grpc_tcp */, grpc_error* error) {
-  grpc_tcp* tcp = (grpc_tcp*)arg;
+  grpc_tcp* tcp = static_cast<grpc_tcp*>(arg);
   GPR_ASSERT(!tcp->finished_edge);
   if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "TCP:%p got_read: %s", tcp, grpc_error_string(error));
@@ -487,7 +490,7 @@
 
 static void tcp_read(grpc_endpoint* ep, grpc_slice_buffer* incoming_buffer,
                      grpc_closure* cb) {
-  grpc_tcp* tcp = (grpc_tcp*)ep;
+  grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
   GPR_ASSERT(tcp->read_cb == nullptr);
   tcp->read_cb = cb;
   tcp->incoming_buffer = incoming_buffer;
@@ -578,7 +581,7 @@
     }
 
     GPR_ASSERT(tcp->outgoing_byte_idx == 0);
-    trailing = sending_length - (size_t)sent_length;
+    trailing = sending_length - static_cast<size_t>(sent_length);
     while (trailing > 0) {
       size_t slice_length;
 
@@ -602,7 +605,7 @@
 }
 
 static void tcp_handle_write(void* arg /* grpc_tcp */, grpc_error* error) {
-  grpc_tcp* tcp = (grpc_tcp*)arg;
+  grpc_tcp* tcp = static_cast<grpc_tcp*>(arg);
   grpc_closure* cb;
 
   if (error != GRPC_ERROR_NONE) {
@@ -634,7 +637,7 @@
 static void tcp_write(grpc_endpoint* ep, grpc_slice_buffer* buf,
                       grpc_closure* cb) {
   GPR_TIMER_SCOPE("tcp_write", 0);
-  grpc_tcp* tcp = (grpc_tcp*)ep;
+  grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
   grpc_error* error = GRPC_ERROR_NONE;
 
   if (grpc_tcp_trace.enabled()) {
@@ -678,34 +681,34 @@
 }
 
 static void tcp_add_to_pollset(grpc_endpoint* ep, grpc_pollset* pollset) {
-  grpc_tcp* tcp = (grpc_tcp*)ep;
+  grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
   grpc_pollset_add_fd(pollset, tcp->em_fd);
 }
 
 static void tcp_add_to_pollset_set(grpc_endpoint* ep,
                                    grpc_pollset_set* pollset_set) {
-  grpc_tcp* tcp = (grpc_tcp*)ep;
+  grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
   grpc_pollset_set_add_fd(pollset_set, tcp->em_fd);
 }
 
 static void tcp_delete_from_pollset_set(grpc_endpoint* ep,
                                         grpc_pollset_set* pollset_set) {
-  grpc_tcp* tcp = (grpc_tcp*)ep;
+  grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
   grpc_pollset_set_del_fd(pollset_set, tcp->em_fd);
 }
 
 static char* tcp_get_peer(grpc_endpoint* ep) {
-  grpc_tcp* tcp = (grpc_tcp*)ep;
+  grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
   return gpr_strdup(tcp->peer_string);
 }
 
 static int tcp_get_fd(grpc_endpoint* ep) {
-  grpc_tcp* tcp = (grpc_tcp*)ep;
+  grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
   return tcp->fd;
 }
 
 static grpc_resource_user* tcp_get_resource_user(grpc_endpoint* ep) {
-  grpc_tcp* tcp = (grpc_tcp*)ep;
+  grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
   return tcp->resource_user;
 }
 
@@ -733,27 +736,25 @@
     for (size_t i = 0; i < channel_args->num_args; i++) {
       if (0 ==
           strcmp(channel_args->args[i].key, GRPC_ARG_TCP_READ_CHUNK_SIZE)) {
-        grpc_integer_options options = {(int)tcp_read_chunk_size, 1,
-                                        MAX_CHUNK_SIZE};
+        grpc_integer_options options = {tcp_read_chunk_size, 1, MAX_CHUNK_SIZE};
         tcp_read_chunk_size =
             grpc_channel_arg_get_integer(&channel_args->args[i], options);
       } else if (0 == strcmp(channel_args->args[i].key,
                              GRPC_ARG_TCP_MIN_READ_CHUNK_SIZE)) {
-        grpc_integer_options options = {(int)tcp_read_chunk_size, 1,
-                                        MAX_CHUNK_SIZE};
+        grpc_integer_options options = {tcp_read_chunk_size, 1, MAX_CHUNK_SIZE};
         tcp_min_read_chunk_size =
             grpc_channel_arg_get_integer(&channel_args->args[i], options);
       } else if (0 == strcmp(channel_args->args[i].key,
                              GRPC_ARG_TCP_MAX_READ_CHUNK_SIZE)) {
-        grpc_integer_options options = {(int)tcp_read_chunk_size, 1,
-                                        MAX_CHUNK_SIZE};
+        grpc_integer_options options = {tcp_read_chunk_size, 1, MAX_CHUNK_SIZE};
         tcp_max_read_chunk_size =
             grpc_channel_arg_get_integer(&channel_args->args[i], options);
       } else if (0 ==
                  strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
         grpc_resource_quota_unref_internal(resource_quota);
-        resource_quota = grpc_resource_quota_ref_internal(
-            (grpc_resource_quota*)channel_args->args[i].value.pointer.p);
+        resource_quota =
+            grpc_resource_quota_ref_internal(static_cast<grpc_resource_quota*>(
+                channel_args->args[i].value.pointer.p));
       }
     }
   }
@@ -764,7 +765,7 @@
   tcp_read_chunk_size = GPR_CLAMP(tcp_read_chunk_size, tcp_min_read_chunk_size,
                                   tcp_max_read_chunk_size);
 
-  grpc_tcp* tcp = (grpc_tcp*)gpr_malloc(sizeof(grpc_tcp));
+  grpc_tcp* tcp = static_cast<grpc_tcp*>(gpr_malloc(sizeof(grpc_tcp)));
   tcp->base.vtable = &vtable;
   tcp->peer_string = gpr_strdup(peer_string);
   tcp->fd = grpc_fd_wrapped_fd(em_fd);
@@ -773,7 +774,7 @@
   tcp->release_fd_cb = nullptr;
   tcp->release_fd = nullptr;
   tcp->incoming_buffer = nullptr;
-  tcp->target_length = (double)tcp_read_chunk_size;
+  tcp->target_length = static_cast<double>(tcp_read_chunk_size);
   tcp->min_read_chunk_size = tcp_min_read_chunk_size;
   tcp->max_read_chunk_size = tcp_max_read_chunk_size;
   tcp->bytes_read_this_round = 0;
@@ -794,7 +795,7 @@
 }
 
 int grpc_tcp_fd(grpc_endpoint* ep) {
-  grpc_tcp* tcp = (grpc_tcp*)ep;
+  grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
   GPR_ASSERT(ep->vtable == &vtable);
   return grpc_fd_wrapped_fd(tcp->em_fd);
 }
@@ -802,7 +803,7 @@
 void grpc_tcp_destroy_and_release_fd(grpc_endpoint* ep, int* fd,
                                      grpc_closure* done) {
   grpc_network_status_unregister_endpoint(ep);
-  grpc_tcp* tcp = (grpc_tcp*)ep;
+  grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
   GPR_ASSERT(ep->vtable == &vtable);
   tcp->release_fd = fd;
   tcp->release_fd_cb = done;
diff --git a/src/core/lib/iomgr/tcp_posix.h b/src/core/lib/iomgr/tcp_posix.h
index 4529c02..af89bd2 100644
--- a/src/core/lib/iomgr/tcp_posix.h
+++ b/src/core/lib/iomgr/tcp_posix.h
@@ -29,6 +29,8 @@
    otherwise specified.
 */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/ev_posix.h"
diff --git a/src/core/lib/iomgr/tcp_server.cc b/src/core/lib/iomgr/tcp_server.cc
new file mode 100644
index 0000000..ea745f2
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_server.cc
@@ -0,0 +1,73 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/tcp_server.h"
+
+grpc_tcp_server_vtable* grpc_tcp_server_impl;
+
+grpc_error* grpc_tcp_server_create(grpc_closure* shutdown_complete,
+                                   const grpc_channel_args* args,
+                                   grpc_tcp_server** server) {
+  return grpc_tcp_server_impl->create(shutdown_complete, args, server);
+}
+
+void grpc_tcp_server_start(grpc_tcp_server* server, grpc_pollset** pollsets,
+                           size_t pollset_count,
+                           grpc_tcp_server_cb on_accept_cb, void* cb_arg) {
+  grpc_tcp_server_impl->start(server, pollsets, pollset_count, on_accept_cb,
+                              cb_arg);
+}
+
+grpc_error* grpc_tcp_server_add_port(grpc_tcp_server* s,
+                                     const grpc_resolved_address* addr,
+                                     int* out_port) {
+  return grpc_tcp_server_impl->add_port(s, addr, out_port);
+}
+
+unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server* s,
+                                       unsigned port_index) {
+  return grpc_tcp_server_impl->port_fd_count(s, port_index);
+}
+
+int grpc_tcp_server_port_fd(grpc_tcp_server* s, unsigned port_index,
+                            unsigned fd_index) {
+  return grpc_tcp_server_impl->port_fd(s, port_index, fd_index);
+}
+
+grpc_tcp_server* grpc_tcp_server_ref(grpc_tcp_server* s) {
+  return grpc_tcp_server_impl->ref(s);
+}
+
+void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server* s,
+                                           grpc_closure* shutdown_starting) {
+  grpc_tcp_server_impl->shutdown_starting_add(s, shutdown_starting);
+}
+
+void grpc_tcp_server_unref(grpc_tcp_server* s) {
+  grpc_tcp_server_impl->unref(s);
+}
+
+void grpc_tcp_server_shutdown_listeners(grpc_tcp_server* s) {
+  grpc_tcp_server_impl->shutdown_listeners(s);
+}
+
+void grpc_set_tcp_server_impl(grpc_tcp_server_vtable* impl) {
+  grpc_tcp_server_impl = impl;
+}
diff --git a/src/core/lib/iomgr/tcp_server.h b/src/core/lib/iomgr/tcp_server.h
index 038c765..8fcbb2f 100644
--- a/src/core/lib/iomgr/tcp_server.h
+++ b/src/core/lib/iomgr/tcp_server.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_TCP_SERVER_H
 #define GRPC_CORE_LIB_IOMGR_TCP_SERVER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 
 #include "src/core/lib/iomgr/closure.h"
@@ -43,6 +45,24 @@
                                    grpc_pollset* accepting_pollset,
                                    grpc_tcp_server_acceptor* acceptor);
 
+typedef struct grpc_tcp_server_vtable {
+  grpc_error* (*create)(grpc_closure* shutdown_complete,
+                        const grpc_channel_args* args,
+                        grpc_tcp_server** server);
+  void (*start)(grpc_tcp_server* server, grpc_pollset** pollsets,
+                size_t pollset_count, grpc_tcp_server_cb on_accept_cb,
+                void* cb_arg);
+  grpc_error* (*add_port)(grpc_tcp_server* s, const grpc_resolved_address* addr,
+                          int* out_port);
+  unsigned (*port_fd_count)(grpc_tcp_server* s, unsigned port_index);
+  int (*port_fd)(grpc_tcp_server* s, unsigned port_index, unsigned fd_index);
+  grpc_tcp_server* (*ref)(grpc_tcp_server* s);
+  void (*shutdown_starting_add)(grpc_tcp_server* s,
+                                grpc_closure* shutdown_starting);
+  void (*unref)(grpc_tcp_server* s);
+  void (*shutdown_listeners)(grpc_tcp_server* s);
+} grpc_tcp_server_vtable;
+
 /* Create a server, initially not bound to any ports. The caller owns one ref.
    If shutdown_complete is not NULL, it will be used by
    grpc_tcp_server_unref() when the ref count reaches zero. */
@@ -95,4 +115,8 @@
 /* Shutdown the fds of listeners. */
 void grpc_tcp_server_shutdown_listeners(grpc_tcp_server* s);
 
+void grpc_tcp_server_global_init();
+
+void grpc_set_tcp_server_impl(grpc_tcp_server_vtable* impl);
+
 #endif /* GRPC_CORE_LIB_IOMGR_TCP_SERVER_H */
diff --git a/src/core/lib/iomgr/tcp_server_custom.cc b/src/core/lib/iomgr/tcp_server_custom.cc
new file mode 100644
index 0000000..be92e61
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_server_custom.cc
@@ -0,0 +1,479 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/iomgr_custom.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/iomgr/tcp_custom.h"
+#include "src/core/lib/iomgr/tcp_server.h"
+
+extern grpc_core::TraceFlag grpc_tcp_trace;
+
+extern grpc_socket_vtable* grpc_custom_socket_vtable;
+
+/* one listening port */
+struct grpc_tcp_listener {
+  grpc_tcp_server* server;
+  unsigned port_index;
+  int port;
+
+  grpc_custom_socket* socket;
+
+  /* linked list */
+  struct grpc_tcp_listener* next;
+
+  bool closed;
+};
+
+struct grpc_tcp_server {
+  gpr_refcount refs;
+
+  /* Called whenever accept() succeeds on a server port. */
+  grpc_tcp_server_cb on_accept_cb;
+  void* on_accept_cb_arg;
+
+  int open_ports;
+
+  /* linked list of server ports */
+  grpc_tcp_listener* head;
+  grpc_tcp_listener* tail;
+
+  /* List of closures passed to shutdown_starting_add(). */
+  grpc_closure_list shutdown_starting;
+
+  /* shutdown callback */
+  grpc_closure* shutdown_complete;
+
+  bool shutdown;
+
+  grpc_resource_quota* resource_quota;
+};
+
+static grpc_error* tcp_server_create(grpc_closure* shutdown_complete,
+                                     const grpc_channel_args* args,
+                                     grpc_tcp_server** server) {
+  grpc_tcp_server* s = (grpc_tcp_server*)gpr_malloc(sizeof(grpc_tcp_server));
+  s->resource_quota = grpc_resource_quota_create(nullptr);
+  for (size_t i = 0; i < (args == nullptr ? 0 : args->num_args); i++) {
+    if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) {
+      if (args->args[i].type == GRPC_ARG_POINTER) {
+        grpc_resource_quota_unref_internal(s->resource_quota);
+        s->resource_quota = grpc_resource_quota_ref_internal(
+            (grpc_resource_quota*)args->args[i].value.pointer.p);
+      } else {
+        grpc_resource_quota_unref_internal(s->resource_quota);
+        gpr_free(s);
+        return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+            GRPC_ARG_RESOURCE_QUOTA " must be a pointer to a buffer pool");
+      }
+    }
+  }
+  gpr_ref_init(&s->refs, 1);
+  s->on_accept_cb = nullptr;
+  s->on_accept_cb_arg = nullptr;
+  s->open_ports = 0;
+  s->head = nullptr;
+  s->tail = nullptr;
+  s->shutdown_starting.head = nullptr;
+  s->shutdown_starting.tail = nullptr;
+  s->shutdown_complete = shutdown_complete;
+  s->shutdown = false;
+  *server = s;
+  return GRPC_ERROR_NONE;
+}
+
+static grpc_tcp_server* tcp_server_ref(grpc_tcp_server* s) {
+  GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+  gpr_ref(&s->refs);
+  return s;
+}
+
+static void tcp_server_shutdown_starting_add(grpc_tcp_server* s,
+                                             grpc_closure* shutdown_starting) {
+  grpc_closure_list_append(&s->shutdown_starting, shutdown_starting,
+                           GRPC_ERROR_NONE);
+}
+
+static void finish_shutdown(grpc_tcp_server* s) {
+  GPR_ASSERT(s->shutdown);
+  if (s->shutdown_complete != nullptr) {
+    GRPC_CLOSURE_SCHED(s->shutdown_complete, GRPC_ERROR_NONE);
+  }
+
+  while (s->head) {
+    grpc_tcp_listener* sp = s->head;
+    s->head = sp->next;
+    sp->next = nullptr;
+    gpr_free(sp);
+  }
+  grpc_resource_quota_unref_internal(s->resource_quota);
+  gpr_free(s);
+}
+
+static void custom_close_callback(grpc_custom_socket* socket) {
+  grpc_tcp_listener* sp = socket->listener;
+  if (sp) {
+    grpc_core::ExecCtx exec_ctx;
+    sp->server->open_ports--;
+    if (sp->server->open_ports == 0 && sp->server->shutdown) {
+      finish_shutdown(sp->server);
+    }
+  }
+  socket->refs--;
+  if (socket->refs == 0) {
+    grpc_custom_socket_vtable->destroy(socket);
+    gpr_free(socket);
+  }
+}
+
+void grpc_custom_close_server_callback(grpc_tcp_listener* sp) {
+  if (sp) {
+    grpc_core::ExecCtx exec_ctx;
+    sp->server->open_ports--;
+    if (sp->server->open_ports == 0 && sp->server->shutdown) {
+      finish_shutdown(sp->server);
+    }
+  }
+}
+
+static void close_listener(grpc_tcp_listener* sp) {
+  grpc_custom_socket* socket = sp->socket;
+  if (!sp->closed) {
+    sp->closed = true;
+    grpc_custom_socket_vtable->close(socket, custom_close_callback);
+  }
+}
+
+static void tcp_server_destroy(grpc_tcp_server* s) {
+  int immediately_done = 0;
+  grpc_tcp_listener* sp;
+
+  GPR_ASSERT(!s->shutdown);
+  s->shutdown = true;
+
+  if (s->open_ports == 0) {
+    immediately_done = 1;
+  }
+  for (sp = s->head; sp; sp = sp->next) {
+    close_listener(sp);
+  }
+
+  if (immediately_done) {
+    finish_shutdown(s);
+  }
+}
+
+static void tcp_server_unref(grpc_tcp_server* s) {
+  GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+  if (gpr_unref(&s->refs)) {
+    /* Complete shutdown_starting work before destroying. */
+    grpc_core::ExecCtx exec_ctx;
+    GRPC_CLOSURE_LIST_SCHED(&s->shutdown_starting);
+    grpc_core::ExecCtx::Get()->Flush();
+    tcp_server_destroy(s);
+  }
+}
+
+static void finish_accept(grpc_tcp_listener* sp, grpc_custom_socket* socket) {
+  grpc_tcp_server_acceptor* acceptor =
+      (grpc_tcp_server_acceptor*)gpr_malloc(sizeof(*acceptor));
+  grpc_endpoint* ep = nullptr;
+  grpc_resolved_address peer_name;
+  char* peer_name_string;
+  grpc_error* err;
+
+  peer_name_string = nullptr;
+  memset(&peer_name, 0, sizeof(grpc_resolved_address));
+  peer_name.len = GRPC_MAX_SOCKADDR_SIZE;
+  err = grpc_custom_socket_vtable->getpeername(
+      socket, (grpc_sockaddr*)&peer_name.addr, (int*)&peer_name.len);
+  if (err == GRPC_ERROR_NONE) {
+    peer_name_string = grpc_sockaddr_to_uri(&peer_name);
+  } else {
+    GRPC_LOG_IF_ERROR("getpeername error", err);
+    GRPC_ERROR_UNREF(err);
+  }
+  if (grpc_tcp_trace.enabled()) {
+    if (peer_name_string) {
+      gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p accepted connection: %s",
+              sp->server, peer_name_string);
+    } else {
+      gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p accepted connection", sp->server);
+    }
+  }
+  ep = custom_tcp_endpoint_create(socket, sp->server->resource_quota,
+                                  peer_name_string);
+  acceptor->from_server = sp->server;
+  acceptor->port_index = sp->port_index;
+  acceptor->fd_index = 0;
+  sp->server->on_accept_cb(sp->server->on_accept_cb_arg, ep, nullptr, acceptor);
+  gpr_free(peer_name_string);
+}
+
+static void custom_accept_callback(grpc_custom_socket* socket,
+                                   grpc_custom_socket* client,
+                                   grpc_error* error);
+
+static void custom_accept_callback(grpc_custom_socket* socket,
+                                   grpc_custom_socket* client,
+                                   grpc_error* error) {
+  grpc_core::ExecCtx exec_ctx;
+  grpc_tcp_listener* sp = socket->listener;
+  if (error != GRPC_ERROR_NONE) {
+    if (!sp->closed) {
+      gpr_log(GPR_ERROR, "Accept failed: %s", grpc_error_string(error));
+    }
+    gpr_free(client);
+    GRPC_ERROR_UNREF(error);
+    return;
+  }
+  finish_accept(sp, client);
+  if (!sp->closed) {
+    grpc_custom_socket* new_socket =
+        (grpc_custom_socket*)gpr_malloc(sizeof(grpc_custom_socket));
+    new_socket->endpoint = nullptr;
+    new_socket->listener = nullptr;
+    new_socket->connector = nullptr;
+    new_socket->refs = 1;
+    grpc_custom_socket_vtable->accept(sp->socket, new_socket,
+                                      custom_accept_callback);
+  }
+}
+
+static grpc_error* add_socket_to_server(grpc_tcp_server* s,
+                                        grpc_custom_socket* socket,
+                                        const grpc_resolved_address* addr,
+                                        unsigned port_index,
+                                        grpc_tcp_listener** listener) {
+  grpc_tcp_listener* sp = nullptr;
+  int port = -1;
+  grpc_error* error;
+  grpc_resolved_address sockname_temp;
+
+  // The last argument to uv_tcp_bind is flags
+  error = grpc_custom_socket_vtable->bind(socket, (grpc_sockaddr*)addr->addr,
+                                          addr->len, 0);
+  if (error != GRPC_ERROR_NONE) {
+    return error;
+  }
+
+  error = grpc_custom_socket_vtable->listen(socket);
+  if (error != GRPC_ERROR_NONE) {
+    return error;
+  }
+
+  sockname_temp.len = GRPC_MAX_SOCKADDR_SIZE;
+  error = grpc_custom_socket_vtable->getsockname(
+      socket, (grpc_sockaddr*)&sockname_temp.addr, (int*)&sockname_temp.len);
+  if (error != GRPC_ERROR_NONE) {
+    return error;
+  }
+
+  port = grpc_sockaddr_get_port(&sockname_temp);
+
+  GPR_ASSERT(port >= 0);
+  GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
+  sp = (grpc_tcp_listener*)gpr_zalloc(sizeof(grpc_tcp_listener));
+  sp->next = nullptr;
+  if (s->head == nullptr) {
+    s->head = sp;
+  } else {
+    s->tail->next = sp;
+  }
+  s->tail = sp;
+  sp->server = s;
+  sp->socket = socket;
+  sp->port = port;
+  sp->port_index = port_index;
+  sp->closed = false;
+  s->open_ports++;
+  *listener = sp;
+
+  return GRPC_ERROR_NONE;
+}
+
+static grpc_error* tcp_server_add_port(grpc_tcp_server* s,
+                                       const grpc_resolved_address* addr,
+                                       int* port) {
+  // This function is mostly copied from tcp_server_windows.c
+  grpc_tcp_listener* sp = nullptr;
+  grpc_custom_socket* socket;
+  grpc_resolved_address addr6_v4mapped;
+  grpc_resolved_address wildcard;
+  grpc_resolved_address* allocated_addr = nullptr;
+  grpc_resolved_address sockname_temp;
+  unsigned port_index = 0;
+  grpc_error* error = GRPC_ERROR_NONE;
+  int family;
+
+  GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+
+  if (s->tail != nullptr) {
+    port_index = s->tail->port_index + 1;
+  }
+
+  /* Check if this is a wildcard port, and if so, try to keep the port the same
+     as some previously created listener. */
+  if (grpc_sockaddr_get_port(addr) == 0) {
+    for (sp = s->head; sp; sp = sp->next) {
+      socket = sp->socket;
+      sockname_temp.len = GRPC_MAX_SOCKADDR_SIZE;
+      if (nullptr == grpc_custom_socket_vtable->getsockname(
+                         socket, (grpc_sockaddr*)&sockname_temp.addr,
+                         (int*)&sockname_temp.len)) {
+        *port = grpc_sockaddr_get_port(&sockname_temp);
+        if (*port > 0) {
+          allocated_addr =
+              (grpc_resolved_address*)gpr_malloc(sizeof(grpc_resolved_address));
+          memcpy(allocated_addr, addr, sizeof(grpc_resolved_address));
+          grpc_sockaddr_set_port(allocated_addr, *port);
+          addr = allocated_addr;
+          break;
+        }
+      }
+    }
+  }
+
+  if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
+    addr = &addr6_v4mapped;
+  }
+
+  /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
+  if (grpc_sockaddr_is_wildcard(addr, port)) {
+    grpc_sockaddr_make_wildcard6(*port, &wildcard);
+
+    addr = &wildcard;
+  }
+
+  if (grpc_tcp_trace.enabled()) {
+    char* port_string;
+    grpc_sockaddr_to_string(&port_string, addr, 0);
+    const char* str = grpc_error_string(error);
+    if (port_string) {
+      gpr_log(GPR_DEBUG, "SERVER %p add_port %s error=%s", s, port_string, str);
+      gpr_free(port_string);
+    } else {
+      gpr_log(GPR_DEBUG, "SERVER %p add_port error=%s", s, str);
+    }
+  }
+
+  family = grpc_sockaddr_get_family(addr);
+  socket = (grpc_custom_socket*)gpr_malloc(sizeof(grpc_custom_socket));
+  socket->refs = 1;
+  socket->endpoint = nullptr;
+  socket->listener = nullptr;
+  socket->connector = nullptr;
+  grpc_custom_socket_vtable->init(socket, family);
+
+  if (error == GRPC_ERROR_NONE) {
+#if defined(GPR_LINUX) && defined(SO_REUSEPORT)
+    if (family == AF_INET || family == AF_INET6) {
+      int enable = 1;
+      grpc_custom_socket_vtable->setsockopt(socket, SOL_SOCKET, SO_REUSEPORT,
+                                            &enable, sizeof(enable));
+    }
+#endif /* GPR_LINUX && SO_REUSEPORT */
+    error = add_socket_to_server(s, socket, addr, port_index, &sp);
+  }
+  gpr_free(allocated_addr);
+
+  if (error != GRPC_ERROR_NONE) {
+    grpc_error* error_out = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+        "Failed to add port to server", &error, 1);
+    GRPC_ERROR_UNREF(error);
+    error = error_out;
+    *port = -1;
+  } else {
+    GPR_ASSERT(sp != nullptr);
+    *port = sp->port;
+  }
+  socket->listener = sp;
+  return error;
+}
+
+static void tcp_server_start(grpc_tcp_server* server, grpc_pollset** pollsets,
+                             size_t pollset_count,
+                             grpc_tcp_server_cb on_accept_cb, void* cb_arg) {
+  grpc_tcp_listener* sp;
+  (void)pollsets;
+  (void)pollset_count;
+  GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+  if (grpc_tcp_trace.enabled()) {
+    gpr_log(GPR_DEBUG, "SERVER_START %p", server);
+  }
+  GPR_ASSERT(on_accept_cb);
+  GPR_ASSERT(!server->on_accept_cb);
+  server->on_accept_cb = on_accept_cb;
+  server->on_accept_cb_arg = cb_arg;
+  for (sp = server->head; sp; sp = sp->next) {
+    grpc_custom_socket* new_socket =
+        (grpc_custom_socket*)gpr_malloc(sizeof(grpc_custom_socket));
+    new_socket->endpoint = nullptr;
+    new_socket->listener = nullptr;
+    new_socket->connector = nullptr;
+    new_socket->refs = 1;
+    grpc_custom_socket_vtable->accept(sp->socket, new_socket,
+                                      custom_accept_callback);
+  }
+}
+
+static unsigned tcp_server_port_fd_count(grpc_tcp_server* s,
+                                         unsigned port_index) {
+  return 0;
+}
+
+static int tcp_server_port_fd(grpc_tcp_server* s, unsigned port_index,
+                              unsigned fd_index) {
+  return -1;
+}
+
+static void tcp_server_shutdown_listeners(grpc_tcp_server* s) {
+  for (grpc_tcp_listener* sp = s->head; sp; sp = sp->next) {
+    if (!sp->closed) {
+      sp->closed = true;
+      grpc_custom_socket_vtable->close(sp->socket, custom_close_callback);
+    }
+  }
+}
+
+grpc_tcp_server_vtable custom_tcp_server_vtable = {
+    tcp_server_create,
+    tcp_server_start,
+    tcp_server_add_port,
+    tcp_server_port_fd_count,
+    tcp_server_port_fd,
+    tcp_server_ref,
+    tcp_server_shutdown_starting_add,
+    tcp_server_unref,
+    tcp_server_shutdown_listeners};
+
+#ifdef GRPC_UV_TEST
+grpc_tcp_server_vtable* default_tcp_server_vtable = &custom_tcp_server_vtable;
+#endif
diff --git a/src/core/lib/iomgr/tcp_server_posix.cc b/src/core/lib/iomgr/tcp_server_posix.cc
index 2fa00a8..4e1d90e 100644
--- a/src/core/lib/iomgr/tcp_server_posix.cc
+++ b/src/core/lib/iomgr/tcp_server_posix.cc
@@ -21,6 +21,8 @@
 #define _GNU_SOURCE
 #endif
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_POSIX_SOCKET
@@ -42,7 +44,6 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
@@ -60,6 +61,11 @@
 static void init(void) {
 #ifndef GPR_MANYLINUX1
   int s = socket(AF_INET, SOCK_STREAM, 0);
+  if (s < 0) {
+    /* This might be an ipv6-only environment in which case 'socket(AF_INET,..)'
+       call would fail. Try creating IPv6 socket in that case */
+    s = socket(AF_INET6, SOCK_STREAM, 0);
+  }
   if (s >= 0) {
     has_so_reuseport = GRPC_LOG_IF_ERROR("check for SO_REUSEPORT",
                                          grpc_set_socket_reuse_port(s, 1));
@@ -68,12 +74,13 @@
 #endif
 }
 
-grpc_error* grpc_tcp_server_create(grpc_closure* shutdown_complete,
-                                   const grpc_channel_args* args,
-                                   grpc_tcp_server** server) {
+static grpc_error* tcp_server_create(grpc_closure* shutdown_complete,
+                                     const grpc_channel_args* args,
+                                     grpc_tcp_server** server) {
   gpr_once_init(&check_init, init);
 
-  grpc_tcp_server* s = (grpc_tcp_server*)gpr_zalloc(sizeof(grpc_tcp_server));
+  grpc_tcp_server* s =
+      static_cast<grpc_tcp_server*>(gpr_zalloc(sizeof(grpc_tcp_server)));
   s->so_reuseport = has_so_reuseport;
   s->expand_wildcard_addrs = false;
   for (size_t i = 0; i < (args == nullptr ? 0 : args->num_args); i++) {
@@ -136,7 +143,7 @@
 }
 
 static void destroyed_port(void* server, grpc_error* error) {
-  grpc_tcp_server* s = (grpc_tcp_server*)server;
+  grpc_tcp_server* s = static_cast<grpc_tcp_server*>(server);
   gpr_mu_lock(&s->mu);
   s->destroyed_ports++;
   if (s->destroyed_ports == s->nports) {
@@ -195,15 +202,15 @@
 
 /* event manager callback when reads are ready */
 static void on_read(void* arg, grpc_error* err) {
-  grpc_tcp_listener* sp = (grpc_tcp_listener*)arg;
+  grpc_tcp_listener* sp = static_cast<grpc_tcp_listener*>(arg);
   grpc_pollset* read_notifier_pollset;
   if (err != GRPC_ERROR_NONE) {
     goto error;
   }
 
   read_notifier_pollset =
-      sp->server->pollsets[(size_t)gpr_atm_no_barrier_fetch_add(
-                               &sp->server->next_pollset_to_assign, 1) %
+      sp->server->pollsets[static_cast<size_t>(gpr_atm_no_barrier_fetch_add(
+                               &sp->server->next_pollset_to_assign, 1)) %
                            sp->server->pollset_count];
 
   /* loop until accept4 returns EAGAIN, and then re-arm notification */
@@ -211,7 +218,8 @@
     grpc_resolved_address addr;
     char* addr_str;
     char* name;
-    addr.len = sizeof(struct sockaddr_storage);
+    memset(&addr, 0, sizeof(addr));
+    addr.len = static_cast<socklen_t>(sizeof(struct sockaddr_storage));
     /* Note: If we ever decide to return this address to the user, remember to
        strip off the ::ffff:0.0.0.0/96 prefix first. */
     int fd = grpc_accept4(sp->fd, &addr, 1, 1);
@@ -250,7 +258,7 @@
 
     // Create acceptor.
     grpc_tcp_server_acceptor* acceptor =
-        (grpc_tcp_server_acceptor*)gpr_malloc(sizeof(*acceptor));
+        static_cast<grpc_tcp_server_acceptor*>(gpr_malloc(sizeof(*acceptor)));
     acceptor->from_server = sp->server;
     acceptor->port_index = sp->port_index;
     acceptor->fd_index = sp->fd_index;
@@ -364,7 +372,7 @@
     listener->server->nports++;
     grpc_sockaddr_to_string(&addr_str, &listener->addr, 1);
     gpr_asprintf(&name, "tcp-server-listener:%s/clone-%d", addr_str, i);
-    sp = (grpc_tcp_listener*)gpr_malloc(sizeof(grpc_tcp_listener));
+    sp = static_cast<grpc_tcp_listener*>(gpr_malloc(sizeof(grpc_tcp_listener)));
     sp->next = listener->next;
     listener->next = sp;
     /* sp (the new listener) is a sibling of 'listener' (the original
@@ -390,9 +398,9 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_tcp_server_add_port(grpc_tcp_server* s,
-                                     const grpc_resolved_address* addr,
-                                     int* out_port) {
+static grpc_error* tcp_server_add_port(grpc_tcp_server* s,
+                                       const grpc_resolved_address* addr,
+                                       int* out_port) {
   grpc_tcp_listener* sp;
   grpc_resolved_address sockname_temp;
   grpc_resolved_address addr6_v4mapped;
@@ -410,9 +418,12 @@
      as some previously created listener. */
   if (requested_port == 0) {
     for (sp = s->head; sp; sp = sp->next) {
-      sockname_temp.len = sizeof(struct sockaddr_storage);
-      if (0 == getsockname(sp->fd, (struct sockaddr*)&sockname_temp.addr,
-                           (socklen_t*)&sockname_temp.len)) {
+      sockname_temp.len =
+          static_cast<socklen_t>(sizeof(struct sockaddr_storage));
+      if (0 ==
+          getsockname(sp->fd,
+                      reinterpret_cast<grpc_sockaddr*>(&sockname_temp.addr),
+                      &sockname_temp.len)) {
         int used_port = grpc_sockaddr_get_port(&sockname_temp);
         if (used_port > 0) {
           memcpy(&sockname_temp, addr, sizeof(grpc_resolved_address));
@@ -454,8 +465,7 @@
   return nullptr;
 }
 
-unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server* s,
-                                       unsigned port_index) {
+unsigned tcp_server_port_fd_count(grpc_tcp_server* s, unsigned port_index) {
   unsigned num_fds = 0;
   gpr_mu_lock(&s->mu);
   grpc_tcp_listener* sp = get_port_index(s, port_index);
@@ -466,8 +476,8 @@
   return num_fds;
 }
 
-int grpc_tcp_server_port_fd(grpc_tcp_server* s, unsigned port_index,
-                            unsigned fd_index) {
+static int tcp_server_port_fd(grpc_tcp_server* s, unsigned port_index,
+                              unsigned fd_index) {
   gpr_mu_lock(&s->mu);
   grpc_tcp_listener* sp = get_port_index(s, port_index);
   for (; sp; sp = sp->sibling, --fd_index) {
@@ -480,10 +490,10 @@
   return -1;
 }
 
-void grpc_tcp_server_start(grpc_tcp_server* s, grpc_pollset** pollsets,
-                           size_t pollset_count,
-                           grpc_tcp_server_cb on_accept_cb,
-                           void* on_accept_cb_arg) {
+static void tcp_server_start(grpc_tcp_server* s, grpc_pollset** pollsets,
+                             size_t pollset_count,
+                             grpc_tcp_server_cb on_accept_cb,
+                             void* on_accept_cb_arg) {
   size_t i;
   grpc_tcp_listener* sp;
   GPR_ASSERT(on_accept_cb);
@@ -522,20 +532,20 @@
   gpr_mu_unlock(&s->mu);
 }
 
-grpc_tcp_server* grpc_tcp_server_ref(grpc_tcp_server* s) {
+grpc_tcp_server* tcp_server_ref(grpc_tcp_server* s) {
   gpr_ref_non_zero(&s->refs);
   return s;
 }
 
-void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server* s,
-                                           grpc_closure* shutdown_starting) {
+static void tcp_server_shutdown_starting_add(grpc_tcp_server* s,
+                                             grpc_closure* shutdown_starting) {
   gpr_mu_lock(&s->mu);
   grpc_closure_list_append(&s->shutdown_starting, shutdown_starting,
                            GRPC_ERROR_NONE);
   gpr_mu_unlock(&s->mu);
 }
 
-void grpc_tcp_server_unref(grpc_tcp_server* s) {
+static void tcp_server_unref(grpc_tcp_server* s) {
   if (gpr_unref(&s->refs)) {
     grpc_tcp_server_shutdown_listeners(s);
     gpr_mu_lock(&s->mu);
@@ -545,7 +555,7 @@
   }
 }
 
-void grpc_tcp_server_shutdown_listeners(grpc_tcp_server* s) {
+static void tcp_server_shutdown_listeners(grpc_tcp_server* s) {
   gpr_mu_lock(&s->mu);
   s->shutdown_listeners = true;
   /* shutdown all fd's */
@@ -559,4 +569,14 @@
   gpr_mu_unlock(&s->mu);
 }
 
+grpc_tcp_server_vtable grpc_posix_tcp_server_vtable = {
+    tcp_server_create,
+    tcp_server_start,
+    tcp_server_add_port,
+    tcp_server_port_fd_count,
+    tcp_server_port_fd,
+    tcp_server_ref,
+    tcp_server_shutdown_starting_add,
+    tcp_server_unref,
+    tcp_server_shutdown_listeners};
 #endif
diff --git a/src/core/lib/iomgr/tcp_server_utils_posix.h b/src/core/lib/iomgr/tcp_server_utils_posix.h
index 6046f25..34d6813 100644
--- a/src/core/lib/iomgr/tcp_server_utils_posix.h
+++ b/src/core/lib/iomgr/tcp_server_utils_posix.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_TCP_SERVER_UTILS_POSIX_H
 #define GRPC_CORE_LIB_IOMGR_TCP_SERVER_UTILS_POSIX_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/socket_utils_posix.h"
diff --git a/src/core/lib/iomgr/tcp_server_utils_posix_common.cc b/src/core/lib/iomgr/tcp_server_utils_posix_common.cc
index 5139760..0734453 100644
--- a/src/core/lib/iomgr/tcp_server_utils_posix_common.cc
+++ b/src/core/lib/iomgr/tcp_server_utils_posix_common.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_POSIX_SOCKET
@@ -56,7 +58,7 @@
     char* end;
     long i = strtol(buf, &end, 10);
     if (i > 0 && i <= INT_MAX && end && *end == '\n') {
-      n = (int)i;
+      n = static_cast<int>(i);
     }
   }
   fclose(fp);
@@ -93,7 +95,7 @@
     gpr_mu_lock(&s->mu);
     s->nports++;
     GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
-    sp = (grpc_tcp_listener*)gpr_malloc(sizeof(grpc_tcp_listener));
+    sp = static_cast<grpc_tcp_listener*>(gpr_malloc(sizeof(grpc_tcp_listener)));
     sp->next = nullptr;
     if (s->head == nullptr) {
       s->head = sp;
@@ -169,7 +171,8 @@
   if (err != GRPC_ERROR_NONE) goto error;
 
   GPR_ASSERT(addr->len < ~(socklen_t)0);
-  if (bind(fd, (struct sockaddr*)addr->addr, (socklen_t)addr->len) < 0) {
+  if (bind(fd, reinterpret_cast<grpc_sockaddr*>(const_cast<char*>(addr->addr)),
+           addr->len) < 0) {
     err = GRPC_OS_ERROR(errno, "bind");
     goto error;
   }
@@ -179,10 +182,10 @@
     goto error;
   }
 
-  sockname_temp.len = sizeof(struct sockaddr_storage);
+  sockname_temp.len = static_cast<socklen_t>(sizeof(struct sockaddr_storage));
 
-  if (getsockname(fd, (struct sockaddr*)sockname_temp.addr,
-                  (socklen_t*)&sockname_temp.len) < 0) {
+  if (getsockname(fd, reinterpret_cast<grpc_sockaddr*>(sockname_temp.addr),
+                  &sockname_temp.len) < 0) {
     err = GRPC_OS_ERROR(errno, "getsockname");
     goto error;
   }
diff --git a/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc b/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc
index 227bf94..7fd86c5 100644
--- a/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc
+++ b/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_HAVE_IFADDRS
@@ -66,12 +68,13 @@
   if (dsmode == GRPC_DSMODE_IPV4) {
     grpc_sockaddr_make_wildcard4(0, &wild);
   }
-  if (bind(fd, (const struct sockaddr*)wild.addr, (socklen_t)wild.len) != 0) {
+  if (bind(fd, reinterpret_cast<const grpc_sockaddr*>(wild.addr), wild.len) !=
+      0) {
     err = GRPC_OS_ERROR(errno, "bind");
     close(fd);
     return err;
   }
-  if (getsockname(fd, (struct sockaddr*)wild.addr, (socklen_t*)&wild.len) !=
+  if (getsockname(fd, reinterpret_cast<grpc_sockaddr*>(wild.addr), &wild.len) !=
       0) {
     err = GRPC_OS_ERROR(errno, "getsockname");
     close(fd);
@@ -116,9 +119,9 @@
     if (ifa_it->ifa_addr == nullptr) {
       continue;
     } else if (ifa_it->ifa_addr->sa_family == AF_INET) {
-      addr.len = sizeof(struct sockaddr_in);
+      addr.len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in));
     } else if (ifa_it->ifa_addr->sa_family == AF_INET6) {
-      addr.len = sizeof(struct sockaddr_in6);
+      addr.len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in6));
     } else {
       continue;
     }
diff --git a/src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc b/src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc
index 2d72b95..86ee14f 100644
--- a/src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc
+++ b/src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #if defined(GRPC_POSIX_SOCKET) && !defined(GRPC_HAVE_IFADDRS)
diff --git a/src/core/lib/iomgr/tcp_server_uv.cc b/src/core/lib/iomgr/tcp_server_uv.cc
deleted file mode 100644
index 1ac4919..0000000
--- a/src/core/lib/iomgr/tcp_server_uv.cc
+++ /dev/null
@@ -1,471 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "src/core/lib/iomgr/port.h"
-
-#ifdef GRPC_UV
-
-#include <assert.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-#include "src/core/lib/iomgr/error.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
-#include "src/core/lib/iomgr/iomgr_uv.h"
-#include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
-#include "src/core/lib/iomgr/tcp_server.h"
-#include "src/core/lib/iomgr/tcp_uv.h"
-
-/* one listening port */
-typedef struct grpc_tcp_listener grpc_tcp_listener;
-struct grpc_tcp_listener {
-  uv_tcp_t* handle;
-  grpc_tcp_server* server;
-  unsigned port_index;
-  int port;
-  /* linked list */
-  struct grpc_tcp_listener* next;
-
-  bool closed;
-
-  bool has_pending_connection;
-};
-
-struct grpc_tcp_server {
-  gpr_refcount refs;
-
-  /* Called whenever accept() succeeds on a server port. */
-  grpc_tcp_server_cb on_accept_cb;
-  void* on_accept_cb_arg;
-
-  int open_ports;
-
-  /* linked list of server ports */
-  grpc_tcp_listener* head;
-  grpc_tcp_listener* tail;
-
-  /* List of closures passed to shutdown_starting_add(). */
-  grpc_closure_list shutdown_starting;
-
-  /* shutdown callback */
-  grpc_closure* shutdown_complete;
-
-  bool shutdown;
-
-  grpc_resource_quota* resource_quota;
-};
-
-grpc_error* grpc_tcp_server_create(grpc_closure* shutdown_complete,
-                                   const grpc_channel_args* args,
-                                   grpc_tcp_server** server) {
-  grpc_tcp_server* s = (grpc_tcp_server*)gpr_malloc(sizeof(grpc_tcp_server));
-  s->resource_quota = grpc_resource_quota_create(NULL);
-  for (size_t i = 0; i < (args == NULL ? 0 : args->num_args); i++) {
-    if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) {
-      if (args->args[i].type == GRPC_ARG_POINTER) {
-        grpc_resource_quota_unref_internal(s->resource_quota);
-        s->resource_quota = grpc_resource_quota_ref_internal(
-            (grpc_resource_quota*)args->args[i].value.pointer.p);
-      } else {
-        grpc_resource_quota_unref_internal(s->resource_quota);
-        gpr_free(s);
-        return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-            GRPC_ARG_RESOURCE_QUOTA " must be a pointer to a buffer pool");
-      }
-    }
-  }
-  gpr_ref_init(&s->refs, 1);
-  s->on_accept_cb = NULL;
-  s->on_accept_cb_arg = NULL;
-  s->open_ports = 0;
-  s->head = NULL;
-  s->tail = NULL;
-  s->shutdown_starting.head = NULL;
-  s->shutdown_starting.tail = NULL;
-  s->shutdown_complete = shutdown_complete;
-  s->shutdown = false;
-  *server = s;
-  return GRPC_ERROR_NONE;
-}
-
-grpc_tcp_server* grpc_tcp_server_ref(grpc_tcp_server* s) {
-  GRPC_UV_ASSERT_SAME_THREAD();
-  gpr_ref(&s->refs);
-  return s;
-}
-
-void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server* s,
-                                           grpc_closure* shutdown_starting) {
-  grpc_closure_list_append(&s->shutdown_starting, shutdown_starting,
-                           GRPC_ERROR_NONE);
-}
-
-static void finish_shutdown(grpc_tcp_server* s) {
-  GPR_ASSERT(s->shutdown);
-  if (s->shutdown_complete != NULL) {
-    GRPC_CLOSURE_SCHED(s->shutdown_complete, GRPC_ERROR_NONE);
-  }
-
-  while (s->head) {
-    grpc_tcp_listener* sp = s->head;
-    s->head = sp->next;
-    sp->next = NULL;
-    gpr_free(sp->handle);
-    gpr_free(sp);
-  }
-  grpc_resource_quota_unref_internal(s->resource_quota);
-  gpr_free(s);
-}
-
-static void handle_close_callback(uv_handle_t* handle) {
-  grpc_tcp_listener* sp = (grpc_tcp_listener*)handle->data;
-  grpc_core::ExecCtx exec_ctx;
-  sp->server->open_ports--;
-  if (sp->server->open_ports == 0 && sp->server->shutdown) {
-    finish_shutdown(sp->server);
-  }
-}
-
-static void close_listener(grpc_tcp_listener* sp) {
-  if (!sp->closed) {
-    sp->closed = true;
-    uv_close((uv_handle_t*)sp->handle, handle_close_callback);
-  }
-}
-
-static void tcp_server_destroy(grpc_tcp_server* s) {
-  int immediately_done = 0;
-  grpc_tcp_listener* sp;
-
-  GPR_ASSERT(!s->shutdown);
-  s->shutdown = true;
-
-  if (s->open_ports == 0) {
-    immediately_done = 1;
-  }
-  for (sp = s->head; sp; sp = sp->next) {
-    close_listener(sp);
-  }
-
-  if (immediately_done) {
-    finish_shutdown(s);
-  }
-}
-
-void grpc_tcp_server_unref(grpc_tcp_server* s) {
-  GRPC_UV_ASSERT_SAME_THREAD();
-  if (gpr_unref(&s->refs)) {
-    /* Complete shutdown_starting work before destroying. */
-    grpc_core::ExecCtx exec_ctx;
-    GRPC_CLOSURE_LIST_SCHED(&s->shutdown_starting);
-    grpc_core::ExecCtx::Get()->Flush();
-    tcp_server_destroy(s);
-  }
-}
-
-static void finish_accept(grpc_tcp_listener* sp) {
-  grpc_tcp_server_acceptor* acceptor =
-      (grpc_tcp_server_acceptor*)gpr_malloc(sizeof(*acceptor));
-  uv_tcp_t* client = NULL;
-  grpc_endpoint* ep = NULL;
-  grpc_resolved_address peer_name;
-  char* peer_name_string;
-  int err;
-  uv_tcp_t* server = sp->handle;
-
-  client = (uv_tcp_t*)gpr_malloc(sizeof(uv_tcp_t));
-  uv_tcp_init(uv_default_loop(), client);
-  // UV documentation says this is guaranteed to succeed
-  uv_accept((uv_stream_t*)server, (uv_stream_t*)client);
-  peer_name_string = NULL;
-  memset(&peer_name, 0, sizeof(grpc_resolved_address));
-  peer_name.len = sizeof(struct sockaddr_storage);
-  err = uv_tcp_getpeername(client, (struct sockaddr*)&peer_name.addr,
-                           (int*)&peer_name.len);
-  if (err == 0) {
-    peer_name_string = grpc_sockaddr_to_uri(&peer_name);
-  } else {
-    gpr_log(GPR_INFO, "uv_tcp_getpeername error: %s", uv_strerror(err));
-  }
-  if (grpc_tcp_trace.enabled()) {
-    if (peer_name_string) {
-      gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p accepted connection: %s",
-              sp->server, peer_name_string);
-    } else {
-      gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p accepted connection", sp->server);
-    }
-  }
-  ep = grpc_tcp_create(client, sp->server->resource_quota, peer_name_string);
-  acceptor->from_server = sp->server;
-  acceptor->port_index = sp->port_index;
-  acceptor->fd_index = 0;
-  sp->server->on_accept_cb(sp->server->on_accept_cb_arg, ep, NULL, acceptor);
-  gpr_free(peer_name_string);
-}
-
-static void on_connect(uv_stream_t* server, int status) {
-  grpc_tcp_listener* sp = (grpc_tcp_listener*)server->data;
-  grpc_core::ExecCtx exec_ctx;
-
-  if (status < 0) {
-    switch (status) {
-      case UV_EINTR:
-      case UV_EAGAIN:
-        return;
-      default:
-        close_listener(sp);
-        return;
-    }
-  }
-
-  GPR_ASSERT(!sp->has_pending_connection);
-
-  if (grpc_tcp_trace.enabled()) {
-    gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p incoming connection", sp->server);
-  }
-
-  // Create acceptor.
-  if (sp->server->on_accept_cb) {
-    finish_accept(sp);
-  } else {
-    sp->has_pending_connection = true;
-  }
-}
-
-static grpc_error* add_addr_to_server(grpc_tcp_server* s,
-                                      const grpc_resolved_address* addr,
-                                      unsigned port_index,
-                                      grpc_tcp_listener** listener) {
-  grpc_tcp_listener* sp = NULL;
-  int port = -1;
-  int status;
-  grpc_error* error;
-  grpc_resolved_address sockname_temp;
-  uv_tcp_t* handle = (uv_tcp_t*)gpr_malloc(sizeof(uv_tcp_t));
-  int family = grpc_sockaddr_get_family(addr);
-
-  status = uv_tcp_init_ex(uv_default_loop(), handle, (unsigned int)family);
-#if defined(GPR_LINUX) && defined(SO_REUSEPORT)
-  if (family == AF_INET || family == AF_INET6) {
-    int fd;
-    uv_fileno((uv_handle_t*)handle, &fd);
-    int enable = 1;
-    setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable));
-  }
-#endif /* GPR_LINUX && SO_REUSEPORT */
-
-  if (status != 0) {
-    error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-        "Failed to initialize UV tcp handle");
-    error =
-        grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
-                           grpc_slice_from_static_string(uv_strerror(status)));
-    return error;
-  }
-
-  // The last argument to uv_tcp_bind is flags
-  status = uv_tcp_bind(handle, (struct sockaddr*)addr->addr, 0);
-  if (status != 0) {
-    error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to bind to port");
-    error =
-        grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
-                           grpc_slice_from_static_string(uv_strerror(status)));
-    return error;
-  }
-
-  status = uv_listen((uv_stream_t*)handle, SOMAXCONN, on_connect);
-  if (status != 0) {
-    error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to listen to port");
-    error =
-        grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
-                           grpc_slice_from_static_string(uv_strerror(status)));
-    return error;
-  }
-
-  sockname_temp.len = (int)sizeof(struct sockaddr_storage);
-  status = uv_tcp_getsockname(handle, (struct sockaddr*)&sockname_temp.addr,
-                              (int*)&sockname_temp.len);
-  if (status != 0) {
-    error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("getsockname failed");
-    error =
-        grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
-                           grpc_slice_from_static_string(uv_strerror(status)));
-    return error;
-  }
-
-  port = grpc_sockaddr_get_port(&sockname_temp);
-
-  GPR_ASSERT(port >= 0);
-  GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
-  sp = (grpc_tcp_listener*)gpr_zalloc(sizeof(grpc_tcp_listener));
-  sp->next = NULL;
-  if (s->head == NULL) {
-    s->head = sp;
-  } else {
-    s->tail->next = sp;
-  }
-  s->tail = sp;
-  sp->server = s;
-  sp->handle = handle;
-  sp->port = port;
-  sp->port_index = port_index;
-  sp->closed = false;
-  handle->data = sp;
-  s->open_ports++;
-  GPR_ASSERT(sp->handle);
-  *listener = sp;
-
-  return GRPC_ERROR_NONE;
-}
-
-static grpc_error* add_wildcard_addrs_to_server(grpc_tcp_server* s,
-                                                unsigned port_index,
-                                                int requested_port,
-                                                grpc_tcp_listener** listener) {
-  grpc_resolved_address wild4;
-  grpc_resolved_address wild6;
-  grpc_tcp_listener* sp = nullptr;
-  grpc_tcp_listener* sp2 = nullptr;
-  grpc_error* v6_err = GRPC_ERROR_NONE;
-  grpc_error* v4_err = GRPC_ERROR_NONE;
-
-  grpc_sockaddr_make_wildcards(requested_port, &wild4, &wild6);
-  /* Try listening on IPv6 first. */
-  if ((v6_err = add_addr_to_server(s, &wild6, port_index, &sp)) ==
-      GRPC_ERROR_NONE) {
-    *listener = sp;
-    return GRPC_ERROR_NONE;
-  }
-
-  if ((v4_err = add_addr_to_server(s, &wild4, port_index, &sp2)) ==
-      GRPC_ERROR_NONE) {
-    *listener = sp2;
-    return GRPC_ERROR_NONE;
-  }
-
-  grpc_error* root_err = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-      "Failed to add any wildcard listeners");
-  root_err = grpc_error_add_child(root_err, v6_err);
-  root_err = grpc_error_add_child(root_err, v4_err);
-  return root_err;
-}
-
-grpc_error* grpc_tcp_server_add_port(grpc_tcp_server* s,
-                                     const grpc_resolved_address* addr,
-                                     int* port) {
-  // This function is mostly copied from tcp_server_windows.c
-  grpc_tcp_listener* sp = NULL;
-  grpc_resolved_address addr6_v4mapped;
-  grpc_resolved_address* allocated_addr = NULL;
-  grpc_resolved_address sockname_temp;
-  unsigned port_index = 0;
-  grpc_error* error = GRPC_ERROR_NONE;
-
-  GRPC_UV_ASSERT_SAME_THREAD();
-
-  if (s->tail != NULL) {
-    port_index = s->tail->port_index + 1;
-  }
-
-  /* Check if this is a wildcard port, and if so, try to keep the port the same
-     as some previously created listener. */
-  if (grpc_sockaddr_get_port(addr) == 0) {
-    for (sp = s->head; sp; sp = sp->next) {
-      sockname_temp.len = sizeof(struct sockaddr_storage);
-      if (0 == uv_tcp_getsockname(sp->handle,
-                                  (struct sockaddr*)&sockname_temp.addr,
-                                  (int*)&sockname_temp.len)) {
-        *port = grpc_sockaddr_get_port(&sockname_temp);
-        if (*port > 0) {
-          allocated_addr =
-              (grpc_resolved_address*)gpr_malloc(sizeof(grpc_resolved_address));
-          memcpy(allocated_addr, addr, sizeof(grpc_resolved_address));
-          grpc_sockaddr_set_port(allocated_addr, *port);
-          addr = allocated_addr;
-          break;
-        }
-      }
-    }
-  }
-
-  /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
-  if (grpc_sockaddr_is_wildcard(addr, port)) {
-    error = add_wildcard_addrs_to_server(s, port_index, *port, &sp);
-  } else {
-    if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
-      addr = &addr6_v4mapped;
-    }
-
-    error = add_addr_to_server(s, addr, port_index, &sp);
-  }
-
-  gpr_free(allocated_addr);
-
-  if (grpc_tcp_trace.enabled()) {
-    char* port_string;
-    grpc_sockaddr_to_string(&port_string, addr, 0);
-    const char* str = grpc_error_string(error);
-    if (port_string) {
-      gpr_log(GPR_DEBUG, "SERVER %p add_port %s error=%s", s, port_string, str);
-      gpr_free(port_string);
-    } else {
-      gpr_log(GPR_DEBUG, "SERVER %p add_port error=%s", s, str);
-    }
-  }
-
-  if (error != GRPC_ERROR_NONE) {
-    grpc_error* error_out = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-        "Failed to add port to server", &error, 1);
-    GRPC_ERROR_UNREF(error);
-    error = error_out;
-    *port = -1;
-  } else {
-    GPR_ASSERT(sp != NULL);
-    *port = sp->port;
-  }
-  return error;
-}
-
-void grpc_tcp_server_start(grpc_tcp_server* server, grpc_pollset** pollsets,
-                           size_t pollset_count,
-                           grpc_tcp_server_cb on_accept_cb, void* cb_arg) {
-  grpc_tcp_listener* sp;
-  (void)pollsets;
-  (void)pollset_count;
-  GRPC_UV_ASSERT_SAME_THREAD();
-  if (grpc_tcp_trace.enabled()) {
-    gpr_log(GPR_DEBUG, "SERVER_START %p", server);
-  }
-  GPR_ASSERT(on_accept_cb);
-  GPR_ASSERT(!server->on_accept_cb);
-  server->on_accept_cb = on_accept_cb;
-  server->on_accept_cb_arg = cb_arg;
-  for (sp = server->head; sp; sp = sp->next) {
-    if (sp->has_pending_connection) {
-      finish_accept(sp);
-      sp->has_pending_connection = false;
-    }
-  }
-}
-
-void grpc_tcp_server_shutdown_listeners(grpc_tcp_server* s) {}
-
-#endif /* GRPC_UV */
diff --git a/src/core/lib/iomgr/tcp_server_windows.cc b/src/core/lib/iomgr/tcp_server_windows.cc
index 8a30dfd..77f3811 100644
--- a/src/core/lib/iomgr/tcp_server_windows.cc
+++ b/src/core/lib/iomgr/tcp_server_windows.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_WINSOCK_SOCKET
@@ -48,7 +50,7 @@
 struct grpc_tcp_listener {
   /* This seemingly magic number comes from AcceptEx's documentation. each
      address buffer needs to have at least 16 more bytes at their end. */
-  uint8_t addresses[(sizeof(struct sockaddr_in6) + 16) * 2];
+  uint8_t addresses[(sizeof(grpc_sockaddr_in6) + 16) * 2];
   /* This will hold the socket for the next accept. */
   SOCKET new_socket;
   /* The listener winsocket. */
@@ -94,9 +96,9 @@
 
 /* Public function. Allocates the proper data structures to hold a
    grpc_tcp_server. */
-grpc_error* grpc_tcp_server_create(grpc_closure* shutdown_complete,
-                                   const grpc_channel_args* args,
-                                   grpc_tcp_server** server) {
+static grpc_error* tcp_server_create(grpc_closure* shutdown_complete,
+                                     const grpc_channel_args* args,
+                                     grpc_tcp_server** server) {
   grpc_tcp_server* s = (grpc_tcp_server*)gpr_malloc(sizeof(grpc_tcp_server));
   s->channel_args = grpc_channel_args_copy(args);
   gpr_ref_init(&s->refs, 1);
@@ -140,13 +142,13 @@
       GRPC_ERROR_NONE);
 }
 
-grpc_tcp_server* grpc_tcp_server_ref(grpc_tcp_server* s) {
+static grpc_tcp_server* tcp_server_ref(grpc_tcp_server* s) {
   gpr_ref_non_zero(&s->refs);
   return s;
 }
 
-void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server* s,
-                                           grpc_closure* shutdown_starting) {
+static void tcp_server_shutdown_starting_add(grpc_tcp_server* s,
+                                             grpc_closure* shutdown_starting) {
   gpr_mu_lock(&s->mu);
   grpc_closure_list_append(&s->shutdown_starting, shutdown_starting,
                            GRPC_ERROR_NONE);
@@ -170,7 +172,7 @@
   gpr_mu_unlock(&s->mu);
 }
 
-void grpc_tcp_server_unref(grpc_tcp_server* s) {
+static void tcp_server_unref(grpc_tcp_server* s) {
   if (gpr_unref(&s->refs)) {
     grpc_tcp_server_shutdown_listeners(s);
     gpr_mu_lock(&s->mu);
@@ -193,7 +195,7 @@
     goto failure;
   }
 
-  if (bind(sock, (const struct sockaddr*)addr->addr, (int)addr->len) ==
+  if (bind(sock, (const grpc_sockaddr*)addr->addr, (int)addr->len) ==
       SOCKET_ERROR) {
     error = GRPC_WSA_ERROR(WSAGetLastError(), "bind");
     goto failure;
@@ -205,7 +207,7 @@
   }
 
   sockname_temp_len = sizeof(struct sockaddr_storage);
-  if (getsockname(sock, (struct sockaddr*)sockname_temp.addr,
+  if (getsockname(sock, (grpc_sockaddr*)sockname_temp.addr,
                   &sockname_temp_len) == SOCKET_ERROR) {
     error = GRPC_WSA_ERROR(WSAGetLastError(), "getsockname");
     goto failure;
@@ -243,7 +245,7 @@
 static grpc_error* start_accept_locked(grpc_tcp_listener* port) {
   SOCKET sock = INVALID_SOCKET;
   BOOL success;
-  DWORD addrlen = sizeof(struct sockaddr_in6) + 16;
+  DWORD addrlen = sizeof(grpc_sockaddr_in6) + 16;
   DWORD bytes_received = 0;
   grpc_error* error = GRPC_ERROR_NONE;
 
@@ -341,7 +343,7 @@
         gpr_free(utf8_message);
       }
       int peer_name_len = (int)peer_name.len;
-      err = getpeername(sock, (struct sockaddr*)peer_name.addr, &peer_name_len);
+      err = getpeername(sock, (grpc_sockaddr*)peer_name.addr, &peer_name_len);
       peer_name.len = (size_t)peer_name_len;
       if (!err) {
         peer_name_string = grpc_sockaddr_to_uri(&peer_name);
@@ -440,9 +442,9 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error* grpc_tcp_server_add_port(grpc_tcp_server* s,
-                                     const grpc_resolved_address* addr,
-                                     int* port) {
+static grpc_error* tcp_server_add_port(grpc_tcp_server* s,
+                                       const grpc_resolved_address* addr,
+                                       int* port) {
   grpc_tcp_listener* sp = NULL;
   SOCKET sock;
   grpc_resolved_address addr6_v4mapped;
@@ -462,7 +464,7 @@
     for (sp = s->head; sp; sp = sp->next) {
       int sockname_temp_len = sizeof(struct sockaddr_storage);
       if (0 == getsockname(sp->socket->socket,
-                           (struct sockaddr*)sockname_temp.addr,
+                           (grpc_sockaddr*)sockname_temp.addr,
                            &sockname_temp_len)) {
         sockname_temp.len = (size_t)sockname_temp_len;
         *port = grpc_sockaddr_get_port(&sockname_temp);
@@ -514,10 +516,10 @@
   return error;
 }
 
-void grpc_tcp_server_start(grpc_tcp_server* s, grpc_pollset** pollset,
-                           size_t pollset_count,
-                           grpc_tcp_server_cb on_accept_cb,
-                           void* on_accept_cb_arg) {
+static void tcp_server_start(grpc_tcp_server* s, grpc_pollset** pollset,
+                             size_t pollset_count,
+                             grpc_tcp_server_cb on_accept_cb,
+                             void* on_accept_cb_arg) {
   grpc_tcp_listener* sp;
   GPR_ASSERT(on_accept_cb);
   gpr_mu_lock(&s->mu);
@@ -532,6 +534,26 @@
   gpr_mu_unlock(&s->mu);
 }
 
-void grpc_tcp_server_shutdown_listeners(grpc_tcp_server* s) {}
+static unsigned tcp_server_port_fd_count(grpc_tcp_server* s,
+                                         unsigned port_index) {
+  return 0;
+}
 
+static int tcp_server_port_fd(grpc_tcp_server* s, unsigned port_index,
+                              unsigned fd_index) {
+  return -1;
+}
+
+static void tcp_server_shutdown_listeners(grpc_tcp_server* s) {}
+
+grpc_tcp_server_vtable grpc_windows_tcp_server_vtable = {
+    tcp_server_create,
+    tcp_server_start,
+    tcp_server_add_port,
+    tcp_server_port_fd_count,
+    tcp_server_port_fd,
+    tcp_server_ref,
+    tcp_server_shutdown_starting_add,
+    tcp_server_unref,
+    tcp_server_shutdown_listeners};
 #endif /* GRPC_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/tcp_uv.cc b/src/core/lib/iomgr/tcp_uv.cc
index b384623..5e31669 100644
--- a/src/core/lib/iomgr/tcp_uv.cc
+++ b/src/core/lib/iomgr/tcp_uv.cc
@@ -16,10 +16,11 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_UV
-
 #include <limits.h>
 #include <string.h>
 
@@ -31,393 +32,393 @@
 
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/error.h"
-#include "src/core/lib/iomgr/iomgr_uv.h"
+#include "src/core/lib/iomgr/iomgr_custom.h"
 #include "src/core/lib/iomgr/network_status_tracker.h"
+#include "src/core/lib/iomgr/resolve_address_custom.h"
 #include "src/core/lib/iomgr/resource_quota.h"
-#include "src/core/lib/iomgr/tcp_uv.h"
+#include "src/core/lib/iomgr/tcp_custom.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 
-grpc_core::TraceFlag grpc_tcp_trace(false, "tcp");
+#include <uv.h>
 
-typedef struct {
-  grpc_endpoint base;
-  gpr_refcount refcount;
+#define IGNORE_CONST(addr) ((grpc_sockaddr*)(uintptr_t)(addr))
 
+typedef struct uv_socket_t {
+  uv_connect_t connect_req;
   uv_write_t write_req;
   uv_shutdown_t shutdown_req;
-
   uv_tcp_t* handle;
-
-  grpc_closure* read_cb;
-  grpc_closure* write_cb;
-
-  grpc_slice_buffer* read_slices;
-  grpc_slice_buffer* write_slices;
   uv_buf_t* write_buffers;
 
-  grpc_resource_user* resource_user;
-  grpc_resource_user_slice_allocator slice_allocator;
+  char* read_buf;
+  size_t read_len;
 
-  bool shutting_down;
+  bool pending_connection;
+  grpc_custom_socket* accept_socket;
+  grpc_error* accept_error;
 
-  char* peer_string;
-  grpc_pollset* pollset;
-} grpc_tcp;
+  grpc_custom_connect_callback connect_cb;
+  grpc_custom_write_callback write_cb;
+  grpc_custom_read_callback read_cb;
+  grpc_custom_accept_callback accept_cb;
+  grpc_custom_close_callback close_cb;
 
-static grpc_error* tcp_annotate_error(grpc_error* src_error, grpc_tcp* tcp) {
-  return grpc_error_set_str(
-      grpc_error_set_int(
-          src_error,
-          /* All tcp errors are marked with UNAVAILABLE so that application may
-           * choose to retry. */
-          GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE),
-      GRPC_ERROR_STR_TARGET_ADDRESS,
-      grpc_slice_from_copied_string(tcp->peer_string));
-}
+} uv_socket_t;
 
-static void tcp_free(grpc_tcp* tcp) {
-  grpc_resource_user_unref(tcp->resource_user);
-  gpr_free(tcp->handle);
-  gpr_free(tcp->peer_string);
-  gpr_free(tcp);
-}
-
-#ifndef NDEBUG
-#define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__)
-#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__)
-static void tcp_unref(grpc_tcp* tcp, const char* reason, const char* file,
-                      int line) {
-  if (grpc_tcp_trace.enabled()) {
-    gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count);
-    gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
-            "TCP unref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp, reason, val,
-            val - 1);
+static grpc_error* tcp_error_create(const char* desc, int status) {
+  if (status == 0) {
+    return GRPC_ERROR_NONE;
   }
-  if (gpr_unref(&tcp->refcount)) {
-    tcp_free(tcp);
-  }
+  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(desc);
+  /* All tcp errors are marked with UNAVAILABLE so that application may
+   * choose to retry. */
+  error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS,
+                             GRPC_STATUS_UNAVAILABLE);
+  return grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
+                            grpc_slice_from_static_string(uv_strerror(status)));
 }
 
-static void tcp_ref(grpc_tcp* tcp, const char* reason, const char* file,
-                    int line) {
-  if (grpc_tcp_trace.enabled()) {
-    gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count);
-    gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
-            "TCP   ref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp, reason, val,
-            val + 1);
-  }
-  gpr_ref(&tcp->refcount);
-}
-#else
-#define TCP_UNREF(tcp, reason) tcp_unref((tcp))
-#define TCP_REF(tcp, reason) tcp_ref((tcp))
-static void tcp_unref(grpc_tcp* tcp) {
-  if (gpr_unref(&tcp->refcount)) {
-    tcp_free(tcp);
-  }
-}
-
-static void tcp_ref(grpc_tcp* tcp) { gpr_ref(&tcp->refcount); }
-#endif
-
-static void uv_close_callback(uv_handle_t* handle) {
-  grpc_core::ExecCtx exec_ctx;
-  grpc_tcp* tcp = (grpc_tcp*)handle->data;
-  TCP_UNREF(tcp, "destroy");
+static void uv_socket_destroy(grpc_custom_socket* socket) {
+  uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+  gpr_free(uv_socket->handle);
+  gpr_free(uv_socket);
 }
 
 static void alloc_uv_buf(uv_handle_t* handle, size_t suggested_size,
                          uv_buf_t* buf) {
-  grpc_core::ExecCtx exec_ctx;
-  grpc_tcp* tcp = (grpc_tcp*)handle->data;
+  uv_socket_t* uv_socket =
+      (uv_socket_t*)((grpc_custom_socket*)handle->data)->impl;
   (void)suggested_size;
-  /* Before calling uv_read_start, we allocate a buffer with exactly one slice
-   * to tcp->read_slices and wait for the callback indicating that the
-   * allocation was successful. So slices[0] should always exist here */
-  buf->base = (char*)GRPC_SLICE_START_PTR(tcp->read_slices->slices[0]);
-  buf->len = GRPC_SLICE_LENGTH(tcp->read_slices->slices[0]);
+  buf->base = uv_socket->read_buf;
+  buf->len = uv_socket->read_len;
 }
 
-static void call_read_cb(grpc_tcp* tcp, grpc_error* error) {
-  grpc_closure* cb = tcp->read_cb;
-  if (grpc_tcp_trace.enabled()) {
-    gpr_log(GPR_DEBUG, "TCP:%p call_cb %p %p:%p", tcp, cb, cb->cb, cb->cb_arg);
-    size_t i;
-    const char* str = grpc_error_string(error);
-    gpr_log(GPR_DEBUG, "read: error=%s", str);
-
-    for (i = 0; i < tcp->read_slices->count; i++) {
-      char* dump = grpc_dump_slice(tcp->read_slices->slices[i],
-                                   GPR_DUMP_HEX | GPR_DUMP_ASCII);
-      gpr_log(GPR_DEBUG, "READ %p (peer=%s): %s", tcp, tcp->peer_string, dump);
-      gpr_free(dump);
-    }
-  }
-  tcp->read_slices = NULL;
-  tcp->read_cb = NULL;
-  GRPC_CLOSURE_RUN(cb, error);
-}
-
-static void read_callback(uv_stream_t* stream, ssize_t nread,
-                          const uv_buf_t* buf) {
-  grpc_error* error;
-  grpc_core::ExecCtx exec_ctx;
-  grpc_tcp* tcp = (grpc_tcp*)stream->data;
-  grpc_slice_buffer garbage;
+static void uv_read_callback(uv_stream_t* stream, ssize_t nread,
+                             const uv_buf_t* buf) {
+  grpc_error* error = GRPC_ERROR_NONE;
   if (nread == 0) {
     // Nothing happened. Wait for the next callback
     return;
   }
-  TCP_UNREF(tcp, "read");
   // TODO(murgatroid99): figure out what the return value here means
   uv_read_stop(stream);
   if (nread == UV_EOF) {
-    error =
-        tcp_annotate_error(GRPC_ERROR_CREATE_FROM_STATIC_STRING("EOF"), tcp);
-    grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices);
-  } else if (nread > 0) {
-    // Successful read
-    error = GRPC_ERROR_NONE;
-    if ((size_t)nread < tcp->read_slices->length) {
-      /* TODO(murgatroid99): Instead of discarding the unused part of the read
-       * buffer, reuse it as the next read buffer. */
-      grpc_slice_buffer_init(&garbage);
-      grpc_slice_buffer_trim_end(
-          tcp->read_slices, tcp->read_slices->length - (size_t)nread, &garbage);
-      grpc_slice_buffer_reset_and_unref_internal(&garbage);
-    }
-  } else {
-    // nread < 0: Error
-    error = tcp_annotate_error(
-        GRPC_ERROR_CREATE_FROM_STATIC_STRING("TCP Read failed"), tcp);
-    grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices);
+    error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("EOF");
+  } else if (nread < 0) {
+    error = tcp_error_create("TCP Read failed", nread);
   }
-  call_read_cb(tcp, error);
+  grpc_custom_socket* socket = (grpc_custom_socket*)stream->data;
+  uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+  uv_socket->read_cb(socket, (size_t)nread, error);
 }
 
-static void tcp_read_allocation_done(void* tcpp, grpc_error* error) {
+static void uv_close_callback(uv_handle_t* handle) {
+  grpc_custom_socket* socket = (grpc_custom_socket*)handle->data;
+  uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+  if (uv_socket->accept_socket) {
+    uv_socket->accept_cb(socket, uv_socket->accept_socket,
+                         GRPC_ERROR_CREATE_FROM_STATIC_STRING("socket closed"));
+  }
+  uv_socket->close_cb(socket);
+}
+
+static void uv_socket_read(grpc_custom_socket* socket, char* buffer,
+                           size_t length, grpc_custom_read_callback read_cb) {
+  uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
   int status;
-  grpc_tcp* tcp = (grpc_tcp*)tcpp;
-  if (grpc_tcp_trace.enabled()) {
-    gpr_log(GPR_DEBUG, "TCP:%p read_allocation_done: %s", tcp,
-            grpc_error_string(error));
-  }
-  if (error == GRPC_ERROR_NONE) {
-    status =
-        uv_read_start((uv_stream_t*)tcp->handle, alloc_uv_buf, read_callback);
-    if (status != 0) {
-      error = tcp_annotate_error(
-          GRPC_ERROR_CREATE_FROM_STATIC_STRING("TCP Read failed at start"),
-          tcp);
-      error = grpc_error_set_str(
-          error, GRPC_ERROR_STR_OS_ERROR,
-          grpc_slice_from_static_string(uv_strerror(status)));
-    }
-  }
-  if (error != GRPC_ERROR_NONE) {
-    grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices);
-    call_read_cb(tcp, GRPC_ERROR_REF(error));
-    TCP_UNREF(tcp, "read");
-  }
-  if (grpc_tcp_trace.enabled()) {
-    const char* str = grpc_error_string(error);
-    gpr_log(GPR_DEBUG, "Initiating read on %p: error=%s", tcp, str);
-  }
-}
-
-static void uv_endpoint_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices,
-                             grpc_closure* cb) {
-  grpc_tcp* tcp = (grpc_tcp*)ep;
-  GRPC_UV_ASSERT_SAME_THREAD();
-  GPR_ASSERT(tcp->read_cb == NULL);
-  tcp->read_cb = cb;
-  tcp->read_slices = read_slices;
-  grpc_slice_buffer_reset_and_unref_internal(read_slices);
-  TCP_REF(tcp, "read");
-  grpc_resource_user_alloc_slices(&tcp->slice_allocator,
-                                  GRPC_TCP_DEFAULT_READ_SLICE_SIZE, 1,
-                                  tcp->read_slices);
-}
-
-static void write_callback(uv_write_t* req, int status) {
-  grpc_tcp* tcp = (grpc_tcp*)req->data;
   grpc_error* error;
-  grpc_core::ExecCtx exec_ctx;
-  grpc_closure* cb = tcp->write_cb;
-  tcp->write_cb = NULL;
-  TCP_UNREF(tcp, "write");
-  if (status == 0) {
-    error = GRPC_ERROR_NONE;
-  } else {
-    error = tcp_annotate_error(
-        GRPC_ERROR_CREATE_FROM_STATIC_STRING("TCP Write failed"), tcp);
-  }
-  if (grpc_tcp_trace.enabled()) {
-    const char* str = grpc_error_string(error);
-    gpr_log(GPR_DEBUG, "write complete on %p: error=%s", tcp, str);
-  }
-  gpr_free(tcp->write_buffers);
-  GRPC_CLOSURE_SCHED(cb, error);
-}
-
-static void uv_endpoint_write(grpc_endpoint* ep,
-                              grpc_slice_buffer* write_slices,
-                              grpc_closure* cb) {
-  grpc_tcp* tcp = (grpc_tcp*)ep;
-  uv_buf_t* buffers;
-  unsigned int buffer_count;
-  unsigned int i;
-  grpc_slice* slice;
-  uv_write_t* write_req;
-  GRPC_UV_ASSERT_SAME_THREAD();
-
-  if (grpc_tcp_trace.enabled()) {
-    size_t j;
-
-    for (j = 0; j < write_slices->count; j++) {
-      char* data = grpc_dump_slice(write_slices->slices[j],
-                                   GPR_DUMP_HEX | GPR_DUMP_ASCII);
-      gpr_log(GPR_DEBUG, "WRITE %p (peer=%s): %s", tcp, tcp->peer_string, data);
-      gpr_free(data);
-    }
-  }
-
-  if (tcp->shutting_down) {
-    GRPC_CLOSURE_SCHED(cb,
-                       tcp_annotate_error(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-                                              "TCP socket is shutting down"),
-                                          tcp));
-    return;
-  }
-
-  GPR_ASSERT(tcp->write_cb == NULL);
-  tcp->write_slices = write_slices;
-  GPR_ASSERT(tcp->write_slices->count <= UINT_MAX);
-  if (tcp->write_slices->count == 0) {
-    // No slices means we don't have to do anything,
-    // and libuv doesn't like empty writes
-    GRPC_CLOSURE_SCHED(cb, GRPC_ERROR_NONE);
-    return;
-  }
-
-  tcp->write_cb = cb;
-  buffer_count = (unsigned int)tcp->write_slices->count;
-  buffers = (uv_buf_t*)gpr_malloc(sizeof(uv_buf_t) * buffer_count);
-  for (i = 0; i < buffer_count; i++) {
-    slice = &tcp->write_slices->slices[i];
-    buffers[i].base = (char*)GRPC_SLICE_START_PTR(*slice);
-    buffers[i].len = GRPC_SLICE_LENGTH(*slice);
-  }
-  tcp->write_buffers = buffers;
-  write_req = &tcp->write_req;
-  write_req->data = tcp;
-  TCP_REF(tcp, "write");
+  uv_socket->read_cb = read_cb;
+  uv_socket->read_buf = buffer;
+  uv_socket->read_len = length;
   // TODO(murgatroid99): figure out what the return value here means
-  uv_write(write_req, (uv_stream_t*)tcp->handle, buffers, buffer_count,
-           write_callback);
+  status =
+      uv_read_start((uv_stream_t*)uv_socket->handle, (uv_alloc_cb)alloc_uv_buf,
+                    (uv_read_cb)uv_read_callback);
+  if (status != 0) {
+    error = tcp_error_create("TCP Read failed at start", status);
+    uv_socket->read_cb(socket, 0, error);
+  }
 }
 
-static void uv_add_to_pollset(grpc_endpoint* ep, grpc_pollset* pollset) {
-  // No-op. We're ignoring pollsets currently
-  (void)ep;
-  (void)pollset;
-  grpc_tcp* tcp = (grpc_tcp*)ep;
-  tcp->pollset = pollset;
+static void uv_write_callback(uv_write_t* req, int status) {
+  grpc_custom_socket* socket = (grpc_custom_socket*)req->data;
+  uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+  gpr_free(uv_socket->write_buffers);
+  uv_socket->write_cb(socket, tcp_error_create("TCP Write failed", status));
 }
 
-static void uv_add_to_pollset_set(grpc_endpoint* ep,
-                                  grpc_pollset_set* pollset) {
-  // No-op. We're ignoring pollsets currently
-  (void)ep;
-  (void)pollset;
-}
+void uv_socket_write(grpc_custom_socket* socket,
+                     grpc_slice_buffer* write_slices,
+                     grpc_custom_write_callback write_cb) {
+  uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+  uv_socket->write_cb = write_cb;
+  uv_buf_t* uv_buffers;
+  uv_write_t* write_req;
 
-static void uv_delete_from_pollset_set(grpc_endpoint* ep,
-                                       grpc_pollset_set* pollset) {
-  // No-op. We're ignoring pollsets currently
-  (void)ep;
-  (void)pollset;
+  uv_buffers = (uv_buf_t*)gpr_malloc(sizeof(uv_buf_t) * write_slices->count);
+  for (size_t i = 0; i < write_slices->count; i++) {
+    uv_buffers[i].base = (char*)GRPC_SLICE_START_PTR(write_slices->slices[i]);
+    uv_buffers[i].len = GRPC_SLICE_LENGTH(write_slices->slices[i]);
+  }
+
+  uv_socket->write_buffers = uv_buffers;
+  write_req = &uv_socket->write_req;
+  write_req->data = socket;
+  // TODO(murgatroid99): figure out what the return value here means
+  uv_write(write_req, (uv_stream_t*)uv_socket->handle, uv_buffers,
+           write_slices->count, uv_write_callback);
 }
 
 static void shutdown_callback(uv_shutdown_t* req, int status) {}
 
-static void uv_endpoint_shutdown(grpc_endpoint* ep, grpc_error* why) {
-  grpc_tcp* tcp = (grpc_tcp*)ep;
-  if (!tcp->shutting_down) {
-    if (grpc_tcp_trace.enabled()) {
-      const char* str = grpc_error_string(why);
-      gpr_log(GPR_DEBUG, "TCP %p shutdown why=%s", tcp->handle, str);
+static void uv_socket_shutdown(grpc_custom_socket* socket) {
+  uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+  uv_shutdown_t* req = &uv_socket->shutdown_req;
+  uv_shutdown(req, (uv_stream_t*)uv_socket->handle, shutdown_callback);
+}
+
+static void uv_socket_close(grpc_custom_socket* socket,
+                            grpc_custom_close_callback close_cb) {
+  uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+  uv_socket->close_cb = close_cb;
+  uv_close((uv_handle_t*)uv_socket->handle, uv_close_callback);
+}
+
+static grpc_error* uv_socket_init_helper(uv_socket_t* uv_socket, int domain) {
+  uv_tcp_t* tcp = (uv_tcp_t*)gpr_malloc(sizeof(uv_tcp_t));
+  uv_socket->handle = tcp;
+  int status = uv_tcp_init_ex(uv_default_loop(), tcp, (unsigned int)domain);
+  if (status != 0) {
+    return tcp_error_create("Failed to initialize UV tcp handle", status);
+  }
+  uv_socket->write_buffers = nullptr;
+  uv_socket->read_len = 0;
+  uv_tcp_nodelay(uv_socket->handle, 1);
+  uv_socket->pending_connection = false;
+  uv_socket->accept_socket = nullptr;
+  uv_socket->accept_error = GRPC_ERROR_NONE;
+  return GRPC_ERROR_NONE;
+}
+
+static grpc_error* uv_socket_init(grpc_custom_socket* socket, int domain) {
+  uv_socket_t* uv_socket = (uv_socket_t*)gpr_malloc(sizeof(uv_socket_t));
+  grpc_error* error = uv_socket_init_helper(uv_socket, domain);
+  if (error != GRPC_ERROR_NONE) {
+    return error;
+  }
+  uv_socket->handle->data = socket;
+  socket->impl = uv_socket;
+  return GRPC_ERROR_NONE;
+}
+
+static grpc_error* uv_socket_getpeername(grpc_custom_socket* socket,
+                                         const grpc_sockaddr* addr,
+                                         int* addr_len) {
+  uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+  int err = uv_tcp_getpeername(uv_socket->handle,
+                               (struct sockaddr*)IGNORE_CONST(addr), addr_len);
+  return tcp_error_create("getpeername failed", err);
+}
+
+static grpc_error* uv_socket_getsockname(grpc_custom_socket* socket,
+                                         const grpc_sockaddr* addr,
+                                         int* addr_len) {
+  uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+  int err = uv_tcp_getsockname(uv_socket->handle,
+                               (struct sockaddr*)IGNORE_CONST(addr), addr_len);
+  return tcp_error_create("getsockname failed", err);
+}
+
+static void accept_new_connection(grpc_custom_socket* socket) {
+  uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+  if (!uv_socket->pending_connection || !uv_socket->accept_socket) {
+    return;
+  }
+  grpc_custom_socket* new_socket = uv_socket->accept_socket;
+  grpc_error* error = uv_socket->accept_error;
+  uv_socket->accept_socket = nullptr;
+  uv_socket->accept_error = GRPC_ERROR_NONE;
+  uv_socket->pending_connection = false;
+  if (uv_socket->accept_error != GRPC_ERROR_NONE) {
+    uv_stream_t dummy_handle;
+    uv_accept((uv_stream_t*)uv_socket->handle, &dummy_handle);
+    uv_socket->accept_cb(socket, new_socket, error);
+  } else {
+    uv_socket_t* uv_new_socket = (uv_socket_t*)gpr_malloc(sizeof(uv_socket_t));
+    uv_socket_init_helper(uv_new_socket, AF_UNSPEC);
+    // UV documentation says this is guaranteed to succeed
+    GPR_ASSERT(uv_accept((uv_stream_t*)uv_socket->handle,
+                         (uv_stream_t*)uv_new_socket->handle) == 0);
+    new_socket->impl = uv_new_socket;
+    uv_new_socket->handle->data = new_socket;
+    uv_socket->accept_cb(socket, new_socket, error);
+  }
+}
+
+static void uv_on_connect(uv_stream_t* server, int status) {
+  grpc_custom_socket* socket = (grpc_custom_socket*)server->data;
+  uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+  GPR_ASSERT(!uv_socket->pending_connection);
+  uv_socket->pending_connection = true;
+  if (status < 0) {
+    switch (status) {
+      case UV_EINTR:
+      case UV_EAGAIN:
+        return;
+      default:
+        uv_socket->accept_error = tcp_error_create("accept failed", status);
     }
-    tcp->shutting_down = true;
-    uv_shutdown_t* req = &tcp->shutdown_req;
-    uv_shutdown(req, (uv_stream_t*)tcp->handle, shutdown_callback);
-    grpc_resource_user_shutdown(tcp->resource_user);
   }
-  GRPC_ERROR_UNREF(why);
+  accept_new_connection(socket);
 }
 
-static void uv_destroy(grpc_endpoint* ep) {
-  grpc_network_status_unregister_endpoint(ep);
-  grpc_tcp* tcp = (grpc_tcp*)ep;
-  uv_close((uv_handle_t*)tcp->handle, uv_close_callback);
+void uv_socket_accept(grpc_custom_socket* socket,
+                      grpc_custom_socket* new_socket,
+                      grpc_custom_accept_callback accept_cb) {
+  uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+  uv_socket->accept_cb = accept_cb;
+  GPR_ASSERT(uv_socket->accept_socket == nullptr);
+  uv_socket->accept_socket = new_socket;
+  accept_new_connection(socket);
 }
 
-static char* uv_get_peer(grpc_endpoint* ep) {
-  grpc_tcp* tcp = (grpc_tcp*)ep;
-  return gpr_strdup(tcp->peer_string);
+static grpc_error* uv_socket_bind(grpc_custom_socket* socket,
+                                  const grpc_sockaddr* addr, size_t len,
+                                  int flags) {
+  uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+  int status =
+      uv_tcp_bind((uv_tcp_t*)uv_socket->handle, (struct sockaddr*)addr, 0);
+  return tcp_error_create("Failed to bind to port", status);
 }
 
-static grpc_resource_user* uv_get_resource_user(grpc_endpoint* ep) {
-  grpc_tcp* tcp = (grpc_tcp*)ep;
-  return tcp->resource_user;
+static grpc_error* uv_socket_listen(grpc_custom_socket* socket) {
+  uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+  int status =
+      uv_listen((uv_stream_t*)uv_socket->handle, SOMAXCONN, uv_on_connect);
+  return tcp_error_create("Failed to listen to port", status);
 }
 
-static int uv_get_fd(grpc_endpoint* ep) { return -1; }
+static grpc_error* uv_socket_setsockopt(grpc_custom_socket* socket, int level,
+                                        int option_name, const void* optval,
+                                        socklen_t option_len) {
+  int fd;
+  uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+  uv_fileno((uv_handle_t*)uv_socket->handle, &fd);
+  // TODO Handle error here.  Also, does this work on windows??
+  setsockopt(fd, level, option_name, &optval, (socklen_t)option_len);
+  return GRPC_ERROR_NONE;
+}
 
-static grpc_endpoint_vtable vtable = {uv_endpoint_read,
-                                      uv_endpoint_write,
-                                      uv_add_to_pollset,
-                                      uv_add_to_pollset_set,
-                                      uv_delete_from_pollset_set,
-                                      uv_endpoint_shutdown,
-                                      uv_destroy,
-                                      uv_get_resource_user,
-                                      uv_get_peer,
-                                      uv_get_fd};
-
-grpc_endpoint* grpc_tcp_create(uv_tcp_t* handle,
-                               grpc_resource_quota* resource_quota,
-                               char* peer_string) {
-  grpc_tcp* tcp = (grpc_tcp*)gpr_malloc(sizeof(grpc_tcp));
-  grpc_core::ExecCtx exec_ctx;
-
-  if (grpc_tcp_trace.enabled()) {
-    gpr_log(GPR_DEBUG, "Creating TCP endpoint %p", tcp);
+static void uv_tc_on_connect(uv_connect_t* req, int status) {
+  grpc_custom_socket* socket = (grpc_custom_socket*)req->data;
+  uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+  grpc_error* error;
+  if (status == UV_ECANCELED) {
+    // This should only happen if the handle is already closed
+    error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Timeout occurred");
+  } else {
+    error = tcp_error_create("Failed to connect to remote host", status);
   }
+  uv_socket->connect_cb(socket, error);
+}
 
-  /* Disable Nagle's Algorithm */
-  uv_tcp_nodelay(handle, 1);
+static void uv_socket_connect(grpc_custom_socket* socket,
+                              const grpc_sockaddr* addr, size_t len,
+                              grpc_custom_connect_callback connect_cb) {
+  uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+  uv_socket->connect_cb = connect_cb;
+  uv_socket->connect_req.data = socket;
+  int status = uv_tcp_connect(&uv_socket->connect_req, uv_socket->handle,
+                              (struct sockaddr*)addr, uv_tc_on_connect);
+  if (status != 0) {
+    // The callback will not be called
+    uv_socket->connect_cb(socket, tcp_error_create("connect failed", status));
+  }
+}
 
-  memset(tcp, 0, sizeof(grpc_tcp));
-  tcp->base.vtable = &vtable;
-  tcp->handle = handle;
-  handle->data = tcp;
-  gpr_ref_init(&tcp->refcount, 1);
-  tcp->peer_string = gpr_strdup(peer_string);
-  tcp->shutting_down = false;
-  tcp->read_slices = NULL;
-  tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string);
-  grpc_resource_user_slice_allocator_init(
-      &tcp->slice_allocator, tcp->resource_user, tcp_read_allocation_done, tcp);
-  /* Tell network status tracking code about the new endpoint */
-  grpc_network_status_register_endpoint(&tcp->base);
+static grpc_resolved_addresses* handle_addrinfo_result(
+    struct addrinfo* result) {
+  struct addrinfo* resp;
+  struct addrinfo* prev;
+  size_t i;
+  grpc_resolved_addresses* addresses =
+      (grpc_resolved_addresses*)gpr_malloc(sizeof(grpc_resolved_addresses));
+  addresses->naddrs = 0;
+  for (resp = result; resp != nullptr; resp = resp->ai_next) {
+    addresses->naddrs++;
+  }
+  addresses->addrs = (grpc_resolved_address*)gpr_malloc(
+      sizeof(grpc_resolved_address) * addresses->naddrs);
+  i = 0;
+  resp = result;
+  while (resp != nullptr) {
+    memcpy(&addresses->addrs[i].addr, resp->ai_addr, resp->ai_addrlen);
+    addresses->addrs[i].len = resp->ai_addrlen;
+    i++;
+    prev = resp;
+    resp = resp->ai_next;
+    gpr_free(prev);
+  }
+  return addresses;
+}
 
-#ifndef GRPC_UV_TCP_HOLD_LOOP
-  uv_unref((uv_handle_t*)handle);
+static void uv_resolve_callback(uv_getaddrinfo_t* req, int status,
+                                struct addrinfo* res) {
+  grpc_custom_resolver* r = (grpc_custom_resolver*)req->data;
+  gpr_free(req);
+  grpc_resolved_addresses* result = nullptr;
+  if (status == 0) {
+    result = handle_addrinfo_result(res);
+  }
+  grpc_custom_resolve_callback(r, result,
+                               tcp_error_create("getaddrinfo failed", status));
+}
+
+static grpc_error* uv_resolve(char* host, char* port,
+                              grpc_resolved_addresses** result) {
+  int status;
+  uv_getaddrinfo_t req;
+  struct addrinfo hints;
+  memset(&hints, 0, sizeof(struct addrinfo));
+  hints.ai_family = AF_UNSPEC;     /* ipv4 or ipv6 */
+  hints.ai_socktype = SOCK_STREAM; /* stream socket */
+  hints.ai_flags = AI_PASSIVE;     /* for wildcard IP address */
+  status = uv_getaddrinfo(uv_default_loop(), &req, NULL, host, port, &hints);
+  if (status != 0) {
+    *result = nullptr;
+  } else {
+    *result = handle_addrinfo_result(req.addrinfo);
+  }
+  return tcp_error_create("getaddrinfo failed", status);
+}
+
+static void uv_resolve_async(grpc_custom_resolver* r, char* host, char* port) {
+  int status;
+  uv_getaddrinfo_t* req =
+      (uv_getaddrinfo_t*)gpr_malloc(sizeof(uv_getaddrinfo_t));
+  req->data = r;
+  struct addrinfo hints;
+  memset(&hints, 0, sizeof(struct addrinfo));
+  hints.ai_family = GRPC_AF_UNSPEC;     /* ipv4 or ipv6 */
+  hints.ai_socktype = GRPC_SOCK_STREAM; /* stream socket */
+  hints.ai_flags = GRPC_AI_PASSIVE;     /* for wildcard IP address */
+  status = uv_getaddrinfo(uv_default_loop(), req, uv_resolve_callback, host,
+                          port, &hints);
+  if (status != 0) {
+    gpr_free(req);
+    grpc_error* error = tcp_error_create("getaddrinfo failed", status);
+    grpc_custom_resolve_callback(r, NULL, error);
+  }
+}
+
+grpc_custom_resolver_vtable uv_resolver_vtable = {uv_resolve, uv_resolve_async};
+
+grpc_socket_vtable grpc_uv_socket_vtable = {
+    uv_socket_init,       uv_socket_connect,     uv_socket_destroy,
+    uv_socket_shutdown,   uv_socket_close,       uv_socket_write,
+    uv_socket_read,       uv_socket_getpeername, uv_socket_getsockname,
+    uv_socket_setsockopt, uv_socket_bind,        uv_socket_listen,
+    uv_socket_accept};
+
 #endif
-
-  return &tcp->base;
-}
-
-#endif /* GRPC_UV */
diff --git a/src/core/lib/iomgr/tcp_uv.h b/src/core/lib/iomgr/tcp_uv.h
deleted file mode 100644
index fd6d190..0000000
--- a/src/core/lib/iomgr/tcp_uv.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- *
- * Copyright 2016 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 GRPC_CORE_LIB_IOMGR_TCP_UV_H
-#define GRPC_CORE_LIB_IOMGR_TCP_UV_H
-/*
-   Low level TCP "bottom half" implementation, for use by transports built on
-   top of a TCP connection.
-
-   Note that this file does not (yet) include APIs for creating the socket in
-   the first place.
-
-   All calls passing slice transfer ownership of a slice refcount unless
-   otherwise specified.
-*/
-
-#include "src/core/lib/debug/trace.h"
-#include "src/core/lib/iomgr/endpoint.h"
-
-#include "src/core/lib/iomgr/port.h"
-
-#ifdef GRPC_UV
-
-#include <uv.h>
-
-extern grpc_core::TraceFlag grpc_tcp_trace;
-
-#define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192
-
-grpc_endpoint* grpc_tcp_create(uv_tcp_t* handle,
-                               grpc_resource_quota* resource_quota,
-                               char* peer_string);
-
-#endif /* GRPC_UV */
-
-#endif /* GRPC_CORE_LIB_IOMGR_TCP_UV_H */
diff --git a/src/core/lib/iomgr/tcp_windows.cc b/src/core/lib/iomgr/tcp_windows.cc
index 6d091b7..04e6f11 100644
--- a/src/core/lib/iomgr/tcp_windows.cc
+++ b/src/core/lib/iomgr/tcp_windows.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_WINSOCK_SOCKET
@@ -30,8 +32,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/log_windows.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/iocp_windows.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
@@ -49,7 +51,7 @@
 #define GRPC_FIONBIO FIONBIO
 #endif
 
-grpc_core::TraceFlag grpc_tcp_trace(false, "tcp");
+extern grpc_core::TraceFlag grpc_tcp_trace;
 
 static grpc_error* set_non_block(SOCKET sock) {
   int status;
diff --git a/src/core/lib/iomgr/tcp_windows.h b/src/core/lib/iomgr/tcp_windows.h
index 8578a35..161a545 100644
--- a/src/core/lib/iomgr/tcp_windows.h
+++ b/src/core/lib/iomgr/tcp_windows.h
@@ -29,6 +29,8 @@
    otherwise specified.
 */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_WINSOCK_SOCKET
diff --git a/src/core/lib/iomgr/time_averaged_stats.cc b/src/core/lib/iomgr/time_averaged_stats.cc
index 3bddec0..6369e48 100644
--- a/src/core/lib/iomgr/time_averaged_stats.cc
+++ b/src/core/lib/iomgr/time_averaged_stats.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/time_averaged_stats.h"
 
 void grpc_time_averaged_stats_init(grpc_time_averaged_stats* stats,
diff --git a/src/core/lib/iomgr/timer.cc b/src/core/lib/iomgr/timer.cc
new file mode 100644
index 0000000..e647cde
--- /dev/null
+++ b/src/core/lib/iomgr/timer.cc
@@ -0,0 +1,45 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/iomgr/timer_manager.h"
+
+grpc_timer_vtable* grpc_timer_impl;
+
+void grpc_set_timer_impl(grpc_timer_vtable* vtable) {
+  grpc_timer_impl = vtable;
+}
+
+void grpc_timer_init(grpc_timer* timer, grpc_millis deadline,
+                     grpc_closure* closure) {
+  grpc_timer_impl->init(timer, deadline, closure);
+}
+
+void grpc_timer_cancel(grpc_timer* timer) { grpc_timer_impl->cancel(timer); }
+
+grpc_timer_check_result grpc_timer_check(grpc_millis* next) {
+  return grpc_timer_impl->check(next);
+}
+
+void grpc_timer_list_init() { grpc_timer_impl->list_init(); }
+
+void grpc_timer_list_shutdown() { grpc_timer_impl->list_shutdown(); }
+
+void grpc_timer_consume_kick() { grpc_timer_impl->consume_kick(); }
diff --git a/src/core/lib/iomgr/timer.h b/src/core/lib/iomgr/timer.h
index 8204985..5ff10d3 100644
--- a/src/core/lib/iomgr/timer.h
+++ b/src/core/lib/iomgr/timer.h
@@ -19,20 +19,45 @@
 #ifndef GRPC_CORE_LIB_IOMGR_TIMER_H
 #define GRPC_CORE_LIB_IOMGR_TIMER_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
-#ifdef GRPC_UV
-#include "src/core/lib/iomgr/timer_uv.h"
-#else
-#include "src/core/lib/iomgr/timer_generic.h"
-#endif /* GRPC_UV */
-
-#include <grpc/support/port_platform.h>
 #include <grpc/support/time.h>
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/iomgr.h"
 
-typedef struct grpc_timer grpc_timer;
+typedef struct grpc_timer {
+  gpr_atm deadline;
+  uint32_t heap_index; /* INVALID_HEAP_INDEX if not in heap */
+  bool pending;
+  struct grpc_timer* next;
+  struct grpc_timer* prev;
+  grpc_closure* closure;
+#ifndef NDEBUG
+  struct grpc_timer* hash_table_next;
+#endif
+
+  // Optional field used by custom timers
+  void* custom_timer;
+} grpc_timer;
+
+typedef enum {
+  GRPC_TIMERS_NOT_CHECKED,
+  GRPC_TIMERS_CHECKED_AND_EMPTY,
+  GRPC_TIMERS_FIRED,
+} grpc_timer_check_result;
+
+typedef struct grpc_timer_vtable {
+  void (*init)(grpc_timer* timer, grpc_millis, grpc_closure* closure);
+  void (*cancel)(grpc_timer* timer);
+
+  /* Internal API */
+  grpc_timer_check_result (*check)(grpc_millis* next);
+  void (*list_init)();
+  void (*list_shutdown)(void);
+  void (*consume_kick)(void);
+} grpc_timer_vtable;
 
 /* Initialize *timer. When expired or canceled, closure will be called with
    error set to indicate if it expired (GRPC_ERROR_NONE) or was canceled
@@ -77,12 +102,6 @@
 
 /* iomgr internal api for dealing with timers */
 
-typedef enum {
-  GRPC_TIMERS_NOT_CHECKED,
-  GRPC_TIMERS_CHECKED_AND_EMPTY,
-  GRPC_TIMERS_FIRED,
-} grpc_timer_check_result;
-
 /* Check for timers to be run, and run them.
    Return true if timer callbacks were executed.
    If next is non-null, TRY to update *next with the next running timer
@@ -98,7 +117,9 @@
 void grpc_timer_consume_kick(void);
 
 /* the following must be implemented by each iomgr implementation */
-
 void grpc_kick_poller(void);
 
+/* Sets the timer implementation */
+void grpc_set_timer_impl(grpc_timer_vtable* vtable);
+
 #endif /* GRPC_CORE_LIB_IOMGR_TIMER_H */
diff --git a/src/core/lib/iomgr/timer_custom.cc b/src/core/lib/iomgr/timer_custom.cc
new file mode 100644
index 0000000..71d825f
--- /dev/null
+++ b/src/core/lib/iomgr/timer_custom.cc
@@ -0,0 +1,93 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/iomgr/iomgr_custom.h"
+#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/iomgr/timer_custom.h"
+
+static grpc_custom_timer_vtable* custom_timer_impl;
+
+void grpc_custom_timer_callback(grpc_custom_timer* t, grpc_error* error) {
+  GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+  grpc_core::ExecCtx exec_ctx;
+  grpc_timer* timer = t->original;
+  GPR_ASSERT(timer->pending);
+  timer->pending = 0;
+  GRPC_CLOSURE_SCHED(timer->closure, GRPC_ERROR_NONE);
+  custom_timer_impl->stop(t);
+  gpr_free(t);
+}
+
+static void timer_init(grpc_timer* timer, grpc_millis deadline,
+                       grpc_closure* closure) {
+  uint64_t timeout;
+  GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+  grpc_millis now = grpc_core::ExecCtx::Get()->Now();
+  if (deadline <= grpc_core::ExecCtx::Get()->Now()) {
+    GRPC_CLOSURE_SCHED(closure, GRPC_ERROR_NONE);
+    timer->pending = false;
+    return;
+  } else {
+    timeout = deadline - now;
+  }
+  timer->pending = true;
+  timer->closure = closure;
+  grpc_custom_timer* timer_wrapper =
+      (grpc_custom_timer*)gpr_malloc(sizeof(grpc_custom_timer));
+  timer_wrapper->timeout_ms = timeout;
+  timer->custom_timer = (void*)timer_wrapper;
+  timer_wrapper->original = timer;
+  custom_timer_impl->start(timer_wrapper);
+}
+
+static void timer_cancel(grpc_timer* timer) {
+  GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+  grpc_custom_timer* tw = (grpc_custom_timer*)timer->custom_timer;
+  if (timer->pending) {
+    timer->pending = 0;
+    GRPC_CLOSURE_SCHED(timer->closure, GRPC_ERROR_CANCELLED);
+    custom_timer_impl->stop(tw);
+    gpr_free(tw);
+  }
+}
+
+static grpc_timer_check_result timer_check(grpc_millis* next) {
+  return GRPC_TIMERS_NOT_CHECKED;
+}
+
+static void timer_list_init() {}
+static void timer_list_shutdown() {}
+
+static void timer_consume_kick(void) {}
+
+static grpc_timer_vtable custom_timer_vtable = {
+    timer_init,      timer_cancel,        timer_check,
+    timer_list_init, timer_list_shutdown, timer_consume_kick};
+
+void grpc_custom_timer_init(grpc_custom_timer_vtable* impl) {
+  custom_timer_impl = impl;
+  grpc_set_timer_impl(&custom_timer_vtable);
+}
diff --git a/src/core/lib/iomgr/timer_custom.h b/src/core/lib/iomgr/timer_custom.h
new file mode 100644
index 0000000..bfea8ba
--- /dev/null
+++ b/src/core/lib/iomgr/timer_custom.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_LIB_IOMGR_TIMER_CUSTOM_H
+#define GRPC_CORE_LIB_IOMGR_TIMER_CUSTOM_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/timer.h"
+
+typedef struct grpc_custom_timer {
+  // Implementation defined
+  void* timer;
+  uint64_t timeout_ms;
+
+  grpc_timer* original;
+} grpc_custom_timer;
+
+typedef struct grpc_custom_timer_vtable {
+  void (*start)(grpc_custom_timer* t);
+  void (*stop)(grpc_custom_timer* t);
+} grpc_custom_timer_vtable;
+
+void grpc_custom_timer_init(grpc_custom_timer_vtable* impl);
+
+void grpc_custom_timer_callback(grpc_custom_timer* t, grpc_error* error);
+
+#endif /* GRPC_CORE_LIB_IOMGR_TIMER_CUSTOM_H */
diff --git a/src/core/lib/iomgr/timer_generic.cc b/src/core/lib/iomgr/timer_generic.cc
index 177bdec..93e654b 100644
--- a/src/core/lib/iomgr/timer_generic.cc
+++ b/src/core/lib/iomgr/timer_generic.cc
@@ -16,12 +16,12 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #include <inttypes.h>
 
-#ifdef GRPC_TIMER_USE_GENERIC
-
 #include "src/core/lib/iomgr/timer.h"
 
 #include <grpc/support/alloc.h>
@@ -29,10 +29,11 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/tls.h>
-#include <grpc/support/useful.h>
+
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/gpr/spinlock.h"
+#include "src/core/lib/gpr/tls.h"
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/time_averaged_stats.h"
 #include "src/core/lib/iomgr/timer_heap.h"
 
@@ -235,13 +236,14 @@
              : grpc_timer_heap_top(&shard->heap)->deadline;
 }
 
-void grpc_timer_list_init() {
+static void timer_list_init() {
   uint32_t i;
 
   g_num_shards = GPR_MIN(1, 2 * gpr_cpu_num_cores());
-  g_shards = (timer_shard*)gpr_zalloc(g_num_shards * sizeof(*g_shards));
-  g_shard_queue =
-      (timer_shard**)gpr_zalloc(g_num_shards * sizeof(*g_shard_queue));
+  g_shards =
+      static_cast<timer_shard*>(gpr_zalloc(g_num_shards * sizeof(*g_shards)));
+  g_shard_queue = static_cast<timer_shard**>(
+      gpr_zalloc(g_num_shards * sizeof(*g_shard_queue)));
 
   g_shared_mutables.initialized = true;
   g_shared_mutables.checker_mu = GPR_SPINLOCK_INITIALIZER;
@@ -266,7 +268,7 @@
   INIT_TIMER_HASH_TABLE();
 }
 
-void grpc_timer_list_shutdown() {
+static void timer_list_shutdown() {
   size_t i;
   run_some_expired_timers(
       GPR_ATM_MAX, nullptr,
@@ -322,8 +324,8 @@
 
 void grpc_timer_init_unset(grpc_timer* timer) { timer->pending = false; }
 
-void grpc_timer_init(grpc_timer* timer, grpc_millis deadline,
-                     grpc_closure* closure) {
+static void timer_init(grpc_timer* timer, grpc_millis deadline,
+                       grpc_closure* closure) {
   int is_first_timer = 0;
   timer_shard* shard = &g_shards[GPR_HASH_POINTER(timer, g_num_shards)];
   timer->closure = closure;
@@ -358,8 +360,8 @@
     return;
   }
 
-  grpc_time_averaged_stats_add_sample(&shard->stats,
-                                      (double)(deadline - now) / 1000.0);
+  grpc_time_averaged_stats_add_sample(
+      &shard->stats, static_cast<double>(deadline - now) / 1000.0);
 
   ADD_TO_HASH_TABLE(timer);
 
@@ -373,7 +375,7 @@
     gpr_log(GPR_DEBUG,
             "  .. add to shard %d with queue_deadline_cap=%" PRIdPTR
             " => is_first_timer=%s",
-            (int)(shard - g_shards), shard->queue_deadline_cap,
+            static_cast<int>(shard - g_shards), shard->queue_deadline_cap,
             is_first_timer ? "true" : "false");
   }
   gpr_mu_unlock(&shard->mu);
@@ -408,12 +410,12 @@
   }
 }
 
-void grpc_timer_consume_kick(void) {
+static void timer_consume_kick(void) {
   /* force re-evaluation of last seeen min */
   gpr_tls_set(&g_last_seen_min_timer, 0);
 }
 
-void grpc_timer_cancel(grpc_timer* timer) {
+static void timer_cancel(grpc_timer* timer) {
   if (!g_shared_mutables.initialized) {
     /* must have already been cancelled, also the shard mutex is invalid */
     return;
@@ -460,11 +462,11 @@
   /* Compute the new cap and put all timers under it into the queue: */
   shard->queue_deadline_cap =
       saturating_add(GPR_MAX(now, shard->queue_deadline_cap),
-                     (gpr_atm)(deadline_delta * 1000.0));
+                     static_cast<gpr_atm>(deadline_delta * 1000.0));
 
   if (grpc_timer_check_trace.enabled()) {
     gpr_log(GPR_DEBUG, "  .. shard[%d]->queue_deadline_cap --> %" PRIdPTR,
-            (int)(shard - g_shards), shard->queue_deadline_cap);
+            static_cast<int>(shard - g_shards), shard->queue_deadline_cap);
   }
   for (timer = shard->list.next; timer != &shard->list; timer = next) {
     next = timer->next;
@@ -489,7 +491,7 @@
   for (;;) {
     if (grpc_timer_check_trace.enabled()) {
       gpr_log(GPR_DEBUG, "  .. shard[%d]: heap_empty=%s",
-              (int)(shard - g_shards),
+              static_cast<int>(shard - g_shards),
               grpc_timer_heap_is_empty(&shard->heap) ? "true" : "false");
     }
     if (grpc_timer_heap_is_empty(&shard->heap)) {
@@ -529,7 +531,7 @@
   gpr_mu_unlock(&shard->mu);
   if (grpc_timer_check_trace.enabled()) {
     gpr_log(GPR_DEBUG, "  .. shard[%d] popped %" PRIdPTR,
-            (int)(shard - g_shards), n);
+            static_cast<int>(shard - g_shards), n);
   }
   return n;
 }
@@ -552,7 +554,7 @@
 
     if (grpc_timer_check_trace.enabled()) {
       gpr_log(GPR_DEBUG, "  .. shard[%d]->min_deadline = %" PRIdPTR,
-              (int)(g_shard_queue[0] - g_shards),
+              static_cast<int>(g_shard_queue[0] - g_shards),
               g_shard_queue[0]->min_deadline);
     }
 
@@ -572,7 +574,7 @@
                 "  .. result --> %d"
                 ", shard[%d]->min_deadline %" PRIdPTR " --> %" PRIdPTR
                 ", now=%" PRIdPTR,
-                result, (int)(g_shard_queue[0] - g_shards),
+                result, static_cast<int>(g_shard_queue[0] - g_shards),
                 g_shard_queue[0]->min_deadline, new_min_deadline, now);
       }
 
@@ -600,7 +602,7 @@
   return result;
 }
 
-grpc_timer_check_result grpc_timer_check(grpc_millis* next) {
+static grpc_timer_check_result timer_check(grpc_millis* next) {
   // prelude
   grpc_millis now = grpc_core::ExecCtx::Get()->Now();
 
@@ -656,4 +658,6 @@
   return r;
 }
 
-#endif /* GRPC_TIMER_USE_GENERIC */
+grpc_timer_vtable grpc_generic_timer_vtable = {
+    timer_init,      timer_cancel,        timer_check,
+    timer_list_init, timer_list_shutdown, timer_consume_kick};
diff --git a/src/core/lib/iomgr/timer_generic.h b/src/core/lib/iomgr/timer_generic.h
index 190381e..97a4513 100644
--- a/src/core/lib/iomgr/timer_generic.h
+++ b/src/core/lib/iomgr/timer_generic.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_TIMER_GENERIC_H
 #define GRPC_CORE_LIB_IOMGR_TIMER_GENERIC_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/time.h>
 #include "src/core/lib/iomgr/exec_ctx.h"
 
diff --git a/src/core/lib/iomgr/timer_heap.cc b/src/core/lib/iomgr/timer_heap.cc
index b350452..0c17d60 100644
--- a/src/core/lib/iomgr/timer_heap.cc
+++ b/src/core/lib/iomgr/timer_heap.cc
@@ -16,16 +16,17 @@
  *
  */
 
-#include "src/core/lib/iomgr/port.h"
+#include <grpc/support/port_platform.h>
 
-#ifdef GRPC_TIMER_USE_GENERIC
+#include "src/core/lib/iomgr/port.h"
 
 #include "src/core/lib/iomgr/timer_heap.h"
 
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
 
 /* Adjusts a heap so as to move a hole at position i closer to the root,
    until a suitable position is found for element t. Then, copies t into that
@@ -34,7 +35,7 @@
    its argument. */
 static void adjust_upwards(grpc_timer** first, uint32_t i, grpc_timer* t) {
   while (i > 0) {
-    uint32_t parent = (uint32_t)(((int)i - 1) / 2);
+    uint32_t parent = static_cast<uint32_t>((static_cast<int>(i) - 1) / 2);
     if (first[parent]->deadline <= t->deadline) break;
     first[i] = first[parent];
     first[i]->heap_index = i;
@@ -73,14 +74,14 @@
   if (heap->timer_count >= 8 &&
       heap->timer_count <= heap->timer_capacity / SHRINK_FULLNESS_FACTOR / 2) {
     heap->timer_capacity = heap->timer_count * SHRINK_FULLNESS_FACTOR;
-    heap->timers = (grpc_timer**)gpr_realloc(
-        heap->timers, heap->timer_capacity * sizeof(grpc_timer*));
+    heap->timers = static_cast<grpc_timer**>(
+        gpr_realloc(heap->timers, heap->timer_capacity * sizeof(grpc_timer*)));
   }
 }
 
 static void note_changed_priority(grpc_timer_heap* heap, grpc_timer* timer) {
   uint32_t i = timer->heap_index;
-  uint32_t parent = (uint32_t)(((int)i - 1) / 2);
+  uint32_t parent = static_cast<uint32_t>((static_cast<int>(i) - 1) / 2);
   if (heap->timers[parent]->deadline > timer->deadline) {
     adjust_upwards(heap->timers, i, timer);
   } else {
@@ -98,8 +99,8 @@
   if (heap->timer_count == heap->timer_capacity) {
     heap->timer_capacity =
         GPR_MAX(heap->timer_capacity + 1, heap->timer_capacity * 3 / 2);
-    heap->timers = (grpc_timer**)gpr_realloc(
-        heap->timers, heap->timer_capacity * sizeof(grpc_timer*));
+    heap->timers = static_cast<grpc_timer**>(
+        gpr_realloc(heap->timers, heap->timer_capacity * sizeof(grpc_timer*)));
   }
   timer->heap_index = heap->timer_count;
   adjust_upwards(heap->timers, heap->timer_count, timer);
@@ -132,5 +133,3 @@
 void grpc_timer_heap_pop(grpc_timer_heap* heap) {
   grpc_timer_heap_remove(heap, grpc_timer_heap_top(heap));
 }
-
-#endif /* GRPC_TIMER_USE_GENERIC */
diff --git a/src/core/lib/iomgr/timer_heap.h b/src/core/lib/iomgr/timer_heap.h
index 436eef5..503365d 100644
--- a/src/core/lib/iomgr/timer_heap.h
+++ b/src/core/lib/iomgr/timer_heap.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_TIMER_HEAP_H
 #define GRPC_CORE_LIB_IOMGR_TIMER_HEAP_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/timer.h"
 
 typedef struct {
diff --git a/src/core/lib/iomgr/timer_manager.cc b/src/core/lib/iomgr/timer_manager.cc
index 7fb068f..94f288a 100644
--- a/src/core/lib/iomgr/timer_manager.cc
+++ b/src/core/lib/iomgr/timer_manager.cc
@@ -16,22 +16,22 @@
  *
  */
 
-#include "src/core/lib/iomgr/timer_manager.h"
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
-#include <grpc/support/thd.h>
 
 #include <inttypes.h>
 
-#include "src/core/lib/debug/trace.h"
-#include "src/core/lib/iomgr/timer.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
 
-typedef struct completed_thread {
-  gpr_thd_id t;
-  struct completed_thread* next;
-} completed_thread;
+#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/gprpp/thd.h"
+#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/iomgr/timer_manager.h"
+
+struct completed_thread {
+  grpc_core::Thread thd;
+  completed_thread* next;
+};
 
 extern grpc_core::TraceFlag grpc_timer_check_trace;
 
@@ -67,7 +67,7 @@
     g_completed_threads = nullptr;
     gpr_mu_unlock(&g_mu);
     while (to_gc != nullptr) {
-      gpr_thd_join(to_gc->t);
+      to_gc->thd.Join();
       completed_thread* next = to_gc->next;
       gpr_free(to_gc);
       to_gc = next;
@@ -84,17 +84,10 @@
   if (grpc_timer_check_trace.enabled()) {
     gpr_log(GPR_DEBUG, "Spawn timer thread");
   }
-  gpr_thd_options opt = gpr_thd_options_default();
-  gpr_thd_options_set_joinable(&opt);
-  completed_thread* ct = (completed_thread*)gpr_malloc(sizeof(*ct));
-  // The call to gpr_thd_new() has to be under the same lock used by
-  // gc_completed_threads(), particularly due to ct->t, which is written here
-  // (internally by gpr_thd_new) and read there. Otherwise it's possible for ct
-  // to leak through g_completed_threads and be freed in gc_completed_threads()
-  // before "&ct->t" is written to, causing a use-after-free.
-  gpr_mu_lock(&g_mu);
-  gpr_thd_new(&ct->t, "grpc_global_timer", timer_thread, ct, &opt);
-  gpr_mu_unlock(&g_mu);
+  completed_thread* ct =
+      static_cast<completed_thread*>(gpr_malloc(sizeof(*ct)));
+  ct->thd = grpc_core::Thread("grpc_global_timer", timer_thread, ct);
+  ct->thd.Start();
 }
 
 void grpc_timer_manager_tick() {
@@ -276,7 +269,7 @@
   grpc_core::ExecCtx exec_ctx(0);
   timer_main_loop();
 
-  timer_thread_cleanup((completed_thread*)completed_thread_ptr);
+  timer_thread_cleanup(static_cast<completed_thread*>(completed_thread_ptr));
 }
 
 static void start_threads(void) {
diff --git a/src/core/lib/iomgr/timer_manager.h b/src/core/lib/iomgr/timer_manager.h
index 0ba5029..3c4cdda 100644
--- a/src/core/lib/iomgr/timer_manager.h
+++ b/src/core/lib/iomgr/timer_manager.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_TIMER_MANAGER_H
 #define GRPC_CORE_LIB_IOMGR_TIMER_MANAGER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stdbool.h>
 
 /* Timer Manager tries to keep one thread waiting for the next timeout at all
diff --git a/src/core/lib/iomgr/timer_uv.cc b/src/core/lib/iomgr/timer_uv.cc
index 5d238da..dadeb96 100644
--- a/src/core/lib/iomgr/timer_uv.cc
+++ b/src/core/lib/iomgr/timer_uv.cc
@@ -16,22 +16,22 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
-#if GRPC_UV
+#ifdef GRPC_UV
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
 #include "src/core/lib/debug/trace.h"
-#include "src/core/lib/iomgr/iomgr_uv.h"
+#include "src/core/lib/iomgr/iomgr_custom.h"
 #include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/iomgr/timer_custom.h"
 
 #include <uv.h>
 
-grpc_core::TraceFlag grpc_timer_trace(false, "timer");
-grpc_core::TraceFlag grpc_timer_check_trace(false, "timer_check");
-
 static void timer_close_callback(uv_handle_t* handle) { gpr_free(handle); }
 
 static void stop_uv_timer(uv_timer_t* handle) {
@@ -41,57 +41,23 @@
 }
 
 void run_expired_timer(uv_timer_t* handle) {
-  grpc_timer* timer = (grpc_timer*)handle->data;
-  grpc_core::ExecCtx exec_ctx;
-  GRPC_UV_ASSERT_SAME_THREAD();
-  GPR_ASSERT(timer->pending);
-  timer->pending = 0;
-  GRPC_CLOSURE_SCHED(timer->closure, GRPC_ERROR_NONE);
-  stop_uv_timer(handle);
+  grpc_custom_timer* timer_wrapper = (grpc_custom_timer*)handle->data;
+  grpc_custom_timer_callback(timer_wrapper, GRPC_ERROR_NONE);
 }
 
-void grpc_timer_init(grpc_timer* timer, grpc_millis deadline,
-                     grpc_closure* closure) {
-  uint64_t timeout;
+static void timer_start(grpc_custom_timer* t) {
   uv_timer_t* uv_timer;
-  GRPC_UV_ASSERT_SAME_THREAD();
-  timer->closure = closure;
-  if (deadline <= grpc_core::ExecCtx::Get()->Now()) {
-    timer->pending = 0;
-    GRPC_CLOSURE_SCHED(timer->closure, GRPC_ERROR_NONE);
-    return;
-  }
-  timer->pending = 1;
-  timeout = (uint64_t)(deadline - grpc_core::ExecCtx::Get()->Now());
   uv_timer = (uv_timer_t*)gpr_malloc(sizeof(uv_timer_t));
   uv_timer_init(uv_default_loop(), uv_timer);
-  uv_timer->data = timer;
-  timer->uv_timer = uv_timer;
-  uv_timer_start(uv_timer, run_expired_timer, timeout, 0);
-  /* We assume that gRPC timers are only used alongside other active gRPC
-     objects, and that there will therefore always be something else keeping
-     the uv loop alive whenever there is a timer */
-  uv_unref((uv_handle_t*)uv_timer);
+  uv_timer->data = t;
+  t->timer = (void*)uv_timer;
+  uv_timer_start(uv_timer, run_expired_timer, t->timeout_ms, 0);
 }
 
-void grpc_timer_init_unset(grpc_timer* timer) { timer->pending = 0; }
-
-void grpc_timer_cancel(grpc_timer* timer) {
-  GRPC_UV_ASSERT_SAME_THREAD();
-  if (timer->pending) {
-    timer->pending = 0;
-    GRPC_CLOSURE_SCHED(timer->closure, GRPC_ERROR_CANCELLED);
-    stop_uv_timer((uv_timer_t*)timer->uv_timer);
-  }
+static void timer_stop(grpc_custom_timer* t) {
+  stop_uv_timer((uv_timer_t*)t->timer);
 }
 
-grpc_timer_check_result grpc_timer_check(grpc_millis* next) {
-  return GRPC_TIMERS_NOT_CHECKED;
-}
+grpc_custom_timer_vtable uv_timer_vtable = {timer_start, timer_stop};
 
-void grpc_timer_list_init() {}
-void grpc_timer_list_shutdown() {}
-
-void grpc_timer_consume_kick(void) {}
-
-#endif /* GRPC_UV */
+#endif
diff --git a/src/core/lib/iomgr/udp_server.cc b/src/core/lib/iomgr/udp_server.cc
index 27d32c5..04716a2 100644
--- a/src/core/lib/iomgr/udp_server.cc
+++ b/src/core/lib/iomgr/udp_server.cc
@@ -25,6 +25,8 @@
 #define SO_RXQ_OVFL 40
 #endif
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_POSIX_SOCKET
@@ -50,6 +52,8 @@
 #include <grpc/support/time.h>
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/inlined_vector.h"
+#include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/executor.h"
@@ -60,41 +64,102 @@
 #include "src/core/lib/iomgr/socket_utils_posix.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
 
-/* one listening port */
-typedef struct grpc_udp_listener grpc_udp_listener;
-struct grpc_udp_listener {
-  int fd;
-  grpc_fd* emfd;
-  grpc_udp_server* server;
-  grpc_resolved_address addr;
-  grpc_closure read_closure;
-  grpc_closure write_closure;
+/* A listener which implements basic features of Listening on a port for
+ * I/O events*/
+class GrpcUdpListener {
+ public:
+  GrpcUdpListener(grpc_udp_server* server, int fd,
+                  const grpc_resolved_address* addr);
+  ~GrpcUdpListener();
+
+  /* Called when grpc server starts to listening on the grpc_fd. */
+  void StartListening(grpc_pollset** pollsets, size_t pollset_count,
+                      GrpcUdpHandlerFactory* handler_factory);
+
+  /* Called when data is available to read from the socket.
+   * Return true if there is more data to read from fd. */
+  void OnRead(grpc_error* error, void* do_read_arg);
+
+  /* Called when the socket is writeable. The given closure should be scheduled
+   * when the socket becomes blocked next time. */
+  void OnCanWrite(grpc_error* error, void* do_write_arg);
+
+  /* Called when the grpc_fd is about to be orphaned (and the FD closed). */
+  void OnFdAboutToOrphan();
+
+  /* Called to orphan fd of this listener.*/
+  void OrphanFd();
+
+  /* Called when this listener is going to be destroyed. */
+  void OnDestroy();
+
+  int fd() const { return fd_; }
+
+ protected:
+  grpc_fd* emfd() const { return emfd_; }
+
+  gpr_mu* mutex() { return &mutex_; }
+
+ private:
+  /* event manager callback when reads are ready */
+  static void on_read(void* arg, grpc_error* error);
+  static void on_write(void* arg, grpc_error* error);
+
+  static void do_read(void* arg, grpc_error* error);
+  static void do_write(void* arg, grpc_error* error);
+  // Wrapper of grpc_fd_notify_on_write() with a grpc_closure callback
+  // interface.
+  static void fd_notify_on_write_wrapper(void* arg, grpc_error* error);
+
+  static void shutdown_fd(void* args, grpc_error* error);
+
+  int fd_;
+  grpc_fd* emfd_;
+  grpc_udp_server* server_;
+  grpc_resolved_address addr_;
+  grpc_closure read_closure_;
+  grpc_closure write_closure_;
   // To be called when corresponding QuicGrpcServer closes all active
   // connections.
-  grpc_closure orphan_fd_closure;
-  grpc_closure destroyed_closure;
-  grpc_udp_server_read_cb read_cb;
-  grpc_udp_server_write_cb write_cb;
-  grpc_udp_server_orphan_cb orphan_cb;
-  grpc_udp_server_start_cb start_cb;
+  grpc_closure orphan_fd_closure_;
+  grpc_closure destroyed_closure_;
   // To be scheduled on another thread to actually read/write.
-  grpc_closure do_read_closure;
-  grpc_closure do_write_closure;
-  grpc_closure notify_on_write_closure;
+  grpc_closure do_read_closure_;
+  grpc_closure do_write_closure_;
+  grpc_closure notify_on_write_closure_;
   // True if orphan_cb is trigered.
-  bool orphan_notified;
+  bool orphan_notified_;
   // True if grpc_fd_notify_on_write() is called after on_write() call.
-  bool notify_on_write_armed;
+  bool notify_on_write_armed_;
   // True if fd has been shutdown.
-  bool already_shutdown;
-
-  struct grpc_udp_listener* next;
+  bool already_shutdown_;
+  // Object actually handles I/O events. Assigned in StartListening().
+  GrpcUdpHandler* udp_handler_ = nullptr;
+  // To be notified on destruction.
+  GrpcUdpHandlerFactory* handler_factory_ = nullptr;
+  // Required to access above fields.
+  gpr_mu mutex_;
 };
 
-struct shutdown_fd_args {
-  grpc_udp_listener* sp;
-  gpr_mu* server_mu;
-};
+GrpcUdpListener::GrpcUdpListener(grpc_udp_server* server, int fd,
+                                 const grpc_resolved_address* addr)
+    : fd_(fd),
+      server_(server),
+      orphan_notified_(false),
+      already_shutdown_(false) {
+  char* addr_str;
+  char* name;
+  grpc_sockaddr_to_string(&addr_str, addr, 1);
+  gpr_asprintf(&name, "udp-server-listener:%s", addr_str);
+  gpr_free(addr_str);
+  emfd_ = grpc_fd_create(fd, name);
+  memcpy(&addr_, addr, sizeof(grpc_resolved_address));
+  GPR_ASSERT(emfd_);
+  gpr_free(name);
+  gpr_mu_init(&mutex_);
+}
+
+GrpcUdpListener::~GrpcUdpListener() { gpr_mu_destroy(&mutex_); }
 
 /* the overall server */
 struct grpc_udp_server {
@@ -111,10 +176,11 @@
   /* is this server shutting down? (boolean) */
   int shutdown;
 
-  /* linked list of server ports */
-  grpc_udp_listener* head;
-  grpc_udp_listener* tail;
-  unsigned nports;
+  /* An array of listeners */
+  grpc_core::InlinedVector<GrpcUdpListener, 16> listeners;
+
+  /* factory for use to create udp listeners */
+  GrpcUdpHandlerFactory* handler_factory;
 
   /* shutdown callback */
   grpc_closure* shutdown_complete;
@@ -132,14 +198,14 @@
     const grpc_arg* arg = grpc_channel_args_find(args, GRPC_ARG_SOCKET_FACTORY);
     if (arg) {
       GPR_ASSERT(arg->type == GRPC_ARG_POINTER);
-      return (grpc_socket_factory*)arg->value.pointer.p;
+      return static_cast<grpc_socket_factory*>(arg->value.pointer.p);
     }
   }
   return nullptr;
 }
 
 grpc_udp_server* grpc_udp_server_create(const grpc_channel_args* args) {
-  grpc_udp_server* s = (grpc_udp_server*)gpr_malloc(sizeof(grpc_udp_server));
+  grpc_udp_server* s = grpc_core::New<grpc_udp_server>();
   gpr_mu_init(&s->mu);
   s->socket_factory = get_socket_factory(args);
   if (s->socket_factory) {
@@ -148,32 +214,27 @@
   s->active_ports = 0;
   s->destroyed_ports = 0;
   s->shutdown = 0;
-  s->head = nullptr;
-  s->tail = nullptr;
-  s->nports = 0;
-
   return s;
 }
 
-static void shutdown_fd(void* args, grpc_error* error) {
-  struct shutdown_fd_args* shutdown_args = (struct shutdown_fd_args*)args;
-  grpc_udp_listener* sp = shutdown_args->sp;
-  gpr_log(GPR_DEBUG, "shutdown fd %d", sp->fd);
-  gpr_mu_lock(shutdown_args->server_mu);
-  grpc_fd_shutdown(sp->emfd, GRPC_ERROR_REF(error));
-  sp->already_shutdown = true;
-  if (!sp->notify_on_write_armed) {
+// static
+void GrpcUdpListener::shutdown_fd(void* args, grpc_error* error) {
+  if (args == nullptr) {
+    // No-op if shutdown args are null.
+    return;
+  }
+  auto sp = static_cast<GrpcUdpListener*>(args);
+  gpr_mu_lock(sp->mutex());
+  gpr_log(GPR_DEBUG, "shutdown fd %d", sp->fd_);
+  grpc_fd_shutdown(sp->emfd_, GRPC_ERROR_REF(error));
+  sp->already_shutdown_ = true;
+  if (!sp->notify_on_write_armed_) {
     // Re-arm write notification to notify listener with error. This is
     // necessary to decrement active_ports.
-    sp->notify_on_write_armed = true;
-    grpc_fd_notify_on_write(sp->emfd, &sp->write_closure);
+    sp->notify_on_write_armed_ = true;
+    grpc_fd_notify_on_write(sp->emfd_, &sp->write_closure_);
   }
-  gpr_mu_unlock(shutdown_args->server_mu);
-  gpr_free(shutdown_args);
-}
-
-static void dummy_cb(void* arg, grpc_error* error) {
-  // No-op.
+  gpr_mu_unlock(sp->mutex());
 }
 
 static void finish_shutdown(grpc_udp_server* s) {
@@ -184,24 +245,22 @@
   gpr_mu_destroy(&s->mu);
 
   gpr_log(GPR_DEBUG, "Destroy all listeners.");
-  while (s->head) {
-    grpc_udp_listener* sp = s->head;
-    s->head = sp->next;
-    gpr_free(sp);
+  for (size_t i = 0; i < s->listeners.size(); ++i) {
+    s->listeners[i].OnDestroy();
   }
 
   if (s->socket_factory) {
     grpc_socket_factory_unref(s->socket_factory);
   }
 
-  gpr_free(s);
+  grpc_core::Delete(s);
 }
 
 static void destroyed_port(void* server, grpc_error* error) {
-  grpc_udp_server* s = (grpc_udp_server*)server;
+  grpc_udp_server* s = static_cast<grpc_udp_server*>(server);
   gpr_mu_lock(&s->mu);
   s->destroyed_ports++;
-  if (s->destroyed_ports == s->nports) {
+  if (s->destroyed_ports == s->listeners.size()) {
     gpr_mu_unlock(&s->mu);
     finish_shutdown(s);
   } else {
@@ -218,35 +277,30 @@
 
   GPR_ASSERT(s->shutdown);
 
-  if (s->head) {
-    grpc_udp_listener* sp;
-    for (sp = s->head; sp; sp = sp->next) {
-      grpc_unlink_if_unix_domain_socket(&sp->addr);
-
-      GRPC_CLOSURE_INIT(&sp->destroyed_closure, destroyed_port, s,
-                        grpc_schedule_on_exec_ctx);
-      if (!sp->orphan_notified) {
-        /* Call the orphan_cb to signal that the FD is about to be closed and
-         * should no longer be used. Because at this point, all listening ports
-         * have been shutdown already, no need to shutdown again.*/
-        GRPC_CLOSURE_INIT(&sp->orphan_fd_closure, dummy_cb, sp,
-                          grpc_schedule_on_exec_ctx);
-        GPR_ASSERT(sp->orphan_cb);
-        gpr_log(GPR_DEBUG, "Orphan fd %d", sp->fd);
-        sp->orphan_cb(sp->emfd, &sp->orphan_fd_closure, sp->server->user_data);
-      }
-      grpc_fd_orphan(sp->emfd, &sp->destroyed_closure, nullptr,
-                     false /* already_closed */, "udp_listener_shutdown");
-    }
-    gpr_mu_unlock(&s->mu);
-  } else {
+  if (s->listeners.size() == 0) {
     gpr_mu_unlock(&s->mu);
     finish_shutdown(s);
+    return;
   }
+  for (size_t i = 0; i < s->listeners.size(); ++i) {
+    s->listeners[i].OrphanFd();
+  }
+  gpr_mu_unlock(&s->mu);
+}
+
+void GrpcUdpListener::OrphanFd() {
+  gpr_log(GPR_DEBUG, "Orphan fd %d, emfd %p", fd_, emfd_);
+  grpc_unlink_if_unix_domain_socket(&addr_);
+
+  GRPC_CLOSURE_INIT(&destroyed_closure_, destroyed_port, server_,
+                    grpc_schedule_on_exec_ctx);
+  /* Because at this point, all listening sockets have been shutdown already, no
+   * need to call OnFdAboutToOrphan() to notify the handler again. */
+  grpc_fd_orphan(emfd_, &destroyed_closure_, nullptr,
+                 false /* already_closed */, "udp_listener_shutdown");
 }
 
 void grpc_udp_server_destroy(grpc_udp_server* s, grpc_closure* on_done) {
-  grpc_udp_listener* sp;
   gpr_mu_lock(&s->mu);
 
   GPR_ASSERT(!s->shutdown);
@@ -257,16 +311,9 @@
   gpr_log(GPR_DEBUG, "start to destroy udp_server");
   /* shutdown all fd's */
   if (s->active_ports) {
-    for (sp = s->head; sp; sp = sp->next) {
-      GPR_ASSERT(sp->orphan_cb);
-      struct shutdown_fd_args* args =
-          (struct shutdown_fd_args*)gpr_malloc(sizeof(*args));
-      args->sp = sp;
-      args->server_mu = &s->mu;
-      GRPC_CLOSURE_INIT(&sp->orphan_fd_closure, shutdown_fd, args,
-                        grpc_schedule_on_exec_ctx);
-      sp->orphan_cb(sp->emfd, &sp->orphan_fd_closure, sp->server->user_data);
-      sp->orphan_notified = true;
+    for (size_t i = 0; i < s->listeners.size(); ++i) {
+      GrpcUdpListener* sp = &s->listeners[i];
+      sp->OnFdAboutToOrphan();
     }
     gpr_mu_unlock(&s->mu);
   } else {
@@ -275,11 +322,32 @@
   }
 }
 
+void GrpcUdpListener::OnFdAboutToOrphan() {
+  gpr_mu_lock(&mutex_);
+  grpc_unlink_if_unix_domain_socket(&addr_);
+
+  GRPC_CLOSURE_INIT(&destroyed_closure_, destroyed_port, server_,
+                    grpc_schedule_on_exec_ctx);
+  if (!orphan_notified_ && udp_handler_ != nullptr) {
+    /* Singals udp_handler that the FD is about to be closed and
+     * should no longer be used. */
+    GRPC_CLOSURE_INIT(&orphan_fd_closure_, shutdown_fd, this,
+                      grpc_schedule_on_exec_ctx);
+    gpr_log(GPR_DEBUG, "fd %d about to be orphaned", fd_);
+    udp_handler_->OnFdAboutToOrphan(&orphan_fd_closure_, server_->user_data);
+    orphan_notified_ = true;
+  }
+  gpr_mu_unlock(&mutex_);
+}
+
 static int bind_socket(grpc_socket_factory* socket_factory, int sockfd,
                        const grpc_resolved_address* addr) {
   return (socket_factory != nullptr)
              ? grpc_socket_factory_bind(socket_factory, sockfd, addr)
-             : bind(sockfd, (struct sockaddr*)addr->addr, (socklen_t)addr->len);
+             : bind(sockfd,
+                    reinterpret_cast<grpc_sockaddr*>(
+                        const_cast<char*>(addr->addr)),
+                    addr->len);
 }
 
 /* Prepare a recently-created socket for listening. */
@@ -287,7 +355,8 @@
                           const grpc_resolved_address* addr, int rcv_buf_size,
                           int snd_buf_size) {
   grpc_resolved_address sockname_temp;
-  struct sockaddr* addr_ptr = (struct sockaddr*)addr->addr;
+  grpc_sockaddr* addr_ptr =
+      reinterpret_cast<grpc_sockaddr*>(const_cast<char*>(addr->addr));
 
   if (fd < 0) {
     goto error;
@@ -321,10 +390,10 @@
     goto error;
   }
 
-  sockname_temp.len = sizeof(struct sockaddr_storage);
+  sockname_temp.len = static_cast<socklen_t>(sizeof(struct sockaddr_storage));
 
-  if (getsockname(fd, (struct sockaddr*)sockname_temp.addr,
-                  (socklen_t*)&sockname_temp.len) < 0) {
+  if (getsockname(fd, reinterpret_cast<grpc_sockaddr*>(sockname_temp.addr),
+                  &sockname_temp.len) < 0) {
     goto error;
   }
 
@@ -356,163 +425,140 @@
   return -1;
 }
 
-static void do_read(void* arg, grpc_error* error) {
-  grpc_udp_listener* sp = reinterpret_cast<grpc_udp_listener*>(arg);
-  GPR_ASSERT(sp->read_cb && error == GRPC_ERROR_NONE);
+// static
+void GrpcUdpListener::do_read(void* arg, grpc_error* error) {
+  GrpcUdpListener* sp = static_cast<GrpcUdpListener*>(arg);
+  GPR_ASSERT(error == GRPC_ERROR_NONE);
   /* TODO: the reason we hold server->mu here is merely to prevent fd
    * shutdown while we are reading. However, it blocks do_write(). Switch to
    * read lock if available. */
-  gpr_mu_lock(&sp->server->mu);
+  gpr_mu_lock(sp->mutex());
   /* Tell the registered callback that data is available to read. */
-  if (!sp->already_shutdown && sp->read_cb(sp->emfd)) {
+  if (!sp->already_shutdown_ && sp->udp_handler_->Read()) {
     /* There maybe more packets to read. Schedule read_more_cb_ closure to run
      * after finishing this event loop. */
-    GRPC_CLOSURE_SCHED(&sp->do_read_closure, GRPC_ERROR_NONE);
+    GRPC_CLOSURE_SCHED(&sp->do_read_closure_, GRPC_ERROR_NONE);
   } else {
     /* Finish reading all the packets, re-arm the notification event so we can
      * get another chance to read. Or fd already shutdown, re-arm to get a
      * notification with shutdown error. */
-    grpc_fd_notify_on_read(sp->emfd, &sp->read_closure);
+    grpc_fd_notify_on_read(sp->emfd_, &sp->read_closure_);
   }
-  gpr_mu_unlock(&sp->server->mu);
+  gpr_mu_unlock(sp->mutex());
 }
 
-/* event manager callback when reads are ready */
-static void on_read(void* arg, grpc_error* error) {
-  grpc_udp_listener* sp = (grpc_udp_listener*)arg;
+// static
+void GrpcUdpListener::on_read(void* arg, grpc_error* error) {
+  GrpcUdpListener* sp = static_cast<GrpcUdpListener*>(arg);
+  sp->OnRead(error, arg);
+}
 
-  gpr_mu_lock(&sp->server->mu);
+void GrpcUdpListener::OnRead(grpc_error* error, void* do_read_arg) {
   if (error != GRPC_ERROR_NONE) {
-    if (0 == --sp->server->active_ports && sp->server->shutdown) {
-      gpr_mu_unlock(&sp->server->mu);
-      deactivated_all_ports(sp->server);
+    gpr_mu_lock(&server_->mu);
+    if (0 == --server_->active_ports && server_->shutdown) {
+      gpr_mu_unlock(&server_->mu);
+      deactivated_all_ports(server_);
     } else {
-      gpr_mu_unlock(&sp->server->mu);
+      gpr_mu_unlock(&server_->mu);
     }
     return;
   }
+
   /* Read once. If there is more data to read, off load the work to another
    * thread to finish. */
-  GPR_ASSERT(sp->read_cb);
-  if (sp->read_cb(sp->emfd)) {
+  if (udp_handler_->Read()) {
     /* There maybe more packets to read. Schedule read_more_cb_ closure to run
      * after finishing this event loop. */
-    GRPC_CLOSURE_INIT(&sp->do_read_closure, do_read, arg,
+    GRPC_CLOSURE_INIT(&do_read_closure_, do_read, do_read_arg,
                       grpc_executor_scheduler(GRPC_EXECUTOR_LONG));
-    GRPC_CLOSURE_SCHED(&sp->do_read_closure, GRPC_ERROR_NONE);
+    GRPC_CLOSURE_SCHED(&do_read_closure_, GRPC_ERROR_NONE);
   } else {
     /* Finish reading all the packets, re-arm the notification event so we can
      * get another chance to read. Or fd already shutdown, re-arm to get a
      * notification with shutdown error. */
-    grpc_fd_notify_on_read(sp->emfd, &sp->read_closure);
+    grpc_fd_notify_on_read(emfd_, &read_closure_);
   }
-  gpr_mu_unlock(&sp->server->mu);
 }
 
+// static
 // Wrapper of grpc_fd_notify_on_write() with a grpc_closure callback interface.
-void fd_notify_on_write_wrapper(void* arg, grpc_error* error) {
-  grpc_udp_listener* sp = reinterpret_cast<grpc_udp_listener*>(arg);
-  gpr_mu_lock(&sp->server->mu);
-  if (!sp->notify_on_write_armed) {
-    grpc_fd_notify_on_write(sp->emfd, &sp->write_closure);
-    sp->notify_on_write_armed = true;
+void GrpcUdpListener::fd_notify_on_write_wrapper(void* arg, grpc_error* error) {
+  GrpcUdpListener* sp = static_cast<GrpcUdpListener*>(arg);
+  gpr_mu_lock(sp->mutex());
+  if (!sp->notify_on_write_armed_) {
+    grpc_fd_notify_on_write(sp->emfd_, &sp->write_closure_);
+    sp->notify_on_write_armed_ = true;
   }
-  gpr_mu_unlock(&sp->server->mu);
+  gpr_mu_unlock(sp->mutex());
 }
 
-static void do_write(void* arg, grpc_error* error) {
-  grpc_udp_listener* sp = reinterpret_cast<grpc_udp_listener*>(arg);
-  gpr_mu_lock(&sp->server->mu);
-  if (sp->already_shutdown) {
+// static
+void GrpcUdpListener::do_write(void* arg, grpc_error* error) {
+  GrpcUdpListener* sp = static_cast<GrpcUdpListener*>(arg);
+  gpr_mu_lock(sp->mutex());
+  if (sp->already_shutdown_) {
     // If fd has been shutdown, don't write any more and re-arm notification.
-    grpc_fd_notify_on_write(sp->emfd, &sp->write_closure);
+    grpc_fd_notify_on_write(sp->emfd_, &sp->write_closure_);
   } else {
-    sp->notify_on_write_armed = false;
+    sp->notify_on_write_armed_ = false;
     /* Tell the registered callback that the socket is writeable. */
-    GPR_ASSERT(sp->write_cb && error == GRPC_ERROR_NONE);
-    GRPC_CLOSURE_INIT(&sp->notify_on_write_closure, fd_notify_on_write_wrapper,
+    GPR_ASSERT(error == GRPC_ERROR_NONE);
+    GRPC_CLOSURE_INIT(&sp->notify_on_write_closure_, fd_notify_on_write_wrapper,
                       arg, grpc_schedule_on_exec_ctx);
-    sp->write_cb(sp->emfd, sp->server->user_data, &sp->notify_on_write_closure);
+    sp->udp_handler_->OnCanWrite(sp->server_->user_data,
+                                 &sp->notify_on_write_closure_);
   }
-  gpr_mu_unlock(&sp->server->mu);
+  gpr_mu_unlock(sp->mutex());
 }
 
-static void on_write(void* arg, grpc_error* error) {
-  grpc_udp_listener* sp = (grpc_udp_listener*)arg;
+// static
+void GrpcUdpListener::on_write(void* arg, grpc_error* error) {
+  GrpcUdpListener* sp = static_cast<GrpcUdpListener*>(arg);
+  sp->OnCanWrite(error, arg);
+}
 
-  gpr_mu_lock(&sp->server->mu);
+void GrpcUdpListener::OnCanWrite(grpc_error* error, void* do_write_arg) {
   if (error != GRPC_ERROR_NONE) {
-    if (0 == --sp->server->active_ports && sp->server->shutdown) {
-      gpr_mu_unlock(&sp->server->mu);
-      deactivated_all_ports(sp->server);
+    gpr_mu_lock(&server_->mu);
+    if (0 == --server_->active_ports && server_->shutdown) {
+      gpr_mu_unlock(&server_->mu);
+      deactivated_all_ports(server_);
     } else {
-      gpr_mu_unlock(&sp->server->mu);
+      gpr_mu_unlock(&server_->mu);
     }
     return;
   }
 
   /* Schedule actual write in another thread. */
-  GRPC_CLOSURE_INIT(&sp->do_write_closure, do_write, arg,
+  GRPC_CLOSURE_INIT(&do_write_closure_, do_write, do_write_arg,
                     grpc_executor_scheduler(GRPC_EXECUTOR_LONG));
 
-  GRPC_CLOSURE_SCHED(&sp->do_write_closure, GRPC_ERROR_NONE);
-  gpr_mu_unlock(&sp->server->mu);
+  GRPC_CLOSURE_SCHED(&do_write_closure_, GRPC_ERROR_NONE);
 }
 
 static int add_socket_to_server(grpc_udp_server* s, int fd,
                                 const grpc_resolved_address* addr,
-                                int rcv_buf_size, int snd_buf_size,
-                                grpc_udp_server_start_cb start_cb,
-                                grpc_udp_server_read_cb read_cb,
-                                grpc_udp_server_write_cb write_cb,
-                                grpc_udp_server_orphan_cb orphan_cb) {
-  grpc_udp_listener* sp;
-  int port;
-  char* addr_str;
-  char* name;
+                                int rcv_buf_size, int snd_buf_size) {
+  gpr_log(GPR_DEBUG, "add socket %d to server", fd);
 
-  port =
+  int port =
       prepare_socket(s->socket_factory, fd, addr, rcv_buf_size, snd_buf_size);
   if (port >= 0) {
-    grpc_sockaddr_to_string(&addr_str, addr, 1);
-    gpr_asprintf(&name, "udp-server-listener:%s", addr_str);
-    gpr_free(addr_str);
     gpr_mu_lock(&s->mu);
-    s->nports++;
-    sp = (grpc_udp_listener*)gpr_malloc(sizeof(grpc_udp_listener));
-    sp->next = nullptr;
-    if (s->head == nullptr) {
-      s->head = sp;
-    } else {
-      s->tail->next = sp;
-    }
-    s->tail = sp;
-    sp->server = s;
-    sp->fd = fd;
-    sp->emfd = grpc_fd_create(fd, name);
-    memcpy(&sp->addr, addr, sizeof(grpc_resolved_address));
-    sp->read_cb = read_cb;
-    sp->write_cb = write_cb;
-    sp->orphan_cb = orphan_cb;
-    sp->start_cb = start_cb;
-    sp->orphan_notified = false;
-    sp->already_shutdown = false;
-    GPR_ASSERT(sp->emfd);
+    s->listeners.emplace_back(s, fd, addr);
+    gpr_log(GPR_DEBUG,
+            "add socket %d to server for port %d, %zu listener(s) in total", fd,
+            port, s->listeners.size());
     gpr_mu_unlock(&s->mu);
-    gpr_free(name);
   }
-
   return port;
 }
 
 int grpc_udp_server_add_port(grpc_udp_server* s,
                              const grpc_resolved_address* addr,
                              int rcv_buf_size, int snd_buf_size,
-                             grpc_udp_server_start_cb start_cb,
-                             grpc_udp_server_read_cb read_cb,
-                             grpc_udp_server_write_cb write_cb,
-                             grpc_udp_server_orphan_cb orphan_cb) {
-  grpc_udp_listener* sp;
+                             GrpcUdpHandlerFactory* handler_factory) {
   int allocated_port1 = -1;
   int allocated_port2 = -1;
   int fd;
@@ -528,14 +574,16 @@
   /* Check if this is a wildcard port, and if so, try to keep the port the same
      as some previously created listener. */
   if (grpc_sockaddr_get_port(addr) == 0) {
-    for (sp = s->head; sp; sp = sp->next) {
-      sockname_temp.len = sizeof(struct sockaddr_storage);
-      if (0 == getsockname(sp->fd, (struct sockaddr*)sockname_temp.addr,
-                           (socklen_t*)&sockname_temp.len)) {
+    for (size_t i = 0; i < s->listeners.size(); ++i) {
+      sockname_temp.len =
+          static_cast<socklen_t>(sizeof(struct sockaddr_storage));
+      if (0 == getsockname(s->listeners[i].fd(),
+                           reinterpret_cast<grpc_sockaddr*>(sockname_temp.addr),
+                           &sockname_temp.len)) {
         port = grpc_sockaddr_get_port(&sockname_temp);
         if (port > 0) {
-          allocated_addr =
-              (grpc_resolved_address*)gpr_malloc(sizeof(grpc_resolved_address));
+          allocated_addr = static_cast<grpc_resolved_address*>(
+              gpr_malloc(sizeof(grpc_resolved_address)));
           memcpy(allocated_addr, addr, sizeof(grpc_resolved_address));
           grpc_sockaddr_set_port(allocated_addr, port);
           addr = allocated_addr;
@@ -549,6 +597,7 @@
     addr = &addr6_v4mapped;
   }
 
+  s->handler_factory = handler_factory;
   /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
   if (grpc_sockaddr_is_wildcard(addr, &port)) {
     grpc_sockaddr_make_wildcards(port, &wild4, &wild6);
@@ -559,8 +608,7 @@
     GRPC_ERROR_UNREF(grpc_create_dualstack_socket_using_factory(
         s->socket_factory, addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd));
     allocated_port1 =
-        add_socket_to_server(s, fd, addr, rcv_buf_size, snd_buf_size, start_cb,
-                             read_cb, write_cb, orphan_cb);
+        add_socket_to_server(s, fd, addr, rcv_buf_size, snd_buf_size);
     if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
       goto done;
     }
@@ -583,8 +631,7 @@
     addr = &addr4_copy;
   }
   allocated_port2 =
-      add_socket_to_server(s, fd, addr, rcv_buf_size, snd_buf_size, start_cb,
-                           read_cb, write_cb, orphan_cb);
+      add_socket_to_server(s, fd, addr, rcv_buf_size, snd_buf_size);
 
 done:
   gpr_free(allocated_addr);
@@ -592,52 +639,55 @@
 }
 
 int grpc_udp_server_get_fd(grpc_udp_server* s, unsigned port_index) {
-  grpc_udp_listener* sp;
-  if (port_index >= s->nports) {
+  if (port_index >= s->listeners.size()) {
     return -1;
   }
 
-  for (sp = s->head; sp && port_index != 0; sp = sp->next) {
-    --port_index;
-  }
-  GPR_ASSERT(sp);  // if this fails, our check earlier was bogus
-  return sp->fd;
+  return s->listeners[port_index].fd();
 }
 
 void grpc_udp_server_start(grpc_udp_server* s, grpc_pollset** pollsets,
                            size_t pollset_count, void* user_data) {
   gpr_log(GPR_DEBUG, "grpc_udp_server_start");
-  size_t i;
   gpr_mu_lock(&s->mu);
-  grpc_udp_listener* sp;
   GPR_ASSERT(s->active_ports == 0);
   s->pollsets = pollsets;
   s->user_data = user_data;
 
-  sp = s->head;
-  while (sp != nullptr) {
-    sp->start_cb(sp->emfd, sp->server->user_data);
-    for (i = 0; i < pollset_count; i++) {
-      grpc_pollset_add_fd(pollsets[i], sp->emfd);
-    }
-    GRPC_CLOSURE_INIT(&sp->read_closure, on_read, sp,
-                      grpc_schedule_on_exec_ctx);
-    grpc_fd_notify_on_read(sp->emfd, &sp->read_closure);
-
-    GRPC_CLOSURE_INIT(&sp->write_closure, on_write, sp,
-                      grpc_schedule_on_exec_ctx);
-    sp->notify_on_write_armed = true;
-    grpc_fd_notify_on_write(sp->emfd, &sp->write_closure);
-
-    /* Registered for both read and write callbacks: increment active_ports
-     * twice to account for this, and delay free-ing of memory until both
-     * on_read and on_write have fired. */
-    s->active_ports += 2;
-
-    sp = sp->next;
+  for (size_t i = 0; i < s->listeners.size(); ++i) {
+    s->listeners[i].StartListening(pollsets, pollset_count, s->handler_factory);
   }
 
   gpr_mu_unlock(&s->mu);
 }
 
+void GrpcUdpListener::StartListening(grpc_pollset** pollsets,
+                                     size_t pollset_count,
+                                     GrpcUdpHandlerFactory* handler_factory) {
+  gpr_mu_lock(&mutex_);
+  handler_factory_ = handler_factory;
+  udp_handler_ = handler_factory->CreateUdpHandler(emfd_, server_->user_data);
+  for (size_t i = 0; i < pollset_count; i++) {
+    grpc_pollset_add_fd(pollsets[i], emfd_);
+  }
+  GRPC_CLOSURE_INIT(&read_closure_, on_read, this, grpc_schedule_on_exec_ctx);
+  grpc_fd_notify_on_read(emfd_, &read_closure_);
+
+  GRPC_CLOSURE_INIT(&write_closure_, on_write, this, grpc_schedule_on_exec_ctx);
+  notify_on_write_armed_ = true;
+  grpc_fd_notify_on_write(emfd_, &write_closure_);
+
+  /* Registered for both read and write callbacks: increment active_ports
+   * twice to account for this, and delay free-ing of memory until both
+   * on_read and on_write have fired. */
+  server_->active_ports += 2;
+  gpr_mu_unlock(&mutex_);
+}
+
+void GrpcUdpListener::OnDestroy() {
+  if (udp_handler_ != nullptr) {
+    handler_factory_->DestroyUdpHandler(udp_handler_);
+  }
+}
+
 #endif
diff --git a/src/core/lib/iomgr/udp_server.h b/src/core/lib/iomgr/udp_server.h
index c1aa49f..4e384d2 100644
--- a/src/core/lib/iomgr/udp_server.h
+++ b/src/core/lib/iomgr/udp_server.h
@@ -19,6 +19,9 @@
 #ifndef GRPC_CORE_LIB_IOMGR_UDP_SERVER_H
 #define GRPC_CORE_LIB_IOMGR_UDP_SERVER_H
 
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/gprpp/abstract.h"
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/resolve_address.h"
@@ -30,22 +33,46 @@
 /* Forward decl of grpc_udp_server */
 typedef struct grpc_udp_server grpc_udp_server;
 
-/* Called when grpc server starts to listening on the grpc_fd. */
-typedef void (*grpc_udp_server_start_cb)(grpc_fd* emfd, void* user_data);
+/* An interface associated with a socket. udp server delivers I/O event on that
+ * socket to the subclass of this interface which is created through
+ * GrpcUdpHandlerFactory.
+ * Its implementation should do the real IO work, e.g. read packet and write. */
+class GrpcUdpHandler {
+ public:
+  GrpcUdpHandler(grpc_fd* emfd, void* user_data) {}
+  virtual ~GrpcUdpHandler() {}
 
-/* Called when data is available to read from the socket.
- * Return true if there is more data to read from fd. */
-typedef bool (*grpc_udp_server_read_cb)(grpc_fd* emfd);
+  // Interfaces to be implemented by subclasses to do the actual setup/tear down
+  // or I/O.
 
-/* Called when the socket is writeable. The given closure should be scheduled
- * when the socket becomes blocked next time. */
-typedef void (*grpc_udp_server_write_cb)(grpc_fd* emfd, void* user_data,
-                                         grpc_closure* notify_on_write_closure);
+  // Called when data is available to read from the socket. Returns true if
+  // there is more data to read after this call.
+  virtual bool Read() GRPC_ABSTRACT;
+  // Called when socket becomes write unblocked. The given closure should be
+  // scheduled when the socket becomes blocked next time.
+  virtual void OnCanWrite(void* user_data,
+                          grpc_closure* notify_on_write_closure) GRPC_ABSTRACT;
+  // Called before the gRPC FD is orphaned. Notify udp server to continue
+  // orphaning fd by scheduling the given closure, afterwards the associated fd
+  // will be closed.
+  virtual void OnFdAboutToOrphan(grpc_closure* orphan_fd_closure,
+                                 void* user_data) GRPC_ABSTRACT;
 
-/* Called when the grpc_fd is about to be orphaned (and the FD closed). */
-typedef void (*grpc_udp_server_orphan_cb)(grpc_fd* emfd,
-                                          grpc_closure* shutdown_fd_callback,
-                                          void* user_data);
+  GRPC_ABSTRACT_BASE_CLASS
+};
+
+class GrpcUdpHandlerFactory {
+ public:
+  virtual ~GrpcUdpHandlerFactory() {}
+  /* Called when start to listen on a socket.
+   * Return an instance of the implementation of GrpcUdpHandler interface which
+   * will process I/O events for this socket from now on. */
+  virtual GrpcUdpHandler* CreateUdpHandler(grpc_fd* emfd,
+                                           void* user_data) GRPC_ABSTRACT;
+  virtual void DestroyUdpHandler(GrpcUdpHandler* handler) GRPC_ABSTRACT;
+
+  GRPC_ABSTRACT_BASE_CLASS
+};
 
 /* Create a server, initially not bound to any ports */
 grpc_udp_server* grpc_udp_server_create(const grpc_channel_args* args);
@@ -69,10 +96,7 @@
 int grpc_udp_server_add_port(grpc_udp_server* s,
                              const grpc_resolved_address* addr,
                              int rcv_buf_size, int snd_buf_size,
-                             grpc_udp_server_start_cb start_cb,
-                             grpc_udp_server_read_cb read_cb,
-                             grpc_udp_server_write_cb write_cb,
-                             grpc_udp_server_orphan_cb orphan_cb);
+                             GrpcUdpHandlerFactory* handler_factory);
 
 void grpc_udp_server_destroy(grpc_udp_server* server, grpc_closure* on_done);
 
diff --git a/src/core/lib/iomgr/unix_sockets_posix.cc b/src/core/lib/iomgr/unix_sockets_posix.cc
index af862c0..22fcaf5 100644
--- a/src/core/lib/iomgr/unix_sockets_posix.cc
+++ b/src/core/lib/iomgr/unix_sockets_posix.cc
@@ -15,6 +15,8 @@
  * limitations under the License.
  *
  */
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_HAVE_UNIX_SOCKET
@@ -30,7 +32,8 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
 
 void grpc_create_socketpair_if_unix(int sv[2]) {
   GPR_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
@@ -50,30 +53,34 @@
     gpr_free(err_msg);
     return err;
   }
-  *addrs =
-      (grpc_resolved_addresses*)gpr_malloc(sizeof(grpc_resolved_addresses));
+  *addrs = static_cast<grpc_resolved_addresses*>(
+      gpr_malloc(sizeof(grpc_resolved_addresses)));
   (*addrs)->naddrs = 1;
-  (*addrs)->addrs =
-      (grpc_resolved_address*)gpr_malloc(sizeof(grpc_resolved_address));
-  un = (struct sockaddr_un*)(*addrs)->addrs->addr;
+  (*addrs)->addrs = static_cast<grpc_resolved_address*>(
+      gpr_malloc(sizeof(grpc_resolved_address)));
+  un = reinterpret_cast<struct sockaddr_un*>((*addrs)->addrs->addr);
   un->sun_family = AF_UNIX;
   strncpy(un->sun_path, name, sizeof(un->sun_path));
-  (*addrs)->addrs->len = strlen(un->sun_path) + sizeof(un->sun_family) + 1;
+  (*addrs)->addrs->len =
+      static_cast<socklen_t>(strlen(un->sun_path) + sizeof(un->sun_family) + 1);
   return GRPC_ERROR_NONE;
 }
 
 int grpc_is_unix_socket(const grpc_resolved_address* resolved_addr) {
-  const struct sockaddr* addr = (const struct sockaddr*)resolved_addr->addr;
+  const grpc_sockaddr* addr =
+      reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
   return addr->sa_family == AF_UNIX;
 }
 
 void grpc_unlink_if_unix_domain_socket(
     const grpc_resolved_address* resolved_addr) {
-  const struct sockaddr* addr = (const struct sockaddr*)resolved_addr->addr;
+  const grpc_sockaddr* addr =
+      reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
   if (addr->sa_family != AF_UNIX) {
     return;
   }
-  struct sockaddr_un* un = (struct sockaddr_un*)resolved_addr->addr;
+  struct sockaddr_un* un = reinterpret_cast<struct sockaddr_un*>(
+      const_cast<char*>(resolved_addr->addr));
   struct stat st;
 
   if (stat(un->sun_path, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) {
@@ -83,7 +90,8 @@
 
 char* grpc_sockaddr_to_uri_unix_if_possible(
     const grpc_resolved_address* resolved_addr) {
-  const struct sockaddr* addr = (const struct sockaddr*)resolved_addr->addr;
+  const grpc_sockaddr* addr =
+      reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
   if (addr->sa_family != AF_UNIX) {
     return nullptr;
   }
diff --git a/src/core/lib/iomgr/unix_sockets_posix.h b/src/core/lib/iomgr/unix_sockets_posix.h
index 1c079e6..917d032 100644
--- a/src/core/lib/iomgr/unix_sockets_posix.h
+++ b/src/core/lib/iomgr/unix_sockets_posix.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_UNIX_SOCKETS_POSIX_H
 #define GRPC_CORE_LIB_IOMGR_UNIX_SOCKETS_POSIX_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #include <grpc/support/string_util.h>
diff --git a/src/core/lib/iomgr/unix_sockets_posix_noop.cc b/src/core/lib/iomgr/unix_sockets_posix_noop.cc
index fbd9602..dfab3e0 100644
--- a/src/core/lib/iomgr/unix_sockets_posix_noop.cc
+++ b/src/core/lib/iomgr/unix_sockets_posix_noop.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
 
 #ifndef GRPC_HAVE_UNIX_SOCKET
diff --git a/src/core/lib/iomgr/wakeup_fd_cv.cc b/src/core/lib/iomgr/wakeup_fd_cv.cc
index c785114..74faa63 100644
--- a/src/core/lib/iomgr/wakeup_fd_cv.cc
+++ b/src/core/lib/iomgr/wakeup_fd_cv.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_POSIX_WAKEUP_FD
@@ -28,9 +30,10 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
 
 #define MAX_TABLE_RESIZE 256
 
@@ -42,8 +45,8 @@
   gpr_mu_lock(&g_cvfds.mu);
   if (!g_cvfds.free_fds) {
     newsize = GPR_MIN(g_cvfds.size * 2, g_cvfds.size + MAX_TABLE_RESIZE);
-    g_cvfds.cvfds = (grpc_fd_node*)gpr_realloc(g_cvfds.cvfds,
-                                               sizeof(grpc_fd_node) * newsize);
+    g_cvfds.cvfds = static_cast<grpc_fd_node*>(
+        gpr_realloc(g_cvfds.cvfds, sizeof(grpc_fd_node) * newsize));
     for (i = g_cvfds.size; i < newsize; i++) {
       g_cvfds.cvfds[i].is_set = 0;
       g_cvfds.cvfds[i].cvs = nullptr;
@@ -53,7 +56,7 @@
     g_cvfds.size = newsize;
   }
 
-  idx = (int)(g_cvfds.free_fds - g_cvfds.cvfds);
+  idx = static_cast<int>(g_cvfds.free_fds - g_cvfds.cvfds);
   g_cvfds.free_fds = g_cvfds.free_fds->next_free;
   g_cvfds.cvfds[idx].cvs = nullptr;
   g_cvfds.cvfds[idx].is_set = 0;
diff --git a/src/core/lib/iomgr/wakeup_fd_cv.h b/src/core/lib/iomgr/wakeup_fd_cv.h
index 399620a..86365f0 100644
--- a/src/core/lib/iomgr/wakeup_fd_cv.h
+++ b/src/core/lib/iomgr/wakeup_fd_cv.h
@@ -33,6 +33,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_WAKEUP_FD_CV_H
 #define GRPC_CORE_LIB_IOMGR_WAKEUP_FD_CV_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/sync.h>
 
 #include "src/core/lib/iomgr/ev_posix.h"
diff --git a/src/core/lib/iomgr/wakeup_fd_eventfd.cc b/src/core/lib/iomgr/wakeup_fd_eventfd.cc
index 421ac55..dcf7dab 100644
--- a/src/core/lib/iomgr/wakeup_fd_eventfd.cc
+++ b/src/core/lib/iomgr/wakeup_fd_eventfd.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_LINUX_EVENTFD
diff --git a/src/core/lib/iomgr/wakeup_fd_nospecial.cc b/src/core/lib/iomgr/wakeup_fd_nospecial.cc
index c2b525a..6477892 100644
--- a/src/core/lib/iomgr/wakeup_fd_nospecial.cc
+++ b/src/core/lib/iomgr/wakeup_fd_nospecial.cc
@@ -21,6 +21,8 @@
  * systems without anything better than pipe.
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_POSIX_NO_SPECIAL_WAKEUP_FD
diff --git a/src/core/lib/iomgr/wakeup_fd_pipe.cc b/src/core/lib/iomgr/wakeup_fd_pipe.cc
index 05d69dc..cb17390 100644
--- a/src/core/lib/iomgr/wakeup_fd_pipe.cc
+++ b/src/core/lib/iomgr/wakeup_fd_pipe.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_POSIX_WAKEUP_FD
diff --git a/src/core/lib/iomgr/wakeup_fd_pipe.h b/src/core/lib/iomgr/wakeup_fd_pipe.h
index 326a0c4..1756976 100644
--- a/src/core/lib/iomgr/wakeup_fd_pipe.h
+++ b/src/core/lib/iomgr/wakeup_fd_pipe.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_WAKEUP_FD_PIPE_H
 #define GRPC_CORE_LIB_IOMGR_WAKEUP_FD_PIPE_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/wakeup_fd_posix.h"
 
 extern const grpc_wakeup_fd_vtable grpc_pipe_wakeup_fd_vtable;
diff --git a/src/core/lib/iomgr/wakeup_fd_posix.cc b/src/core/lib/iomgr/wakeup_fd_posix.cc
index e8de208..b5b8b37 100644
--- a/src/core/lib/iomgr/wakeup_fd_posix.cc
+++ b/src/core/lib/iomgr/wakeup_fd_posix.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/port.h"
 
 #ifdef GRPC_POSIX_WAKEUP_FD
diff --git a/src/core/lib/iomgr/wakeup_fd_posix.h b/src/core/lib/iomgr/wakeup_fd_posix.h
index a9584d0..670c319 100644
--- a/src/core/lib/iomgr/wakeup_fd_posix.h
+++ b/src/core/lib/iomgr/wakeup_fd_posix.h
@@ -47,6 +47,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_WAKEUP_FD_POSIX_H
 #define GRPC_CORE_LIB_IOMGR_WAKEUP_FD_POSIX_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/error.h"
 
 void grpc_wakeup_fd_global_init(void);
diff --git a/src/core/lib/json/json.cc b/src/core/lib/json/json.cc
index 4ad51f6..816241b 100644
--- a/src/core/lib/json/json.cc
+++ b/src/core/lib/json/json.cc
@@ -16,14 +16,17 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <string.h>
 
 #include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
 
 #include "src/core/lib/json/json.h"
 
 grpc_json* grpc_json_create(grpc_json_type type) {
-  grpc_json* json = (grpc_json*)gpr_zalloc(sizeof(*json));
+  grpc_json* json = static_cast<grpc_json*>(gpr_zalloc(sizeof(*json)));
   json->type = type;
 
   return json;
@@ -44,5 +47,40 @@
     json->parent->child = json->next;
   }
 
+  if (json->owns_value) {
+    gpr_free((void*)json->value);
+  }
+
   gpr_free(json);
 }
+
+grpc_json* grpc_json_link_child(grpc_json* parent, grpc_json* child,
+                                grpc_json* sibling) {
+  // first child case.
+  if (parent->child == nullptr) {
+    GPR_ASSERT(sibling == nullptr);
+    parent->child = child;
+    return child;
+  }
+  if (sibling == nullptr) {
+    sibling = parent->child;
+  }
+  // always find the right most sibling.
+  while (sibling->next != nullptr) {
+    sibling = sibling->next;
+  }
+  sibling->next = child;
+  return child;
+}
+
+grpc_json* grpc_json_create_child(grpc_json* sibling, grpc_json* parent,
+                                  const char* key, const char* value,
+                                  grpc_json_type type, bool owns_value) {
+  grpc_json* child = grpc_json_create(type);
+  grpc_json_link_child(parent, child, sibling);
+  child->owns_value = owns_value;
+  child->parent = parent;
+  child->value = value;
+  child->key = key;
+  return child;
+}
diff --git a/src/core/lib/json/json.h b/src/core/lib/json/json.h
index bbd4302..f93b430 100644
--- a/src/core/lib/json/json.h
+++ b/src/core/lib/json/json.h
@@ -19,6 +19,9 @@
 #ifndef GRPC_CORE_LIB_JSON_JSON_H
 #define GRPC_CORE_LIB_JSON_JSON_H
 
+#include <grpc/support/port_platform.h>
+
+#include <stdbool.h>
 #include <stdlib.h>
 
 #include "src/core/lib/json/json_common.h"
@@ -35,6 +38,9 @@
   grpc_json_type type;
   const char* key;
   const char* value;
+
+  /* if set, destructor will free value */
+  bool owns_value;
 } grpc_json;
 
 /* The next two functions are going to parse the input string, and
@@ -65,9 +71,24 @@
 
 /* Use these to create or delete a grpc_json object.
  * Deletion is recursive. We will not attempt to free any of the strings
- * in any of the objects of that tree.
+ * in any of the objects of that tree, unless the boolean, owns_value,
+ * is true.
  */
 grpc_json* grpc_json_create(grpc_json_type type);
 void grpc_json_destroy(grpc_json* json);
 
+/* Links the child json object into the parent's json tree. If the parent
+ * already has children, then passing in the most recently added child as the
+ * sibling parameter is an optimization. For if sibling is NULL, this function
+ * will manually traverse the tree in order to find the right most sibling.
+ */
+grpc_json* grpc_json_link_child(grpc_json* parent, grpc_json* child,
+                                grpc_json* sibling);
+
+/* Creates a child json object into the parent's json tree then links it in
+ * as described above. */
+grpc_json* grpc_json_create_child(grpc_json* sibling, grpc_json* parent,
+                                  const char* key, const char* value,
+                                  grpc_json_type type, bool owns_value);
+
 #endif /* GRPC_CORE_LIB_JSON_JSON_H */
diff --git a/src/core/lib/json/json_reader.cc b/src/core/lib/json/json_reader.cc
index 3003941..819572e 100644
--- a/src/core/lib/json/json_reader.cc
+++ b/src/core/lib/json/json_reader.cc
@@ -16,10 +16,10 @@
  *
  */
 
-#include <string.h>
-
 #include <grpc/support/port_platform.h>
 
+#include <string.h>
+
 #include <grpc/support/log.h>
 
 #include "src/core/lib/json/json_reader.h"
@@ -138,7 +138,7 @@
           case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
           case GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
           case GRPC_JSON_STATE_VALUE_NUMBER_EPM:
-            success = (uint32_t)json_reader_set_number(reader);
+            success = static_cast<uint32_t>(json_reader_set_number(reader));
             if (!success) return GRPC_JSON_PARSE_ERROR;
             json_reader_string_clear(reader);
             reader->state = GRPC_JSON_STATE_VALUE_END;
@@ -173,7 +173,7 @@
             } else if ((c == ']') && !reader->in_array) {
               return GRPC_JSON_PARSE_ERROR;
             }
-            success = (uint32_t)json_reader_set_number(reader);
+            success = static_cast<uint32_t>(json_reader_set_number(reader));
             if (!success) return GRPC_JSON_PARSE_ERROR;
             json_reader_string_clear(reader);
             reader->state = GRPC_JSON_STATE_VALUE_END;
@@ -417,8 +417,10 @@
             } else {
               return GRPC_JSON_PARSE_ERROR;
             }
-            reader->unicode_char = (uint16_t)(reader->unicode_char << 4);
-            reader->unicode_char = (uint16_t)(reader->unicode_char | c);
+            reader->unicode_char =
+                static_cast<uint16_t>(reader->unicode_char << 4);
+            reader->unicode_char =
+                static_cast<uint16_t>(reader->unicode_char | c);
 
             switch (reader->state) {
               case GRPC_JSON_STATE_STRING_ESCAPE_U1:
@@ -445,9 +447,9 @@
                   if (reader->unicode_high_surrogate == 0)
                     return GRPC_JSON_PARSE_ERROR;
                   utf32 = 0x10000;
-                  utf32 += (uint32_t)(
+                  utf32 += static_cast<uint32_t>(
                       (reader->unicode_high_surrogate - 0xd800) * 0x400);
-                  utf32 += (uint32_t)(reader->unicode_char - 0xdc00);
+                  utf32 += static_cast<uint32_t>(reader->unicode_char - 0xdc00);
                   json_reader_string_add_utf32(reader, utf32);
                   reader->unicode_high_surrogate = 0;
                 } else {
diff --git a/src/core/lib/json/json_reader.h b/src/core/lib/json/json_reader.h
index 03185cb..78f7ad9 100644
--- a/src/core/lib/json/json_reader.h
+++ b/src/core/lib/json/json_reader.h
@@ -20,6 +20,7 @@
 #define GRPC_CORE_LIB_JSON_JSON_READER_H
 
 #include <grpc/support/port_platform.h>
+
 #include "src/core/lib/json/json_common.h"
 
 typedef enum {
diff --git a/src/core/lib/json/json_string.cc b/src/core/lib/json/json_string.cc
index a339eec..4f9175b 100644
--- a/src/core/lib/json/json_string.cc
+++ b/src/core/lib/json/json_string.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <stdlib.h>
 #include <string.h>
 
@@ -63,19 +65,20 @@
  * bytes at a time (or multiples thereof).
  */
 static void json_writer_output_check(void* userdata, size_t needed) {
-  json_writer_userdata* state = (json_writer_userdata*)userdata;
+  json_writer_userdata* state = static_cast<json_writer_userdata*>(userdata);
   if (state->free_space >= needed) return;
   needed -= state->free_space;
   /* Round up by 256 bytes. */
   needed = (needed + 0xff) & ~0xffU;
-  state->output = (char*)gpr_realloc(state->output, state->allocated + needed);
+  state->output =
+      static_cast<char*>(gpr_realloc(state->output, state->allocated + needed));
   state->free_space += needed;
   state->allocated += needed;
 }
 
 /* These are needed by the writer's implementation. */
 static void json_writer_output_char(void* userdata, char c) {
-  json_writer_userdata* state = (json_writer_userdata*)userdata;
+  json_writer_userdata* state = static_cast<json_writer_userdata*>(userdata);
   json_writer_output_check(userdata, 1);
   state->output[state->string_len++] = c;
   state->free_space--;
@@ -83,7 +86,7 @@
 
 static void json_writer_output_string_with_len(void* userdata, const char* str,
                                                size_t len) {
-  json_writer_userdata* state = (json_writer_userdata*)userdata;
+  json_writer_userdata* state = static_cast<json_writer_userdata*>(userdata);
   json_writer_output_check(userdata, len);
   memcpy(state->output + state->string_len, str, len);
   state->string_len += len;
@@ -99,7 +102,7 @@
  * the end of the current string, and advance our output pointer.
  */
 static void json_reader_string_clear(void* userdata) {
-  json_reader_userdata* state = (json_reader_userdata*)userdata;
+  json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
   if (state->string) {
     GPR_ASSERT(state->string_ptr < state->input);
     *state->string_ptr++ = 0;
@@ -108,10 +111,10 @@
 }
 
 static void json_reader_string_add_char(void* userdata, uint32_t c) {
-  json_reader_userdata* state = (json_reader_userdata*)userdata;
+  json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
   GPR_ASSERT(state->string_ptr < state->input);
   GPR_ASSERT(c <= 0xff);
-  *state->string_ptr++ = (uint8_t)c;
+  *state->string_ptr++ = static_cast<uint8_t>(c);
 }
 
 /* We are converting a UTF-32 character into UTF-8 here,
@@ -149,7 +152,7 @@
  */
 static uint32_t json_reader_read_char(void* userdata) {
   uint32_t r;
-  json_reader_userdata* state = (json_reader_userdata*)userdata;
+  json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
 
   if (state->remaining_input == 0) return GRPC_JSON_READ_CHAR_EOF;
 
@@ -168,7 +171,7 @@
  * our tree-in-progress inside our opaque structure.
  */
 static grpc_json* json_create_and_link(void* userdata, grpc_json_type type) {
-  json_reader_userdata* state = (json_reader_userdata*)userdata;
+  json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
   grpc_json* json = grpc_json_create(type);
 
   json->parent = state->current_container;
@@ -183,7 +186,7 @@
       json->parent->child = json;
     }
     if (json->parent->type == GRPC_JSON_OBJECT) {
-      json->key = (char*)state->key;
+      json->key = reinterpret_cast<char*>(state->key);
     }
   }
   if (!state->top) {
@@ -194,7 +197,7 @@
 }
 
 static void json_reader_container_begins(void* userdata, grpc_json_type type) {
-  json_reader_userdata* state = (json_reader_userdata*)userdata;
+  json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
   grpc_json* container;
 
   GPR_ASSERT(type == GRPC_JSON_ARRAY || type == GRPC_JSON_OBJECT);
@@ -215,7 +218,7 @@
  */
 static grpc_json_type json_reader_container_ends(void* userdata) {
   grpc_json_type container_type = GRPC_JSON_TOP_LEVEL;
-  json_reader_userdata* state = (json_reader_userdata*)userdata;
+  json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
 
   GPR_ASSERT(state->current_container);
 
@@ -236,20 +239,20 @@
  * We'll keep it as a string, and leave it to the caller to evaluate it.
  */
 static void json_reader_set_key(void* userdata) {
-  json_reader_userdata* state = (json_reader_userdata*)userdata;
+  json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
   state->key = state->string;
 }
 
 static void json_reader_set_string(void* userdata) {
-  json_reader_userdata* state = (json_reader_userdata*)userdata;
+  json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
   grpc_json* json = json_create_and_link(userdata, GRPC_JSON_STRING);
-  json->value = (char*)state->string;
+  json->value = reinterpret_cast<char*>(state->string);
 }
 
 static int json_reader_set_number(void* userdata) {
-  json_reader_userdata* state = (json_reader_userdata*)userdata;
+  json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
   grpc_json* json = json_create_and_link(userdata, GRPC_JSON_NUMBER);
-  json->value = (char*)state->string;
+  json->value = reinterpret_cast<char*>(state->string);
   return 1;
 }
 
@@ -287,7 +290,7 @@
 
   state.top = state.current_container = state.current_value = nullptr;
   state.string = state.key = nullptr;
-  state.string_ptr = state.input = (uint8_t*)input;
+  state.string_ptr = state.input = reinterpret_cast<uint8_t*>(input);
   state.remaining_input = size;
   grpc_json_reader_init(&reader, &reader_vtable, &state);
 
diff --git a/src/core/lib/json/json_writer.cc b/src/core/lib/json/json_writer.cc
index 0b9c7c3..7bbdccc 100644
--- a/src/core/lib/json/json_writer.cc
+++ b/src/core/lib/json/json_writer.cc
@@ -16,10 +16,10 @@
  *
  */
 
-#include <string.h>
-
 #include <grpc/support/port_platform.h>
 
+#include <string.h>
+
 #include "src/core/lib/json/json_writer.h"
 
 static void json_writer_output_char(grpc_json_writer* writer, char c) {
@@ -52,7 +52,7 @@
       "                "
       "                ";
 
-  unsigned spaces = (unsigned)(writer->depth * writer->indent);
+  unsigned spaces = static_cast<unsigned>(writer->depth * writer->indent);
 
   if (writer->indent == 0) return;
 
@@ -64,7 +64,7 @@
   while (spaces >= (sizeof(spacesstr) - 1)) {
     json_writer_output_string_with_len(writer, spacesstr,
                                        sizeof(spacesstr) - 1);
-    spaces -= (unsigned)(sizeof(spacesstr) - 1);
+    spaces -= static_cast<unsigned>(sizeof(spacesstr) - 1);
   }
 
   if (spaces == 0) return;
@@ -100,12 +100,12 @@
   json_writer_output_char(writer, '"');
 
   for (;;) {
-    uint8_t c = (uint8_t)*string++;
+    uint8_t c = static_cast<uint8_t>(*string++);
     if (c == 0) {
       break;
     } else if ((c >= 32) && (c <= 126)) {
       if ((c == '\\') || (c == '"')) json_writer_output_char(writer, '\\');
-      json_writer_output_char(writer, (char)c);
+      json_writer_output_char(writer, static_cast<char>(c));
     } else if ((c < 32) || (c == 127)) {
       switch (c) {
         case '\b':
@@ -146,7 +146,7 @@
       }
       for (i = 0; i < extra; i++) {
         utf32 <<= 6;
-        c = (uint8_t)(*string++);
+        c = static_cast<uint8_t>(*string++);
         /* Breaks out and bail on any invalid UTF-8 sequence, including \0. */
         if ((c & 0xc0) != 0x80) {
           valid = 0;
@@ -179,10 +179,12 @@
          * That range is exactly 20 bits.
          */
         utf32 -= 0x10000;
-        json_writer_escape_utf16(writer, (uint16_t)(0xd800 | (utf32 >> 10)));
-        json_writer_escape_utf16(writer, (uint16_t)(0xdc00 | (utf32 & 0x3ff)));
+        json_writer_escape_utf16(writer,
+                                 static_cast<uint16_t>(0xd800 | (utf32 >> 10)));
+        json_writer_escape_utf16(
+            writer, static_cast<uint16_t>(0xdc00 | (utf32 & 0x3ff)));
       } else {
-        json_writer_escape_utf16(writer, (uint16_t)utf32);
+        json_writer_escape_utf16(writer, static_cast<uint16_t>(utf32));
       }
     }
   }
diff --git a/src/core/lib/json/json_writer.h b/src/core/lib/json/json_writer.h
index a4f2d4d..ba0bedd 100644
--- a/src/core/lib/json/json_writer.h
+++ b/src/core/lib/json/json_writer.h
@@ -31,6 +31,8 @@
 #ifndef GRPC_CORE_LIB_JSON_JSON_WRITER_H
 #define GRPC_CORE_LIB_JSON_JSON_WRITER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stdlib.h>
 
 #include "src/core/lib/json/json_common.h"
diff --git a/src/core/lib/profiling/basic_timers.cc b/src/core/lib/profiling/basic_timers.cc
index d1c9fd7..652a498 100644
--- a/src/core/lib/profiling/basic_timers.cc
+++ b/src/core/lib/profiling/basic_timers.cc
@@ -25,8 +25,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -68,7 +68,7 @@
 static gpr_timer_log_list g_in_progress_logs;
 static gpr_timer_log_list g_done_logs;
 static int g_shutdown;
-static gpr_thd_id g_writing_thread;
+static pthread_t g_writing_thread;
 static __thread int g_thread_id;
 static int g_next_thread_id;
 static int g_writing_enabled = 1;
@@ -149,7 +149,7 @@
   }
 }
 
-static void writing_thread(void* unused) {
+static void* writing_thread(void* unused) {
   gpr_timer_log* log;
   pthread_mutex_lock(&g_mu);
   for (;;) {
@@ -164,7 +164,7 @@
     }
     if (g_shutdown) {
       pthread_mutex_unlock(&g_mu);
-      return;
+      return NULL;
     }
   }
 }
@@ -182,7 +182,7 @@
   g_shutdown = 1;
   pthread_cond_signal(&g_cv);
   pthread_mutex_unlock(&g_mu);
-  gpr_thd_join(g_writing_thread);
+  pthread_join(g_writing_thread, NULL);
 
   gpr_log(GPR_INFO, "flushing logs");
 
@@ -201,10 +201,12 @@
 }
 
 static void init_output() {
-  gpr_thd_options options = gpr_thd_options_default();
-  gpr_thd_options_set_joinable(&options);
-  GPR_ASSERT(gpr_thd_new(&g_writing_thread, "timer_output_thread",
-                         writing_thread, NULL, &options));
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+  pthread_create(&g_writing_thread, &attr, &writing_thread, NULL);
+  pthread_attr_destroy(&attr);
+
   atexit(finish_writing);
 }
 
diff --git a/src/core/lib/profiling/timers.h b/src/core/lib/profiling/timers.h
index d0188b5..7ff7278 100644
--- a/src/core/lib/profiling/timers.h
+++ b/src/core/lib/profiling/timers.h
@@ -82,9 +82,12 @@
 };
 }  // namespace grpc
 
-#define GPR_TIMER_SCOPE(tag, important)                                        \
-  ::grpc::ProfileScope _profile_scope_##__LINE__((tag), (important), __FILE__, \
-                                                 __LINE__)
+#define GPR_TIMER_SCOPE_NAME_INTERNAL(prefix, line) prefix##line
+#define GPR_TIMER_SCOPE_NAME(prefix, line) \
+  GPR_TIMER_SCOPE_NAME_INTERNAL(prefix, line)
+#define GPR_TIMER_SCOPE(tag, important)                                 \
+  ::grpc::ProfileScope GPR_TIMER_SCOPE_NAME(_profile_scope_, __LINE__)( \
+      (tag), (important), __FILE__, __LINE__)
 
 #endif /* at least one profiler requested. */
 
diff --git a/src/core/lib/security/context/security_context.cc b/src/core/lib/security/context/security_context.cc
index 63ec42c..14051a3 100644
--- a/src/core/lib/security/context/security_context.cc
+++ b/src/core/lib/security/context/security_context.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <string.h>
 
 #include "src/core/lib/channel/channel_args.h"
@@ -44,8 +46,8 @@
     gpr_log(GPR_ERROR, "Method is client-side only.");
     return GRPC_CALL_ERROR_NOT_ON_SERVER;
   }
-  ctx = (grpc_client_security_context*)grpc_call_context_get(
-      call, GRPC_CONTEXT_SECURITY);
+  ctx = static_cast<grpc_client_security_context*>(
+      grpc_call_context_get(call, GRPC_CONTEXT_SECURITY));
   if (ctx == nullptr) {
     ctx = grpc_client_security_context_create();
     ctx->creds = grpc_call_credentials_ref(creds);
@@ -80,13 +82,14 @@
 /* --- grpc_client_security_context --- */
 
 grpc_client_security_context* grpc_client_security_context_create(void) {
-  return (grpc_client_security_context*)gpr_zalloc(
-      sizeof(grpc_client_security_context));
+  return static_cast<grpc_client_security_context*>(
+      gpr_zalloc(sizeof(grpc_client_security_context)));
 }
 
 void grpc_client_security_context_destroy(void* ctx) {
   grpc_core::ExecCtx exec_ctx;
-  grpc_client_security_context* c = (grpc_client_security_context*)ctx;
+  grpc_client_security_context* c =
+      static_cast<grpc_client_security_context*>(ctx);
   grpc_call_credentials_unref(c->creds);
   GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "client_security_context");
   if (c->extension.instance != nullptr && c->extension.destroy != nullptr) {
@@ -98,12 +101,13 @@
 /* --- grpc_server_security_context --- */
 
 grpc_server_security_context* grpc_server_security_context_create(void) {
-  return (grpc_server_security_context*)gpr_zalloc(
-      sizeof(grpc_server_security_context));
+  return static_cast<grpc_server_security_context*>(
+      gpr_zalloc(sizeof(grpc_server_security_context)));
 }
 
 void grpc_server_security_context_destroy(void* ctx) {
-  grpc_server_security_context* c = (grpc_server_security_context*)ctx;
+  grpc_server_security_context* c =
+      static_cast<grpc_server_security_context*>(ctx);
   GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "server_security_context");
   if (c->extension.instance != nullptr && c->extension.destroy != nullptr) {
     c->extension.destroy(c->extension.instance);
@@ -117,7 +121,7 @@
 
 grpc_auth_context* grpc_auth_context_create(grpc_auth_context* chained) {
   grpc_auth_context* ctx =
-      (grpc_auth_context*)gpr_zalloc(sizeof(grpc_auth_context));
+      static_cast<grpc_auth_context*>(gpr_zalloc(sizeof(grpc_auth_context)));
   gpr_ref_init(&ctx->refcount, 1);
   if (chained != nullptr) {
     ctx->chained = GRPC_AUTH_CONTEXT_REF(chained, "chained");
@@ -258,9 +262,9 @@
   if (ctx->properties.count == ctx->properties.capacity) {
     ctx->properties.capacity =
         GPR_MAX(ctx->properties.capacity + 8, ctx->properties.capacity * 2);
-    ctx->properties.array = (grpc_auth_property*)gpr_realloc(
-        ctx->properties.array,
-        ctx->properties.capacity * sizeof(grpc_auth_property));
+    ctx->properties.array = static_cast<grpc_auth_property*>(
+        gpr_realloc(ctx->properties.array,
+                    ctx->properties.capacity * sizeof(grpc_auth_property)));
   }
 }
 
@@ -276,7 +280,7 @@
   ensure_auth_context_capacity(ctx);
   prop = &ctx->properties.array[ctx->properties.count++];
   prop->name = gpr_strdup(name);
-  prop->value = (char*)gpr_malloc(value_length + 1);
+  prop->value = static_cast<char*>(gpr_malloc(value_length + 1));
   memcpy(prop->value, value, value_length);
   prop->value[value_length] = '\0';
   prop->value_length = value_length;
@@ -329,7 +333,7 @@
             GRPC_AUTH_CONTEXT_ARG);
     return nullptr;
   }
-  return (grpc_auth_context*)arg->value.pointer.p;
+  return static_cast<grpc_auth_context*>(arg->value.pointer.p);
 }
 
 grpc_auth_context* grpc_find_auth_context_in_args(
diff --git a/src/core/lib/security/context/security_context.h b/src/core/lib/security/context/security_context.h
index 34f8c24..e782e4f 100644
--- a/src/core/lib/security/context/security_context.h
+++ b/src/core/lib/security/context/security_context.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SECURITY_CONTEXT_SECURITY_CONTEXT_H
 #define GRPC_CORE_LIB_SECURITY_CONTEXT_SECURITY_CONTEXT_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/pollset.h"
 #include "src/core/lib/security/credentials/credentials.h"
 
diff --git a/src/core/lib/security/credentials/alts/alts_credentials.cc b/src/core/lib/security/credentials/alts/alts_credentials.cc
new file mode 100644
index 0000000..fa05d90
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/alts_credentials.cc
@@ -0,0 +1,119 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/lib/security/credentials/alts/alts_credentials.h"
+
+#include <cstring>
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/security/credentials/alts/check_gcp_environment.h"
+#include "src/core/lib/security/security_connector/alts_security_connector.h"
+
+#define GRPC_CREDENTIALS_TYPE_ALTS "Alts"
+#define GRPC_ALTS_HANDSHAKER_SERVICE_URL "metadata.google.internal:8080"
+
+static void alts_credentials_destruct(grpc_channel_credentials* creds) {
+  grpc_alts_credentials* alts_creds =
+      reinterpret_cast<grpc_alts_credentials*>(creds);
+  grpc_alts_credentials_options_destroy(alts_creds->options);
+  gpr_free(alts_creds->handshaker_service_url);
+}
+
+static void alts_server_credentials_destruct(grpc_server_credentials* creds) {
+  grpc_alts_server_credentials* alts_creds =
+      reinterpret_cast<grpc_alts_server_credentials*>(creds);
+  grpc_alts_credentials_options_destroy(alts_creds->options);
+  gpr_free(alts_creds->handshaker_service_url);
+}
+
+static grpc_security_status alts_create_security_connector(
+    grpc_channel_credentials* creds,
+    grpc_call_credentials* request_metadata_creds, const char* target_name,
+    const grpc_channel_args* args, grpc_channel_security_connector** sc,
+    grpc_channel_args** new_args) {
+  return grpc_alts_channel_security_connector_create(
+      creds, request_metadata_creds, target_name, sc);
+}
+
+static grpc_security_status alts_server_create_security_connector(
+    grpc_server_credentials* creds, grpc_server_security_connector** sc) {
+  return grpc_alts_server_security_connector_create(creds, sc);
+}
+
+static const grpc_channel_credentials_vtable alts_credentials_vtable = {
+    alts_credentials_destruct, alts_create_security_connector,
+    /*duplicate_without_call_credentials=*/nullptr};
+
+static const grpc_server_credentials_vtable alts_server_credentials_vtable = {
+    alts_server_credentials_destruct, alts_server_create_security_connector};
+
+grpc_channel_credentials* grpc_alts_credentials_create_customized(
+    const grpc_alts_credentials_options* options,
+    const char* handshaker_service_url, bool enable_untrusted_alts) {
+  if (!enable_untrusted_alts && !grpc_alts_is_running_on_gcp()) {
+    return nullptr;
+  }
+  auto creds = static_cast<grpc_alts_credentials*>(
+      gpr_zalloc(sizeof(grpc_alts_credentials)));
+  creds->options = grpc_alts_credentials_options_copy(options);
+  creds->handshaker_service_url =
+      handshaker_service_url == nullptr
+          ? gpr_strdup(GRPC_ALTS_HANDSHAKER_SERVICE_URL)
+          : gpr_strdup(handshaker_service_url);
+  creds->base.type = GRPC_CREDENTIALS_TYPE_ALTS;
+  creds->base.vtable = &alts_credentials_vtable;
+  gpr_ref_init(&creds->base.refcount, 1);
+  return &creds->base;
+}
+
+grpc_server_credentials* grpc_alts_server_credentials_create_customized(
+    const grpc_alts_credentials_options* options,
+    const char* handshaker_service_url, bool enable_untrusted_alts) {
+  if (!enable_untrusted_alts && !grpc_alts_is_running_on_gcp()) {
+    return nullptr;
+  }
+  auto creds = static_cast<grpc_alts_server_credentials*>(
+      gpr_zalloc(sizeof(grpc_alts_server_credentials)));
+  creds->options = grpc_alts_credentials_options_copy(options);
+  creds->handshaker_service_url =
+      handshaker_service_url == nullptr
+          ? gpr_strdup(GRPC_ALTS_HANDSHAKER_SERVICE_URL)
+          : gpr_strdup(handshaker_service_url);
+  creds->base.type = GRPC_CREDENTIALS_TYPE_ALTS;
+  creds->base.vtable = &alts_server_credentials_vtable;
+  gpr_ref_init(&creds->base.refcount, 1);
+  return &creds->base;
+}
+
+grpc_channel_credentials* grpc_alts_credentials_create(
+    const grpc_alts_credentials_options* options) {
+  return grpc_alts_credentials_create_customized(
+      options, GRPC_ALTS_HANDSHAKER_SERVICE_URL, false);
+}
+
+grpc_server_credentials* grpc_alts_server_credentials_create(
+    const grpc_alts_credentials_options* options) {
+  return grpc_alts_server_credentials_create_customized(
+      options, GRPC_ALTS_HANDSHAKER_SERVICE_URL, false);
+}
diff --git a/src/core/lib/security/credentials/alts/alts_credentials.h b/src/core/lib/security/credentials/alts/alts_credentials.h
new file mode 100644
index 0000000..621789c
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/alts_credentials.h
@@ -0,0 +1,102 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_ALTS_CREDENTIALS_H
+#define GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_ALTS_CREDENTIALS_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/grpc_security.h>
+
+#include "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h"
+#include "src/core/lib/security/credentials/credentials.h"
+
+/* Main struct for grpc ALTS channel credential. */
+typedef struct grpc_alts_credentials {
+  grpc_channel_credentials base;
+  grpc_alts_credentials_options* options;
+  char* handshaker_service_url;
+} grpc_alts_credentials;
+
+/* Main struct for grpc ALTS server credential. */
+typedef struct grpc_alts_server_credentials {
+  grpc_server_credentials base;
+  grpc_alts_credentials_options* options;
+  char* handshaker_service_url;
+} grpc_alts_server_credentials;
+
+/**
+ * This method creates an ALTS channel credential object.
+ *
+ * - options: grpc ALTS credentials options instance for client.
+ *
+ * It returns the created ALTS channel credential object.
+ */
+grpc_channel_credentials* grpc_alts_credentials_create(
+    const grpc_alts_credentials_options* options);
+
+/**
+ * This method creates an ALTS server credential object.
+ *
+ * - options: grpc ALTS credentials options instance for server.
+ *
+ * It returns the created ALTS server credential object.
+ */
+grpc_server_credentials* grpc_alts_server_credentials_create(
+    const grpc_alts_credentials_options* options);
+
+/**
+ * This method creates an ALTS channel credential object with customized
+ * information provided by caller.
+ *
+ * - options: grpc ALTS credentials options instance for client.
+ * - handshaker_service_url: address of ALTS handshaker service in the format of
+ *   "host:port". If it's nullptr, the address of default metadata server will
+ *   be used.
+ * - enable_untrusted_alts: a boolean flag used to enable ALTS in untrusted
+ *   mode. This mode can be enabled when we are sure ALTS is running on GCP or
+ * for testing purpose.
+ *
+ * It returns nullptr if the flag is disabled AND ALTS is not running on GCP.
+ * Otherwise, it returns the created credential object.
+ */
+
+grpc_channel_credentials* grpc_alts_credentials_create_customized(
+    const grpc_alts_credentials_options* options,
+    const char* handshaker_service_url, bool enable_untrusted_alts);
+
+/**
+ * This method creates an ALTS server credential object with customized
+ * information provided by caller.
+ *
+ * - options: grpc ALTS credentials options instance for server.
+ * - handshaker_service_url: address of ALTS handshaker service in the format of
+ *   "host:port". If it's nullptr, the address of default metadata server will
+ *   be used.
+ * - enable_untrusted_alts: a boolean flag used to enable ALTS in untrusted
+ *   mode. This mode can be enabled when we are sure ALTS is running on GCP or
+ * for testing purpose.
+ *
+ * It returns nullptr if the flag is disabled and ALTS is not running on GCP.
+ * Otherwise, it returns the created credential object.
+ */
+grpc_server_credentials* grpc_alts_server_credentials_create_customized(
+    const grpc_alts_credentials_options* options,
+    const char* handshaker_service_url, bool enable_untrusted_alts);
+
+#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_ALTS_CREDENTIALS_H */
diff --git a/src/core/lib/security/credentials/alts/check_gcp_environment.cc b/src/core/lib/security/credentials/alts/check_gcp_environment.cc
new file mode 100644
index 0000000..9680787
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/check_gcp_environment.cc
@@ -0,0 +1,72 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/lib/security/credentials/alts/check_gcp_environment.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+const size_t kBiosDataBufferSize = 256;
+
+static char* trim(const char* src) {
+  if (src == nullptr) {
+    return nullptr;
+  }
+  char* des = nullptr;
+  size_t start = 0, end = strlen(src) - 1;
+  /* find the last character that is not a whitespace. */
+  while (end != 0 && isspace(src[end])) {
+    end--;
+  }
+  /* find the first character that is not a whitespace. */
+  while (start < strlen(src) && isspace(src[start])) {
+    start++;
+  }
+  if (start <= end) {
+    des = static_cast<char*>(
+        gpr_zalloc(sizeof(char) * (end - start + 2 /* '\0' */)));
+    memcpy(des, src + start, end - start + 1);
+  }
+  return des;
+}
+
+namespace grpc_core {
+namespace internal {
+
+char* read_bios_file(const char* bios_file) {
+  FILE* fp = fopen(bios_file, "r");
+  if (!fp) {
+    gpr_log(GPR_ERROR, "BIOS data file cannot be opened.");
+    return nullptr;
+  }
+  char buf[kBiosDataBufferSize + 1];
+  size_t ret = fread(buf, sizeof(char), kBiosDataBufferSize, fp);
+  buf[ret] = '\0';
+  char* trimmed_buf = trim(buf);
+  fclose(fp);
+  return trimmed_buf;
+}
+
+}  // namespace internal
+}  // namespace grpc_core
diff --git a/src/core/lib/security/credentials/alts/check_gcp_environment.h b/src/core/lib/security/credentials/alts/check_gcp_environment.h
new file mode 100644
index 0000000..aea4cea
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/check_gcp_environment.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_CHECK_GCP_ENVIRONMENT_H
+#define GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_CHECK_GCP_ENVIRONMENT_H
+
+namespace grpc_core {
+namespace internal {
+
+/**
+ * This method is a helper function that reads a file containing system bios
+ * data. Exposed for testing only.
+ *
+ * - bios_file: a file containing BIOS data used to determine GCE tenancy
+ *   information.
+ *
+ * It returns a buffer containing the data read from the file.
+ */
+char* read_bios_file(const char* bios_file);
+
+/**
+ * This method checks if system BIOS data contains Google-specific phrases.
+ * Exposed for testing only.
+ *
+ * - bios_data: a buffer containing system BIOS data.
+ *
+ * It returns true if the BIOS data contains Google-specific phrases, and false
+ * otherwise.
+ */
+bool check_bios_data(const char* bios_data);
+
+}  // namespace internal
+}  // namespace grpc_core
+
+/**
+ * This method checks if a VM (Windows or Linux) is running within Google
+ * compute Engine (GCE) or not. It returns true if the VM is running in GCE and
+ * false otherwise.
+ */
+bool grpc_alts_is_running_on_gcp();
+
+#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_CHECK_GCP_ENVIRONMENT_H */
diff --git a/src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc b/src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc
new file mode 100644
index 0000000..7c4d7a7
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc
@@ -0,0 +1,67 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#ifdef GPR_LINUX
+
+#include "src/core/lib/security/credentials/alts/check_gcp_environment.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/sync.h>
+
+#include <string.h>
+
+#define GRPC_ALTS_EXPECT_NAME_GOOGLE "Google"
+#define GRPC_ALTS_EXPECT_NAME_GCE "Google Compute Engine"
+#define GRPC_ALTS_PRODUCT_NAME_FILE "/sys/class/dmi/id/product_name"
+
+static bool g_compute_engine_detection_done = false;
+static bool g_is_on_compute_engine = false;
+static gpr_mu g_mu;
+static gpr_once g_once = GPR_ONCE_INIT;
+
+namespace grpc_core {
+namespace internal {
+
+bool check_bios_data(const char* bios_data_file) {
+  char* bios_data = read_bios_file(bios_data_file);
+  bool result = (!strcmp(bios_data, GRPC_ALTS_EXPECT_NAME_GOOGLE)) ||
+                (!strcmp(bios_data, GRPC_ALTS_EXPECT_NAME_GCE));
+  gpr_free(bios_data);
+  return result;
+}
+
+}  // namespace internal
+}  // namespace grpc_core
+
+static void init_mu(void) { gpr_mu_init(&g_mu); }
+
+bool grpc_alts_is_running_on_gcp() {
+  gpr_once_init(&g_once, init_mu);
+  gpr_mu_lock(&g_mu);
+  if (!g_compute_engine_detection_done) {
+    g_is_on_compute_engine =
+        grpc_core::internal::check_bios_data(GRPC_ALTS_PRODUCT_NAME_FILE);
+    g_compute_engine_detection_done = true;
+  }
+  gpr_mu_unlock(&g_mu);
+  return g_is_on_compute_engine;
+}
+
+#endif  // GPR_LINUX
diff --git a/src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc b/src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc
new file mode 100644
index 0000000..d97681b
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc
@@ -0,0 +1,33 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#if !defined(GPR_LINUX) && !defined(GPR_WINDOWS)
+
+#include "src/core/lib/security/credentials/alts/check_gcp_environment.h"
+
+#include <grpc/support/log.h>
+
+bool grpc_alts_is_running_on_gcp() {
+  gpr_log(GPR_ERROR,
+          "Platforms other than Linux and Windows are not supported");
+  return false;
+}
+
+#endif  // !defined(LINUX) && !defined(GPR_WINDOWS)
diff --git a/src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc b/src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc
new file mode 100644
index 0000000..55efe0e
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc
@@ -0,0 +1,114 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#ifdef GPR_WINDOWS
+
+#include "src/core/lib/security/credentials/alts/check_gcp_environment.h"
+
+#include <shellapi.h>
+#include <stdio.h>
+#include <tchar.h>
+#include <windows.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+
+#define GRPC_ALTS_EXPECT_NAME_GOOGLE "Google"
+#define GRPC_ALTS_WINDOWS_CHECK_COMMAND "powershell.exe"
+#define GRPC_ALTS_WINDOWS_CHECK_COMMAND_ARGS \
+  "(Get-WmiObject -Class Win32_BIOS).Manufacturer"
+#define GRPC_ALTS_WINDOWS_CHECK_BIOS_FILE "windows_bios.data"
+
+const size_t kBiosDataBufferSize = 256;
+
+static bool g_compute_engine_detection_done = false;
+static bool g_is_on_compute_engine = false;
+static gpr_mu g_mu;
+static gpr_once g_once = GPR_ONCE_INIT;
+
+namespace grpc_core {
+namespace internal {
+
+bool check_bios_data(const char* bios_data_file) {
+  char* bios_data = read_bios_file(bios_data_file);
+  bool result = !strcmp(bios_data, GRPC_ALTS_EXPECT_NAME_GOOGLE);
+  remove(GRPC_ALTS_WINDOWS_CHECK_BIOS_FILE);
+  gpr_free(bios_data);
+  return result;
+}
+
+}  // namespace internal
+}  // namespace grpc_core
+
+static void init_mu(void) { gpr_mu_init(&g_mu); }
+
+static bool run_powershell() {
+  SECURITY_ATTRIBUTES sa;
+  sa.nLength = sizeof(sa);
+  sa.lpSecurityDescriptor = NULL;
+  sa.bInheritHandle = TRUE;
+  HANDLE h = CreateFile(_T(GRPC_ALTS_WINDOWS_CHECK_BIOS_FILE), GENERIC_WRITE,
+                        FILE_SHARE_WRITE | FILE_SHARE_READ, &sa, OPEN_ALWAYS,
+                        FILE_ATTRIBUTE_NORMAL, NULL);
+  if (h == INVALID_HANDLE_VALUE) {
+    gpr_log(GPR_ERROR, "CreateFile failed (%d).", GetLastError());
+    return false;
+  }
+  PROCESS_INFORMATION pi;
+  STARTUPINFO si;
+  DWORD flags = CREATE_NO_WINDOW;
+  ZeroMemory(&pi, sizeof(pi));
+  ZeroMemory(&si, sizeof(si));
+  si.cb = sizeof(si);
+  si.dwFlags |= STARTF_USESTDHANDLES;
+  si.hStdInput = NULL;
+  si.hStdError = h;
+  si.hStdOutput = h;
+  TCHAR cmd[kBiosDataBufferSize];
+  _sntprintf(cmd, kBiosDataBufferSize, _T("%s %s"),
+             _T(GRPC_ALTS_WINDOWS_CHECK_COMMAND),
+             _T(GRPC_ALTS_WINDOWS_CHECK_COMMAND_ARGS));
+  if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, flags, NULL, NULL, &si,
+                     &pi)) {
+    gpr_log(GPR_ERROR, "CreateProcess failed (%d).\n", GetLastError());
+    return false;
+  }
+  WaitForSingleObject(pi.hProcess, INFINITE);
+  CloseHandle(pi.hProcess);
+  CloseHandle(pi.hThread);
+  CloseHandle(h);
+  return true;
+}
+
+bool grpc_alts_is_running_on_gcp() {
+  gpr_once_init(&g_once, init_mu);
+  gpr_mu_lock(&g_mu);
+  if (!g_compute_engine_detection_done) {
+    g_is_on_compute_engine =
+        run_powershell() &&
+        grpc_core::internal::check_bios_data(GRPC_ALTS_WINDOWS_CHECK_BIOS_FILE);
+    g_compute_engine_detection_done = true;
+  }
+  gpr_mu_unlock(&g_mu);
+  return g_is_on_compute_engine;
+}
+
+#endif  // GPR_WINDOWS
diff --git a/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc b/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc
new file mode 100644
index 0000000..7d54e83
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc
@@ -0,0 +1,126 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h"
+#include "src/core/tsi/alts/handshaker/transport_security_common_api.h"
+
+static grpc_alts_credentials_options* alts_client_options_copy(
+    const grpc_alts_credentials_options* options);
+
+static void alts_client_options_destroy(grpc_alts_credentials_options* options);
+
+static target_service_account* target_service_account_create(
+    const char* service_account) {
+  if (service_account == nullptr) {
+    return nullptr;
+  }
+  auto* sa = static_cast<target_service_account*>(
+      gpr_zalloc(sizeof(target_service_account)));
+  sa->data = gpr_strdup(service_account);
+  return sa;
+}
+
+bool grpc_alts_credentials_client_options_add_target_service_account(
+    grpc_alts_credentials_client_options* options,
+    const char* service_account) {
+  if (options == nullptr || service_account == nullptr) {
+    gpr_log(
+        GPR_ERROR,
+        "Invalid nullptr arguments to "
+        "grpc_alts_credentials_client_options_add_target_service_account()");
+    return false;
+  }
+  target_service_account* node = target_service_account_create(service_account);
+  node->next = options->target_account_list_head;
+  options->target_account_list_head = node;
+  return true;
+}
+
+static void target_service_account_destroy(
+    target_service_account* service_account) {
+  if (service_account == nullptr) {
+    return;
+  }
+  gpr_free(service_account->data);
+  gpr_free(service_account);
+}
+
+static const grpc_alts_credentials_options_vtable vtable = {
+    alts_client_options_copy, alts_client_options_destroy};
+
+grpc_alts_credentials_options* grpc_alts_credentials_client_options_create() {
+  auto client_options = static_cast<grpc_alts_credentials_client_options*>(
+      gpr_zalloc(sizeof(grpc_alts_credentials_client_options)));
+  client_options->base.vtable = &vtable;
+  return &client_options->base;
+}
+
+static grpc_alts_credentials_options* alts_client_options_copy(
+    const grpc_alts_credentials_options* options) {
+  if (options == nullptr) {
+    return nullptr;
+  }
+  grpc_alts_credentials_options* new_options =
+      grpc_alts_credentials_client_options_create();
+  auto new_client_options =
+      reinterpret_cast<grpc_alts_credentials_client_options*>(new_options);
+  /* Copy target service accounts. */
+  target_service_account* prev = nullptr;
+  auto node =
+      (reinterpret_cast<const grpc_alts_credentials_client_options*>(options))
+          ->target_account_list_head;
+  while (node != nullptr) {
+    target_service_account* new_node =
+        target_service_account_create(node->data);
+    if (prev == nullptr) {
+      new_client_options->target_account_list_head = new_node;
+    } else {
+      prev->next = new_node;
+    }
+    prev = new_node;
+    node = node->next;
+  }
+  /* Copy rpc protocol versions. */
+  grpc_gcp_rpc_protocol_versions_copy(&options->rpc_versions,
+                                      &new_options->rpc_versions);
+  return new_options;
+}
+
+static void alts_client_options_destroy(
+    grpc_alts_credentials_options* options) {
+  if (options == nullptr) {
+    return;
+  }
+  auto* client_options =
+      reinterpret_cast<grpc_alts_credentials_client_options*>(options);
+  target_service_account* node = client_options->target_account_list_head;
+  while (node != nullptr) {
+    target_service_account* next_node = node->next;
+    target_service_account_destroy(node);
+    node = next_node;
+  }
+}
diff --git a/src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc b/src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc
new file mode 100644
index 0000000..d428171
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc
@@ -0,0 +1,46 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+grpc_alts_credentials_options* grpc_alts_credentials_options_copy(
+    const grpc_alts_credentials_options* options) {
+  if (options != nullptr && options->vtable != nullptr &&
+      options->vtable->copy != nullptr) {
+    return options->vtable->copy(options);
+  }
+  /* An error occurred. */
+  gpr_log(GPR_ERROR,
+          "Invalid arguments to grpc_alts_credentials_options_copy()");
+  return nullptr;
+}
+
+void grpc_alts_credentials_options_destroy(
+    grpc_alts_credentials_options* options) {
+  if (options != nullptr) {
+    if (options->vtable != nullptr && options->vtable->destruct != nullptr) {
+      options->vtable->destruct(options);
+    }
+    gpr_free(options);
+  }
+}
diff --git a/src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h b/src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h
new file mode 100644
index 0000000..4e46d9f
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h
@@ -0,0 +1,112 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_GRPC_ALTS_CREDENTIALS_OPTIONS_H
+#define GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_GRPC_ALTS_CREDENTIALS_OPTIONS_H
+
+#include <grpc/support/port_platform.h>
+
+#include <stdbool.h>
+
+#include "src/core/tsi/alts/handshaker/transport_security_common_api.h"
+
+/**
+ * Main interface for ALTS credentials options. The options will contain
+ * information that will be passed from grpc to TSI layer such as RPC protocol
+ * versions. ALTS client (channel) and server credentials will have their own
+ * implementation of this interface. The APIs listed in this header are
+ * thread-compatible.
+ */
+typedef struct grpc_alts_credentials_options grpc_alts_credentials_options;
+
+/* V-table for grpc_alts_credentials_options */
+typedef struct grpc_alts_credentials_options_vtable {
+  grpc_alts_credentials_options* (*copy)(
+      const grpc_alts_credentials_options* options);
+  void (*destruct)(grpc_alts_credentials_options* options);
+} grpc_alts_credentials_options_vtable;
+
+struct grpc_alts_credentials_options {
+  const struct grpc_alts_credentials_options_vtable* vtable;
+  grpc_gcp_rpc_protocol_versions rpc_versions;
+};
+
+typedef struct target_service_account {
+  struct target_service_account* next;
+  char* data;
+} target_service_account;
+
+/**
+ * Main struct for ALTS client credentials options. The options contain a
+ * a list of target service accounts (if specified) used for secure naming
+ * check.
+ */
+typedef struct grpc_alts_credentials_client_options {
+  grpc_alts_credentials_options base;
+  target_service_account* target_account_list_head;
+} grpc_alts_credentials_client_options;
+
+/**
+ * Main struct for ALTS server credentials options. The options currently
+ * do not contain any server-specific fields.
+ */
+typedef struct grpc_alts_credentials_server_options {
+  grpc_alts_credentials_options base;
+} grpc_alts_credentials_server_options;
+
+/**
+ * This method performs a deep copy on grpc_alts_credentials_options instance.
+ *
+ * - options: a grpc_alts_credentials_options instance that needs to be copied.
+ *
+ * It returns a new grpc_alts_credentials_options instance on success and NULL
+ * on failure.
+ */
+grpc_alts_credentials_options* grpc_alts_credentials_options_copy(
+    const grpc_alts_credentials_options* options);
+
+/**
+ * This method destroys a grpc_alts_credentials_options instance by
+ * de-allocating all of its occupied memory.
+ *
+ * - options: a grpc_alts_credentials_options instance that needs to be
+ *   destroyed.
+ */
+void grpc_alts_credentials_options_destroy(
+    grpc_alts_credentials_options* options);
+
+/* This method creates a grpc ALTS credentials client options instance. */
+grpc_alts_credentials_options* grpc_alts_credentials_client_options_create();
+
+/* This method creates a grpc ALTS credentials server options instance. */
+grpc_alts_credentials_options* grpc_alts_credentials_server_options_create();
+
+/**
+ * This method adds a target service account to grpc ALTS credentials client
+ * options instance.
+ *
+ * - options: grpc ALTS credentials client options instance.
+ * - service_account: service account of target endpoint.
+ *
+ * It returns true on success and false on failure.
+ */
+bool grpc_alts_credentials_client_options_add_target_service_account(
+    grpc_alts_credentials_client_options* options, const char* service_account);
+
+#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_GRPC_ALTS_CREDENTIALS_OPTIONS_H \
+        */
diff --git a/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc b/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc
new file mode 100644
index 0000000..62aa7a6
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc
@@ -0,0 +1,58 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h"
+#include "src/core/tsi/alts/handshaker/transport_security_common_api.h"
+
+static grpc_alts_credentials_options* alts_server_options_copy(
+    const grpc_alts_credentials_options* options);
+
+static void alts_server_options_destroy(
+    grpc_alts_credentials_options* options) {}
+
+static const grpc_alts_credentials_options_vtable vtable = {
+    alts_server_options_copy, alts_server_options_destroy};
+
+grpc_alts_credentials_options* grpc_alts_credentials_server_options_create() {
+  grpc_alts_credentials_server_options* server_options =
+      static_cast<grpc_alts_credentials_server_options*>(
+          gpr_zalloc(sizeof(*server_options)));
+  server_options->base.vtable = &vtable;
+  return &server_options->base;
+}
+
+static grpc_alts_credentials_options* alts_server_options_copy(
+    const grpc_alts_credentials_options* options) {
+  if (options == nullptr) {
+    return nullptr;
+  }
+  grpc_alts_credentials_options* new_options =
+      grpc_alts_credentials_server_options_create();
+  /* Copy rpc protocol versions. */
+  grpc_gcp_rpc_protocol_versions_copy(&options->rpc_versions,
+                                      &new_options->rpc_versions);
+  return new_options;
+}
diff --git a/src/core/lib/security/credentials/composite/composite_credentials.cc b/src/core/lib/security/credentials/composite/composite_credentials.cc
index e4c1604..b8f4092 100644
--- a/src/core/lib/security/credentials/composite/composite_credentials.cc
+++ b/src/core/lib/security/credentials/composite/composite_credentials.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/credentials/composite/composite_credentials.h"
 
 #include <string.h>
@@ -40,7 +42,8 @@
 } grpc_composite_call_credentials_metadata_context;
 
 static void composite_call_destruct(grpc_call_credentials* creds) {
-  grpc_composite_call_credentials* c = (grpc_composite_call_credentials*)creds;
+  grpc_composite_call_credentials* c =
+      reinterpret_cast<grpc_composite_call_credentials*>(creds);
   for (size_t i = 0; i < c->inner.num_creds; i++) {
     grpc_call_credentials_unref(c->inner.creds_array[i]);
   }
@@ -49,7 +52,7 @@
 
 static void composite_call_metadata_cb(void* arg, grpc_error* error) {
   grpc_composite_call_credentials_metadata_context* ctx =
-      (grpc_composite_call_credentials_metadata_context*)arg;
+      static_cast<grpc_composite_call_credentials_metadata_context*>(arg);
   if (error == GRPC_ERROR_NONE) {
     /* See if we need to get some more metadata. */
     if (ctx->creds_index < ctx->composite_creds->inner.num_creds) {
@@ -75,10 +78,11 @@
     grpc_auth_metadata_context auth_md_context,
     grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata,
     grpc_error** error) {
-  grpc_composite_call_credentials* c = (grpc_composite_call_credentials*)creds;
+  grpc_composite_call_credentials* c =
+      reinterpret_cast<grpc_composite_call_credentials*>(creds);
   grpc_composite_call_credentials_metadata_context* ctx;
-  ctx = (grpc_composite_call_credentials_metadata_context*)gpr_zalloc(
-      sizeof(grpc_composite_call_credentials_metadata_context));
+  ctx = static_cast<grpc_composite_call_credentials_metadata_context*>(
+      gpr_zalloc(sizeof(grpc_composite_call_credentials_metadata_context)));
   ctx->composite_creds = c;
   ctx->pollent = pollent;
   ctx->auth_md_context = auth_md_context;
@@ -106,7 +110,8 @@
 static void composite_call_cancel_get_request_metadata(
     grpc_call_credentials* creds, grpc_credentials_mdelem_array* md_array,
     grpc_error* error) {
-  grpc_composite_call_credentials* c = (grpc_composite_call_credentials*)creds;
+  grpc_composite_call_credentials* c =
+      reinterpret_cast<grpc_composite_call_credentials*>(creds);
   for (size_t i = 0; i < c->inner.num_creds; ++i) {
     grpc_call_credentials_cancel_get_request_metadata(
         c->inner.creds_array[i], md_array, GRPC_ERROR_REF(error));
@@ -145,8 +150,8 @@
   GPR_ASSERT(reserved == nullptr);
   GPR_ASSERT(creds1 != nullptr);
   GPR_ASSERT(creds2 != nullptr);
-  c = (grpc_composite_call_credentials*)gpr_zalloc(
-      sizeof(grpc_composite_call_credentials));
+  c = static_cast<grpc_composite_call_credentials*>(
+      gpr_zalloc(sizeof(grpc_composite_call_credentials)));
   c->base.type = GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE;
   c->base.vtable = &composite_call_credentials_vtable;
   gpr_ref_init(&c->base.refcount, 1);
@@ -155,7 +160,7 @@
   c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds;
   creds_array_byte_size = c->inner.num_creds * sizeof(grpc_call_credentials*);
   c->inner.creds_array =
-      (grpc_call_credentials**)gpr_zalloc(creds_array_byte_size);
+      static_cast<grpc_call_credentials**>(gpr_zalloc(creds_array_byte_size));
   for (i = 0; i < creds1_array.num_creds; i++) {
     grpc_call_credentials* cur_creds = creds1_array.creds_array[i];
     c->inner.creds_array[i] = grpc_call_credentials_ref(cur_creds);
@@ -171,7 +176,7 @@
 const grpc_call_credentials_array*
 grpc_composite_call_credentials_get_credentials(grpc_call_credentials* creds) {
   const grpc_composite_call_credentials* c =
-      (const grpc_composite_call_credentials*)creds;
+      reinterpret_cast<const grpc_composite_call_credentials*>(creds);
   GPR_ASSERT(strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0);
   return &c->inner;
 }
@@ -200,7 +205,7 @@
 
 static void composite_channel_destruct(grpc_channel_credentials* creds) {
   grpc_composite_channel_credentials* c =
-      (grpc_composite_channel_credentials*)creds;
+      reinterpret_cast<grpc_composite_channel_credentials*>(creds);
   grpc_channel_credentials_unref(c->inner_creds);
   grpc_call_credentials_unref(c->call_creds);
 }
@@ -210,7 +215,7 @@
     const char* target, const grpc_channel_args* args,
     grpc_channel_security_connector** sc, grpc_channel_args** new_args) {
   grpc_composite_channel_credentials* c =
-      (grpc_composite_channel_credentials*)creds;
+      reinterpret_cast<grpc_composite_channel_credentials*>(creds);
   grpc_security_status status = GRPC_SECURITY_ERROR;
 
   GPR_ASSERT(c->inner_creds != nullptr && c->call_creds != nullptr &&
@@ -236,7 +241,7 @@
 composite_channel_duplicate_without_call_credentials(
     grpc_channel_credentials* creds) {
   grpc_composite_channel_credentials* c =
-      (grpc_composite_channel_credentials*)creds;
+      reinterpret_cast<grpc_composite_channel_credentials*>(creds);
   return grpc_channel_credentials_ref(c->inner_creds);
 }
 
@@ -248,7 +253,7 @@
     grpc_channel_credentials* channel_creds, grpc_call_credentials* call_creds,
     void* reserved) {
   grpc_composite_channel_credentials* c =
-      (grpc_composite_channel_credentials*)gpr_zalloc(sizeof(*c));
+      static_cast<grpc_composite_channel_credentials*>(gpr_zalloc(sizeof(*c)));
   GPR_ASSERT(channel_creds != nullptr && call_creds != nullptr &&
              reserved == nullptr);
   GRPC_API_TRACE(
diff --git a/src/core/lib/security/credentials/composite/composite_credentials.h b/src/core/lib/security/credentials/composite/composite_credentials.h
index 11990d3..a952ad5 100644
--- a/src/core/lib/security/credentials/composite/composite_credentials.h
+++ b/src/core/lib/security/credentials/composite/composite_credentials.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_COMPOSITE_COMPOSITE_CREDENTIALS_H
 #define GRPC_CORE_LIB_SECURITY_CREDENTIALS_COMPOSITE_COMPOSITE_CREDENTIALS_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/credentials/credentials.h"
 
 typedef struct {
diff --git a/src/core/lib/security/credentials/credentials.cc b/src/core/lib/security/credentials/credentials.cc
index 009a5ce..c43cb44 100644
--- a/src/core/lib/security/credentials/credentials.cc
+++ b/src/core/lib/security/credentials/credentials.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/credentials/credentials.h"
 
 #include <stdio.h>
@@ -40,8 +42,8 @@
 grpc_credentials_metadata_request* grpc_credentials_metadata_request_create(
     grpc_call_credentials* creds) {
   grpc_credentials_metadata_request* r =
-      (grpc_credentials_metadata_request*)gpr_zalloc(
-          sizeof(grpc_credentials_metadata_request));
+      static_cast<grpc_credentials_metadata_request*>(
+          gpr_zalloc(sizeof(grpc_credentials_metadata_request)));
   r->creds = grpc_call_credentials_ref(creds);
   return r;
 }
@@ -145,11 +147,12 @@
 }
 
 static void credentials_pointer_arg_destroy(void* p) {
-  grpc_channel_credentials_unref((grpc_channel_credentials*)p);
+  grpc_channel_credentials_unref(static_cast<grpc_channel_credentials*>(p));
 }
 
 static void* credentials_pointer_arg_copy(void* p) {
-  return grpc_channel_credentials_ref((grpc_channel_credentials*)p);
+  return grpc_channel_credentials_ref(
+      static_cast<grpc_channel_credentials*>(p));
 }
 
 static int credentials_pointer_cmp(void* a, void* b) { return GPR_ICMP(a, b); }
@@ -173,7 +176,7 @@
             GRPC_ARG_CHANNEL_CREDENTIALS);
     return nullptr;
   }
-  return (grpc_channel_credentials*)arg->value.pointer.p;
+  return static_cast<grpc_channel_credentials*>(arg->value.pointer.p);
 }
 
 grpc_channel_credentials* grpc_channel_credentials_find_in_args(
@@ -240,11 +243,11 @@
 }
 
 static void server_credentials_pointer_arg_destroy(void* p) {
-  grpc_server_credentials_unref((grpc_server_credentials*)p);
+  grpc_server_credentials_unref(static_cast<grpc_server_credentials*>(p));
 }
 
 static void* server_credentials_pointer_arg_copy(void* p) {
-  return grpc_server_credentials_ref((grpc_server_credentials*)p);
+  return grpc_server_credentials_ref(static_cast<grpc_server_credentials*>(p));
 }
 
 static int server_credentials_pointer_cmp(void* a, void* b) {
@@ -267,7 +270,7 @@
             GRPC_SERVER_CREDENTIALS_ARG);
     return nullptr;
   }
-  return (grpc_server_credentials*)arg->value.pointer.p;
+  return static_cast<grpc_server_credentials*>(arg->value.pointer.p);
 }
 
 grpc_server_credentials* grpc_find_server_credentials_in_args(
diff --git a/src/core/lib/security/credentials/credentials.h b/src/core/lib/security/credentials/credentials.h
index 4825b65..b1421e8 100644
--- a/src/core/lib/security/credentials/credentials.h
+++ b/src/core/lib/security/credentials/credentials.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_CREDENTIALS_H
 #define GRPC_CORE_LIB_SECURITY_CREDENTIALS_CREDENTIALS_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
 #include <grpc/support/sync.h>
@@ -27,7 +29,7 @@
 #include "src/core/lib/http/httpcli.h"
 #include "src/core/lib/http/parser.h"
 #include "src/core/lib/iomgr/polling_entity.h"
-#include "src/core/lib/security/transport/security_connector.h"
+#include "src/core/lib/security/security_connector/security_connector.h"
 
 struct grpc_http_response;
 
diff --git a/src/core/lib/security/credentials/credentials_metadata.cc b/src/core/lib/security/credentials/credentials_metadata.cc
index 9ceaf21..703de4a 100644
--- a/src/core/lib/security/credentials/credentials_metadata.cc
+++ b/src/core/lib/security/credentials/credentials_metadata.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/credentials/credentials.h"
 
 #include <grpc/support/alloc.h>
@@ -33,8 +35,8 @@
   while (new_size < target_size) {
     new_size *= 2;
   }
-  list->md =
-      (grpc_mdelem*)gpr_realloc(list->md, sizeof(grpc_mdelem) * new_size);
+  list->md = static_cast<grpc_mdelem*>(
+      gpr_realloc(list->md, sizeof(grpc_mdelem) * new_size));
 }
 
 void grpc_credentials_mdelem_array_add(grpc_credentials_mdelem_array* list,
diff --git a/src/core/lib/security/credentials/fake/fake_credentials.cc b/src/core/lib/security/credentials/fake/fake_credentials.cc
index 9065325..858ab6b 100644
--- a/src/core/lib/security/credentials/fake/fake_credentials.cc
+++ b/src/core/lib/security/credentials/fake/fake_credentials.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/credentials/fake/fake_credentials.h"
 
 #include <string.h>
@@ -30,9 +32,6 @@
 
 /* -- Fake transport security credentials. -- */
 
-#define GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS \
-  "grpc.fake_security.expected_targets"
-
 static grpc_security_status fake_transport_security_create_security_connector(
     grpc_channel_credentials* c, grpc_call_credentials* call_creds,
     const char* target, const grpc_channel_args* args,
@@ -59,8 +58,8 @@
 
 grpc_channel_credentials* grpc_fake_transport_security_credentials_create(
     void) {
-  grpc_channel_credentials* c =
-      (grpc_channel_credentials*)gpr_zalloc(sizeof(grpc_channel_credentials));
+  grpc_channel_credentials* c = static_cast<grpc_channel_credentials*>(
+      gpr_zalloc(sizeof(grpc_channel_credentials)));
   c->type = GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
   c->vtable = &fake_transport_security_credentials_vtable;
   gpr_ref_init(&c->refcount, 1);
@@ -69,8 +68,8 @@
 
 grpc_server_credentials* grpc_fake_transport_security_server_credentials_create(
     void) {
-  grpc_server_credentials* c =
-      (grpc_server_credentials*)gpr_malloc(sizeof(grpc_server_credentials));
+  grpc_server_credentials* c = static_cast<grpc_server_credentials*>(
+      gpr_malloc(sizeof(grpc_server_credentials)));
   memset(c, 0, sizeof(grpc_server_credentials));
   c->type = GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
   gpr_ref_init(&c->refcount, 1);
@@ -87,17 +86,14 @@
     const grpc_channel_args* args) {
   const grpc_arg* expected_target_arg =
       grpc_channel_args_find(args, GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS);
-  if (expected_target_arg != nullptr &&
-      expected_target_arg->type == GRPC_ARG_STRING) {
-    return expected_target_arg->value.string;
-  }
-  return nullptr;
+  return grpc_channel_arg_get_string(expected_target_arg);
 }
 
 /* -- Metadata-only test credentials. -- */
 
 static void md_only_test_destruct(grpc_call_credentials* creds) {
-  grpc_md_only_test_credentials* c = (grpc_md_only_test_credentials*)creds;
+  grpc_md_only_test_credentials* c =
+      reinterpret_cast<grpc_md_only_test_credentials*>(creds);
   GRPC_MDELEM_UNREF(c->md);
 }
 
@@ -105,7 +101,8 @@
     grpc_call_credentials* creds, grpc_polling_entity* pollent,
     grpc_auth_metadata_context context, grpc_credentials_mdelem_array* md_array,
     grpc_closure* on_request_metadata, grpc_error** error) {
-  grpc_md_only_test_credentials* c = (grpc_md_only_test_credentials*)creds;
+  grpc_md_only_test_credentials* c =
+      reinterpret_cast<grpc_md_only_test_credentials*>(creds);
   grpc_credentials_mdelem_array_add(md_array, c->md);
   if (c->is_async) {
     GRPC_CLOSURE_SCHED(on_request_metadata, GRPC_ERROR_NONE);
@@ -126,8 +123,9 @@
 
 grpc_call_credentials* grpc_md_only_test_credentials_create(
     const char* md_key, const char* md_value, bool is_async) {
-  grpc_md_only_test_credentials* c = (grpc_md_only_test_credentials*)gpr_zalloc(
-      sizeof(grpc_md_only_test_credentials));
+  grpc_md_only_test_credentials* c =
+      static_cast<grpc_md_only_test_credentials*>(
+          gpr_zalloc(sizeof(grpc_md_only_test_credentials)));
   c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2;
   c->base.vtable = &md_only_test_vtable;
   gpr_ref_init(&c->base.refcount, 1);
diff --git a/src/core/lib/security/credentials/fake/fake_credentials.h b/src/core/lib/security/credentials/fake/fake_credentials.h
index 0e9ff15..e89e6e2 100644
--- a/src/core/lib/security/credentials/fake/fake_credentials.h
+++ b/src/core/lib/security/credentials/fake/fake_credentials.h
@@ -19,8 +19,13 @@
 #ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_FAKE_FAKE_CREDENTIALS_H
 #define GRPC_CORE_LIB_SECURITY_CREDENTIALS_FAKE_FAKE_CREDENTIALS_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/credentials/credentials.h"
 
+#define GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS \
+  "grpc.fake_security.expected_targets"
+
 /* -- Fake transport security credentials. -- */
 
 /* Creates a fake transport security credentials object for testing. */
diff --git a/src/core/lib/security/credentials/google_default/credentials_generic.cc b/src/core/lib/security/credentials/google_default/credentials_generic.cc
index 15ae9d6..10ff0f6 100644
--- a/src/core/lib/security/credentials/google_default/credentials_generic.cc
+++ b/src/core/lib/security/credentials/google_default/credentials_generic.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/credentials/google_default/google_default_credentials.h"
 
 #include <grpc/support/alloc.h>
diff --git a/src/core/lib/security/credentials/google_default/google_default_credentials.cc b/src/core/lib/security/credentials/google_default/google_default_credentials.cc
index dc19202..70d4c3e 100644
--- a/src/core/lib/security/credentials/google_default/google_default_credentials.cc
+++ b/src/core/lib/security/credentials/google_default/google_default_credentials.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/credentials/credentials.h"
 
 #include <string.h>
@@ -60,7 +62,8 @@
 
 static void on_compute_engine_detection_http_response(void* user_data,
                                                       grpc_error* error) {
-  compute_engine_detector* detector = (compute_engine_detector*)user_data;
+  compute_engine_detector* detector =
+      static_cast<compute_engine_detector*>(user_data);
   if (error == GRPC_ERROR_NONE && detector->response.status == 200 &&
       detector->response.hdr_count > 0) {
     /* Internet providers can return a generic response to all requests, so
@@ -85,7 +88,7 @@
 }
 
 static void destroy_pollset(void* p, grpc_error* e) {
-  grpc_pollset_destroy((grpc_pollset*)p);
+  grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
 }
 
 static int is_stack_running_on_compute_engine() {
@@ -98,7 +101,8 @@
      on compute engine. */
   grpc_millis max_detection_delay = GPR_MS_PER_SEC;
 
-  grpc_pollset* pollset = (grpc_pollset*)gpr_zalloc(grpc_pollset_size());
+  grpc_pollset* pollset =
+      static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
   grpc_pollset_init(pollset, &g_polling_mu);
   detector.pollent = grpc_polling_entity_create_from_pollset(pollset);
   detector.is_done = 0;
@@ -171,7 +175,8 @@
     goto end;
   }
   json = grpc_json_parse_string_with_len(
-      (char*)GRPC_SLICE_START_PTR(creds_data), GRPC_SLICE_LENGTH(creds_data));
+      reinterpret_cast<char*> GRPC_SLICE_START_PTR(creds_data),
+      GRPC_SLICE_LENGTH(creds_data));
   if (json == nullptr) {
     error = grpc_error_set_str(
         GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to parse JSON"),
diff --git a/src/core/lib/security/credentials/iam/iam_credentials.cc b/src/core/lib/security/credentials/iam/iam_credentials.cc
index 75acb2a..5d92fa8 100644
--- a/src/core/lib/security/credentials/iam/iam_credentials.cc
+++ b/src/core/lib/security/credentials/iam/iam_credentials.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/credentials/iam/iam_credentials.h"
 
 #include <string.h>
@@ -28,7 +30,8 @@
 #include <grpc/support/sync.h>
 
 static void iam_destruct(grpc_call_credentials* creds) {
-  grpc_google_iam_credentials* c = (grpc_google_iam_credentials*)creds;
+  grpc_google_iam_credentials* c =
+      reinterpret_cast<grpc_google_iam_credentials*>(creds);
   grpc_credentials_mdelem_array_destroy(&c->md_array);
 }
 
@@ -38,7 +41,8 @@
                                      grpc_credentials_mdelem_array* md_array,
                                      grpc_closure* on_request_metadata,
                                      grpc_error** error) {
-  grpc_google_iam_credentials* c = (grpc_google_iam_credentials*)creds;
+  grpc_google_iam_credentials* c =
+      reinterpret_cast<grpc_google_iam_credentials*>(creds);
   grpc_credentials_mdelem_array_append(md_array, &c->md_array);
   return true;
 }
@@ -63,7 +67,7 @@
   GPR_ASSERT(token != nullptr);
   GPR_ASSERT(authority_selector != nullptr);
   grpc_google_iam_credentials* c =
-      (grpc_google_iam_credentials*)gpr_zalloc(sizeof(*c));
+      static_cast<grpc_google_iam_credentials*>(gpr_zalloc(sizeof(*c)));
   c->base.type = GRPC_CALL_CREDENTIALS_TYPE_IAM;
   c->base.vtable = &iam_vtable;
   gpr_ref_init(&c->base.refcount, 1);
diff --git a/src/core/lib/security/credentials/iam/iam_credentials.h b/src/core/lib/security/credentials/iam/iam_credentials.h
index 5e3cf65..a45710f 100644
--- a/src/core/lib/security/credentials/iam/iam_credentials.h
+++ b/src/core/lib/security/credentials/iam/iam_credentials.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_IAM_IAM_CREDENTIALS_H
 #define GRPC_CORE_LIB_SECURITY_CREDENTIALS_IAM_IAM_CREDENTIALS_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/credentials/credentials.h"
 
 typedef struct {
diff --git a/src/core/lib/security/credentials/jwt/json_token.cc b/src/core/lib/security/credentials/jwt/json_token.cc
index 078f04e..1c4827d 100644
--- a/src/core/lib/security/credentials/jwt/json_token.cc
+++ b/src/core/lib/security/credentials/jwt/json_token.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/credentials/jwt/json_token.h"
 
 #include <string.h>
@@ -96,7 +98,7 @@
   }
   bio = BIO_new(BIO_s_mem());
   success = BIO_puts(bio, prop_value);
-  if ((success < 0) || ((size_t)success != strlen(prop_value))) {
+  if ((success < 0) || (static_cast<size_t>(success) != strlen(prop_value))) {
     gpr_log(GPR_ERROR, "Could not write into openssl BIO.");
     goto end;
   }
@@ -219,7 +221,8 @@
   size_t str1_len = strlen(str1);
   size_t str2_len = strlen(str2);
   size_t result_len = str1_len + 1 /* dot */ + str2_len;
-  char* result = (char*)gpr_malloc(result_len + 1 /* NULL terminated */);
+  char* result =
+      static_cast<char*>(gpr_malloc(result_len + 1 /* NULL terminated */));
   char* current = result;
   memcpy(current, str1, str1_len);
   current += str1_len;
@@ -271,7 +274,7 @@
     gpr_log(GPR_ERROR, "DigestFinal (get signature length) failed.");
     goto end;
   }
-  sig = (unsigned char*)gpr_malloc(sig_len);
+  sig = static_cast<unsigned char*>(gpr_malloc(sig_len));
   if (EVP_DigestSignFinal(md_ctx, sig, &sig_len) != 1) {
     gpr_log(GPR_ERROR, "DigestFinal (signature compute) failed.");
     goto end;
diff --git a/src/core/lib/security/credentials/jwt/json_token.h b/src/core/lib/security/credentials/jwt/json_token.h
index 9b77488..d0fb4eb 100644
--- a/src/core/lib/security/credentials/jwt/json_token.h
+++ b/src/core/lib/security/credentials/jwt/json_token.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_JWT_JSON_TOKEN_H
 #define GRPC_CORE_LIB_SECURITY_CREDENTIALS_JWT_JSON_TOKEN_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice.h>
 #include <openssl/rsa.h>
 
diff --git a/src/core/lib/security/credentials/jwt/jwt_credentials.cc b/src/core/lib/security/credentials/jwt/jwt_credentials.cc
index 2404e86..05c08a6 100644
--- a/src/core/lib/security/credentials/jwt/jwt_credentials.cc
+++ b/src/core/lib/security/credentials/jwt/jwt_credentials.cc
@@ -42,7 +42,7 @@
 
 static void jwt_destruct(grpc_call_credentials* creds) {
   grpc_service_account_jwt_access_credentials* c =
-      (grpc_service_account_jwt_access_credentials*)creds;
+      reinterpret_cast<grpc_service_account_jwt_access_credentials*>(creds);
   grpc_auth_json_key_destruct(&c->key);
   jwt_reset_cache(c);
   gpr_mu_destroy(&c->cache_mu);
@@ -55,7 +55,7 @@
                                      grpc_closure* on_request_metadata,
                                      grpc_error** error) {
   grpc_service_account_jwt_access_credentials* c =
-      (grpc_service_account_jwt_access_credentials*)creds;
+      reinterpret_cast<grpc_service_account_jwt_access_credentials*>(creds);
   gpr_timespec refresh_threshold = gpr_time_from_seconds(
       GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN);
 
@@ -123,8 +123,8 @@
     gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation");
     return nullptr;
   }
-  c = (grpc_service_account_jwt_access_credentials*)gpr_zalloc(
-      sizeof(grpc_service_account_jwt_access_credentials));
+  c = static_cast<grpc_service_account_jwt_access_credentials*>(
+      gpr_zalloc(sizeof(grpc_service_account_jwt_access_credentials)));
   c->base.type = GRPC_CALL_CREDENTIALS_TYPE_JWT;
   gpr_ref_init(&c->base.refcount, 1);
   c->base.vtable = &jwt_vtable;
@@ -133,7 +133,7 @@
   if (gpr_time_cmp(token_lifetime, max_token_lifetime) > 0) {
     gpr_log(GPR_INFO,
             "Cropping token lifetime to maximum allowed value (%d secs).",
-            (int)max_token_lifetime.tv_sec);
+            static_cast<int>(max_token_lifetime.tv_sec));
     token_lifetime = grpc_max_auth_token_lifetime();
   }
   c->jwt_lifetime = token_lifetime;
@@ -154,7 +154,7 @@
   while (current) {
     if (current->type == GRPC_JSON_STRING &&
         strcmp(current->key, "private_key") == 0) {
-      current->value = (char*)redacted;
+      current->value = const_cast<char*>(redacted);
       break;
     }
     current = current->next;
@@ -177,7 +177,7 @@
             ", tv_nsec: %d, clock_type: %d }, "
             "reserved=%p)",
             clean_json, token_lifetime.tv_sec, token_lifetime.tv_nsec,
-            (int)token_lifetime.clock_type, reserved);
+            static_cast<int>(token_lifetime.clock_type), reserved);
     gpr_free(clean_json);
   }
   GPR_ASSERT(reserved == nullptr);
diff --git a/src/core/lib/security/credentials/jwt/jwt_credentials.h b/src/core/lib/security/credentials/jwt/jwt_credentials.h
index f58a8b6..5c3d34a 100644
--- a/src/core/lib/security/credentials/jwt/jwt_credentials.h
+++ b/src/core/lib/security/credentials/jwt/jwt_credentials.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_JWT_JWT_CREDENTIALS_H
 #define GRPC_CORE_LIB_SECURITY_CREDENTIALS_JWT_JWT_CREDENTIALS_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/credentials/credentials.h"
 #include "src/core/lib/security/credentials/jwt/json_token.h"
 
diff --git a/src/core/lib/security/credentials/jwt/jwt_verifier.cc b/src/core/lib/security/credentials/jwt/jwt_verifier.cc
index 860506d..5c47276 100644
--- a/src/core/lib/security/credentials/jwt/jwt_verifier.cc
+++ b/src/core/lib/security/credentials/jwt/jwt_verifier.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/credentials/jwt/jwt_verifier.h"
 
 #include <limits.h>
@@ -25,7 +27,6 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/useful.h>
 
 extern "C" {
 #include <openssl/pem.h>
@@ -83,8 +84,9 @@
     gpr_log(GPR_ERROR, "Invalid base64.");
     return nullptr;
   }
-  json = grpc_json_parse_string_with_len((char*)GRPC_SLICE_START_PTR(*buffer),
-                                         GRPC_SLICE_LENGTH(*buffer));
+  json = grpc_json_parse_string_with_len(
+      reinterpret_cast<char*> GRPC_SLICE_START_PTR(*buffer),
+      GRPC_SLICE_LENGTH(*buffer));
   if (json == nullptr) {
     grpc_slice_unref_internal(*buffer);
     gpr_log(GPR_ERROR, "JSON parsing error.");
@@ -130,7 +132,7 @@
 /* Takes ownership of json and buffer. */
 static jose_header* jose_header_from_json(grpc_json* json, grpc_slice buffer) {
   grpc_json* cur;
-  jose_header* h = (jose_header*)gpr_zalloc(sizeof(jose_header));
+  jose_header* h = static_cast<jose_header*>(gpr_zalloc(sizeof(jose_header)));
   h->buffer = buffer;
   for (cur = json->child; cur != nullptr; cur = cur->next) {
     if (strcmp(cur->key, "alg") == 0) {
@@ -232,7 +234,7 @@
 grpc_jwt_claims* grpc_jwt_claims_from_json(grpc_json* json, grpc_slice buffer) {
   grpc_json* cur;
   grpc_jwt_claims* claims =
-      (grpc_jwt_claims*)gpr_malloc(sizeof(grpc_jwt_claims));
+      static_cast<grpc_jwt_claims*>(gpr_malloc(sizeof(grpc_jwt_claims)));
   memset(claims, 0, sizeof(grpc_jwt_claims));
   claims->json = json;
   claims->buffer = buffer;
@@ -348,7 +350,8 @@
     const char* signed_jwt, size_t signed_jwt_len, void* user_data,
     grpc_jwt_verification_done_cb cb) {
   grpc_core::ExecCtx exec_ctx;
-  verifier_cb_ctx* ctx = (verifier_cb_ctx*)gpr_zalloc(sizeof(verifier_cb_ctx));
+  verifier_cb_ctx* ctx =
+      static_cast<verifier_cb_ctx*>(gpr_zalloc(sizeof(verifier_cb_ctx)));
   ctx->verifier = verifier;
   ctx->pollent = grpc_polling_entity_create_from_pollset(pollset);
   ctx->header = header;
@@ -430,7 +433,7 @@
   BIO* bio = BIO_new(BIO_s_mem());
   size_t len = strlen(x509_str);
   GPR_ASSERT(len < INT_MAX);
-  BIO_write(bio, x509_str, (int)len);
+  BIO_write(bio, x509_str, static_cast<int>(len));
   x509 = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
   if (x509 == nullptr) {
     gpr_log(GPR_ERROR, "Unable to parse x509 cert.");
@@ -626,7 +629,7 @@
 }
 
 static void on_keys_retrieved(void* user_data, grpc_error* error) {
-  verifier_cb_ctx* ctx = (verifier_cb_ctx*)user_data;
+  verifier_cb_ctx* ctx = static_cast<verifier_cb_ctx*>(user_data);
   grpc_json* json = json_from_http(&ctx->responses[HTTP_RESPONSE_KEYS]);
   EVP_PKEY* verification_key = nullptr;
   grpc_jwt_verifier_status status = GRPC_JWT_VERIFIER_GENERIC_ERROR;
@@ -667,7 +670,7 @@
 
 static void on_openid_config_retrieved(void* user_data, grpc_error* error) {
   const grpc_json* cur;
-  verifier_cb_ctx* ctx = (verifier_cb_ctx*)user_data;
+  verifier_cb_ctx* ctx = static_cast<verifier_cb_ctx*>(user_data);
   const grpc_http_response* response = &ctx->responses[HTTP_RESPONSE_OPENID];
   grpc_json* json = json_from_http(response);
   grpc_httpcli_request req;
@@ -690,7 +693,7 @@
   jwks_uri += 8;
   req.handshaker = &grpc_httpcli_ssl;
   req.host = gpr_strdup(jwks_uri);
-  req.http.path = (char*)strchr(jwks_uri, '/');
+  req.http.path = const_cast<char*>(strchr(jwks_uri, '/'));
   if (req.http.path == nullptr) {
     req.http.path = (char*)"";
   } else {
@@ -755,8 +758,8 @@
   if (dot == nullptr || dot == email_domain) return email_domain;
   GPR_ASSERT(dot > email_domain);
   /* There may be a subdomain, we just want the domain. */
-  dot = (const char*)gpr_memrchr((void*)email_domain, '.',
-                                 (size_t)(dot - email_domain));
+  dot = static_cast<const char*>(gpr_memrchr(
+      (void*)email_domain, '.', static_cast<size_t>(dot - email_domain)));
   if (dot == nullptr) return email_domain;
   return dot + 1;
 }
@@ -862,7 +865,8 @@
              cb != nullptr);
   dot = strchr(cur, '.');
   if (dot == nullptr) goto error;
-  json = parse_json_part_from_jwt(cur, (size_t)(dot - cur), &header_buffer);
+  json = parse_json_part_from_jwt(cur, static_cast<size_t>(dot - cur),
+                                  &header_buffer);
   if (json == nullptr) goto error;
   header = jose_header_from_json(json, header_buffer);
   if (header == nullptr) goto error;
@@ -870,12 +874,13 @@
   cur = dot + 1;
   dot = strchr(cur, '.');
   if (dot == nullptr) goto error;
-  json = parse_json_part_from_jwt(cur, (size_t)(dot - cur), &claims_buffer);
+  json = parse_json_part_from_jwt(cur, static_cast<size_t>(dot - cur),
+                                  &claims_buffer);
   if (json == nullptr) goto error;
   claims = grpc_jwt_claims_from_json(json, claims_buffer);
   if (claims == nullptr) goto error;
 
-  signed_jwt_len = (size_t)(dot - jwt);
+  signed_jwt_len = static_cast<size_t>(dot - jwt);
   cur = dot + 1;
   signature = grpc_base64_decode(cur, 1);
   if (GRPC_SLICE_IS_EMPTY(signature)) goto error;
@@ -894,13 +899,13 @@
     const grpc_jwt_verifier_email_domain_key_url_mapping* mappings,
     size_t num_mappings) {
   grpc_jwt_verifier* v =
-      (grpc_jwt_verifier*)gpr_zalloc(sizeof(grpc_jwt_verifier));
+      static_cast<grpc_jwt_verifier*>(gpr_zalloc(sizeof(grpc_jwt_verifier)));
   grpc_httpcli_context_init(&v->http_ctx);
 
   /* We know at least of one mapping. */
   v->allocated_mappings = 1 + num_mappings;
-  v->mappings = (email_key_mapping*)gpr_malloc(v->allocated_mappings *
-                                               sizeof(email_key_mapping));
+  v->mappings = static_cast<email_key_mapping*>(
+      gpr_malloc(v->allocated_mappings * sizeof(email_key_mapping)));
   verifier_put_mapping(v, GRPC_GOOGLE_SERVICE_ACCOUNTS_EMAIL_DOMAIN,
                        GRPC_GOOGLE_SERVICE_ACCOUNTS_KEY_URL_PREFIX);
   /* User-Provided mappings. */
diff --git a/src/core/lib/security/credentials/jwt/jwt_verifier.h b/src/core/lib/security/credentials/jwt/jwt_verifier.h
index b3805e7..cdb0987 100644
--- a/src/core/lib/security/credentials/jwt/jwt_verifier.h
+++ b/src/core/lib/security/credentials/jwt/jwt_verifier.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_JWT_JWT_VERIFIER_H
 #define GRPC_CORE_LIB_SECURITY_CREDENTIALS_JWT_JWT_VERIFIER_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/pollset.h"
 #include "src/core/lib/json/json.h"
 
diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc b/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
index e243ea5..2129029 100644
--- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
+++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/credentials/oauth2/oauth2_credentials.h"
 
 #include <string.h>
@@ -105,7 +107,7 @@
 
 static void oauth2_token_fetcher_destruct(grpc_call_credentials* creds) {
   grpc_oauth2_token_fetcher_credentials* c =
-      (grpc_oauth2_token_fetcher_credentials*)creds;
+      reinterpret_cast<grpc_oauth2_token_fetcher_credentials*>(creds);
   GRPC_MDELEM_UNREF(c->access_token_md);
   gpr_mu_destroy(&c->mu);
   grpc_pollset_set_destroy(grpc_polling_entity_pollset_set(&c->pollent));
@@ -128,7 +130,8 @@
   }
 
   if (response->body_length > 0) {
-    null_terminated_body = (char*)gpr_malloc(response->body_length + 1);
+    null_terminated_body =
+        static_cast<char*>(gpr_malloc(response->body_length + 1));
     null_terminated_body[response->body_length] = '\0';
     memcpy(null_terminated_body, response->body, response->body_length);
   }
@@ -204,9 +207,9 @@
                                                   grpc_error* error) {
   GRPC_LOG_IF_ERROR("oauth_fetch", GRPC_ERROR_REF(error));
   grpc_credentials_metadata_request* r =
-      (grpc_credentials_metadata_request*)user_data;
+      static_cast<grpc_credentials_metadata_request*>(user_data);
   grpc_oauth2_token_fetcher_credentials* c =
-      (grpc_oauth2_token_fetcher_credentials*)r->creds;
+      reinterpret_cast<grpc_oauth2_token_fetcher_credentials*>(r->creds);
   grpc_mdelem access_token_md = GRPC_MDNULL;
   grpc_millis token_lifetime;
   grpc_credentials_status status =
@@ -249,7 +252,7 @@
     grpc_auth_metadata_context context, grpc_credentials_mdelem_array* md_array,
     grpc_closure* on_request_metadata, grpc_error** error) {
   grpc_oauth2_token_fetcher_credentials* c =
-      (grpc_oauth2_token_fetcher_credentials*)creds;
+      reinterpret_cast<grpc_oauth2_token_fetcher_credentials*>(creds);
   // Check if we can use the cached token.
   grpc_millis refresh_threshold =
       GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS * GPR_MS_PER_SEC;
@@ -269,8 +272,8 @@
   // Couldn't get the token from the cache.
   // Add request to c->pending_requests and start a new fetch if needed.
   grpc_oauth2_pending_get_request_metadata* pending_request =
-      (grpc_oauth2_pending_get_request_metadata*)gpr_malloc(
-          sizeof(*pending_request));
+      static_cast<grpc_oauth2_pending_get_request_metadata*>(
+          gpr_malloc(sizeof(*pending_request)));
   pending_request->md_array = md_array;
   pending_request->on_request_metadata = on_request_metadata;
   pending_request->pollent = pollent;
@@ -298,7 +301,7 @@
     grpc_call_credentials* creds, grpc_credentials_mdelem_array* md_array,
     grpc_error* error) {
   grpc_oauth2_token_fetcher_credentials* c =
-      (grpc_oauth2_token_fetcher_credentials*)creds;
+      reinterpret_cast<grpc_oauth2_token_fetcher_credentials*>(creds);
   gpr_mu_lock(&c->mu);
   grpc_oauth2_pending_get_request_metadata* prev = nullptr;
   grpc_oauth2_pending_get_request_metadata* pending_request =
@@ -371,8 +374,8 @@
 grpc_call_credentials* grpc_google_compute_engine_credentials_create(
     void* reserved) {
   grpc_oauth2_token_fetcher_credentials* c =
-      (grpc_oauth2_token_fetcher_credentials*)gpr_malloc(
-          sizeof(grpc_oauth2_token_fetcher_credentials));
+      static_cast<grpc_oauth2_token_fetcher_credentials*>(
+          gpr_malloc(sizeof(grpc_oauth2_token_fetcher_credentials)));
   GRPC_API_TRACE("grpc_compute_engine_credentials_create(reserved=%p)", 1,
                  (reserved));
   GPR_ASSERT(reserved == nullptr);
@@ -387,7 +390,7 @@
 
 static void refresh_token_destruct(grpc_call_credentials* creds) {
   grpc_google_refresh_token_credentials* c =
-      (grpc_google_refresh_token_credentials*)creds;
+      reinterpret_cast<grpc_google_refresh_token_credentials*>(creds);
   grpc_auth_refresh_token_destruct(&c->refresh_token);
   oauth2_token_fetcher_destruct(&c->base.base);
 }
@@ -401,7 +404,8 @@
     grpc_httpcli_context* httpcli_context, grpc_polling_entity* pollent,
     grpc_iomgr_cb_func response_cb, grpc_millis deadline) {
   grpc_google_refresh_token_credentials* c =
-      (grpc_google_refresh_token_credentials*)metadata_req->creds;
+      reinterpret_cast<grpc_google_refresh_token_credentials*>(
+          metadata_req->creds);
   grpc_http_header header = {(char*)"Content-Type",
                              (char*)"application/x-www-form-urlencoded"};
   grpc_httpcli_request request;
@@ -437,8 +441,8 @@
     gpr_log(GPR_ERROR, "Invalid input for refresh token credentials creation");
     return nullptr;
   }
-  c = (grpc_google_refresh_token_credentials*)gpr_zalloc(
-      sizeof(grpc_google_refresh_token_credentials));
+  c = static_cast<grpc_google_refresh_token_credentials*>(
+      gpr_zalloc(sizeof(grpc_google_refresh_token_credentials)));
   init_oauth2_token_fetcher(&c->base, refresh_token_fetch_oauth2);
   c->base.base.vtable = &refresh_token_vtable;
   c->refresh_token = refresh_token;
@@ -478,7 +482,8 @@
 //
 
 static void access_token_destruct(grpc_call_credentials* creds) {
-  grpc_access_token_credentials* c = (grpc_access_token_credentials*)creds;
+  grpc_access_token_credentials* c =
+      reinterpret_cast<grpc_access_token_credentials*>(creds);
   GRPC_MDELEM_UNREF(c->access_token_md);
 }
 
@@ -486,7 +491,8 @@
     grpc_call_credentials* creds, grpc_polling_entity* pollent,
     grpc_auth_metadata_context context, grpc_credentials_mdelem_array* md_array,
     grpc_closure* on_request_metadata, grpc_error** error) {
-  grpc_access_token_credentials* c = (grpc_access_token_credentials*)creds;
+  grpc_access_token_credentials* c =
+      reinterpret_cast<grpc_access_token_credentials*>(creds);
   grpc_credentials_mdelem_array_add(md_array, c->access_token_md);
   return true;
 }
@@ -503,8 +509,9 @@
 
 grpc_call_credentials* grpc_access_token_credentials_create(
     const char* access_token, void* reserved) {
-  grpc_access_token_credentials* c = (grpc_access_token_credentials*)gpr_zalloc(
-      sizeof(grpc_access_token_credentials));
+  grpc_access_token_credentials* c =
+      static_cast<grpc_access_token_credentials*>(
+          gpr_zalloc(sizeof(grpc_access_token_credentials)));
   GRPC_API_TRACE(
       "grpc_access_token_credentials_create(access_token=<redacted>, "
       "reserved=%p)",
diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.h b/src/core/lib/security/credentials/oauth2/oauth2_credentials.h
index e5b8df8..c0dd154 100644
--- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.h
+++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_OAUTH2_OAUTH2_CREDENTIALS_H
 #define GRPC_CORE_LIB_SECURITY_CREDENTIALS_OAUTH2_OAUTH2_CREDENTIALS_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/json/json.h"
 #include "src/core/lib/security/credentials/credentials.h"
 
diff --git a/src/core/lib/security/credentials/plugin/plugin_credentials.cc b/src/core/lib/security/credentials/plugin/plugin_credentials.cc
index 203ba58..73946ce 100644
--- a/src/core/lib/security/credentials/plugin/plugin_credentials.cc
+++ b/src/core/lib/security/credentials/plugin/plugin_credentials.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/credentials/plugin/plugin_credentials.h"
 
 #include <string.h>
@@ -34,7 +36,8 @@
 grpc_core::TraceFlag grpc_plugin_credentials_trace(false, "plugin_credentials");
 
 static void plugin_destruct(grpc_call_credentials* creds) {
-  grpc_plugin_credentials* c = (grpc_plugin_credentials*)creds;
+  grpc_plugin_credentials* c =
+      reinterpret_cast<grpc_plugin_credentials*>(creds);
   gpr_mu_destroy(&c->mu);
   if (c->plugin.state != nullptr && c->plugin.destroy != nullptr) {
     c->plugin.destroy(c->plugin.state);
@@ -118,7 +121,7 @@
   grpc_core::ExecCtx exec_ctx(GRPC_EXEC_CTX_FLAG_IS_FINISHED |
                               GRPC_EXEC_CTX_FLAG_THREAD_RESOURCE_LOOP);
   grpc_plugin_credentials_pending_request* r =
-      (grpc_plugin_credentials_pending_request*)request;
+      static_cast<grpc_plugin_credentials_pending_request*>(request);
   if (grpc_plugin_credentials_trace.enabled()) {
     gpr_log(GPR_INFO,
             "plugin_credentials[%p]: request %p: plugin returned "
@@ -147,13 +150,14 @@
                                         grpc_credentials_mdelem_array* md_array,
                                         grpc_closure* on_request_metadata,
                                         grpc_error** error) {
-  grpc_plugin_credentials* c = (grpc_plugin_credentials*)creds;
+  grpc_plugin_credentials* c =
+      reinterpret_cast<grpc_plugin_credentials*>(creds);
   bool retval = true;  // Synchronous return.
   if (c->plugin.get_metadata != nullptr) {
     // Create pending_request object.
     grpc_plugin_credentials_pending_request* pending_request =
-        (grpc_plugin_credentials_pending_request*)gpr_zalloc(
-            sizeof(*pending_request));
+        static_cast<grpc_plugin_credentials_pending_request*>(
+            gpr_zalloc(sizeof(*pending_request)));
     pending_request->creds = c;
     pending_request->md_array = md_array;
     pending_request->on_request_metadata = on_request_metadata;
@@ -225,7 +229,8 @@
 static void plugin_cancel_get_request_metadata(
     grpc_call_credentials* creds, grpc_credentials_mdelem_array* md_array,
     grpc_error* error) {
-  grpc_plugin_credentials* c = (grpc_plugin_credentials*)creds;
+  grpc_plugin_credentials* c =
+      reinterpret_cast<grpc_plugin_credentials*>(creds);
   gpr_mu_lock(&c->mu);
   for (grpc_plugin_credentials_pending_request* pending_request =
            c->pending_requests;
@@ -252,7 +257,8 @@
 
 grpc_call_credentials* grpc_metadata_credentials_create_from_plugin(
     grpc_metadata_credentials_plugin plugin, void* reserved) {
-  grpc_plugin_credentials* c = (grpc_plugin_credentials*)gpr_zalloc(sizeof(*c));
+  grpc_plugin_credentials* c =
+      static_cast<grpc_plugin_credentials*>(gpr_zalloc(sizeof(*c)));
   GRPC_API_TRACE("grpc_metadata_credentials_create_from_plugin(reserved=%p)", 1,
                  (reserved));
   GPR_ASSERT(reserved == nullptr);
diff --git a/src/core/lib/security/credentials/plugin/plugin_credentials.h b/src/core/lib/security/credentials/plugin/plugin_credentials.h
index e1467b0..caf990e 100644
--- a/src/core/lib/security/credentials/plugin/plugin_credentials.h
+++ b/src/core/lib/security/credentials/plugin/plugin_credentials.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_PLUGIN_PLUGIN_CREDENTIALS_H
 #define GRPC_CORE_LIB_SECURITY_CREDENTIALS_PLUGIN_PLUGIN_CREDENTIALS_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/credentials/credentials.h"
 
 extern grpc_core::TraceFlag grpc_plugin_credentials_trace;
diff --git a/src/core/lib/security/credentials/ssl/ssl_credentials.cc b/src/core/lib/security/credentials/ssl/ssl_credentials.cc
index d854644..2b6377d 100644
--- a/src/core/lib/security/credentials/ssl/ssl_credentials.cc
+++ b/src/core/lib/security/credentials/ssl/ssl_credentials.cc
@@ -16,12 +16,15 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/credentials/ssl/ssl_credentials.h"
 
 #include <string.h>
 
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/surface/api_trace.h"
+#include "src/core/tsi/ssl_transport_security.h"
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
@@ -42,7 +45,7 @@
 }
 
 static void ssl_destruct(grpc_channel_credentials* creds) {
-  grpc_ssl_credentials* c = (grpc_ssl_credentials*)creds;
+  grpc_ssl_credentials* c = reinterpret_cast<grpc_ssl_credentials*>(creds);
   gpr_free(c->config.pem_root_certs);
   grpc_tsi_ssl_pem_key_cert_pairs_destroy(c->config.pem_key_cert_pair, 1);
 }
@@ -51,19 +54,25 @@
     grpc_channel_credentials* creds, grpc_call_credentials* call_creds,
     const char* target, const grpc_channel_args* args,
     grpc_channel_security_connector** sc, grpc_channel_args** new_args) {
-  grpc_ssl_credentials* c = (grpc_ssl_credentials*)creds;
+  grpc_ssl_credentials* c = reinterpret_cast<grpc_ssl_credentials*>(creds);
   grpc_security_status status = GRPC_SECURITY_OK;
   const char* overridden_target_name = nullptr;
+  tsi_ssl_session_cache* ssl_session_cache = nullptr;
   for (size_t i = 0; args && i < args->num_args; i++) {
     grpc_arg* arg = &args->args[i];
     if (strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == 0 &&
         arg->type == GRPC_ARG_STRING) {
       overridden_target_name = arg->value.string;
-      break;
+    }
+    if (strcmp(arg->key, GRPC_SSL_SESSION_CACHE_ARG) == 0 &&
+        arg->type == GRPC_ARG_POINTER) {
+      ssl_session_cache =
+          static_cast<tsi_ssl_session_cache*>(arg->value.pointer.p);
     }
   }
   status = grpc_ssl_channel_security_connector_create(
-      creds, call_creds, &c->config, target, overridden_target_name, sc);
+      creds, call_creds, &c->config, target, overridden_target_name,
+      ssl_session_cache, sc);
   if (status != GRPC_SECURITY_OK) {
     return status;
   }
@@ -85,8 +94,8 @@
   if (pem_key_cert_pair != nullptr) {
     GPR_ASSERT(pem_key_cert_pair->private_key != nullptr);
     GPR_ASSERT(pem_key_cert_pair->cert_chain != nullptr);
-    config->pem_key_cert_pair = (tsi_ssl_pem_key_cert_pair*)gpr_zalloc(
-        sizeof(tsi_ssl_pem_key_cert_pair));
+    config->pem_key_cert_pair = static_cast<tsi_ssl_pem_key_cert_pair*>(
+        gpr_zalloc(sizeof(tsi_ssl_pem_key_cert_pair)));
     config->pem_key_cert_pair->cert_chain =
         gpr_strdup(pem_key_cert_pair->cert_chain);
     config->pem_key_cert_pair->private_key =
@@ -97,8 +106,8 @@
 grpc_channel_credentials* grpc_ssl_credentials_create(
     const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
     void* reserved) {
-  grpc_ssl_credentials* c =
-      (grpc_ssl_credentials*)gpr_zalloc(sizeof(grpc_ssl_credentials));
+  grpc_ssl_credentials* c = static_cast<grpc_ssl_credentials*>(
+      gpr_zalloc(sizeof(grpc_ssl_credentials)));
   GRPC_API_TRACE(
       "grpc_ssl_credentials_create(pem_root_certs=%s, "
       "pem_key_cert_pair=%p, "
@@ -123,7 +132,8 @@
 };
 
 static void ssl_server_destruct(grpc_server_credentials* creds) {
-  grpc_ssl_server_credentials* c = (grpc_ssl_server_credentials*)creds;
+  grpc_ssl_server_credentials* c =
+      reinterpret_cast<grpc_ssl_server_credentials*>(creds);
   grpc_tsi_ssl_pem_key_cert_pairs_destroy(c->config.pem_key_cert_pairs,
                                           c->config.num_key_cert_pairs);
   gpr_free(c->config.pem_root_certs);
@@ -143,8 +153,8 @@
   tsi_ssl_pem_key_cert_pair* tsi_pairs = nullptr;
   if (num_key_cert_pairs > 0) {
     GPR_ASSERT(pem_key_cert_pairs != nullptr);
-    tsi_pairs = (tsi_ssl_pem_key_cert_pair*)gpr_zalloc(
-        num_key_cert_pairs * sizeof(tsi_ssl_pem_key_cert_pair));
+    tsi_pairs = static_cast<tsi_ssl_pem_key_cert_pair*>(
+        gpr_zalloc(num_key_cert_pairs * sizeof(tsi_ssl_pem_key_cert_pair)));
   }
   for (size_t i = 0; i < num_key_cert_pairs; i++) {
     GPR_ASSERT(pem_key_cert_pairs[i].private_key != nullptr);
@@ -174,15 +184,15 @@
     const grpc_ssl_pem_key_cert_pair* pem_key_cert_pairs,
     size_t num_key_cert_pairs) {
   grpc_ssl_server_certificate_config* config =
-      (grpc_ssl_server_certificate_config*)gpr_zalloc(
-          sizeof(grpc_ssl_server_certificate_config));
+      static_cast<grpc_ssl_server_certificate_config*>(
+          gpr_zalloc(sizeof(grpc_ssl_server_certificate_config)));
   if (pem_root_certs != nullptr) {
     config->pem_root_certs = gpr_strdup(pem_root_certs);
   }
   if (num_key_cert_pairs > 0) {
     GPR_ASSERT(pem_key_cert_pairs != nullptr);
-    config->pem_key_cert_pairs = (grpc_ssl_pem_key_cert_pair*)gpr_zalloc(
-        num_key_cert_pairs * sizeof(grpc_ssl_pem_key_cert_pair));
+    config->pem_key_cert_pairs = static_cast<grpc_ssl_pem_key_cert_pair*>(
+        gpr_zalloc(num_key_cert_pairs * sizeof(grpc_ssl_pem_key_cert_pair)));
   }
   config->num_key_cert_pairs = num_key_cert_pairs;
   for (size_t i = 0; i < num_key_cert_pairs; i++) {
@@ -217,8 +227,8 @@
     gpr_log(GPR_ERROR, "Certificate config must not be NULL.");
     goto done;
   }
-  options = (grpc_ssl_server_credentials_options*)gpr_zalloc(
-      sizeof(grpc_ssl_server_credentials_options));
+  options = static_cast<grpc_ssl_server_credentials_options*>(
+      gpr_zalloc(sizeof(grpc_ssl_server_credentials_options)));
   options->client_certificate_request = client_certificate_request;
   options->certificate_config = config;
 done:
@@ -235,14 +245,14 @@
   }
 
   grpc_ssl_server_certificate_config_fetcher* fetcher =
-      (grpc_ssl_server_certificate_config_fetcher*)gpr_zalloc(
-          sizeof(grpc_ssl_server_certificate_config_fetcher));
+      static_cast<grpc_ssl_server_certificate_config_fetcher*>(
+          gpr_zalloc(sizeof(grpc_ssl_server_certificate_config_fetcher)));
   fetcher->cb = cb;
   fetcher->user_data = user_data;
 
   grpc_ssl_server_credentials_options* options =
-      (grpc_ssl_server_credentials_options*)gpr_zalloc(
-          sizeof(grpc_ssl_server_credentials_options));
+      static_cast<grpc_ssl_server_credentials_options*>(
+          gpr_zalloc(sizeof(grpc_ssl_server_credentials_options)));
   options->client_certificate_request = client_certificate_request;
   options->certificate_config_fetcher = fetcher;
 
@@ -307,8 +317,8 @@
     goto done;
   }
 
-  c = (grpc_ssl_server_credentials*)gpr_zalloc(
-      sizeof(grpc_ssl_server_credentials));
+  c = static_cast<grpc_ssl_server_credentials*>(
+      gpr_zalloc(sizeof(grpc_ssl_server_credentials)));
   c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL;
   gpr_ref_init(&c->base.refcount, 1);
   c->base.vtable = &ssl_server_vtable;
diff --git a/src/core/lib/security/credentials/ssl/ssl_credentials.h b/src/core/lib/security/credentials/ssl/ssl_credentials.h
index 0003905..712d34c 100644
--- a/src/core/lib/security/credentials/ssl/ssl_credentials.h
+++ b/src/core/lib/security/credentials/ssl/ssl_credentials.h
@@ -18,6 +18,8 @@
 #ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_SSL_SSL_CREDENTIALS_H
 #define GRPC_CORE_LIB_SECURITY_CREDENTIALS_SSL_SSL_CREDENTIALS_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/credentials/credentials.h"
 
 typedef struct {
diff --git a/src/core/lib/security/security_connector/alts_security_connector.cc b/src/core/lib/security/security_connector/alts_security_connector.cc
new file mode 100644
index 0000000..5ff7d79
--- /dev/null
+++ b/src/core/lib/security/security_connector/alts_security_connector.cc
@@ -0,0 +1,287 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/lib/security/security_connector/alts_security_connector.h"
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/security/credentials/alts/alts_credentials.h"
+#include "src/core/lib/security/transport/security_handshaker.h"
+#include "src/core/lib/transport/transport.h"
+#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h"
+
+typedef struct {
+  grpc_channel_security_connector base;
+  char* target_name;
+} grpc_alts_channel_security_connector;
+
+typedef struct {
+  grpc_server_security_connector base;
+} grpc_alts_server_security_connector;
+
+static void alts_channel_destroy(grpc_security_connector* sc) {
+  if (sc == nullptr) {
+    return;
+  }
+  auto c = reinterpret_cast<grpc_alts_channel_security_connector*>(sc);
+  grpc_call_credentials_unref(c->base.request_metadata_creds);
+  grpc_channel_credentials_unref(c->base.channel_creds);
+  gpr_free(c->target_name);
+  gpr_free(sc);
+}
+
+static void alts_server_destroy(grpc_security_connector* sc) {
+  if (sc == nullptr) {
+    return;
+  }
+  auto c = reinterpret_cast<grpc_alts_server_security_connector*>(sc);
+  grpc_server_credentials_unref(c->base.server_creds);
+  gpr_free(sc);
+}
+
+static void alts_channel_add_handshakers(
+    grpc_channel_security_connector* sc,
+    grpc_handshake_manager* handshake_manager) {
+  tsi_handshaker* handshaker = nullptr;
+  auto c = reinterpret_cast<grpc_alts_channel_security_connector*>(sc);
+  grpc_alts_credentials* creds =
+      reinterpret_cast<grpc_alts_credentials*>(c->base.channel_creds);
+  GPR_ASSERT(alts_tsi_handshaker_create(creds->options, c->target_name,
+                                        creds->handshaker_service_url, true,
+                                        &handshaker) == TSI_OK);
+  grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create(
+                                                    handshaker, &sc->base));
+}
+
+static void alts_server_add_handshakers(
+    grpc_server_security_connector* sc,
+    grpc_handshake_manager* handshake_manager) {
+  tsi_handshaker* handshaker = nullptr;
+  auto c = reinterpret_cast<grpc_alts_server_security_connector*>(sc);
+  grpc_alts_server_credentials* creds =
+      reinterpret_cast<grpc_alts_server_credentials*>(c->base.server_creds);
+  GPR_ASSERT(alts_tsi_handshaker_create(creds->options, nullptr,
+                                        creds->handshaker_service_url, false,
+                                        &handshaker) == TSI_OK);
+  grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create(
+                                                    handshaker, &sc->base));
+}
+
+static void alts_set_rpc_protocol_versions(
+    grpc_gcp_rpc_protocol_versions* rpc_versions) {
+  grpc_gcp_rpc_protocol_versions_set_max(rpc_versions,
+                                         GRPC_PROTOCOL_VERSION_MAX_MAJOR,
+                                         GRPC_PROTOCOL_VERSION_MAX_MINOR);
+  grpc_gcp_rpc_protocol_versions_set_min(rpc_versions,
+                                         GRPC_PROTOCOL_VERSION_MIN_MAJOR,
+                                         GRPC_PROTOCOL_VERSION_MIN_MINOR);
+}
+
+namespace grpc_core {
+namespace internal {
+
+grpc_security_status grpc_alts_auth_context_from_tsi_peer(
+    const tsi_peer* peer, grpc_auth_context** ctx) {
+  if (peer == nullptr || ctx == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid arguments to grpc_alts_auth_context_from_tsi_peer()");
+    return GRPC_SECURITY_ERROR;
+  }
+  *ctx = nullptr;
+  /* Validate certificate type. */
+  const tsi_peer_property* cert_type_prop =
+      tsi_peer_get_property_by_name(peer, TSI_CERTIFICATE_TYPE_PEER_PROPERTY);
+  if (cert_type_prop == nullptr ||
+      strncmp(cert_type_prop->value.data, TSI_ALTS_CERTIFICATE_TYPE,
+              cert_type_prop->value.length) != 0) {
+    gpr_log(GPR_ERROR, "Invalid or missing certificate type property.");
+    return GRPC_SECURITY_ERROR;
+  }
+  /* Validate RPC protocol versions. */
+  const tsi_peer_property* rpc_versions_prop =
+      tsi_peer_get_property_by_name(peer, TSI_ALTS_RPC_VERSIONS);
+  if (rpc_versions_prop == nullptr) {
+    gpr_log(GPR_ERROR, "Missing rpc protocol versions property.");
+    return GRPC_SECURITY_ERROR;
+  }
+  grpc_gcp_rpc_protocol_versions local_versions, peer_versions;
+  alts_set_rpc_protocol_versions(&local_versions);
+  grpc_slice slice = grpc_slice_from_copied_buffer(
+      rpc_versions_prop->value.data, rpc_versions_prop->value.length);
+  bool decode_result =
+      grpc_gcp_rpc_protocol_versions_decode(slice, &peer_versions);
+  grpc_slice_unref(slice);
+  if (!decode_result) {
+    gpr_log(GPR_ERROR, "Invalid peer rpc protocol versions.");
+    return GRPC_SECURITY_ERROR;
+  }
+  /* TODO: Pass highest common rpc protocol version to grpc caller. */
+  bool check_result = grpc_gcp_rpc_protocol_versions_check(
+      &local_versions, &peer_versions, nullptr);
+  if (!check_result) {
+    gpr_log(GPR_ERROR, "Mismatch of local and peer rpc protocol versions.");
+    return GRPC_SECURITY_ERROR;
+  }
+  /* Create auth context. */
+  *ctx = grpc_auth_context_create(nullptr);
+  grpc_auth_context_add_cstring_property(
+      *ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+      GRPC_ALTS_TRANSPORT_SECURITY_TYPE);
+  size_t i = 0;
+  for (i = 0; i < peer->property_count; i++) {
+    const tsi_peer_property* tsi_prop = &peer->properties[i];
+    /* Add service account to auth context. */
+    if (strcmp(tsi_prop->name, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 0) {
+      grpc_auth_context_add_property(
+          *ctx, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY, tsi_prop->value.data,
+          tsi_prop->value.length);
+      GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
+                     *ctx, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 1);
+    }
+  }
+  if (!grpc_auth_context_peer_is_authenticated(*ctx)) {
+    gpr_log(GPR_ERROR, "Invalid unauthenticated peer.");
+    GRPC_AUTH_CONTEXT_UNREF(*ctx, "test");
+    *ctx = nullptr;
+    return GRPC_SECURITY_ERROR;
+  }
+  return GRPC_SECURITY_OK;
+}
+
+}  // namespace internal
+}  // namespace grpc_core
+
+static void alts_check_peer(grpc_security_connector* sc, tsi_peer peer,
+                            grpc_auth_context** auth_context,
+                            grpc_closure* on_peer_checked) {
+  grpc_security_status status;
+  status = grpc_core::internal::grpc_alts_auth_context_from_tsi_peer(
+      &peer, auth_context);
+  tsi_peer_destruct(&peer);
+  grpc_error* error =
+      status == GRPC_SECURITY_OK
+          ? GRPC_ERROR_NONE
+          : GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+                "Could not get ALTS auth context from TSI peer");
+  GRPC_CLOSURE_SCHED(on_peer_checked, error);
+}
+
+static int alts_channel_cmp(grpc_security_connector* sc1,
+                            grpc_security_connector* sc2) {
+  grpc_alts_channel_security_connector* c1 =
+      reinterpret_cast<grpc_alts_channel_security_connector*>(sc1);
+  grpc_alts_channel_security_connector* c2 =
+      reinterpret_cast<grpc_alts_channel_security_connector*>(sc2);
+  int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base);
+  if (c != 0) return c;
+  return strcmp(c1->target_name, c2->target_name);
+}
+
+static int alts_server_cmp(grpc_security_connector* sc1,
+                           grpc_security_connector* sc2) {
+  grpc_alts_server_security_connector* c1 =
+      reinterpret_cast<grpc_alts_server_security_connector*>(sc1);
+  grpc_alts_server_security_connector* c2 =
+      reinterpret_cast<grpc_alts_server_security_connector*>(sc2);
+  return grpc_server_security_connector_cmp(&c1->base, &c2->base);
+}
+
+static grpc_security_connector_vtable alts_channel_vtable = {
+    alts_channel_destroy, alts_check_peer, alts_channel_cmp};
+
+static grpc_security_connector_vtable alts_server_vtable = {
+    alts_server_destroy, alts_check_peer, alts_server_cmp};
+
+static bool alts_check_call_host(grpc_channel_security_connector* sc,
+                                 const char* host,
+                                 grpc_auth_context* auth_context,
+                                 grpc_closure* on_call_host_checked,
+                                 grpc_error** error) {
+  grpc_alts_channel_security_connector* alts_sc =
+      reinterpret_cast<grpc_alts_channel_security_connector*>(sc);
+  if (host == nullptr || alts_sc == nullptr ||
+      strcmp(host, alts_sc->target_name) != 0) {
+    *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "ALTS call host does not match target name");
+  }
+  return true;
+}
+
+static void alts_cancel_check_call_host(grpc_channel_security_connector* sc,
+                                        grpc_closure* on_call_host_checked,
+                                        grpc_error* error) {
+  GRPC_ERROR_UNREF(error);
+}
+
+grpc_security_status grpc_alts_channel_security_connector_create(
+    grpc_channel_credentials* channel_creds,
+    grpc_call_credentials* request_metadata_creds, const char* target_name,
+    grpc_channel_security_connector** sc) {
+  if (channel_creds == nullptr || sc == nullptr || target_name == nullptr) {
+    gpr_log(
+        GPR_ERROR,
+        "Invalid arguments to grpc_alts_channel_security_connector_create()");
+    return GRPC_SECURITY_ERROR;
+  }
+  auto c = static_cast<grpc_alts_channel_security_connector*>(
+      gpr_zalloc(sizeof(grpc_alts_channel_security_connector)));
+  gpr_ref_init(&c->base.base.refcount, 1);
+  c->base.base.vtable = &alts_channel_vtable;
+  c->base.add_handshakers = alts_channel_add_handshakers;
+  c->base.channel_creds = grpc_channel_credentials_ref(channel_creds);
+  c->base.request_metadata_creds =
+      grpc_call_credentials_ref(request_metadata_creds);
+  c->base.check_call_host = alts_check_call_host;
+  c->base.cancel_check_call_host = alts_cancel_check_call_host;
+  grpc_alts_credentials* creds =
+      reinterpret_cast<grpc_alts_credentials*>(c->base.channel_creds);
+  alts_set_rpc_protocol_versions(&creds->options->rpc_versions);
+  c->target_name = gpr_strdup(target_name);
+  *sc = &c->base;
+  return GRPC_SECURITY_OK;
+}
+
+grpc_security_status grpc_alts_server_security_connector_create(
+    grpc_server_credentials* server_creds,
+    grpc_server_security_connector** sc) {
+  if (server_creds == nullptr || sc == nullptr) {
+    gpr_log(
+        GPR_ERROR,
+        "Invalid arguments to grpc_alts_server_security_connector_create()");
+    return GRPC_SECURITY_ERROR;
+  }
+  auto c = static_cast<grpc_alts_server_security_connector*>(
+      gpr_zalloc(sizeof(grpc_alts_server_security_connector)));
+  gpr_ref_init(&c->base.base.refcount, 1);
+  c->base.base.vtable = &alts_server_vtable;
+  c->base.server_creds = grpc_server_credentials_ref(server_creds);
+  c->base.add_handshakers = alts_server_add_handshakers;
+  grpc_alts_server_credentials* creds =
+      reinterpret_cast<grpc_alts_server_credentials*>(c->base.server_creds);
+  alts_set_rpc_protocol_versions(&creds->options->rpc_versions);
+  *sc = &c->base;
+  return GRPC_SECURITY_OK;
+}
diff --git a/src/core/lib/security/security_connector/alts_security_connector.h b/src/core/lib/security/security_connector/alts_security_connector.h
new file mode 100644
index 0000000..e7e4cff
--- /dev/null
+++ b/src/core/lib/security/security_connector/alts_security_connector.h
@@ -0,0 +1,69 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_ALTS_SECURITY_CONNECTOR_H
+#define GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_ALTS_SECURITY_CONNECTOR_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/security/context/security_context.h"
+#include "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h"
+
+#define GRPC_ALTS_TRANSPORT_SECURITY_TYPE "alts"
+
+/**
+ * This method creates an ALTS channel security connector.
+ *
+ * - channel_creds: channel credential instance.
+ * - request_metadata_creds: credential object which will be sent with each
+ *   request. This parameter can be nullptr.
+ * - target_name: the name of the endpoint that the channel is connecting to.
+ * - sc: address of ALTS channel security connector instance to be returned from
+ *   the method.
+ *
+ * It returns GRPC_SECURITY_OK on success, and an error stauts code on failure.
+ */
+grpc_security_status grpc_alts_channel_security_connector_create(
+    grpc_channel_credentials* channel_creds,
+    grpc_call_credentials* request_metadata_creds, const char* target_name,
+    grpc_channel_security_connector** sc);
+
+/**
+ * This method creates an ALTS server security connector.
+ *
+ * - server_creds: server credential instance.
+ * - sc: address of ALTS server security connector instance to be returned from
+ *   the method.
+ *
+ * It returns GRPC_SECURITY_OK on success, and an error status code on failure.
+ */
+grpc_security_status grpc_alts_server_security_connector_create(
+    grpc_server_credentials* server_creds, grpc_server_security_connector** sc);
+
+namespace grpc_core {
+namespace internal {
+
+/* Exposed only for testing. */
+grpc_security_status grpc_alts_auth_context_from_tsi_peer(
+    const tsi_peer* peer, grpc_auth_context** ctx);
+
+}  // namespace internal
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_ALTS_SECURITY_CONNECTOR_H \
+        */
diff --git a/src/core/lib/security/transport/security_connector.cc b/src/core/lib/security/security_connector/security_connector.cc
similarity index 83%
rename from src/core/lib/security/transport/security_connector.cc
rename to src/core/lib/security/security_connector/security_connector.cc
index 1d962f9..3967112 100644
--- a/src/core/lib/security/transport/security_connector.cc
+++ b/src/core/lib/security/security_connector/security_connector.cc
@@ -16,14 +16,15 @@
  *
  */
 
-#include "src/core/lib/security/transport/security_connector.h"
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/security/security_connector/security_connector.h"
 
 #include <stdbool.h>
 #include <string.h>
 
 #include <grpc/slice_buffer.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
@@ -31,15 +32,16 @@
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/handshaker.h"
 #include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/load_file.h"
 #include "src/core/lib/security/context/security_context.h"
 #include "src/core/lib/security/credentials/credentials.h"
 #include "src/core/lib/security/credentials/fake/fake_credentials.h"
 #include "src/core/lib/security/credentials/ssl/ssl_credentials.h"
-#include "src/core/lib/security/transport/lb_targets_info.h"
 #include "src/core/lib/security/transport/secure_endpoint.h"
 #include "src/core/lib/security/transport/security_handshaker.h"
+#include "src/core/lib/security/transport/target_authority_table.h"
 #include "src/core/tsi/fake_transport_security.h"
 #include "src/core/tsi/ssl_transport_security.h"
 #include "src/core/tsi/transport_security_adapter.h"
@@ -239,8 +241,8 @@
 }
 
 static int connector_cmp(void* a, void* b) {
-  return grpc_security_connector_cmp((grpc_security_connector*)a,
-                                     (grpc_security_connector*)b);
+  return grpc_security_connector_cmp(static_cast<grpc_security_connector*>(a),
+                                     static_cast<grpc_security_connector*>(b));
 }
 
 static const grpc_arg_pointer_vtable connector_arg_vtable = {
@@ -258,7 +260,7 @@
             GRPC_ARG_SECURITY_CONNECTOR);
     return nullptr;
   }
-  return (grpc_security_connector*)arg->value.pointer.p;
+  return static_cast<grpc_security_connector*>(arg->value.pointer.p);
 }
 
 grpc_security_connector* grpc_security_connector_find_in_args(
@@ -308,7 +310,7 @@
 
 static void fake_channel_destroy(grpc_security_connector* sc) {
   grpc_fake_channel_security_connector* c =
-      (grpc_fake_channel_security_connector*)sc;
+      reinterpret_cast<grpc_fake_channel_security_connector*>(sc);
   grpc_call_credentials_unref(c->base.request_metadata_creds);
   gpr_free(c->target);
   gpr_free(c->expected_targets);
@@ -420,7 +422,7 @@
                                     grpc_closure* on_peer_checked) {
   fake_check_peer(sc, peer, auth_context, on_peer_checked);
   grpc_fake_channel_security_connector* c =
-      (grpc_fake_channel_security_connector*)sc;
+      reinterpret_cast<grpc_fake_channel_security_connector*>(sc);
   fake_secure_name_check(c->target, c->expected_targets, c->is_lb_channel);
 }
 
@@ -433,9 +435,9 @@
 static int fake_channel_cmp(grpc_security_connector* sc1,
                             grpc_security_connector* sc2) {
   grpc_fake_channel_security_connector* c1 =
-      (grpc_fake_channel_security_connector*)sc1;
+      reinterpret_cast<grpc_fake_channel_security_connector*>(sc1);
   grpc_fake_channel_security_connector* c2 =
-      (grpc_fake_channel_security_connector*)sc2;
+      reinterpret_cast<grpc_fake_channel_security_connector*>(sc2);
   int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base);
   if (c != 0) return c;
   c = strcmp(c1->target, c2->target);
@@ -452,8 +454,8 @@
 static int fake_server_cmp(grpc_security_connector* sc1,
                            grpc_security_connector* sc2) {
   return grpc_server_security_connector_cmp(
-      (grpc_server_security_connector*)sc1,
-      (grpc_server_security_connector*)sc2);
+      reinterpret_cast<grpc_server_security_connector*>(sc1),
+      reinterpret_cast<grpc_server_security_connector*>(sc2));
 }
 
 static bool fake_channel_check_call_host(grpc_channel_security_connector* sc,
@@ -461,6 +463,15 @@
                                          grpc_auth_context* auth_context,
                                          grpc_closure* on_call_host_checked,
                                          grpc_error** error) {
+  grpc_fake_channel_security_connector* c =
+      reinterpret_cast<grpc_fake_channel_security_connector*>(sc);
+  if (c->is_lb_channel) {
+    // TODO(dgq): verify that the host (ie, authority header) matches that of
+    // the LB, as opposed to that of the backends.
+  } else {
+    // TODO(dgq): verify that the host (ie, authority header) matches that of
+    // the backend, not the LB's.
+  }
   return true;
 }
 
@@ -498,7 +509,8 @@
     grpc_call_credentials* request_metadata_creds, const char* target,
     const grpc_channel_args* args) {
   grpc_fake_channel_security_connector* c =
-      (grpc_fake_channel_security_connector*)gpr_zalloc(sizeof(*c));
+      static_cast<grpc_fake_channel_security_connector*>(
+          gpr_zalloc(sizeof(*c)));
   gpr_ref_init(&c->base.base.refcount, 1);
   c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
   c->base.base.vtable = &fake_channel_vtable;
@@ -511,15 +523,15 @@
   c->target = gpr_strdup(target);
   const char* expected_targets = grpc_fake_transport_get_expected_targets(args);
   c->expected_targets = gpr_strdup(expected_targets);
-  c->is_lb_channel = (grpc_lb_targets_info_find_in_args(args) != nullptr);
+  c->is_lb_channel = grpc_core::FindTargetAuthorityTableInArgs(args) != nullptr;
   return &c->base;
 }
 
 grpc_server_security_connector* grpc_fake_server_security_connector_create(
     grpc_server_credentials* server_creds) {
   grpc_server_security_connector* c =
-      (grpc_server_security_connector*)gpr_zalloc(
-          sizeof(grpc_server_security_connector));
+      static_cast<grpc_server_security_connector*>(
+          gpr_zalloc(sizeof(grpc_server_security_connector)));
   gpr_ref_init(&c->base.refcount, 1);
   c->base.vtable = &fake_server_vtable;
   c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
@@ -530,6 +542,46 @@
 
 /* --- Ssl implementation. --- */
 
+grpc_ssl_session_cache* grpc_ssl_session_cache_create_lru(size_t capacity) {
+  tsi_ssl_session_cache* cache = tsi_ssl_session_cache_create_lru(capacity);
+  return reinterpret_cast<grpc_ssl_session_cache*>(cache);
+}
+
+void grpc_ssl_session_cache_destroy(grpc_ssl_session_cache* cache) {
+  tsi_ssl_session_cache* tsi_cache =
+      reinterpret_cast<tsi_ssl_session_cache*>(cache);
+  tsi_ssl_session_cache_unref(tsi_cache);
+}
+
+static void* grpc_ssl_session_cache_arg_copy(void* p) {
+  tsi_ssl_session_cache* tsi_cache =
+      reinterpret_cast<tsi_ssl_session_cache*>(p);
+  // destroy call below will unref the pointer.
+  tsi_ssl_session_cache_ref(tsi_cache);
+  return p;
+}
+
+static void grpc_ssl_session_cache_arg_destroy(void* p) {
+  tsi_ssl_session_cache* tsi_cache =
+      reinterpret_cast<tsi_ssl_session_cache*>(p);
+  tsi_ssl_session_cache_unref(tsi_cache);
+}
+
+static int grpc_ssl_session_cache_arg_cmp(void* p, void* q) {
+  return GPR_ICMP(p, q);
+}
+
+grpc_arg grpc_ssl_session_cache_create_channel_arg(
+    grpc_ssl_session_cache* cache) {
+  static const grpc_arg_pointer_vtable vtable = {
+      grpc_ssl_session_cache_arg_copy,
+      grpc_ssl_session_cache_arg_destroy,
+      grpc_ssl_session_cache_arg_cmp,
+  };
+  return grpc_channel_arg_pointer_create(
+      const_cast<char*>(GRPC_SSL_SESSION_CACHE_ARG), cache, &vtable);
+}
+
 typedef struct {
   grpc_channel_security_connector base;
   tsi_ssl_client_handshaker_factory* client_handshaker_factory;
@@ -546,14 +598,14 @@
     grpc_ssl_server_security_connector* c) {
   GPR_ASSERT(c != nullptr);
   grpc_ssl_server_credentials* server_creds =
-      (grpc_ssl_server_credentials*)c->base.server_creds;
+      reinterpret_cast<grpc_ssl_server_credentials*>(c->base.server_creds);
   GPR_ASSERT(server_creds != nullptr);
   return server_creds->certificate_config_fetcher.cb != nullptr;
 }
 
 static void ssl_channel_destroy(grpc_security_connector* sc) {
   grpc_ssl_channel_security_connector* c =
-      (grpc_ssl_channel_security_connector*)sc;
+      reinterpret_cast<grpc_ssl_channel_security_connector*>(sc);
   grpc_channel_credentials_unref(c->base.channel_creds);
   grpc_call_credentials_unref(c->base.request_metadata_creds);
   tsi_ssl_client_handshaker_factory_unref(c->client_handshaker_factory);
@@ -565,7 +617,7 @@
 
 static void ssl_server_destroy(grpc_security_connector* sc) {
   grpc_ssl_server_security_connector* c =
-      (grpc_ssl_server_security_connector*)sc;
+      reinterpret_cast<grpc_ssl_server_security_connector*>(sc);
   grpc_server_credentials_unref(c->base.server_creds);
   tsi_ssl_server_handshaker_factory_unref(c->server_handshaker_factory);
   c->server_handshaker_factory = nullptr;
@@ -575,7 +627,7 @@
 static void ssl_channel_add_handshakers(grpc_channel_security_connector* sc,
                                         grpc_handshake_manager* handshake_mgr) {
   grpc_ssl_channel_security_connector* c =
-      (grpc_ssl_channel_security_connector*)sc;
+      reinterpret_cast<grpc_ssl_channel_security_connector*>(sc);
   // Instantiate TSI handshaker.
   tsi_handshaker* tsi_hs = nullptr;
   tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker(
@@ -597,8 +649,8 @@
 static const char** fill_alpn_protocol_strings(size_t* num_alpn_protocols) {
   GPR_ASSERT(num_alpn_protocols != nullptr);
   *num_alpn_protocols = grpc_chttp2_num_alpn_versions();
-  const char** alpn_protocol_strings =
-      (const char**)gpr_malloc(sizeof(const char*) * (*num_alpn_protocols));
+  const char** alpn_protocol_strings = static_cast<const char**>(
+      gpr_malloc(sizeof(const char*) * (*num_alpn_protocols)));
   for (size_t i = 0; i < *num_alpn_protocols; i++) {
     alpn_protocol_strings[i] = grpc_chttp2_get_alpn_version_index(i);
   }
@@ -627,13 +679,13 @@
       config->pem_key_cert_pairs, config->num_key_cert_pairs);
   tsi_ssl_server_handshaker_factory* new_handshaker_factory = nullptr;
   grpc_ssl_server_credentials* server_creds =
-      (grpc_ssl_server_credentials*)sc->base.server_creds;
+      reinterpret_cast<grpc_ssl_server_credentials*>(sc->base.server_creds);
   tsi_result result = tsi_create_ssl_server_handshaker_factory_ex(
       cert_pairs, config->num_key_cert_pairs, config->pem_root_certs,
       get_tsi_client_certificate_request_type(
           server_creds->config.client_certificate_request),
-      ssl_cipher_suites(), alpn_protocol_strings, (uint16_t)num_alpn_protocols,
-      &new_handshaker_factory);
+      ssl_cipher_suites(), alpn_protocol_strings,
+      static_cast<uint16_t>(num_alpn_protocols), &new_handshaker_factory);
   gpr_free(cert_pairs);
   gpr_free((void*)alpn_protocol_strings);
 
@@ -659,7 +711,7 @@
   if (!server_connector_has_cert_config_fetcher(sc)) return false;
 
   grpc_ssl_server_credentials* server_creds =
-      (grpc_ssl_server_credentials*)sc->base.server_creds;
+      reinterpret_cast<grpc_ssl_server_credentials*>(sc->base.server_creds);
   grpc_ssl_certificate_config_reload_status cb_result =
       server_creds->certificate_config_fetcher.cb(
           server_creds->certificate_config_fetcher.user_data,
@@ -686,7 +738,7 @@
 static void ssl_server_add_handshakers(grpc_server_security_connector* sc,
                                        grpc_handshake_manager* handshake_mgr) {
   grpc_ssl_server_security_connector* c =
-      (grpc_ssl_server_security_connector*)sc;
+      reinterpret_cast<grpc_ssl_server_security_connector*>(sc);
   // Instantiate TSI handshaker.
   try_fetch_ssl_server_credentials(c);
   tsi_handshaker* tsi_hs = nullptr;
@@ -748,6 +800,9 @@
     } else if (strcmp(prop->name, TSI_X509_PEM_CERT_PROPERTY) == 0) {
       grpc_auth_context_add_property(ctx, GRPC_X509_PEM_CERT_PROPERTY_NAME,
                                      prop->value.data, prop->value.length);
+    } else if (strcmp(prop->name, TSI_SSL_SESSION_REUSED_PEER_PROPERTY) == 0) {
+      grpc_auth_context_add_property(ctx, GRPC_SSL_SESSION_REUSED_PROPERTY,
+                                     prop->value.data, prop->value.length);
     }
   }
   if (peer_identity_property_name != nullptr) {
@@ -788,7 +843,7 @@
                                    grpc_auth_context** auth_context,
                                    grpc_closure* on_peer_checked) {
   grpc_ssl_channel_security_connector* c =
-      (grpc_ssl_channel_security_connector*)sc;
+      reinterpret_cast<grpc_ssl_channel_security_connector*>(sc);
   grpc_error* error = ssl_check_peer(sc,
                                      c->overridden_target_name != nullptr
                                          ? c->overridden_target_name
@@ -809,9 +864,9 @@
 static int ssl_channel_cmp(grpc_security_connector* sc1,
                            grpc_security_connector* sc2) {
   grpc_ssl_channel_security_connector* c1 =
-      (grpc_ssl_channel_security_connector*)sc1;
+      reinterpret_cast<grpc_ssl_channel_security_connector*>(sc1);
   grpc_ssl_channel_security_connector* c2 =
-      (grpc_ssl_channel_security_connector*)sc2;
+      reinterpret_cast<grpc_ssl_channel_security_connector*>(sc2);
   int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base);
   if (c != 0) return c;
   c = strcmp(c1->target_name, c2->target_name);
@@ -825,15 +880,15 @@
 static int ssl_server_cmp(grpc_security_connector* sc1,
                           grpc_security_connector* sc2) {
   return grpc_server_security_connector_cmp(
-      (grpc_server_security_connector*)sc1,
-      (grpc_server_security_connector*)sc2);
+      reinterpret_cast<grpc_server_security_connector*>(sc1),
+      reinterpret_cast<grpc_server_security_connector*>(sc2));
 }
 
 static void add_shallow_auth_property_to_peer(tsi_peer* peer,
                                               const grpc_auth_property* prop,
                                               const char* tsi_prop_name) {
   tsi_peer_property* tsi_prop = &peer->properties[peer->property_count++];
-  tsi_prop->name = (char*)tsi_prop_name;
+  tsi_prop->name = const_cast<char*>(tsi_prop_name);
   tsi_prop->value.data = prop->value;
   tsi_prop->value.length = prop->value_length;
 }
@@ -850,8 +905,8 @@
   while (grpc_auth_property_iterator_next(&it) != nullptr) max_num_props++;
 
   if (max_num_props > 0) {
-    peer.properties = (tsi_peer_property*)gpr_malloc(max_num_props *
-                                                     sizeof(tsi_peer_property));
+    peer.properties = static_cast<tsi_peer_property*>(
+        gpr_malloc(max_num_props * sizeof(tsi_peer_property)));
     it = grpc_auth_context_property_iterator(auth_context);
     while ((prop = grpc_auth_property_iterator_next(&it)) != nullptr) {
       if (strcmp(prop->name, GRPC_X509_SAN_PROPERTY_NAME) == 0) {
@@ -879,7 +934,7 @@
                                         grpc_closure* on_call_host_checked,
                                         grpc_error** error) {
   grpc_ssl_channel_security_connector* c =
-      (grpc_ssl_channel_security_connector*)sc;
+      reinterpret_cast<grpc_ssl_channel_security_connector*>(sc);
   grpc_security_status status = GRPC_SECURITY_ERROR;
   tsi_peer peer = tsi_shallow_peer_from_ssl_auth_context(auth_context);
   if (ssl_host_matches_name(&peer, host)) status = GRPC_SECURITY_OK;
@@ -910,92 +965,39 @@
 static grpc_security_connector_vtable ssl_server_vtable = {
     ssl_server_destroy, ssl_server_check_peer, ssl_server_cmp};
 
-/* returns a NULL terminated slice. */
-static grpc_slice compute_default_pem_root_certs_once(void) {
-  grpc_slice result = grpc_empty_slice();
-
-  /* First try to load the roots from the environment. */
-  char* default_root_certs_path =
-      gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR);
-  if (default_root_certs_path != nullptr) {
-    GRPC_LOG_IF_ERROR("load_file",
-                      grpc_load_file(default_root_certs_path, 1, &result));
-    gpr_free(default_root_certs_path);
-  }
-
-  /* Try overridden roots if needed. */
-  grpc_ssl_roots_override_result ovrd_res = GRPC_SSL_ROOTS_OVERRIDE_FAIL;
-  if (GRPC_SLICE_IS_EMPTY(result) && ssl_roots_override_cb != nullptr) {
-    char* pem_root_certs = nullptr;
-    ovrd_res = ssl_roots_override_cb(&pem_root_certs);
-    if (ovrd_res == GRPC_SSL_ROOTS_OVERRIDE_OK) {
-      GPR_ASSERT(pem_root_certs != nullptr);
-      result = grpc_slice_from_copied_buffer(
-          pem_root_certs,
-          strlen(pem_root_certs) + 1);  // NULL terminator.
-    }
-    gpr_free(pem_root_certs);
-  }
-
-  /* Fall back to installed certs if needed. */
-  if (GRPC_SLICE_IS_EMPTY(result) &&
-      ovrd_res != GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY) {
-    GRPC_LOG_IF_ERROR("load_file",
-                      grpc_load_file(installed_roots_path, 1, &result));
-  }
-  return result;
-}
-
-static grpc_slice default_pem_root_certs;
-
-static void init_default_pem_root_certs(void) {
-  default_pem_root_certs = compute_default_pem_root_certs_once();
-}
-
-grpc_slice grpc_get_default_ssl_roots_for_testing(void) {
-  return compute_default_pem_root_certs_once();
-}
-
-const char* grpc_get_default_ssl_roots(void) {
-  /* TODO(jboeuf@google.com): Maybe revisit the approach which consists in
-     loading all the roots once for the lifetime of the process. */
-  static gpr_once once = GPR_ONCE_INIT;
-  gpr_once_init(&once, init_default_pem_root_certs);
-  return GRPC_SLICE_IS_EMPTY(default_pem_root_certs)
-             ? nullptr
-             : (const char*)GRPC_SLICE_START_PTR(default_pem_root_certs);
-}
-
 grpc_security_status grpc_ssl_channel_security_connector_create(
     grpc_channel_credentials* channel_creds,
     grpc_call_credentials* request_metadata_creds,
     const grpc_ssl_config* config, const char* target_name,
-    const char* overridden_target_name, grpc_channel_security_connector** sc) {
-  size_t num_alpn_protocols = 0;
-  const char** alpn_protocol_strings =
-      fill_alpn_protocol_strings(&num_alpn_protocols);
+    const char* overridden_target_name,
+    tsi_ssl_session_cache* ssl_session_cache,
+    grpc_channel_security_connector** sc) {
   tsi_result result = TSI_OK;
   grpc_ssl_channel_security_connector* c;
-  const char* pem_root_certs;
   char* port;
   bool has_key_cert_pair;
+  tsi_ssl_client_handshaker_options options;
+  memset(&options, 0, sizeof(options));
+  options.alpn_protocols =
+      fill_alpn_protocol_strings(&options.num_alpn_protocols);
 
   if (config == nullptr || target_name == nullptr) {
     gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name.");
     goto error;
   }
   if (config->pem_root_certs == nullptr) {
-    pem_root_certs = grpc_get_default_ssl_roots();
-    if (pem_root_certs == nullptr) {
+    // Use default root certificates.
+    options.pem_root_certs = grpc_core::DefaultSslRootStore::GetPemRootCerts();
+    options.root_store = grpc_core::DefaultSslRootStore::GetRootStore();
+    if (options.pem_root_certs == nullptr) {
       gpr_log(GPR_ERROR, "Could not get default pem root certs.");
       goto error;
     }
   } else {
-    pem_root_certs = config->pem_root_certs;
+    options.pem_root_certs = config->pem_root_certs;
   }
-
-  c = (grpc_ssl_channel_security_connector*)gpr_zalloc(
-      sizeof(grpc_ssl_channel_security_connector));
+  c = static_cast<grpc_ssl_channel_security_connector*>(
+      gpr_zalloc(sizeof(grpc_ssl_channel_security_connector)));
 
   gpr_ref_init(&c->base.base.refcount, 1);
   c->base.base.vtable = &ssl_channel_vtable;
@@ -1015,10 +1017,13 @@
   has_key_cert_pair = config->pem_key_cert_pair != nullptr &&
                       config->pem_key_cert_pair->private_key != nullptr &&
                       config->pem_key_cert_pair->cert_chain != nullptr;
-  result = tsi_create_ssl_client_handshaker_factory(
-      has_key_cert_pair ? config->pem_key_cert_pair : nullptr, pem_root_certs,
-      ssl_cipher_suites(), alpn_protocol_strings, (uint16_t)num_alpn_protocols,
-      &c->client_handshaker_factory);
+  if (has_key_cert_pair) {
+    options.pem_key_cert_pair = config->pem_key_cert_pair;
+  }
+  options.cipher_suites = ssl_cipher_suites();
+  options.session_cache = ssl_session_cache;
+  result = tsi_create_ssl_client_handshaker_factory_with_options(
+      &options, &c->client_handshaker_factory);
   if (result != TSI_OK) {
     gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
             tsi_result_to_string(result));
@@ -1027,11 +1032,11 @@
     goto error;
   }
   *sc = &c->base;
-  gpr_free((void*)alpn_protocol_strings);
+  gpr_free((void*)options.alpn_protocols);
   return GRPC_SECURITY_OK;
 
 error:
-  gpr_free((void*)alpn_protocol_strings);
+  gpr_free((void*)options.alpn_protocols);
   return GRPC_SECURITY_ERROR;
 }
 
@@ -1039,8 +1044,8 @@
 grpc_ssl_server_security_connector_initialize(
     grpc_server_credentials* server_creds) {
   grpc_ssl_server_security_connector* c =
-      (grpc_ssl_server_security_connector*)gpr_zalloc(
-          sizeof(grpc_ssl_server_security_connector));
+      static_cast<grpc_ssl_server_security_connector*>(
+          gpr_zalloc(sizeof(grpc_ssl_server_security_connector)));
   gpr_ref_init(&c->base.base.refcount, 1);
   c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
   c->base.base.vtable = &ssl_server_vtable;
@@ -1053,7 +1058,7 @@
     grpc_server_credentials* gsc, grpc_server_security_connector** sc) {
   tsi_result result = TSI_OK;
   grpc_ssl_server_credentials* server_credentials =
-      (grpc_ssl_server_credentials*)gsc;
+      reinterpret_cast<grpc_ssl_server_credentials*>(gsc);
   grpc_security_status retval = GRPC_SECURITY_OK;
 
   GPR_ASSERT(server_credentials != nullptr);
@@ -1078,7 +1083,8 @@
         get_tsi_client_certificate_request_type(
             server_credentials->config.client_certificate_request),
         ssl_cipher_suites(), alpn_protocol_strings,
-        (uint16_t)num_alpn_protocols, &c->server_handshaker_factory);
+        static_cast<uint16_t>(num_alpn_protocols),
+        &c->server_handshaker_factory);
     gpr_free((void*)alpn_protocol_strings);
     if (result != TSI_OK) {
       gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
@@ -1095,3 +1101,79 @@
   }
   return retval;
 }
+
+namespace grpc_core {
+
+tsi_ssl_root_certs_store* DefaultSslRootStore::default_root_store_;
+grpc_slice DefaultSslRootStore::default_pem_root_certs_;
+
+const tsi_ssl_root_certs_store* DefaultSslRootStore::GetRootStore() {
+  InitRootStore();
+  return default_root_store_;
+}
+
+const char* DefaultSslRootStore::GetPemRootCerts() {
+  InitRootStore();
+  return GRPC_SLICE_IS_EMPTY(default_pem_root_certs_)
+             ? nullptr
+             : reinterpret_cast<const char*>
+                   GRPC_SLICE_START_PTR(default_pem_root_certs_);
+}
+
+void DefaultSslRootStore::Initialize() {
+  default_root_store_ = nullptr;
+  default_pem_root_certs_ = grpc_empty_slice();
+}
+
+void DefaultSslRootStore::Destroy() {
+  tsi_ssl_root_certs_store_destroy(default_root_store_);
+  grpc_slice_unref_internal(default_pem_root_certs_);
+}
+
+grpc_slice DefaultSslRootStore::ComputePemRootCerts() {
+  grpc_slice result = grpc_empty_slice();
+  // First try to load the roots from the environment.
+  char* default_root_certs_path =
+      gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR);
+  if (default_root_certs_path != nullptr) {
+    GRPC_LOG_IF_ERROR("load_file",
+                      grpc_load_file(default_root_certs_path, 1, &result));
+    gpr_free(default_root_certs_path);
+  }
+  // Try overridden roots if needed.
+  grpc_ssl_roots_override_result ovrd_res = GRPC_SSL_ROOTS_OVERRIDE_FAIL;
+  if (GRPC_SLICE_IS_EMPTY(result) && ssl_roots_override_cb != nullptr) {
+    char* pem_root_certs = nullptr;
+    ovrd_res = ssl_roots_override_cb(&pem_root_certs);
+    if (ovrd_res == GRPC_SSL_ROOTS_OVERRIDE_OK) {
+      GPR_ASSERT(pem_root_certs != nullptr);
+      result = grpc_slice_from_copied_buffer(
+          pem_root_certs,
+          strlen(pem_root_certs) + 1);  // nullptr terminator.
+    }
+    gpr_free(pem_root_certs);
+  }
+  // Fall back to installed certs if needed.
+  if (GRPC_SLICE_IS_EMPTY(result) &&
+      ovrd_res != GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY) {
+    GRPC_LOG_IF_ERROR("load_file",
+                      grpc_load_file(installed_roots_path, 1, &result));
+  }
+  return result;
+}
+
+void DefaultSslRootStore::InitRootStore() {
+  static gpr_once once = GPR_ONCE_INIT;
+  gpr_once_init(&once, DefaultSslRootStore::InitRootStoreOnce);
+}
+
+void DefaultSslRootStore::InitRootStoreOnce() {
+  default_pem_root_certs_ = ComputePemRootCerts();
+  if (!GRPC_SLICE_IS_EMPTY(default_pem_root_certs_)) {
+    default_root_store_ =
+        tsi_ssl_root_certs_store_create(reinterpret_cast<const char*>(
+            GRPC_SLICE_START_PTR(default_pem_root_certs_)));
+  }
+}
+
+}  // namespace grpc_core
diff --git a/src/core/lib/security/transport/security_connector.h b/src/core/lib/security/security_connector/security_connector.h
similarity index 84%
rename from src/core/lib/security/transport/security_connector.h
rename to src/core/lib/security/security_connector/security_connector.h
index 495821d..5d3d1e0 100644
--- a/src/core/lib/security/transport/security_connector.h
+++ b/src/core/lib/security/security_connector/security_connector.h
@@ -16,8 +16,10 @@
  *
  */
 
-#ifndef GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_CONNECTOR_H
-#define GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_CONNECTOR_H
+#ifndef GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_SECURITY_CONNECTOR_H
+#define GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_SECURITY_CONNECTOR_H
+
+#include <grpc/support/port_platform.h>
 
 #include <stdbool.h>
 
@@ -210,13 +212,9 @@
     grpc_channel_credentials* channel_creds,
     grpc_call_credentials* request_metadata_creds,
     const grpc_ssl_config* config, const char* target_name,
-    const char* overridden_target_name, grpc_channel_security_connector** sc);
-
-/* Gets the default ssl roots. Returns NULL if not found. */
-const char* grpc_get_default_ssl_roots(void);
-
-/* Exposed for TESTING ONLY!. */
-grpc_slice grpc_get_default_ssl_roots_for_testing(void);
+    const char* overridden_target_name,
+    tsi_ssl_session_cache* ssl_session_cache,
+    grpc_channel_security_connector** sc);
 
 /* Config for ssl servers. */
 typedef struct {
@@ -246,4 +244,49 @@
     const grpc_auth_context* auth_context);
 void tsi_shallow_peer_destruct(tsi_peer* peer);
 
-#endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_CONNECTOR_H */
+/* --- Default SSL Root Store. --- */
+namespace grpc_core {
+
+// The class implements default SSL root store.
+class DefaultSslRootStore {
+ public:
+  // Gets the default SSL root store. Returns nullptr if not found.
+  static const tsi_ssl_root_certs_store* GetRootStore();
+
+  // Gets the default PEM root certificate.
+  static const char* GetPemRootCerts();
+
+  // Initializes the SSL root store's underlying data structure. It does not
+  // load default SSL root certificates. Should only be called by
+  // grpc_security_init().
+  static void Initialize();
+
+  // Destroys the default SSL root store. Should only be called by
+  // grpc_security_shutdown().
+  static void Destroy();
+
+ protected:
+  // Returns default PEM root certificates in nullptr terminated grpc_slice.
+  // This function is protected instead of private, so that it can be tested.
+  static grpc_slice ComputePemRootCerts();
+
+ private:
+  // Construct me not!
+  DefaultSslRootStore();
+
+  // Initialization of default SSL root store.
+  static void InitRootStore();
+
+  // One-time initialization of default SSL root store.
+  static void InitRootStoreOnce();
+
+  // SSL root store in tsi_ssl_root_certs_store object.
+  static tsi_ssl_root_certs_store* default_root_store_;
+
+  // Default PEM root certificates.
+  static grpc_slice default_pem_root_certs_;
+};
+
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_SECURITY_CONNECTOR_H */
diff --git a/src/core/lib/security/transport/auth_filters.h b/src/core/lib/security/transport/auth_filters.h
index e999a02..af2104c 100644
--- a/src/core/lib/security/transport/auth_filters.h
+++ b/src/core/lib/security/transport/auth_filters.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SECURITY_TRANSPORT_AUTH_FILTERS_H
 #define GRPC_CORE_LIB_SECURITY_TRANSPORT_AUTH_FILTERS_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc_security.h>
 #include "src/core/lib/channel/channel_stack.h"
 
diff --git a/src/core/lib/security/transport/client_auth_filter.cc b/src/core/lib/security/transport/client_auth_filter.cc
index 16814d2..048e390 100644
--- a/src/core/lib/security/transport/client_auth_filter.cc
+++ b/src/core/lib/security/transport/client_auth_filter.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/transport/auth_filters.h"
 
 #include <string.h>
@@ -29,7 +31,7 @@
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/security/context/security_context.h"
 #include "src/core/lib/security/credentials/credentials.h"
-#include "src/core/lib/security/transport/security_connector.h"
+#include "src/core/lib/security/security_connector/security_connector.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/surface/call.h"
@@ -43,8 +45,6 @@
   grpc_call_stack* owning_call;
   grpc_call_combiner* call_combiner;
   grpc_call_credentials* creds;
-  bool have_host;
-  bool have_method;
   grpc_slice host;
   grpc_slice method;
   /* pollset{_set} bound to this call; if we need to make external
@@ -70,11 +70,11 @@
 void grpc_auth_metadata_context_reset(
     grpc_auth_metadata_context* auth_md_context) {
   if (auth_md_context->service_url != nullptr) {
-    gpr_free((char*)auth_md_context->service_url);
+    gpr_free(const_cast<char*>(auth_md_context->service_url));
     auth_md_context->service_url = nullptr;
   }
   if (auth_md_context->method_name != nullptr) {
-    gpr_free((char*)auth_md_context->method_name);
+    gpr_free(const_cast<char*>(auth_md_context->method_name));
     auth_md_context->method_name = nullptr;
   }
   GRPC_AUTH_CONTEXT_UNREF(
@@ -93,10 +93,11 @@
 }
 
 static void on_credentials_metadata(void* arg, grpc_error* input_error) {
-  grpc_transport_stream_op_batch* batch = (grpc_transport_stream_op_batch*)arg;
+  grpc_transport_stream_op_batch* batch =
+      static_cast<grpc_transport_stream_op_batch*>(arg);
   grpc_call_element* elem =
-      (grpc_call_element*)batch->handler_private.extra_arg;
-  call_data* calld = (call_data*)elem->call_data;
+      static_cast<grpc_call_element*>(batch->handler_private.extra_arg);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   grpc_auth_metadata_context_reset(&calld->auth_md_context);
   grpc_error* error = GRPC_ERROR_REF(input_error);
   if (error == GRPC_ERROR_NONE) {
@@ -118,6 +119,7 @@
     grpc_transport_stream_op_batch_finish_with_failure(batch, error,
                                                        calld->call_combiner);
   }
+  GRPC_CALL_STACK_UNREF(calld->owning_call, "get_request_metadata");
 }
 
 void grpc_auth_metadata_context_build(
@@ -158,8 +160,8 @@
 }
 
 static void cancel_get_request_metadata(void* arg, grpc_error* error) {
-  grpc_call_element* elem = (grpc_call_element*)arg;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   if (error != GRPC_ERROR_NONE) {
     grpc_call_credentials_cancel_get_request_metadata(
         calld->creds, &calld->md_array, GRPC_ERROR_REF(error));
@@ -169,12 +171,11 @@
 
 static void send_security_metadata(grpc_call_element* elem,
                                    grpc_transport_stream_op_batch* batch) {
-  call_data* calld = (call_data*)elem->call_data;
-  channel_data* chand = (channel_data*)elem->channel_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   grpc_client_security_context* ctx =
-      (grpc_client_security_context*)batch->payload
-          ->context[GRPC_CONTEXT_SECURITY]
-          .value;
+      static_cast<grpc_client_security_context*>(
+          batch->payload->context[GRPC_CONTEXT_SECURITY].value);
   grpc_call_credentials* channel_call_creds =
       chand->security_connector->request_metadata_creds;
   int call_creds_has_md = (ctx != nullptr) && (ctx->creds != nullptr);
@@ -208,7 +209,7 @@
       chand->auth_context, &calld->auth_md_context);
 
   GPR_ASSERT(calld->pollent != nullptr);
-
+  GRPC_CALL_STACK_REF(calld->owning_call, "get_request_metadata");
   GRPC_CLOSURE_INIT(&calld->async_result_closure, on_credentials_metadata,
                     batch, grpc_schedule_on_exec_ctx);
   grpc_error* error = GRPC_ERROR_NONE;
@@ -230,10 +231,11 @@
 }
 
 static void on_host_checked(void* arg, grpc_error* error) {
-  grpc_transport_stream_op_batch* batch = (grpc_transport_stream_op_batch*)arg;
+  grpc_transport_stream_op_batch* batch =
+      static_cast<grpc_transport_stream_op_batch*>(arg);
   grpc_call_element* elem =
-      (grpc_call_element*)batch->handler_private.extra_arg;
-  call_data* calld = (call_data*)elem->call_data;
+      static_cast<grpc_call_element*>(batch->handler_private.extra_arg);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   if (error == GRPC_ERROR_NONE) {
     send_security_metadata(elem, batch);
   } else {
@@ -250,12 +252,13 @@
         calld->call_combiner);
     gpr_free(error_msg);
   }
+  GRPC_CALL_STACK_UNREF(calld->owning_call, "check_call_host");
 }
 
 static void cancel_check_call_host(void* arg, grpc_error* error) {
-  grpc_call_element* elem = (grpc_call_element*)arg;
-  call_data* calld = (call_data*)elem->call_data;
-  channel_data* chand = (channel_data*)elem->channel_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   if (error != GRPC_ERROR_NONE) {
     grpc_channel_security_connector_cancel_check_call_host(
         chand->security_connector, &calld->async_result_closure,
@@ -269,8 +272,8 @@
   GPR_TIMER_SCOPE("auth_start_transport_stream_op_batch", 0);
 
   /* grab pointers to our data from the call element */
-  call_data* calld = (call_data*)elem->call_data;
-  channel_data* chand = (channel_data*)elem->channel_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
 
   if (!batch->cancel_stream) {
     GPR_ASSERT(batch->payload->context != nullptr);
@@ -281,37 +284,25 @@
           grpc_client_security_context_destroy;
     }
     grpc_client_security_context* sec_ctx =
-        (grpc_client_security_context*)batch->payload
-            ->context[GRPC_CONTEXT_SECURITY]
-            .value;
+        static_cast<grpc_client_security_context*>(
+            batch->payload->context[GRPC_CONTEXT_SECURITY].value);
     GRPC_AUTH_CONTEXT_UNREF(sec_ctx->auth_context, "client auth filter");
     sec_ctx->auth_context =
         GRPC_AUTH_CONTEXT_REF(chand->auth_context, "client_auth_filter");
   }
 
   if (batch->send_initial_metadata) {
-    for (grpc_linked_mdelem* l = batch->payload->send_initial_metadata
-                                     .send_initial_metadata->list.head;
-         l != nullptr; l = l->next) {
-      grpc_mdelem md = l->md;
-      /* Pointer comparison is OK for md_elems created from the same context.
-       */
-      if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_AUTHORITY)) {
-        if (calld->have_host) {
-          grpc_slice_unref_internal(calld->host);
-        }
-        calld->host = grpc_slice_ref_internal(GRPC_MDVALUE(md));
-        calld->have_host = true;
-      } else if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_PATH)) {
-        if (calld->have_method) {
-          grpc_slice_unref_internal(calld->method);
-        }
-        calld->method = grpc_slice_ref_internal(GRPC_MDVALUE(md));
-        calld->have_method = true;
-      }
+    grpc_metadata_batch* metadata =
+        batch->payload->send_initial_metadata.send_initial_metadata;
+    if (metadata->idx.named.path != nullptr) {
+      calld->method =
+          grpc_slice_ref_internal(GRPC_MDVALUE(metadata->idx.named.path->md));
     }
-    if (calld->have_host) {
+    if (metadata->idx.named.authority != nullptr) {
+      calld->host = grpc_slice_ref_internal(
+          GRPC_MDVALUE(metadata->idx.named.authority->md));
       batch->handler_private.extra_arg = elem;
+      GRPC_CALL_STACK_REF(calld->owning_call, "check_call_host");
       GRPC_CLOSURE_INIT(&calld->async_result_closure, on_host_checked, batch,
                         grpc_schedule_on_exec_ctx);
       char* call_host = grpc_slice_to_c_string(calld->host);
@@ -343,15 +334,17 @@
 /* Constructor for call_data */
 static grpc_error* init_call_elem(grpc_call_element* elem,
                                   const grpc_call_element_args* args) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   calld->owning_call = args->call_stack;
   calld->call_combiner = args->call_combiner;
+  calld->host = grpc_empty_slice();
+  calld->method = grpc_empty_slice();
   return GRPC_ERROR_NONE;
 }
 
 static void set_pollset_or_pollset_set(grpc_call_element* elem,
                                        grpc_polling_entity* pollent) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   calld->pollent = pollent;
 }
 
@@ -359,15 +352,11 @@
 static void destroy_call_elem(grpc_call_element* elem,
                               const grpc_call_final_info* final_info,
                               grpc_closure* ignored) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   grpc_credentials_mdelem_array_destroy(&calld->md_array);
   grpc_call_credentials_unref(calld->creds);
-  if (calld->have_host) {
-    grpc_slice_unref_internal(calld->host);
-  }
-  if (calld->have_method) {
-    grpc_slice_unref_internal(calld->method);
-  }
+  grpc_slice_unref_internal(calld->host);
+  grpc_slice_unref_internal(calld->method);
   grpc_auth_metadata_context_reset(&calld->auth_md_context);
 }
 
@@ -388,7 +377,7 @@
   }
 
   /* grab pointers to our data from the channel element */
-  channel_data* chand = (channel_data*)elem->channel_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
 
   /* The first and the last filters tend to be implemented differently to
      handle the case that there's no 'next' filter to call on the up or down
@@ -397,8 +386,8 @@
 
   /* initialize members */
   chand->security_connector =
-      (grpc_channel_security_connector*)GRPC_SECURITY_CONNECTOR_REF(
-          sc, "client_auth_filter");
+      reinterpret_cast<grpc_channel_security_connector*>(
+          GRPC_SECURITY_CONNECTOR_REF(sc, "client_auth_filter"));
   chand->auth_context =
       GRPC_AUTH_CONTEXT_REF(auth_context, "client_auth_filter");
   return GRPC_ERROR_NONE;
@@ -407,7 +396,7 @@
 /* Destructor for channel data */
 static void destroy_channel_elem(grpc_channel_element* elem) {
   /* grab pointers to our data from the channel element */
-  channel_data* chand = (channel_data*)elem->channel_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   grpc_channel_security_connector* sc = chand->security_connector;
   if (sc != nullptr) {
     GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "client_auth_filter");
diff --git a/src/core/lib/security/transport/lb_targets_info.cc b/src/core/lib/security/transport/lb_targets_info.cc
deleted file mode 100644
index 183b1eb..0000000
--- a/src/core/lib/security/transport/lb_targets_info.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- *
- * Copyright 2017 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <grpc/support/log.h>
-
-#include "src/core/lib/channel/channel_args.h"
-#include "src/core/lib/security/transport/lb_targets_info.h"
-
-/* Channel arg key for the mapping of LB server addresses to their names for
- * secure naming purposes. */
-#define GRPC_ARG_LB_SECURE_NAMING_MAP "grpc.lb_secure_naming_map"
-
-static void* targets_info_copy(void* p) {
-  return grpc_slice_hash_table_ref((grpc_slice_hash_table*)p);
-}
-static void targets_info_destroy(void* p) {
-  grpc_slice_hash_table_unref((grpc_slice_hash_table*)p);
-}
-static int targets_info_cmp(void* a, void* b) {
-  return grpc_slice_hash_table_cmp((const grpc_slice_hash_table*)a,
-                                   (const grpc_slice_hash_table*)b);
-}
-static const grpc_arg_pointer_vtable server_to_balancer_names_vtable = {
-    targets_info_copy, targets_info_destroy, targets_info_cmp};
-
-grpc_arg grpc_lb_targets_info_create_channel_arg(
-    grpc_slice_hash_table* targets_info) {
-  return grpc_channel_arg_pointer_create((char*)GRPC_ARG_LB_SECURE_NAMING_MAP,
-                                         targets_info,
-                                         &server_to_balancer_names_vtable);
-}
-
-grpc_slice_hash_table* grpc_lb_targets_info_find_in_args(
-    const grpc_channel_args* args) {
-  const grpc_arg* targets_info_arg =
-      grpc_channel_args_find(args, GRPC_ARG_LB_SECURE_NAMING_MAP);
-  if (targets_info_arg != nullptr) {
-    GPR_ASSERT(targets_info_arg->type == GRPC_ARG_POINTER);
-    return (grpc_slice_hash_table*)targets_info_arg->value.pointer.p;
-  }
-  return nullptr;
-}
diff --git a/src/core/lib/security/transport/lb_targets_info.h b/src/core/lib/security/transport/lb_targets_info.h
deleted file mode 100644
index 7543d3c..0000000
--- a/src/core/lib/security/transport/lb_targets_info.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- *
- * Copyright 2017 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 GRPC_CORE_LIB_SECURITY_TRANSPORT_LB_TARGETS_INFO_H
-#define GRPC_CORE_LIB_SECURITY_TRANSPORT_LB_TARGETS_INFO_H
-
-#include "src/core/lib/slice/slice_hash_table.h"
-
-/** Return a channel argument containing \a targets_info. */
-grpc_arg grpc_lb_targets_info_create_channel_arg(
-    grpc_slice_hash_table* targets_info);
-
-/** Return the instance of targets info in \a args or NULL */
-grpc_slice_hash_table* grpc_lb_targets_info_find_in_args(
-    const grpc_channel_args* args);
-
-#endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_LB_TARGETS_INFO_H */
diff --git a/src/core/lib/security/transport/secure_endpoint.cc b/src/core/lib/security/transport/secure_endpoint.cc
index 9eaa299..31b779e 100644
--- a/src/core/lib/security/transport/secure_endpoint.cc
+++ b/src/core/lib/security/transport/secure_endpoint.cc
@@ -20,6 +20,8 @@
    using that endpoint. Because of various transitive includes in uv.h,
    including windows.h on Windows, uv.h must be included before other system
    headers. Therefore, sockaddr.h must always be included first */
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/sockaddr.h"
 
 #include <grpc/slice.h>
@@ -144,7 +146,7 @@
   unsigned i;
   uint8_t keep_looping = 0;
   tsi_result result = TSI_OK;
-  secure_endpoint* ep = (secure_endpoint*)user_data;
+  secure_endpoint* ep = static_cast<secure_endpoint*>(user_data);
   uint8_t* cur = GRPC_SLICE_START_PTR(ep->read_staging_buffer);
   uint8_t* end = GRPC_SLICE_END_PTR(ep->read_staging_buffer);
 
@@ -168,7 +170,7 @@
       size_t message_size = GRPC_SLICE_LENGTH(encrypted);
 
       while (message_size > 0 || keep_looping) {
-        size_t unprotected_buffer_size_written = (size_t)(end - cur);
+        size_t unprotected_buffer_size_written = static_cast<size_t>(end - cur);
         size_t processed_message_size = message_size;
         gpr_mu_lock(&ep->protector_mu);
         result = tsi_frame_protector_unprotect(
@@ -205,7 +207,8 @@
           ep->read_buffer,
           grpc_slice_split_head(
               &ep->read_staging_buffer,
-              (size_t)(cur - GRPC_SLICE_START_PTR(ep->read_staging_buffer))));
+              static_cast<size_t>(
+                  cur - GRPC_SLICE_START_PTR(ep->read_staging_buffer))));
     }
   }
 
@@ -226,7 +229,7 @@
 
 static void endpoint_read(grpc_endpoint* secure_ep, grpc_slice_buffer* slices,
                           grpc_closure* cb) {
-  secure_endpoint* ep = (secure_endpoint*)secure_ep;
+  secure_endpoint* ep = reinterpret_cast<secure_endpoint*>(secure_ep);
   ep->read_cb = cb;
   ep->read_buffer = slices;
   grpc_slice_buffer_reset_and_unref_internal(ep->read_buffer);
@@ -256,7 +259,7 @@
 
   unsigned i;
   tsi_result result = TSI_OK;
-  secure_endpoint* ep = (secure_endpoint*)secure_ep;
+  secure_endpoint* ep = reinterpret_cast<secure_endpoint*>(secure_ep);
   uint8_t* cur = GRPC_SLICE_START_PTR(ep->write_staging_buffer);
   uint8_t* end = GRPC_SLICE_END_PTR(ep->write_staging_buffer);
 
@@ -282,7 +285,7 @@
       uint8_t* message_bytes = GRPC_SLICE_START_PTR(plain);
       size_t message_size = GRPC_SLICE_LENGTH(plain);
       while (message_size > 0) {
-        size_t protected_buffer_size_to_send = (size_t)(end - cur);
+        size_t protected_buffer_size_to_send = static_cast<size_t>(end - cur);
         size_t processed_message_size = message_size;
         gpr_mu_lock(&ep->protector_mu);
         result = tsi_frame_protector_protect(ep->protector, message_bytes,
@@ -307,7 +310,7 @@
     if (result == TSI_OK) {
       size_t still_pending_size;
       do {
-        size_t protected_buffer_size_to_send = (size_t)(end - cur);
+        size_t protected_buffer_size_to_send = static_cast<size_t>(end - cur);
         gpr_mu_lock(&ep->protector_mu);
         result = tsi_frame_protector_protect_flush(
             ep->protector, cur, &protected_buffer_size_to_send,
@@ -324,8 +327,8 @@
             &ep->output_buffer,
             grpc_slice_split_head(
                 &ep->write_staging_buffer,
-                (size_t)(cur -
-                         GRPC_SLICE_START_PTR(ep->write_staging_buffer))));
+                static_cast<size_t>(
+                    cur - GRPC_SLICE_START_PTR(ep->write_staging_buffer))));
       }
     }
   }
@@ -343,46 +346,46 @@
 }
 
 static void endpoint_shutdown(grpc_endpoint* secure_ep, grpc_error* why) {
-  secure_endpoint* ep = (secure_endpoint*)secure_ep;
+  secure_endpoint* ep = reinterpret_cast<secure_endpoint*>(secure_ep);
   grpc_endpoint_shutdown(ep->wrapped_ep, why);
 }
 
 static void endpoint_destroy(grpc_endpoint* secure_ep) {
-  secure_endpoint* ep = (secure_endpoint*)secure_ep;
+  secure_endpoint* ep = reinterpret_cast<secure_endpoint*>(secure_ep);
   SECURE_ENDPOINT_UNREF(ep, "destroy");
 }
 
 static void endpoint_add_to_pollset(grpc_endpoint* secure_ep,
                                     grpc_pollset* pollset) {
-  secure_endpoint* ep = (secure_endpoint*)secure_ep;
+  secure_endpoint* ep = reinterpret_cast<secure_endpoint*>(secure_ep);
   grpc_endpoint_add_to_pollset(ep->wrapped_ep, pollset);
 }
 
 static void endpoint_add_to_pollset_set(grpc_endpoint* secure_ep,
                                         grpc_pollset_set* pollset_set) {
-  secure_endpoint* ep = (secure_endpoint*)secure_ep;
+  secure_endpoint* ep = reinterpret_cast<secure_endpoint*>(secure_ep);
   grpc_endpoint_add_to_pollset_set(ep->wrapped_ep, pollset_set);
 }
 
 static void endpoint_delete_from_pollset_set(grpc_endpoint* secure_ep,
                                              grpc_pollset_set* pollset_set) {
-  secure_endpoint* ep = (secure_endpoint*)secure_ep;
+  secure_endpoint* ep = reinterpret_cast<secure_endpoint*>(secure_ep);
   grpc_endpoint_delete_from_pollset_set(ep->wrapped_ep, pollset_set);
 }
 
 static char* endpoint_get_peer(grpc_endpoint* secure_ep) {
-  secure_endpoint* ep = (secure_endpoint*)secure_ep;
+  secure_endpoint* ep = reinterpret_cast<secure_endpoint*>(secure_ep);
   return grpc_endpoint_get_peer(ep->wrapped_ep);
 }
 
 static int endpoint_get_fd(grpc_endpoint* secure_ep) {
-  secure_endpoint* ep = (secure_endpoint*)secure_ep;
+  secure_endpoint* ep = reinterpret_cast<secure_endpoint*>(secure_ep);
   return grpc_endpoint_get_fd(ep->wrapped_ep);
 }
 
 static grpc_resource_user* endpoint_get_resource_user(
     grpc_endpoint* secure_ep) {
-  secure_endpoint* ep = (secure_endpoint*)secure_ep;
+  secure_endpoint* ep = reinterpret_cast<secure_endpoint*>(secure_ep);
   return grpc_endpoint_get_resource_user(ep->wrapped_ep);
 }
 
@@ -403,7 +406,8 @@
     grpc_endpoint* transport, grpc_slice* leftover_slices,
     size_t leftover_nslices) {
   size_t i;
-  secure_endpoint* ep = (secure_endpoint*)gpr_malloc(sizeof(secure_endpoint));
+  secure_endpoint* ep =
+      static_cast<secure_endpoint*>(gpr_malloc(sizeof(secure_endpoint)));
   ep->base.vtable = &vtable;
   ep->wrapped_ep = transport;
   ep->protector = protector;
diff --git a/src/core/lib/security/transport/secure_endpoint.h b/src/core/lib/security/transport/secure_endpoint.h
index b2556a0..e7e3351 100644
--- a/src/core/lib/security/transport/secure_endpoint.h
+++ b/src/core/lib/security/transport/secure_endpoint.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURE_ENDPOINT_H
 #define GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURE_ENDPOINT_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice.h>
 #include "src/core/lib/iomgr/endpoint.h"
 
diff --git a/src/core/lib/security/transport/security_handshaker.cc b/src/core/lib/security/transport/security_handshaker.cc
index 7623fbf..0c97dfa 100644
--- a/src/core/lib/security/transport/security_handshaker.cc
+++ b/src/core/lib/security/transport/security_handshaker.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/transport/security_handshaker.h"
 
 #include <stdbool.h>
@@ -68,8 +70,8 @@
 static size_t move_read_buffer_into_handshake_buffer(security_handshaker* h) {
   size_t bytes_in_read_buffer = h->args->read_buffer->length;
   if (h->handshake_buffer_size < bytes_in_read_buffer) {
-    h->handshake_buffer =
-        (uint8_t*)gpr_realloc(h->handshake_buffer, bytes_in_read_buffer);
+    h->handshake_buffer = static_cast<uint8_t*>(
+        gpr_realloc(h->handshake_buffer, bytes_in_read_buffer));
     h->handshake_buffer_size = bytes_in_read_buffer;
   }
   size_t offset = 0;
@@ -205,7 +207,7 @@
 }
 
 static void on_peer_checked(void* arg, grpc_error* error) {
-  security_handshaker* h = (security_handshaker*)arg;
+  security_handshaker* h = static_cast<security_handshaker*>(arg);
   gpr_mu_lock(&h->mu);
   on_peer_checked_inner(h, error);
   gpr_mu_unlock(&h->mu);
@@ -249,7 +251,7 @@
   if (bytes_to_send_size > 0) {
     // Send data to peer, if needed.
     grpc_slice to_send = grpc_slice_from_copied_buffer(
-        (const char*)bytes_to_send, bytes_to_send_size);
+        reinterpret_cast<const char*>(bytes_to_send), bytes_to_send_size);
     grpc_slice_buffer_reset_and_unref_internal(&h->outgoing);
     grpc_slice_buffer_add(&h->outgoing, to_send);
     grpc_endpoint_write(h->args->endpoint, &h->outgoing,
@@ -268,7 +270,7 @@
 static void on_handshake_next_done_grpc_wrapper(
     tsi_result result, void* user_data, const unsigned char* bytes_to_send,
     size_t bytes_to_send_size, tsi_handshaker_result* handshaker_result) {
-  security_handshaker* h = (security_handshaker*)user_data;
+  security_handshaker* h = static_cast<security_handshaker*>(user_data);
   // This callback will be invoked by TSI in a non-grpc thread, so it's
   // safe to create our own exec_ctx here.
   grpc_core::ExecCtx exec_ctx;
@@ -307,7 +309,7 @@
 }
 
 static void on_handshake_data_received_from_peer(void* arg, grpc_error* error) {
-  security_handshaker* h = (security_handshaker*)arg;
+  security_handshaker* h = static_cast<security_handshaker*>(arg);
   gpr_mu_lock(&h->mu);
   if (error != GRPC_ERROR_NONE || h->shutdown) {
     security_handshake_failed_locked(
@@ -333,7 +335,7 @@
 }
 
 static void on_handshake_data_sent_to_peer(void* arg, grpc_error* error) {
-  security_handshaker* h = (security_handshaker*)arg;
+  security_handshaker* h = static_cast<security_handshaker*>(arg);
   gpr_mu_lock(&h->mu);
   if (error != GRPC_ERROR_NONE || h->shutdown) {
     security_handshake_failed_locked(
@@ -364,13 +366,13 @@
 //
 
 static void security_handshaker_destroy(grpc_handshaker* handshaker) {
-  security_handshaker* h = (security_handshaker*)handshaker;
+  security_handshaker* h = reinterpret_cast<security_handshaker*>(handshaker);
   security_handshaker_unref(h);
 }
 
 static void security_handshaker_shutdown(grpc_handshaker* handshaker,
                                          grpc_error* why) {
-  security_handshaker* h = (security_handshaker*)handshaker;
+  security_handshaker* h = reinterpret_cast<security_handshaker*>(handshaker);
   gpr_mu_lock(&h->mu);
   if (!h->shutdown) {
     h->shutdown = true;
@@ -385,7 +387,7 @@
                                              grpc_tcp_server_acceptor* acceptor,
                                              grpc_closure* on_handshake_done,
                                              grpc_handshaker_args* args) {
-  security_handshaker* h = (security_handshaker*)handshaker;
+  security_handshaker* h = reinterpret_cast<security_handshaker*>(handshaker);
   gpr_mu_lock(&h->mu);
   h->args = args;
   h->on_handshake_done = on_handshake_done;
@@ -408,15 +410,16 @@
 
 static grpc_handshaker* security_handshaker_create(
     tsi_handshaker* handshaker, grpc_security_connector* connector) {
-  security_handshaker* h =
-      (security_handshaker*)gpr_zalloc(sizeof(security_handshaker));
+  security_handshaker* h = static_cast<security_handshaker*>(
+      gpr_zalloc(sizeof(security_handshaker)));
   grpc_handshaker_init(&security_handshaker_vtable, &h->base);
   h->handshaker = handshaker;
   h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake");
   gpr_mu_init(&h->mu);
   gpr_ref_init(&h->refs, 1);
   h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE;
-  h->handshake_buffer = (uint8_t*)gpr_malloc(h->handshake_buffer_size);
+  h->handshake_buffer =
+      static_cast<uint8_t*>(gpr_malloc(h->handshake_buffer_size));
   GRPC_CLOSURE_INIT(&h->on_handshake_data_sent_to_peer,
                     on_handshake_data_sent_to_peer, h,
                     grpc_schedule_on_exec_ctx);
@@ -456,7 +459,7 @@
     fail_handshaker_do_handshake};
 
 static grpc_handshaker* fail_handshaker_create() {
-  grpc_handshaker* h = (grpc_handshaker*)gpr_malloc(sizeof(*h));
+  grpc_handshaker* h = static_cast<grpc_handshaker*>(gpr_malloc(sizeof(*h)));
   grpc_handshaker_init(&fail_handshaker_vtable, h);
   return h;
 }
@@ -469,8 +472,8 @@
     grpc_handshaker_factory* handshaker_factory, const grpc_channel_args* args,
     grpc_handshake_manager* handshake_mgr) {
   grpc_channel_security_connector* security_connector =
-      (grpc_channel_security_connector*)grpc_security_connector_find_in_args(
-          args);
+      reinterpret_cast<grpc_channel_security_connector*>(
+          grpc_security_connector_find_in_args(args));
   grpc_channel_security_connector_add_handshakers(security_connector,
                                                   handshake_mgr);
 }
@@ -479,8 +482,8 @@
     grpc_handshaker_factory* hf, const grpc_channel_args* args,
     grpc_handshake_manager* handshake_mgr) {
   grpc_server_security_connector* security_connector =
-      (grpc_server_security_connector*)grpc_security_connector_find_in_args(
-          args);
+      reinterpret_cast<grpc_server_security_connector*>(
+          grpc_security_connector_find_in_args(args));
   grpc_server_security_connector_add_handshakers(security_connector,
                                                  handshake_mgr);
 }
diff --git a/src/core/lib/security/transport/security_handshaker.h b/src/core/lib/security/transport/security_handshaker.h
index 6cd6446..88483b0 100644
--- a/src/core/lib/security/transport/security_handshaker.h
+++ b/src/core/lib/security/transport/security_handshaker.h
@@ -19,9 +19,10 @@
 #ifndef GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_HANDSHAKER_H
 #define GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_HANDSHAKER_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/channel/handshaker.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
-#include "src/core/lib/security/transport/security_connector.h"
+#include "src/core/lib/security/security_connector/security_connector.h"
 
 /// Creates a security handshaker using \a handshaker.
 grpc_handshaker* grpc_security_handshaker_create(
diff --git a/src/core/lib/security/transport/server_auth_filter.cc b/src/core/lib/security/transport/server_auth_filter.cc
index f82971d..a560a4a 100644
--- a/src/core/lib/security/transport/server_auth_filter.cc
+++ b/src/core/lib/security/transport/server_auth_filter.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <string.h>
 
 #include <grpc/support/alloc.h>
@@ -65,8 +67,8 @@
     grpc_slice value = GRPC_MDVALUE(md);
     if (result.count == result.capacity) {
       result.capacity = GPR_MAX(result.capacity + 8, result.capacity * 2);
-      result.metadata = (grpc_metadata*)gpr_realloc(
-          result.metadata, result.capacity * sizeof(grpc_metadata));
+      result.metadata = static_cast<grpc_metadata*>(gpr_realloc(
+          result.metadata, result.capacity * sizeof(grpc_metadata)));
     }
     usr_md = &result.metadata[result.count++];
     usr_md->key = grpc_slice_ref_internal(key);
@@ -77,8 +79,8 @@
 
 static grpc_filtered_mdelem remove_consumed_md(void* user_data,
                                                grpc_mdelem md) {
-  grpc_call_element* elem = (grpc_call_element*)user_data;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   size_t i;
   for (i = 0; i < calld->num_consumed_md; i++) {
     const grpc_metadata* consumed_md = &calld->consumed_md[i];
@@ -95,7 +97,7 @@
                                         const grpc_metadata* response_md,
                                         size_t num_response_md,
                                         grpc_error* error) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   grpc_transport_stream_op_batch* batch = calld->recv_initial_metadata_batch;
   /* TODO(jboeuf): Implement support for response_md. */
   if (response_md != nullptr && num_response_md > 0) {
@@ -118,12 +120,12 @@
     void* user_data, const grpc_metadata* consumed_md, size_t num_consumed_md,
     const grpc_metadata* response_md, size_t num_response_md,
     grpc_status_code status, const char* error_details) {
-  grpc_call_element* elem = (grpc_call_element*)user_data;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   grpc_core::ExecCtx exec_ctx;
   // If the call was not cancelled while we were in flight, process the result.
-  if (gpr_atm_full_cas(&calld->state, (gpr_atm)STATE_INIT,
-                       (gpr_atm)STATE_DONE)) {
+  if (gpr_atm_full_cas(&calld->state, static_cast<gpr_atm>(STATE_INIT),
+                       static_cast<gpr_atm>(STATE_DONE))) {
     grpc_error* error = GRPC_ERROR_NONE;
     if (status != GRPC_STATUS_OK) {
       if (error_details == nullptr) {
@@ -146,12 +148,12 @@
 }
 
 static void cancel_call(void* arg, grpc_error* error) {
-  grpc_call_element* elem = (grpc_call_element*)arg;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   // If the result was not already processed, invoke the callback now.
   if (error != GRPC_ERROR_NONE &&
-      gpr_atm_full_cas(&calld->state, (gpr_atm)STATE_INIT,
-                       (gpr_atm)STATE_CANCELLED)) {
+      gpr_atm_full_cas(&calld->state, static_cast<gpr_atm>(STATE_INIT),
+                       static_cast<gpr_atm>(STATE_CANCELLED))) {
     on_md_processing_done_inner(elem, nullptr, 0, nullptr, 0,
                                 GRPC_ERROR_REF(error));
   }
@@ -159,9 +161,9 @@
 }
 
 static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
-  grpc_call_element* elem = (grpc_call_element*)arg;
-  channel_data* chand = (channel_data*)elem->channel_data;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   grpc_transport_stream_op_batch* batch = calld->recv_initial_metadata_batch;
   if (error == GRPC_ERROR_NONE) {
     if (chand->creds != nullptr && chand->creds->processor.process != nullptr) {
@@ -187,7 +189,7 @@
 
 static void auth_start_transport_stream_op_batch(
     grpc_call_element* elem, grpc_transport_stream_op_batch* batch) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   if (batch->recv_initial_metadata) {
     // Inject our callback.
     calld->recv_initial_metadata_batch = batch;
@@ -202,8 +204,8 @@
 /* Constructor for call_data */
 static grpc_error* init_call_elem(grpc_call_element* elem,
                                   const grpc_call_element_args* args) {
-  call_data* calld = (call_data*)elem->call_data;
-  channel_data* chand = (channel_data*)elem->channel_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   calld->call_combiner = args->call_combiner;
   calld->owning_call = args->call_stack;
   GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready,
@@ -234,7 +236,7 @@
 static grpc_error* init_channel_elem(grpc_channel_element* elem,
                                      grpc_channel_element_args* args) {
   GPR_ASSERT(!args->is_last);
-  channel_data* chand = (channel_data*)elem->channel_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   grpc_auth_context* auth_context =
       grpc_find_auth_context_in_args(args->channel_args);
   GPR_ASSERT(auth_context != nullptr);
@@ -248,7 +250,7 @@
 
 /* Destructor for channel data */
 static void destroy_channel_elem(grpc_channel_element* elem) {
-  channel_data* chand = (channel_data*)elem->channel_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "server_auth_filter");
   grpc_server_credentials_unref(chand->creds);
 }
diff --git a/src/core/lib/security/transport/target_authority_table.cc b/src/core/lib/security/transport/target_authority_table.cc
new file mode 100644
index 0000000..1eeb557
--- /dev/null
+++ b/src/core/lib/security/transport/target_authority_table.cc
@@ -0,0 +1,75 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include <grpc/support/log.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/security/transport/target_authority_table.h"
+
+// Channel arg key for the mapping of target addresses to their authorities.
+#define GRPC_ARG_TARGET_AUTHORITY_TABLE "grpc.target_authority_table"
+
+namespace grpc_core {
+namespace {
+
+void* target_authority_table_copy(void* p) {
+  TargetAuthorityTable* table = static_cast<TargetAuthorityTable*>(p);
+  // TODO(roth): When channel_args are converted to C++, pass the
+  // RefCountedPtr<> directly instead of managing the ref manually.
+  table->Ref().release();
+  return p;
+}
+void target_authority_table_destroy(void* p) {
+  TargetAuthorityTable* table = static_cast<TargetAuthorityTable*>(p);
+  table->Unref();
+}
+int target_authority_table_cmp(void* a, void* b) {
+  return TargetAuthorityTable::Cmp(
+      *static_cast<const TargetAuthorityTable*>(a),
+      *static_cast<const TargetAuthorityTable*>(b));
+}
+const grpc_arg_pointer_vtable target_authority_table_arg_vtable = {
+    target_authority_table_copy, target_authority_table_destroy,
+    target_authority_table_cmp};
+
+}  // namespace
+
+grpc_arg CreateTargetAuthorityTableChannelArg(TargetAuthorityTable* table) {
+  return grpc_channel_arg_pointer_create((char*)GRPC_ARG_TARGET_AUTHORITY_TABLE,
+                                         table,
+                                         &target_authority_table_arg_vtable);
+}
+
+TargetAuthorityTable* FindTargetAuthorityTableInArgs(
+    const grpc_channel_args* args) {
+  const grpc_arg* arg =
+      grpc_channel_args_find(args, GRPC_ARG_TARGET_AUTHORITY_TABLE);
+  if (arg != nullptr) {
+    if (arg->type == GRPC_ARG_POINTER) {
+      return static_cast<TargetAuthorityTable*>(arg->value.pointer.p);
+    } else {
+      gpr_log(GPR_ERROR, "value of " GRPC_ARG_TARGET_AUTHORITY_TABLE
+                         " channel arg was not pointer type; ignoring");
+    }
+  }
+  return nullptr;
+}
+
+}  // namespace grpc_core
diff --git a/src/core/lib/security/transport/target_authority_table.h b/src/core/lib/security/transport/target_authority_table.h
new file mode 100644
index 0000000..a2e7dc6
--- /dev/null
+++ b/src/core/lib/security/transport/target_authority_table.h
@@ -0,0 +1,40 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_LIB_SECURITY_TRANSPORT_TARGET_AUTHORITY_TABLE_H
+#define GRPC_CORE_LIB_SECURITY_TRANSPORT_TARGET_AUTHORITY_TABLE_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/slice/slice_hash_table.h"
+
+namespace grpc_core {
+
+/// A hash table mapping target addresses to authorities.
+typedef SliceHashTable<UniquePtr<char>> TargetAuthorityTable;
+
+/// Returns a channel argument containing \a table.
+grpc_arg CreateTargetAuthorityTableChannelArg(TargetAuthorityTable* table);
+
+/// Returns the target authority table from \a args or nullptr.
+TargetAuthorityTable* FindTargetAuthorityTableInArgs(
+    const grpc_channel_args* args);
+
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_TARGET_AUTHORITY_TABLE_H */
diff --git a/src/core/lib/security/transport/tsi_error.cc b/src/core/lib/security/transport/tsi_error.cc
index f71696d..f78bb8d 100644
--- a/src/core/lib/security/transport/tsi_error.cc
+++ b/src/core/lib/security/transport/tsi_error.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/transport/tsi_error.h"
 
 grpc_error* grpc_set_tsi_error_result(grpc_error* error, tsi_result result) {
diff --git a/src/core/lib/security/transport/tsi_error.h b/src/core/lib/security/transport/tsi_error.h
index 8fa6c48..16e04f7 100644
--- a/src/core/lib/security/transport/tsi_error.h
+++ b/src/core/lib/security/transport/tsi_error.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SECURITY_TRANSPORT_TSI_ERROR_H
 #define GRPC_CORE_LIB_SECURITY_TRANSPORT_TSI_ERROR_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/tsi/transport_security_interface.h"
 
diff --git a/src/core/lib/security/util/json_util.cc b/src/core/lib/security/util/json_util.cc
index fef1a1f..75512a1 100644
--- a/src/core/lib/security/util/json_util.cc
+++ b/src/core/lib/security/util/json_util.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/security/util/json_util.h"
 
 #include <string.h>
diff --git a/src/core/lib/security/util/json_util.h b/src/core/lib/security/util/json_util.h
index b7e46d4..89deffc 100644
--- a/src/core/lib/security/util/json_util.h
+++ b/src/core/lib/security/util/json_util.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SECURITY_UTIL_JSON_UTIL_H
 #define GRPC_CORE_LIB_SECURITY_UTIL_JSON_UTIL_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stdbool.h>
 
 #include "src/core/lib/json/json.h"
diff --git a/src/core/lib/slice/b64.cc b/src/core/lib/slice/b64.cc
index f36b13e..27f2724 100644
--- a/src/core/lib/slice/b64.cc
+++ b/src/core/lib/slice/b64.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/slice/b64.h"
 
 #include <stdint.h>
@@ -23,8 +25,8 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
 
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/slice/slice_internal.h"
 
 /* --- Constants. --- */
@@ -58,7 +60,7 @@
                          int multiline) {
   size_t result_projected_size =
       grpc_base64_estimate_encoded_size(data_size, url_safe, multiline);
-  char* result = (char*)gpr_malloc(result_projected_size);
+  char* result = static_cast<char*>(gpr_malloc(result_projected_size));
   grpc_base64_encode_core(result, vdata, data_size, url_safe, multiline);
   return result;
 }
@@ -75,7 +77,7 @@
 
 void grpc_base64_encode_core(char* result, const void* vdata, size_t data_size,
                              int url_safe, int multiline) {
-  const unsigned char* data = (const unsigned char*)vdata;
+  const unsigned char* data = static_cast<const unsigned char*>(vdata);
   const char* base64_chars =
       url_safe ? base64_url_safe_chars : base64_url_unsafe_chars;
   const size_t result_projected_size =
@@ -128,16 +130,18 @@
 
 static void decode_one_char(const unsigned char* codes, unsigned char* result,
                             size_t* result_offset) {
-  uint32_t packed = ((uint32_t)codes[0] << 2) | ((uint32_t)codes[1] >> 4);
-  result[(*result_offset)++] = (unsigned char)packed;
+  uint32_t packed = (static_cast<uint32_t>(codes[0]) << 2) |
+                    (static_cast<uint32_t>(codes[1]) >> 4);
+  result[(*result_offset)++] = static_cast<unsigned char>(packed);
 }
 
 static void decode_two_chars(const unsigned char* codes, unsigned char* result,
                              size_t* result_offset) {
-  uint32_t packed = ((uint32_t)codes[0] << 10) | ((uint32_t)codes[1] << 4) |
-                    ((uint32_t)codes[2] >> 2);
-  result[(*result_offset)++] = (unsigned char)(packed >> 8);
-  result[(*result_offset)++] = (unsigned char)(packed);
+  uint32_t packed = (static_cast<uint32_t>(codes[0]) << 10) |
+                    (static_cast<uint32_t>(codes[1]) << 4) |
+                    (static_cast<uint32_t>(codes[2]) >> 2);
+  result[(*result_offset)++] = static_cast<unsigned char>(packed >> 8);
+  result[(*result_offset)++] = static_cast<unsigned char>(packed);
 }
 
 static int decode_group(const unsigned char* codes, size_t num_codes,
@@ -175,11 +179,12 @@
     decode_two_chars(codes, result, result_offset);
   } else {
     /* No padding. */
-    uint32_t packed = ((uint32_t)codes[0] << 18) | ((uint32_t)codes[1] << 12) |
-                      ((uint32_t)codes[2] << 6) | codes[3];
-    result[(*result_offset)++] = (unsigned char)(packed >> 16);
-    result[(*result_offset)++] = (unsigned char)(packed >> 8);
-    result[(*result_offset)++] = (unsigned char)(packed);
+    uint32_t packed = (static_cast<uint32_t>(codes[0]) << 18) |
+                      (static_cast<uint32_t>(codes[1]) << 12) |
+                      (static_cast<uint32_t>(codes[2]) << 6) | codes[3];
+    result[(*result_offset)++] = static_cast<unsigned char>(packed >> 16);
+    result[(*result_offset)++] = static_cast<unsigned char>(packed >> 8);
+    result[(*result_offset)++] = static_cast<unsigned char>(packed);
   }
   return 1;
 }
@@ -193,7 +198,7 @@
   size_t num_codes = 0;
 
   while (b64_len--) {
-    unsigned char c = (unsigned char)(*b64++);
+    unsigned char c = static_cast<unsigned char>(*b64++);
     signed char code;
     if (c >= GPR_ARRAY_SIZE(base64_bytes)) continue;
     if (url_safe) {
@@ -214,7 +219,7 @@
         goto fail;
       }
     } else {
-      codes[num_codes++] = (unsigned char)code;
+      codes[num_codes++] = static_cast<unsigned char>(code);
       if (num_codes == 4) {
         if (!decode_group(codes, num_codes, current, &result_size)) goto fail;
         num_codes = 0;
diff --git a/src/core/lib/slice/b64.h b/src/core/lib/slice/b64.h
index 17e7306..4475568 100644
--- a/src/core/lib/slice/b64.h
+++ b/src/core/lib/slice/b64.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SLICE_B64_H
 #define GRPC_CORE_LIB_SLICE_B64_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice.h>
 
 /* Encodes data using base64. It is the caller's responsability to free
diff --git a/src/core/lib/slice/percent_encoding.cc b/src/core/lib/slice/percent_encoding.cc
index 894e43b..45cd2cc 100644
--- a/src/core/lib/slice/percent_encoding.cc
+++ b/src/core/lib/slice/percent_encoding.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/slice/percent_encoding.h"
 
 #include <grpc/support/log.h>
@@ -78,9 +80,9 @@
 }
 
 static uint8_t dehex(uint8_t c) {
-  if (c >= '0' && c <= '9') return (uint8_t)(c - '0');
-  if (c >= 'A' && c <= 'F') return (uint8_t)(c - 'A' + 10);
-  if (c >= 'a' && c <= 'f') return (uint8_t)(c - 'a' + 10);
+  if (c >= '0' && c <= '9') return static_cast<uint8_t>(c - '0');
+  if (c >= 'A' && c <= 'F') return static_cast<uint8_t>(c - 'A' + 10);
+  if (c >= 'a' && c <= 'f') return static_cast<uint8_t>(c - 'a' + 10);
   GPR_UNREACHABLE_CODE(return 255);
 }
 
@@ -114,7 +116,7 @@
   uint8_t* q = GRPC_SLICE_START_PTR(*slice_out);
   while (p != in_end) {
     if (*p == '%') {
-      *q++ = (uint8_t)(dehex(p[1]) << 4) | (dehex(p[2]));
+      *q++ = static_cast<uint8_t>(dehex(p[1]) << 4) | (dehex(p[2]));
       p += 3;
     } else {
       *q++ = *p++;
@@ -155,7 +157,7 @@
       if (!valid_hex(p + 1, in_end) || !valid_hex(p + 2, in_end)) {
         *q++ = *p++;
       } else {
-        *q++ = (uint8_t)(dehex(p[1]) << 4) | (dehex(p[2]));
+        *q++ = static_cast<uint8_t>(dehex(p[1]) << 4) | (dehex(p[2]));
         p += 3;
       }
     } else {
diff --git a/src/core/lib/slice/percent_encoding.h b/src/core/lib/slice/percent_encoding.h
index a1009ff..6b13ffc 100644
--- a/src/core/lib/slice/percent_encoding.h
+++ b/src/core/lib/slice/percent_encoding.h
@@ -26,6 +26,8 @@
      and another which applies percent encoding only to non-http2 header
      bytes (the 'compatible' variant) */
 
+#include <grpc/support/port_platform.h>
+
 #include <stdbool.h>
 
 #include <grpc/slice.h>
diff --git a/src/core/lib/slice/slice.cc b/src/core/lib/slice/slice.cc
index 1eb1529..585b41c 100644
--- a/src/core/lib/slice/slice.cc
+++ b/src/core/lib/slice/slice.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/slice/slice_internal.h"
 
 #include <grpc/slice.h>
@@ -27,7 +29,7 @@
 #include "src/core/lib/iomgr/exec_ctx.h"
 
 char* grpc_slice_to_c_string(grpc_slice slice) {
-  char* out = (char*)gpr_malloc(GRPC_SLICE_LENGTH(slice) + 1);
+  char* out = static_cast<char*>(gpr_malloc(GRPC_SLICE_LENGTH(slice) + 1));
   memcpy(out, GRPC_SLICE_START_PTR(slice), GRPC_SLICE_LENGTH(slice));
   out[GRPC_SLICE_LENGTH(slice)] = 0;
   return out;
@@ -104,12 +106,12 @@
 } new_slice_refcount;
 
 static void new_slice_ref(void* p) {
-  new_slice_refcount* r = (new_slice_refcount*)p;
+  new_slice_refcount* r = static_cast<new_slice_refcount*>(p);
   gpr_ref(&r->refs);
 }
 
 static void new_slice_unref(void* p) {
-  new_slice_refcount* r = (new_slice_refcount*)p;
+  new_slice_refcount* r = static_cast<new_slice_refcount*>(p);
   if (gpr_unref(&r->refs)) {
     r->user_destroy(r->user_data);
     gpr_free(r);
@@ -125,7 +127,7 @@
                                          void* user_data) {
   grpc_slice slice;
   new_slice_refcount* rc =
-      (new_slice_refcount*)gpr_malloc(sizeof(new_slice_refcount));
+      static_cast<new_slice_refcount*>(gpr_malloc(sizeof(new_slice_refcount)));
   gpr_ref_init(&rc->refs, 1);
   rc->rc.vtable = &new_slice_vtable;
   rc->rc.sub_refcount = &rc->rc;
@@ -133,7 +135,7 @@
   rc->user_data = user_data;
 
   slice.refcount = &rc->rc;
-  slice.data.refcounted.bytes = (uint8_t*)p;
+  slice.data.refcounted.bytes = static_cast<uint8_t*>(p);
   slice.data.refcounted.length = len;
   return slice;
 }
@@ -154,12 +156,12 @@
 } new_with_len_slice_refcount;
 
 static void new_with_len_ref(void* p) {
-  new_with_len_slice_refcount* r = (new_with_len_slice_refcount*)p;
+  new_with_len_slice_refcount* r = static_cast<new_with_len_slice_refcount*>(p);
   gpr_ref(&r->refs);
 }
 
 static void new_with_len_unref(void* p) {
-  new_with_len_slice_refcount* r = (new_with_len_slice_refcount*)p;
+  new_with_len_slice_refcount* r = static_cast<new_with_len_slice_refcount*>(p);
   if (gpr_unref(&r->refs)) {
     r->user_destroy(r->user_data, r->user_length);
     gpr_free(r);
@@ -173,8 +175,8 @@
 grpc_slice grpc_slice_new_with_len(void* p, size_t len,
                                    void (*destroy)(void*, size_t)) {
   grpc_slice slice;
-  new_with_len_slice_refcount* rc = (new_with_len_slice_refcount*)gpr_malloc(
-      sizeof(new_with_len_slice_refcount));
+  new_with_len_slice_refcount* rc = static_cast<new_with_len_slice_refcount*>(
+      gpr_malloc(sizeof(new_with_len_slice_refcount)));
   gpr_ref_init(&rc->refs, 1);
   rc->rc.vtable = &new_with_len_vtable;
   rc->rc.sub_refcount = &rc->rc;
@@ -183,7 +185,7 @@
   rc->user_length = len;
 
   slice.refcount = &rc->rc;
-  slice.data.refcounted.bytes = (uint8_t*)p;
+  slice.data.refcounted.bytes = static_cast<uint8_t*>(p);
   slice.data.refcounted.length = len;
   return slice;
 }
@@ -205,12 +207,12 @@
 } malloc_refcount;
 
 static void malloc_ref(void* p) {
-  malloc_refcount* r = (malloc_refcount*)p;
+  malloc_refcount* r = static_cast<malloc_refcount*>(p);
   gpr_ref(&r->refs);
 }
 
 static void malloc_unref(void* p) {
-  malloc_refcount* r = (malloc_refcount*)p;
+  malloc_refcount* r = static_cast<malloc_refcount*>(p);
   if (gpr_unref(&r->refs)) {
     gpr_free(r);
   }
@@ -232,8 +234,8 @@
      refcount is a malloc_refcount
      bytes is an array of bytes of the requested length
      Both parts are placed in the same allocation returned from gpr_malloc */
-  malloc_refcount* rc =
-      (malloc_refcount*)gpr_malloc(sizeof(malloc_refcount) + length);
+  malloc_refcount* rc = static_cast<malloc_refcount*>(
+      gpr_malloc(sizeof(malloc_refcount) + length));
 
   /* Initial refcount on rc is 1 - and it's up to the caller to release
      this reference. */
@@ -246,7 +248,7 @@
   /* The slices refcount points back to the allocated block. */
   slice.refcount = &rc->base;
   /* The data bytes are placed immediately after the refcount struct */
-  slice.data.refcounted.bytes = (uint8_t*)(rc + 1);
+  slice.data.refcounted.bytes = reinterpret_cast<uint8_t*>(rc + 1);
   /* And the length of the block is set to the requested length */
   slice.data.refcounted.length = length;
   return slice;
@@ -260,7 +262,7 @@
   } else {
     /* small slice: just inline the data */
     slice.refcount = nullptr;
-    slice.data.inlined.length = (uint8_t)length;
+    slice.data.inlined.length = static_cast<uint8_t>(length);
   }
   return slice;
 }
@@ -283,7 +285,7 @@
     /* Enforce preconditions */
     GPR_ASSERT(source.data.inlined.length >= end);
     subset.refcount = nullptr;
-    subset.data.inlined.length = (uint8_t)(end - begin);
+    subset.data.inlined.length = static_cast<uint8_t>(end - begin);
     memcpy(subset.data.inlined.bytes, source.data.inlined.bytes + begin,
            end - begin);
   }
@@ -295,7 +297,7 @@
 
   if (end - begin <= sizeof(subset.data.inlined.bytes)) {
     subset.refcount = nullptr;
-    subset.data.inlined.length = (uint8_t)(end - begin);
+    subset.data.inlined.length = static_cast<uint8_t>(end - begin);
     memcpy(subset.data.inlined.bytes, GRPC_SLICE_START_PTR(source) + begin,
            end - begin);
   } else {
@@ -314,10 +316,11 @@
     /* inlined data, copy it out */
     GPR_ASSERT(source->data.inlined.length >= split);
     tail.refcount = nullptr;
-    tail.data.inlined.length = (uint8_t)(source->data.inlined.length - split);
+    tail.data.inlined.length =
+        static_cast<uint8_t>(source->data.inlined.length - split);
     memcpy(tail.data.inlined.bytes, source->data.inlined.bytes + split,
            tail.data.inlined.length);
-    source->data.inlined.length = (uint8_t)split;
+    source->data.inlined.length = static_cast<uint8_t>(split);
   } else {
     size_t tail_length = source->data.refcounted.length - split;
     GPR_ASSERT(source->data.refcounted.length >= split);
@@ -325,7 +328,7 @@
         ref_whom != GRPC_SLICE_REF_TAIL) {
       /* Copy out the bytes - it'll be cheaper than refcounting */
       tail.refcount = nullptr;
-      tail.data.inlined.length = (uint8_t)tail_length;
+      tail.data.inlined.length = static_cast<uint8_t>(tail_length);
       memcpy(tail.data.inlined.bytes, source->data.refcounted.bytes + split,
              tail_length);
       source->refcount = source->refcount->sub_refcount;
@@ -368,17 +371,17 @@
     GPR_ASSERT(source->data.inlined.length >= split);
 
     head.refcount = nullptr;
-    head.data.inlined.length = (uint8_t)split;
+    head.data.inlined.length = static_cast<uint8_t>(split);
     memcpy(head.data.inlined.bytes, source->data.inlined.bytes, split);
     source->data.inlined.length =
-        (uint8_t)(source->data.inlined.length - split);
+        static_cast<uint8_t>(source->data.inlined.length - split);
     memmove(source->data.inlined.bytes, source->data.inlined.bytes + split,
             source->data.inlined.length);
   } else if (split < sizeof(head.data.inlined.bytes)) {
     GPR_ASSERT(source->data.refcounted.length >= split);
 
     head.refcount = nullptr;
-    head.data.inlined.length = (uint8_t)split;
+    head.data.inlined.length = static_cast<uint8_t>(split);
     memcpy(head.data.inlined.bytes, source->data.refcounted.bytes, split);
     source->refcount = source->refcount->sub_refcount;
     source->data.refcounted.bytes += split;
@@ -416,7 +419,7 @@
 }
 
 int grpc_slice_cmp(grpc_slice a, grpc_slice b) {
-  int d = (int)(GRPC_SLICE_LENGTH(a) - GRPC_SLICE_LENGTH(b));
+  int d = static_cast<int>(GRPC_SLICE_LENGTH(a) - GRPC_SLICE_LENGTH(b));
   if (d != 0) return d;
   return memcmp(GRPC_SLICE_START_PTR(a), GRPC_SLICE_START_PTR(b),
                 GRPC_SLICE_LENGTH(a));
@@ -424,7 +427,7 @@
 
 int grpc_slice_str_cmp(grpc_slice a, const char* b) {
   size_t b_length = strlen(b);
-  int d = (int)(GRPC_SLICE_LENGTH(a) - b_length);
+  int d = static_cast<int>(GRPC_SLICE_LENGTH(a) - b_length);
   if (d != 0) return d;
   return memcmp(GRPC_SLICE_START_PTR(a), b, b_length);
 }
@@ -443,17 +446,17 @@
 }
 
 int grpc_slice_rchr(grpc_slice s, char c) {
-  const char* b = (const char*)GRPC_SLICE_START_PTR(s);
+  const char* b = reinterpret_cast<const char*> GRPC_SLICE_START_PTR(s);
   int i;
-  for (i = (int)GRPC_SLICE_LENGTH(s) - 1; i != -1 && b[i] != c; i--)
+  for (i = static_cast<int> GRPC_SLICE_LENGTH(s) - 1; i != -1 && b[i] != c; i--)
     ;
   return i;
 }
 
 int grpc_slice_chr(grpc_slice s, char c) {
-  const char* b = (const char*)GRPC_SLICE_START_PTR(s);
-  const char* p = (const char*)memchr(b, c, GRPC_SLICE_LENGTH(s));
-  return p == nullptr ? -1 : (int)(p - b);
+  const char* b = reinterpret_cast<const char*> GRPC_SLICE_START_PTR(s);
+  const char* p = static_cast<const char*>(memchr(b, c, GRPC_SLICE_LENGTH(s)));
+  return p == nullptr ? -1 : static_cast<int>(p - b);
 }
 
 int grpc_slice_slice(grpc_slice haystack, grpc_slice needle) {
@@ -466,12 +469,13 @@
   if (haystack_len < needle_len) return -1;
   if (haystack_len == needle_len)
     return grpc_slice_eq(haystack, needle) ? 0 : -1;
-  if (needle_len == 1) return grpc_slice_chr(haystack, (char)*needle_bytes);
+  if (needle_len == 1)
+    return grpc_slice_chr(haystack, static_cast<char>(*needle_bytes));
 
   const uint8_t* last = haystack_bytes + haystack_len - needle_len;
   for (const uint8_t* cur = haystack_bytes; cur != last; ++cur) {
     if (0 == memcmp(cur, needle_bytes, needle_len)) {
-      return (int)(cur - haystack_bytes);
+      return static_cast<int>(cur - haystack_bytes);
     }
   }
   return -1;
diff --git a/src/core/lib/slice/slice_buffer.cc b/src/core/lib/slice/slice_buffer.cc
index 33ec2af..58ca495 100644
--- a/src/core/lib/slice/slice_buffer.cc
+++ b/src/core/lib/slice/slice_buffer.cc
@@ -16,15 +16,17 @@
  *
  */
 
-#include <grpc/slice_buffer.h>
 #include <grpc/support/port_platform.h>
 
+#include <grpc/slice_buffer.h>
+
 #include <string.h>
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
 
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/slice/slice_internal.h"
 
 /* grow a buffer; requires GRPC_SLICE_BUFFER_INLINE_ELEMENTS > 1 */
@@ -32,7 +34,7 @@
 
 static void maybe_embiggen(grpc_slice_buffer* sb) {
   /* How far away from sb->base_slices is sb->slices pointer */
-  size_t slice_offset = (size_t)(sb->slices - sb->base_slices);
+  size_t slice_offset = static_cast<size_t>(sb->slices - sb->base_slices);
   size_t slice_count = sb->count + slice_offset;
 
   if (slice_count == sb->capacity) {
@@ -45,12 +47,12 @@
       sb->capacity = GROW(sb->capacity);
       GPR_ASSERT(sb->capacity > slice_count);
       if (sb->base_slices == sb->inlined) {
-        sb->base_slices =
-            (grpc_slice*)gpr_malloc(sb->capacity * sizeof(grpc_slice));
+        sb->base_slices = static_cast<grpc_slice*>(
+            gpr_malloc(sb->capacity * sizeof(grpc_slice)));
         memcpy(sb->base_slices, sb->inlined, slice_count * sizeof(grpc_slice));
       } else {
-        sb->base_slices = (grpc_slice*)gpr_realloc(
-            sb->base_slices, sb->capacity * sizeof(grpc_slice));
+        sb->base_slices = static_cast<grpc_slice*>(
+            gpr_realloc(sb->base_slices, sb->capacity * sizeof(grpc_slice)));
       }
 
       sb->slices = sb->base_slices + slice_offset;
@@ -89,7 +91,8 @@
   if ((back->data.inlined.length + n) > sizeof(back->data.inlined.bytes))
     goto add_new;
   out = back->data.inlined.bytes + back->data.inlined.length;
-  back->data.inlined.length = (uint8_t)(back->data.inlined.length + n);
+  back->data.inlined.length =
+      static_cast<uint8_t>(back->data.inlined.length + n);
   return out;
 
 add_new:
@@ -97,7 +100,7 @@
   back = &sb->slices[sb->count];
   sb->count++;
   back->refcount = nullptr;
-  back->data.inlined.length = (uint8_t)n;
+  back->data.inlined.length = static_cast<uint8_t>(n);
   return back->data.inlined.bytes;
 }
 
@@ -125,8 +128,8 @@
           GRPC_SLICE_INLINED_SIZE) {
         memcpy(back->data.inlined.bytes + back->data.inlined.length,
                s.data.inlined.bytes, s.data.inlined.length);
-        back->data.inlined.length =
-            (uint8_t)(back->data.inlined.length + s.data.inlined.length);
+        back->data.inlined.length = static_cast<uint8_t>(
+            back->data.inlined.length + s.data.inlined.length);
       } else {
         size_t cp1 = GRPC_SLICE_INLINED_SIZE - back->data.inlined.length;
         memcpy(back->data.inlined.bytes + back->data.inlined.length,
@@ -136,7 +139,8 @@
         back = &sb->slices[n];
         sb->count = n + 1;
         back->refcount = nullptr;
-        back->data.inlined.length = (uint8_t)(s.data.inlined.length - cp1);
+        back->data.inlined.length =
+            static_cast<uint8_t>(s.data.inlined.length - cp1);
         memcpy(back->data.inlined.bytes, s.data.inlined.bytes + cp1,
                s.data.inlined.length - cp1);
       }
@@ -177,8 +181,8 @@
 }
 
 void grpc_slice_buffer_swap(grpc_slice_buffer* a, grpc_slice_buffer* b) {
-  size_t a_offset = (size_t)(a->slices - a->base_slices);
-  size_t b_offset = (size_t)(b->slices - b->base_slices);
+  size_t a_offset = static_cast<size_t>(a->slices - a->base_slices);
+  size_t b_offset = static_cast<size_t>(b->slices - b->base_slices);
 
   size_t a_count = a->count + a_offset;
   size_t b_count = b->count + b_offset;
@@ -287,7 +291,7 @@
 
 void grpc_slice_buffer_move_first_into_buffer(grpc_slice_buffer* src, size_t n,
                                               void* dst) {
-  char* dstp = (char*)dst;
+  char* dstp = static_cast<char*>(dst);
   GPR_ASSERT(src->length >= n);
 
   while (n > 0) {
diff --git a/src/core/lib/slice/slice_hash_table.cc b/src/core/lib/slice/slice_hash_table.cc
deleted file mode 100644
index 89340ef..0000000
--- a/src/core/lib/slice/slice_hash_table.cc
+++ /dev/null
@@ -1,144 +0,0 @@
-//
-// Copyright 2016 gRPC authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#include "src/core/lib/slice/slice_hash_table.h"
-
-#include <stdbool.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-#include "src/core/lib/slice/slice_internal.h"
-#include "src/core/lib/transport/metadata.h"
-
-struct grpc_slice_hash_table {
-  gpr_refcount refs;
-  void (*destroy_value)(void* value);
-  int (*value_cmp)(void* a, void* b);
-  size_t size;
-  size_t max_num_probes;
-  grpc_slice_hash_table_entry* entries;
-};
-
-static bool is_empty(grpc_slice_hash_table_entry* entry) {
-  return entry->value == nullptr;
-}
-
-static void grpc_slice_hash_table_add(grpc_slice_hash_table* table,
-                                      grpc_slice key, void* value) {
-  GPR_ASSERT(value != nullptr);
-  const size_t hash = grpc_slice_hash(key);
-  for (size_t offset = 0; offset < table->size; ++offset) {
-    const size_t idx = (hash + offset) % table->size;
-    if (is_empty(&table->entries[idx])) {
-      table->entries[idx].key = key;
-      table->entries[idx].value = value;
-      // Keep track of the maximum number of probes needed, since this
-      // provides an upper bound for lookups.
-      if (offset > table->max_num_probes) table->max_num_probes = offset;
-      return;
-    }
-  }
-  GPR_ASSERT(false);  // Table should never be full.
-}
-
-grpc_slice_hash_table* grpc_slice_hash_table_create(
-    size_t num_entries, grpc_slice_hash_table_entry* entries,
-    void (*destroy_value)(void* value), int (*value_cmp)(void* a, void* b)) {
-  grpc_slice_hash_table* table =
-      (grpc_slice_hash_table*)gpr_zalloc(sizeof(*table));
-  gpr_ref_init(&table->refs, 1);
-  table->destroy_value = destroy_value;
-  table->value_cmp = value_cmp;
-  // Keep load factor low to improve performance of lookups.
-  table->size = num_entries * 2;
-  const size_t entry_size = sizeof(grpc_slice_hash_table_entry) * table->size;
-  table->entries = (grpc_slice_hash_table_entry*)gpr_zalloc(entry_size);
-  for (size_t i = 0; i < num_entries; ++i) {
-    grpc_slice_hash_table_entry* entry = &entries[i];
-    grpc_slice_hash_table_add(table, entry->key, entry->value);
-  }
-  return table;
-}
-
-grpc_slice_hash_table* grpc_slice_hash_table_ref(grpc_slice_hash_table* table) {
-  if (table != nullptr) gpr_ref(&table->refs);
-  return table;
-}
-
-void grpc_slice_hash_table_unref(grpc_slice_hash_table* table) {
-  if (table != nullptr && gpr_unref(&table->refs)) {
-    for (size_t i = 0; i < table->size; ++i) {
-      grpc_slice_hash_table_entry* entry = &table->entries[i];
-      if (!is_empty(entry)) {
-        grpc_slice_unref_internal(entry->key);
-        table->destroy_value(entry->value);
-      }
-    }
-    gpr_free(table->entries);
-    gpr_free(table);
-  }
-}
-
-void* grpc_slice_hash_table_get(const grpc_slice_hash_table* table,
-                                const grpc_slice key) {
-  const size_t hash = grpc_slice_hash(key);
-  // We cap the number of probes at the max number recorded when
-  // populating the table.
-  for (size_t offset = 0; offset <= table->max_num_probes; ++offset) {
-    const size_t idx = (hash + offset) % table->size;
-    if (is_empty(&table->entries[idx])) break;
-    if (grpc_slice_eq(table->entries[idx].key, key)) {
-      return table->entries[idx].value;
-    }
-  }
-  return nullptr;  // Not found.
-}
-
-static int pointer_cmp(void* a, void* b) { return GPR_ICMP(a, b); }
-int grpc_slice_hash_table_cmp(const grpc_slice_hash_table* a,
-                              const grpc_slice_hash_table* b) {
-  int (*const value_cmp_fn_a)(void* a, void* b) =
-      a->value_cmp != nullptr ? a->value_cmp : pointer_cmp;
-  int (*const value_cmp_fn_b)(void* a, void* b) =
-      b->value_cmp != nullptr ? b->value_cmp : pointer_cmp;
-  // Compare value_fns
-  const int value_fns_cmp =
-      GPR_ICMP((void*)value_cmp_fn_a, (void*)value_cmp_fn_b);
-  if (value_fns_cmp != 0) return value_fns_cmp;
-  // Compare sizes
-  if (a->size < b->size) return -1;
-  if (a->size > b->size) return 1;
-  // Compare rows.
-  for (size_t i = 0; i < a->size; ++i) {
-    if (is_empty(&a->entries[i])) {
-      if (!is_empty(&b->entries[i])) {
-        return -1;  // a empty but b non-empty
-      }
-      continue;  // both empty, no need to check key or value
-    } else if (is_empty(&b->entries[i])) {
-      return 1;  // a non-empty but b empty
-    }
-    // neither entry is empty
-    const int key_cmp = grpc_slice_cmp(a->entries[i].key, b->entries[i].key);
-    if (key_cmp != 0) return key_cmp;
-    const int value_cmp =
-        value_cmp_fn_a(a->entries[i].value, b->entries[i].value);
-    if (value_cmp != 0) return value_cmp;
-  }
-  return 0;
-}
diff --git a/src/core/lib/slice/slice_hash_table.h b/src/core/lib/slice/slice_hash_table.h
index db69da6..fbe9cc5 100644
--- a/src/core/lib/slice/slice_hash_table.h
+++ b/src/core/lib/slice/slice_hash_table.h
@@ -17,52 +17,185 @@
 #ifndef GRPC_CORE_LIB_SLICE_SLICE_HASH_TABLE_H
 #define GRPC_CORE_LIB_SLICE_SLICE_HASH_TABLE_H
 
-#include "src/core/lib/transport/metadata.h"
+#include <grpc/support/port_platform.h>
 
-/** Hash table implementation.
- *
- * This implementation uses open addressing
- * (https://en.wikipedia.org/wiki/Open_addressing) with linear
- * probing (https://en.wikipedia.org/wiki/Linear_probing).
- *
- * The keys are \a grpc_slice objects.  The values are arbitrary pointers
- * with a common destroy function.
- *
- * Hash tables are intentionally immutable, to avoid the need for locking.
- */
+#include <string.h>
 
-typedef struct grpc_slice_hash_table grpc_slice_hash_table;
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
 
-typedef struct grpc_slice_hash_table_entry {
-  grpc_slice key;
-  void* value; /* Must not be NULL. */
-} grpc_slice_hash_table_entry;
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/ref_counted.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
+#include "src/core/lib/slice/slice_internal.h"
 
-/** Creates a new hash table of containing \a entries, which is an array
-    of length \a num_entries.  Takes ownership of all keys and values in \a
-    entries.  Values will be cleaned up via \a destroy_value(). If not NULL, \a
-    value_cmp will be used to compare values in the context of \a
-    grpc_slice_hash_table_cmp. If NULL, raw pointer (\a GPR_ICMP) comparison
-    will be used. */
-grpc_slice_hash_table* grpc_slice_hash_table_create(
-    size_t num_entries, grpc_slice_hash_table_entry* entries,
-    void (*destroy_value)(void* value), int (*value_cmp)(void* a, void* b));
+/// Hash table implementation.
+///
+/// This implementation uses open addressing
+/// (https://en.wikipedia.org/wiki/Open_addressing) with linear
+/// probing (https://en.wikipedia.org/wiki/Linear_probing).
+///
+/// The keys are \a grpc_slice objects.  The values can be any type.
+///
+/// Hash tables are intentionally immutable, to avoid the need for locking.
 
-grpc_slice_hash_table* grpc_slice_hash_table_ref(grpc_slice_hash_table* table);
-void grpc_slice_hash_table_unref(grpc_slice_hash_table* table);
+namespace grpc_core {
 
-/** Returns the value from \a table associated with \a key.
-    Returns NULL if \a key is not found. */
-void* grpc_slice_hash_table_get(const grpc_slice_hash_table* table,
-                                const grpc_slice key);
+template <typename T>
+class SliceHashTable : public RefCounted<SliceHashTable<T>> {
+ public:
+  struct Entry {
+    grpc_slice key;
+    T value;
+    bool is_set;
+  };
 
-/** Compares \a a vs. \a b.
- * A table is considered "smaller" (resp. "greater") if:
- *  - GPR_ICMP(a->value_cmp, b->value_cmp) < 1 (resp. > 1),
- *  - else, it contains fewer (resp. more) entries,
- *  - else, if strcmp(a_key, b_key) < 1 (resp. > 1),
- *  - else, if value_cmp(a_value, b_value) < 1 (resp. > 1). */
-int grpc_slice_hash_table_cmp(const grpc_slice_hash_table* a,
-                              const grpc_slice_hash_table* b);
+  // Function for comparing values.
+  // TODO(roth): Eliminate this and the Cmp() method from this API once
+  // grpc_channel_args is redesigned to require that keys are unique.
+  typedef int (*ValueCmp)(const T&, const T&);
+
+  /// Creates a new hash table containing \a entries, which is an array
+  /// of length \a num_entries.  Takes ownership of all keys and values in \a
+  /// entries.  If not null, \a value_cmp will be used to compare values in
+  /// the context of \a Cmp(). If null, raw pointer (\a GPR_ICMP) comparison
+  /// will be used.
+  static RefCountedPtr<SliceHashTable> Create(size_t num_entries,
+                                              Entry* entries,
+                                              ValueCmp value_cmp);
+
+  /// Returns the value from the table associated with \a key.
+  /// Returns null if \a key is not found.
+  const T* Get(const grpc_slice& key) const;
+
+  /// Compares \a a vs. \a b.
+  /// A table is considered "smaller" (resp. "greater") if:
+  ///  - GPR_ICMP(a->value_cmp, b->value_cmp) < 1 (resp. > 1),
+  ///  - else, it contains fewer (resp. more) entries,
+  ///  - else, if strcmp(a_key, b_key) < 1 (resp. > 1),
+  ///  - else, if value_cmp(a_value, b_value) < 1 (resp. > 1).
+  static int Cmp(const SliceHashTable& a, const SliceHashTable& b);
+
+ private:
+  // So New() can call our private ctor.
+  template <typename T2, typename... Args>
+  friend T2* New(Args&&... args);
+
+  SliceHashTable(size_t num_entries, Entry* entries, ValueCmp value_cmp);
+  virtual ~SliceHashTable();
+
+  void Add(grpc_slice key, T& value);
+
+  // Default value comparison function, if none specified by caller.
+  static int DefaultValueCmp(const T& a, const T& b) { return GPR_ICMP(a, b); }
+
+  const ValueCmp value_cmp_;
+  const size_t size_;
+  size_t max_num_probes_;
+  Entry* entries_;
+};
+
+//
+// implementation -- no user-serviceable parts below
+//
+
+template <typename T>
+RefCountedPtr<SliceHashTable<T>> SliceHashTable<T>::Create(size_t num_entries,
+                                                           Entry* entries,
+                                                           ValueCmp value_cmp) {
+  return MakeRefCounted<SliceHashTable<T>>(num_entries, entries, value_cmp);
+}
+
+template <typename T>
+SliceHashTable<T>::SliceHashTable(size_t num_entries, Entry* entries,
+                                  ValueCmp value_cmp)
+    : value_cmp_(value_cmp),
+      // Keep load factor low to improve performance of lookups.
+      size_(num_entries * 2),
+      max_num_probes_(0) {
+  entries_ = static_cast<Entry*>(gpr_zalloc(sizeof(Entry) * size_));
+  for (size_t i = 0; i < num_entries; ++i) {
+    Entry* entry = &entries[i];
+    Add(entry->key, entry->value);
+  }
+}
+
+template <typename T>
+SliceHashTable<T>::~SliceHashTable() {
+  for (size_t i = 0; i < size_; ++i) {
+    Entry& entry = entries_[i];
+    if (entry.is_set) {
+      grpc_slice_unref_internal(entry.key);
+      entry.value.~T();
+    }
+  }
+  gpr_free(entries_);
+}
+
+template <typename T>
+void SliceHashTable<T>::Add(grpc_slice key, T& value) {
+  const size_t hash = grpc_slice_hash(key);
+  for (size_t offset = 0; offset < size_; ++offset) {
+    const size_t idx = (hash + offset) % size_;
+    if (!entries_[idx].is_set) {
+      entries_[idx].is_set = true;
+      entries_[idx].key = key;
+      entries_[idx].value = std::move(value);
+      // Keep track of the maximum number of probes needed, since this
+      // provides an upper bound for lookups.
+      if (offset > max_num_probes_) max_num_probes_ = offset;
+      return;
+    }
+  }
+  GPR_ASSERT(false);  // Table should never be full.
+}
+
+template <typename T>
+const T* SliceHashTable<T>::Get(const grpc_slice& key) const {
+  const size_t hash = grpc_slice_hash(key);
+  // We cap the number of probes at the max number recorded when
+  // populating the table.
+  for (size_t offset = 0; offset <= max_num_probes_; ++offset) {
+    const size_t idx = (hash + offset) % size_;
+    if (!entries_[idx].is_set) break;
+    if (grpc_slice_eq(entries_[idx].key, key)) {
+      return &entries_[idx].value;
+    }
+  }
+  return nullptr;  // Not found.
+}
+
+template <typename T>
+int SliceHashTable<T>::Cmp(const SliceHashTable& a, const SliceHashTable& b) {
+  ValueCmp value_cmp_a =
+      a.value_cmp_ != nullptr ? a.value_cmp_ : DefaultValueCmp;
+  ValueCmp value_cmp_b =
+      b.value_cmp_ != nullptr ? b.value_cmp_ : DefaultValueCmp;
+  // Compare value_fns
+  const int value_fns_cmp = GPR_ICMP((void*)value_cmp_a, (void*)value_cmp_b);
+  if (value_fns_cmp != 0) return value_fns_cmp;
+  // Compare sizes
+  if (a.size_ < b.size_) return -1;
+  if (a.size_ > b.size_) return 1;
+  // Compare rows.
+  for (size_t i = 0; i < a.size_; ++i) {
+    if (!a.entries_[i].is_set) {
+      if (b.entries_[i].is_set) {
+        return -1;  // a empty but b non-empty
+      }
+      continue;  // both empty, no need to check key or value
+    } else if (!b.entries_[i].is_set) {
+      return 1;  // a non-empty but b empty
+    }
+    // neither entry is empty
+    const int key_cmp = grpc_slice_cmp(a.entries_[i].key, b.entries_[i].key);
+    if (key_cmp != 0) return key_cmp;
+    const int value_cmp = value_cmp_a(a.entries_[i].value, b.entries_[i].value);
+    if (value_cmp != 0) return value_cmp;
+  }
+  return 0;
+}
+
+}  // namespace grpc_core
 
 #endif /* GRPC_CORE_LIB_SLICE_SLICE_HASH_TABLE_H */
diff --git a/src/core/lib/slice/slice_intern.cc b/src/core/lib/slice/slice_intern.cc
index cf471f3..e53c040 100644
--- a/src/core/lib/slice/slice_intern.cc
+++ b/src/core/lib/slice/slice_intern.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/slice/slice_internal.h"
 
 #include <inttypes.h>
@@ -70,7 +72,7 @@
 static uint32_t static_metadata_hash_values[GRPC_STATIC_MDSTR_COUNT];
 
 static void interned_slice_ref(void* p) {
-  interned_slice_refcount* s = (interned_slice_refcount*)p;
+  interned_slice_refcount* s = static_cast<interned_slice_refcount*>(p);
   GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&s->refcnt, 1) > 0);
 }
 
@@ -91,22 +93,25 @@
 }
 
 static void interned_slice_unref(void* p) {
-  interned_slice_refcount* s = (interned_slice_refcount*)p;
+  interned_slice_refcount* s = static_cast<interned_slice_refcount*>(p);
   if (1 == gpr_atm_full_fetch_add(&s->refcnt, -1)) {
     interned_slice_destroy(s);
   }
 }
 
 static void interned_slice_sub_ref(void* p) {
-  interned_slice_ref(((char*)p) - offsetof(interned_slice_refcount, sub));
+  interned_slice_ref((static_cast<char*>(p)) -
+                     offsetof(interned_slice_refcount, sub));
 }
 
 static void interned_slice_sub_unref(void* p) {
-  interned_slice_unref(((char*)p) - offsetof(interned_slice_refcount, sub));
+  interned_slice_unref((static_cast<char*>(p)) -
+                       offsetof(interned_slice_refcount, sub));
 }
 
 static uint32_t interned_slice_hash(grpc_slice slice) {
-  interned_slice_refcount* s = (interned_slice_refcount*)slice.refcount;
+  interned_slice_refcount* s =
+      reinterpret_cast<interned_slice_refcount*>(slice.refcount);
   return s->hash;
 }
 
@@ -129,8 +134,8 @@
   interned_slice_refcount** strtab;
   interned_slice_refcount *s, *next;
 
-  strtab = (interned_slice_refcount**)gpr_zalloc(
-      sizeof(interned_slice_refcount*) * capacity);
+  strtab = static_cast<interned_slice_refcount**>(
+      gpr_zalloc(sizeof(interned_slice_refcount*) * capacity));
 
   for (i = 0; i < shard->capacity; i++) {
     for (s = shard->strs[i]; s; s = next) {
@@ -148,7 +153,7 @@
 static grpc_slice materialize(interned_slice_refcount* s) {
   grpc_slice slice;
   slice.refcount = &s->base;
-  slice.data.refcounted.bytes = (uint8_t*)(s + 1);
+  slice.data.refcounted.bytes = reinterpret_cast<uint8_t*>(s + 1);
   slice.data.refcounted.length = s->length;
   return slice;
 }
@@ -237,8 +242,8 @@
 
   /* not found: create a new string */
   /* string data goes after the internal_string header */
-  s = (interned_slice_refcount*)gpr_malloc(sizeof(*s) +
-                                           GRPC_SLICE_LENGTH(slice));
+  s = static_cast<interned_slice_refcount*>(
+      gpr_malloc(sizeof(*s) + GRPC_SLICE_LENGTH(slice)));
   gpr_atm_rel_store(&s->refcnt, 1);
   s->length = GRPC_SLICE_LENGTH(slice);
   s->hash = hash;
@@ -268,15 +273,15 @@
 
 void grpc_slice_intern_init(void) {
   if (!g_forced_hash_seed) {
-    g_hash_seed = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec;
+    g_hash_seed = static_cast<uint32_t>(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
   }
   for (size_t i = 0; i < SHARD_COUNT; i++) {
     slice_shard* shard = &g_shards[i];
     gpr_mu_init(&shard->mu);
     shard->count = 0;
     shard->capacity = INITIAL_SHARD_CAPACITY;
-    shard->strs = (interned_slice_refcount**)gpr_zalloc(sizeof(*shard->strs) *
-                                                        shard->capacity);
+    shard->strs = static_cast<interned_slice_refcount**>(
+        gpr_zalloc(sizeof(*shard->strs) * shard->capacity));
   }
   for (size_t i = 0; i < GPR_ARRAY_SIZE(static_metadata_hash); i++) {
     static_metadata_hash[i].hash = 0;
@@ -291,9 +296,9 @@
                     GPR_ARRAY_SIZE(static_metadata_hash);
       if (static_metadata_hash[slot].idx == GRPC_STATIC_MDSTR_COUNT) {
         static_metadata_hash[slot].hash = static_metadata_hash_values[i];
-        static_metadata_hash[slot].idx = (uint32_t)i;
+        static_metadata_hash[slot].idx = static_cast<uint32_t>(i);
         if (j > max_static_metadata_hash_probe) {
-          max_static_metadata_hash_probe = (uint32_t)j;
+          max_static_metadata_hash_probe = static_cast<uint32_t>(j);
         }
         break;
       }
diff --git a/src/core/lib/slice/slice_internal.h b/src/core/lib/slice/slice_internal.h
index 4e9ab80..5d3d26b 100644
--- a/src/core/lib/slice/slice_internal.h
+++ b/src/core/lib/slice/slice_internal.h
@@ -19,11 +19,11 @@
 #ifndef GRPC_CORE_LIB_SLICE_SLICE_INTERNAL_H
 #define GRPC_CORE_LIB_SLICE_SLICE_INTERNAL_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice.h>
 #include <grpc/slice_buffer.h>
 
-#include "src/core/lib/iomgr/exec_ctx.h"
-
 grpc_slice grpc_slice_ref_internal(grpc_slice slice);
 void grpc_slice_unref_internal(grpc_slice slice);
 void grpc_slice_buffer_reset_and_unref_internal(grpc_slice_buffer* sb);
diff --git a/src/core/lib/slice/slice_string_helpers.cc b/src/core/lib/slice/slice_string_helpers.cc
index 4441a26..6af9c33 100644
--- a/src/core/lib/slice/slice_string_helpers.cc
+++ b/src/core/lib/slice/slice_string_helpers.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/slice/slice_string_helpers.h"
 
 #include <string.h>
@@ -26,8 +28,8 @@
 #include "src/core/lib/slice/slice_internal.h"
 
 char* grpc_dump_slice(grpc_slice s, uint32_t flags) {
-  return gpr_dump((const char*)GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s),
-                  flags);
+  return gpr_dump(reinterpret_cast<const char*> GRPC_SLICE_START_PTR(s),
+                  GRPC_SLICE_LENGTH(s), flags);
 }
 
 /** Finds the initial (\a begin) and final (\a end) offsets of the next
@@ -110,6 +112,7 @@
 }
 
 bool grpc_parse_slice_to_uint32(grpc_slice str, uint32_t* result) {
-  return gpr_parse_bytes_to_uint32((const char*)GRPC_SLICE_START_PTR(str),
-                                   GRPC_SLICE_LENGTH(str), result) != 0;
+  return gpr_parse_bytes_to_uint32(
+             reinterpret_cast<const char*> GRPC_SLICE_START_PTR(str),
+             GRPC_SLICE_LENGTH(str), result) != 0;
 }
diff --git a/src/core/lib/slice/slice_string_helpers.h b/src/core/lib/slice/slice_string_helpers.h
index 429f9ff..976f724 100644
--- a/src/core/lib/slice/slice_string_helpers.h
+++ b/src/core/lib/slice/slice_string_helpers.h
@@ -19,12 +19,13 @@
 #ifndef GRPC_CORE_LIB_SLICE_SLICE_STRING_HELPERS_H
 #define GRPC_CORE_LIB_SLICE_SLICE_STRING_HELPERS_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stdbool.h>
 #include <stddef.h>
 
 #include <grpc/slice.h>
 #include <grpc/slice_buffer.h>
-#include <grpc/support/port_platform.h>
 
 #include "src/core/lib/gpr/string.h"
 
diff --git a/src/core/lib/slice/slice_traits.h b/src/core/lib/slice/slice_traits.h
index 4b898bd..ee01916 100644
--- a/src/core/lib/slice/slice_traits.h
+++ b/src/core/lib/slice/slice_traits.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SLICE_SLICE_TRAITS_H
 #define GRPC_CORE_LIB_SLICE_SLICE_TRAITS_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice.h>
 #include <stdbool.h>
 
diff --git a/src/core/lib/slice/slice_weak_hash_table.h b/src/core/lib/slice/slice_weak_hash_table.h
new file mode 100644
index 0000000..9d0ddfc
--- /dev/null
+++ b/src/core/lib/slice/slice_weak_hash_table.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_LIB_SLICE_SLICE_WEAK_HASH_TABLE_H
+#define GRPC_CORE_LIB_SLICE_SLICE_WEAK_HASH_TABLE_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/gprpp/ref_counted.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
+#include "src/core/lib/slice/slice_internal.h"
+
+/// Weak hash table implementation.
+///
+/// This entries in this table are weak: an entry may be removed at any time due
+/// to a number of reasons: memory pressure, hash collisions, etc.
+///
+/// The keys are \a grpc_slice objects. The values are of arbitrary type.
+///
+/// This class is thread unsafe. It's the caller's responsibility to ensure
+/// proper locking when accessing its methods.
+
+namespace grpc_core {
+
+template <typename T, size_t Size>
+class SliceWeakHashTable : public RefCounted<SliceWeakHashTable<T, Size>> {
+ public:
+  /// Creates a new table of at most \a size entries.
+  static RefCountedPtr<SliceWeakHashTable> Create() {
+    return MakeRefCounted<SliceWeakHashTable<T, Size>>();
+  }
+
+  /// Add a mapping from \a key to \a value, taking ownership of \a key. This
+  /// operation will always succeed. It may discard older entries.
+  void Add(grpc_slice key, T value) {
+    const size_t idx = grpc_slice_hash(key) % Size;
+    entries_[idx].Set(key, std::move(value));
+    return;
+  }
+
+  /// Returns the value from the table associated with / \a key or null if not
+  /// found.
+  const T* Get(const grpc_slice key) const {
+    const size_t idx = grpc_slice_hash(key) % Size;
+    const auto& entry = entries_[idx];
+    return grpc_slice_eq(entry.key(), key) ? entry.value() : nullptr;
+  }
+
+ private:
+  // So New() can call our private ctor.
+  template <typename T2, typename... Args>
+  friend T2* New(Args&&... args);
+
+  SliceWeakHashTable() = default;
+  ~SliceWeakHashTable() = default;
+
+  /// The type of the table "rows".
+  class Entry {
+   public:
+    Entry() = default;
+    ~Entry() {
+      if (is_set_) grpc_slice_unref_internal(key_);
+    }
+    grpc_slice key() const { return key_; }
+
+    /// Return the entry's value, or null if unset.
+    const T* value() const {
+      if (!is_set_) return nullptr;
+      return &value_;
+    }
+
+    /// Set the \a key and \a value (which is moved) for the entry.
+    void Set(grpc_slice key, T&& value) {
+      if (is_set_) grpc_slice_unref_internal(key_);
+      key_ = key;
+      value_ = std::move(value);
+      is_set_ = true;
+    }
+
+   private:
+    grpc_slice key_;
+    T value_;
+    bool is_set_ = false;
+  };
+
+  Entry entries_[Size];
+};
+
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_SLICE_SLICE_WEAK_HASH_TABLE_H */
diff --git a/src/core/lib/surface/api_trace.cc b/src/core/lib/surface/api_trace.cc
index 7ab836a..bab5a79 100644
--- a/src/core/lib/surface/api_trace.cc
+++ b/src/core/lib/surface/api_trace.cc
@@ -16,7 +16,9 @@
  *
  */
 
-#include "src/core/lib/surface/api_trace.h"
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/debug/trace.h"
+#include "src/core/lib/surface/api_trace.h"
 
 grpc_core::TraceFlag grpc_api_trace(false, "api");
diff --git a/src/core/lib/surface/api_trace.h b/src/core/lib/surface/api_trace.h
index a4e11ce..72ed830 100644
--- a/src/core/lib/surface/api_trace.h
+++ b/src/core/lib/surface/api_trace.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SURFACE_API_TRACE_H
 #define GRPC_CORE_LIB_SURFACE_API_TRACE_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/support/log.h>
 #include "src/core/lib/debug/trace.h"
 
diff --git a/src/core/lib/surface/byte_buffer.cc b/src/core/lib/surface/byte_buffer.cc
index e4c2a4a..6246796 100644
--- a/src/core/lib/surface/byte_buffer.cc
+++ b/src/core/lib/surface/byte_buffer.cc
@@ -16,10 +16,13 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/byte_buffer.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/slice/slice_internal.h"
 
 grpc_byte_buffer* grpc_raw_byte_buffer_create(grpc_slice* slices,
@@ -33,7 +36,7 @@
     grpc_compression_algorithm compression) {
   size_t i;
   grpc_byte_buffer* bb =
-      (grpc_byte_buffer*)gpr_malloc(sizeof(grpc_byte_buffer));
+      static_cast<grpc_byte_buffer*>(gpr_malloc(sizeof(grpc_byte_buffer)));
   bb->type = GRPC_BB_RAW;
   bb->data.raw.compression = compression;
   grpc_slice_buffer_init(&bb->data.raw.slice_buffer);
@@ -47,7 +50,7 @@
 grpc_byte_buffer* grpc_raw_byte_buffer_from_reader(
     grpc_byte_buffer_reader* reader) {
   grpc_byte_buffer* bb =
-      (grpc_byte_buffer*)gpr_malloc(sizeof(grpc_byte_buffer));
+      static_cast<grpc_byte_buffer*>(gpr_malloc(sizeof(grpc_byte_buffer)));
   grpc_slice slice;
   bb->type = GRPC_BB_RAW;
   bb->data.raw.compression = GRPC_COMPRESS_NONE;
diff --git a/src/core/lib/surface/byte_buffer_reader.cc b/src/core/lib/surface/byte_buffer_reader.cc
index f7ea516..1debc98 100644
--- a/src/core/lib/surface/byte_buffer_reader.cc
+++ b/src/core/lib/surface/byte_buffer_reader.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/byte_buffer_reader.h>
 #include <string.h>
 
@@ -27,6 +29,7 @@
 #include <grpc/support/log.h>
 
 #include "src/core/lib/compression/message_compress.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/slice/slice_internal.h"
 
 static int is_compressed(grpc_byte_buffer* buffer) {
diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc
index f2096d8..c683cc0 100644
--- a/src/core/lib/surface/call.cc
+++ b/src/core/lib/surface/call.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <assert.h>
 #include <limits.h>
 #include <stdio.h>
@@ -28,13 +30,14 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/compression/algorithm_metadata.h"
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/gpr/arena.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/manual_constructor.h"
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/slice/slice_internal.h"
@@ -48,6 +51,7 @@
 #include "src/core/lib/transport/error_utils.h"
 #include "src/core/lib/transport/metadata.h"
 #include "src/core/lib/transport/static_metadata.h"
+#include "src/core/lib/transport/status_metadata.h"
 #include "src/core/lib/transport/transport.h"
 
 /** The maximum number of concurrent batches possible.
@@ -97,7 +101,7 @@
   if ((atm & 1) == 0) {
     return {false, GRPC_ERROR_NONE};
   } else {
-    return {true, (grpc_error*)(atm & ~(gpr_atm)1)};
+    return {true, (grpc_error*)(atm & ~static_cast<gpr_atm>(1))};
   }
 }
 
@@ -218,9 +222,9 @@
   int send_extra_metadata_count;
   grpc_millis send_deadline;
 
-  grpc_slice_buffer_stream sending_stream;
+  grpc_core::ManualConstructor<grpc_core::SliceBufferByteStream> sending_stream;
 
-  grpc_byte_stream* receiving_stream;
+  grpc_core::OrphanablePtr<grpc_core::ByteStream> receiving_stream;
   grpc_byte_buffer** receiving_buffer;
   grpc_slice receiving_slice;
   grpc_closure receiving_slice_ready;
@@ -304,7 +308,7 @@
 static parent_call* get_or_create_parent_call(grpc_call* call) {
   parent_call* p = (parent_call*)gpr_atm_acq_load(&call->parent_call_atm);
   if (p == nullptr) {
-    p = (parent_call*)gpr_arena_alloc(call->arena, sizeof(*p));
+    p = static_cast<parent_call*>(gpr_arena_alloc(call->arena, sizeof(*p)));
     gpr_mu_init(&p->child_list_mu);
     if (!gpr_atm_rel_cas(&call->parent_call_atm, (gpr_atm) nullptr,
                          (gpr_atm)p)) {
@@ -330,8 +334,8 @@
   size_t initial_size = grpc_channel_get_call_size_estimate(args->channel);
   GRPC_STATS_INC_CALL_INITIAL_SIZE(initial_size);
   gpr_arena* arena = gpr_arena_create(initial_size);
-  call = (grpc_call*)gpr_arena_alloc(
-      arena, sizeof(grpc_call) + channel_stack->call_stack_size);
+  call = static_cast<grpc_call*>(gpr_arena_alloc(
+      arena, sizeof(grpc_call) + channel_stack->call_stack_size));
   gpr_ref_init(&call->ext_ref, 1);
   call->arena = arena;
   grpc_call_combiner_init(&call->call_combiner);
@@ -360,7 +364,8 @@
             GRPC_MDVALUE(args->add_initial_metadata[i]));
       }
     }
-    call->send_extra_metadata_count = (int)args->add_initial_metadata_count;
+    call->send_extra_metadata_count =
+        static_cast<int>(args->add_initial_metadata_count);
   } else {
     GPR_ASSERT(args->add_initial_metadata_count == 0);
     call->send_extra_metadata_count = 0;
@@ -375,18 +380,14 @@
   bool immediately_cancel = false;
 
   if (args->parent != nullptr) {
-    child_call* cc = call->child =
-        (child_call*)gpr_arena_alloc(arena, sizeof(child_call));
+    call->child =
+        static_cast<child_call*>(gpr_arena_alloc(arena, sizeof(child_call)));
     call->child->parent = args->parent;
 
     GRPC_CALL_INTERNAL_REF(args->parent, "child");
     GPR_ASSERT(call->is_client);
     GPR_ASSERT(!args->parent->is_client);
 
-    parent_call* pc = get_or_create_parent_call(args->parent);
-
-    gpr_mu_lock(&pc->child_list_mu);
-
     if (args->propagation_mask & GRPC_PROPAGATE_DEADLINE) {
       send_deadline = GPR_MIN(send_deadline, args->parent->send_deadline);
     }
@@ -414,18 +415,6 @@
         immediately_cancel = true;
       }
     }
-
-    if (pc->first_child == nullptr) {
-      pc->first_child = call;
-      cc->sibling_next = cc->sibling_prev = call;
-    } else {
-      cc->sibling_next = pc->first_child;
-      cc->sibling_prev = pc->first_child->child->sibling_prev;
-      cc->sibling_next->child->sibling_prev =
-          cc->sibling_prev->child->sibling_next = call;
-    }
-
-    gpr_mu_unlock(&pc->child_list_mu);
   }
 
   call->send_deadline = send_deadline;
@@ -442,6 +431,22 @@
                                       &call->call_combiner};
   add_init_error(&error, grpc_call_stack_init(channel_stack, 1, destroy_call,
                                               call, &call_args));
+  // Publish this call to parent only after the call stack has been initialized.
+  if (args->parent != nullptr) {
+    child_call* cc = call->child;
+    parent_call* pc = get_or_create_parent_call(args->parent);
+    gpr_mu_lock(&pc->child_list_mu);
+    if (pc->first_child == nullptr) {
+      pc->first_child = call;
+      cc->sibling_next = cc->sibling_prev = call;
+    } else {
+      cc->sibling_next = pc->first_child;
+      cc->sibling_prev = pc->first_child->child->sibling_prev;
+      cc->sibling_next->child->sibling_prev =
+          cc->sibling_prev->child->sibling_next = call;
+    }
+    gpr_mu_unlock(&pc->child_list_mu);
+  }
   if (error != GRPC_ERROR_NONE) {
     cancel_with_error(call, STATUS_FROM_SURFACE, GRPC_ERROR_REF(error));
   }
@@ -500,7 +505,7 @@
 }
 
 static void release_call(void* call, grpc_error* error) {
-  grpc_call* c = (grpc_call*)call;
+  grpc_call* c = static_cast<grpc_call*>(call);
   grpc_channel* channel = c->channel;
   grpc_call_combiner_destroy(&c->call_combiner);
   gpr_free((char*)c->peer_string);
@@ -513,14 +518,12 @@
   GPR_TIMER_SCOPE("destroy_call", 0);
   size_t i;
   int ii;
-  grpc_call* c = (grpc_call*)call;
+  grpc_call* c = static_cast<grpc_call*>(call);
   for (i = 0; i < 2; i++) {
     grpc_metadata_batch_destroy(
         &c->metadata_batch[1 /* is_receiving */][i /* is_initial */]);
   }
-  if (c->receiving_stream != nullptr) {
-    grpc_byte_stream_destroy(c->receiving_stream);
-  }
+  c->receiving_stream.reset();
   parent_call* pc = get_parent_call(c);
   if (pc != nullptr) {
     gpr_mu_destroy(&pc->child_list_mu);
@@ -608,8 +611,9 @@
 // the filter stack.
 static void execute_batch_in_call_combiner(void* arg, grpc_error* ignored) {
   GPR_TIMER_SCOPE("execute_batch", 0);
-  grpc_transport_stream_op_batch* batch = (grpc_transport_stream_op_batch*)arg;
-  grpc_call* call = (grpc_call*)batch->handler_private.extra_arg;
+  grpc_transport_stream_op_batch* batch =
+      static_cast<grpc_transport_stream_op_batch*>(arg);
+  grpc_call* call = static_cast<grpc_call*>(batch->handler_private.extra_arg);
   grpc_call_element* elem = CALL_ELEM_FROM_CALL(call, 0);
   GRPC_CALL_LOG_OP(GPR_INFO, elem, batch);
   elem->filter->start_transport_stream_op_batch(elem, batch);
@@ -667,7 +671,7 @@
 // The on_complete callback used when sending a cancel_stream batch down
 // the filter stack.  Yields the call combiner when the batch is done.
 static void done_termination(void* arg, grpc_error* error) {
-  cancel_state* state = (cancel_state*)arg;
+  cancel_state* state = static_cast<cancel_state*>(arg);
   GRPC_CALL_COMBINER_STOP(&state->call->call_combiner,
                           "on_complete for cancel_stream op");
   GRPC_CALL_INTERNAL_UNREF(state->call, "termination");
@@ -683,7 +687,7 @@
   // down the filter stack in a timely manner.
   grpc_call_combiner_cancel(&c->call_combiner, GRPC_ERROR_REF(error));
   set_status_from_error(c, source, GRPC_ERROR_REF(error));
-  cancel_state* state = (cancel_state*)gpr_malloc(sizeof(*state));
+  cancel_state* state = static_cast<cancel_state*>(gpr_malloc(sizeof(*state)));
   state->call = c;
   GRPC_CLOSURE_INIT(&state->finish_batch, done_termination, state,
                     grpc_schedule_on_exec_ctx);
@@ -845,7 +849,7 @@
       grpc_mdelem_get_user_data(mdel, destroy_encodings_accepted_by_peer);
   if (accepted_user_data != nullptr) {
     *encodings_accepted_by_peer =
-        (uint32_t)(((uintptr_t)accepted_user_data) - 1);
+        static_cast<uint32_t>(((uintptr_t)accepted_user_data) - 1);
     return;
   }
 
@@ -863,11 +867,11 @@
     if (!stream_encoding) {
       r = grpc_message_compression_algorithm_parse(
           accept_encoding_entry_slice,
-          (grpc_message_compression_algorithm*)&algorithm);
+          reinterpret_cast<grpc_message_compression_algorithm*>(&algorithm));
     } else {
       r = grpc_stream_compression_algorithm_parse(
           accept_encoding_entry_slice,
-          (grpc_stream_compression_algorithm*)&algorithm);
+          reinterpret_cast<grpc_stream_compression_algorithm*>(&algorithm));
     }
     if (r) {
       GPR_BITSET(encodings_accepted_by_peer, algorithm);
@@ -885,7 +889,7 @@
 
   grpc_mdelem_set_user_data(
       mdel, destroy_encodings_accepted_by_peer,
-      (void*)(((uintptr_t)(*encodings_accepted_by_peer)) + 1));
+      (void*)((static_cast<uintptr_t>(*encodings_accepted_by_peer)) + 1));
 }
 
 uint32_t grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call* call) {
@@ -936,7 +940,7 @@
                    grpc_validate_header_nonbin_value_is_legal(md->value))) {
       break;
     }
-    l->md = grpc_mdelem_from_grpc_metadata((grpc_metadata*)md);
+    l->md = grpc_mdelem_from_grpc_metadata(const_cast<grpc_metadata*>(md));
   }
   if (i != total_count) {
     for (int j = 0; j < i; j++) {
@@ -972,31 +976,6 @@
   return 1;
 }
 
-/* we offset status by a small amount when storing it into transport metadata
-   as metadata cannot store a 0 value (which is used as OK for grpc_status_codes
-   */
-#define STATUS_OFFSET 1
-static void destroy_status(void* ignored) {}
-
-static uint32_t decode_status(grpc_mdelem md) {
-  uint32_t status;
-  void* user_data;
-  if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) return 0;
-  if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_1)) return 1;
-  if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_2)) return 2;
-  user_data = grpc_mdelem_get_user_data(md, destroy_status);
-  if (user_data != nullptr) {
-    status = ((uint32_t)(intptr_t)user_data) - STATUS_OFFSET;
-  } else {
-    if (!grpc_parse_slice_to_uint32(GRPC_MDVALUE(md), &status)) {
-      status = GRPC_STATUS_UNKNOWN; /* could not parse status code */
-    }
-    grpc_mdelem_set_user_data(md, destroy_status,
-                              (void*)(intptr_t)(status + STATUS_OFFSET));
-  }
-  return status;
-}
-
 static grpc_message_compression_algorithm decode_message_compression(
     grpc_mdelem md) {
   grpc_message_compression_algorithm algorithm =
@@ -1032,6 +1011,7 @@
 static void publish_app_metadata(grpc_call* call, grpc_metadata_batch* b,
                                  int is_trailing) {
   if (b->list.count == 0) return;
+  if (is_trailing && call->buffered_metadata[1] == nullptr) return;
   GPR_TIMER_SCOPE("publish_app_metadata", 0);
   grpc_metadata_array* dest;
   grpc_metadata* mdusr;
@@ -1039,8 +1019,8 @@
   if (dest->count + b->list.count > dest->capacity) {
     dest->capacity =
         GPR_MAX(dest->capacity + b->list.count, dest->capacity * 3 / 2);
-    dest->metadata = (grpc_metadata*)gpr_realloc(
-        dest->metadata, sizeof(grpc_metadata) * dest->capacity);
+    dest->metadata = static_cast<grpc_metadata*>(
+        gpr_realloc(dest->metadata, sizeof(grpc_metadata) * dest->capacity));
   }
   for (grpc_linked_mdelem* l = b->list.head; l != nullptr; l = l->next) {
     mdusr = &dest->metadata[dest->count++];
@@ -1085,16 +1065,17 @@
 }
 
 static void recv_trailing_filter(void* args, grpc_metadata_batch* b) {
-  grpc_call* call = (grpc_call*)args;
+  grpc_call* call = static_cast<grpc_call*>(args);
   if (b->idx.named.grpc_status != nullptr) {
-    uint32_t status_code = decode_status(b->idx.named.grpc_status->md);
+    grpc_status_code status_code =
+        grpc_get_status_code_from_metadata(b->idx.named.grpc_status->md);
     grpc_error* error =
         status_code == GRPC_STATUS_OK
             ? GRPC_ERROR_NONE
             : grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
                                      "Error received from peer"),
                                  GRPC_ERROR_INT_GRPC_STATUS,
-                                 (intptr_t)status_code);
+                                 static_cast<intptr_t>(status_code));
     if (b->idx.named.grpc_message != nullptr) {
       error = grpc_error_set_str(
           error, GRPC_ERROR_STR_GRPC_MESSAGE,
@@ -1119,11 +1100,11 @@
  */
 
 static void set_status_value_directly(grpc_status_code status, void* dest) {
-  *(grpc_status_code*)dest = status;
+  *static_cast<grpc_status_code*>(dest) = status;
 }
 
 static void set_cancelled_value(grpc_status_code status, void* dest) {
-  *(int*)dest = (status != GRPC_STATUS_OK);
+  *static_cast<int*>(dest) = (status != GRPC_STATUS_OK);
 }
 
 static bool are_write_flags_valid(uint32_t flags) {
@@ -1169,8 +1150,8 @@
   int slot = batch_slot_for_op(ops[0].op);
   batch_control** pslot = &call->active_batches[slot];
   if (*pslot == nullptr) {
-    *pslot =
-        (batch_control*)gpr_arena_alloc(call->arena, sizeof(batch_control));
+    *pslot = static_cast<batch_control*>(
+        gpr_arena_alloc(call->arena, sizeof(batch_control)));
   }
   batch_control* bctl = *pslot;
   if (bctl->call != nullptr) {
@@ -1184,14 +1165,14 @@
 
 static void finish_batch_completion(void* user_data,
                                     grpc_cq_completion* storage) {
-  batch_control* bctl = (batch_control*)user_data;
+  batch_control* bctl = static_cast<batch_control*>(user_data);
   grpc_call* call = bctl->call;
   bctl->call = nullptr;
   GRPC_CALL_INTERNAL_UNREF(call, "completion");
 }
 
 static grpc_error* consolidate_batch_errors(batch_control* bctl) {
-  size_t n = (size_t)gpr_atm_acq_load(&bctl->num_errors);
+  size_t n = static_cast<size_t>(gpr_atm_acq_load(&bctl->num_errors));
   if (n == 0) {
     return GRPC_ERROR_NONE;
   } else if (n == 1) {
@@ -1299,25 +1280,21 @@
   grpc_error* error;
   grpc_call* call = bctl->call;
   for (;;) {
-    size_t remaining = call->receiving_stream->length -
+    size_t remaining = call->receiving_stream->length() -
                        (*call->receiving_buffer)->data.raw.slice_buffer.length;
     if (remaining == 0) {
       call->receiving_message = 0;
-      grpc_byte_stream_destroy(call->receiving_stream);
-      call->receiving_stream = nullptr;
+      call->receiving_stream.reset();
       finish_batch_step(bctl);
       return;
     }
-    if (grpc_byte_stream_next(call->receiving_stream, remaining,
-                              &call->receiving_slice_ready)) {
-      error =
-          grpc_byte_stream_pull(call->receiving_stream, &call->receiving_slice);
+    if (call->receiving_stream->Next(remaining, &call->receiving_slice_ready)) {
+      error = call->receiving_stream->Pull(&call->receiving_slice);
       if (error == GRPC_ERROR_NONE) {
         grpc_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer,
                               call->receiving_slice);
       } else {
-        grpc_byte_stream_destroy(call->receiving_stream);
-        call->receiving_stream = nullptr;
+        call->receiving_stream.reset();
         grpc_byte_buffer_destroy(*call->receiving_buffer);
         *call->receiving_buffer = nullptr;
         call->receiving_message = 0;
@@ -1331,21 +1308,19 @@
 }
 
 static void receiving_slice_ready(void* bctlp, grpc_error* error) {
-  batch_control* bctl = (batch_control*)bctlp;
+  batch_control* bctl = static_cast<batch_control*>(bctlp);
   grpc_call* call = bctl->call;
-  grpc_byte_stream* bs = call->receiving_stream;
   bool release_error = false;
 
   if (error == GRPC_ERROR_NONE) {
     grpc_slice slice;
-    error = grpc_byte_stream_pull(bs, &slice);
+    error = call->receiving_stream->Pull(&slice);
     if (error == GRPC_ERROR_NONE) {
       grpc_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer,
                             slice);
       continue_receiving_slices(bctl);
     } else {
-      /* Error returned by grpc_byte_stream_pull needs to be released manually
-       */
+      /* Error returned by ByteStream::Pull() needs to be released manually */
       release_error = true;
     }
   }
@@ -1354,8 +1329,7 @@
     if (grpc_trace_operation_failures.enabled()) {
       GRPC_LOG_IF_ERROR("receiving_slice_ready", GRPC_ERROR_REF(error));
     }
-    grpc_byte_stream_destroy(call->receiving_stream);
-    call->receiving_stream = nullptr;
+    call->receiving_stream.reset();
     grpc_byte_buffer_destroy(*call->receiving_buffer);
     *call->receiving_buffer = nullptr;
     call->receiving_message = 0;
@@ -1373,8 +1347,8 @@
     call->receiving_message = 0;
     finish_batch_step(bctl);
   } else {
-    call->test_only_last_message_flags = call->receiving_stream->flags;
-    if ((call->receiving_stream->flags & GRPC_WRITE_INTERNAL_COMPRESS) &&
+    call->test_only_last_message_flags = call->receiving_stream->flags();
+    if ((call->receiving_stream->flags() & GRPC_WRITE_INTERNAL_COMPRESS) &&
         (call->incoming_message_compression_algorithm >
          GRPC_MESSAGE_COMPRESS_NONE)) {
       grpc_compression_algorithm algo;
@@ -1394,13 +1368,10 @@
 }
 
 static void receiving_stream_ready(void* bctlp, grpc_error* error) {
-  batch_control* bctl = (batch_control*)bctlp;
+  batch_control* bctl = static_cast<batch_control*>(bctlp);
   grpc_call* call = bctl->call;
   if (error != GRPC_ERROR_NONE) {
-    if (call->receiving_stream != nullptr) {
-      grpc_byte_stream_destroy(call->receiving_stream);
-      call->receiving_stream = nullptr;
-    }
+    call->receiving_stream.reset();
     add_batch_error(bctl, GRPC_ERROR_REF(error), true);
     cancel_with_error(call, STATUS_FROM_SURFACE, GRPC_ERROR_REF(error));
   }
@@ -1418,7 +1389,7 @@
 // before processing the received message.
 static void receiving_stream_ready_in_call_combiner(void* bctlp,
                                                     grpc_error* error) {
-  batch_control* bctl = (batch_control*)bctlp;
+  batch_control* bctl = static_cast<batch_control*>(bctlp);
   grpc_call* call = bctl->call;
   GRPC_CALL_COMBINER_STOP(&call->call_combiner, "recv_message_ready");
   receiving_stream_ready(bctlp, error);
@@ -1494,7 +1465,7 @@
 static void add_batch_error(batch_control* bctl, grpc_error* error,
                             bool has_cancelled) {
   if (error == GRPC_ERROR_NONE) return;
-  int idx = (int)gpr_atm_full_fetch_add(&bctl->num_errors, 1);
+  int idx = static_cast<int>(gpr_atm_full_fetch_add(&bctl->num_errors, 1));
   if (idx == 0 && !has_cancelled) {
     cancel_with_error(bctl->call, STATUS_FROM_CORE, GRPC_ERROR_REF(error));
   }
@@ -1502,7 +1473,7 @@
 }
 
 static void receiving_initial_metadata_ready(void* bctlp, grpc_error* error) {
-  batch_control* bctl = (batch_control*)bctlp;
+  batch_control* bctl = static_cast<batch_control*>(bctlp);
   grpc_call* call = bctl->call;
 
   GRPC_CALL_COMBINER_STOP(&call->call_combiner, "recv_initial_metadata_ready");
@@ -1554,7 +1525,7 @@
 }
 
 static void finish_batch(void* bctlp, grpc_error* error) {
-  batch_control* bctl = (batch_control*)bctlp;
+  batch_control* bctl = static_cast<batch_control*>(bctlp);
   grpc_call* call = bctl->call;
   GRPC_CALL_COMBINER_STOP(&call->call_combiner, "on_complete");
   add_batch_error(bctl, GRPC_ERROR_REF(error), false);
@@ -1583,9 +1554,10 @@
   if (nops == 0) {
     if (!is_notify_tag_closure) {
       GPR_ASSERT(grpc_cq_begin_op(call->cq, notify_tag));
-      grpc_cq_end_op(
-          call->cq, notify_tag, GRPC_ERROR_NONE, free_no_op_completion, nullptr,
-          (grpc_cq_completion*)gpr_malloc(sizeof(grpc_cq_completion)));
+      grpc_cq_end_op(call->cq, notify_tag, GRPC_ERROR_NONE,
+                     free_no_op_completion, nullptr,
+                     static_cast<grpc_cq_completion*>(
+                         gpr_malloc(sizeof(grpc_cq_completion))));
     } else {
       GRPC_CLOSURE_SCHED((grpc_closure*)notify_tag, GRPC_ERROR_NONE);
     }
@@ -1599,7 +1571,7 @@
   }
   bctl->completion_data.notify_tag.tag = notify_tag;
   bctl->completion_data.notify_tag.is_closure =
-      (uint8_t)(is_notify_tag_closure != 0);
+      static_cast<uint8_t>(is_notify_tag_closure != 0);
 
   stream_op = &bctl->op;
   stream_op_payload = &call->stream_op_payload;
@@ -1659,9 +1631,10 @@
         stream_op->send_initial_metadata = true;
         call->sent_initial_metadata = true;
         if (!prepare_application_metadata(
-                call, (int)op->data.send_initial_metadata.count,
+                call, static_cast<int>(op->data.send_initial_metadata.count),
                 op->data.send_initial_metadata.metadata, 0, call->is_client,
-                &call->compression_md, (int)additional_metadata_count)) {
+                &call->compression_md,
+                static_cast<int>(additional_metadata_count))) {
           error = GRPC_CALL_ERROR_INVALID_METADATA;
           goto done_with_error;
         }
@@ -1692,21 +1665,20 @@
           error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
           goto done_with_error;
         }
-        stream_op->send_message = true;
-        call->sending_message = true;
-        grpc_slice_buffer_stream_init(
-            &call->sending_stream,
-            &op->data.send_message.send_message->data.raw.slice_buffer,
-            op->flags);
+        uint32_t flags = op->flags;
         /* If the outgoing buffer is already compressed, mark it as so in the
            flags. These will be picked up by the compression filter and further
            (wasteful) attempts at compression skipped. */
         if (op->data.send_message.send_message->data.raw.compression >
             GRPC_COMPRESS_NONE) {
-          call->sending_stream.base.flags |= GRPC_WRITE_INTERNAL_COMPRESS;
+          flags |= GRPC_WRITE_INTERNAL_COMPRESS;
         }
-        stream_op_payload->send_message.send_message =
-            &call->sending_stream.base;
+        stream_op->send_message = true;
+        call->sending_message = true;
+        call->sending_stream.Init(
+            &op->data.send_message.send_message->data.raw.slice_buffer, flags);
+        stream_op_payload->send_message.send_message.reset(
+            call->sending_stream.get());
         break;
       }
       case GRPC_OP_SEND_CLOSE_FROM_CLIENT: {
@@ -1778,7 +1750,8 @@
         }
         if (!prepare_application_metadata(
                 call,
-                (int)op->data.send_status_from_server.trailing_metadata_count,
+                static_cast<int>(
+                    op->data.send_status_from_server.trailing_metadata_count),
                 op->data.send_status_from_server.trailing_metadata, 1, 1,
                 nullptr, 0)) {
           for (int n = 0; n < call->send_extra_metadata_count; n++) {
@@ -1924,7 +1897,7 @@
   }
   if (stream_op->send_message) {
     call->sending_message = false;
-    grpc_byte_stream_destroy(&call->sending_stream.base);
+    call->sending_stream->Orphan();
   }
   if (stream_op->send_trailing_metadata) {
     call->sent_final_op = false;
diff --git a/src/core/lib/surface/call.h b/src/core/lib/surface/call.h
index 189329c..793cce4 100644
--- a/src/core/lib/surface/call.h
+++ b/src/core/lib/surface/call.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SURFACE_CALL_H
 #define GRPC_CORE_LIB_SURFACE_CALL_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/channel/context.h"
 #include "src/core/lib/surface/api_trace.h"
diff --git a/src/core/lib/surface/call_details.cc b/src/core/lib/surface/call_details.cc
index cd0b145..7f20b1d 100644
--- a/src/core/lib/surface/call_details.cc
+++ b/src/core/lib/surface/call_details.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 
diff --git a/src/core/lib/surface/call_log_batch.cc b/src/core/lib/surface/call_log_batch.cc
index d56ea2a..f0c82c0 100644
--- a/src/core/lib/surface/call_log_batch.cc
+++ b/src/core/lib/surface/call_log_batch.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/surface/call.h"
 
 #include <inttypes.h>
diff --git a/src/core/lib/surface/call_test_only.h b/src/core/lib/surface/call_test_only.h
index 9eb32f0..dbd1a86 100644
--- a/src/core/lib/surface/call_test_only.h
+++ b/src/core/lib/surface/call_test_only.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SURFACE_CALL_TEST_ONLY_H
 #define GRPC_CORE_LIB_SURFACE_CALL_TEST_ONLY_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 
 /** Return the message compression algorithm from \a call.
diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc
index 679666b..cecc15b 100644
--- a/src/core/lib/surface/channel.cc
+++ b/src/core/lib/surface/channel.cc
@@ -16,9 +16,12 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/surface/channel.h"
 
 #include <inttypes.h>
+#include <limits.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -28,8 +31,12 @@
 #include <grpc/support/string_util.h>
 
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/channel_trace.h"
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/manual_constructor.h"
+#include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/surface/api_trace.h"
@@ -60,6 +67,8 @@
   gpr_mu registered_call_mu;
   registered_call* registered_calls;
 
+  grpc_core::RefCountedPtr<grpc_core::ChannelTrace> tracer;
+
   char* target;
 };
 
@@ -85,18 +94,20 @@
   }
   grpc_error* error = grpc_channel_stack_builder_finish(
       builder, sizeof(grpc_channel), 1, destroy_channel, nullptr,
-      (void**)&channel);
+      reinterpret_cast<void**>(&channel));
   if (error != GRPC_ERROR_NONE) {
     gpr_log(GPR_ERROR, "channel stack builder failed: %s",
             grpc_error_string(error));
     GRPC_ERROR_UNREF(error);
     gpr_free(target);
-    goto done;
+    grpc_channel_args_destroy(args);
+    return channel;
   }
 
   memset(channel, 0, sizeof(*channel));
   channel->target = target;
   channel->is_client = grpc_channel_stack_type_is_client(channel_stack_type);
+  size_t channel_tracer_max_nodes = 0;  // default to off
   gpr_mu_init(&channel->registered_call_mu);
   channel->registered_calls = nullptr;
 
@@ -157,16 +168,35 @@
                strcmp(args->args[i].key,
                       GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET)) {
       channel->compression_options.enabled_algorithms_bitset =
-          (uint32_t)args->args[i].value.integer |
+          static_cast<uint32_t>(args->args[i].value.integer) |
           0x1; /* always support no compression */
+    } else if (0 == strcmp(args->args[i].key,
+                           GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE)) {
+      GPR_ASSERT(channel_tracer_max_nodes == 0);
+      // max_nodes defaults to 0 (which is off), clamped between 0 and INT_MAX
+      const grpc_integer_options options = {0, 0, INT_MAX};
+      channel_tracer_max_nodes =
+          (size_t)grpc_channel_arg_get_integer(&args->args[i], options);
     }
   }
 
-done:
   grpc_channel_args_destroy(args);
+  channel->tracer = grpc_core::MakeRefCounted<grpc_core::ChannelTrace>(
+      channel_tracer_max_nodes);
+  channel->tracer->AddTraceEvent(
+      grpc_core::ChannelTrace::Severity::Info,
+      grpc_slice_from_static_string("Channel created"));
   return channel;
 }
 
+char* grpc_channel_get_trace(grpc_channel* channel) {
+  return channel->tracer->RenderTrace();
+}
+
+intptr_t grpc_channel_get_uuid(grpc_channel* channel) {
+  return channel->tracer->GetUuid();
+}
+
 grpc_channel* grpc_channel_create(const char* target,
                                   const grpc_channel_args* input_args,
                                   grpc_channel_stack_type channel_stack_type,
@@ -190,26 +220,29 @@
          (which is common) - which tends to help most allocators reuse memory
       2. a small amount of allowed growth over the estimate without hitting
          the arena size doubling case, reducing overall memory usage */
-  return ((size_t)gpr_atm_no_barrier_load(&channel->call_size_estimate) +
+  return (static_cast<size_t>(
+              gpr_atm_no_barrier_load(&channel->call_size_estimate)) +
           2 * ROUND_UP_SIZE) &
-         ~(size_t)(ROUND_UP_SIZE - 1);
+         ~static_cast<size_t>(ROUND_UP_SIZE - 1);
 }
 
 void grpc_channel_update_call_size_estimate(grpc_channel* channel,
                                             size_t size) {
-  size_t cur = (size_t)gpr_atm_no_barrier_load(&channel->call_size_estimate);
+  size_t cur = static_cast<size_t>(
+      gpr_atm_no_barrier_load(&channel->call_size_estimate));
   if (cur < size) {
     /* size grew: update estimate */
-    gpr_atm_no_barrier_cas(&channel->call_size_estimate, (gpr_atm)cur,
-                           (gpr_atm)size);
+    gpr_atm_no_barrier_cas(&channel->call_size_estimate,
+                           static_cast<gpr_atm>(cur),
+                           static_cast<gpr_atm>(size));
     /* if we lose: never mind, something else will likely update soon enough */
   } else if (cur == size) {
     /* no change: holding pattern */
   } else if (cur > 0) {
     /* size shrank: decrease estimate */
     gpr_atm_no_barrier_cas(
-        &channel->call_size_estimate, (gpr_atm)cur,
-        (gpr_atm)(GPR_MIN(cur - 1, (255 * cur + size) / 256)));
+        &channel->call_size_estimate, static_cast<gpr_atm>(cur),
+        static_cast<gpr_atm>(GPR_MIN(cur - 1, (255 * cur + size) / 256)));
     /* if we lose: never mind, something else will likely update soon enough */
   }
 }
@@ -297,7 +330,8 @@
 
 void* grpc_channel_register_call(grpc_channel* channel, const char* method,
                                  const char* host, void* reserved) {
-  registered_call* rc = (registered_call*)gpr_malloc(sizeof(registered_call));
+  registered_call* rc =
+      static_cast<registered_call*>(gpr_malloc(sizeof(registered_call)));
   GRPC_API_TRACE(
       "grpc_channel_register_call(channel=%p, method=%s, host=%s, reserved=%p)",
       4, (channel, method, host, reserved));
@@ -324,7 +358,7 @@
     grpc_channel* channel, grpc_call* parent_call, uint32_t propagation_mask,
     grpc_completion_queue* completion_queue, void* registered_call_handle,
     gpr_timespec deadline, void* reserved) {
-  registered_call* rc = (registered_call*)registered_call_handle;
+  registered_call* rc = static_cast<registered_call*>(registered_call_handle);
   GRPC_API_TRACE(
       "grpc_channel_create_registered_call("
       "channel=%p, parent_call=%p, propagation_mask=%x, completion_queue=%p, "
@@ -362,7 +396,7 @@
 }
 
 static void destroy_channel(void* arg, grpc_error* error) {
-  grpc_channel* channel = (grpc_channel*)arg;
+  grpc_channel* channel = static_cast<grpc_channel*>(arg);
   grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel));
   while (channel->registered_calls) {
     registered_call* rc = channel->registered_calls;
@@ -371,6 +405,7 @@
     GRPC_MDELEM_UNREF(rc->authority);
     gpr_free(rc);
   }
+  channel->tracer.reset();
   GRPC_MDELEM_UNREF(channel->default_authority);
   gpr_mu_destroy(&channel->registered_call_mu);
   gpr_free(channel->target);
diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h
index 26d8fce..2883139 100644
--- a/src/core/lib/surface/channel.h
+++ b/src/core/lib/surface/channel.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SURFACE_CHANNEL_H
 #define GRPC_CORE_LIB_SURFACE_CHANNEL_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/channel/channel_stack_builder.h"
 #include "src/core/lib/surface/channel_stack_type.h"
diff --git a/src/core/lib/surface/channel_init.cc b/src/core/lib/surface/channel_init.cc
index 95cbbbd..62eb1c3 100644
--- a/src/core/lib/surface/channel_init.cc
+++ b/src/core/lib/surface/channel_init.cc
@@ -16,10 +16,11 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/surface/channel_init.h"
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/useful.h>
 
 typedef struct stage_slot {
   grpc_channel_init_stage fn;
@@ -53,9 +54,9 @@
   GPR_ASSERT(!g_finalized);
   if (g_slots[type].cap_slots == g_slots[type].num_slots) {
     g_slots[type].cap_slots = GPR_MAX(8, 3 * g_slots[type].cap_slots / 2);
-    g_slots[type].slots = (stage_slot*)gpr_realloc(
-        g_slots[type].slots,
-        g_slots[type].cap_slots * sizeof(*g_slots[type].slots));
+    g_slots[type].slots = static_cast<stage_slot*>(
+        gpr_realloc(g_slots[type].slots,
+                    g_slots[type].cap_slots * sizeof(*g_slots[type].slots)));
   }
   stage_slot* s = &g_slots[type].slots[g_slots[type].num_slots++];
   s->insertion_order = g_slots[type].num_slots;
@@ -65,8 +66,8 @@
 }
 
 static int compare_slots(const void* a, const void* b) {
-  const stage_slot* sa = (const stage_slot*)a;
-  const stage_slot* sb = (const stage_slot*)b;
+  const stage_slot* sa = static_cast<const stage_slot*>(a);
+  const stage_slot* sb = static_cast<const stage_slot*>(b);
 
   int c = GPR_ICMP(sa->priority, sb->priority);
   if (c != 0) return c;
@@ -85,7 +86,8 @@
 void grpc_channel_init_shutdown(void) {
   for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) {
     gpr_free(g_slots[i].slots);
-    g_slots[i].slots = (stage_slot*)(void*)(uintptr_t)0xdeadbeef;
+    g_slots[i].slots =
+        static_cast<stage_slot*>((void*)static_cast<uintptr_t>(0xdeadbeef));
   }
 }
 
diff --git a/src/core/lib/surface/channel_init.h b/src/core/lib/surface/channel_init.h
index d702f0f..f018524 100644
--- a/src/core/lib/surface/channel_init.h
+++ b/src/core/lib/surface/channel_init.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SURFACE_CHANNEL_INIT_H
 #define GRPC_CORE_LIB_SURFACE_CHANNEL_INIT_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/channel/channel_stack_builder.h"
 #include "src/core/lib/surface/channel_stack_type.h"
 #include "src/core/lib/transport/transport.h"
diff --git a/src/core/lib/surface/channel_ping.cc b/src/core/lib/surface/channel_ping.cc
index a030d8d..bae9459 100644
--- a/src/core/lib/surface/channel_ping.cc
+++ b/src/core/lib/surface/channel_ping.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/surface/channel.h"
 
 #include <string.h>
@@ -38,7 +40,7 @@
 }
 
 static void ping_done(void* arg, grpc_error* error) {
-  ping_result* pr = (ping_result*)arg;
+  ping_result* pr = static_cast<ping_result*>(arg);
   grpc_cq_end_op(pr->cq, pr->tag, GRPC_ERROR_REF(error), ping_destroy, pr,
                  &pr->completion_storage);
 }
@@ -48,7 +50,7 @@
   GRPC_API_TRACE("grpc_channel_ping(channel=%p, cq=%p, tag=%p, reserved=%p)", 4,
                  (channel, cq, tag, reserved));
   grpc_transport_op* op = grpc_make_transport_op(nullptr);
-  ping_result* pr = (ping_result*)gpr_malloc(sizeof(*pr));
+  ping_result* pr = static_cast<ping_result*>(gpr_malloc(sizeof(*pr)));
   grpc_channel_element* top_elem =
       grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
   grpc_core::ExecCtx exec_ctx;
diff --git a/src/core/lib/surface/channel_stack_type.cc b/src/core/lib/surface/channel_stack_type.cc
index 366c452..fcf96dd 100644
--- a/src/core/lib/surface/channel_stack_type.cc
+++ b/src/core/lib/surface/channel_stack_type.cc
@@ -16,10 +16,11 @@
  *
  */
 
-#include "src/core/lib/surface/channel_stack_type.h"
-#include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
 
+#include <grpc/support/log.h>
+#include "src/core/lib/surface/channel_stack_type.h"
+
 bool grpc_channel_stack_type_is_client(grpc_channel_stack_type type) {
   switch (type) {
     case GRPC_CLIENT_CHANNEL:
diff --git a/src/core/lib/surface/channel_stack_type.h b/src/core/lib/surface/channel_stack_type.h
index 52f85a6..8a3c08e 100644
--- a/src/core/lib/surface/channel_stack_type.h
+++ b/src/core/lib/surface/channel_stack_type.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SURFACE_CHANNEL_STACK_TYPE_H
 #define GRPC_CORE_LIB_SURFACE_CHANNEL_STACK_TYPE_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stdbool.h>
 
 typedef enum {
diff --git a/src/core/lib/surface/completion_queue.cc b/src/core/lib/surface/completion_queue.cc
index 8362522..d036391 100644
--- a/src/core/lib/surface/completion_queue.cc
+++ b/src/core/lib/surface/completion_queue.cc
@@ -28,11 +28,11 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
-#include <grpc/support/tls.h>
 
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/gpr/spinlock.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/tls.h"
 #include "src/core/lib/iomgr/pollset.h"
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/profiling/timers.h"
@@ -88,24 +88,24 @@
 }
 
 static void non_polling_poller_init(grpc_pollset* pollset, gpr_mu** mu) {
-  non_polling_poller* npp = (non_polling_poller*)pollset;
+  non_polling_poller* npp = reinterpret_cast<non_polling_poller*>(pollset);
   gpr_mu_init(&npp->mu);
   *mu = &npp->mu;
 }
 
 static void non_polling_poller_destroy(grpc_pollset* pollset) {
-  non_polling_poller* npp = (non_polling_poller*)pollset;
+  non_polling_poller* npp = reinterpret_cast<non_polling_poller*>(pollset);
   gpr_mu_destroy(&npp->mu);
 }
 
 static grpc_error* non_polling_poller_work(grpc_pollset* pollset,
                                            grpc_pollset_worker** worker,
                                            grpc_millis deadline) {
-  non_polling_poller* npp = (non_polling_poller*)pollset;
+  non_polling_poller* npp = reinterpret_cast<non_polling_poller*>(pollset);
   if (npp->shutdown) return GRPC_ERROR_NONE;
   non_polling_worker w;
   gpr_cv_init(&w.cv);
-  if (worker != nullptr) *worker = (grpc_pollset_worker*)&w;
+  if (worker != nullptr) *worker = reinterpret_cast<grpc_pollset_worker*>(&w);
   if (npp->root == nullptr) {
     npp->root = w.next = w.prev = &w;
   } else {
@@ -138,11 +138,12 @@
 
 static grpc_error* non_polling_poller_kick(
     grpc_pollset* pollset, grpc_pollset_worker* specific_worker) {
-  non_polling_poller* p = (non_polling_poller*)pollset;
+  non_polling_poller* p = reinterpret_cast<non_polling_poller*>(pollset);
   if (specific_worker == nullptr)
-    specific_worker = (grpc_pollset_worker*)p->root;
+    specific_worker = reinterpret_cast<grpc_pollset_worker*>(p->root);
   if (specific_worker != nullptr) {
-    non_polling_worker* w = (non_polling_worker*)specific_worker;
+    non_polling_worker* w =
+        reinterpret_cast<non_polling_worker*>(specific_worker);
     if (!w->kicked) {
       w->kicked = true;
       gpr_cv_signal(&w->cv);
@@ -153,7 +154,7 @@
 
 static void non_polling_poller_shutdown(grpc_pollset* pollset,
                                         grpc_closure* closure) {
-  non_polling_poller* p = (non_polling_poller*)pollset;
+  non_polling_poller* p = reinterpret_cast<non_polling_poller*>(pollset);
   GPR_ASSERT(closure != nullptr);
   p->shutdown = closure;
   if (p->root == nullptr) {
@@ -354,10 +355,10 @@
       (grpc_completion_queue*)gpr_tls_get(&g_cached_cq) == cq) {
     *tag = storage->tag;
     grpc_core::ExecCtx exec_ctx;
-    *ok = (storage->next & (uintptr_t)(1)) == 1;
+    *ok = (storage->next & static_cast<uintptr_t>(1)) == 1;
     storage->done(storage->done_arg, storage);
     ret = 1;
-    cq_next_data* cqd = (cq_next_data*)DATA_FROM_CQ(cq);
+    cq_next_data* cqd = static_cast<cq_next_data*> DATA_FROM_CQ(cq);
     if (gpr_atm_full_fetch_add(&cqd->pending_events, -1) == 1) {
       GRPC_CQ_INTERNAL_REF(cq, "shutting_down");
       gpr_mu_lock(cq->mu);
@@ -383,7 +384,7 @@
 }
 
 static bool cq_event_queue_push(grpc_cq_event_queue* q, grpc_cq_completion* c) {
-  gpr_mpscq_push(&q->queue, (gpr_mpscq_node*)c);
+  gpr_mpscq_push(&q->queue, reinterpret_cast<gpr_mpscq_node*>(c));
   return gpr_atm_no_barrier_fetch_add(&q->num_queue_items, 1) == 0;
 }
 
@@ -395,7 +396,8 @@
     GRPC_STATS_INC_CQ_EV_QUEUE_TRYLOCK_SUCCESSES();
 
     bool is_empty = false;
-    c = (grpc_cq_completion*)gpr_mpscq_pop_and_check_end(&q->queue, &is_empty);
+    c = reinterpret_cast<grpc_cq_completion*>(
+        gpr_mpscq_pop_and_check_end(&q->queue, &is_empty));
     gpr_spinlock_unlock(&q->queue_lock);
 
     if (c == nullptr && !is_empty) {
@@ -415,7 +417,7 @@
 /* Note: The counter is not incremented/decremented atomically with push/pop.
  * The count is only eventually consistent */
 static long cq_event_queue_num_items(grpc_cq_event_queue* q) {
-  return (long)gpr_atm_no_barrier_load(&q->num_queue_items);
+  return static_cast<long>(gpr_atm_no_barrier_load(&q->num_queue_items));
 }
 
 grpc_completion_queue* grpc_completion_queue_create_internal(
@@ -437,9 +439,9 @@
   grpc_core::ExecCtx exec_ctx;
   GRPC_STATS_INC_CQS_CREATED();
 
-  cq = (grpc_completion_queue*)gpr_zalloc(sizeof(grpc_completion_queue) +
-                                          vtable->data_size +
-                                          poller_vtable->size());
+  cq = static_cast<grpc_completion_queue*>(
+      gpr_zalloc(sizeof(grpc_completion_queue) + vtable->data_size +
+                 poller_vtable->size()));
 
   cq->vtable = vtable;
   cq->poller_vtable = poller_vtable;
@@ -456,7 +458,7 @@
 }
 
 static void cq_init_next(void* ptr) {
-  cq_next_data* cqd = (cq_next_data*)ptr;
+  cq_next_data* cqd = static_cast<cq_next_data*>(ptr);
   /* Initial count is dropped by grpc_completion_queue_shutdown */
   gpr_atm_no_barrier_store(&cqd->pending_events, 1);
   cqd->shutdown_called = false;
@@ -465,13 +467,13 @@
 }
 
 static void cq_destroy_next(void* ptr) {
-  cq_next_data* cqd = (cq_next_data*)ptr;
+  cq_next_data* cqd = static_cast<cq_next_data*>(ptr);
   GPR_ASSERT(cq_event_queue_num_items(&cqd->queue) == 0);
   cq_event_queue_destroy(&cqd->queue);
 }
 
 static void cq_init_pluck(void* ptr) {
-  cq_pluck_data* cqd = (cq_pluck_data*)ptr;
+  cq_pluck_data* cqd = static_cast<cq_pluck_data*>(ptr);
   /* Initial count is dropped by grpc_completion_queue_shutdown */
   gpr_atm_no_barrier_store(&cqd->pending_events, 1);
   cqd->completed_tail = &cqd->completed_head;
@@ -483,7 +485,7 @@
 }
 
 static void cq_destroy_pluck(void* ptr) {
-  cq_pluck_data* cqd = (cq_pluck_data*)ptr;
+  cq_pluck_data* cqd = static_cast<cq_pluck_data*>(ptr);
   GPR_ASSERT(cqd->completed_head.next == (uintptr_t)&cqd->completed_head);
 }
 
@@ -515,7 +517,7 @@
 }
 
 static void on_pollset_shutdown_done(void* arg, grpc_error* error) {
-  grpc_completion_queue* cq = (grpc_completion_queue*)arg;
+  grpc_completion_queue* cq = static_cast<grpc_completion_queue*>(arg);
   GRPC_CQ_INTERNAL_UNREF(cq, "pollset_destroy");
 }
 
@@ -548,7 +550,7 @@
     gpr_mu_lock(cq->mu);
   }
 
-  for (int i = 0; i < (int)cq->outstanding_tag_count; i++) {
+  for (int i = 0; i < static_cast<int>(cq->outstanding_tag_count); i++) {
     if (cq->outstanding_tags[i] == tag) {
       cq->outstanding_tag_count--;
       GPR_SWAP(void*, cq->outstanding_tags[i],
@@ -587,12 +589,12 @@
 }
 
 static bool cq_begin_op_for_next(grpc_completion_queue* cq, void* tag) {
-  cq_next_data* cqd = (cq_next_data*)DATA_FROM_CQ(cq);
+  cq_next_data* cqd = static_cast<cq_next_data*> DATA_FROM_CQ(cq);
   return atm_inc_if_nonzero(&cqd->pending_events);
 }
 
 static bool cq_begin_op_for_pluck(grpc_completion_queue* cq, void* tag) {
-  cq_pluck_data* cqd = (cq_pluck_data*)DATA_FROM_CQ(cq);
+  cq_pluck_data* cqd = static_cast<cq_pluck_data*> DATA_FROM_CQ(cq);
   return atm_inc_if_nonzero(&cqd->pending_events);
 }
 
@@ -601,9 +603,9 @@
   gpr_mu_lock(cq->mu);
   if (cq->outstanding_tag_count == cq->outstanding_tag_capacity) {
     cq->outstanding_tag_capacity = GPR_MAX(4, 2 * cq->outstanding_tag_capacity);
-    cq->outstanding_tags = (void**)gpr_realloc(
+    cq->outstanding_tags = static_cast<void**>(gpr_realloc(
         cq->outstanding_tags,
-        sizeof(*cq->outstanding_tags) * cq->outstanding_tag_capacity);
+        sizeof(*cq->outstanding_tags) * cq->outstanding_tag_capacity));
   }
   cq->outstanding_tags[cq->outstanding_tag_count++] = tag;
   gpr_mu_unlock(cq->mu);
@@ -632,13 +634,13 @@
       gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg);
     }
   }
-  cq_next_data* cqd = (cq_next_data*)DATA_FROM_CQ(cq);
+  cq_next_data* cqd = static_cast<cq_next_data*> DATA_FROM_CQ(cq);
   int is_success = (error == GRPC_ERROR_NONE);
 
   storage->tag = tag;
   storage->done = done;
   storage->done_arg = done_arg;
-  storage->next = (uintptr_t)(is_success);
+  storage->next = static_cast<uintptr_t>(is_success);
 
   cq_check_tag(cq, tag, true); /* Used in debug builds only */
 
@@ -701,7 +703,7 @@
                                 void* done_arg, grpc_cq_completion* storage) {
   GPR_TIMER_SCOPE("cq_end_op_for_pluck", 0);
 
-  cq_pluck_data* cqd = (cq_pluck_data*)DATA_FROM_CQ(cq);
+  cq_pluck_data* cqd = static_cast<cq_pluck_data*> DATA_FROM_CQ(cq);
   int is_success = (error == GRPC_ERROR_NONE);
 
   if (grpc_api_trace.enabled() ||
@@ -719,7 +721,8 @@
   storage->tag = tag;
   storage->done = done;
   storage->done_arg = done_arg;
-  storage->next = ((uintptr_t)&cqd->completed_head) | ((uintptr_t)(is_success));
+  storage->next =
+      ((uintptr_t)&cqd->completed_head) | (static_cast<uintptr_t>(is_success));
 
   gpr_mu_lock(cq->mu);
   cq_check_tag(cq, tag, false); /* Used in debug builds only */
@@ -727,7 +730,7 @@
   /* Add to the list of completions */
   gpr_atm_no_barrier_fetch_add(&cqd->things_queued_ever, 1);
   cqd->completed_tail->next =
-      ((uintptr_t)storage) | (1u & (uintptr_t)cqd->completed_tail->next);
+      ((uintptr_t)storage) | (1u & cqd->completed_tail->next);
   cqd->completed_tail = storage;
 
   if (gpr_atm_full_fetch_add(&cqd->pending_events, -1) == 1) {
@@ -778,9 +781,10 @@
   ExecCtxNext(void* arg) : ExecCtx(0), check_ready_to_finish_arg_(arg) {}
 
   bool CheckReadyToFinish() override {
-    cq_is_finished_arg* a = (cq_is_finished_arg*)check_ready_to_finish_arg_;
+    cq_is_finished_arg* a =
+        static_cast<cq_is_finished_arg*>(check_ready_to_finish_arg_);
     grpc_completion_queue* cq = a->cq;
-    cq_next_data* cqd = (cq_next_data*)DATA_FROM_CQ(cq);
+    cq_next_data* cqd = static_cast<cq_next_data*> DATA_FROM_CQ(cq);
     GPR_ASSERT(a->stolen_completion == nullptr);
 
     gpr_atm current_last_seen_things_queued_ever =
@@ -836,7 +840,7 @@
   GPR_TIMER_SCOPE("grpc_completion_queue_next", 0);
 
   grpc_event ret;
-  cq_next_data* cqd = (cq_next_data*)DATA_FROM_CQ(cq);
+  cq_next_data* cqd = static_cast<cq_next_data*> DATA_FROM_CQ(cq);
 
   GRPC_API_TRACE(
       "grpc_completion_queue_next("
@@ -961,7 +965,7 @@
    - grpc_completion_queue_shutdown() MUST have been called before calling
    this function */
 static void cq_finish_shutdown_next(grpc_completion_queue* cq) {
-  cq_next_data* cqd = (cq_next_data*)DATA_FROM_CQ(cq);
+  cq_next_data* cqd = static_cast<cq_next_data*> DATA_FROM_CQ(cq);
 
   GPR_ASSERT(cqd->shutdown_called);
   GPR_ASSERT(gpr_atm_no_barrier_load(&cqd->pending_events) == 0);
@@ -970,7 +974,7 @@
 }
 
 static void cq_shutdown_next(grpc_completion_queue* cq) {
-  cq_next_data* cqd = (cq_next_data*)DATA_FROM_CQ(cq);
+  cq_next_data* cqd = static_cast<cq_next_data*> DATA_FROM_CQ(cq);
 
   /* Need an extra ref for cq here because:
    * We call cq_finish_shutdown_next() below, that would call pollset shutdown.
@@ -1003,7 +1007,7 @@
 
 static int add_plucker(grpc_completion_queue* cq, void* tag,
                        grpc_pollset_worker** worker) {
-  cq_pluck_data* cqd = (cq_pluck_data*)DATA_FROM_CQ(cq);
+  cq_pluck_data* cqd = static_cast<cq_pluck_data*> DATA_FROM_CQ(cq);
   if (cqd->num_pluckers == GRPC_MAX_COMPLETION_QUEUE_PLUCKERS) {
     return 0;
   }
@@ -1015,7 +1019,7 @@
 
 static void del_plucker(grpc_completion_queue* cq, void* tag,
                         grpc_pollset_worker** worker) {
-  cq_pluck_data* cqd = (cq_pluck_data*)DATA_FROM_CQ(cq);
+  cq_pluck_data* cqd = static_cast<cq_pluck_data*> DATA_FROM_CQ(cq);
   for (int i = 0; i < cqd->num_pluckers; i++) {
     if (cqd->pluckers[i].tag == tag && cqd->pluckers[i].worker == worker) {
       cqd->num_pluckers--;
@@ -1031,9 +1035,10 @@
   ExecCtxPluck(void* arg) : ExecCtx(0), check_ready_to_finish_arg_(arg) {}
 
   bool CheckReadyToFinish() override {
-    cq_is_finished_arg* a = (cq_is_finished_arg*)check_ready_to_finish_arg_;
+    cq_is_finished_arg* a =
+        static_cast<cq_is_finished_arg*>(check_ready_to_finish_arg_);
     grpc_completion_queue* cq = a->cq;
-    cq_pluck_data* cqd = (cq_pluck_data*)DATA_FROM_CQ(cq);
+    cq_pluck_data* cqd = static_cast<cq_pluck_data*> DATA_FROM_CQ(cq);
 
     GPR_ASSERT(a->stolen_completion == nullptr);
     gpr_atm current_last_seen_things_queued_ever =
@@ -1045,10 +1050,12 @@
           gpr_atm_no_barrier_load(&cqd->things_queued_ever);
       grpc_cq_completion* c;
       grpc_cq_completion* prev = &cqd->completed_head;
-      while ((c = (grpc_cq_completion*)(prev->next & ~(uintptr_t)1)) !=
+      while ((c = (grpc_cq_completion*)(prev->next &
+                                        ~static_cast<uintptr_t>(1))) !=
              &cqd->completed_head) {
         if (c->tag == a->tag) {
-          prev->next = (prev->next & (uintptr_t)1) | (c->next & ~(uintptr_t)1);
+          prev->next = (prev->next & static_cast<uintptr_t>(1)) |
+                       (c->next & ~static_cast<uintptr_t>(1));
           if (c == cqd->completed_tail) {
             cqd->completed_tail = prev;
           }
@@ -1075,7 +1082,7 @@
   grpc_cq_completion* c;
   grpc_cq_completion* prev;
   grpc_pollset_worker* worker = nullptr;
-  cq_pluck_data* cqd = (cq_pluck_data*)DATA_FROM_CQ(cq);
+  cq_pluck_data* cqd = static_cast<cq_pluck_data*> DATA_FROM_CQ(cq);
 
   if (grpc_cq_pluck_trace.enabled()) {
     GRPC_API_TRACE(
@@ -1115,10 +1122,12 @@
       break;
     }
     prev = &cqd->completed_head;
-    while ((c = (grpc_cq_completion*)(prev->next & ~(uintptr_t)1)) !=
-           &cqd->completed_head) {
+    while (
+        (c = (grpc_cq_completion*)(prev->next & ~static_cast<uintptr_t>(1))) !=
+        &cqd->completed_head) {
       if (c->tag == tag) {
-        prev->next = (prev->next & (uintptr_t)1) | (c->next & ~(uintptr_t)1);
+        prev->next = (prev->next & static_cast<uintptr_t>(1)) |
+                     (c->next & ~static_cast<uintptr_t>(1));
         if (c == cqd->completed_tail) {
           cqd->completed_tail = prev;
         }
@@ -1191,7 +1200,7 @@
 }
 
 static void cq_finish_shutdown_pluck(grpc_completion_queue* cq) {
-  cq_pluck_data* cqd = (cq_pluck_data*)DATA_FROM_CQ(cq);
+  cq_pluck_data* cqd = static_cast<cq_pluck_data*> DATA_FROM_CQ(cq);
 
   GPR_ASSERT(cqd->shutdown_called);
   GPR_ASSERT(!gpr_atm_no_barrier_load(&cqd->shutdown));
@@ -1203,7 +1212,7 @@
 /* NOTE: This function is almost exactly identical to cq_shutdown_next() but
  * merging them is a bit tricky and probably not worth it */
 static void cq_shutdown_pluck(grpc_completion_queue* cq) {
-  cq_pluck_data* cqd = (cq_pluck_data*)DATA_FROM_CQ(cq);
+  cq_pluck_data* cqd = static_cast<cq_pluck_data*> DATA_FROM_CQ(cq);
 
   /* Need an extra ref for cq here because:
    * We call cq_finish_shutdown_pluck() below, that would call pollset shutdown.
diff --git a/src/core/lib/surface/completion_queue.h b/src/core/lib/surface/completion_queue.h
index aea47af..c9dc2d9 100644
--- a/src/core/lib/surface/completion_queue.h
+++ b/src/core/lib/surface/completion_queue.h
@@ -21,6 +21,8 @@
 
 /* Internal API for completion queues */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/iomgr/pollset.h"
diff --git a/src/core/lib/surface/completion_queue_factory.cc b/src/core/lib/surface/completion_queue_factory.cc
index d0bb065..51c1183 100644
--- a/src/core/lib/surface/completion_queue_factory.cc
+++ b/src/core/lib/surface/completion_queue_factory.cc
@@ -16,8 +16,10 @@
  *
  */
 
-#include "src/core/lib/surface/completion_queue_factory.h"
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/surface/completion_queue.h"
+#include "src/core/lib/surface/completion_queue_factory.h"
 
 #include <grpc/support/log.h>
 
diff --git a/src/core/lib/surface/completion_queue_factory.h b/src/core/lib/surface/completion_queue_factory.h
index 89be8f8..d2b30a9 100644
--- a/src/core/lib/surface/completion_queue_factory.h
+++ b/src/core/lib/surface/completion_queue_factory.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SURFACE_COMPLETION_QUEUE_FACTORY_H
 #define GRPC_CORE_LIB_SURFACE_COMPLETION_QUEUE_FACTORY_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 #include "src/core/lib/surface/completion_queue.h"
 
diff --git a/src/core/lib/surface/event_string.cc b/src/core/lib/surface/event_string.cc
index 7f40bb2..d639bae 100644
--- a/src/core/lib/surface/event_string.cc
+++ b/src/core/lib/surface/event_string.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/surface/event_string.h"
 
 #include <stdio.h>
diff --git a/src/core/lib/surface/event_string.h b/src/core/lib/surface/event_string.h
index cbf96da..e609570 100644
--- a/src/core/lib/surface/event_string.h
+++ b/src/core/lib/surface/event_string.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SURFACE_EVENT_STRING_H
 #define GRPC_CORE_LIB_SURFACE_EVENT_STRING_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 
 /* Returns a string describing an event. Must be later freed with gpr_free() */
diff --git a/src/core/lib/surface/init.cc b/src/core/lib/surface/init.cc
index 7f7947f..52e0ee1 100644
--- a/src/core/lib/surface/init.cc
+++ b/src/core/lib/surface/init.cc
@@ -27,12 +27,13 @@
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/channel/channel_trace_registry.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/channel/handshaker_registry.h"
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/gpr/fork.h"
-#include "src/core/lib/gpr/thd_internal.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/http/parser.h"
 #include "src/core/lib/iomgr/call_combiner.h"
 #include "src/core/lib/iomgr/combiner.h"
@@ -74,12 +75,12 @@
 
 static bool append_filter(grpc_channel_stack_builder* builder, void* arg) {
   return grpc_channel_stack_builder_append_filter(
-      builder, (const grpc_channel_filter*)arg, nullptr, nullptr);
+      builder, static_cast<const grpc_channel_filter*>(arg), nullptr, nullptr);
 }
 
 static bool prepend_filter(grpc_channel_stack_builder* builder, void* arg) {
   return grpc_channel_stack_builder_prepend_filter(
-      builder, (const grpc_channel_filter*)arg, nullptr, nullptr);
+      builder, static_cast<const grpc_channel_filter*>(arg), nullptr, nullptr);
 }
 
 static void register_builtin_channel_init() {
@@ -123,11 +124,12 @@
   gpr_mu_lock(&g_init_mu);
   if (++g_initializations == 1) {
     gpr_time_init();
-    gpr_thd_init();
+    grpc_core::Thread::Init();
     grpc_stats_init();
     grpc_slice_intern_init();
     grpc_mdctx_global_init();
     grpc_channel_init_init();
+    grpc_channel_trace_registry_init();
     grpc_security_pre_init();
     grpc_core::ExecCtx::GlobalInit();
     grpc_iomgr_init();
@@ -170,12 +172,14 @@
           }
         }
       }
+      grpc_security_shutdown();
       grpc_iomgr_shutdown();
       gpr_timers_global_destroy();
       grpc_tracer_shutdown();
       grpc_mdctx_global_shutdown();
       grpc_handshaker_factory_registry_shutdown();
       grpc_slice_intern_shutdown();
+      grpc_channel_trace_registry_shutdown();
       grpc_stats_shutdown();
     }
     grpc_core::ExecCtx::GlobalShutdown();
diff --git a/src/core/lib/surface/init.h b/src/core/lib/surface/init.h
index 9353208..d8282b4 100644
--- a/src/core/lib/surface/init.h
+++ b/src/core/lib/surface/init.h
@@ -22,6 +22,7 @@
 void grpc_register_security_filters(void);
 void grpc_security_pre_init(void);
 void grpc_security_init(void);
+void grpc_security_shutdown(void);
 int grpc_is_initialized(void);
 
 #endif /* GRPC_CORE_LIB_SURFACE_INIT_H */
diff --git a/src/core/lib/surface/init_secure.cc b/src/core/lib/surface/init_secure.cc
index 75ed9fa..3e4f1a8 100644
--- a/src/core/lib/surface/init_secure.cc
+++ b/src/core/lib/surface/init_secure.cc
@@ -27,9 +27,9 @@
 #include "src/core/lib/security/context/security_context.h"
 #include "src/core/lib/security/credentials/credentials.h"
 #include "src/core/lib/security/credentials/plugin/plugin_credentials.h"
+#include "src/core/lib/security/security_connector/security_connector.h"
 #include "src/core/lib/security/transport/auth_filters.h"
 #include "src/core/lib/security/transport/secure_endpoint.h"
-#include "src/core/lib/security/transport/security_connector.h"
 #include "src/core/lib/security/transport/security_handshaker.h"
 #include "src/core/lib/surface/channel_init.h"
 #include "src/core/tsi/transport_security_interface.h"
@@ -75,4 +75,9 @@
                                    maybe_prepend_server_auth_filter, nullptr);
 }
 
-void grpc_security_init() { grpc_security_register_handshaker_factories(); }
+void grpc_security_init() {
+  grpc_security_register_handshaker_factories();
+  grpc_core::DefaultSslRootStore::Initialize();
+}
+
+void grpc_security_shutdown() { grpc_core::DefaultSslRootStore::Destroy(); }
diff --git a/src/core/lib/surface/init_unsecure.cc b/src/core/lib/surface/init_unsecure.cc
index b852cab..1c8d07b 100644
--- a/src/core/lib/surface/init_unsecure.cc
+++ b/src/core/lib/surface/init_unsecure.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/surface/init.h"
 
 void grpc_security_pre_init(void) {}
@@ -23,3 +25,5 @@
 void grpc_register_security_filters(void) {}
 
 void grpc_security_init(void) {}
+
+void grpc_security_shutdown(void) {}
diff --git a/src/core/lib/surface/lame_client.cc b/src/core/lib/surface/lame_client.cc
index a1f1cf1..5a84428 100644
--- a/src/core/lib/surface/lame_client.cc
+++ b/src/core/lib/surface/lame_client.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 
 #include <string.h>
@@ -50,14 +52,14 @@
 };
 
 static void fill_metadata(grpc_call_element* elem, grpc_metadata_batch* mdb) {
-  CallData* calld = reinterpret_cast<CallData*>(elem->call_data);
+  CallData* calld = static_cast<CallData*>(elem->call_data);
   bool expected = false;
   if (!calld->filled_metadata.compare_exchange_strong(
           expected, true, grpc_core::memory_order_relaxed,
           grpc_core::memory_order_relaxed)) {
     return;
   }
-  ChannelData* chand = reinterpret_cast<ChannelData*>(elem->channel_data);
+  ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
   char tmp[GPR_LTOA_MIN_BUFSIZE];
   gpr_ltoa(chand->error_code, tmp);
   calld->status.md = grpc_mdelem_from_slices(
@@ -76,7 +78,7 @@
 
 static void lame_start_transport_stream_op_batch(
     grpc_call_element* elem, grpc_transport_stream_op_batch* op) {
-  CallData* calld = reinterpret_cast<CallData*>(elem->call_data);
+  CallData* calld = static_cast<CallData*>(elem->call_data);
   if (op->recv_initial_metadata) {
     fill_metadata(elem,
                   op->payload->recv_initial_metadata.recv_initial_metadata);
@@ -117,7 +119,7 @@
 
 static grpc_error* init_call_elem(grpc_call_element* elem,
                                   const grpc_call_element_args* args) {
-  CallData* calld = reinterpret_cast<CallData*>(elem->call_data);
+  CallData* calld = static_cast<CallData*>(elem->call_data);
   calld->call_combiner = args->call_combiner;
   return GRPC_ERROR_NONE;
 }
@@ -170,7 +172,7 @@
       "error_message=%s)",
       3, (target, (int)error_code, error_message));
   GPR_ASSERT(elem->filter == &grpc_lame_filter);
-  auto chand = reinterpret_cast<grpc_core::ChannelData*>(elem->channel_data);
+  auto chand = static_cast<grpc_core::ChannelData*>(elem->channel_data);
   chand->error_code = error_code;
   chand->error_message = error_message;
 
diff --git a/src/core/lib/surface/lame_client.h b/src/core/lib/surface/lame_client.h
index 3ce353f..aefa67c 100644
--- a/src/core/lib/surface/lame_client.h
+++ b/src/core/lib/surface/lame_client.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SURFACE_LAME_CLIENT_H
 #define GRPC_CORE_LIB_SURFACE_LAME_CLIENT_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/channel/channel_stack.h"
 
 extern const grpc_channel_filter grpc_lame_filter;
diff --git a/src/core/lib/surface/metadata_array.cc b/src/core/lib/surface/metadata_array.cc
index 0afb8b4..f794a2b 100644
--- a/src/core/lib/surface/metadata_array.cc
+++ b/src/core/lib/surface/metadata_array.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 
diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc
index c8c1db3..f7505c8 100644
--- a/src/core/lib/surface/server.cc
+++ b/src/core/lib/surface/server.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/surface/server.h"
 
 #include <limits.h>
@@ -25,7 +27,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
@@ -242,8 +243,8 @@
     count++;
   }
   cb->num_channels = count;
-  cb->channels =
-      (grpc_channel**)gpr_malloc(sizeof(*cb->channels) * cb->num_channels);
+  cb->channels = static_cast<grpc_channel**>(
+      gpr_malloc(sizeof(*cb->channels) * cb->num_channels));
   count = 0;
   for (c = s->root_channel_data.next; c != &s->root_channel_data; c = c->next) {
     cb->channels[count++] = c->channel;
@@ -257,7 +258,8 @@
 };
 
 static void shutdown_cleanup(void* arg, grpc_error* error) {
-  struct shutdown_cleanup_args* a = (struct shutdown_cleanup_args*)arg;
+  struct shutdown_cleanup_args* a =
+      static_cast<struct shutdown_cleanup_args*>(arg);
   grpc_slice_unref_internal(a->slice);
   gpr_free(a);
 }
@@ -265,7 +267,7 @@
 static void send_shutdown(grpc_channel* channel, bool send_goaway,
                           grpc_error* send_disconnect) {
   struct shutdown_cleanup_args* sc =
-      (struct shutdown_cleanup_args*)gpr_malloc(sizeof(*sc));
+      static_cast<struct shutdown_cleanup_args*>(gpr_malloc(sizeof(*sc)));
   GRPC_CLOSURE_INIT(&sc->closure, shutdown_cleanup, sc,
                     grpc_schedule_on_exec_ctx);
   grpc_transport_op* op = grpc_make_transport_op(&sc->closure);
@@ -305,8 +307,8 @@
 static void request_matcher_init(request_matcher* rm, grpc_server* server) {
   memset(rm, 0, sizeof(*rm));
   rm->server = server;
-  rm->requests_per_cq = (gpr_locked_mpscq*)gpr_malloc(
-      sizeof(*rm->requests_per_cq) * server->cq_count);
+  rm->requests_per_cq = static_cast<gpr_locked_mpscq*>(
+      gpr_malloc(sizeof(*rm->requests_per_cq) * server->cq_count));
   for (size_t i = 0; i < server->cq_count; i++) {
     gpr_locked_mpscq_init(&rm->requests_per_cq[i]);
   }
@@ -321,7 +323,8 @@
 }
 
 static void kill_zombie(void* elem, grpc_error* error) {
-  grpc_call_unref(grpc_call_from_top_element((grpc_call_element*)elem));
+  grpc_call_unref(
+      grpc_call_from_top_element(static_cast<grpc_call_element*>(elem)));
 }
 
 static void request_matcher_zombify_all_pending_calls(request_matcher* rm) {
@@ -342,8 +345,8 @@
                                           grpc_error* error) {
   requested_call* rc;
   for (size_t i = 0; i < server->cq_count; i++) {
-    while ((rc = (requested_call*)gpr_locked_mpscq_pop(
-                &rm->requests_per_cq[i])) != nullptr) {
+    while ((rc = reinterpret_cast<requested_call*>(
+                gpr_locked_mpscq_pop(&rm->requests_per_cq[i]))) != nullptr) {
       fail_call(server, i, rc, GRPC_ERROR_REF(error));
     }
   }
@@ -403,7 +406,7 @@
 }
 
 static void finish_destroy_channel(void* cd, grpc_error* error) {
-  channel_data* chand = (channel_data*)cd;
+  channel_data* chand = static_cast<channel_data*>(cd);
   grpc_server* server = chand->server;
   GRPC_CHANNEL_INTERNAL_UNREF(chand->channel, "server");
   server_unref(server);
@@ -470,9 +473,9 @@
 }
 
 static void publish_new_rpc(void* arg, grpc_error* error) {
-  grpc_call_element* call_elem = (grpc_call_element*)arg;
-  call_data* calld = (call_data*)call_elem->call_data;
-  channel_data* chand = (channel_data*)call_elem->channel_data;
+  grpc_call_element* call_elem = static_cast<grpc_call_element*>(arg);
+  call_data* calld = static_cast<call_data*>(call_elem->call_data);
+  channel_data* chand = static_cast<channel_data*>(call_elem->channel_data);
   request_matcher* rm = calld->matcher;
   grpc_server* server = rm->server;
 
@@ -488,8 +491,8 @@
 
   for (size_t i = 0; i < server->cq_count; i++) {
     size_t cq_idx = (chand->cq_idx + i) % server->cq_count;
-    requested_call* rc =
-        (requested_call*)gpr_locked_mpscq_try_pop(&rm->requests_per_cq[cq_idx]);
+    requested_call* rc = reinterpret_cast<requested_call*>(
+        gpr_locked_mpscq_try_pop(&rm->requests_per_cq[cq_idx]));
     if (rc == nullptr) {
       continue;
     } else {
@@ -510,8 +513,8 @@
   // added to the pending list.
   for (size_t i = 0; i < server->cq_count; i++) {
     size_t cq_idx = (chand->cq_idx + i) % server->cq_count;
-    requested_call* rc =
-        (requested_call*)gpr_locked_mpscq_pop(&rm->requests_per_cq[cq_idx]);
+    requested_call* rc = reinterpret_cast<requested_call*>(
+        gpr_locked_mpscq_pop(&rm->requests_per_cq[cq_idx]));
     if (rc == nullptr) {
       continue;
     } else {
@@ -537,7 +540,7 @@
 static void finish_start_new_rpc(
     grpc_server* server, grpc_call_element* elem, request_matcher* rm,
     grpc_server_register_method_payload_handling payload_handling) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
 
   if (gpr_atm_acq_load(&server->shutdown_flag)) {
     gpr_atm_no_barrier_store(&calld->state, ZOMBIED);
@@ -567,8 +570,8 @@
 }
 
 static void start_new_rpc(grpc_call_element* elem) {
-  channel_data* chand = (channel_data*)elem->channel_data;
-  call_data* calld = (call_data*)elem->call_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   grpc_server* server = chand->server;
   uint32_t i;
   uint32_t hash;
@@ -627,7 +630,7 @@
 }
 
 static void done_shutdown_event(void* server, grpc_cq_completion* completion) {
-  server_unref((grpc_server*)server);
+  server_unref(static_cast<grpc_server*>(server));
 }
 
 static int num_channels(grpc_server* server) {
@@ -690,8 +693,8 @@
 }
 
 static void server_on_recv_initial_metadata(void* ptr, grpc_error* error) {
-  grpc_call_element* elem = (grpc_call_element*)ptr;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(ptr);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   grpc_millis op_deadline;
 
   if (error == GRPC_ERROR_NONE) {
@@ -729,7 +732,7 @@
 
 static void server_mutate_op(grpc_call_element* elem,
                              grpc_transport_stream_op_batch* op) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
 
   if (op->recv_initial_metadata) {
     GPR_ASSERT(op->payload->recv_initial_metadata.recv_flags == nullptr);
@@ -751,8 +754,8 @@
 }
 
 static void got_initial_metadata(void* ptr, grpc_error* error) {
-  grpc_call_element* elem = (grpc_call_element*)ptr;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(ptr);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   if (error == GRPC_ERROR_NONE) {
     start_new_rpc(elem);
   } else {
@@ -769,7 +772,7 @@
 
 static void accept_stream(void* cd, grpc_transport* transport,
                           const void* transport_server_data) {
-  channel_data* chand = (channel_data*)cd;
+  channel_data* chand = static_cast<channel_data*>(cd);
   /* create a call */
   grpc_call_create_args args;
   memset(&args, 0, sizeof(args));
@@ -785,7 +788,7 @@
     GRPC_ERROR_UNREF(error);
     return;
   }
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   grpc_op op;
   memset(&op, 0, sizeof(op));
   op.op = GRPC_OP_RECV_INITIAL_METADATA;
@@ -797,7 +800,7 @@
 }
 
 static void channel_connectivity_changed(void* cd, grpc_error* error) {
-  channel_data* chand = (channel_data*)cd;
+  channel_data* chand = static_cast<channel_data*>(cd);
   grpc_server* server = chand->server;
   if (chand->connectivity_state != GRPC_CHANNEL_SHUTDOWN) {
     grpc_transport_op* op = grpc_make_transport_op(nullptr);
@@ -816,8 +819,8 @@
 
 static grpc_error* init_call_elem(grpc_call_element* elem,
                                   const grpc_call_element_args* args) {
-  call_data* calld = (call_data*)elem->call_data;
-  channel_data* chand = (channel_data*)elem->channel_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   memset(calld, 0, sizeof(call_data));
   calld->deadline = GRPC_MILLIS_INF_FUTURE;
   calld->call = grpc_call_from_top_element(elem);
@@ -833,8 +836,8 @@
 static void destroy_call_elem(grpc_call_element* elem,
                               const grpc_call_final_info* final_info,
                               grpc_closure* ignored) {
-  channel_data* chand = (channel_data*)elem->channel_data;
-  call_data* calld = (call_data*)elem->call_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
 
   GPR_ASSERT(calld->state != PENDING);
 
@@ -852,7 +855,7 @@
 
 static grpc_error* init_channel_elem(grpc_channel_element* elem,
                                      grpc_channel_element_args* args) {
-  channel_data* chand = (channel_data*)elem->channel_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   GPR_ASSERT(args->is_first);
   GPR_ASSERT(!args->is_last);
   chand->server = nullptr;
@@ -868,7 +871,7 @@
 
 static void destroy_channel_elem(grpc_channel_element* elem) {
   size_t i;
-  channel_data* chand = (channel_data*)elem->channel_data;
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   if (chand->registered_methods) {
     for (i = 0; i < chand->registered_method_slots; i++) {
       grpc_slice_unref_internal(chand->registered_methods[i].method);
@@ -914,8 +917,8 @@
 
   GRPC_CQ_INTERNAL_REF(cq, "server");
   n = server->cq_count++;
-  server->cqs = (grpc_completion_queue**)gpr_realloc(
-      server->cqs, server->cq_count * sizeof(grpc_completion_queue*));
+  server->cqs = static_cast<grpc_completion_queue**>(gpr_realloc(
+      server->cqs, server->cq_count * sizeof(grpc_completion_queue*)));
   server->cqs[n] = cq;
 }
 
@@ -940,7 +943,8 @@
 grpc_server* grpc_server_create(const grpc_channel_args* args, void* reserved) {
   GRPC_API_TRACE("grpc_server_create(%p, %p)", 2, (args, reserved));
 
-  grpc_server* server = (grpc_server*)gpr_zalloc(sizeof(grpc_server));
+  grpc_server* server =
+      static_cast<grpc_server*>(gpr_zalloc(sizeof(grpc_server)));
 
   gpr_mu_init(&server->mu_global);
   gpr_mu_init(&server->mu_call);
@@ -989,7 +993,7 @@
             flags);
     return nullptr;
   }
-  m = (registered_method*)gpr_zalloc(sizeof(registered_method));
+  m = static_cast<registered_method*>(gpr_zalloc(sizeof(registered_method)));
   m->method = gpr_strdup(method);
   m->host = gpr_strdup(host);
   m->next = server->registered_methods;
@@ -1000,7 +1004,7 @@
 }
 
 static void start_listeners(void* s, grpc_error* error) {
-  grpc_server* server = (grpc_server*)s;
+  grpc_server* server = static_cast<grpc_server*>(s);
   for (listener* l = server->listeners; l; l = l->next) {
     l->start(server, l->arg, server->pollsets, server->pollset_count);
   }
@@ -1021,8 +1025,8 @@
 
   server->started = true;
   server->pollset_count = 0;
-  server->pollsets =
-      (grpc_pollset**)gpr_malloc(sizeof(grpc_pollset*) * server->cq_count);
+  server->pollsets = static_cast<grpc_pollset**>(
+      gpr_malloc(sizeof(grpc_pollset*) * server->cq_count));
   for (i = 0; i < server->cq_count; i++) {
     if (grpc_cq_can_listen(server->cqs[i])) {
       server->pollsets[server->pollset_count++] =
@@ -1064,9 +1068,9 @@
   grpc_transport_op* op = nullptr;
 
   channel = grpc_channel_create(nullptr, args, GRPC_SERVER_CHANNEL, transport);
-  chand = (channel_data*)grpc_channel_stack_element(
-              grpc_channel_get_channel_stack(channel), 0)
-              ->channel_data;
+  chand = static_cast<channel_data*>(
+      grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0)
+          ->channel_data);
   chand->server = s;
   server_ref(s);
   chand->channel = channel;
@@ -1077,7 +1081,7 @@
   }
   if (cq_idx == s->cq_count) {
     /* completion queue not found: pick a random one to publish new calls to */
-    cq_idx = (size_t)rand() % s->cq_count;
+    cq_idx = static_cast<size_t>(rand()) % s->cq_count;
   }
   chand->cq_idx = cq_idx;
 
@@ -1090,7 +1094,8 @@
   if (num_registered_methods > 0) {
     slots = 2 * num_registered_methods;
     alloc = sizeof(channel_registered_method) * slots;
-    chand->registered_methods = (channel_registered_method*)gpr_zalloc(alloc);
+    chand->registered_methods =
+        static_cast<channel_registered_method*>(gpr_zalloc(alloc));
     for (rm = s->registered_methods; rm; rm = rm->next) {
       grpc_slice host;
       bool has_host;
@@ -1119,7 +1124,7 @@
       crm->method = method;
     }
     GPR_ASSERT(slots <= UINT32_MAX);
-    chand->registered_method_slots = (uint32_t)slots;
+    chand->registered_method_slots = static_cast<uint32_t>(slots);
     chand->registered_method_max_probes = max_probes;
   }
 
@@ -1149,7 +1154,7 @@
 }
 
 static void listener_destroy_done(void* s, grpc_error* error) {
-  grpc_server* server = (grpc_server*)s;
+  grpc_server* server = static_cast<grpc_server*>(s);
   gpr_mu_lock(&server->mu_global);
   server->listeners_destroyed++;
   maybe_finish_shutdown(server);
@@ -1177,13 +1182,14 @@
   GPR_ASSERT(grpc_cq_begin_op(cq, tag));
   if (server->shutdown_published) {
     grpc_cq_end_op(cq, tag, GRPC_ERROR_NONE, done_published_shutdown, nullptr,
-                   (grpc_cq_completion*)gpr_malloc(sizeof(grpc_cq_completion)));
+                   static_cast<grpc_cq_completion*>(
+                       gpr_malloc(sizeof(grpc_cq_completion))));
     gpr_mu_unlock(&server->mu_global);
     return;
   }
-  server->shutdown_tags = (shutdown_tag*)gpr_realloc(
-      server->shutdown_tags,
-      sizeof(shutdown_tag) * (server->num_shutdown_tags + 1));
+  server->shutdown_tags = static_cast<shutdown_tag*>(
+      gpr_realloc(server->shutdown_tags,
+                  sizeof(shutdown_tag) * (server->num_shutdown_tags + 1)));
   sdt = &server->shutdown_tags[server->num_shutdown_tags++];
   sdt->tag = tag;
   sdt->cq = cq;
@@ -1260,7 +1266,7 @@
                                             size_t pollset_count),
                               void (*destroy)(grpc_server* server, void* arg,
                                               grpc_closure* on_done)) {
-  listener* l = (listener*)gpr_malloc(sizeof(listener));
+  listener* l = static_cast<listener*>(gpr_malloc(sizeof(listener)));
   l->arg = arg;
   l->start = start;
   l->destroy = destroy;
@@ -1290,7 +1296,8 @@
        matching calls */
     gpr_mu_lock(&server->mu_call);
     while ((calld = rm->pending_head) != nullptr) {
-      rc = (requested_call*)gpr_locked_mpscq_pop(&rm->requests_per_cq[cq_idx]);
+      rc = reinterpret_cast<requested_call*>(
+          gpr_locked_mpscq_pop(&rm->requests_per_cq[cq_idx]));
       if (rc == nullptr) break;
       rm->pending_head = calld->pending_next;
       gpr_mu_unlock(&server->mu_call);
@@ -1318,7 +1325,7 @@
     grpc_completion_queue* cq_for_notification, void* tag) {
   grpc_call_error error;
   grpc_core::ExecCtx exec_ctx;
-  requested_call* rc = (requested_call*)gpr_malloc(sizeof(*rc));
+  requested_call* rc = static_cast<requested_call*>(gpr_malloc(sizeof(*rc)));
   GRPC_STATS_INC_SERVER_REQUESTED_CALLS();
   GRPC_API_TRACE(
       "grpc_server_request_call("
@@ -1365,8 +1372,8 @@
     grpc_completion_queue* cq_for_notification, void* tag) {
   grpc_call_error error;
   grpc_core::ExecCtx exec_ctx;
-  requested_call* rc = (requested_call*)gpr_malloc(sizeof(*rc));
-  registered_method* rm = (registered_method*)rmp;
+  requested_call* rc = static_cast<requested_call*>(gpr_malloc(sizeof(*rc)));
+  registered_method* rm = static_cast<registered_method*>(rmp);
   GRPC_STATS_INC_SERVER_REQUESTED_CALLS();
   GRPC_API_TRACE(
       "grpc_server_request_registered_call("
diff --git a/src/core/lib/surface/server.h b/src/core/lib/surface/server.h
index 63b6dff..c617cc2 100644
--- a/src/core/lib/surface/server.h
+++ b/src/core/lib/surface/server.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SURFACE_SERVER_H
 #define GRPC_CORE_LIB_SURFACE_SERVER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/debug/trace.h"
diff --git a/src/core/lib/surface/validate_metadata.cc b/src/core/lib/surface/validate_metadata.cc
index fc94ea7..2dd18f3 100644
--- a/src/core/lib/surface/validate_metadata.cc
+++ b/src/core/lib/surface/validate_metadata.cc
@@ -16,12 +16,13 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <stdlib.h>
 #include <string.h>
 
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/port_platform.h>
 
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/slice/slice_internal.h"
diff --git a/src/core/lib/surface/validate_metadata.h b/src/core/lib/surface/validate_metadata.h
index ff074b0..e87fb7b 100644
--- a/src/core/lib/surface/validate_metadata.h
+++ b/src/core/lib/surface/validate_metadata.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_SURFACE_VALIDATE_METADATA_H
 #define GRPC_CORE_LIB_SURFACE_VALIDATE_METADATA_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice.h>
 #include "src/core/lib/iomgr/error.h"
 
diff --git a/src/core/lib/surface/version.cc b/src/core/lib/surface/version.cc
index 153b6e0..be196a7 100644
--- a/src/core/lib/surface/version.cc
+++ b/src/core/lib/surface/version.cc
@@ -19,8 +19,10 @@
 /* This file is autogenerated from:
    templates/src/core/surface/version.c.template */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 
 const char* grpc_version_string(void) { return "6.0.0-dev"; }
 
-const char* grpc_g_stands_for(void) { return "glossy"; }
+const char* grpc_g_stands_for(void) { return "gorgeous"; }
diff --git a/src/core/lib/transport/bdp_estimator.cc b/src/core/lib/transport/bdp_estimator.cc
index 5fcc62e..8130535 100644
--- a/src/core/lib/transport/bdp_estimator.cc
+++ b/src/core/lib/transport/bdp_estimator.cc
@@ -16,12 +16,14 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/transport/bdp_estimator.h"
 
 #include <inttypes.h>
 #include <stdlib.h>
 
-#include <grpc/support/useful.h>
+#include "src/core/lib/gpr/useful.h"
 
 grpc_core::TraceFlag grpc_bdp_estimator_trace(false, "bdp_estimator");
 
@@ -40,8 +42,9 @@
 grpc_millis BdpEstimator::CompletePing() {
   gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
   gpr_timespec dt_ts = gpr_time_sub(now, ping_start_time_);
-  double dt = (double)dt_ts.tv_sec + 1e-9 * (double)dt_ts.tv_nsec;
-  double bw = dt > 0 ? ((double)accumulator_ / dt) : 0;
+  double dt = static_cast<double>(dt_ts.tv_sec) +
+              1e-9 * static_cast<double>(dt_ts.tv_nsec);
+  double bw = dt > 0 ? (static_cast<double>(accumulator_) / dt) : 0;
   int start_inter_ping_delay = inter_ping_delay_;
   if (grpc_bdp_estimator_trace.enabled()) {
     gpr_log(GPR_DEBUG,
@@ -64,8 +67,8 @@
     stable_estimate_count_++;
     if (stable_estimate_count_ >= 2) {
       inter_ping_delay_ +=
-          100 +
-          (int)(rand() * 100.0 / RAND_MAX);  // if the ping estimate is steady,
+          100 + static_cast<int>(rand() * 100.0 /
+                                 RAND_MAX);  // if the ping estimate is steady,
                                              // slowly ramp down the probe time
     }
   }
diff --git a/src/core/lib/transport/byte_stream.cc b/src/core/lib/transport/byte_stream.cc
index 8dcb1e0..cb15a71 100644
--- a/src/core/lib/transport/byte_stream.cc
+++ b/src/core/lib/transport/byte_stream.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/transport/byte_stream.h"
 
 #include <stdlib.h>
@@ -23,151 +25,136 @@
 
 #include <grpc/support/log.h>
 
+#include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/slice/slice_internal.h"
 
-bool grpc_byte_stream_next(grpc_byte_stream* byte_stream, size_t max_size_hint,
-                           grpc_closure* on_complete) {
-  return byte_stream->vtable->next(byte_stream, max_size_hint, on_complete);
+namespace grpc_core {
+
+//
+// SliceBufferByteStream
+//
+
+SliceBufferByteStream::SliceBufferByteStream(grpc_slice_buffer* slice_buffer,
+                                             uint32_t flags)
+    : ByteStream(static_cast<uint32_t>(slice_buffer->length), flags) {
+  GPR_ASSERT(slice_buffer->length <= UINT32_MAX);
+  grpc_slice_buffer_init(&backing_buffer_);
+  grpc_slice_buffer_swap(slice_buffer, &backing_buffer_);
 }
 
-grpc_error* grpc_byte_stream_pull(grpc_byte_stream* byte_stream,
-                                  grpc_slice* slice) {
-  return byte_stream->vtable->pull(byte_stream, slice);
+SliceBufferByteStream::~SliceBufferByteStream() {}
+
+void SliceBufferByteStream::Orphan() {
+  grpc_slice_buffer_destroy(&backing_buffer_);
+  GRPC_ERROR_UNREF(shutdown_error_);
+  // Note: We do not actually delete the object here, since
+  // SliceBufferByteStream is usually allocated as part of a larger
+  // object and has an OrphanablePtr of itself passed down through the
+  // filter stack.
 }
 
-void grpc_byte_stream_shutdown(grpc_byte_stream* byte_stream,
-                               grpc_error* error) {
-  byte_stream->vtable->shutdown(byte_stream, error);
-}
-
-void grpc_byte_stream_destroy(grpc_byte_stream* byte_stream) {
-  byte_stream->vtable->destroy(byte_stream);
-}
-
-// grpc_slice_buffer_stream
-
-static bool slice_buffer_stream_next(grpc_byte_stream* byte_stream,
-                                     size_t max_size_hint,
-                                     grpc_closure* on_complete) {
-  grpc_slice_buffer_stream* stream = (grpc_slice_buffer_stream*)byte_stream;
-  GPR_ASSERT(stream->cursor < stream->backing_buffer->count);
+bool SliceBufferByteStream::Next(size_t max_size_hint,
+                                 grpc_closure* on_complete) {
+  GPR_ASSERT(cursor_ < backing_buffer_.count);
   return true;
 }
 
-static grpc_error* slice_buffer_stream_pull(grpc_byte_stream* byte_stream,
-                                            grpc_slice* slice) {
-  grpc_slice_buffer_stream* stream = (grpc_slice_buffer_stream*)byte_stream;
-  if (stream->shutdown_error != GRPC_ERROR_NONE) {
-    return GRPC_ERROR_REF(stream->shutdown_error);
+grpc_error* SliceBufferByteStream::Pull(grpc_slice* slice) {
+  if (shutdown_error_ != GRPC_ERROR_NONE) {
+    return GRPC_ERROR_REF(shutdown_error_);
   }
-  GPR_ASSERT(stream->cursor < stream->backing_buffer->count);
-  *slice =
-      grpc_slice_ref_internal(stream->backing_buffer->slices[stream->cursor]);
-  stream->cursor++;
+  GPR_ASSERT(cursor_ < backing_buffer_.count);
+  *slice = grpc_slice_ref_internal(backing_buffer_.slices[cursor_]);
+  ++cursor_;
   return GRPC_ERROR_NONE;
 }
 
-static void slice_buffer_stream_shutdown(grpc_byte_stream* byte_stream,
-                                         grpc_error* error) {
-  grpc_slice_buffer_stream* stream = (grpc_slice_buffer_stream*)byte_stream;
-  GRPC_ERROR_UNREF(stream->shutdown_error);
-  stream->shutdown_error = error;
+void SliceBufferByteStream::Shutdown(grpc_error* error) {
+  GRPC_ERROR_UNREF(shutdown_error_);
+  shutdown_error_ = error;
 }
 
-static void slice_buffer_stream_destroy(grpc_byte_stream* byte_stream) {
-  grpc_slice_buffer_stream* stream = (grpc_slice_buffer_stream*)byte_stream;
-  grpc_slice_buffer_reset_and_unref_internal(stream->backing_buffer);
-  GRPC_ERROR_UNREF(stream->shutdown_error);
+//
+// ByteStreamCache
+//
+
+ByteStreamCache::ByteStreamCache(OrphanablePtr<ByteStream> underlying_stream)
+    : underlying_stream_(std::move(underlying_stream)),
+      length_(underlying_stream_->length()),
+      flags_(underlying_stream_->flags()) {
+  grpc_slice_buffer_init(&cache_buffer_);
 }
 
-static const grpc_byte_stream_vtable slice_buffer_stream_vtable = {
-    slice_buffer_stream_next, slice_buffer_stream_pull,
-    slice_buffer_stream_shutdown, slice_buffer_stream_destroy};
+ByteStreamCache::~ByteStreamCache() { Destroy(); }
 
-void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream* stream,
-                                   grpc_slice_buffer* slice_buffer,
-                                   uint32_t flags) {
-  GPR_ASSERT(slice_buffer->length <= UINT32_MAX);
-  stream->base.length = (uint32_t)slice_buffer->length;
-  stream->base.flags = flags;
-  stream->base.vtable = &slice_buffer_stream_vtable;
-  stream->backing_buffer = slice_buffer;
-  stream->cursor = 0;
-  stream->shutdown_error = GRPC_ERROR_NONE;
-}
-
-// grpc_caching_byte_stream
-
-void grpc_byte_stream_cache_init(grpc_byte_stream_cache* cache,
-                                 grpc_byte_stream* underlying_stream) {
-  cache->underlying_stream = underlying_stream;
-  grpc_slice_buffer_init(&cache->cache_buffer);
-}
-
-void grpc_byte_stream_cache_destroy(grpc_byte_stream_cache* cache) {
-  grpc_byte_stream_destroy(cache->underlying_stream);
-  grpc_slice_buffer_destroy_internal(&cache->cache_buffer);
-}
-
-static bool caching_byte_stream_next(grpc_byte_stream* byte_stream,
-                                     size_t max_size_hint,
-                                     grpc_closure* on_complete) {
-  grpc_caching_byte_stream* stream = (grpc_caching_byte_stream*)byte_stream;
-  if (stream->shutdown_error != GRPC_ERROR_NONE) return true;
-  if (stream->cursor < stream->cache->cache_buffer.count) return true;
-  return grpc_byte_stream_next(stream->cache->underlying_stream, max_size_hint,
-                               on_complete);
-}
-
-static grpc_error* caching_byte_stream_pull(grpc_byte_stream* byte_stream,
-                                            grpc_slice* slice) {
-  grpc_caching_byte_stream* stream = (grpc_caching_byte_stream*)byte_stream;
-  if (stream->shutdown_error != GRPC_ERROR_NONE) {
-    return GRPC_ERROR_REF(stream->shutdown_error);
+void ByteStreamCache::Destroy() {
+  underlying_stream_.reset();
+  if (cache_buffer_.length > 0) {
+    grpc_slice_buffer_destroy_internal(&cache_buffer_);
   }
-  if (stream->cursor < stream->cache->cache_buffer.count) {
-    *slice = grpc_slice_ref_internal(
-        stream->cache->cache_buffer.slices[stream->cursor]);
-    ++stream->cursor;
+}
+
+//
+// ByteStreamCache::CachingByteStream
+//
+
+ByteStreamCache::CachingByteStream::CachingByteStream(ByteStreamCache* cache)
+    : ByteStream(cache->length_, cache->flags_), cache_(cache) {}
+
+ByteStreamCache::CachingByteStream::~CachingByteStream() {}
+
+void ByteStreamCache::CachingByteStream::Orphan() {
+  GRPC_ERROR_UNREF(shutdown_error_);
+  // Note: We do not actually delete the object here, since
+  // CachingByteStream is usually allocated as part of a larger
+  // object and has an OrphanablePtr of itself passed down through the
+  // filter stack.
+}
+
+bool ByteStreamCache::CachingByteStream::Next(size_t max_size_hint,
+                                              grpc_closure* on_complete) {
+  if (shutdown_error_ != GRPC_ERROR_NONE) return true;
+  if (cursor_ < cache_->cache_buffer_.count) return true;
+  GPR_ASSERT(cache_->underlying_stream_ != nullptr);
+  return cache_->underlying_stream_->Next(max_size_hint, on_complete);
+}
+
+grpc_error* ByteStreamCache::CachingByteStream::Pull(grpc_slice* slice) {
+  if (shutdown_error_ != GRPC_ERROR_NONE) {
+    return GRPC_ERROR_REF(shutdown_error_);
+  }
+  if (cursor_ < cache_->cache_buffer_.count) {
+    *slice = grpc_slice_ref_internal(cache_->cache_buffer_.slices[cursor_]);
+    ++cursor_;
+    offset_ += GRPC_SLICE_LENGTH(*slice);
     return GRPC_ERROR_NONE;
   }
-  grpc_error* error =
-      grpc_byte_stream_pull(stream->cache->underlying_stream, slice);
+  GPR_ASSERT(cache_->underlying_stream_ != nullptr);
+  grpc_error* error = cache_->underlying_stream_->Pull(slice);
   if (error == GRPC_ERROR_NONE) {
-    ++stream->cursor;
-    grpc_slice_buffer_add(&stream->cache->cache_buffer,
+    grpc_slice_buffer_add(&cache_->cache_buffer_,
                           grpc_slice_ref_internal(*slice));
+    ++cursor_;
+    offset_ += GRPC_SLICE_LENGTH(*slice);
+    // Orphan the underlying stream if it's been drained.
+    if (offset_ == cache_->underlying_stream_->length()) {
+      cache_->underlying_stream_.reset();
+    }
   }
   return error;
 }
 
-static void caching_byte_stream_shutdown(grpc_byte_stream* byte_stream,
-                                         grpc_error* error) {
-  grpc_caching_byte_stream* stream = (grpc_caching_byte_stream*)byte_stream;
-  GRPC_ERROR_UNREF(stream->shutdown_error);
-  stream->shutdown_error = GRPC_ERROR_REF(error);
-  grpc_byte_stream_shutdown(stream->cache->underlying_stream, error);
+void ByteStreamCache::CachingByteStream::Shutdown(grpc_error* error) {
+  GRPC_ERROR_UNREF(shutdown_error_);
+  shutdown_error_ = GRPC_ERROR_REF(error);
+  if (cache_->underlying_stream_ != nullptr) {
+    cache_->underlying_stream_->Shutdown(error);
+  }
 }
 
-static void caching_byte_stream_destroy(grpc_byte_stream* byte_stream) {
-  grpc_caching_byte_stream* stream = (grpc_caching_byte_stream*)byte_stream;
-  GRPC_ERROR_UNREF(stream->shutdown_error);
+void ByteStreamCache::CachingByteStream::Reset() {
+  cursor_ = 0;
+  offset_ = 0;
 }
 
-static const grpc_byte_stream_vtable caching_byte_stream_vtable = {
-    caching_byte_stream_next, caching_byte_stream_pull,
-    caching_byte_stream_shutdown, caching_byte_stream_destroy};
-
-void grpc_caching_byte_stream_init(grpc_caching_byte_stream* stream,
-                                   grpc_byte_stream_cache* cache) {
-  memset(stream, 0, sizeof(*stream));
-  stream->base.length = cache->underlying_stream->length;
-  stream->base.flags = cache->underlying_stream->flags;
-  stream->base.vtable = &caching_byte_stream_vtable;
-  stream->cache = cache;
-  stream->shutdown_error = GRPC_ERROR_NONE;
-}
-
-void grpc_caching_byte_stream_reset(grpc_caching_byte_stream* stream) {
-  stream->cursor = 0;
-}
+}  // namespace grpc_core
diff --git a/src/core/lib/transport/byte_stream.h b/src/core/lib/transport/byte_stream.h
index 52c7a07..eff8325 100644
--- a/src/core/lib/transport/byte_stream.h
+++ b/src/core/lib/transport/byte_stream.h
@@ -19,8 +19,12 @@
 #ifndef GRPC_CORE_LIB_TRANSPORT_BYTE_STREAM_H
 #define GRPC_CORE_LIB_TRANSPORT_BYTE_STREAM_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice_buffer.h>
-#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/gprpp/abstract.h"
+#include "src/core/lib/gprpp/orphanable.h"
+#include "src/core/lib/iomgr/closure.h"
 
 /** Internal bit flag for grpc_begin_message's \a flags signaling the use of
  * compression for the message */
@@ -28,71 +32,82 @@
 /** Mask of all valid internal flags. */
 #define GRPC_WRITE_INTERNAL_USED_MASK (GRPC_WRITE_INTERNAL_COMPRESS)
 
-typedef struct grpc_byte_stream grpc_byte_stream;
+namespace grpc_core {
 
-typedef struct {
-  bool (*next)(grpc_byte_stream* byte_stream, size_t max_size_hint,
-               grpc_closure* on_complete);
-  grpc_error* (*pull)(grpc_byte_stream* byte_stream, grpc_slice* slice);
-  void (*shutdown)(grpc_byte_stream* byte_stream, grpc_error* error);
-  void (*destroy)(grpc_byte_stream* byte_stream);
-} grpc_byte_stream_vtable;
+class ByteStream : public Orphanable {
+ public:
+  virtual ~ByteStream() {}
 
-struct grpc_byte_stream {
-  uint32_t length;
-  uint32_t flags;
-  const grpc_byte_stream_vtable* vtable;
+  // Returns true if the bytes are available immediately (in which case
+  // on_complete will not be called), or false if the bytes will be available
+  // asynchronously (in which case on_complete will be called when they
+  // are available).
+  //
+  // max_size_hint can be set as a hint as to the maximum number
+  // of bytes that would be acceptable to read.
+  virtual bool Next(size_t max_size_hint,
+                    grpc_closure* on_complete) GRPC_ABSTRACT;
+
+  // Returns the next slice in the byte stream when it is available, as
+  // indicated by Next().
+  //
+  // Once a slice is returned into *slice, it is owned by the caller.
+  virtual grpc_error* Pull(grpc_slice* slice) GRPC_ABSTRACT;
+
+  // Shuts down the byte stream.
+  //
+  // If there is a pending call to on_complete from Next(), it will be
+  // invoked with the error passed to Shutdown().
+  //
+  // The next call to Pull() (if any) will return the error passed to
+  // Shutdown().
+  virtual void Shutdown(grpc_error* error) GRPC_ABSTRACT;
+
+  uint32_t length() const { return length_; }
+  uint32_t flags() const { return flags_; }
+
+  void set_flags(uint32_t flags) { flags_ = flags; }
+
+  GRPC_ABSTRACT_BASE_CLASS
+
+ protected:
+  ByteStream(uint32_t length, uint32_t flags)
+      : length_(length), flags_(flags) {}
+
+ private:
+  const uint32_t length_;
+  uint32_t flags_;
 };
 
-// Returns true if the bytes are available immediately (in which case
-// on_complete will not be called), false if the bytes will be available
-// asynchronously.
 //
-// max_size_hint can be set as a hint as to the maximum number
-// of bytes that would be acceptable to read.
-bool grpc_byte_stream_next(grpc_byte_stream* byte_stream, size_t max_size_hint,
-                           grpc_closure* on_complete);
-
-// Returns the next slice in the byte stream when it is ready (indicated by
-// either grpc_byte_stream_next returning true or on_complete passed to
-// grpc_byte_stream_next is called).
+// SliceBufferByteStream
 //
-// Once a slice is returned into *slice, it is owned by the caller.
-grpc_error* grpc_byte_stream_pull(grpc_byte_stream* byte_stream,
-                                  grpc_slice* slice);
-
-// Shuts down the byte stream.
+// A ByteStream that wraps a slice buffer.
 //
-// If there is a pending call to on_complete from grpc_byte_stream_next(),
-// it will be invoked with the error passed to grpc_byte_stream_shutdown().
+
+class SliceBufferByteStream : public ByteStream {
+ public:
+  // Removes all slices in slice_buffer, leaving it empty.
+  SliceBufferByteStream(grpc_slice_buffer* slice_buffer, uint32_t flags);
+
+  ~SliceBufferByteStream();
+
+  void Orphan() override;
+
+  bool Next(size_t max_size_hint, grpc_closure* on_complete) override;
+  grpc_error* Pull(grpc_slice* slice) override;
+  void Shutdown(grpc_error* error) override;
+
+ private:
+  grpc_slice_buffer backing_buffer_;
+  size_t cursor_ = 0;
+  grpc_error* shutdown_error_ = GRPC_ERROR_NONE;
+};
+
 //
-// The next call to grpc_byte_stream_pull() (if any) will return the error
-// passed to grpc_byte_stream_shutdown().
-void grpc_byte_stream_shutdown(grpc_byte_stream* byte_stream,
-                               grpc_error* error);
-
-void grpc_byte_stream_destroy(grpc_byte_stream* byte_stream);
-
-// grpc_slice_buffer_stream
+// CachingByteStream
 //
-// A grpc_byte_stream that wraps a slice buffer.  The stream takes
-// ownership of the slices in the buffer, and on destruction will
-// reset the contents of the buffer.
-
-typedef struct grpc_slice_buffer_stream {
-  grpc_byte_stream base;
-  grpc_slice_buffer* backing_buffer;
-  size_t cursor;
-  grpc_error* shutdown_error;
-} grpc_slice_buffer_stream;
-
-void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream* stream,
-                                   grpc_slice_buffer* slice_buffer,
-                                   uint32_t flags);
-
-// grpc_caching_byte_stream
-//
-// A grpc_byte_stream that that wraps an underlying byte stream but caches
+// A ByteStream that that wraps an underlying byte stream but caches
 // the resulting slices in a slice buffer.  If an initial attempt fails
 // without fully draining the underlying stream, a new caching stream
 // can be created from the same underlying cache, in which case it will
@@ -100,32 +115,50 @@
 // underlying stream.
 //
 // NOTE: No synchronization is done, so it is not safe to have multiple
-// grpc_caching_byte_streams simultaneously drawing from the same underlying
-// grpc_byte_stream_cache at the same time.
+// CachingByteStreams simultaneously drawing from the same underlying
+// ByteStreamCache at the same time.
+//
 
-typedef struct {
-  grpc_byte_stream* underlying_stream;
-  grpc_slice_buffer cache_buffer;
-} grpc_byte_stream_cache;
+class ByteStreamCache {
+ public:
+  class CachingByteStream : public ByteStream {
+   public:
+    explicit CachingByteStream(ByteStreamCache* cache);
 
-// Takes ownership of underlying_stream.
-void grpc_byte_stream_cache_init(grpc_byte_stream_cache* cache,
-                                 grpc_byte_stream* underlying_stream);
+    ~CachingByteStream();
 
-// Must not be called while still in use by a grpc_caching_byte_stream.
-void grpc_byte_stream_cache_destroy(grpc_byte_stream_cache* cache);
+    void Orphan() override;
 
-typedef struct {
-  grpc_byte_stream base;
-  grpc_byte_stream_cache* cache;
-  size_t cursor;
-  grpc_error* shutdown_error;
-} grpc_caching_byte_stream;
+    bool Next(size_t max_size_hint, grpc_closure* on_complete) override;
+    grpc_error* Pull(grpc_slice* slice) override;
+    void Shutdown(grpc_error* error) override;
 
-void grpc_caching_byte_stream_init(grpc_caching_byte_stream* stream,
-                                   grpc_byte_stream_cache* cache);
+    // Resets the byte stream to the start of the underlying stream.
+    void Reset();
 
-// Resets the byte stream to the start of the underlying stream.
-void grpc_caching_byte_stream_reset(grpc_caching_byte_stream* stream);
+   private:
+    ByteStreamCache* cache_;
+    size_t cursor_ = 0;
+    size_t offset_ = 0;
+    grpc_error* shutdown_error_ = GRPC_ERROR_NONE;
+  };
+
+  explicit ByteStreamCache(OrphanablePtr<ByteStream> underlying_stream);
+
+  ~ByteStreamCache();
+
+  // Must not be destroyed while still in use by a CachingByteStream.
+  void Destroy();
+
+  grpc_slice_buffer* cache_buffer() { return &cache_buffer_; }
+
+ private:
+  OrphanablePtr<ByteStream> underlying_stream_;
+  uint32_t length_;
+  uint32_t flags_;
+  grpc_slice_buffer cache_buffer_;
+};
+
+}  // namespace grpc_core
 
 #endif /* GRPC_CORE_LIB_TRANSPORT_BYTE_STREAM_H */
diff --git a/src/core/lib/transport/connectivity_state.cc b/src/core/lib/transport/connectivity_state.cc
index c42cc9c..0122e77 100644
--- a/src/core/lib/transport/connectivity_state.cc
+++ b/src/core/lib/transport/connectivity_state.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/transport/connectivity_state.h"
 
 #include <string.h>
@@ -73,9 +75,8 @@
 
 grpc_connectivity_state grpc_connectivity_state_check(
     grpc_connectivity_state_tracker* tracker) {
-  grpc_connectivity_state cur =
-      (grpc_connectivity_state)gpr_atm_no_barrier_load(
-          &tracker->current_state_atm);
+  grpc_connectivity_state cur = static_cast<grpc_connectivity_state>(
+      gpr_atm_no_barrier_load(&tracker->current_state_atm));
   if (grpc_connectivity_state_trace.enabled()) {
     gpr_log(GPR_DEBUG, "CONWATCH: %p %s: get %s", tracker, tracker->name,
             grpc_connectivity_state_name(cur));
@@ -85,9 +86,8 @@
 
 grpc_connectivity_state grpc_connectivity_state_get(
     grpc_connectivity_state_tracker* tracker, grpc_error** error) {
-  grpc_connectivity_state cur =
-      (grpc_connectivity_state)gpr_atm_no_barrier_load(
-          &tracker->current_state_atm);
+  grpc_connectivity_state cur = static_cast<grpc_connectivity_state>(
+      gpr_atm_no_barrier_load(&tracker->current_state_atm));
   if (grpc_connectivity_state_trace.enabled()) {
     gpr_log(GPR_DEBUG, "CONWATCH: %p %s: get %s", tracker, tracker->name,
             grpc_connectivity_state_name(cur));
@@ -106,9 +106,8 @@
 bool grpc_connectivity_state_notify_on_state_change(
     grpc_connectivity_state_tracker* tracker, grpc_connectivity_state* current,
     grpc_closure* notify) {
-  grpc_connectivity_state cur =
-      (grpc_connectivity_state)gpr_atm_no_barrier_load(
-          &tracker->current_state_atm);
+  grpc_connectivity_state cur = static_cast<grpc_connectivity_state>(
+      gpr_atm_no_barrier_load(&tracker->current_state_atm));
   if (grpc_connectivity_state_trace.enabled()) {
     if (current == nullptr) {
       gpr_log(GPR_DEBUG, "CONWATCH: %p %s: unsubscribe notify=%p", tracker,
@@ -144,7 +143,7 @@
       GRPC_CLOSURE_SCHED(notify, GRPC_ERROR_REF(tracker->current_error));
     } else {
       grpc_connectivity_state_watcher* w =
-          (grpc_connectivity_state_watcher*)gpr_malloc(sizeof(*w));
+          static_cast<grpc_connectivity_state_watcher*>(gpr_malloc(sizeof(*w)));
       w->current = current;
       w->notify = notify;
       w->next = tracker->watchers;
@@ -157,9 +156,8 @@
 void grpc_connectivity_state_set(grpc_connectivity_state_tracker* tracker,
                                  grpc_connectivity_state state,
                                  grpc_error* error, const char* reason) {
-  grpc_connectivity_state cur =
-      (grpc_connectivity_state)gpr_atm_no_barrier_load(
-          &tracker->current_state_atm);
+  grpc_connectivity_state cur = static_cast<grpc_connectivity_state>(
+      gpr_atm_no_barrier_load(&tracker->current_state_atm));
   grpc_connectivity_state_watcher* w;
   if (grpc_connectivity_state_trace.enabled()) {
     const char* error_string = grpc_error_string(error);
diff --git a/src/core/lib/transport/connectivity_state.h b/src/core/lib/transport/connectivity_state.h
index c3a50f3..ecb083c 100644
--- a/src/core/lib/transport/connectivity_state.h
+++ b/src/core/lib/transport/connectivity_state.h
@@ -19,9 +19,11 @@
 #ifndef GRPC_CORE_LIB_TRANSPORT_CONNECTIVITY_STATE_H
 #define GRPC_CORE_LIB_TRANSPORT_CONNECTIVITY_STATE_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 #include "src/core/lib/debug/trace.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/closure.h"
 
 typedef struct grpc_connectivity_state_watcher {
   /** we keep watchers in a linked list */
diff --git a/src/core/lib/transport/error_utils.cc b/src/core/lib/transport/error_utils.cc
index 891576f..2eff8b2 100644
--- a/src/core/lib/transport/error_utils.cc
+++ b/src/core/lib/transport/error_utils.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/transport/error_utils.h"
 
 #include <grpc/support/string_util.h>
@@ -32,7 +34,8 @@
   // Otherwise, search through its children.
   uint8_t slot = error->first_err;
   while (slot != UINT8_MAX) {
-    grpc_linked_error* lerr = (grpc_linked_error*)(error->arena + slot);
+    grpc_linked_error* lerr =
+        reinterpret_cast<grpc_linked_error*>(error->arena + slot);
     grpc_error* result = recursively_find_error_with_field(lerr->err, which);
     if (result) return result;
     slot = lerr->next;
@@ -62,11 +65,11 @@
   grpc_status_code status = GRPC_STATUS_UNKNOWN;
   intptr_t integer;
   if (grpc_error_get_int(found_error, GRPC_ERROR_INT_GRPC_STATUS, &integer)) {
-    status = (grpc_status_code)integer;
+    status = static_cast<grpc_status_code>(integer);
   } else if (grpc_error_get_int(found_error, GRPC_ERROR_INT_HTTP2_ERROR,
                                 &integer)) {
-    status = grpc_http2_error_to_grpc_status((grpc_http2_error_code)integer,
-                                             deadline);
+    status = grpc_http2_error_to_grpc_status(
+        static_cast<grpc_http2_error_code>(integer), deadline);
   }
   if (code != nullptr) *code = status;
 
@@ -76,10 +79,11 @@
 
   if (http_error != nullptr) {
     if (grpc_error_get_int(found_error, GRPC_ERROR_INT_HTTP2_ERROR, &integer)) {
-      *http_error = (grpc_http2_error_code)integer;
+      *http_error = static_cast<grpc_http2_error_code>(integer);
     } else if (grpc_error_get_int(found_error, GRPC_ERROR_INT_GRPC_STATUS,
                                   &integer)) {
-      *http_error = grpc_status_to_http2_error((grpc_status_code)integer);
+      *http_error =
+          grpc_status_to_http2_error(static_cast<grpc_status_code>(integer));
     } else {
       *http_error = found_error == GRPC_ERROR_NONE ? GRPC_HTTP2_NO_ERROR
                                                    : GRPC_HTTP2_INTERNAL_ERROR;
@@ -103,7 +107,8 @@
   }
   uint8_t slot = error->first_err;
   while (slot != UINT8_MAX) {
-    grpc_linked_error* lerr = (grpc_linked_error*)(error->arena + slot);
+    grpc_linked_error* lerr =
+        reinterpret_cast<grpc_linked_error*>(error->arena + slot);
     if (grpc_error_has_clear_grpc_status(lerr->err)) {
       return true;
     }
diff --git a/src/core/lib/transport/error_utils.h b/src/core/lib/transport/error_utils.h
index 4100f65..9a46267 100644
--- a/src/core/lib/transport/error_utils.h
+++ b/src/core/lib/transport/error_utils.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_TRANSPORT_ERROR_UTILS_H
 #define GRPC_CORE_LIB_TRANSPORT_ERROR_UTILS_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/transport/http2_errors.h"
diff --git a/src/core/lib/transport/metadata.cc b/src/core/lib/transport/metadata.cc
index cc1edd5..d10194a 100644
--- a/src/core/lib/transport/metadata.cc
+++ b/src/core/lib/transport/metadata.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/transport/metadata.h"
 
 #include <assert.h>
@@ -118,8 +120,8 @@
     shard->count = 0;
     gpr_atm_no_barrier_store(&shard->free_estimate, 0);
     shard->capacity = INITIAL_SHARD_CAPACITY;
-    shard->elems = (interned_metadata**)gpr_zalloc(sizeof(*shard->elems) *
-                                                   shard->capacity);
+    shard->elems = static_cast<interned_metadata**>(
+        gpr_zalloc(sizeof(*shard->elems) * shard->capacity));
   }
 }
 
@@ -206,8 +208,8 @@
   interned_metadata *md, *next;
   uint32_t hash;
 
-  mdtab =
-      (interned_metadata**)gpr_zalloc(sizeof(interned_metadata*) * capacity);
+  mdtab = static_cast<interned_metadata**>(
+      gpr_zalloc(sizeof(interned_metadata*) * capacity));
 
   for (i = 0; i < shard->capacity; i++) {
     for (md = shard->elems[i]; md; md = next) {
@@ -227,7 +229,7 @@
 
 static void rehash_mdtab(mdtab_shard* shard) {
   if (gpr_atm_no_barrier_load(&shard->free_estimate) >
-      (gpr_atm)(shard->capacity / 4)) {
+      static_cast<gpr_atm>(shard->capacity / 4)) {
     gc_mdtab(shard);
   } else {
     grow_mdtab(shard);
@@ -244,7 +246,7 @@
     }
 
     allocated_metadata* allocated =
-        (allocated_metadata*)gpr_malloc(sizeof(*allocated));
+        static_cast<allocated_metadata*>(gpr_malloc(sizeof(*allocated)));
     allocated->key = grpc_slice_ref_internal(key);
     allocated->value = grpc_slice_ref_internal(value);
     gpr_atm_rel_store(&allocated->refcnt, 1);
@@ -292,7 +294,7 @@
   }
 
   /* not found: create a new pair */
-  md = (interned_metadata*)gpr_malloc(sizeof(interned_metadata));
+  md = static_cast<interned_metadata*>(gpr_malloc(sizeof(interned_metadata)));
   gpr_atm_rel_store(&md->refcnt, 1);
   md->key = grpc_slice_ref_internal(key);
   md->value = grpc_slice_ref_internal(value);
@@ -335,8 +337,9 @@
       grpc_slice_maybe_static_intern(metadata->key, &changed);
   grpc_slice value_slice =
       grpc_slice_maybe_static_intern(metadata->value, &changed);
-  return grpc_mdelem_create(key_slice, value_slice,
-                            changed ? nullptr : (grpc_mdelem_data*)metadata);
+  return grpc_mdelem_create(
+      key_slice, value_slice,
+      changed ? nullptr : reinterpret_cast<grpc_mdelem_data*>(metadata));
 }
 
 static size_t get_base64_encoded_size(size_t raw_length) {
@@ -363,7 +366,8 @@
     case GRPC_MDELEM_STORAGE_STATIC:
       break;
     case GRPC_MDELEM_STORAGE_INTERNED: {
-      interned_metadata* md = (interned_metadata*)GRPC_MDELEM_DATA(gmd);
+      interned_metadata* md =
+          reinterpret_cast<interned_metadata*> GRPC_MDELEM_DATA(gmd);
 #ifndef NDEBUG
       if (grpc_trace_metadata.enabled()) {
         char* key_str = grpc_slice_to_c_string(md->key);
@@ -385,7 +389,8 @@
       break;
     }
     case GRPC_MDELEM_STORAGE_ALLOCATED: {
-      allocated_metadata* md = (allocated_metadata*)GRPC_MDELEM_DATA(gmd);
+      allocated_metadata* md =
+          reinterpret_cast<allocated_metadata*> GRPC_MDELEM_DATA(gmd);
 #ifndef NDEBUG
       if (grpc_trace_metadata.enabled()) {
         char* key_str = grpc_slice_to_c_string(md->key);
@@ -415,7 +420,8 @@
     case GRPC_MDELEM_STORAGE_STATIC:
       break;
     case GRPC_MDELEM_STORAGE_INTERNED: {
-      interned_metadata* md = (interned_metadata*)GRPC_MDELEM_DATA(gmd);
+      interned_metadata* md =
+          reinterpret_cast<interned_metadata*> GRPC_MDELEM_DATA(gmd);
 #ifndef NDEBUG
       if (grpc_trace_metadata.enabled()) {
         char* key_str = grpc_slice_to_c_string(md->key);
@@ -441,7 +447,8 @@
       break;
     }
     case GRPC_MDELEM_STORAGE_ALLOCATED: {
-      allocated_metadata* md = (allocated_metadata*)GRPC_MDELEM_DATA(gmd);
+      allocated_metadata* md =
+          reinterpret_cast<allocated_metadata*> GRPC_MDELEM_DATA(gmd);
 #ifndef NDEBUG
       if (grpc_trace_metadata.enabled()) {
         char* key_str = grpc_slice_to_c_string(md->key);
@@ -475,7 +482,8 @@
       return (void*)grpc_static_mdelem_user_data[GRPC_MDELEM_DATA(md) -
                                                  grpc_static_mdelem_table];
     case GRPC_MDELEM_STORAGE_INTERNED: {
-      interned_metadata* im = (interned_metadata*)GRPC_MDELEM_DATA(md);
+      interned_metadata* im =
+          reinterpret_cast<interned_metadata*> GRPC_MDELEM_DATA(md);
       void* result;
       if (gpr_atm_acq_load(&im->destroy_user_data) == (gpr_atm)destroy_func) {
         return (void*)gpr_atm_no_barrier_load(&im->user_data);
@@ -500,7 +508,8 @@
       return (void*)grpc_static_mdelem_user_data[GRPC_MDELEM_DATA(md) -
                                                  grpc_static_mdelem_table];
     case GRPC_MDELEM_STORAGE_INTERNED: {
-      interned_metadata* im = (interned_metadata*)GRPC_MDELEM_DATA(md);
+      interned_metadata* im =
+          reinterpret_cast<interned_metadata*> GRPC_MDELEM_DATA(md);
       GPR_ASSERT(!is_mdelem_static(md));
       GPR_ASSERT((user_data == nullptr) == (destroy_func == nullptr));
       gpr_mu_lock(&im->mu_user_data);
diff --git a/src/core/lib/transport/metadata.h b/src/core/lib/transport/metadata.h
index 78e6bef..78df4bc 100644
--- a/src/core/lib/transport/metadata.h
+++ b/src/core/lib/transport/metadata.h
@@ -19,11 +19,13 @@
 #ifndef GRPC_CORE_LIB_TRANSPORT_METADATA_H
 #define GRPC_CORE_LIB_TRANSPORT_METADATA_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 #include <grpc/slice.h>
-#include <grpc/support/useful.h>
 
-#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/gpr/useful.h"
 
 extern grpc_core::DebugOnlyTraceFlag grpc_trace_metadata;
 
diff --git a/src/core/lib/transport/metadata_batch.cc b/src/core/lib/transport/metadata_batch.cc
index 9c95339..49740fc 100644
--- a/src/core/lib/transport/metadata_batch.cc
+++ b/src/core/lib/transport/metadata_batch.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/transport/metadata_batch.h"
 
 #include <stdbool.h>
@@ -301,3 +303,27 @@
   }
   return error;
 }
+
+void grpc_metadata_batch_copy(grpc_metadata_batch* src,
+                              grpc_metadata_batch* dst,
+                              grpc_linked_mdelem* storage) {
+  grpc_metadata_batch_init(dst);
+  dst->deadline = src->deadline;
+  size_t i = 0;
+  for (grpc_linked_mdelem* elem = src->list.head; elem != nullptr;
+       elem = elem->next) {
+    grpc_error* error = grpc_metadata_batch_add_tail(dst, &storage[i++],
+                                                     GRPC_MDELEM_REF(elem->md));
+    // The only way that grpc_metadata_batch_add_tail() can fail is if
+    // there's a duplicate entry for a callout.  However, that can't be
+    // the case here, because we would not have been allowed to create
+    // a source batch that had that kind of conflict.
+    GPR_ASSERT(error == GRPC_ERROR_NONE);
+  }
+}
+
+void grpc_metadata_batch_move(grpc_metadata_batch* src,
+                              grpc_metadata_batch* dst) {
+  *dst = *src;
+  grpc_metadata_batch_init(src);
+}
diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h
index 8353a42..7068750 100644
--- a/src/core/lib/transport/metadata_batch.h
+++ b/src/core/lib/transport/metadata_batch.h
@@ -19,12 +19,14 @@
 #ifndef GRPC_CORE_LIB_TRANSPORT_METADATA_BATCH_H
 #define GRPC_CORE_LIB_TRANSPORT_METADATA_BATCH_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stdbool.h>
 
 #include <grpc/grpc.h>
 #include <grpc/slice.h>
-#include <grpc/support/port_platform.h>
 #include <grpc/support/time.h>
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/transport/metadata.h"
 #include "src/core/lib/transport/static_metadata.h"
 
@@ -136,4 +138,13 @@
   } while (0)
 #endif
 
+/// Copies \a src to \a dst.  \a storage must point to an array of
+/// \a grpc_linked_mdelem structs of at least the same size as \a src.
+void grpc_metadata_batch_copy(grpc_metadata_batch* src,
+                              grpc_metadata_batch* dst,
+                              grpc_linked_mdelem* storage);
+
+void grpc_metadata_batch_move(grpc_metadata_batch* src,
+                              grpc_metadata_batch* dst);
+
 #endif /* GRPC_CORE_LIB_TRANSPORT_METADATA_BATCH_H */
diff --git a/src/core/lib/transport/pid_controller.cc b/src/core/lib/transport/pid_controller.cc
index e31cc85..dbc98f4 100644
--- a/src/core/lib/transport/pid_controller.cc
+++ b/src/core/lib/transport/pid_controller.cc
@@ -16,8 +16,11 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/transport/pid_controller.h"
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
 
 namespace grpc_core {
 
diff --git a/src/core/lib/transport/pid_controller.h b/src/core/lib/transport/pid_controller.h
index 87e59a1..e26205b 100644
--- a/src/core/lib/transport/pid_controller.h
+++ b/src/core/lib/transport/pid_controller.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H
 #define GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H
 
+#include <grpc/support/port_platform.h>
+
 #include <limits>
 
 /* \file Simple PID controller.
diff --git a/src/core/lib/transport/service_config.cc b/src/core/lib/transport/service_config.cc
index 5c9930a..e1a55d9 100644
--- a/src/core/lib/transport/service_config.cc
+++ b/src/core/lib/transport/service_config.cc
@@ -14,6 +14,8 @@
 // limitations under the License.
 //
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/transport/service_config.h"
 
 #include <string.h>
@@ -29,74 +31,30 @@
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 
-// The main purpose of the code here is to parse the service config in
-// JSON form, which will look like this:
-//
-// {
-//   "loadBalancingPolicy": "string",  // optional
-//   "methodConfig": [  // array of one or more method_config objects
-//     {
-//       "name": [  // array of one or more name objects
-//         {
-//           "service": "string",  // required
-//           "method": "string",  // optional
-//         }
-//       ],
-//       // remaining fields are optional.
-//       // see https://developers.google.com/protocol-buffers/docs/proto3#json
-//       // for format details.
-//       "waitForReady": bool,
-//       "timeout": "duration_string",
-//       "maxRequestMessageBytes": "int64_string",
-//       "maxResponseMessageBytes": "int64_string",
-//     }
-//   ]
-// }
+namespace grpc_core {
 
-struct grpc_service_config {
-  char* json_string;  // Underlying storage for json_tree.
-  grpc_json* json_tree;
-};
-
-grpc_service_config* grpc_service_config_create(const char* json_string) {
-  grpc_service_config* service_config =
-      (grpc_service_config*)gpr_malloc(sizeof(*service_config));
-  service_config->json_string = gpr_strdup(json_string);
-  service_config->json_tree =
-      grpc_json_parse_string(service_config->json_string);
-  if (service_config->json_tree == nullptr) {
+UniquePtr<ServiceConfig> ServiceConfig::Create(const char* json) {
+  UniquePtr<char> json_string(gpr_strdup(json));
+  grpc_json* json_tree = grpc_json_parse_string(json_string.get());
+  if (json_tree == nullptr) {
     gpr_log(GPR_INFO, "failed to parse JSON for service config");
-    gpr_free(service_config->json_string);
-    gpr_free(service_config);
     return nullptr;
   }
-  return service_config;
+  return MakeUnique<ServiceConfig>(std::move(json_string), json_tree);
 }
 
-void grpc_service_config_destroy(grpc_service_config* service_config) {
-  grpc_json_destroy(service_config->json_tree);
-  gpr_free(service_config->json_string);
-  gpr_free(service_config);
-}
+ServiceConfig::ServiceConfig(UniquePtr<char> json_string, grpc_json* json_tree)
+    : json_string_(std::move(json_string)), json_tree_(json_tree) {}
 
-void grpc_service_config_parse_global_params(
-    const grpc_service_config* service_config,
-    void (*process_json)(const grpc_json* json, void* arg), void* arg) {
-  const grpc_json* json = service_config->json_tree;
-  if (json->type != GRPC_JSON_OBJECT || json->key != nullptr) return;
-  for (grpc_json* field = json->child; field != nullptr; field = field->next) {
-    if (field->key == nullptr) return;
-    if (strcmp(field->key, "methodConfig") == 0) continue;
-    process_json(field, arg);
+ServiceConfig::~ServiceConfig() { grpc_json_destroy(json_tree_); }
+
+const char* ServiceConfig::GetLoadBalancingPolicyName() const {
+  if (json_tree_->type != GRPC_JSON_OBJECT || json_tree_->key != nullptr) {
+    return nullptr;
   }
-}
-
-const char* grpc_service_config_get_lb_policy_name(
-    const grpc_service_config* service_config) {
-  const grpc_json* json = service_config->json_tree;
-  if (json->type != GRPC_JSON_OBJECT || json->key != nullptr) return nullptr;
   const char* lb_policy_name = nullptr;
-  for (grpc_json* field = json->child; field != nullptr; field = field->next) {
+  for (grpc_json* field = json_tree_->child; field != nullptr;
+       field = field->next) {
     if (field->key == nullptr) return nullptr;
     if (strcmp(field->key, "loadBalancingPolicy") == 0) {
       if (lb_policy_name != nullptr) return nullptr;  // Duplicate.
@@ -107,8 +65,7 @@
   return lb_policy_name;
 }
 
-// Returns the number of names specified in the method config \a json.
-static size_t count_names_in_method_config_json(grpc_json* json) {
+size_t ServiceConfig::CountNamesInMethodConfig(grpc_json* json) {
   size_t num_names = 0;
   for (grpc_json* field = json->child; field != nullptr; field = field->next) {
     if (field->key != nullptr && strcmp(field->key, "name") == 0) {
@@ -122,9 +79,7 @@
   return num_names;
 }
 
-// Returns a path string for the JSON name object specified by \a json.
-// Returns NULL on error.  Caller takes ownership of result.
-static char* parse_json_method_name(grpc_json* json) {
+UniquePtr<char> ServiceConfig::ParseJsonMethodName(grpc_json* json) {
   if (json->type != GRPC_JSON_OBJECT) return nullptr;
   const char* service_name = nullptr;
   const char* method_name = nullptr;
@@ -145,116 +100,7 @@
   char* path;
   gpr_asprintf(&path, "/%s/%s", service_name,
                method_name == nullptr ? "*" : method_name);
-  return path;
+  return UniquePtr<char>(path);
 }
 
-// Parses the method config from \a json.  Adds an entry to \a entries for
-// each name found, incrementing \a idx for each entry added.
-// Returns false on error.
-static bool parse_json_method_config(
-    grpc_json* json, void* (*create_value)(const grpc_json* method_config_json),
-    void* (*ref_value)(void* value), void (*unref_value)(void* value),
-    grpc_slice_hash_table_entry* entries, size_t* idx) {
-  // Construct value.
-  void* method_config = create_value(json);
-  if (method_config == nullptr) return false;
-  // Construct list of paths.
-  bool success = false;
-  gpr_strvec paths;
-  gpr_strvec_init(&paths);
-  for (grpc_json* child = json->child; child != nullptr; child = child->next) {
-    if (child->key == nullptr) continue;
-    if (strcmp(child->key, "name") == 0) {
-      if (child->type != GRPC_JSON_ARRAY) goto done;
-      for (grpc_json* name = child->child; name != nullptr; name = name->next) {
-        char* path = parse_json_method_name(name);
-        if (path == nullptr) goto done;
-        gpr_strvec_add(&paths, path);
-      }
-    }
-  }
-  if (paths.count == 0) goto done;  // No names specified.
-  // Add entry for each path.
-  for (size_t i = 0; i < paths.count; ++i) {
-    entries[*idx].key = grpc_slice_from_copied_string(paths.strs[i]);
-    entries[*idx].value = ref_value(method_config);
-    ++*idx;
-  }
-  success = true;
-done:
-  unref_value(method_config);
-  gpr_strvec_destroy(&paths);
-  return success;
-}
-
-grpc_slice_hash_table* grpc_service_config_create_method_config_table(
-    const grpc_service_config* service_config,
-    void* (*create_value)(const grpc_json* method_config_json),
-    void* (*ref_value)(void* value), void (*unref_value)(void* value)) {
-  const grpc_json* json = service_config->json_tree;
-  // Traverse parsed JSON tree.
-  if (json->type != GRPC_JSON_OBJECT || json->key != nullptr) return nullptr;
-  size_t num_entries = 0;
-  grpc_slice_hash_table_entry* entries = nullptr;
-  for (grpc_json* field = json->child; field != nullptr; field = field->next) {
-    if (field->key == nullptr) return nullptr;
-    if (strcmp(field->key, "methodConfig") == 0) {
-      if (entries != nullptr) return nullptr;  // Duplicate.
-      if (field->type != GRPC_JSON_ARRAY) return nullptr;
-      // Find number of entries.
-      for (grpc_json* method = field->child; method != nullptr;
-           method = method->next) {
-        size_t count = count_names_in_method_config_json(method);
-        if (count <= 0) return nullptr;
-        num_entries += count;
-      }
-      // Populate method config table entries.
-      entries = (grpc_slice_hash_table_entry*)gpr_malloc(
-          num_entries * sizeof(grpc_slice_hash_table_entry));
-      size_t idx = 0;
-      for (grpc_json* method = field->child; method != nullptr;
-           method = method->next) {
-        if (!parse_json_method_config(method, create_value, ref_value,
-                                      unref_value, entries, &idx)) {
-          for (size_t i = 0; i < idx; ++i) {
-            grpc_slice_unref_internal(entries[i].key);
-            unref_value(entries[i].value);
-          }
-          gpr_free(entries);
-          return nullptr;
-        }
-      }
-      GPR_ASSERT(idx == num_entries);
-    }
-  }
-  // Instantiate method config table.
-  grpc_slice_hash_table* method_config_table = nullptr;
-  if (entries != nullptr) {
-    method_config_table = grpc_slice_hash_table_create(num_entries, entries,
-                                                       unref_value, nullptr);
-    gpr_free(entries);
-  }
-  return method_config_table;
-}
-
-void* grpc_method_config_table_get(const grpc_slice_hash_table* table,
-                                   grpc_slice path) {
-  void* value = grpc_slice_hash_table_get(table, path);
-  // If we didn't find a match for the path, try looking for a wildcard
-  // entry (i.e., change "/service/method" to "/service/*").
-  if (value == nullptr) {
-    char* path_str = grpc_slice_to_c_string(path);
-    const char* sep = strrchr(path_str, '/') + 1;
-    const size_t len = (size_t)(sep - path_str);
-    char* buf = (char*)gpr_malloc(len + 2);  // '*' and NUL
-    memcpy(buf, path_str, len);
-    buf[len] = '*';
-    buf[len + 1] = '\0';
-    grpc_slice wildcard_path = grpc_slice_from_copied_string(buf);
-    gpr_free(buf);
-    value = grpc_slice_hash_table_get(table, wildcard_path);
-    grpc_slice_unref_internal(wildcard_path);
-    gpr_free(path_str);
-  }
-  return value;
-}
+}  // namespace grpc_core
diff --git a/src/core/lib/transport/service_config.h b/src/core/lib/transport/service_config.h
index 98554b9..a65b267 100644
--- a/src/core/lib/transport/service_config.h
+++ b/src/core/lib/transport/service_config.h
@@ -17,45 +17,233 @@
 #ifndef GRPC_CORE_LIB_TRANSPORT_SERVICE_CONFIG_H
 #define GRPC_CORE_LIB_TRANSPORT_SERVICE_CONFIG_H
 
-#include <grpc/impl/codegen/grpc_types.h>
+#include <grpc/support/port_platform.h>
 
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/gprpp/inlined_vector.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/json/json.h"
 #include "src/core/lib/slice/slice_hash_table.h"
 
-typedef struct grpc_service_config grpc_service_config;
+// The main purpose of the code here is to parse the service config in
+// JSON form, which will look like this:
+//
+// {
+//   "loadBalancingPolicy": "string",  // optional
+//   "methodConfig": [  // array of one or more method_config objects
+//     {
+//       "name": [  // array of one or more name objects
+//         {
+//           "service": "string",  // required
+//           "method": "string",  // optional
+//         }
+//       ],
+//       // remaining fields are optional.
+//       // see
+//       https://developers.google.com/protocol-buffers/docs/proto3#json
+//       // for format details.
+//       "waitForReady": bool,
+//       "timeout": "duration_string",
+//       "maxRequestMessageBytes": "int64_string",
+//       "maxResponseMessageBytes": "int64_string",
+//     }
+//   ]
+// }
 
-grpc_service_config* grpc_service_config_create(const char* json_string);
-void grpc_service_config_destroy(grpc_service_config* service_config);
+namespace grpc_core {
 
-/// Invokes \a process_json() for each global parameter in the service
-/// config.  \a arg is passed as the second argument to \a process_json().
-void grpc_service_config_parse_global_params(
-    const grpc_service_config* service_config,
-    void (*process_json)(const grpc_json* json, void* arg), void* arg);
+class ServiceConfig {
+ public:
+  /// Creates a new service config from parsing \a json_string.
+  /// Returns null on parse error.
+  static UniquePtr<ServiceConfig> Create(const char* json);
 
-/// Gets the LB policy name from \a service_config.
-/// Returns NULL if no LB policy name was specified.
-/// Caller does NOT take ownership.
-const char* grpc_service_config_get_lb_policy_name(
-    const grpc_service_config* service_config);
+  ~ServiceConfig();
 
-/// Creates a method config table based on the data in \a json.
-/// The table's keys are request paths.  The table's value type is
-/// returned by \a create_value(), based on data parsed from the JSON tree.
-/// \a ref_value() and \a unref_value() are used to ref and unref values.
-/// Returns NULL on error.
-grpc_slice_hash_table* grpc_service_config_create_method_config_table(
-    const grpc_service_config* service_config,
-    void* (*create_value)(const grpc_json* method_config_json),
-    void* (*ref_value)(void* value), void (*unref_value)(void* value));
+  /// Invokes \a process_json() for each global parameter in the service
+  /// config.  \a arg is passed as the second argument to \a process_json().
+  template <typename T>
+  using ProcessJson = void (*)(const grpc_json*, T*);
+  template <typename T>
+  void ParseGlobalParams(ProcessJson<T> process_json, T* arg) const;
 
-/// A helper function for looking up values in the table returned by
-/// \a grpc_service_config_create_method_config_table().
-/// Gets the method config for the specified \a path, which should be of
-/// the form "/service/method".
-/// Returns NULL if the method has no config.
-/// Caller does NOT own a reference to the result.
-void* grpc_method_config_table_get(const grpc_slice_hash_table* table,
-                                   grpc_slice path);
+  /// Gets the LB policy name from \a service_config.
+  /// Returns NULL if no LB policy name was specified.
+  /// Caller does NOT take ownership.
+  const char* GetLoadBalancingPolicyName() const;
+
+  /// Creates a method config table based on the data in \a json.
+  /// The table's keys are request paths.  The table's value type is
+  /// returned by \a create_value(), based on data parsed from the JSON tree.
+  /// Returns null on error.
+  template <typename T>
+  using CreateValue = RefCountedPtr<T> (*)(const grpc_json* method_config_json);
+  template <typename T>
+  RefCountedPtr<SliceHashTable<RefCountedPtr<T>>> CreateMethodConfigTable(
+      CreateValue<T> create_value);
+
+  /// A helper function for looking up values in the table returned by
+  /// \a CreateMethodConfigTable().
+  /// Gets the method config for the specified \a path, which should be of
+  /// the form "/service/method".
+  /// Returns null if the method has no config.
+  /// Caller does NOT own a reference to the result.
+  template <typename T>
+  static RefCountedPtr<T> MethodConfigTableLookup(
+      const SliceHashTable<RefCountedPtr<T>>& table, grpc_slice path);
+
+ private:
+  // So New() can call our private ctor.
+  template <typename T, typename... Args>
+  friend T* New(Args&&... args);
+
+  // Takes ownership of \a json_tree.
+  ServiceConfig(UniquePtr<char> json_string, grpc_json* json_tree);
+
+  // Returns the number of names specified in the method config \a json.
+  static size_t CountNamesInMethodConfig(grpc_json* json);
+
+  // Returns a path string for the JSON name object specified by \a json.
+  // Returns null on error.
+  static UniquePtr<char> ParseJsonMethodName(grpc_json* json);
+
+  // Parses the method config from \a json.  Adds an entry to \a entries for
+  // each name found, incrementing \a idx for each entry added.
+  // Returns false on error.
+  template <typename T>
+  static bool ParseJsonMethodConfig(
+      grpc_json* json, CreateValue<T> create_value,
+      typename SliceHashTable<RefCountedPtr<T>>::Entry* entries, size_t* idx);
+
+  UniquePtr<char> json_string_;  // Underlying storage for json_tree.
+  grpc_json* json_tree_;
+};
+
+//
+// implementation -- no user-serviceable parts below
+//
+
+template <typename T>
+void ServiceConfig::ParseGlobalParams(ProcessJson<T> process_json,
+                                      T* arg) const {
+  if (json_tree_->type != GRPC_JSON_OBJECT || json_tree_->key != nullptr) {
+    return;
+  }
+  for (grpc_json* field = json_tree_->child; field != nullptr;
+       field = field->next) {
+    if (field->key == nullptr) return;
+    if (strcmp(field->key, "methodConfig") == 0) continue;
+    process_json(field, arg);
+  }
+}
+
+template <typename T>
+bool ServiceConfig::ParseJsonMethodConfig(
+    grpc_json* json, CreateValue<T> create_value,
+    typename SliceHashTable<RefCountedPtr<T>>::Entry* entries, size_t* idx) {
+  // Construct value.
+  RefCountedPtr<T> method_config = create_value(json);
+  if (method_config == nullptr) return false;
+  // Construct list of paths.
+  InlinedVector<UniquePtr<char>, 10> paths;
+  for (grpc_json* child = json->child; child != nullptr; child = child->next) {
+    if (child->key == nullptr) continue;
+    if (strcmp(child->key, "name") == 0) {
+      if (child->type != GRPC_JSON_ARRAY) return false;
+      for (grpc_json* name = child->child; name != nullptr; name = name->next) {
+        UniquePtr<char> path = ParseJsonMethodName(name);
+        if (path == nullptr) return false;
+        paths.push_back(std::move(path));
+      }
+    }
+  }
+  if (paths.size() == 0) return false;  // No names specified.
+  // Add entry for each path.
+  for (size_t i = 0; i < paths.size(); ++i) {
+    entries[*idx].key = grpc_slice_from_copied_string(paths[i].get());
+    entries[*idx].value = method_config;  // Takes a new ref.
+    ++*idx;
+  }
+  // Success.
+  return true;
+}
+
+template <typename T>
+RefCountedPtr<SliceHashTable<RefCountedPtr<T>>>
+ServiceConfig::CreateMethodConfigTable(CreateValue<T> create_value) {
+  // Traverse parsed JSON tree.
+  if (json_tree_->type != GRPC_JSON_OBJECT || json_tree_->key != nullptr) {
+    return nullptr;
+  }
+  size_t num_entries = 0;
+  typename SliceHashTable<RefCountedPtr<T>>::Entry* entries = nullptr;
+  for (grpc_json* field = json_tree_->child; field != nullptr;
+       field = field->next) {
+    if (field->key == nullptr) return nullptr;
+    if (strcmp(field->key, "methodConfig") == 0) {
+      if (entries != nullptr) return nullptr;  // Duplicate.
+      if (field->type != GRPC_JSON_ARRAY) return nullptr;
+      // Find number of entries.
+      for (grpc_json* method = field->child; method != nullptr;
+           method = method->next) {
+        size_t count = CountNamesInMethodConfig(method);
+        if (count <= 0) return nullptr;
+        num_entries += count;
+      }
+      // Populate method config table entries.
+      entries = static_cast<typename SliceHashTable<RefCountedPtr<T>>::Entry*>(
+          gpr_zalloc(num_entries *
+                     sizeof(typename SliceHashTable<RefCountedPtr<T>>::Entry)));
+      size_t idx = 0;
+      for (grpc_json* method = field->child; method != nullptr;
+           method = method->next) {
+        if (!ParseJsonMethodConfig(method, create_value, entries, &idx)) {
+          for (size_t i = 0; i < idx; ++i) {
+            grpc_slice_unref_internal(entries[i].key);
+            entries[i].value.reset();
+          }
+          gpr_free(entries);
+          return nullptr;
+        }
+      }
+      GPR_ASSERT(idx == num_entries);
+    }
+  }
+  // Instantiate method config table.
+  RefCountedPtr<SliceHashTable<RefCountedPtr<T>>> method_config_table;
+  if (entries != nullptr) {
+    method_config_table =
+        SliceHashTable<RefCountedPtr<T>>::Create(num_entries, entries, nullptr);
+    gpr_free(entries);
+  }
+  return method_config_table;
+}
+
+template <typename T>
+RefCountedPtr<T> ServiceConfig::MethodConfigTableLookup(
+    const SliceHashTable<RefCountedPtr<T>>& table, grpc_slice path) {
+  const RefCountedPtr<T>* value = table.Get(path);
+  // If we didn't find a match for the path, try looking for a wildcard
+  // entry (i.e., change "/service/method" to "/service/*").
+  if (value == nullptr) {
+    char* path_str = grpc_slice_to_c_string(path);
+    const char* sep = strrchr(path_str, '/') + 1;
+    const size_t len = (size_t)(sep - path_str);
+    char* buf = (char*)gpr_malloc(len + 2);  // '*' and NUL
+    memcpy(buf, path_str, len);
+    buf[len] = '*';
+    buf[len + 1] = '\0';
+    grpc_slice wildcard_path = grpc_slice_from_copied_string(buf);
+    gpr_free(buf);
+    value = table.Get(wildcard_path);
+    grpc_slice_unref_internal(wildcard_path);
+    gpr_free(path_str);
+  }
+  return RefCountedPtr<T>(*value);
+}
+
+}  // namespace grpc_core
 
 #endif /* GRPC_CORE_LIB_TRANSPORT_SERVICE_CONFIG_H */
diff --git a/src/core/lib/transport/static_metadata.cc b/src/core/lib/transport/static_metadata.cc
index 82ba7ac..6a5144f 100644
--- a/src/core/lib/transport/static_metadata.cc
+++ b/src/core/lib/transport/static_metadata.cc
@@ -20,10 +20,12 @@
  * To make changes to this file, change
  * tools/codegen/core/gen_static_metadata.py, and then re-run it.
  *
- * See metadata.h for an explanation of the interface here, and metadata.c for
+ * See metadata.h for an explanation of the interface here, and metadata.cc for
  * an explanation of what's going on.
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/transport/static_metadata.h"
 
 #include "src/core/lib/slice/slice_internal.h"
@@ -48,62 +50,64 @@
     114, 110, 97,  108, 45,  115, 116, 114, 101, 97,  109, 45,  101, 110, 99,
     111, 100, 105, 110, 103, 45,  114, 101, 113, 117, 101, 115, 116, 117, 115,
     101, 114, 45,  97,  103, 101, 110, 116, 104, 111, 115, 116, 108, 98,  45,
-    116, 111, 107, 101, 110, 103, 114, 112, 99,  45,  116, 105, 109, 101, 111,
-    117, 116, 103, 114, 112, 99,  46,  119, 97,  105, 116, 95,  102, 111, 114,
-    95,  114, 101, 97,  100, 121, 103, 114, 112, 99,  46,  116, 105, 109, 101,
-    111, 117, 116, 103, 114, 112, 99,  46,  109, 97,  120, 95,  114, 101, 113,
-    117, 101, 115, 116, 95,  109, 101, 115, 115, 97,  103, 101, 95,  98,  121,
-    116, 101, 115, 103, 114, 112, 99,  46,  109, 97,  120, 95,  114, 101, 115,
-    112, 111, 110, 115, 101, 95,  109, 101, 115, 115, 97,  103, 101, 95,  98,
-    121, 116, 101, 115, 47,  103, 114, 112, 99,  46,  108, 98,  46,  118, 49,
-    46,  76,  111, 97,  100, 66,  97,  108, 97,  110, 99,  101, 114, 47,  66,
-    97,  108, 97,  110, 99,  101, 76,  111, 97,  100, 109, 101, 115, 115, 97,
-    103, 101, 47,  100, 101, 102, 108, 97,  116, 101, 109, 101, 115, 115, 97,
-    103, 101, 47,  103, 122, 105, 112, 115, 116, 114, 101, 97,  109, 47,  103,
-    122, 105, 112, 48,  49,  50,  105, 100, 101, 110, 116, 105, 116, 121, 103,
-    122, 105, 112, 100, 101, 102, 108, 97,  116, 101, 116, 114, 97,  105, 108,
-    101, 114, 115, 97,  112, 112, 108, 105, 99,  97,  116, 105, 111, 110, 47,
-    103, 114, 112, 99,  80,  79,  83,  84,  50,  48,  48,  52,  48,  52,  104,
-    116, 116, 112, 104, 116, 116, 112, 115, 103, 114, 112, 99,  71,  69,  84,
-    80,  85,  84,  47,  47,  105, 110, 100, 101, 120, 46,  104, 116, 109, 108,
-    50,  48,  52,  50,  48,  54,  51,  48,  52,  52,  48,  48,  53,  48,  48,
-    97,  99,  99,  101, 112, 116, 45,  99,  104, 97,  114, 115, 101, 116, 103,
-    122, 105, 112, 44,  32,  100, 101, 102, 108, 97,  116, 101, 97,  99,  99,
-    101, 112, 116, 45,  108, 97,  110, 103, 117, 97,  103, 101, 97,  99,  99,
-    101, 112, 116, 45,  114, 97,  110, 103, 101, 115, 97,  99,  99,  101, 112,
-    116, 97,  99,  99,  101, 115, 115, 45,  99,  111, 110, 116, 114, 111, 108,
-    45,  97,  108, 108, 111, 119, 45,  111, 114, 105, 103, 105, 110, 97,  103,
-    101, 97,  108, 108, 111, 119, 97,  117, 116, 104, 111, 114, 105, 122, 97,
-    116, 105, 111, 110, 99,  97,  99,  104, 101, 45,  99,  111, 110, 116, 114,
-    111, 108, 99,  111, 110, 116, 101, 110, 116, 45,  100, 105, 115, 112, 111,
-    115, 105, 116, 105, 111, 110, 99,  111, 110, 116, 101, 110, 116, 45,  108,
-    97,  110, 103, 117, 97,  103, 101, 99,  111, 110, 116, 101, 110, 116, 45,
-    108, 101, 110, 103, 116, 104, 99,  111, 110, 116, 101, 110, 116, 45,  108,
-    111, 99,  97,  116, 105, 111, 110, 99,  111, 110, 116, 101, 110, 116, 45,
-    114, 97,  110, 103, 101, 99,  111, 111, 107, 105, 101, 100, 97,  116, 101,
-    101, 116, 97,  103, 101, 120, 112, 101, 99,  116, 101, 120, 112, 105, 114,
-    101, 115, 102, 114, 111, 109, 105, 102, 45,  109, 97,  116, 99,  104, 105,
-    102, 45,  109, 111, 100, 105, 102, 105, 101, 100, 45,  115, 105, 110, 99,
-    101, 105, 102, 45,  110, 111, 110, 101, 45,  109, 97,  116, 99,  104, 105,
-    102, 45,  114, 97,  110, 103, 101, 105, 102, 45,  117, 110, 109, 111, 100,
-    105, 102, 105, 101, 100, 45,  115, 105, 110, 99,  101, 108, 97,  115, 116,
-    45,  109, 111, 100, 105, 102, 105, 101, 100, 108, 98,  45,  99,  111, 115,
-    116, 45,  98,  105, 110, 108, 105, 110, 107, 108, 111, 99,  97,  116, 105,
-    111, 110, 109, 97,  120, 45,  102, 111, 114, 119, 97,  114, 100, 115, 112,
-    114, 111, 120, 121, 45,  97,  117, 116, 104, 101, 110, 116, 105, 99,  97,
-    116, 101, 112, 114, 111, 120, 121, 45,  97,  117, 116, 104, 111, 114, 105,
-    122, 97,  116, 105, 111, 110, 114, 97,  110, 103, 101, 114, 101, 102, 101,
-    114, 101, 114, 114, 101, 102, 114, 101, 115, 104, 114, 101, 116, 114, 121,
-    45,  97,  102, 116, 101, 114, 115, 101, 114, 118, 101, 114, 115, 101, 116,
-    45,  99,  111, 111, 107, 105, 101, 115, 116, 114, 105, 99,  116, 45,  116,
-    114, 97,  110, 115, 112, 111, 114, 116, 45,  115, 101, 99,  117, 114, 105,
-    116, 121, 116, 114, 97,  110, 115, 102, 101, 114, 45,  101, 110, 99,  111,
-    100, 105, 110, 103, 118, 97,  114, 121, 118, 105, 97,  119, 119, 119, 45,
-    97,  117, 116, 104, 101, 110, 116, 105, 99,  97,  116, 101, 105, 100, 101,
-    110, 116, 105, 116, 121, 44,  100, 101, 102, 108, 97,  116, 101, 105, 100,
-    101, 110, 116, 105, 116, 121, 44,  103, 122, 105, 112, 100, 101, 102, 108,
-    97,  116, 101, 44,  103, 122, 105, 112, 105, 100, 101, 110, 116, 105, 116,
-    121, 44,  100, 101, 102, 108, 97,  116, 101, 44,  103, 122, 105, 112};
+    116, 111, 107, 101, 110, 103, 114, 112, 99,  45,  112, 114, 101, 118, 105,
+    111, 117, 115, 45,  114, 112, 99,  45,  97,  116, 116, 101, 109, 112, 116,
+    115, 103, 114, 112, 99,  45,  114, 101, 116, 114, 121, 45,  112, 117, 115,
+    104, 98,  97,  99,  107, 45,  109, 115, 103, 114, 112, 99,  45,  116, 105,
+    109, 101, 111, 117, 116, 49,  50,  51,  52,  103, 114, 112, 99,  46,  119,
+    97,  105, 116, 95,  102, 111, 114, 95,  114, 101, 97,  100, 121, 103, 114,
+    112, 99,  46,  116, 105, 109, 101, 111, 117, 116, 103, 114, 112, 99,  46,
+    109, 97,  120, 95,  114, 101, 113, 117, 101, 115, 116, 95,  109, 101, 115,
+    115, 97,  103, 101, 95,  98,  121, 116, 101, 115, 103, 114, 112, 99,  46,
+    109, 97,  120, 95,  114, 101, 115, 112, 111, 110, 115, 101, 95,  109, 101,
+    115, 115, 97,  103, 101, 95,  98,  121, 116, 101, 115, 47,  103, 114, 112,
+    99,  46,  108, 98,  46,  118, 49,  46,  76,  111, 97,  100, 66,  97,  108,
+    97,  110, 99,  101, 114, 47,  66,  97,  108, 97,  110, 99,  101, 76,  111,
+    97,  100, 100, 101, 102, 108, 97,  116, 101, 103, 122, 105, 112, 115, 116,
+    114, 101, 97,  109, 47,  103, 122, 105, 112, 48,  105, 100, 101, 110, 116,
+    105, 116, 121, 116, 114, 97,  105, 108, 101, 114, 115, 97,  112, 112, 108,
+    105, 99,  97,  116, 105, 111, 110, 47,  103, 114, 112, 99,  80,  79,  83,
+    84,  50,  48,  48,  52,  48,  52,  104, 116, 116, 112, 104, 116, 116, 112,
+    115, 103, 114, 112, 99,  71,  69,  84,  80,  85,  84,  47,  47,  105, 110,
+    100, 101, 120, 46,  104, 116, 109, 108, 50,  48,  52,  50,  48,  54,  51,
+    48,  52,  52,  48,  48,  53,  48,  48,  97,  99,  99,  101, 112, 116, 45,
+    99,  104, 97,  114, 115, 101, 116, 103, 122, 105, 112, 44,  32,  100, 101,
+    102, 108, 97,  116, 101, 97,  99,  99,  101, 112, 116, 45,  108, 97,  110,
+    103, 117, 97,  103, 101, 97,  99,  99,  101, 112, 116, 45,  114, 97,  110,
+    103, 101, 115, 97,  99,  99,  101, 112, 116, 97,  99,  99,  101, 115, 115,
+    45,  99,  111, 110, 116, 114, 111, 108, 45,  97,  108, 108, 111, 119, 45,
+    111, 114, 105, 103, 105, 110, 97,  103, 101, 97,  108, 108, 111, 119, 97,
+    117, 116, 104, 111, 114, 105, 122, 97,  116, 105, 111, 110, 99,  97,  99,
+    104, 101, 45,  99,  111, 110, 116, 114, 111, 108, 99,  111, 110, 116, 101,
+    110, 116, 45,  100, 105, 115, 112, 111, 115, 105, 116, 105, 111, 110, 99,
+    111, 110, 116, 101, 110, 116, 45,  108, 97,  110, 103, 117, 97,  103, 101,
+    99,  111, 110, 116, 101, 110, 116, 45,  108, 101, 110, 103, 116, 104, 99,
+    111, 110, 116, 101, 110, 116, 45,  108, 111, 99,  97,  116, 105, 111, 110,
+    99,  111, 110, 116, 101, 110, 116, 45,  114, 97,  110, 103, 101, 99,  111,
+    111, 107, 105, 101, 100, 97,  116, 101, 101, 116, 97,  103, 101, 120, 112,
+    101, 99,  116, 101, 120, 112, 105, 114, 101, 115, 102, 114, 111, 109, 105,
+    102, 45,  109, 97,  116, 99,  104, 105, 102, 45,  109, 111, 100, 105, 102,
+    105, 101, 100, 45,  115, 105, 110, 99,  101, 105, 102, 45,  110, 111, 110,
+    101, 45,  109, 97,  116, 99,  104, 105, 102, 45,  114, 97,  110, 103, 101,
+    105, 102, 45,  117, 110, 109, 111, 100, 105, 102, 105, 101, 100, 45,  115,
+    105, 110, 99,  101, 108, 97,  115, 116, 45,  109, 111, 100, 105, 102, 105,
+    101, 100, 108, 98,  45,  99,  111, 115, 116, 45,  98,  105, 110, 108, 105,
+    110, 107, 108, 111, 99,  97,  116, 105, 111, 110, 109, 97,  120, 45,  102,
+    111, 114, 119, 97,  114, 100, 115, 112, 114, 111, 120, 121, 45,  97,  117,
+    116, 104, 101, 110, 116, 105, 99,  97,  116, 101, 112, 114, 111, 120, 121,
+    45,  97,  117, 116, 104, 111, 114, 105, 122, 97,  116, 105, 111, 110, 114,
+    97,  110, 103, 101, 114, 101, 102, 101, 114, 101, 114, 114, 101, 102, 114,
+    101, 115, 104, 114, 101, 116, 114, 121, 45,  97,  102, 116, 101, 114, 115,
+    101, 114, 118, 101, 114, 115, 101, 116, 45,  99,  111, 111, 107, 105, 101,
+    115, 116, 114, 105, 99,  116, 45,  116, 114, 97,  110, 115, 112, 111, 114,
+    116, 45,  115, 101, 99,  117, 114, 105, 116, 121, 116, 114, 97,  110, 115,
+    102, 101, 114, 45,  101, 110, 99,  111, 100, 105, 110, 103, 118, 97,  114,
+    121, 118, 105, 97,  119, 119, 119, 45,  97,  117, 116, 104, 101, 110, 116,
+    105, 99,  97,  116, 101, 105, 100, 101, 110, 116, 105, 116, 121, 44,  100,
+    101, 102, 108, 97,  116, 101, 105, 100, 101, 110, 116, 105, 116, 121, 44,
+    103, 122, 105, 112, 100, 101, 102, 108, 97,  116, 101, 44,  103, 122, 105,
+    112, 105, 100, 101, 110, 116, 105, 116, 121, 44,  100, 101, 102, 108, 97,
+    116, 101, 44,  103, 122, 105, 112};
 
 static void static_ref(void* unused) {}
 static void static_unref(void* unused) {}
@@ -218,6 +222,8 @@
     {&grpc_static_metadata_vtable, &static_sub_refcnt},
     {&grpc_static_metadata_vtable, &static_sub_refcnt},
     {&grpc_static_metadata_vtable, &static_sub_refcnt},
+    {&grpc_static_metadata_vtable, &static_sub_refcnt},
+    {&grpc_static_metadata_vtable, &static_sub_refcnt},
 };
 
 const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT] = {
@@ -243,87 +249,89 @@
     {&grpc_static_metadata_refcounts[19], {{g_bytes + 268, 10}}},
     {&grpc_static_metadata_refcounts[20], {{g_bytes + 278, 4}}},
     {&grpc_static_metadata_refcounts[21], {{g_bytes + 282, 8}}},
-    {&grpc_static_metadata_refcounts[22], {{g_bytes + 290, 12}}},
-    {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}},
-    {&grpc_static_metadata_refcounts[24], {{g_bytes + 302, 19}}},
-    {&grpc_static_metadata_refcounts[25], {{g_bytes + 321, 12}}},
-    {&grpc_static_metadata_refcounts[26], {{g_bytes + 333, 30}}},
-    {&grpc_static_metadata_refcounts[27], {{g_bytes + 363, 31}}},
-    {&grpc_static_metadata_refcounts[28], {{g_bytes + 394, 36}}},
-    {&grpc_static_metadata_refcounts[29], {{g_bytes + 430, 15}}},
-    {&grpc_static_metadata_refcounts[30], {{g_bytes + 445, 12}}},
-    {&grpc_static_metadata_refcounts[31], {{g_bytes + 457, 11}}},
-    {&grpc_static_metadata_refcounts[32], {{g_bytes + 468, 1}}},
-    {&grpc_static_metadata_refcounts[33], {{g_bytes + 469, 1}}},
-    {&grpc_static_metadata_refcounts[34], {{g_bytes + 470, 1}}},
-    {&grpc_static_metadata_refcounts[35], {{g_bytes + 471, 8}}},
-    {&grpc_static_metadata_refcounts[36], {{g_bytes + 479, 4}}},
-    {&grpc_static_metadata_refcounts[37], {{g_bytes + 483, 7}}},
-    {&grpc_static_metadata_refcounts[38], {{g_bytes + 490, 8}}},
-    {&grpc_static_metadata_refcounts[39], {{g_bytes + 498, 16}}},
-    {&grpc_static_metadata_refcounts[40], {{g_bytes + 514, 4}}},
-    {&grpc_static_metadata_refcounts[41], {{g_bytes + 518, 3}}},
-    {&grpc_static_metadata_refcounts[42], {{g_bytes + 521, 3}}},
-    {&grpc_static_metadata_refcounts[43], {{g_bytes + 524, 4}}},
-    {&grpc_static_metadata_refcounts[44], {{g_bytes + 528, 5}}},
-    {&grpc_static_metadata_refcounts[45], {{g_bytes + 533, 4}}},
-    {&grpc_static_metadata_refcounts[46], {{g_bytes + 537, 3}}},
-    {&grpc_static_metadata_refcounts[47], {{g_bytes + 540, 3}}},
-    {&grpc_static_metadata_refcounts[48], {{g_bytes + 543, 1}}},
-    {&grpc_static_metadata_refcounts[49], {{g_bytes + 544, 11}}},
-    {&grpc_static_metadata_refcounts[50], {{g_bytes + 555, 3}}},
-    {&grpc_static_metadata_refcounts[51], {{g_bytes + 558, 3}}},
-    {&grpc_static_metadata_refcounts[52], {{g_bytes + 561, 3}}},
-    {&grpc_static_metadata_refcounts[53], {{g_bytes + 564, 3}}},
-    {&grpc_static_metadata_refcounts[54], {{g_bytes + 567, 3}}},
-    {&grpc_static_metadata_refcounts[55], {{g_bytes + 570, 14}}},
-    {&grpc_static_metadata_refcounts[56], {{g_bytes + 584, 13}}},
-    {&grpc_static_metadata_refcounts[57], {{g_bytes + 597, 15}}},
-    {&grpc_static_metadata_refcounts[58], {{g_bytes + 612, 13}}},
-    {&grpc_static_metadata_refcounts[59], {{g_bytes + 625, 6}}},
-    {&grpc_static_metadata_refcounts[60], {{g_bytes + 631, 27}}},
-    {&grpc_static_metadata_refcounts[61], {{g_bytes + 658, 3}}},
-    {&grpc_static_metadata_refcounts[62], {{g_bytes + 661, 5}}},
-    {&grpc_static_metadata_refcounts[63], {{g_bytes + 666, 13}}},
-    {&grpc_static_metadata_refcounts[64], {{g_bytes + 679, 13}}},
-    {&grpc_static_metadata_refcounts[65], {{g_bytes + 692, 19}}},
-    {&grpc_static_metadata_refcounts[66], {{g_bytes + 711, 16}}},
-    {&grpc_static_metadata_refcounts[67], {{g_bytes + 727, 14}}},
-    {&grpc_static_metadata_refcounts[68], {{g_bytes + 741, 16}}},
-    {&grpc_static_metadata_refcounts[69], {{g_bytes + 757, 13}}},
-    {&grpc_static_metadata_refcounts[70], {{g_bytes + 770, 6}}},
-    {&grpc_static_metadata_refcounts[71], {{g_bytes + 776, 4}}},
-    {&grpc_static_metadata_refcounts[72], {{g_bytes + 780, 4}}},
-    {&grpc_static_metadata_refcounts[73], {{g_bytes + 784, 6}}},
-    {&grpc_static_metadata_refcounts[74], {{g_bytes + 790, 7}}},
-    {&grpc_static_metadata_refcounts[75], {{g_bytes + 797, 4}}},
-    {&grpc_static_metadata_refcounts[76], {{g_bytes + 801, 8}}},
-    {&grpc_static_metadata_refcounts[77], {{g_bytes + 809, 17}}},
-    {&grpc_static_metadata_refcounts[78], {{g_bytes + 826, 13}}},
-    {&grpc_static_metadata_refcounts[79], {{g_bytes + 839, 8}}},
-    {&grpc_static_metadata_refcounts[80], {{g_bytes + 847, 19}}},
-    {&grpc_static_metadata_refcounts[81], {{g_bytes + 866, 13}}},
-    {&grpc_static_metadata_refcounts[82], {{g_bytes + 879, 11}}},
-    {&grpc_static_metadata_refcounts[83], {{g_bytes + 890, 4}}},
-    {&grpc_static_metadata_refcounts[84], {{g_bytes + 894, 8}}},
-    {&grpc_static_metadata_refcounts[85], {{g_bytes + 902, 12}}},
-    {&grpc_static_metadata_refcounts[86], {{g_bytes + 914, 18}}},
-    {&grpc_static_metadata_refcounts[87], {{g_bytes + 932, 19}}},
-    {&grpc_static_metadata_refcounts[88], {{g_bytes + 951, 5}}},
-    {&grpc_static_metadata_refcounts[89], {{g_bytes + 956, 7}}},
-    {&grpc_static_metadata_refcounts[90], {{g_bytes + 963, 7}}},
-    {&grpc_static_metadata_refcounts[91], {{g_bytes + 970, 11}}},
-    {&grpc_static_metadata_refcounts[92], {{g_bytes + 981, 6}}},
-    {&grpc_static_metadata_refcounts[93], {{g_bytes + 987, 10}}},
-    {&grpc_static_metadata_refcounts[94], {{g_bytes + 997, 25}}},
-    {&grpc_static_metadata_refcounts[95], {{g_bytes + 1022, 17}}},
-    {&grpc_static_metadata_refcounts[96], {{g_bytes + 1039, 4}}},
-    {&grpc_static_metadata_refcounts[97], {{g_bytes + 1043, 3}}},
-    {&grpc_static_metadata_refcounts[98], {{g_bytes + 1046, 16}}},
-    {&grpc_static_metadata_refcounts[99], {{g_bytes + 1062, 16}}},
-    {&grpc_static_metadata_refcounts[100], {{g_bytes + 1078, 13}}},
-    {&grpc_static_metadata_refcounts[101], {{g_bytes + 1091, 12}}},
-    {&grpc_static_metadata_refcounts[102], {{g_bytes + 1103, 21}}},
+    {&grpc_static_metadata_refcounts[22], {{g_bytes + 290, 26}}},
+    {&grpc_static_metadata_refcounts[23], {{g_bytes + 316, 22}}},
+    {&grpc_static_metadata_refcounts[24], {{g_bytes + 338, 12}}},
+    {&grpc_static_metadata_refcounts[25], {{g_bytes + 350, 1}}},
+    {&grpc_static_metadata_refcounts[26], {{g_bytes + 351, 1}}},
+    {&grpc_static_metadata_refcounts[27], {{g_bytes + 352, 1}}},
+    {&grpc_static_metadata_refcounts[28], {{g_bytes + 353, 1}}},
+    {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}},
+    {&grpc_static_metadata_refcounts[30], {{g_bytes + 354, 19}}},
+    {&grpc_static_metadata_refcounts[31], {{g_bytes + 373, 12}}},
+    {&grpc_static_metadata_refcounts[32], {{g_bytes + 385, 30}}},
+    {&grpc_static_metadata_refcounts[33], {{g_bytes + 415, 31}}},
+    {&grpc_static_metadata_refcounts[34], {{g_bytes + 446, 36}}},
+    {&grpc_static_metadata_refcounts[35], {{g_bytes + 482, 7}}},
+    {&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}},
+    {&grpc_static_metadata_refcounts[37], {{g_bytes + 493, 11}}},
+    {&grpc_static_metadata_refcounts[38], {{g_bytes + 504, 1}}},
+    {&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}},
+    {&grpc_static_metadata_refcounts[40], {{g_bytes + 513, 8}}},
+    {&grpc_static_metadata_refcounts[41], {{g_bytes + 521, 16}}},
+    {&grpc_static_metadata_refcounts[42], {{g_bytes + 537, 4}}},
+    {&grpc_static_metadata_refcounts[43], {{g_bytes + 541, 3}}},
+    {&grpc_static_metadata_refcounts[44], {{g_bytes + 544, 3}}},
+    {&grpc_static_metadata_refcounts[45], {{g_bytes + 547, 4}}},
+    {&grpc_static_metadata_refcounts[46], {{g_bytes + 551, 5}}},
+    {&grpc_static_metadata_refcounts[47], {{g_bytes + 556, 4}}},
+    {&grpc_static_metadata_refcounts[48], {{g_bytes + 560, 3}}},
+    {&grpc_static_metadata_refcounts[49], {{g_bytes + 563, 3}}},
+    {&grpc_static_metadata_refcounts[50], {{g_bytes + 566, 1}}},
+    {&grpc_static_metadata_refcounts[51], {{g_bytes + 567, 11}}},
+    {&grpc_static_metadata_refcounts[52], {{g_bytes + 578, 3}}},
+    {&grpc_static_metadata_refcounts[53], {{g_bytes + 581, 3}}},
+    {&grpc_static_metadata_refcounts[54], {{g_bytes + 584, 3}}},
+    {&grpc_static_metadata_refcounts[55], {{g_bytes + 587, 3}}},
+    {&grpc_static_metadata_refcounts[56], {{g_bytes + 590, 3}}},
+    {&grpc_static_metadata_refcounts[57], {{g_bytes + 593, 14}}},
+    {&grpc_static_metadata_refcounts[58], {{g_bytes + 607, 13}}},
+    {&grpc_static_metadata_refcounts[59], {{g_bytes + 620, 15}}},
+    {&grpc_static_metadata_refcounts[60], {{g_bytes + 635, 13}}},
+    {&grpc_static_metadata_refcounts[61], {{g_bytes + 648, 6}}},
+    {&grpc_static_metadata_refcounts[62], {{g_bytes + 654, 27}}},
+    {&grpc_static_metadata_refcounts[63], {{g_bytes + 681, 3}}},
+    {&grpc_static_metadata_refcounts[64], {{g_bytes + 684, 5}}},
+    {&grpc_static_metadata_refcounts[65], {{g_bytes + 689, 13}}},
+    {&grpc_static_metadata_refcounts[66], {{g_bytes + 702, 13}}},
+    {&grpc_static_metadata_refcounts[67], {{g_bytes + 715, 19}}},
+    {&grpc_static_metadata_refcounts[68], {{g_bytes + 734, 16}}},
+    {&grpc_static_metadata_refcounts[69], {{g_bytes + 750, 14}}},
+    {&grpc_static_metadata_refcounts[70], {{g_bytes + 764, 16}}},
+    {&grpc_static_metadata_refcounts[71], {{g_bytes + 780, 13}}},
+    {&grpc_static_metadata_refcounts[72], {{g_bytes + 793, 6}}},
+    {&grpc_static_metadata_refcounts[73], {{g_bytes + 799, 4}}},
+    {&grpc_static_metadata_refcounts[74], {{g_bytes + 803, 4}}},
+    {&grpc_static_metadata_refcounts[75], {{g_bytes + 807, 6}}},
+    {&grpc_static_metadata_refcounts[76], {{g_bytes + 813, 7}}},
+    {&grpc_static_metadata_refcounts[77], {{g_bytes + 820, 4}}},
+    {&grpc_static_metadata_refcounts[78], {{g_bytes + 824, 8}}},
+    {&grpc_static_metadata_refcounts[79], {{g_bytes + 832, 17}}},
+    {&grpc_static_metadata_refcounts[80], {{g_bytes + 849, 13}}},
+    {&grpc_static_metadata_refcounts[81], {{g_bytes + 862, 8}}},
+    {&grpc_static_metadata_refcounts[82], {{g_bytes + 870, 19}}},
+    {&grpc_static_metadata_refcounts[83], {{g_bytes + 889, 13}}},
+    {&grpc_static_metadata_refcounts[84], {{g_bytes + 902, 11}}},
+    {&grpc_static_metadata_refcounts[85], {{g_bytes + 913, 4}}},
+    {&grpc_static_metadata_refcounts[86], {{g_bytes + 917, 8}}},
+    {&grpc_static_metadata_refcounts[87], {{g_bytes + 925, 12}}},
+    {&grpc_static_metadata_refcounts[88], {{g_bytes + 937, 18}}},
+    {&grpc_static_metadata_refcounts[89], {{g_bytes + 955, 19}}},
+    {&grpc_static_metadata_refcounts[90], {{g_bytes + 974, 5}}},
+    {&grpc_static_metadata_refcounts[91], {{g_bytes + 979, 7}}},
+    {&grpc_static_metadata_refcounts[92], {{g_bytes + 986, 7}}},
+    {&grpc_static_metadata_refcounts[93], {{g_bytes + 993, 11}}},
+    {&grpc_static_metadata_refcounts[94], {{g_bytes + 1004, 6}}},
+    {&grpc_static_metadata_refcounts[95], {{g_bytes + 1010, 10}}},
+    {&grpc_static_metadata_refcounts[96], {{g_bytes + 1020, 25}}},
+    {&grpc_static_metadata_refcounts[97], {{g_bytes + 1045, 17}}},
+    {&grpc_static_metadata_refcounts[98], {{g_bytes + 1062, 4}}},
+    {&grpc_static_metadata_refcounts[99], {{g_bytes + 1066, 3}}},
+    {&grpc_static_metadata_refcounts[100], {{g_bytes + 1069, 16}}},
+    {&grpc_static_metadata_refcounts[101], {{g_bytes + 1085, 16}}},
+    {&grpc_static_metadata_refcounts[102], {{g_bytes + 1101, 13}}},
+    {&grpc_static_metadata_refcounts[103], {{g_bytes + 1114, 12}}},
+    {&grpc_static_metadata_refcounts[104], {{g_bytes + 1126, 21}}},
 };
 
 uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {
@@ -333,16 +341,16 @@
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 4, 6, 6, 8, 8, 2, 4, 4};
 
 static const int8_t elems_r[] = {
-    11, 9,  -3, 0,  10,  25, -77, 26,  0,   11,  -7,  0,   0,  0,  21, 14, 1,
-    0,  0,  33, 12, 11,  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,  -56, 0,  -36, -61, -60, -39, -63, -64, 0,  36, 35, 34, 33,
-    34, 33, 32, 31, 31,  30, 29,  28,  27,  26,  26,  25,  25, 24, 23, 22, 21,
-    20, 19, 22, 21, 20,  19, 18,  17,  16,  15,  14,  13,  12, 12, 11, 0};
+    16, 11, -1, 0,   15, 2,   -78, 24,  0,  18, -5, 0,  0,  0,  17, 14, -8, 0,
+    0,  27, 8,  7,   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,  -64, 0,  -44, -43, -70, 0,  34, 33, 33, 32, 31, 30, 29, 28, 27,
+    27, 26, 25, 24,  23, 22,  21,  20,  20, 19, 19, 18, 17, 16, 15, 14, 13, 12,
+    11, 14, 13, 12,  11, 10,  9,   9,   8,  7,  6,  5,  0};
 static uint32_t elems_phash(uint32_t i) {
-  i -= 48;
-  uint32_t x = i % 101;
-  uint32_t y = i / 101;
+  i -= 50;
+  uint32_t x = i % 103;
+  uint32_t y = i / 103;
   uint32_t h = x;
   if (y < GPR_ARRAY_SIZE(elems_r)) {
     uint32_t delta = (uint32_t)elems_r[y];
@@ -352,31 +360,32 @@
 }
 
 static const uint16_t elem_keys[] = {
-    1065, 1066, 1067, 256,  257,  258,  259,  260,  1671,  149,   150,  48,
-    49,   455,  456,  457,  962,  963,  964,  1568, 1683,  1684,  753,  754,
-    1465, 553,  755,  2083, 2186, 5688, 5997, 1580, 1581,  6100,  6306, 6409,
-    6512, 6615, 6718, 6821, 1481, 1704, 6924, 7027, 7130,  7233,  1980, 7336,
-    7439, 7542, 7645, 7748, 7851, 5894, 7954, 8057, 6203,  8160,  8263, 8366,
-    8469, 8572, 8675, 8778, 1129, 1130, 1131, 1132, 8881,  8984,  9087, 9190,
-    9293, 9396, 9499, 9602, 9705, 9808, 9911, 332,  10014, 10117, 0,    0,
-    0,    1748, 0,    0,    0,    0,    0,    0,    0,     0,     0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,     0,     143,  247,
-    248,  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};
+    1085,  1086,  565,   1709,  1089,  262,  263,  264,  265,  266,   1716,
+    153,   154,   1719,  760,   761,   50,   51,   465,  466,  467,   980,
+    981,   1604,  1499,  984,   773,   2129, 2234, 6014, 1611, 6434,  1738,
+    1614,  6539,  6644,  1511,  6749,  6854, 6959, 7064, 7169, 7274,  7379,
+    2024,  7484,  7589,  7694,  7799,  7904, 8009, 8114, 8219, 6224,  8324,
+    8429,  6329,  8534,  8639,  8744,  8849, 8954, 9059, 9164, 9269,  9374,
+    1151,  1152,  1153,  1154,  9479,  9584, 9689, 9794, 9899, 10004, 1782,
+    10109, 10214, 10319, 10424, 10529, 0,    0,    0,    0,    0,     344,
+    0,     0,     0,     0,     0,     0,    0,    0,    0,    0,     0,
+    0,     0,     0,     0,     0,     0,    0,    0,    0,    0,     0,
+    0,     253,   254,   147,   0,     0,    0,    0,    0,    0,     0,
+    0,     0,     0,     0,     0,     0,    0,    0,    0,    0,     0,
+    0,     0,     0,     0};
 static const uint8_t elem_idxs[] = {
-    76,  79,  77,  19,  20,  21,  22,  23,  25,  15,  16,  17,  18,  11,
-    12,  13,  3,   4,   5,   38,  83,  84,  0,   1,   43,  6,   2,   50,
-    57,  24,  28,  36,  37,  29,  31,  32,  33,  34,  35,  39,  7,   26,
-    40,  41,  42,  44,  72,  45,  46,  47,  48,  49,  51,  27,  52,  53,
-    30,  54,  55,  56,  58,  59,  60,  61,  78,  80,  81,  82,  62,  63,
-    64,  65,  66,  67,  68,  69,  70,  71,  73,  14,  74,  75,  255, 255,
-    255, 85,  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-    255, 255, 255, 255, 255, 255, 255, 255, 8,   9,   10};
+    77,  79,  6,   25,  76,  19,  20,  21,  22,  23,  84,  15,  16,  83,  1,
+    2,   17,  18,  11,  12,  13,  5,   4,   38,  43,  3,   0,   50,  57,  24,
+    37,  29,  26,  36,  30,  31,  7,   32,  33,  34,  35,  39,  40,  41,  72,
+    42,  44,  45,  46,  47,  48,  49,  51,  27,  52,  53,  28,  54,  55,  56,
+    58,  59,  60,  61,  62,  63,  78,  80,  81,  82,  64,  65,  66,  67,  68,
+    69,  85,  70,  71,  73,  74,  75,  255, 255, 255, 255, 255, 14,  255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 9,   10,  8};
 
 grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) {
   if (a == -1 || b == -1) return GRPC_MDNULL;
-  uint32_t k = (uint32_t)(a * 103 + b);
+  uint32_t k = (uint32_t)(a * 105 + b);
   uint32_t h = elems_phash(k);
   return h < GPR_ARRAY_SIZE(elem_keys) && elem_keys[h] == k &&
                  elem_idxs[h] != 255
@@ -387,177 +396,177 @@
 
 grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {
     {{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
-     {&grpc_static_metadata_refcounts[32], {{g_bytes + 468, 1}}}},
+     {&grpc_static_metadata_refcounts[38], {{g_bytes + 504, 1}}}},
     {{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
-     {&grpc_static_metadata_refcounts[33], {{g_bytes + 469, 1}}}},
+     {&grpc_static_metadata_refcounts[25], {{g_bytes + 350, 1}}}},
     {{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
-     {&grpc_static_metadata_refcounts[34], {{g_bytes + 470, 1}}}},
+     {&grpc_static_metadata_refcounts[26], {{g_bytes + 351, 1}}}},
     {{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
-     {&grpc_static_metadata_refcounts[35], {{g_bytes + 471, 8}}}},
+     {&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}}},
     {{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
-     {&grpc_static_metadata_refcounts[36], {{g_bytes + 479, 4}}}},
+     {&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}},
     {{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
-     {&grpc_static_metadata_refcounts[37], {{g_bytes + 483, 7}}}},
+     {&grpc_static_metadata_refcounts[35], {{g_bytes + 482, 7}}}},
     {{&grpc_static_metadata_refcounts[5], {{g_bytes + 36, 2}}},
-     {&grpc_static_metadata_refcounts[38], {{g_bytes + 490, 8}}}},
+     {&grpc_static_metadata_refcounts[40], {{g_bytes + 513, 8}}}},
     {{&grpc_static_metadata_refcounts[14], {{g_bytes + 158, 12}}},
-     {&grpc_static_metadata_refcounts[39], {{g_bytes + 498, 16}}}},
+     {&grpc_static_metadata_refcounts[41], {{g_bytes + 521, 16}}}},
     {{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}},
-     {&grpc_static_metadata_refcounts[40], {{g_bytes + 514, 4}}}},
+     {&grpc_static_metadata_refcounts[42], {{g_bytes + 537, 4}}}},
     {{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
-     {&grpc_static_metadata_refcounts[41], {{g_bytes + 518, 3}}}},
+     {&grpc_static_metadata_refcounts[43], {{g_bytes + 541, 3}}}},
     {{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
-     {&grpc_static_metadata_refcounts[42], {{g_bytes + 521, 3}}}},
+     {&grpc_static_metadata_refcounts[44], {{g_bytes + 544, 3}}}},
     {{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
-     {&grpc_static_metadata_refcounts[43], {{g_bytes + 524, 4}}}},
+     {&grpc_static_metadata_refcounts[45], {{g_bytes + 547, 4}}}},
     {{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
-     {&grpc_static_metadata_refcounts[44], {{g_bytes + 528, 5}}}},
+     {&grpc_static_metadata_refcounts[46], {{g_bytes + 551, 5}}}},
     {{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
-     {&grpc_static_metadata_refcounts[45], {{g_bytes + 533, 4}}}},
+     {&grpc_static_metadata_refcounts[47], {{g_bytes + 556, 4}}}},
     {{&grpc_static_metadata_refcounts[3], {{g_bytes + 19, 10}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
     {{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}},
-     {&grpc_static_metadata_refcounts[46], {{g_bytes + 537, 3}}}},
+     {&grpc_static_metadata_refcounts[48], {{g_bytes + 560, 3}}}},
     {{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}},
-     {&grpc_static_metadata_refcounts[47], {{g_bytes + 540, 3}}}},
+     {&grpc_static_metadata_refcounts[49], {{g_bytes + 563, 3}}}},
     {{&grpc_static_metadata_refcounts[0], {{g_bytes + 0, 5}}},
-     {&grpc_static_metadata_refcounts[48], {{g_bytes + 543, 1}}}},
+     {&grpc_static_metadata_refcounts[50], {{g_bytes + 566, 1}}}},
     {{&grpc_static_metadata_refcounts[0], {{g_bytes + 0, 5}}},
-     {&grpc_static_metadata_refcounts[49], {{g_bytes + 544, 11}}}},
+     {&grpc_static_metadata_refcounts[51], {{g_bytes + 567, 11}}}},
     {{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
-     {&grpc_static_metadata_refcounts[50], {{g_bytes + 555, 3}}}},
+     {&grpc_static_metadata_refcounts[52], {{g_bytes + 578, 3}}}},
     {{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
-     {&grpc_static_metadata_refcounts[51], {{g_bytes + 558, 3}}}},
+     {&grpc_static_metadata_refcounts[53], {{g_bytes + 581, 3}}}},
     {{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
-     {&grpc_static_metadata_refcounts[52], {{g_bytes + 561, 3}}}},
+     {&grpc_static_metadata_refcounts[54], {{g_bytes + 584, 3}}}},
     {{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
-     {&grpc_static_metadata_refcounts[53], {{g_bytes + 564, 3}}}},
+     {&grpc_static_metadata_refcounts[55], {{g_bytes + 587, 3}}}},
     {{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
-     {&grpc_static_metadata_refcounts[54], {{g_bytes + 567, 3}}}},
-    {{&grpc_static_metadata_refcounts[55], {{g_bytes + 570, 14}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
+     {&grpc_static_metadata_refcounts[56], {{g_bytes + 590, 3}}}},
+    {{&grpc_static_metadata_refcounts[57], {{g_bytes + 593, 14}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
     {{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
     {{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
-     {&grpc_static_metadata_refcounts[56], {{g_bytes + 584, 13}}}},
-    {{&grpc_static_metadata_refcounts[57], {{g_bytes + 597, 15}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[58], {{g_bytes + 612, 13}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[59], {{g_bytes + 625, 6}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[60], {{g_bytes + 631, 27}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[61], {{g_bytes + 658, 3}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[62], {{g_bytes + 661, 5}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[63], {{g_bytes + 666, 13}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[64], {{g_bytes + 679, 13}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[65], {{g_bytes + 692, 19}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
+     {&grpc_static_metadata_refcounts[58], {{g_bytes + 607, 13}}}},
+    {{&grpc_static_metadata_refcounts[59], {{g_bytes + 620, 15}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[60], {{g_bytes + 635, 13}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[61], {{g_bytes + 648, 6}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[62], {{g_bytes + 654, 27}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[63], {{g_bytes + 681, 3}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[64], {{g_bytes + 684, 5}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[65], {{g_bytes + 689, 13}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[66], {{g_bytes + 702, 13}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[67], {{g_bytes + 715, 19}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
     {{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}},
-     {&grpc_static_metadata_refcounts[35], {{g_bytes + 471, 8}}}},
+     {&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}}},
     {{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}},
-     {&grpc_static_metadata_refcounts[36], {{g_bytes + 479, 4}}}},
+     {&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}},
     {{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[66], {{g_bytes + 711, 16}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[67], {{g_bytes + 727, 14}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[68], {{g_bytes + 741, 16}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[69], {{g_bytes + 757, 13}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[68], {{g_bytes + 734, 16}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[69], {{g_bytes + 750, 14}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[70], {{g_bytes + 764, 16}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[71], {{g_bytes + 780, 13}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
     {{&grpc_static_metadata_refcounts[14], {{g_bytes + 158, 12}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[70], {{g_bytes + 770, 6}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[71], {{g_bytes + 776, 4}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[72], {{g_bytes + 780, 4}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[73], {{g_bytes + 784, 6}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[74], {{g_bytes + 790, 7}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[75], {{g_bytes + 797, 4}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[72], {{g_bytes + 793, 6}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[73], {{g_bytes + 799, 4}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[74], {{g_bytes + 803, 4}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[75], {{g_bytes + 807, 6}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[76], {{g_bytes + 813, 7}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[77], {{g_bytes + 820, 4}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
     {{&grpc_static_metadata_refcounts[20], {{g_bytes + 278, 4}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[76], {{g_bytes + 801, 8}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[77], {{g_bytes + 809, 17}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[78], {{g_bytes + 826, 13}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[79], {{g_bytes + 839, 8}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[80], {{g_bytes + 847, 19}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[81], {{g_bytes + 866, 13}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[78], {{g_bytes + 824, 8}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[79], {{g_bytes + 832, 17}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[80], {{g_bytes + 849, 13}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[81], {{g_bytes + 862, 8}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[82], {{g_bytes + 870, 19}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[83], {{g_bytes + 889, 13}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
     {{&grpc_static_metadata_refcounts[21], {{g_bytes + 282, 8}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[82], {{g_bytes + 879, 11}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[83], {{g_bytes + 890, 4}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[84], {{g_bytes + 894, 8}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[85], {{g_bytes + 902, 12}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[86], {{g_bytes + 914, 18}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[87], {{g_bytes + 932, 19}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[88], {{g_bytes + 951, 5}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[89], {{g_bytes + 956, 7}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[90], {{g_bytes + 963, 7}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[91], {{g_bytes + 970, 11}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[92], {{g_bytes + 981, 6}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[93], {{g_bytes + 987, 10}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[94], {{g_bytes + 997, 25}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[95], {{g_bytes + 1022, 17}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[84], {{g_bytes + 902, 11}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[85], {{g_bytes + 913, 4}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[86], {{g_bytes + 917, 8}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[87], {{g_bytes + 925, 12}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[88], {{g_bytes + 937, 18}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[89], {{g_bytes + 955, 19}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[90], {{g_bytes + 974, 5}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[91], {{g_bytes + 979, 7}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[92], {{g_bytes + 986, 7}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[93], {{g_bytes + 993, 11}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[94], {{g_bytes + 1004, 6}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[95], {{g_bytes + 1010, 10}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[96], {{g_bytes + 1020, 25}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[97], {{g_bytes + 1045, 17}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
     {{&grpc_static_metadata_refcounts[19], {{g_bytes + 268, 10}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[96], {{g_bytes + 1039, 4}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[97], {{g_bytes + 1043, 3}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
-    {{&grpc_static_metadata_refcounts[98], {{g_bytes + 1046, 16}}},
-     {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[98], {{g_bytes + 1062, 4}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[99], {{g_bytes + 1066, 3}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+    {{&grpc_static_metadata_refcounts[100], {{g_bytes + 1069, 16}}},
+     {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
     {{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
-     {&grpc_static_metadata_refcounts[35], {{g_bytes + 471, 8}}}},
+     {&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}}},
     {{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
-     {&grpc_static_metadata_refcounts[37], {{g_bytes + 483, 7}}}},
+     {&grpc_static_metadata_refcounts[35], {{g_bytes + 482, 7}}}},
     {{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
-     {&grpc_static_metadata_refcounts[99], {{g_bytes + 1062, 16}}}},
+     {&grpc_static_metadata_refcounts[101], {{g_bytes + 1085, 16}}}},
     {{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
-     {&grpc_static_metadata_refcounts[36], {{g_bytes + 479, 4}}}},
+     {&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}},
     {{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
-     {&grpc_static_metadata_refcounts[100], {{g_bytes + 1078, 13}}}},
+     {&grpc_static_metadata_refcounts[102], {{g_bytes + 1101, 13}}}},
     {{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
-     {&grpc_static_metadata_refcounts[101], {{g_bytes + 1091, 12}}}},
+     {&grpc_static_metadata_refcounts[103], {{g_bytes + 1114, 12}}}},
     {{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
-     {&grpc_static_metadata_refcounts[102], {{g_bytes + 1103, 21}}}},
+     {&grpc_static_metadata_refcounts[104], {{g_bytes + 1126, 21}}}},
     {{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
-     {&grpc_static_metadata_refcounts[35], {{g_bytes + 471, 8}}}},
+     {&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}}},
     {{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
-     {&grpc_static_metadata_refcounts[36], {{g_bytes + 479, 4}}}},
+     {&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}},
     {{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
-     {&grpc_static_metadata_refcounts[100], {{g_bytes + 1078, 13}}}},
+     {&grpc_static_metadata_refcounts[102], {{g_bytes + 1101, 13}}}},
 };
 bool grpc_static_callout_is_default[GRPC_BATCH_CALLOUTS_COUNT] = {
     true,  // :path
@@ -582,6 +591,8 @@
     true,  // user-agent
     true,  // host
     true,  // lb-token
+    true,  // grpc-previous-rpc-attempts
+    true,  // grpc-retry-pushback-ms
 };
 
 const uint8_t grpc_static_accept_encoding_metadata[8] = {0,  76, 77, 78,
diff --git a/src/core/lib/transport/static_metadata.h b/src/core/lib/transport/static_metadata.h
index 21dc7a3..b3a10f5 100644
--- a/src/core/lib/transport/static_metadata.h
+++ b/src/core/lib/transport/static_metadata.h
@@ -20,16 +20,18 @@
  * To make changes to this file, change
  * tools/codegen/core/gen_static_metadata.py, and then re-run it.
  *
- * See metadata.h for an explanation of the interface here, and metadata.c for
+ * See metadata.h for an explanation of the interface here, and metadata.cc for
  * an explanation of what's going on.
  */
 
 #ifndef GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H
 #define GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/transport/metadata.h"
 
-#define GRPC_STATIC_MDSTR_COUNT 103
+#define GRPC_STATIC_MDSTR_COUNT 105
 extern const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT];
 /* ":path" */
 #define GRPC_MDSTR_PATH (grpc_static_slice_table[0])
@@ -76,172 +78,176 @@
 #define GRPC_MDSTR_HOST (grpc_static_slice_table[20])
 /* "lb-token" */
 #define GRPC_MDSTR_LB_TOKEN (grpc_static_slice_table[21])
+/* "grpc-previous-rpc-attempts" */
+#define GRPC_MDSTR_GRPC_PREVIOUS_RPC_ATTEMPTS (grpc_static_slice_table[22])
+/* "grpc-retry-pushback-ms" */
+#define GRPC_MDSTR_GRPC_RETRY_PUSHBACK_MS (grpc_static_slice_table[23])
 /* "grpc-timeout" */
-#define GRPC_MDSTR_GRPC_TIMEOUT (grpc_static_slice_table[22])
+#define GRPC_MDSTR_GRPC_TIMEOUT (grpc_static_slice_table[24])
+/* "1" */
+#define GRPC_MDSTR_1 (grpc_static_slice_table[25])
+/* "2" */
+#define GRPC_MDSTR_2 (grpc_static_slice_table[26])
+/* "3" */
+#define GRPC_MDSTR_3 (grpc_static_slice_table[27])
+/* "4" */
+#define GRPC_MDSTR_4 (grpc_static_slice_table[28])
 /* "" */
-#define GRPC_MDSTR_EMPTY (grpc_static_slice_table[23])
+#define GRPC_MDSTR_EMPTY (grpc_static_slice_table[29])
 /* "grpc.wait_for_ready" */
-#define GRPC_MDSTR_GRPC_DOT_WAIT_FOR_READY (grpc_static_slice_table[24])
+#define GRPC_MDSTR_GRPC_DOT_WAIT_FOR_READY (grpc_static_slice_table[30])
 /* "grpc.timeout" */
-#define GRPC_MDSTR_GRPC_DOT_TIMEOUT (grpc_static_slice_table[25])
+#define GRPC_MDSTR_GRPC_DOT_TIMEOUT (grpc_static_slice_table[31])
 /* "grpc.max_request_message_bytes" */
 #define GRPC_MDSTR_GRPC_DOT_MAX_REQUEST_MESSAGE_BYTES \
-  (grpc_static_slice_table[26])
+  (grpc_static_slice_table[32])
 /* "grpc.max_response_message_bytes" */
 #define GRPC_MDSTR_GRPC_DOT_MAX_RESPONSE_MESSAGE_BYTES \
-  (grpc_static_slice_table[27])
+  (grpc_static_slice_table[33])
 /* "/grpc.lb.v1.LoadBalancer/BalanceLoad" */
 #define GRPC_MDSTR_SLASH_GRPC_DOT_LB_DOT_V1_DOT_LOADBALANCER_SLASH_BALANCELOAD \
-  (grpc_static_slice_table[28])
-/* "message/deflate" */
-#define GRPC_MDSTR_MESSAGE_SLASH_DEFLATE (grpc_static_slice_table[29])
-/* "message/gzip" */
-#define GRPC_MDSTR_MESSAGE_SLASH_GZIP (grpc_static_slice_table[30])
-/* "stream/gzip" */
-#define GRPC_MDSTR_STREAM_SLASH_GZIP (grpc_static_slice_table[31])
-/* "0" */
-#define GRPC_MDSTR_0 (grpc_static_slice_table[32])
-/* "1" */
-#define GRPC_MDSTR_1 (grpc_static_slice_table[33])
-/* "2" */
-#define GRPC_MDSTR_2 (grpc_static_slice_table[34])
-/* "identity" */
-#define GRPC_MDSTR_IDENTITY (grpc_static_slice_table[35])
+  (grpc_static_slice_table[34])
+/* "deflate" */
+#define GRPC_MDSTR_DEFLATE (grpc_static_slice_table[35])
 /* "gzip" */
 #define GRPC_MDSTR_GZIP (grpc_static_slice_table[36])
-/* "deflate" */
-#define GRPC_MDSTR_DEFLATE (grpc_static_slice_table[37])
+/* "stream/gzip" */
+#define GRPC_MDSTR_STREAM_SLASH_GZIP (grpc_static_slice_table[37])
+/* "0" */
+#define GRPC_MDSTR_0 (grpc_static_slice_table[38])
+/* "identity" */
+#define GRPC_MDSTR_IDENTITY (grpc_static_slice_table[39])
 /* "trailers" */
-#define GRPC_MDSTR_TRAILERS (grpc_static_slice_table[38])
+#define GRPC_MDSTR_TRAILERS (grpc_static_slice_table[40])
 /* "application/grpc" */
-#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (grpc_static_slice_table[39])
+#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (grpc_static_slice_table[41])
 /* "POST" */
-#define GRPC_MDSTR_POST (grpc_static_slice_table[40])
+#define GRPC_MDSTR_POST (grpc_static_slice_table[42])
 /* "200" */
-#define GRPC_MDSTR_200 (grpc_static_slice_table[41])
+#define GRPC_MDSTR_200 (grpc_static_slice_table[43])
 /* "404" */
-#define GRPC_MDSTR_404 (grpc_static_slice_table[42])
+#define GRPC_MDSTR_404 (grpc_static_slice_table[44])
 /* "http" */
-#define GRPC_MDSTR_HTTP (grpc_static_slice_table[43])
+#define GRPC_MDSTR_HTTP (grpc_static_slice_table[45])
 /* "https" */
-#define GRPC_MDSTR_HTTPS (grpc_static_slice_table[44])
+#define GRPC_MDSTR_HTTPS (grpc_static_slice_table[46])
 /* "grpc" */
-#define GRPC_MDSTR_GRPC (grpc_static_slice_table[45])
+#define GRPC_MDSTR_GRPC (grpc_static_slice_table[47])
 /* "GET" */
-#define GRPC_MDSTR_GET (grpc_static_slice_table[46])
+#define GRPC_MDSTR_GET (grpc_static_slice_table[48])
 /* "PUT" */
-#define GRPC_MDSTR_PUT (grpc_static_slice_table[47])
+#define GRPC_MDSTR_PUT (grpc_static_slice_table[49])
 /* "/" */
-#define GRPC_MDSTR_SLASH (grpc_static_slice_table[48])
+#define GRPC_MDSTR_SLASH (grpc_static_slice_table[50])
 /* "/index.html" */
-#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (grpc_static_slice_table[49])
+#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (grpc_static_slice_table[51])
 /* "204" */
-#define GRPC_MDSTR_204 (grpc_static_slice_table[50])
+#define GRPC_MDSTR_204 (grpc_static_slice_table[52])
 /* "206" */
-#define GRPC_MDSTR_206 (grpc_static_slice_table[51])
+#define GRPC_MDSTR_206 (grpc_static_slice_table[53])
 /* "304" */
-#define GRPC_MDSTR_304 (grpc_static_slice_table[52])
+#define GRPC_MDSTR_304 (grpc_static_slice_table[54])
 /* "400" */
-#define GRPC_MDSTR_400 (grpc_static_slice_table[53])
+#define GRPC_MDSTR_400 (grpc_static_slice_table[55])
 /* "500" */
-#define GRPC_MDSTR_500 (grpc_static_slice_table[54])
+#define GRPC_MDSTR_500 (grpc_static_slice_table[56])
 /* "accept-charset" */
-#define GRPC_MDSTR_ACCEPT_CHARSET (grpc_static_slice_table[55])
+#define GRPC_MDSTR_ACCEPT_CHARSET (grpc_static_slice_table[57])
 /* "gzip, deflate" */
-#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (grpc_static_slice_table[56])
+#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (grpc_static_slice_table[58])
 /* "accept-language" */
-#define GRPC_MDSTR_ACCEPT_LANGUAGE (grpc_static_slice_table[57])
+#define GRPC_MDSTR_ACCEPT_LANGUAGE (grpc_static_slice_table[59])
 /* "accept-ranges" */
-#define GRPC_MDSTR_ACCEPT_RANGES (grpc_static_slice_table[58])
+#define GRPC_MDSTR_ACCEPT_RANGES (grpc_static_slice_table[60])
 /* "accept" */
-#define GRPC_MDSTR_ACCEPT (grpc_static_slice_table[59])
+#define GRPC_MDSTR_ACCEPT (grpc_static_slice_table[61])
 /* "access-control-allow-origin" */
-#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (grpc_static_slice_table[60])
+#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (grpc_static_slice_table[62])
 /* "age" */
-#define GRPC_MDSTR_AGE (grpc_static_slice_table[61])
+#define GRPC_MDSTR_AGE (grpc_static_slice_table[63])
 /* "allow" */
-#define GRPC_MDSTR_ALLOW (grpc_static_slice_table[62])
+#define GRPC_MDSTR_ALLOW (grpc_static_slice_table[64])
 /* "authorization" */
-#define GRPC_MDSTR_AUTHORIZATION (grpc_static_slice_table[63])
+#define GRPC_MDSTR_AUTHORIZATION (grpc_static_slice_table[65])
 /* "cache-control" */
-#define GRPC_MDSTR_CACHE_CONTROL (grpc_static_slice_table[64])
+#define GRPC_MDSTR_CACHE_CONTROL (grpc_static_slice_table[66])
 /* "content-disposition" */
-#define GRPC_MDSTR_CONTENT_DISPOSITION (grpc_static_slice_table[65])
+#define GRPC_MDSTR_CONTENT_DISPOSITION (grpc_static_slice_table[67])
 /* "content-language" */
-#define GRPC_MDSTR_CONTENT_LANGUAGE (grpc_static_slice_table[66])
+#define GRPC_MDSTR_CONTENT_LANGUAGE (grpc_static_slice_table[68])
 /* "content-length" */
-#define GRPC_MDSTR_CONTENT_LENGTH (grpc_static_slice_table[67])
+#define GRPC_MDSTR_CONTENT_LENGTH (grpc_static_slice_table[69])
 /* "content-location" */
-#define GRPC_MDSTR_CONTENT_LOCATION (grpc_static_slice_table[68])
+#define GRPC_MDSTR_CONTENT_LOCATION (grpc_static_slice_table[70])
 /* "content-range" */
-#define GRPC_MDSTR_CONTENT_RANGE (grpc_static_slice_table[69])
+#define GRPC_MDSTR_CONTENT_RANGE (grpc_static_slice_table[71])
 /* "cookie" */
-#define GRPC_MDSTR_COOKIE (grpc_static_slice_table[70])
+#define GRPC_MDSTR_COOKIE (grpc_static_slice_table[72])
 /* "date" */
-#define GRPC_MDSTR_DATE (grpc_static_slice_table[71])
+#define GRPC_MDSTR_DATE (grpc_static_slice_table[73])
 /* "etag" */
-#define GRPC_MDSTR_ETAG (grpc_static_slice_table[72])
+#define GRPC_MDSTR_ETAG (grpc_static_slice_table[74])
 /* "expect" */
-#define GRPC_MDSTR_EXPECT (grpc_static_slice_table[73])
+#define GRPC_MDSTR_EXPECT (grpc_static_slice_table[75])
 /* "expires" */
-#define GRPC_MDSTR_EXPIRES (grpc_static_slice_table[74])
+#define GRPC_MDSTR_EXPIRES (grpc_static_slice_table[76])
 /* "from" */
-#define GRPC_MDSTR_FROM (grpc_static_slice_table[75])
+#define GRPC_MDSTR_FROM (grpc_static_slice_table[77])
 /* "if-match" */
-#define GRPC_MDSTR_IF_MATCH (grpc_static_slice_table[76])
+#define GRPC_MDSTR_IF_MATCH (grpc_static_slice_table[78])
 /* "if-modified-since" */
-#define GRPC_MDSTR_IF_MODIFIED_SINCE (grpc_static_slice_table[77])
+#define GRPC_MDSTR_IF_MODIFIED_SINCE (grpc_static_slice_table[79])
 /* "if-none-match" */
-#define GRPC_MDSTR_IF_NONE_MATCH (grpc_static_slice_table[78])
+#define GRPC_MDSTR_IF_NONE_MATCH (grpc_static_slice_table[80])
 /* "if-range" */
-#define GRPC_MDSTR_IF_RANGE (grpc_static_slice_table[79])
+#define GRPC_MDSTR_IF_RANGE (grpc_static_slice_table[81])
 /* "if-unmodified-since" */
-#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (grpc_static_slice_table[80])
+#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (grpc_static_slice_table[82])
 /* "last-modified" */
-#define GRPC_MDSTR_LAST_MODIFIED (grpc_static_slice_table[81])
+#define GRPC_MDSTR_LAST_MODIFIED (grpc_static_slice_table[83])
 /* "lb-cost-bin" */
-#define GRPC_MDSTR_LB_COST_BIN (grpc_static_slice_table[82])
+#define GRPC_MDSTR_LB_COST_BIN (grpc_static_slice_table[84])
 /* "link" */
-#define GRPC_MDSTR_LINK (grpc_static_slice_table[83])
+#define GRPC_MDSTR_LINK (grpc_static_slice_table[85])
 /* "location" */
-#define GRPC_MDSTR_LOCATION (grpc_static_slice_table[84])
+#define GRPC_MDSTR_LOCATION (grpc_static_slice_table[86])
 /* "max-forwards" */
-#define GRPC_MDSTR_MAX_FORWARDS (grpc_static_slice_table[85])
+#define GRPC_MDSTR_MAX_FORWARDS (grpc_static_slice_table[87])
 /* "proxy-authenticate" */
-#define GRPC_MDSTR_PROXY_AUTHENTICATE (grpc_static_slice_table[86])
+#define GRPC_MDSTR_PROXY_AUTHENTICATE (grpc_static_slice_table[88])
 /* "proxy-authorization" */
-#define GRPC_MDSTR_PROXY_AUTHORIZATION (grpc_static_slice_table[87])
+#define GRPC_MDSTR_PROXY_AUTHORIZATION (grpc_static_slice_table[89])
 /* "range" */
-#define GRPC_MDSTR_RANGE (grpc_static_slice_table[88])
+#define GRPC_MDSTR_RANGE (grpc_static_slice_table[90])
 /* "referer" */
-#define GRPC_MDSTR_REFERER (grpc_static_slice_table[89])
+#define GRPC_MDSTR_REFERER (grpc_static_slice_table[91])
 /* "refresh" */
-#define GRPC_MDSTR_REFRESH (grpc_static_slice_table[90])
+#define GRPC_MDSTR_REFRESH (grpc_static_slice_table[92])
 /* "retry-after" */
-#define GRPC_MDSTR_RETRY_AFTER (grpc_static_slice_table[91])
+#define GRPC_MDSTR_RETRY_AFTER (grpc_static_slice_table[93])
 /* "server" */
-#define GRPC_MDSTR_SERVER (grpc_static_slice_table[92])
+#define GRPC_MDSTR_SERVER (grpc_static_slice_table[94])
 /* "set-cookie" */
-#define GRPC_MDSTR_SET_COOKIE (grpc_static_slice_table[93])
+#define GRPC_MDSTR_SET_COOKIE (grpc_static_slice_table[95])
 /* "strict-transport-security" */
-#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (grpc_static_slice_table[94])
+#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (grpc_static_slice_table[96])
 /* "transfer-encoding" */
-#define GRPC_MDSTR_TRANSFER_ENCODING (grpc_static_slice_table[95])
+#define GRPC_MDSTR_TRANSFER_ENCODING (grpc_static_slice_table[97])
 /* "vary" */
-#define GRPC_MDSTR_VARY (grpc_static_slice_table[96])
+#define GRPC_MDSTR_VARY (grpc_static_slice_table[98])
 /* "via" */
-#define GRPC_MDSTR_VIA (grpc_static_slice_table[97])
+#define GRPC_MDSTR_VIA (grpc_static_slice_table[99])
 /* "www-authenticate" */
-#define GRPC_MDSTR_WWW_AUTHENTICATE (grpc_static_slice_table[98])
+#define GRPC_MDSTR_WWW_AUTHENTICATE (grpc_static_slice_table[100])
 /* "identity,deflate" */
-#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (grpc_static_slice_table[99])
+#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (grpc_static_slice_table[101])
 /* "identity,gzip" */
-#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (grpc_static_slice_table[100])
+#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (grpc_static_slice_table[102])
 /* "deflate,gzip" */
-#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (grpc_static_slice_table[101])
+#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (grpc_static_slice_table[103])
 /* "identity,deflate,gzip" */
 #define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
-  (grpc_static_slice_table[102])
+  (grpc_static_slice_table[104])
 
 extern const grpc_slice_refcount_vtable grpc_static_metadata_vtable;
 extern grpc_slice_refcount
@@ -539,6 +545,8 @@
   GRPC_BATCH_USER_AGENT,
   GRPC_BATCH_HOST,
   GRPC_BATCH_LB_TOKEN,
+  GRPC_BATCH_GRPC_PREVIOUS_RPC_ATTEMPTS,
+  GRPC_BATCH_GRPC_RETRY_PUSHBACK_MS,
   GRPC_BATCH_CALLOUTS_COUNT
 } grpc_metadata_batch_callouts_index;
 
@@ -567,6 +575,8 @@
     struct grpc_linked_mdelem* user_agent;
     struct grpc_linked_mdelem* host;
     struct grpc_linked_mdelem* lb_token;
+    struct grpc_linked_mdelem* grpc_previous_rpc_attempts;
+    struct grpc_linked_mdelem* grpc_retry_pushback_ms;
   } named;
 } grpc_metadata_batch_callouts;
 
@@ -590,5 +600,4 @@
   (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table                                  \
                         [grpc_static_accept_stream_encoding_metadata[(algs)]], \
                     GRPC_MDELEM_STORAGE_STATIC))
-
 #endif /* GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H */
diff --git a/src/core/lib/transport/status_conversion.cc b/src/core/lib/transport/status_conversion.cc
index 46cba42..e58bef5 100644
--- a/src/core/lib/transport/status_conversion.cc
+++ b/src/core/lib/transport/status_conversion.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/transport/status_conversion.h"
 
 grpc_http2_error_code grpc_status_to_http2_error(grpc_status_code status) {
diff --git a/src/core/lib/transport/status_conversion.h b/src/core/lib/transport/status_conversion.h
index 107eb92..487f00c 100644
--- a/src/core/lib/transport/status_conversion.h
+++ b/src/core/lib/transport/status_conversion.h
@@ -19,7 +19,10 @@
 #ifndef GRPC_CORE_LIB_TRANSPORT_STATUS_CONVERSION_H
 #define GRPC_CORE_LIB_TRANSPORT_STATUS_CONVERSION_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
+
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/transport/http2_errors.h"
 
diff --git a/src/core/lib/transport/status_metadata.cc b/src/core/lib/transport/status_metadata.cc
new file mode 100644
index 0000000..f896053
--- /dev/null
+++ b/src/core/lib/transport/status_metadata.cc
@@ -0,0 +1,54 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/lib/transport/status_metadata.h"
+
+#include "src/core/lib/slice/slice_string_helpers.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+/* we offset status by a small amount when storing it into transport metadata
+   as metadata cannot store a 0 value (which is used as OK for grpc_status_codes
+   */
+#define STATUS_OFFSET 1
+
+static void destroy_status(void* ignored) {}
+
+grpc_status_code grpc_get_status_code_from_metadata(grpc_mdelem md) {
+  if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
+    return GRPC_STATUS_OK;
+  }
+  if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_1)) {
+    return GRPC_STATUS_CANCELLED;
+  }
+  if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_2)) {
+    return GRPC_STATUS_UNKNOWN;
+  }
+  void* user_data = grpc_mdelem_get_user_data(md, destroy_status);
+  if (user_data != nullptr) {
+    return static_cast<grpc_status_code>((intptr_t)user_data - STATUS_OFFSET);
+  }
+  uint32_t status;
+  if (!grpc_parse_slice_to_uint32(GRPC_MDVALUE(md), &status)) {
+    status = GRPC_STATUS_UNKNOWN; /* could not parse status code */
+  }
+  grpc_mdelem_set_user_data(
+      md, destroy_status, (void*)static_cast<intptr_t>(status + STATUS_OFFSET));
+  return static_cast<grpc_status_code>(status);
+}
diff --git a/src/core/lib/transport/status_metadata.h b/src/core/lib/transport/status_metadata.h
new file mode 100644
index 0000000..aed9c7a
--- /dev/null
+++ b/src/core/lib/transport/status_metadata.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_LIB_TRANSPORT_STATUS_METADATA_H
+#define GRPC_CORE_LIB_TRANSPORT_STATUS_METADATA_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/status.h>
+
+#include "src/core/lib/transport/metadata.h"
+
+grpc_status_code grpc_get_status_code_from_metadata(grpc_mdelem md);
+
+#endif /* GRPC_CORE_LIB_TRANSPORT_STATUS_METADATA_H */
diff --git a/src/core/lib/transport/timeout_encoding.cc b/src/core/lib/transport/timeout_encoding.cc
index 47f964a..c372499 100644
--- a/src/core/lib/transport/timeout_encoding.cc
+++ b/src/core/lib/transport/timeout_encoding.cc
@@ -16,12 +16,13 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/transport/timeout_encoding.h"
 
 #include <stdio.h>
 #include <string.h>
 
-#include <grpc/support/port_platform.h>
 #include "src/core/lib/gpr/string.h"
 
 static int64_t round_up(int64_t x, int64_t divisor) {
@@ -98,7 +99,7 @@
     ;
   /* decode numeric part */
   for (; p != end && *p >= '0' && *p <= '9'; p++) {
-    int32_t digit = (int32_t)(*p - (uint8_t)'0');
+    int32_t digit = static_cast<int32_t>(*p - static_cast<uint8_t>('0'));
     have_digit = 1;
     /* spec allows max. 8 digits, but we allow values up to 1,000,000,000 */
     if (x >= (100 * 1000 * 1000)) {
@@ -138,5 +139,6 @@
       return 0;
   }
   p++;
-  return is_all_whitespace((const char*)p, (const char*)end);
+  return is_all_whitespace(reinterpret_cast<const char*>(p),
+                           reinterpret_cast<const char*>(end));
 }
diff --git a/src/core/lib/transport/timeout_encoding.h b/src/core/lib/transport/timeout_encoding.h
index 4e92682..8505e32 100644
--- a/src/core/lib/transport/timeout_encoding.h
+++ b/src/core/lib/transport/timeout_encoding.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_TRANSPORT_TIMEOUT_ENCODING_H
 #define GRPC_CORE_LIB_TRANSPORT_TIMEOUT_ENCODING_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice.h>
 #include <grpc/support/time.h>
 
diff --git a/src/core/lib/transport/transport.cc b/src/core/lib/transport/transport.cc
index ea0380e..6b41e4b 100644
--- a/src/core/lib/transport/transport.cc
+++ b/src/core/lib/transport/transport.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/transport/transport.h"
 
 #include <string.h>
@@ -101,7 +103,7 @@
   slice_stream_ref(&refcount->slice_refcount);
   grpc_slice res;
   res.refcount = &refcount->slice_refcount;
-  res.data.refcounted.bytes = (uint8_t*)buffer;
+  res.data.refcounted.bytes = static_cast<uint8_t*>(buffer);
   res.data.refcounted.length = length;
   return res;
 }
@@ -207,7 +209,7 @@
     grpc_transport_stream_op_batch* batch, grpc_error* error,
     grpc_call_combiner* call_combiner) {
   if (batch->send_message) {
-    grpc_byte_stream_destroy(batch->payload->send_message.send_message);
+    batch->payload->send_message.send_message.reset();
   }
   if (batch->recv_message) {
     GRPC_CALL_COMBINER_START(
@@ -233,13 +235,14 @@
 } made_transport_op;
 
 static void destroy_made_transport_op(void* arg, grpc_error* error) {
-  made_transport_op* op = (made_transport_op*)arg;
+  made_transport_op* op = static_cast<made_transport_op*>(arg);
   GRPC_CLOSURE_SCHED(op->inner_on_complete, GRPC_ERROR_REF(error));
   gpr_free(op);
 }
 
 grpc_transport_op* grpc_make_transport_op(grpc_closure* on_complete) {
-  made_transport_op* op = (made_transport_op*)gpr_malloc(sizeof(*op));
+  made_transport_op* op =
+      static_cast<made_transport_op*>(gpr_malloc(sizeof(*op)));
   GRPC_CLOSURE_INIT(&op->outer_on_complete, destroy_made_transport_op, op,
                     grpc_schedule_on_exec_ctx);
   op->inner_on_complete = on_complete;
@@ -256,7 +259,7 @@
 } made_transport_stream_op;
 
 static void destroy_made_transport_stream_op(void* arg, grpc_error* error) {
-  made_transport_stream_op* op = (made_transport_stream_op*)arg;
+  made_transport_stream_op* op = static_cast<made_transport_stream_op*>(arg);
   grpc_closure* c = op->inner_on_complete;
   gpr_free(op);
   GRPC_CLOSURE_RUN(c, GRPC_ERROR_REF(error));
@@ -265,7 +268,7 @@
 grpc_transport_stream_op_batch* grpc_make_transport_stream_op(
     grpc_closure* on_complete) {
   made_transport_stream_op* op =
-      (made_transport_stream_op*)gpr_zalloc(sizeof(*op));
+      static_cast<made_transport_stream_op*>(gpr_zalloc(sizeof(*op)));
   op->op.payload = &op->payload;
   GRPC_CLOSURE_INIT(&op->outer_on_complete, destroy_made_transport_stream_op,
                     op, grpc_schedule_on_exec_ctx);
diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h
index b392c69..10e9df0 100644
--- a/src/core/lib/transport/transport.h
+++ b/src/core/lib/transport/transport.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_TRANSPORT_TRANSPORT_H
 #define GRPC_CORE_LIB_TRANSPORT_TRANSPORT_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stddef.h>
 
 #include "src/core/lib/channel/context.h"
@@ -96,6 +98,19 @@
 void grpc_transport_move_stats(grpc_transport_stream_stats* from,
                                grpc_transport_stream_stats* to);
 
+// This struct (which is present in both grpc_transport_stream_op_batch
+// and grpc_transport_op_batch) is a convenience to allow filters or
+// transports to schedule a closure related to a particular batch without
+// having to allocate memory.  The general pattern is to initialize the
+// closure with the callback arg set to the batch and extra_arg set to
+// whatever state is associated with the handler (e.g., the call element
+// or the transport stream object).
+//
+// Note that this can only be used by the current handler of a given
+// batch on the way down the stack (i.e., whichever filter or transport is
+// currently handling the batch).  Once a filter or transport passes control
+// of the batch to the next handler, it cannot depend on the contents of
+// this struct anymore, because the next handler may reuse it.
 typedef struct {
   void* extra_arg;
   grpc_closure closure;
@@ -155,6 +170,11 @@
     uint32_t send_initial_metadata_flags;
     // If non-NULL, will be set by the transport to the peer string
     // (a char*, which the caller takes ownership of).
+    // Note: This pointer may be used by the transport after the
+    // send_initial_metadata op is completed.  It must remain valid
+    // until the call is destroyed.
+    // Note: When a transport sets this, it must free the previous
+    // value, if any.
     gpr_atm* peer_string;
   } send_initial_metadata;
 
@@ -164,15 +184,17 @@
 
   struct {
     // The transport (or a filter that decides to return a failure before
-    // the op gets down to the transport) is responsible for calling
-    // grpc_byte_stream_destroy() on this.
+    // the op gets down to the transport) takes ownership.
     // The batch's on_complete will not be called until after the byte
-    // stream is destroyed.
-    grpc_byte_stream* send_message;
+    // stream is orphaned.
+    grpc_core::OrphanablePtr<grpc_core::ByteStream> send_message;
   } send_message;
 
   struct {
     grpc_metadata_batch* recv_initial_metadata;
+    // Flags are used only on the server side.  If non-null, will be set to
+    // a bitfield of the GRPC_INITIAL_METADATA_xxx macros (e.g., to
+    // indicate if the call is idempotent).
     uint32_t* recv_flags;
     /** Should be enqueued when initial metadata is ready to be processed. */
     grpc_closure* recv_initial_metadata_ready;
@@ -182,15 +204,19 @@
     bool* trailing_metadata_available;
     // If non-NULL, will be set by the transport to the peer string
     // (a char*, which the caller takes ownership of).
+    // Note: This pointer may be used by the transport after the
+    // recv_initial_metadata op is completed.  It must remain valid
+    // until the call is destroyed.
+    // Note: When a transport sets this, it must free the previous
+    // value, if any.
     gpr_atm* peer_string;
   } recv_initial_metadata;
 
   struct {
     // Will be set by the transport to point to the byte stream
     // containing a received message.
-    // The caller is responsible for calling grpc_byte_stream_destroy()
-    // on this byte stream.
-    grpc_byte_stream** recv_message;
+    // Will be NULL if trailing metadata is received instead of a message.
+    grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message;
     /** Should be enqueued when one message is ready to be processed. */
     grpc_closure* recv_message_ready;
   } recv_message;
diff --git a/src/core/lib/transport/transport_impl.h b/src/core/lib/transport/transport_impl.h
index 50b8a5f..ba5e05d 100644
--- a/src/core/lib/transport/transport_impl.h
+++ b/src/core/lib/transport/transport_impl.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_LIB_TRANSPORT_TRANSPORT_IMPL_H
 #define GRPC_CORE_LIB_TRANSPORT_TRANSPORT_IMPL_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/transport/transport.h"
 
 typedef struct grpc_transport_vtable {
diff --git a/src/core/lib/transport/transport_op_string.cc b/src/core/lib/transport/transport_op_string.cc
index 58a21e9..99af7c1 100644
--- a/src/core/lib/transport/transport_op_string.cc
+++ b/src/core/lib/transport/transport_op_string.cc
@@ -27,7 +27,6 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/transport/connectivity_state.h"
@@ -76,9 +75,16 @@
 
   if (op->send_message) {
     gpr_strvec_add(&b, gpr_strdup(" "));
-    gpr_asprintf(&tmp, "SEND_MESSAGE:flags=0x%08x:len=%d",
-                 op->payload->send_message.send_message->flags,
-                 op->payload->send_message.send_message->length);
+    if (op->payload->send_message.send_message != nullptr) {
+      gpr_asprintf(&tmp, "SEND_MESSAGE:flags=0x%08x:len=%d",
+                   op->payload->send_message.send_message->flags(),
+                   op->payload->send_message.send_message->length());
+    } else {
+      // This can happen when we check a batch after the transport has
+      // processed and cleared the send_message op.
+      tmp =
+          gpr_strdup("SEND_MESSAGE(flag and length unknown, already orphaned)");
+    }
     gpr_strvec_add(&b, tmp);
   }
 
diff --git a/src/core/plugin_registry/grpc_cronet_plugin_registry.cc b/src/core/plugin_registry/grpc_cronet_plugin_registry.cc
index fe5eb28..84228cb 100644
--- a/src/core/plugin_registry/grpc_cronet_plugin_registry.cc
+++ b/src/core/plugin_registry/grpc_cronet_plugin_registry.cc
@@ -16,32 +16,54 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 
-void grpc_http_filters_init(void);
-void grpc_http_filters_shutdown(void);
-void grpc_chttp2_plugin_init(void);
-void grpc_chttp2_plugin_shutdown(void);
 void grpc_deadline_filter_init(void);
 void grpc_deadline_filter_shutdown(void);
 void grpc_client_channel_init(void);
 void grpc_client_channel_shutdown(void);
-void grpc_tsi_alts_init(void);
-void grpc_tsi_alts_shutdown(void);
+void grpc_lb_policy_pick_first_init(void);
+void grpc_lb_policy_pick_first_shutdown(void);
+void grpc_max_age_filter_init(void);
+void grpc_max_age_filter_shutdown(void);
+void grpc_message_size_filter_init(void);
+void grpc_message_size_filter_shutdown(void);
+void grpc_resolver_dns_native_init(void);
+void grpc_resolver_dns_native_shutdown(void);
+void grpc_resolver_sockaddr_init(void);
+void grpc_resolver_sockaddr_shutdown(void);
 void grpc_server_load_reporting_plugin_init(void);
 void grpc_server_load_reporting_plugin_shutdown(void);
+void grpc_http_filters_init(void);
+void grpc_http_filters_shutdown(void);
+void grpc_chttp2_plugin_init(void);
+void grpc_chttp2_plugin_shutdown(void);
+void grpc_tsi_alts_init(void);
+void grpc_tsi_alts_shutdown(void);
 
 void grpc_register_built_in_plugins(void) {
-  grpc_register_plugin(grpc_http_filters_init,
-                       grpc_http_filters_shutdown);
-  grpc_register_plugin(grpc_chttp2_plugin_init,
-                       grpc_chttp2_plugin_shutdown);
   grpc_register_plugin(grpc_deadline_filter_init,
                        grpc_deadline_filter_shutdown);
   grpc_register_plugin(grpc_client_channel_init,
                        grpc_client_channel_shutdown);
-  grpc_register_plugin(grpc_tsi_alts_init,
-                       grpc_tsi_alts_shutdown);
+  grpc_register_plugin(grpc_lb_policy_pick_first_init,
+                       grpc_lb_policy_pick_first_shutdown);
+  grpc_register_plugin(grpc_max_age_filter_init,
+                       grpc_max_age_filter_shutdown);
+  grpc_register_plugin(grpc_message_size_filter_init,
+                       grpc_message_size_filter_shutdown);
+  grpc_register_plugin(grpc_resolver_dns_native_init,
+                       grpc_resolver_dns_native_shutdown);
+  grpc_register_plugin(grpc_resolver_sockaddr_init,
+                       grpc_resolver_sockaddr_shutdown);
   grpc_register_plugin(grpc_server_load_reporting_plugin_init,
                        grpc_server_load_reporting_plugin_shutdown);
+  grpc_register_plugin(grpc_http_filters_init,
+                       grpc_http_filters_shutdown);
+  grpc_register_plugin(grpc_chttp2_plugin_init,
+                       grpc_chttp2_plugin_shutdown);
+  grpc_register_plugin(grpc_tsi_alts_init,
+                       grpc_tsi_alts_shutdown);
 }
diff --git a/src/core/plugin_registry/grpc_plugin_registry.cc b/src/core/plugin_registry/grpc_plugin_registry.cc
index fdf9acc..6f11e6b 100644
--- a/src/core/plugin_registry/grpc_plugin_registry.cc
+++ b/src/core/plugin_registry/grpc_plugin_registry.cc
@@ -16,18 +16,20 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 
 void grpc_http_filters_init(void);
 void grpc_http_filters_shutdown(void);
 void grpc_chttp2_plugin_init(void);
 void grpc_chttp2_plugin_shutdown(void);
-void grpc_tsi_alts_init(void);
-void grpc_tsi_alts_shutdown(void);
 void grpc_deadline_filter_init(void);
 void grpc_deadline_filter_shutdown(void);
 void grpc_client_channel_init(void);
 void grpc_client_channel_shutdown(void);
+void grpc_tsi_alts_init(void);
+void grpc_tsi_alts_shutdown(void);
 void grpc_inproc_plugin_init(void);
 void grpc_inproc_plugin_shutdown(void);
 void grpc_resolver_fake_init(void);
@@ -58,12 +60,12 @@
                        grpc_http_filters_shutdown);
   grpc_register_plugin(grpc_chttp2_plugin_init,
                        grpc_chttp2_plugin_shutdown);
-  grpc_register_plugin(grpc_tsi_alts_init,
-                       grpc_tsi_alts_shutdown);
   grpc_register_plugin(grpc_deadline_filter_init,
                        grpc_deadline_filter_shutdown);
   grpc_register_plugin(grpc_client_channel_init,
                        grpc_client_channel_shutdown);
+  grpc_register_plugin(grpc_tsi_alts_init,
+                       grpc_tsi_alts_shutdown);
   grpc_register_plugin(grpc_inproc_plugin_init,
                        grpc_inproc_plugin_shutdown);
   grpc_register_plugin(grpc_resolver_fake_init,
diff --git a/src/core/plugin_registry/grpc_unsecure_plugin_registry.cc b/src/core/plugin_registry/grpc_unsecure_plugin_registry.cc
index d73f946..b08c5ce 100644
--- a/src/core/plugin_registry/grpc_unsecure_plugin_registry.cc
+++ b/src/core/plugin_registry/grpc_unsecure_plugin_registry.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 
 void grpc_http_filters_init(void);
diff --git a/src/core/tsi/alts/crypt/aes_gcm.cc b/src/core/tsi/alts/crypt/aes_gcm.cc
new file mode 100644
index 0000000..02b1ac4
--- /dev/null
+++ b/src/core/tsi/alts/crypt/aes_gcm.cc
@@ -0,0 +1,687 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/crypt/gsec.h"
+
+#include <openssl/bio.h>
+#include <openssl/buffer.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+
+constexpr size_t kKdfKeyLen = 32;
+constexpr size_t kKdfCounterLen = 6;
+constexpr size_t kKdfCounterOffset = 2;
+constexpr size_t kRekeyAeadKeyLen = kAes128GcmKeyLength;
+
+/* Struct for additional data required if rekeying is enabled. */
+struct gsec_aes_gcm_aead_rekey_data {
+  uint8_t kdf_counter[kKdfCounterLen];
+  uint8_t nonce_mask[kAesGcmNonceLength];
+};
+
+/* Main struct for AES_GCM crypter interface. */
+struct gsec_aes_gcm_aead_crypter {
+  gsec_aead_crypter crypter;
+  size_t key_length;
+  size_t nonce_length;
+  size_t tag_length;
+  uint8_t* key;
+  gsec_aes_gcm_aead_rekey_data* rekey_data;
+  EVP_CIPHER_CTX* ctx;
+};
+
+static char* aes_gcm_get_openssl_errors() {
+  BIO* bio = BIO_new(BIO_s_mem());
+  ERR_print_errors(bio);
+  BUF_MEM* mem = nullptr;
+  char* error_msg = nullptr;
+  BIO_get_mem_ptr(bio, &mem);
+  if (mem != nullptr) {
+    error_msg = static_cast<char*>(gpr_malloc(mem->length + 1));
+    memcpy(error_msg, mem->data, mem->length);
+    error_msg[mem->length] = '\0';
+  }
+  BIO_free_all(bio);
+  return error_msg;
+}
+
+static void aes_gcm_format_errors(const char* error_msg, char** error_details) {
+  if (error_details == nullptr) {
+    return;
+  }
+  unsigned long error = ERR_get_error();
+  if (error == 0 && error_msg != nullptr) {
+    *error_details = static_cast<char*>(gpr_malloc(strlen(error_msg) + 1));
+    memcpy(*error_details, error_msg, strlen(error_msg) + 1);
+    return;
+  }
+  char* openssl_errors = aes_gcm_get_openssl_errors();
+  if (openssl_errors != nullptr && error_msg != nullptr) {
+    size_t len = strlen(error_msg) + strlen(openssl_errors) + 2; /* ", " */
+    *error_details = static_cast<char*>(gpr_malloc(len + 1));
+    snprintf(*error_details, len + 1, "%s, %s", error_msg, openssl_errors);
+    gpr_free(openssl_errors);
+  }
+}
+
+static grpc_status_code gsec_aes_gcm_aead_crypter_max_ciphertext_and_tag_length(
+    const gsec_aead_crypter* crypter, size_t plaintext_length,
+    size_t* max_ciphertext_and_tag_length, char** error_details) {
+  if (max_ciphertext_and_tag_length == nullptr) {
+    aes_gcm_format_errors("max_ciphertext_and_tag_length is nullptr.",
+                          error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  gsec_aes_gcm_aead_crypter* aes_gcm_crypter =
+      reinterpret_cast<gsec_aes_gcm_aead_crypter*>(
+          const_cast<gsec_aead_crypter*>(crypter));
+  *max_ciphertext_and_tag_length =
+      plaintext_length + aes_gcm_crypter->tag_length;
+  return GRPC_STATUS_OK;
+}
+
+static grpc_status_code gsec_aes_gcm_aead_crypter_max_plaintext_length(
+    const gsec_aead_crypter* crypter, size_t ciphertext_and_tag_length,
+    size_t* max_plaintext_length, char** error_details) {
+  if (max_plaintext_length == nullptr) {
+    aes_gcm_format_errors("max_plaintext_length is nullptr.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  gsec_aes_gcm_aead_crypter* aes_gcm_crypter =
+      reinterpret_cast<gsec_aes_gcm_aead_crypter*>(
+          const_cast<gsec_aead_crypter*>(crypter));
+  if (ciphertext_and_tag_length < aes_gcm_crypter->tag_length) {
+    *max_plaintext_length = 0;
+    aes_gcm_format_errors(
+        "ciphertext_and_tag_length is smaller than tag_length.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  *max_plaintext_length =
+      ciphertext_and_tag_length - aes_gcm_crypter->tag_length;
+  return GRPC_STATUS_OK;
+}
+
+static grpc_status_code gsec_aes_gcm_aead_crypter_nonce_length(
+    const gsec_aead_crypter* crypter, size_t* nonce_length,
+    char** error_details) {
+  if (nonce_length == nullptr) {
+    aes_gcm_format_errors("nonce_length is nullptr.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  gsec_aes_gcm_aead_crypter* aes_gcm_crypter =
+      reinterpret_cast<gsec_aes_gcm_aead_crypter*>(
+          const_cast<gsec_aead_crypter*>(crypter));
+  *nonce_length = aes_gcm_crypter->nonce_length;
+  return GRPC_STATUS_OK;
+}
+
+static grpc_status_code gsec_aes_gcm_aead_crypter_key_length(
+    const gsec_aead_crypter* crypter, size_t* key_length,
+    char** error_details) {
+  if (key_length == nullptr) {
+    aes_gcm_format_errors("key_length is nullptr.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  gsec_aes_gcm_aead_crypter* aes_gcm_crypter =
+      reinterpret_cast<gsec_aes_gcm_aead_crypter*>(
+          const_cast<gsec_aead_crypter*>(crypter));
+  *key_length = aes_gcm_crypter->key_length;
+  return GRPC_STATUS_OK;
+}
+
+static grpc_status_code gsec_aes_gcm_aead_crypter_tag_length(
+    const gsec_aead_crypter* crypter, size_t* tag_length,
+    char** error_details) {
+  if (tag_length == nullptr) {
+    aes_gcm_format_errors("tag_length is nullptr.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  gsec_aes_gcm_aead_crypter* aes_gcm_crypter =
+      reinterpret_cast<gsec_aes_gcm_aead_crypter*>(
+          const_cast<gsec_aead_crypter*>(crypter));
+  *tag_length = aes_gcm_crypter->tag_length;
+  return GRPC_STATUS_OK;
+}
+
+static void aes_gcm_mask_nonce(uint8_t* dst, const uint8_t* nonce,
+                               const uint8_t* mask) {
+  uint64_t mask1;
+  uint32_t mask2;
+  memcpy(&mask1, mask, sizeof(mask1));
+  memcpy(&mask2, mask + sizeof(mask1), sizeof(mask2));
+  uint64_t nonce1;
+  uint32_t nonce2;
+  memcpy(&nonce1, nonce, sizeof(nonce1));
+  memcpy(&nonce2, nonce + sizeof(nonce1), sizeof(nonce2));
+  nonce1 ^= mask1;
+  nonce2 ^= mask2;
+  memcpy(dst, &nonce1, sizeof(nonce1));
+  memcpy(dst + sizeof(nonce1), &nonce2, sizeof(nonce2));
+}
+
+static grpc_status_code aes_gcm_derive_aead_key(uint8_t* dst,
+                                                const uint8_t* kdf_key,
+                                                const uint8_t* kdf_counter) {
+  unsigned char buf[EVP_MAX_MD_SIZE];
+  unsigned char ctr = 1;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+  HMAC_CTX hmac;
+  HMAC_CTX_init(&hmac);
+  if (!HMAC_Init_ex(&hmac, kdf_key, kKdfKeyLen, EVP_sha256(), nullptr) ||
+      !HMAC_Update(&hmac, kdf_counter, kKdfCounterLen) ||
+      !HMAC_Update(&hmac, &ctr, 1) || !HMAC_Final(&hmac, buf, nullptr)) {
+    HMAC_CTX_cleanup(&hmac);
+    return GRPC_STATUS_INTERNAL;
+  }
+  HMAC_CTX_cleanup(&hmac);
+#else
+  HMAC_CTX* hmac = HMAC_CTX_new();
+  if (hmac == nullptr) {
+    return GRPC_STATUS_INTERNAL;
+  }
+  if (!HMAC_Init_ex(hmac, kdf_key, kKdfKeyLen, EVP_sha256(), nullptr) ||
+      !HMAC_Update(hmac, kdf_counter, kKdfCounterLen) ||
+      !HMAC_Update(hmac, &ctr, 1) || !HMAC_Final(hmac, buf, nullptr)) {
+    HMAC_CTX_free(hmac);
+    return GRPC_STATUS_INTERNAL;
+  }
+  HMAC_CTX_free(hmac);
+#endif
+  memcpy(dst, buf, kRekeyAeadKeyLen);
+  return GRPC_STATUS_OK;
+}
+
+static grpc_status_code aes_gcm_rekey_if_required(
+    gsec_aes_gcm_aead_crypter* aes_gcm_crypter, const uint8_t* nonce,
+    char** error_details) {
+  // If rekey_data is nullptr, then rekeying is not supported and not required.
+  // If bytes 2-7 of kdf_counter differ from the (per message) nonce, then the
+  // encryption key is recomputed from a new kdf_counter to ensure that we don't
+  // encrypt more than 2^16 messages per encryption key (in each direction).
+  if (aes_gcm_crypter->rekey_data == nullptr ||
+      memcmp(aes_gcm_crypter->rekey_data->kdf_counter,
+             nonce + kKdfCounterOffset, kKdfCounterLen) == 0) {
+    return GRPC_STATUS_OK;
+  }
+  memcpy(aes_gcm_crypter->rekey_data->kdf_counter, nonce + kKdfCounterOffset,
+         kKdfCounterLen);
+  uint8_t aead_key[kRekeyAeadKeyLen];
+  if (aes_gcm_derive_aead_key(aead_key, aes_gcm_crypter->key,
+                              aes_gcm_crypter->rekey_data->kdf_counter) !=
+      GRPC_STATUS_OK) {
+    aes_gcm_format_errors("Rekeying failed in key derivation.", error_details);
+    return GRPC_STATUS_INTERNAL;
+  }
+  if (!EVP_DecryptInit_ex(aes_gcm_crypter->ctx, nullptr, nullptr, aead_key,
+                          nullptr)) {
+    aes_gcm_format_errors("Rekeying failed in context update.", error_details);
+    return GRPC_STATUS_INTERNAL;
+  }
+  return GRPC_STATUS_OK;
+}
+
+static grpc_status_code gsec_aes_gcm_aead_crypter_encrypt_iovec(
+    gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length,
+    const struct iovec* aad_vec, size_t aad_vec_length,
+    const struct iovec* plaintext_vec, size_t plaintext_vec_length,
+    struct iovec ciphertext_vec, size_t* ciphertext_bytes_written,
+    char** error_details) {
+  gsec_aes_gcm_aead_crypter* aes_gcm_crypter =
+      reinterpret_cast<gsec_aes_gcm_aead_crypter*>(crypter);
+  // Input checks
+  if (nonce == nullptr) {
+    aes_gcm_format_errors("Nonce buffer is nullptr.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  if (kAesGcmNonceLength != nonce_length) {
+    aes_gcm_format_errors("Nonce buffer has the wrong length.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  if (aad_vec_length > 0 && aad_vec == nullptr) {
+    aes_gcm_format_errors("Non-zero aad_vec_length but aad_vec is nullptr.",
+                          error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  if (plaintext_vec_length > 0 && plaintext_vec == nullptr) {
+    aes_gcm_format_errors(
+        "Non-zero plaintext_vec_length but plaintext_vec is nullptr.",
+        error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  if (ciphertext_bytes_written == nullptr) {
+    aes_gcm_format_errors("bytes_written is nullptr.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  *ciphertext_bytes_written = 0;
+  // rekey if required
+  if (aes_gcm_rekey_if_required(aes_gcm_crypter, nonce, error_details) !=
+      GRPC_STATUS_OK) {
+    return GRPC_STATUS_INTERNAL;
+  }
+  // mask nonce if required
+  const uint8_t* nonce_aead = nonce;
+  uint8_t nonce_masked[kAesGcmNonceLength];
+  if (aes_gcm_crypter->rekey_data != nullptr) {
+    aes_gcm_mask_nonce(nonce_masked, aes_gcm_crypter->rekey_data->nonce_mask,
+                       nonce);
+    nonce_aead = nonce_masked;
+  }
+  // init openssl context
+  if (!EVP_EncryptInit_ex(aes_gcm_crypter->ctx, nullptr, nullptr, nullptr,
+                          nonce_aead)) {
+    aes_gcm_format_errors("Initializing nonce failed", error_details);
+    return GRPC_STATUS_INTERNAL;
+  }
+  // process aad
+  size_t i;
+  for (i = 0; i < aad_vec_length; i++) {
+    const uint8_t* aad = static_cast<uint8_t*>(aad_vec[i].iov_base);
+    size_t aad_length = aad_vec[i].iov_len;
+    if (aad_length == 0) {
+      continue;
+    }
+    size_t aad_bytes_read = 0;
+    if (aad == nullptr) {
+      aes_gcm_format_errors("aad is nullptr.", error_details);
+      return GRPC_STATUS_INVALID_ARGUMENT;
+    }
+    if (!EVP_EncryptUpdate(aes_gcm_crypter->ctx, nullptr,
+                           reinterpret_cast<int*>(&aad_bytes_read), aad,
+                           static_cast<int>(aad_length)) ||
+        aad_bytes_read != aad_length) {
+      aes_gcm_format_errors("Setting authenticated associated data failed",
+                            error_details);
+      return GRPC_STATUS_INTERNAL;
+    }
+  }
+  uint8_t* ciphertext = static_cast<uint8_t*>(ciphertext_vec.iov_base);
+  size_t ciphertext_length = ciphertext_vec.iov_len;
+  if (ciphertext == nullptr) {
+    aes_gcm_format_errors("ciphertext is nullptr.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  // process plaintext
+  for (i = 0; i < plaintext_vec_length; i++) {
+    const uint8_t* plaintext = static_cast<uint8_t*>(plaintext_vec[i].iov_base);
+    size_t plaintext_length = plaintext_vec[i].iov_len;
+    if (plaintext == nullptr) {
+      if (plaintext_length == 0) {
+        continue;
+      }
+      aes_gcm_format_errors("plaintext is nullptr.", error_details);
+      return GRPC_STATUS_INVALID_ARGUMENT;
+    }
+    if (ciphertext_length < plaintext_length) {
+      aes_gcm_format_errors(
+          "ciphertext is not large enough to hold the result.", error_details);
+      return GRPC_STATUS_INVALID_ARGUMENT;
+    }
+    int bytes_written = 0;
+    int bytes_to_write = static_cast<int>(plaintext_length);
+    if (!EVP_EncryptUpdate(aes_gcm_crypter->ctx, ciphertext, &bytes_written,
+                           plaintext, bytes_to_write)) {
+      aes_gcm_format_errors("Encrypting plaintext failed.", error_details);
+      return GRPC_STATUS_INTERNAL;
+    }
+    if (bytes_written > bytes_to_write) {
+      aes_gcm_format_errors("More bytes written than expected.", error_details);
+      return GRPC_STATUS_INTERNAL;
+    }
+    ciphertext += bytes_written;
+    ciphertext_length -= bytes_written;
+  }
+  int bytes_written_temp = 0;
+  if (!EVP_EncryptFinal_ex(aes_gcm_crypter->ctx, nullptr,
+                           &bytes_written_temp)) {
+    aes_gcm_format_errors("Finalizing encryption failed.", error_details);
+    return GRPC_STATUS_INTERNAL;
+  }
+  if (bytes_written_temp != 0) {
+    aes_gcm_format_errors("Openssl wrote some unexpected bytes.",
+                          error_details);
+    return GRPC_STATUS_INTERNAL;
+  }
+  if (ciphertext_length < kAesGcmTagLength) {
+    aes_gcm_format_errors("ciphertext is too small to hold a tag.",
+                          error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+
+  if (!EVP_CIPHER_CTX_ctrl(aes_gcm_crypter->ctx, EVP_CTRL_GCM_GET_TAG,
+                           kAesGcmTagLength, ciphertext)) {
+    aes_gcm_format_errors("Writing tag failed.", error_details);
+    return GRPC_STATUS_INTERNAL;
+  }
+  ciphertext += kAesGcmTagLength;
+  ciphertext_length -= kAesGcmTagLength;
+  *ciphertext_bytes_written = ciphertext_vec.iov_len - ciphertext_length;
+  return GRPC_STATUS_OK;
+}
+
+static grpc_status_code gsec_aes_gcm_aead_crypter_decrypt_iovec(
+    gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length,
+    const struct iovec* aad_vec, size_t aad_vec_length,
+    const struct iovec* ciphertext_vec, size_t ciphertext_vec_length,
+    struct iovec plaintext_vec, size_t* plaintext_bytes_written,
+    char** error_details) {
+  gsec_aes_gcm_aead_crypter* aes_gcm_crypter =
+      reinterpret_cast<gsec_aes_gcm_aead_crypter*>(
+          const_cast<gsec_aead_crypter*>(crypter));
+  if (nonce == nullptr) {
+    aes_gcm_format_errors("Nonce buffer is nullptr.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  if (kAesGcmNonceLength != nonce_length) {
+    aes_gcm_format_errors("Nonce buffer has the wrong length.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  if (aad_vec_length > 0 && aad_vec == nullptr) {
+    aes_gcm_format_errors("Non-zero aad_vec_length but aad_vec is nullptr.",
+                          error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  if (ciphertext_vec_length > 0 && ciphertext_vec == nullptr) {
+    aes_gcm_format_errors(
+        "Non-zero plaintext_vec_length but plaintext_vec is nullptr.",
+        error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  // Compute the total length so we can ensure we don't pass the tag into
+  // EVP_decrypt.
+  size_t total_ciphertext_length = 0;
+  size_t i;
+  for (i = 0; i < ciphertext_vec_length; i++) {
+    total_ciphertext_length += ciphertext_vec[i].iov_len;
+  }
+  if (total_ciphertext_length < kAesGcmTagLength) {
+    aes_gcm_format_errors("ciphertext is too small to hold a tag.",
+                          error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  if (plaintext_bytes_written == nullptr) {
+    aes_gcm_format_errors("bytes_written is nullptr.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  *plaintext_bytes_written = 0;
+  // rekey if required
+  if (aes_gcm_rekey_if_required(aes_gcm_crypter, nonce, error_details) !=
+      GRPC_STATUS_OK) {
+    aes_gcm_format_errors("Rekeying failed.", error_details);
+    return GRPC_STATUS_INTERNAL;
+  }
+  // mask nonce if required
+  const uint8_t* nonce_aead = nonce;
+  uint8_t nonce_masked[kAesGcmNonceLength];
+  if (aes_gcm_crypter->rekey_data != nullptr) {
+    aes_gcm_mask_nonce(nonce_masked, aes_gcm_crypter->rekey_data->nonce_mask,
+                       nonce);
+    nonce_aead = nonce_masked;
+  }
+  // init openssl context
+  if (!EVP_DecryptInit_ex(aes_gcm_crypter->ctx, nullptr, nullptr, nullptr,
+                          nonce_aead)) {
+    aes_gcm_format_errors("Initializing nonce failed.", error_details);
+    return GRPC_STATUS_INTERNAL;
+  }
+  // process aad
+  for (i = 0; i < aad_vec_length; i++) {
+    const uint8_t* aad = static_cast<uint8_t*>(aad_vec[i].iov_base);
+    size_t aad_length = aad_vec[i].iov_len;
+    if (aad_length == 0) {
+      continue;
+    }
+    size_t aad_bytes_read = 0;
+    if (aad == nullptr) {
+      aes_gcm_format_errors("aad is nullptr.", error_details);
+      return GRPC_STATUS_INVALID_ARGUMENT;
+    }
+    if (!EVP_DecryptUpdate(aes_gcm_crypter->ctx, nullptr,
+                           reinterpret_cast<int*>(&aad_bytes_read), aad,
+                           static_cast<int>(aad_length)) ||
+        aad_bytes_read != aad_length) {
+      aes_gcm_format_errors("Setting authenticated associated data failed.",
+                            error_details);
+      return GRPC_STATUS_INTERNAL;
+    }
+  }
+  // process ciphertext
+  uint8_t* plaintext = static_cast<uint8_t*>(plaintext_vec.iov_base);
+  size_t plaintext_length = plaintext_vec.iov_len;
+  if (plaintext_length > 0 && plaintext == nullptr) {
+    aes_gcm_format_errors(
+        "plaintext is nullptr, but plaintext_length is positive.",
+        error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  const uint8_t* ciphertext = nullptr;
+  size_t ciphertext_length = 0;
+  for (i = 0;
+       i < ciphertext_vec_length && total_ciphertext_length > kAesGcmTagLength;
+       i++) {
+    ciphertext = static_cast<uint8_t*>(ciphertext_vec[i].iov_base);
+    ciphertext_length = ciphertext_vec[i].iov_len;
+    if (ciphertext == nullptr) {
+      if (ciphertext_length == 0) {
+        continue;
+      }
+      aes_gcm_format_errors("ciphertext is nullptr.", error_details);
+      memset(plaintext_vec.iov_base, 0x00, plaintext_vec.iov_len);
+      return GRPC_STATUS_INVALID_ARGUMENT;
+    }
+    size_t bytes_written = 0;
+    size_t bytes_to_write = ciphertext_length;
+    // Don't include the tag
+    if (bytes_to_write > total_ciphertext_length - kAesGcmTagLength) {
+      bytes_to_write = total_ciphertext_length - kAesGcmTagLength;
+    }
+    if (plaintext_length < bytes_to_write) {
+      aes_gcm_format_errors(
+          "Not enough plaintext buffer to hold encrypted ciphertext.",
+          error_details);
+      return GRPC_STATUS_INVALID_ARGUMENT;
+    }
+    if (!EVP_DecryptUpdate(aes_gcm_crypter->ctx, plaintext,
+                           reinterpret_cast<int*>(&bytes_written), ciphertext,
+                           static_cast<int>(bytes_to_write))) {
+      aes_gcm_format_errors("Decrypting ciphertext failed.", error_details);
+      memset(plaintext_vec.iov_base, 0x00, plaintext_vec.iov_len);
+      return GRPC_STATUS_INTERNAL;
+    }
+    if (bytes_written > ciphertext_length) {
+      aes_gcm_format_errors("More bytes written than expected.", error_details);
+      memset(plaintext_vec.iov_base, 0x00, plaintext_vec.iov_len);
+      return GRPC_STATUS_INTERNAL;
+    }
+    ciphertext += bytes_written;
+    ciphertext_length -= bytes_written;
+    total_ciphertext_length -= bytes_written;
+    plaintext += bytes_written;
+    plaintext_length -= bytes_written;
+  }
+  if (total_ciphertext_length > kAesGcmTagLength) {
+    aes_gcm_format_errors(
+        "Not enough plaintext buffer to hold encrypted ciphertext.",
+        error_details);
+    memset(plaintext_vec.iov_base, 0x00, plaintext_vec.iov_len);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  uint8_t tag[kAesGcmTagLength];
+  uint8_t* tag_tmp = tag;
+  if (ciphertext_length > 0) {
+    memcpy(tag_tmp, ciphertext, ciphertext_length);
+    tag_tmp += ciphertext_length;
+    total_ciphertext_length -= ciphertext_length;
+  }
+  for (; i < ciphertext_vec_length; i++) {
+    ciphertext = static_cast<uint8_t*>(ciphertext_vec[i].iov_base);
+    ciphertext_length = ciphertext_vec[i].iov_len;
+    if (ciphertext == nullptr) {
+      if (ciphertext_length == 0) {
+        continue;
+      }
+      aes_gcm_format_errors("ciphertext is nullptr.", error_details);
+      memset(plaintext_vec.iov_base, 0x00, plaintext_vec.iov_len);
+      return GRPC_STATUS_INVALID_ARGUMENT;
+    }
+    memcpy(tag_tmp, ciphertext, ciphertext_length);
+    tag_tmp += ciphertext_length;
+    total_ciphertext_length -= ciphertext_length;
+  }
+  if (!EVP_CIPHER_CTX_ctrl(aes_gcm_crypter->ctx, EVP_CTRL_GCM_SET_TAG,
+                           kAesGcmTagLength, reinterpret_cast<void*>(tag))) {
+    aes_gcm_format_errors("Setting tag failed.", error_details);
+    memset(plaintext_vec.iov_base, 0x00, plaintext_vec.iov_len);
+    return GRPC_STATUS_INTERNAL;
+  }
+  int bytes_written_temp = 0;
+  if (!EVP_DecryptFinal_ex(aes_gcm_crypter->ctx, nullptr,
+                           &bytes_written_temp)) {
+    aes_gcm_format_errors("Checking tag failed.", error_details);
+    memset(plaintext_vec.iov_base, 0x00, plaintext_vec.iov_len);
+    return GRPC_STATUS_FAILED_PRECONDITION;
+  }
+  if (bytes_written_temp != 0) {
+    aes_gcm_format_errors("Openssl wrote some unexpected bytes.",
+                          error_details);
+    memset(plaintext_vec.iov_base, 0x00, plaintext_vec.iov_len);
+    return GRPC_STATUS_INTERNAL;
+  }
+  *plaintext_bytes_written = plaintext_vec.iov_len - plaintext_length;
+  return GRPC_STATUS_OK;
+}
+
+static void gsec_aes_gcm_aead_crypter_destroy(gsec_aead_crypter* crypter) {
+  gsec_aes_gcm_aead_crypter* aes_gcm_crypter =
+      reinterpret_cast<gsec_aes_gcm_aead_crypter*>(
+          const_cast<gsec_aead_crypter*>(crypter));
+  gpr_free(aes_gcm_crypter->key);
+  gpr_free(aes_gcm_crypter->rekey_data);
+  EVP_CIPHER_CTX_free(aes_gcm_crypter->ctx);
+}
+
+static const gsec_aead_crypter_vtable vtable = {
+    gsec_aes_gcm_aead_crypter_encrypt_iovec,
+    gsec_aes_gcm_aead_crypter_decrypt_iovec,
+    gsec_aes_gcm_aead_crypter_max_ciphertext_and_tag_length,
+    gsec_aes_gcm_aead_crypter_max_plaintext_length,
+    gsec_aes_gcm_aead_crypter_nonce_length,
+    gsec_aes_gcm_aead_crypter_key_length,
+    gsec_aes_gcm_aead_crypter_tag_length,
+    gsec_aes_gcm_aead_crypter_destroy};
+
+static grpc_status_code aes_gcm_new_evp_cipher_ctx(
+    gsec_aes_gcm_aead_crypter* aes_gcm_crypter, char** error_details) {
+  const EVP_CIPHER* cipher = nullptr;
+  bool is_rekey = aes_gcm_crypter->rekey_data != nullptr;
+  switch (is_rekey ? kRekeyAeadKeyLen : aes_gcm_crypter->key_length) {
+    case kAes128GcmKeyLength:
+      cipher = EVP_aes_128_gcm();
+      break;
+    case kAes256GcmKeyLength:
+      cipher = EVP_aes_256_gcm();
+      break;
+  }
+  const uint8_t* aead_key = aes_gcm_crypter->key;
+  uint8_t aead_key_rekey[kRekeyAeadKeyLen];
+  if (is_rekey) {
+    if (aes_gcm_derive_aead_key(aead_key_rekey, aes_gcm_crypter->key,
+                                aes_gcm_crypter->rekey_data->kdf_counter) !=
+        GRPC_STATUS_OK) {
+      aes_gcm_format_errors("Deriving key failed.", error_details);
+      return GRPC_STATUS_INTERNAL;
+    }
+    aead_key = aead_key_rekey;
+  }
+  if (!EVP_DecryptInit_ex(aes_gcm_crypter->ctx, cipher, nullptr, aead_key,
+                          nullptr)) {
+    aes_gcm_format_errors("Setting key failed.", error_details);
+    return GRPC_STATUS_INTERNAL;
+  }
+  if (!EVP_CIPHER_CTX_ctrl(aes_gcm_crypter->ctx, EVP_CTRL_GCM_SET_IVLEN,
+                           static_cast<int>(aes_gcm_crypter->nonce_length),
+                           nullptr)) {
+    aes_gcm_format_errors("Setting nonce length failed.", error_details);
+    return GRPC_STATUS_INTERNAL;
+  }
+  return GRPC_STATUS_OK;
+}
+
+grpc_status_code gsec_aes_gcm_aead_crypter_create(const uint8_t* key,
+                                                  size_t key_length,
+                                                  size_t nonce_length,
+                                                  size_t tag_length, bool rekey,
+                                                  gsec_aead_crypter** crypter,
+                                                  char** error_details) {
+  if (key == nullptr) {
+    aes_gcm_format_errors("key is nullptr.", error_details);
+    return GRPC_STATUS_FAILED_PRECONDITION;
+  }
+  if (crypter == nullptr) {
+    aes_gcm_format_errors("crypter is nullptr.", error_details);
+    return GRPC_STATUS_FAILED_PRECONDITION;
+  }
+  *crypter = nullptr;
+  if ((rekey && key_length != kAes128GcmRekeyKeyLength) ||
+      (!rekey && key_length != kAes128GcmKeyLength &&
+       key_length != kAes256GcmKeyLength) ||
+      (tag_length != kAesGcmTagLength) ||
+      (nonce_length != kAesGcmNonceLength)) {
+    aes_gcm_format_errors(
+        "Invalid key and/or nonce and/or tag length are provided at AEAD "
+        "crypter instance construction time.",
+        error_details);
+    return GRPC_STATUS_FAILED_PRECONDITION;
+  }
+  gsec_aes_gcm_aead_crypter* aes_gcm_crypter =
+      static_cast<gsec_aes_gcm_aead_crypter*>(
+          gpr_malloc(sizeof(gsec_aes_gcm_aead_crypter)));
+  aes_gcm_crypter->crypter.vtable = &vtable;
+  aes_gcm_crypter->nonce_length = nonce_length;
+  aes_gcm_crypter->tag_length = tag_length;
+  if (rekey) {
+    aes_gcm_crypter->key_length = kKdfKeyLen;
+    aes_gcm_crypter->rekey_data = static_cast<gsec_aes_gcm_aead_rekey_data*>(
+        gpr_malloc(sizeof(gsec_aes_gcm_aead_rekey_data)));
+    memcpy(aes_gcm_crypter->rekey_data->nonce_mask, key + kKdfKeyLen,
+           kAesGcmNonceLength);
+    // Set kdf_counter to all-zero for initial key derivation.
+    memset(aes_gcm_crypter->rekey_data->kdf_counter, 0, kKdfCounterLen);
+  } else {
+    aes_gcm_crypter->key_length = key_length;
+    aes_gcm_crypter->rekey_data = nullptr;
+  }
+  aes_gcm_crypter->key =
+      static_cast<uint8_t*>(gpr_malloc(aes_gcm_crypter->key_length));
+  memcpy(aes_gcm_crypter->key, key, aes_gcm_crypter->key_length);
+  aes_gcm_crypter->ctx = EVP_CIPHER_CTX_new();
+  grpc_status_code status =
+      aes_gcm_new_evp_cipher_ctx(aes_gcm_crypter, error_details);
+  if (status != GRPC_STATUS_OK) {
+    gsec_aes_gcm_aead_crypter_destroy(&aes_gcm_crypter->crypter);
+    gpr_free(aes_gcm_crypter);
+    return status;
+  }
+  *crypter = &aes_gcm_crypter->crypter;
+  return GRPC_STATUS_OK;
+}
diff --git a/src/core/tsi/alts/crypt/gsec.cc b/src/core/tsi/alts/crypt/gsec.cc
new file mode 100644
index 0000000..6236591
--- /dev/null
+++ b/src/core/tsi/alts/crypt/gsec.cc
@@ -0,0 +1,189 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/crypt/gsec.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+
+static const char vtable_error_msg[] =
+    "crypter or crypter->vtable has not been initialized properly";
+
+static void maybe_copy_error_msg(const char* src, char** dst) {
+  if (dst != nullptr && src != nullptr) {
+    *dst = static_cast<char*>(gpr_malloc(strlen(src) + 1));
+    memcpy(*dst, src, strlen(src) + 1);
+  }
+}
+
+grpc_status_code gsec_aead_crypter_encrypt(
+    gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length,
+    const uint8_t* aad, size_t aad_length, const uint8_t* plaintext,
+    size_t plaintext_length, uint8_t* ciphertext_and_tag,
+    size_t ciphertext_and_tag_length, size_t* bytes_written,
+    char** error_details) {
+  if (crypter != nullptr && crypter->vtable != nullptr &&
+      crypter->vtable->encrypt_iovec != nullptr) {
+    struct iovec aad_vec = {(void*)aad, aad_length};
+    struct iovec plaintext_vec = {(void*)plaintext, plaintext_length};
+    struct iovec ciphertext_vec = {ciphertext_and_tag,
+                                   ciphertext_and_tag_length};
+    return crypter->vtable->encrypt_iovec(
+        crypter, nonce, nonce_length, &aad_vec, 1, &plaintext_vec, 1,
+        ciphertext_vec, bytes_written, error_details);
+  }
+  /* An error occurred. */
+  maybe_copy_error_msg(vtable_error_msg, error_details);
+  return GRPC_STATUS_INVALID_ARGUMENT;
+}
+
+grpc_status_code gsec_aead_crypter_encrypt_iovec(
+    gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length,
+    const struct iovec* aad_vec, size_t aad_vec_length,
+    const struct iovec* plaintext_vec, size_t plaintext_vec_length,
+    struct iovec ciphertext_vec, size_t* ciphertext_bytes_written,
+    char** error_details) {
+  if (crypter != nullptr && crypter->vtable != nullptr &&
+      crypter->vtable->encrypt_iovec != nullptr) {
+    return crypter->vtable->encrypt_iovec(
+        crypter, nonce, nonce_length, aad_vec, aad_vec_length, plaintext_vec,
+        plaintext_vec_length, ciphertext_vec, ciphertext_bytes_written,
+        error_details);
+  }
+  /* An error occurred. */
+  maybe_copy_error_msg(vtable_error_msg, error_details);
+  return GRPC_STATUS_INVALID_ARGUMENT;
+}
+
+grpc_status_code gsec_aead_crypter_decrypt(
+    gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length,
+    const uint8_t* aad, size_t aad_length, const uint8_t* ciphertext_and_tag,
+    size_t ciphertext_and_tag_length, uint8_t* plaintext,
+    size_t plaintext_length, size_t* bytes_written, char** error_details) {
+  if (crypter != nullptr && crypter->vtable != nullptr &&
+      crypter->vtable->decrypt_iovec != nullptr) {
+    struct iovec aad_vec = {(void*)aad, aad_length};
+    struct iovec ciphertext_vec = {(void*)ciphertext_and_tag,
+                                   ciphertext_and_tag_length};
+    struct iovec plaintext_vec = {plaintext, plaintext_length};
+    return crypter->vtable->decrypt_iovec(
+        crypter, nonce, nonce_length, &aad_vec, 1, &ciphertext_vec, 1,
+        plaintext_vec, bytes_written, error_details);
+  }
+  /* An error occurred. */
+  maybe_copy_error_msg(vtable_error_msg, error_details);
+  return GRPC_STATUS_INVALID_ARGUMENT;
+}
+
+grpc_status_code gsec_aead_crypter_decrypt_iovec(
+    gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length,
+    const struct iovec* aad_vec, size_t aad_vec_length,
+    const struct iovec* ciphertext_vec, size_t ciphertext_vec_length,
+    struct iovec plaintext_vec, size_t* plaintext_bytes_written,
+    char** error_details) {
+  if (crypter != nullptr && crypter->vtable != nullptr &&
+      crypter->vtable->encrypt_iovec != nullptr) {
+    return crypter->vtable->decrypt_iovec(
+        crypter, nonce, nonce_length, aad_vec, aad_vec_length, ciphertext_vec,
+        ciphertext_vec_length, plaintext_vec, plaintext_bytes_written,
+        error_details);
+  }
+  /* An error occurred. */
+  maybe_copy_error_msg(vtable_error_msg, error_details);
+  return GRPC_STATUS_INVALID_ARGUMENT;
+}
+
+grpc_status_code gsec_aead_crypter_max_ciphertext_and_tag_length(
+    const gsec_aead_crypter* crypter, size_t plaintext_length,
+    size_t* max_ciphertext_and_tag_length_to_return, char** error_details) {
+  if (crypter != nullptr && crypter->vtable != nullptr &&
+      crypter->vtable->max_ciphertext_and_tag_length != nullptr) {
+    return crypter->vtable->max_ciphertext_and_tag_length(
+        crypter, plaintext_length, max_ciphertext_and_tag_length_to_return,
+        error_details);
+  }
+  /* An error occurred. */
+  maybe_copy_error_msg(vtable_error_msg, error_details);
+  return GRPC_STATUS_INVALID_ARGUMENT;
+}
+
+grpc_status_code gsec_aead_crypter_max_plaintext_length(
+    const gsec_aead_crypter* crypter, size_t ciphertext_and_tag_length,
+    size_t* max_plaintext_length_to_return, char** error_details) {
+  if (crypter != nullptr && crypter->vtable != nullptr &&
+      crypter->vtable->max_plaintext_length != nullptr) {
+    return crypter->vtable->max_plaintext_length(
+        crypter, ciphertext_and_tag_length, max_plaintext_length_to_return,
+        error_details);
+  }
+  /* An error occurred. */
+  maybe_copy_error_msg(vtable_error_msg, error_details);
+  return GRPC_STATUS_INVALID_ARGUMENT;
+}
+
+grpc_status_code gsec_aead_crypter_nonce_length(
+    const gsec_aead_crypter* crypter, size_t* nonce_length_to_return,
+    char** error_details) {
+  if (crypter != nullptr && crypter->vtable != nullptr &&
+      crypter->vtable->nonce_length != nullptr) {
+    return crypter->vtable->nonce_length(crypter, nonce_length_to_return,
+                                         error_details);
+  }
+  /* An error occurred. */
+  maybe_copy_error_msg(vtable_error_msg, error_details);
+  return GRPC_STATUS_INVALID_ARGUMENT;
+}
+
+grpc_status_code gsec_aead_crypter_key_length(const gsec_aead_crypter* crypter,
+                                              size_t* key_length_to_return,
+                                              char** error_details) {
+  if (crypter != nullptr && crypter->vtable != nullptr &&
+      crypter->vtable->key_length != nullptr) {
+    return crypter->vtable->key_length(crypter, key_length_to_return,
+                                       error_details);
+  }
+  /* An error occurred */
+  maybe_copy_error_msg(vtable_error_msg, error_details);
+  return GRPC_STATUS_INVALID_ARGUMENT;
+}
+
+grpc_status_code gsec_aead_crypter_tag_length(const gsec_aead_crypter* crypter,
+                                              size_t* tag_length_to_return,
+                                              char** error_details) {
+  if (crypter != nullptr && crypter->vtable != nullptr &&
+      crypter->vtable->tag_length != nullptr) {
+    return crypter->vtable->tag_length(crypter, tag_length_to_return,
+                                       error_details);
+  }
+  /* An error occurred. */
+  maybe_copy_error_msg(vtable_error_msg, error_details);
+  return GRPC_STATUS_INVALID_ARGUMENT;
+}
+
+void gsec_aead_crypter_destroy(gsec_aead_crypter* crypter) {
+  if (crypter != nullptr) {
+    if (crypter->vtable != nullptr && crypter->vtable->destruct != nullptr) {
+      crypter->vtable->destruct(crypter);
+    }
+    gpr_free(crypter);
+  }
+}
diff --git a/src/core/tsi/alts/crypt/gsec.h b/src/core/tsi/alts/crypt/gsec.h
new file mode 100644
index 0000000..4d65caa
--- /dev/null
+++ b/src/core/tsi/alts/crypt/gsec.h
@@ -0,0 +1,454 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_ALTS_CRYPT_GSEC_H
+#define GRPC_CORE_TSI_ALTS_CRYPT_GSEC_H
+
+#include <grpc/support/port_platform.h>
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <grpc/grpc.h>
+
+struct iovec {
+  void* iov_base;
+  size_t iov_len;
+};
+
+/**
+ * A gsec interface for AEAD encryption schemes. The API is thread-compatible.
+ * Each implementation of this interface should specify supported values for
+ * key, nonce, and tag lengths.
+ */
+
+/* Key, nonce, and tag length in bytes */
+const size_t kAesGcmNonceLength = 12;
+const size_t kAesGcmTagLength = 16;
+const size_t kAes128GcmKeyLength = 16;
+const size_t kAes256GcmKeyLength = 32;
+
+// The first 32 bytes are used as a KDF key and the remaining 12 bytes are used
+// to mask the nonce.
+const size_t kAes128GcmRekeyKeyLength = 44;
+
+typedef struct gsec_aead_crypter gsec_aead_crypter;
+
+/**
+ * The gsec_aead_crypter is an API for different AEAD implementations such as
+ * AES_GCM. It encapsulates all AEAD-related operations in the format of
+ * V-table that stores pointers to functions implementing those operations.
+ * It also provides helper functions to wrap each of those function pointers.
+ *
+ * A typical usage of this object would be:
+ *
+ *------------------------------------------------------------------------------
+ * // Declare a gsec_aead_crypter object, and create and assign an instance
+ * // of specific AEAD implementation e.g., AES_GCM to it. We assume both
+ * // key and nonce contain cryptographically secure random bytes, and the key
+ * // can be derived from an upper-layer application.
+ * gsec_aead_crypter* crypter;
+ * char* error_in_creation;
+ * // User can populate the message with any 100 bytes data.
+ * uint8_t* message = gpr_malloc(100);
+ * grpc_status_code creation_status = gsec_aes_gcm_aead_crypter_create(key,
+ *                                                      kAes128GcmKeyLength,
+ *                                                      kAesGcmNonceLength,
+ *                                                      kAesGcmTagLength,
+ *                                                      &crypter,
+ *                                                      false,
+ *                                                      0
+ *                                                      &error_in_creation);
+ *
+ * if (creation_status == GRPC_STATUS_OK) {
+ *    // Allocate a correct amount of memory to hold a ciphertext.
+ *    size_t clength = 0;
+ *    gsec_aead_crypter_max_ciphertext_and_tag_length(crypter, 100, &clength,
+ *                                                    nullptr);
+ *    uint8_t* ciphertext = gpr_malloc(clength);
+ *
+ *    // Perform encryption
+ *    size_t num_encrypted_bytes = 0;
+ *    char* error_in_encryption = nullptr;
+ *    grpc_status_code status = gsec_aead_crypter_encrypt(crypter, nonce,
+ *                                                        kAesGcmNonceLength,
+ *                                                        nullptr, 0, message,
+ *                                                        100, ciphertext,
+ *                                                        clength,
+ *                                                        &num_encrypted_bytes,
+ *                                                        &error_in_encryption);
+ * if (status == GRPC_STATUS_OK) {
+ *       // Allocate a correct amount of memory to hold a plaintext.
+ *       size_t plength = 0;
+ *       gsec_aead_crypter_max_plaintext_length(crypter, num_encrypted_bytes,
+ *                                              &plength, nullptr);
+ *       uint8_t* plaintext = gpr_malloc(plength);
+ *
+ *       // Perform decryption.
+ *       size_t num_decrypted_bytes = 0;
+ *       char* error_in_decryption = nullptr;
+ *       status = gsec_aead_crypter_decrypt(crypter, nonce,
+ *                                          kAesGcmNonceLength, nullptr, 0,
+ *                                          ciphertext, num_encrypted_bytes,
+ *                                          plaintext, plength,
+ *                                          &num_decrypted_bytes,
+ *                                          &error_in_decryption);
+ *       if (status != GRPC_STATUS_OK) {
+ *         fprintf(stderr, "AEAD decrypt operation failed with error code:"
+ *                         "%d, message: %s\n", status, error_in_decryption);
+ *       }
+ *       ...
+ *       gpr_free(plaintext);
+ *       gpr_free(error_in_decryption);
+ *    } else {
+ *        fprintf(stderr, "AEAD encrypt operation failed with error code:"
+ *                        "%d, message: %s\n", status, error_in_encryption);
+ *    }
+ *    ...
+ *    gpr_free(ciphertext);
+ *    gpr_free(error_in_encryption);
+ * } else {
+ *   fprintf(stderr, "Creation of AEAD crypter instance failed with error code:"
+ *                   "%d, message: %s\n", creation_status, error_in_creation);
+ * }
+ *
+ * // Destruct AEAD crypter instance.
+ * if (creation_status == GRPC_STATUS_OK) {
+ *   gsec_aead_crypter_destroy(crypter);
+ * }
+ * gpr_free(error_in_creation);
+ * gpr_free(message);
+ * -----------------------------------------------------------------------------
+ */
+
+/* V-table for gsec AEAD operations */
+typedef struct gsec_aead_crypter_vtable {
+  grpc_status_code (*encrypt_iovec)(
+      gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length,
+      const struct iovec* aad_vec, size_t aad_vec_length,
+      const struct iovec* plaintext_vec, size_t plaintext_vec_length,
+      struct iovec ciphertext_vec, size_t* ciphertext_bytes_written,
+      char** error_details);
+  grpc_status_code (*decrypt_iovec)(
+      gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length,
+      const struct iovec* aad_vec, size_t aad_vec_length,
+      const struct iovec* ciphertext_vec, size_t ciphertext_vec_length,
+      struct iovec plaintext_vec, size_t* plaintext_bytes_written,
+      char** error_details);
+  grpc_status_code (*max_ciphertext_and_tag_length)(
+      const gsec_aead_crypter* crypter, size_t plaintext_length,
+      size_t* max_ciphertext_and_tag_length_to_return, char** error_details);
+  grpc_status_code (*max_plaintext_length)(
+      const gsec_aead_crypter* crypter, size_t ciphertext_and_tag_length,
+      size_t* max_plaintext_length_to_return, char** error_details);
+  grpc_status_code (*nonce_length)(const gsec_aead_crypter* crypter,
+                                   size_t* nonce_length_to_return,
+                                   char** error_details);
+  grpc_status_code (*key_length)(const gsec_aead_crypter* crypter,
+                                 size_t* key_length_to_return,
+                                 char** error_details);
+  grpc_status_code (*tag_length)(const gsec_aead_crypter* crypter,
+                                 size_t* tag_length_to_return,
+                                 char** error_details);
+  void (*destruct)(gsec_aead_crypter* crypter);
+} gsec_aead_crypter_vtable;
+
+/* Main struct for gsec interface */
+struct gsec_aead_crypter {
+  const struct gsec_aead_crypter_vtable* vtable;
+};
+
+/**
+ * This method performs an AEAD encrypt operation.
+ *
+ * - crypter: AEAD crypter instance.
+ * - nonce: buffer containing a nonce with its size equal to nonce_length.
+ * - nonce_length: size of nonce buffer, and must be equal to the value returned
+ *   from method gsec_aead_crypter_nonce_length.
+ * - aad: buffer containing data that needs to be authenticated but not
+ *   encrypted with its size equal to aad_length.
+ * - aad_length: size of aad buffer, which should be zero if the buffer is
+ *   nullptr.
+ * - plaintext: buffer containing data that needs to be both encrypted and
+ *   authenticated with its size equal to plaintext_length.
+ * - plaintext_length: size of plaintext buffer, which should be zero if
+ *   plaintext is nullptr.
+ * - ciphertext_and_tag: buffer that will contain ciphertext and tags the method
+ *   produced. The buffer should not overlap the plaintext buffer, and pointers
+ *   to those buffers should not be equal. Also if the ciphertext+tag buffer is
+ *   nullptr, the plaintext_length should be zero.
+ * - ciphertext_and_tag_length: size of ciphertext+tag buffer, which should be
+ *   at least as long as the one returned from method
+ *   gsec_aead_crypter_max_ciphertext_and_tag_length.
+ * - bytes_written: the actual number of bytes written to the ciphertext+tag
+ *   buffer. If bytes_written is nullptr, the plaintext_length should be zero.
+ * - error_details: a buffer containing an error message if the method does not
+ *   function correctly. It is legal to pass nullptr into error_details, and
+ *   otherwise, the parameter should be freed with gpr_free.
+ *
+ * On the success of encryption, the method returns GRPC_STATUS_OK. Otherwise,
+ * it returns an error status code along with its details specified in
+ * error_details (if error_details is not nullptr).
+ *
+ */
+grpc_status_code gsec_aead_crypter_encrypt(
+    gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length,
+    const uint8_t* aad, size_t aad_length, const uint8_t* plaintext,
+    size_t plaintext_length, uint8_t* ciphertext_and_tag,
+    size_t ciphertext_and_tag_length, size_t* bytes_written,
+    char** error_details);
+
+/**
+ * This method performs an AEAD encrypt operation.
+ *
+ * - crypter: AEAD crypter instance.
+ * - nonce: buffer containing a nonce with its size equal to nonce_length.
+ * - nonce_length: size of nonce buffer, and must be equal to the value returned
+ *   from method gsec_aead_crypter_nonce_length.
+ * - aad_vec: an iovec array containing data that needs to be authenticated but
+ *   not encrypted.
+ * - aad_vec_length: the array length of aad_vec.
+ * - plaintext_vec: an iovec array containing data that needs to be both
+ *   encrypted and authenticated.
+ * - plaintext_vec_length: the array length of plaintext_vec.
+ * - ciphertext_vec: an iovec containing a ciphertext buffer. The buffer should
+ *   not overlap the plaintext buffer.
+ * - ciphertext_bytes_written: the actual number of bytes written to
+ *   ciphertext_vec.
+ * - error_details: a buffer containing an error message if the method does not
+ *   function correctly. It is legal to pass nullptr into error_details, and
+ *   otherwise, the parameter should be freed with gpr_free.
+ *
+ * On the success of encryption, the method returns GRPC_STATUS_OK. Otherwise,
+ * it returns an error status code along with its details specified in
+ * error_details (if error_details is not nullptr).
+ *
+ */
+grpc_status_code gsec_aead_crypter_encrypt_iovec(
+    gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length,
+    const struct iovec* aad_vec, size_t aad_vec_length,
+    const struct iovec* plaintext_vec, size_t plaintext_vec_length,
+    struct iovec ciphertext_vec, size_t* ciphertext_bytes_written,
+    char** error_details);
+
+/**
+ * This method performs an AEAD decrypt operation.
+ *
+ * - crypter: AEAD crypter instance.
+ * - nonce: buffer containing a nonce with its size equal to nonce_length.
+ * - nonce_length: size of nonce buffer, and must be equal to the value returned
+ *   from method gsec_aead_crypter_nonce_length.
+ * - aad: buffer containing data that needs to be authenticated only.
+ * - aad_length: size of aad buffer, which should be zero if the buffer is
+ *   nullptr.
+ * - ciphertext_and_tag: buffer containing ciphertext and tag.
+ * - ciphertext_and_tag_length: length of ciphertext and tag. It should be zero
+ *   if any of plaintext, ciphertext_and_tag, or bytes_written is nullptr. Also,
+ *   ciphertext_and_tag_length should be at least as large as the tag length set
+ *   at AEAD crypter instance construction time.
+ * - plaintext: buffer containing decrypted and authenticated data the method
+ *   produced. The buffer should not overlap with the ciphertext+tag buffer, and
+ *   pointers to those buffers should not be equal.
+ * - plaintext_length: size of plaintext buffer, which should be at least as
+ *   long as the one returned from gsec_aead_crypter_max_plaintext_length
+ *   method.
+ * - bytes_written: the actual number of bytes written to the plaintext
+ *   buffer.
+ * - error_details: a buffer containing an error message if the method does not
+ *   function correctly. It is legal to pass nullptr into error_details, and
+ *   otherwise, the parameter should be freed with gpr_free.
+ *
+ * On the success of decryption, the method returns GRPC_STATUS_OK. Otherwise,
+ * it returns an error status code along with its details specified in
+ * error_details (if error_details is not nullptr).
+ */
+grpc_status_code gsec_aead_crypter_decrypt(
+    gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length,
+    const uint8_t* aad, size_t aad_length, const uint8_t* ciphertext_and_tag,
+    size_t ciphertext_and_tag_length, uint8_t* plaintext,
+    size_t plaintext_length, size_t* bytes_written, char** error_details);
+
+/**
+ * This method performs an AEAD decrypt operation.
+ *
+ * - crypter: AEAD crypter instance.
+ * - nonce: buffer containing a nonce with its size equal to nonce_length.
+ * - nonce_length: size of nonce buffer, and must be equal to the value returned
+ *   from method gsec_aead_crypter_nonce_length.
+ * - aad_vec: an iovec array containing data that needs to be authenticated but
+ *   not encrypted.
+ * - aad_vec_length: the array length of aad_vec.
+ * - ciphertext_vec: an iovec array containing the ciphertext and tag.
+ * - ciphertext_vec_length: the array length of ciphertext_vec.
+ * - plaintext_vec: an iovec containing a plaintext buffer. The buffer should
+ *   not overlap the ciphertext buffer.
+ * - plaintext_bytes_written: the actual number of bytes written to
+ *   plaintext_vec.
+ * - error_details: a buffer containing an error message if the method does not
+ *   function correctly. It is legal to pass nullptr into error_details, and
+ *   otherwise, the parameter should be freed with gpr_free.
+ *
+ * On the success of decryption, the method returns GRPC_STATUS_OK. Otherwise,
+ * it returns an error status code along with its details specified in
+ * error_details (if error_details is not nullptr).
+ */
+grpc_status_code gsec_aead_crypter_decrypt_iovec(
+    gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length,
+    const struct iovec* aad_vec, size_t aad_vec_length,
+    const struct iovec* ciphertext_vec, size_t ciphertext_vec_length,
+    struct iovec plaintext_vec, size_t* plaintext_bytes_written,
+    char** error_details);
+
+/**
+ * This method computes the size of ciphertext+tag buffer that must be passed to
+ * gsec_aead_crypter_encrypt function to ensure correct encryption of a
+ * plaintext. The actual size of ciphertext+tag written to the buffer could be
+ * smaller.
+ *
+ * - crypter: AEAD crypter instance.
+ * - plaintext_length: length of plaintext.
+ * - max_ciphertext_and_tag_length_to_return: the size of ciphertext+tag buffer
+ *   the method returns.
+ * - error_details: a buffer containing an error message if the method does not
+ *   function correctly. It is legal to pass nullptr into error_details, and
+ *   otherwise, the parameter should be freed with gpr_free.
+ *
+ * On the success of execution, the method returns GRPC_STATUS_OK. Otherwise,
+ * it returns an error status code along with its details specified in
+ * error_details (if error_details is not nullptr).
+ */
+grpc_status_code gsec_aead_crypter_max_ciphertext_and_tag_length(
+    const gsec_aead_crypter* crypter, size_t plaintext_length,
+    size_t* max_ciphertext_and_tag_length_to_return, char** error_details);
+
+/**
+ * This method computes the size of plaintext buffer that must be passed to
+ * gsec_aead_crypter_decrypt function to ensure correct decryption of a
+ * ciphertext. The actual size of plaintext written to the buffer could be
+ * smaller.
+ *
+ * - crypter: AEAD crypter instance.
+ * - ciphertext_and_tag_length: length of ciphertext and tag.
+ * - max_plaintext_length_to_return: the size of plaintext buffer the method
+ *   returns.
+ * - error_details: a buffer containing an error message if the method does not
+ *   function correctly. It is legal to pass nullptr into error_details, and
+ *   otherwise, the parameter should be freed with gpr_free.
+ *
+ * On the success of execution, the method returns GRPC_STATUS_OK. Otherwise,
+ * it returns an error status code along with its details specified in
+ * error_details (if error_details is not nullptr).
+ */
+grpc_status_code gsec_aead_crypter_max_plaintext_length(
+    const gsec_aead_crypter* crypter, size_t ciphertext_and_tag_length,
+    size_t* max_plaintext_length_to_return, char** error_details);
+
+/**
+ * This method returns a valid size of nonce array used at the construction of
+ * AEAD crypter instance. It is also the size that should be passed to encrypt
+ * and decrypt methods executed on the instance.
+ *
+ * - crypter: AEAD crypter instance.
+ * - nonce_length_to_return: the length of nonce array the method returns.
+ * - error_details: a buffer containing an error message if the method does not
+ *   function correctly. It is legal to pass nullptr into error_details, and
+ *   otherwise, the parameter should be freed with gpr_free.
+ *
+ * On the success of execution, the method returns GRPC_STATUS_OK. Otherwise,
+ * it returns an error status code along with its details specified in
+ * error_details (if error_details is not nullptr).
+ */
+grpc_status_code gsec_aead_crypter_nonce_length(
+    const gsec_aead_crypter* crypter, size_t* nonce_length_to_return,
+    char** error_details);
+
+/**
+ * This method returns a valid size of key array used at the construction of
+ * AEAD crypter instance. It is also the size that should be passed to encrypt
+ * and decrypt methods executed on the instance.
+ *
+ * - crypter: AEAD crypter instance.
+ * - key_length_to_return: the length of key array the method returns.
+ * - error_details: a buffer containing an error message if the method does not
+ *   function correctly. It is legal to pass nullptr into error_details, and
+ *   otherwise, the parameter should be freed with gpr_free.
+ *
+ * On the success of execution, the method returns GRPC_STATUS_OK. Otherwise,
+ * it returns an error status code along with its details specified in
+ * error_details (if error_details is not nullptr).
+ */
+grpc_status_code gsec_aead_crypter_key_length(const gsec_aead_crypter* crypter,
+                                              size_t* key_length_to_return,
+                                              char** error_details);
+/**
+ * This method returns a valid size of tag array used at the construction of
+ * AEAD crypter instance. It is also the size that should be passed to encrypt
+ * and decrypt methods executed on the instance.
+ *
+ * - crypter: AEAD crypter instance.
+ * - tag_length_to_return: the length of tag array the method returns.
+ * - error_details: a buffer containing an error message if the method does not
+ *   function correctly. It is legal to pass nullptr into error_details, and
+ *   otherwise, the parameter should be freed with gpr_free.
+ *
+ * On the success of execution, the method returns GRPC_STATUS_OK. Otherwise,
+ * it returns an error status code along with its details specified in
+ * error_details (if error_details is not nullptr).
+ */
+grpc_status_code gsec_aead_crypter_tag_length(const gsec_aead_crypter* crypter,
+                                              size_t* tag_length_to_return,
+                                              char** error_details);
+
+/**
+ * This method destroys an AEAD crypter instance by de-allocating all of its
+ * occupied memory.
+ *
+ * - crypter: AEAD crypter instance that needs to be destroyed.
+ */
+void gsec_aead_crypter_destroy(gsec_aead_crypter* crypter);
+
+/**
+ * This method creates an AEAD crypter instance of AES-GCM encryption scheme
+ * which supports 16 and 32 bytes long keys, 12 and 16 bytes long nonces, and
+ * 16 bytes long tags. It should be noted that once the lengths of key, nonce,
+ * and tag are determined at construction time, they cannot be modified later.
+ *
+ * - key: buffer containing a key which is binded with AEAD crypter instance.
+ * - key_length: length of a key in bytes, which should be 44 if rekeying is
+ *   enabled and 16 or 32 otherwise.
+ * - nonce_length: length of a nonce in bytes, which should be either 12 or 16.
+ * - tag_length: length of a tag in bytes, which should be always 16.
+ * - rekey: enable nonce-based rekeying and nonce-masking.
+ * - crypter: address of AES_GCM crypter instance returned from the method.
+ * - error_details: a buffer containing an error message if the method does not
+ *   function correctly. It is legal to pass nullptr into error_details, and
+ *   otherwise, the parameter should be freed with gpr_free.
+ *
+ * On success of instance creation, it stores the address of instance at
+ * crypter. Otherwise, it returns an error status code together with its details
+ * specified in error_details.
+ */
+grpc_status_code gsec_aes_gcm_aead_crypter_create(const uint8_t* key,
+                                                  size_t key_length,
+                                                  size_t nonce_length,
+                                                  size_t tag_length, bool rekey,
+                                                  gsec_aead_crypter** crypter,
+                                                  char** error_details);
+
+#endif /* GRPC_CORE_TSI_ALTS_CRYPT_GSEC_H */
diff --git a/src/core/tsi/alts/frame_protector/alts_counter.cc b/src/core/tsi/alts/frame_protector/alts_counter.cc
new file mode 100644
index 0000000..de163e3
--- /dev/null
+++ b/src/core/tsi/alts/frame_protector/alts_counter.cc
@@ -0,0 +1,118 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/frame_protector/alts_counter.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+
+static void maybe_copy_error_msg(const char* src, char** dst) {
+  if (dst != nullptr && src != nullptr) {
+    *dst = static_cast<char*>(gpr_malloc(strlen(src) + 1));
+    memcpy(*dst, src, strlen(src) + 1);
+  }
+}
+
+grpc_status_code alts_counter_create(bool is_client, size_t counter_size,
+                                     size_t overflow_size,
+                                     alts_counter** crypter_counter,
+                                     char** error_details) {
+  /* Perform input sanity check. */
+  if (counter_size == 0) {
+    const char error_msg[] = "counter_size is invalid.";
+    maybe_copy_error_msg(error_msg, error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  if (overflow_size == 0 || overflow_size >= counter_size) {
+    const char error_msg[] = "overflow_size is invalid.";
+    maybe_copy_error_msg(error_msg, error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  if (crypter_counter == nullptr) {
+    const char error_msg[] = "crypter_counter is nullptr.";
+    maybe_copy_error_msg(error_msg, error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  *crypter_counter =
+      static_cast<alts_counter*>(gpr_malloc(sizeof(**crypter_counter)));
+  (*crypter_counter)->size = counter_size;
+  (*crypter_counter)->overflow_size = overflow_size;
+  (*crypter_counter)->counter =
+      static_cast<unsigned char*>(gpr_zalloc(counter_size));
+  if (is_client) {
+    ((*crypter_counter)->counter)[counter_size - 1] = 0x80;
+  }
+  return GRPC_STATUS_OK;
+}
+
+grpc_status_code alts_counter_increment(alts_counter* crypter_counter,
+                                        bool* is_overflow,
+                                        char** error_details) {
+  /* Perform input sanity check. */
+  if (crypter_counter == nullptr) {
+    const char error_msg[] = "crypter_counter is nullptr.";
+    maybe_copy_error_msg(error_msg, error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  if (is_overflow == nullptr) {
+    const char error_msg[] = "is_overflow is nullptr.";
+    maybe_copy_error_msg(error_msg, error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  /* Increment the internal counter. */
+  size_t i = 0;
+  for (; i < crypter_counter->overflow_size; i++) {
+    (crypter_counter->counter)[i]++;
+    if ((crypter_counter->counter)[i] != 0x00) {
+      break;
+    }
+  }
+  /**
+   * If the lower overflow_size bytes are all zero, the counter has overflowed.
+   */
+  if (i == crypter_counter->overflow_size) {
+    *is_overflow = true;
+    return GRPC_STATUS_FAILED_PRECONDITION;
+  }
+  *is_overflow = false;
+  return GRPC_STATUS_OK;
+}
+
+size_t alts_counter_get_size(alts_counter* crypter_counter) {
+  if (crypter_counter == nullptr) {
+    return 0;
+  }
+  return crypter_counter->size;
+}
+
+unsigned char* alts_counter_get_counter(alts_counter* crypter_counter) {
+  if (crypter_counter == nullptr) {
+    return nullptr;
+  }
+  return crypter_counter->counter;
+}
+
+void alts_counter_destroy(alts_counter* crypter_counter) {
+  if (crypter_counter != nullptr) {
+    gpr_free(crypter_counter->counter);
+    gpr_free(crypter_counter);
+  }
+}
diff --git a/src/core/tsi/alts/frame_protector/alts_counter.h b/src/core/tsi/alts/frame_protector/alts_counter.h
new file mode 100644
index 0000000..d705638
--- /dev/null
+++ b/src/core/tsi/alts/frame_protector/alts_counter.h
@@ -0,0 +1,98 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_COUNTER_H
+#define GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_COUNTER_H
+
+#include <grpc/support/port_platform.h>
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <grpc/grpc.h>
+
+/* Main struct for a crypter counter managed within seal/unseal operations. */
+typedef struct alts_counter {
+  size_t size;
+  size_t overflow_size;
+  unsigned char* counter;
+} alts_counter;
+
+/**
+ * This method creates and initializes an alts_counter instance.
+ *
+ * - is_client: a flag indicating if the alts_counter instance will be used
+ *   at client (is_client = true) or server (is_client = false) side.
+ * - counter_size: size of buffer holding the counter value.
+ * - overflow_size: overflow size in bytes. The counter instance can be used
+ *   to produce at most 2^(overflow_size*8) frames.
+ * - crypter_counter: an alts_counter instance to be returned from the method.
+ * - error_details: a buffer containing an error message if the method does not
+ *   function correctly. It is legal to pass nullptr into error_details and
+ *   otherwise, the parameter should be freed with gpr_free.
+ *
+ * On success, the method returns GRPC_STATUS_OK. Otherwise,
+ * it returns an error status code along with its details specified in
+ * error_details (if error_details is not nullptr).
+ */
+grpc_status_code alts_counter_create(bool is_client, size_t counter_size,
+                                     size_t overflow_size,
+                                     alts_counter** crypter_counter,
+                                     char** error_details);
+
+/**
+ * This method increments the internal counter.
+ *
+ * - crypter_counter: an alts_counter instance.
+ * - is_overflow: after incrementing the internal counter, if an overflow
+ *   occurs, is_overflow is set to true, and no further calls to
+ *   alts_counter_increment() should be made. Otherwise, is_overflow is set to
+ *   false.
+ * - error_details: a buffer containing an error message if the method does not
+ *   function correctly. It is legal to pass nullptr into error_details and
+ *   otherwise, the parameter should be freed with gpr_free.
+ *
+ * On success, the method returns GRPC_STATUS_OK. Otherwise,
+ * it returns an error status code along with its details specified in
+ * error_details (if error_details is not nullptr).
+ */
+grpc_status_code alts_counter_increment(alts_counter* crypter_counter,
+                                        bool* is_overflow,
+                                        char** error_details);
+
+/**
+ * This method returns the size of counter buffer.
+ *
+ * - crypter_counter: an alts_counter instance.
+ */
+size_t alts_counter_get_size(alts_counter* crypter_counter);
+
+/**
+ * This method returns the counter buffer.
+ *
+ * - crypter_counter: an alts_counter instance.
+ */
+unsigned char* alts_counter_get_counter(alts_counter* crypter_counter);
+
+/**
+ * This method de-allocates all memory allocated to an alts_coutner instance.
+ * - crypter_counter: an alts_counter instance.
+ */
+void alts_counter_destroy(alts_counter* crypter_counter);
+
+#endif /* GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_COUNTER_H */
diff --git a/src/core/tsi/alts/frame_protector/alts_crypter.cc b/src/core/tsi/alts/frame_protector/alts_crypter.cc
new file mode 100644
index 0000000..56f0512
--- /dev/null
+++ b/src/core/tsi/alts/frame_protector/alts_crypter.cc
@@ -0,0 +1,66 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/frame_protector/alts_crypter.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+
+static void maybe_copy_error_msg(const char* src, char** dst) {
+  if (dst != nullptr && src != nullptr) {
+    *dst = static_cast<char*>(gpr_malloc(strlen(src) + 1));
+    memcpy(*dst, src, strlen(src) + 1);
+  }
+}
+
+grpc_status_code alts_crypter_process_in_place(
+    alts_crypter* crypter, unsigned char* data, size_t data_allocated_size,
+    size_t data_size, size_t* output_size, char** error_details) {
+  if (crypter != nullptr && crypter->vtable != nullptr &&
+      crypter->vtable->process_in_place != nullptr) {
+    return crypter->vtable->process_in_place(crypter, data, data_allocated_size,
+                                             data_size, output_size,
+                                             error_details);
+  }
+  /* An error occurred. */
+  const char error_msg[] =
+      "crypter or crypter->vtable has not been initialized properly.";
+  maybe_copy_error_msg(error_msg, error_details);
+  return GRPC_STATUS_INVALID_ARGUMENT;
+}
+
+size_t alts_crypter_num_overhead_bytes(const alts_crypter* crypter) {
+  if (crypter != nullptr && crypter->vtable != nullptr &&
+      crypter->vtable->num_overhead_bytes != nullptr) {
+    return crypter->vtable->num_overhead_bytes(crypter);
+  }
+  /* An error occurred. */
+  return 0;
+}
+
+void alts_crypter_destroy(alts_crypter* crypter) {
+  if (crypter != nullptr) {
+    if (crypter->vtable != nullptr && crypter->vtable->destruct != nullptr) {
+      crypter->vtable->destruct(crypter);
+    }
+    gpr_free(crypter);
+  }
+}
diff --git a/src/core/tsi/alts/frame_protector/alts_crypter.h b/src/core/tsi/alts/frame_protector/alts_crypter.h
new file mode 100644
index 0000000..3140778
--- /dev/null
+++ b/src/core/tsi/alts/frame_protector/alts_crypter.h
@@ -0,0 +1,255 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_CRYPTER_H
+#define GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_CRYPTER_H
+
+#include <grpc/support/port_platform.h>
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <grpc/grpc.h>
+
+#include "src/core/tsi/alts/crypt/gsec.h"
+
+/**
+ * An alts_crypter interface for an ALTS record protocol providing
+ * seal/unseal functionality. The interface is thread-compatible.
+ */
+
+typedef struct alts_crypter alts_crypter;
+
+/**
+ * A typical usage of the interface would be
+ *------------------------------------------------------------------------------
+ * // Perform a seal operation. We assume the gsec_aead_crypter instance -
+ * // client_aead_crypter is created beforehand with a 16-byte key and 12-byte
+ * // nonce length.
+ *
+ * alts_crypter* client = nullptr;
+ * char* client_error_in_creation = nullptr;
+ * unsigned char* data = nullptr;
+ * grpc_status_code client_status =
+ *                 alts_seal_crypter_create(client_aead_crypter, 1, 5, &client,
+ *                                          &client_error_in_creation);
+ * if (client_status == GRPC_STATUS_OK) {
+ *   size_t data_size = 100;
+ *   size_t num_overhead_bytes = alts_crypter_num_overhead_bytes(client);
+ *   size_t data_allocated_size = data_size + num_overhead_bytes;
+ *   data = gpr_malloc(data_allocated_size);
+ *   char* client_error_in_seal = nullptr;
+ *   // Client performs a seal operation.
+ *   client_status = alts_crypter_process_in_place(client, data,
+ *                                                 data_allocated_size,
+ *                                                 &data_size,
+ *                                                 &client_error_in_seal);
+ *   if (client_status != GRPC_STATUS_OK) {
+ *     fprintf(stderr, "seal operation failed with error code:"
+ *                     "%d, message: %s\n", client_status,
+ *                      client_error_in_seal);
+ *    }
+ *    gpr_free(client_error_in_seal);
+ * } else {
+ *     fprintf(stderr, "alts_crypter instance creation failed with error"
+ *                     "code: %d, message: %s\n", client_status,
+ *                      client_error_in_creation);
+ * }
+ *
+ * ...
+ *
+ * gpr_free(client_error_in_creation);
+ * alts_crypter_destroy(client);
+ *
+ * ...
+ *
+ * // Perform an unseal operation. We assume the gsec_aead_crypter instance -
+ * // server_aead_crypter is created beforehand with a 16-byte key and 12-byte
+ * // nonce length. The key used in the creation of gsec_aead_crypter instances
+ * // at server and client sides should be identical.
+ *
+ * alts_crypter* server = nullptr;
+ * char* server_error_in_creation = nullptr;
+ * grpc_status_code server_status =
+ *               alts_unseal_crypter_create(server_aead_crypter, 0, 5, &server,
+ *                                          &server_error_in_creation);
+ * if (server_status == GRPC_STATUS_OK) {
+ *   size_t num_overhead_bytes = alts_crypter_num_overhead_bytes(server);
+ *   size_t data_size = 100 + num_overhead_bytes;
+ *   size_t data_allocated_size = data_size;
+ *   char* server_error_in_unseal = nullptr;
+ *   // Server performs an unseal operation.
+ *   server_status = alts_crypter_process_in_place(server, data,
+ *                                                 data_allocated_size,
+ *                                                 &data_size,
+ *                                                 &server_error_in_unseal);
+ *   if (server_status != GRPC_STATUS_OK) {
+ *     fprintf(stderr, "unseal operation failed with error code:"
+ *                     "%d, message: %s\n", server_status,
+ *                      server_error_in_unseal);
+ *   }
+ *   gpr_free(server_error_in_unseal);
+ * } else {
+ *     fprintf(stderr, "alts_crypter instance creation failed with error"
+ *                     "code: %d, message: %s\n", server_status,
+ *                      server_error_in_creation);
+ * }
+ *
+ * ...
+ *
+ * gpr_free(data);
+ * gpr_free(server_error_in_creation);
+ * alts_crypter_destroy(server);
+ *
+ * ...
+ *------------------------------------------------------------------------------
+ */
+
+/* V-table for alts_crypter operations */
+typedef struct alts_crypter_vtable {
+  size_t (*num_overhead_bytes)(const alts_crypter* crypter);
+  grpc_status_code (*process_in_place)(alts_crypter* crypter,
+                                       unsigned char* data,
+                                       size_t data_allocated_size,
+                                       size_t data_size, size_t* output_size,
+                                       char** error_details);
+  void (*destruct)(alts_crypter* crypter);
+} alts_crypter_vtable;
+
+/* Main struct for alts_crypter interface */
+struct alts_crypter {
+  const alts_crypter_vtable* vtable;
+};
+
+/**
+ * This method gets the number of overhead bytes needed for sealing data that
+ * is the difference in size between the protected and raw data. The counter
+ * value used in a seal or unseal operation is locally maintained (not sent or
+ * received from the other peer) and therefore, will not be counted as part of
+ * overhead bytes.
+ *
+ * - crypter: an alts_crypter instance.
+ *
+ * On success, the method returns the number of overhead bytes. Otherwise, it
+ * returns zero.
+ *
+ */
+size_t alts_crypter_num_overhead_bytes(const alts_crypter* crypter);
+
+/**
+ * This method performs either a seal or an unseal operation depending on the
+ * alts_crypter instance - crypter passed to the method. If the crypter is
+ * an instance implementing a seal operation, the method will perform a seal
+ * operation. That is, it seals raw data and stores the result in-place, and the
+ * memory allocated for data must be at least data_length +
+ * alts_crypter_num_overhead_bytes(). If the crypter is an instance
+ * implementing an unseal operation, the method will perform an unseal
+ * operation. That is, it unseals protected data and stores the result in-place.
+ * The size of unsealed data will be data_length -
+ * alts_crypter_num_overhead_bytes(). Integrity tag will be verified during
+ * the unseal operation, and if verification fails, the data will be wiped.
+ * The counters used in both seal and unseal operations are managed internally.
+ *
+ * - crypter: an alts_crypter instance.
+ * - data: if the method performs a seal operation, the data represents raw data
+ *   that needs to be sealed. It also plays the role of buffer to hold the
+ *   protected data as a result of seal. If the method performs an unseal
+ *   operation, the data represents protected data that needs to be unsealed. It
+ *   also plays the role of buffer to hold raw data as a result of unseal.
+ * - data_allocated_size: the size of data buffer. The parameter is used to
+ *   check whether the result of either seal or unseal can be safely written to
+ *   the data buffer.
+ * - data_size: if the method performs a seal operation, data_size
+ *   represents the size of raw data that needs to be sealed, and if the method
+ *   performs an unseal operation, data_size represents the size of protected
+ *   data that needs to be unsealed.
+ * - output_size: size of data written to the data buffer after a seal or an
+ *   unseal operation.
+ * - error_details: a buffer containing an error message if the method does not
+ *   function correctly. It is legal to pass nullptr into error_details and
+ *   otherwise, the parameter should be freed with gpr_free.
+ *
+ * On success, the method returns GRPC_STATUS_OK. Otherwise,
+ * it returns an error status code along with its details specified in
+ * error_details (if error_details is not nullptr).
+ */
+grpc_status_code alts_crypter_process_in_place(
+    alts_crypter* crypter, unsigned char* data, size_t data_allocated_size,
+    size_t data_size, size_t* output_size, char** error_details);
+
+/**
+ * This method creates an alts_crypter instance to be used to perform a seal
+ * operation, given a gsec_aead_crypter instance and a flag indicating if the
+ * created instance will be used at the client or server side. It takes
+ * ownership of gsec_aead_crypter instance.
+ *
+ * - gc: a gsec_aead_crypter instance used to perform AEAD encryption.
+ * - is_client: a flag indicating if the alts_crypter instance will be
+ *   used at the client (is_client = true) or server (is_client =
+ *   false) side.
+ * - overflow_size: overflow size of counter in bytes.
+ * - crypter: an alts_crypter instance to be returned from the method.
+ * - error_details: a buffer containing an error message if the method does
+ *   not function correctly. It is legal to pass nullptr into error_details, and
+ *   otherwise, the parameter should be freed with gpr_free.
+ *
+ * On success of creation, the method returns GRPC_STATUS_OK.
+ * Otherwise, it returns an error status code along with its details specified
+ * in error_details (if error_details is not nullptr).
+ */
+grpc_status_code alts_seal_crypter_create(gsec_aead_crypter* gc, bool is_client,
+                                          size_t overflow_size,
+                                          alts_crypter** crypter,
+                                          char** error_details);
+
+/**
+ * This method creates an alts_crypter instance used to perform an unseal
+ * operation, given a gsec_aead_crypter instance and a flag indicating if the
+ * created instance will be used at the client or server side. It takes
+ * ownership of gsec_aead_crypter instance.
+ *
+ * - gc: a gsec_aead_crypter instance used to perform AEAD decryption.
+ * - is_client: a flag indicating if the alts_crypter instance will be
+ *   used at the client (is_client = true) or server (is_client =
+ *   false) side.
+ * - overflow_size: overflow size of counter in bytes.
+ * - crypter: an alts_crypter instance to be returned from the method.
+ * - error_details: a buffer containing an error message if the method does
+ *   not function correctly. It is legal to pass nullptr into error_details, and
+ *   otherwise, the parameter should be freed with gpr_free.
+ *
+ * On success of creation, the method returns GRPC_STATUS_OK.
+ * Otherwise, it returns an error status code along with its details specified
+ * in error_details (if error_details is not nullptr).
+ */
+grpc_status_code alts_unseal_crypter_create(gsec_aead_crypter* gc,
+                                            bool is_client,
+                                            size_t overflow_size,
+                                            alts_crypter** crypter,
+                                            char** error_details);
+
+/**
+ * This method destroys an alts_crypter instance by de-allocating all of its
+ * occupied memory. A gsec_aead_crypter instance passed in at alts_crypter
+ * instance creation time will be destroyed in this method.
+ *
+ * - crypter: an alts_crypter instance.
+ */
+void alts_crypter_destroy(alts_crypter* crypter);
+
+#endif /* GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_CRYPTER_H */
diff --git a/src/core/tsi/alts/frame_protector/alts_frame_protector.cc b/src/core/tsi/alts/frame_protector/alts_frame_protector.cc
new file mode 100644
index 0000000..bfa0b7a
--- /dev/null
+++ b/src/core/tsi/alts/frame_protector/alts_frame_protector.cc
@@ -0,0 +1,407 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/frame_protector/alts_frame_protector.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/tsi/alts/crypt/gsec.h"
+#include "src/core/tsi/alts/frame_protector/alts_crypter.h"
+#include "src/core/tsi/alts/frame_protector/frame_handler.h"
+#include "src/core/tsi/transport_security.h"
+
+constexpr size_t kMinFrameLength = 1024;
+constexpr size_t kDefaultFrameLength = 16 * 1024;
+constexpr size_t kMaxFrameLength = 1024 * 1024;
+
+// Limit k on number of frames such that at most 2^(8 * k) frames can be sent.
+constexpr size_t kAltsRecordProtocolRekeyFrameLimit = 8;
+constexpr size_t kAltsRecordProtocolFrameLimit = 5;
+
+/* Main struct for alts_frame_protector. */
+struct alts_frame_protector {
+  tsi_frame_protector base;
+  alts_crypter* seal_crypter;
+  alts_crypter* unseal_crypter;
+  alts_frame_writer* writer;
+  alts_frame_reader* reader;
+  unsigned char* in_place_protect_buffer;
+  unsigned char* in_place_unprotect_buffer;
+  size_t in_place_protect_bytes_buffered;
+  size_t in_place_unprotect_bytes_processed;
+  size_t max_protected_frame_size;
+  size_t max_unprotected_frame_size;
+  size_t overhead_length;
+  size_t counter_overflow;
+};
+
+static tsi_result seal(alts_frame_protector* impl) {
+  char* error_details = nullptr;
+  size_t output_size = 0;
+  grpc_status_code status = alts_crypter_process_in_place(
+      impl->seal_crypter, impl->in_place_protect_buffer,
+      impl->max_protected_frame_size, impl->in_place_protect_bytes_buffered,
+      &output_size, &error_details);
+  impl->in_place_protect_bytes_buffered = output_size;
+  if (status != GRPC_STATUS_OK) {
+    gpr_log(GPR_ERROR, "%s", error_details);
+    gpr_free(error_details);
+    return TSI_INTERNAL_ERROR;
+  }
+  return TSI_OK;
+}
+
+static size_t max_encrypted_payload_bytes(alts_frame_protector* impl) {
+  return impl->max_protected_frame_size - kFrameHeaderSize;
+}
+
+static tsi_result alts_protect_flush(tsi_frame_protector* self,
+                                     unsigned char* protected_output_frames,
+                                     size_t* protected_output_frames_size,
+                                     size_t* still_pending_size) {
+  if (self == nullptr || protected_output_frames == nullptr ||
+      protected_output_frames_size == nullptr ||
+      still_pending_size == nullptr) {
+    gpr_log(GPR_ERROR, "Invalid nullptr arguments to alts_protect_flush().");
+    return TSI_INVALID_ARGUMENT;
+  }
+  alts_frame_protector* impl = reinterpret_cast<alts_frame_protector*>(self);
+  /**
+   * If there's nothing to flush (i.e., in_place_protect_buffer is empty),
+   * we're done.
+   */
+  if (impl->in_place_protect_bytes_buffered == 0) {
+    *protected_output_frames_size = 0;
+    *still_pending_size = 0;
+    return TSI_OK;
+  }
+  /**
+   * If a new frame can start being processed, we encrypt the payload and reset
+   * the frame writer to point to in_place_protect_buffer that holds the newly
+   * sealed frame.
+   */
+  if (alts_is_frame_writer_done(impl->writer)) {
+    tsi_result result = seal(impl);
+    if (result != TSI_OK) {
+      return result;
+    }
+    if (!alts_reset_frame_writer(impl->writer, impl->in_place_protect_buffer,
+                                 impl->in_place_protect_bytes_buffered)) {
+      gpr_log(GPR_ERROR, "Couldn't reset frame writer.");
+      return TSI_INTERNAL_ERROR;
+    }
+  }
+  /**
+   * Write the sealed frame as much as possible to protected_output_frames. It's
+   * possible a frame will not be written out completely by a single flush
+   * (i.e., still_pending_size != 0), in which case the flush should be called
+   * iteratively until a complete frame has been written out.
+   */
+  size_t written_frame_bytes = *protected_output_frames_size;
+  if (!alts_write_frame_bytes(impl->writer, protected_output_frames,
+                              &written_frame_bytes)) {
+    gpr_log(GPR_ERROR, "Couldn't write frame bytes.");
+    return TSI_INTERNAL_ERROR;
+  }
+  *protected_output_frames_size = written_frame_bytes;
+  *still_pending_size = alts_get_num_writer_bytes_remaining(impl->writer);
+  /**
+   * If the current frame has been finished processing (i.e., sealed and written
+   * out completely), we empty in_place_protect_buffer.
+   */
+  if (alts_is_frame_writer_done(impl->writer)) {
+    impl->in_place_protect_bytes_buffered = 0;
+  }
+  return TSI_OK;
+}
+
+static tsi_result alts_protect(tsi_frame_protector* self,
+                               const unsigned char* unprotected_bytes,
+                               size_t* unprotected_bytes_size,
+                               unsigned char* protected_output_frames,
+                               size_t* protected_output_frames_size) {
+  if (self == nullptr || unprotected_bytes == nullptr ||
+      unprotected_bytes_size == nullptr || protected_output_frames == nullptr ||
+      protected_output_frames_size == nullptr) {
+    gpr_log(GPR_ERROR, "Invalid nullptr arguments to alts_protect().");
+    return TSI_INVALID_ARGUMENT;
+  }
+  alts_frame_protector* impl = reinterpret_cast<alts_frame_protector*>(self);
+
+  /**
+   * If more payload can be buffered, we buffer it as much as possible to
+   * in_place_protect_buffer.
+   */
+  if (impl->in_place_protect_bytes_buffered + impl->overhead_length <
+      max_encrypted_payload_bytes(impl)) {
+    size_t bytes_to_buffer = GPR_MIN(*unprotected_bytes_size,
+                                     max_encrypted_payload_bytes(impl) -
+                                         impl->in_place_protect_bytes_buffered -
+                                         impl->overhead_length);
+    *unprotected_bytes_size = bytes_to_buffer;
+    if (bytes_to_buffer > 0) {
+      memcpy(
+          impl->in_place_protect_buffer + impl->in_place_protect_bytes_buffered,
+          unprotected_bytes, bytes_to_buffer);
+      impl->in_place_protect_bytes_buffered += bytes_to_buffer;
+    }
+  } else {
+    *unprotected_bytes_size = 0;
+  }
+  /**
+   * If a full frame has been buffered, we output it. If the first condition
+   * holds, then there exists an unencrypted full frame. If the second
+   * condition holds, then there exists a full frame that has already been
+   * encrypted.
+   */
+  if (max_encrypted_payload_bytes(impl) ==
+          impl->in_place_protect_bytes_buffered + impl->overhead_length ||
+      max_encrypted_payload_bytes(impl) ==
+          impl->in_place_protect_bytes_buffered) {
+    size_t still_pending_size = 0;
+    return alts_protect_flush(self, protected_output_frames,
+                              protected_output_frames_size,
+                              &still_pending_size);
+  } else {
+    *protected_output_frames_size = 0;
+    return TSI_OK;
+  }
+}
+
+static tsi_result unseal(alts_frame_protector* impl) {
+  char* error_details = nullptr;
+  size_t output_size = 0;
+  grpc_status_code status = alts_crypter_process_in_place(
+      impl->unseal_crypter, impl->in_place_unprotect_buffer,
+      impl->max_unprotected_frame_size,
+      alts_get_output_bytes_read(impl->reader), &output_size, &error_details);
+  if (status != GRPC_STATUS_OK) {
+    gpr_log(GPR_ERROR, "%s", error_details);
+    gpr_free(error_details);
+    return TSI_DATA_CORRUPTED;
+  }
+  return TSI_OK;
+}
+
+static void ensure_buffer_size(alts_frame_protector* impl) {
+  if (!alts_has_read_frame_length(impl->reader)) {
+    return;
+  }
+  size_t buffer_space_remaining = impl->max_unprotected_frame_size -
+                                  alts_get_output_bytes_read(impl->reader);
+  /**
+   * Check if we need to resize in_place_unprotect_buffer in order to hold
+   * remaining bytes of a full frame.
+   */
+  if (buffer_space_remaining < alts_get_reader_bytes_remaining(impl->reader)) {
+    size_t buffer_len = alts_get_output_bytes_read(impl->reader) +
+                        alts_get_reader_bytes_remaining(impl->reader);
+    unsigned char* buffer = static_cast<unsigned char*>(gpr_malloc(buffer_len));
+    memcpy(buffer, impl->in_place_unprotect_buffer,
+           alts_get_output_bytes_read(impl->reader));
+    impl->max_unprotected_frame_size = buffer_len;
+    gpr_free(impl->in_place_unprotect_buffer);
+    impl->in_place_unprotect_buffer = buffer;
+    alts_reset_reader_output_buffer(
+        impl->reader, buffer + alts_get_output_bytes_read(impl->reader));
+  }
+}
+
+static tsi_result alts_unprotect(tsi_frame_protector* self,
+                                 const unsigned char* protected_frames_bytes,
+                                 size_t* protected_frames_bytes_size,
+                                 unsigned char* unprotected_bytes,
+                                 size_t* unprotected_bytes_size) {
+  if (self == nullptr || protected_frames_bytes == nullptr ||
+      protected_frames_bytes_size == nullptr || unprotected_bytes == nullptr ||
+      unprotected_bytes_size == nullptr) {
+    gpr_log(GPR_ERROR, "Invalid nullptr arguments to alts_unprotect().");
+    return TSI_INVALID_ARGUMENT;
+  }
+  alts_frame_protector* impl = reinterpret_cast<alts_frame_protector*>(self);
+  /**
+   * If a new frame can start being processed, we reset the frame reader to
+   * point to in_place_unprotect_buffer that will be used to hold deframed
+   * result.
+   */
+  if (alts_is_frame_reader_done(impl->reader) &&
+      ((alts_get_output_buffer(impl->reader) == nullptr) ||
+       (alts_get_output_bytes_read(impl->reader) ==
+        impl->in_place_unprotect_bytes_processed + impl->overhead_length))) {
+    if (!alts_reset_frame_reader(impl->reader,
+                                 impl->in_place_unprotect_buffer)) {
+      gpr_log(GPR_ERROR, "Couldn't reset frame reader.");
+      return TSI_INTERNAL_ERROR;
+    }
+    impl->in_place_unprotect_bytes_processed = 0;
+  }
+  /**
+   * If a full frame has not yet been read, we read more bytes from
+   * protected_frames_bytes until a full frame has been read. We also need to
+   * make sure in_place_unprotect_buffer is large enough to hold a complete
+   * frame.
+   */
+  if (!alts_is_frame_reader_done(impl->reader)) {
+    ensure_buffer_size(impl);
+    *protected_frames_bytes_size =
+        GPR_MIN(impl->max_unprotected_frame_size -
+                    alts_get_output_bytes_read(impl->reader),
+                *protected_frames_bytes_size);
+    size_t read_frames_bytes_size = *protected_frames_bytes_size;
+    if (!alts_read_frame_bytes(impl->reader, protected_frames_bytes,
+                               &read_frames_bytes_size)) {
+      gpr_log(GPR_ERROR, "Failed to process frame.");
+      return TSI_INTERNAL_ERROR;
+    }
+    *protected_frames_bytes_size = read_frames_bytes_size;
+  } else {
+    *protected_frames_bytes_size = 0;
+  }
+  /**
+   * If a full frame has been read, we unseal it, and write out the
+   * deframed result to unprotected_bytes.
+   */
+  if (alts_is_frame_reader_done(impl->reader)) {
+    if (impl->in_place_unprotect_bytes_processed == 0) {
+      tsi_result result = unseal(impl);
+      if (result != TSI_OK) {
+        return result;
+      }
+    }
+    size_t bytes_to_write = GPR_MIN(
+        *unprotected_bytes_size, alts_get_output_bytes_read(impl->reader) -
+                                     impl->in_place_unprotect_bytes_processed -
+                                     impl->overhead_length);
+    if (bytes_to_write > 0) {
+      memcpy(unprotected_bytes,
+             impl->in_place_unprotect_buffer +
+                 impl->in_place_unprotect_bytes_processed,
+             bytes_to_write);
+    }
+    *unprotected_bytes_size = bytes_to_write;
+    impl->in_place_unprotect_bytes_processed += bytes_to_write;
+    return TSI_OK;
+  } else {
+    *unprotected_bytes_size = 0;
+    return TSI_OK;
+  }
+}
+
+static void alts_destroy(tsi_frame_protector* self) {
+  alts_frame_protector* impl = reinterpret_cast<alts_frame_protector*>(self);
+  if (impl != nullptr) {
+    alts_crypter_destroy(impl->seal_crypter);
+    alts_crypter_destroy(impl->unseal_crypter);
+    gpr_free(impl->in_place_protect_buffer);
+    gpr_free(impl->in_place_unprotect_buffer);
+    alts_destroy_frame_writer(impl->writer);
+    alts_destroy_frame_reader(impl->reader);
+    gpr_free(impl);
+  }
+}
+
+static const tsi_frame_protector_vtable alts_frame_protector_vtable = {
+    alts_protect, alts_protect_flush, alts_unprotect, alts_destroy};
+
+static grpc_status_code create_alts_crypters(const uint8_t* key,
+                                             size_t key_size, bool is_client,
+                                             bool is_rekey,
+                                             alts_frame_protector* impl,
+                                             char** error_details) {
+  grpc_status_code status;
+  gsec_aead_crypter* aead_crypter_seal = nullptr;
+  gsec_aead_crypter* aead_crypter_unseal = nullptr;
+  status = gsec_aes_gcm_aead_crypter_create(key, key_size, kAesGcmNonceLength,
+                                            kAesGcmTagLength, is_rekey,
+                                            &aead_crypter_seal, error_details);
+  if (status != GRPC_STATUS_OK) {
+    return status;
+  }
+  status = gsec_aes_gcm_aead_crypter_create(
+      key, key_size, kAesGcmNonceLength, kAesGcmTagLength, is_rekey,
+      &aead_crypter_unseal, error_details);
+  if (status != GRPC_STATUS_OK) {
+    return status;
+  }
+  size_t overflow_size = is_rekey ? kAltsRecordProtocolRekeyFrameLimit
+                                  : kAltsRecordProtocolFrameLimit;
+  status = alts_seal_crypter_create(aead_crypter_seal, is_client, overflow_size,
+                                    &impl->seal_crypter, error_details);
+  if (status != GRPC_STATUS_OK) {
+    return status;
+  }
+  status =
+      alts_unseal_crypter_create(aead_crypter_unseal, is_client, overflow_size,
+                                 &impl->unseal_crypter, error_details);
+  return status;
+}
+
+tsi_result alts_create_frame_protector(const uint8_t* key, size_t key_size,
+                                       bool is_client, bool is_rekey,
+                                       size_t* max_protected_frame_size,
+                                       tsi_frame_protector** self) {
+  if (key == nullptr || self == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to alts_create_frame_protector().");
+    return TSI_INTERNAL_ERROR;
+  }
+  char* error_details = nullptr;
+  alts_frame_protector* impl =
+      static_cast<alts_frame_protector*>(gpr_zalloc(sizeof(*impl)));
+  grpc_status_code status = create_alts_crypters(
+      key, key_size, is_client, is_rekey, impl, &error_details);
+  if (status != GRPC_STATUS_OK) {
+    gpr_log(GPR_ERROR, "Failed to create ALTS crypters, %s.", error_details);
+    gpr_free(error_details);
+    return TSI_INTERNAL_ERROR;
+  }
+  /**
+   * Set maximum frame size to be used by a frame protector. If it is nullptr, a
+   * default frame size will be used. Otherwise, the provided frame size will be
+   * adjusted (if not falling into a valid frame range) and used.
+   */
+  size_t max_protected_frame_size_to_set = kDefaultFrameLength;
+  if (max_protected_frame_size != nullptr) {
+    *max_protected_frame_size =
+        GPR_MIN(*max_protected_frame_size, kMaxFrameLength);
+    *max_protected_frame_size =
+        GPR_MAX(*max_protected_frame_size, kMinFrameLength);
+    max_protected_frame_size_to_set = *max_protected_frame_size;
+  }
+  impl->max_protected_frame_size = max_protected_frame_size_to_set;
+  impl->max_unprotected_frame_size = max_protected_frame_size_to_set;
+  impl->in_place_protect_bytes_buffered = 0;
+  impl->in_place_unprotect_bytes_processed = 0;
+  impl->in_place_protect_buffer = static_cast<unsigned char*>(
+      gpr_malloc(sizeof(unsigned char) * max_protected_frame_size_to_set));
+  impl->in_place_unprotect_buffer = static_cast<unsigned char*>(
+      gpr_malloc(sizeof(unsigned char) * max_protected_frame_size_to_set));
+  impl->overhead_length = alts_crypter_num_overhead_bytes(impl->seal_crypter);
+  impl->writer = alts_create_frame_writer();
+  impl->reader = alts_create_frame_reader();
+  impl->base.vtable = &alts_frame_protector_vtable;
+  *self = &impl->base;
+  return TSI_OK;
+}
diff --git a/src/core/tsi/alts/frame_protector/alts_frame_protector.h b/src/core/tsi/alts/frame_protector/alts_frame_protector.h
new file mode 100644
index 0000000..321bffa
--- /dev/null
+++ b/src/core/tsi/alts/frame_protector/alts_frame_protector.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_FRAME_PROTECTOR_H
+#define GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_FRAME_PROTECTOR_H
+
+#include <grpc/support/port_platform.h>
+
+#include <stdbool.h>
+
+#include "src/core/tsi/transport_security_interface.h"
+
+typedef struct alts_frame_protector alts_frame_protector;
+
+/**
+ * TODO: Add a parameter to the interface to support the use of
+ * different record protocols within a frame protector.
+ *
+ * This method creates a frame protector.
+ *
+ * - key: a symmetric key used to seal/unseal frames.
+ * - key_size: the size of symmetric key.
+ * - is_client: a flag indicating if the frame protector will be used at client
+ *   (is_client = true) or server (is_client = false) side.
+ * - is_rekey: a flag indicating if the frame protector will use an AEAD with
+ *   rekeying.
+ * - max_protected_frame_size: an in/out parameter indicating max frame size
+ *   to be used by the frame protector. If it is nullptr, the default frame
+ *   size will be used. Otherwise, the provided frame size will be adjusted (if
+ *   not falling into a valid frame range) and used.
+ * - self: a pointer to the frame protector returned from the method.
+ *
+ * This method returns TSI_OK on success and TSI_INTERNAL_ERROR otherwise.
+ */
+tsi_result alts_create_frame_protector(const uint8_t* key, size_t key_size,
+                                       bool is_client, bool is_rekey,
+                                       size_t* max_protected_frame_size,
+                                       tsi_frame_protector** self);
+
+#endif /* GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_FRAME_PROTECTOR_H */
diff --git a/src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc b/src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc
new file mode 100644
index 0000000..0574ed5
--- /dev/null
+++ b/src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc
@@ -0,0 +1,114 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h"
+
+#include <grpc/support/alloc.h>
+
+static void maybe_copy_error_msg(const char* src, char** dst) {
+  if (dst != nullptr && src != nullptr) {
+    *dst = static_cast<char*>(gpr_malloc(strlen(src) + 1));
+    memcpy(*dst, src, strlen(src) + 1);
+  }
+}
+
+grpc_status_code input_sanity_check(
+    const alts_record_protocol_crypter* rp_crypter, const unsigned char* data,
+    size_t* output_size, char** error_details) {
+  if (rp_crypter == nullptr) {
+    maybe_copy_error_msg("alts_crypter instance is nullptr.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  } else if (data == nullptr) {
+    maybe_copy_error_msg("data is nullptr.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  } else if (output_size == nullptr) {
+    maybe_copy_error_msg("output_size is nullptr.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  return GRPC_STATUS_OK;
+}
+
+grpc_status_code increment_counter(alts_record_protocol_crypter* rp_crypter,
+                                   char** error_details) {
+  bool is_overflow = false;
+  grpc_status_code status =
+      alts_counter_increment(rp_crypter->ctr, &is_overflow, error_details);
+  if (status != GRPC_STATUS_OK) {
+    return status;
+  }
+  if (is_overflow) {
+    const char error_msg[] =
+        "crypter counter is wrapped. The connection"
+        "should be closed and the key should be deleted.";
+    maybe_copy_error_msg(error_msg, error_details);
+    return GRPC_STATUS_INTERNAL;
+  }
+  return GRPC_STATUS_OK;
+}
+
+size_t alts_record_protocol_crypter_num_overhead_bytes(const alts_crypter* c) {
+  if (c != nullptr) {
+    size_t num_overhead_bytes = 0;
+    char* error_details = nullptr;
+    const alts_record_protocol_crypter* rp_crypter =
+        reinterpret_cast<const alts_record_protocol_crypter*>(c);
+    grpc_status_code status = gsec_aead_crypter_tag_length(
+        rp_crypter->crypter, &num_overhead_bytes, &error_details);
+    if (status == GRPC_STATUS_OK) {
+      return num_overhead_bytes;
+    }
+  }
+  return 0;
+}
+
+void alts_record_protocol_crypter_destruct(alts_crypter* c) {
+  if (c != nullptr) {
+    alts_record_protocol_crypter* rp_crypter =
+        reinterpret_cast<alts_record_protocol_crypter*>(c);
+    alts_counter_destroy(rp_crypter->ctr);
+    gsec_aead_crypter_destroy(rp_crypter->crypter);
+  }
+}
+
+alts_record_protocol_crypter* alts_crypter_create_common(
+    gsec_aead_crypter* crypter, bool is_client, size_t overflow_size,
+    char** error_details) {
+  if (crypter != nullptr) {
+    auto* rp_crypter = static_cast<alts_record_protocol_crypter*>(
+        gpr_malloc(sizeof(alts_record_protocol_crypter)));
+    size_t counter_size = 0;
+    grpc_status_code status =
+        gsec_aead_crypter_nonce_length(crypter, &counter_size, error_details);
+    if (status != GRPC_STATUS_OK) {
+      return nullptr;
+    }
+    /* Create a counter. */
+    status = alts_counter_create(is_client, counter_size, overflow_size,
+                                 &rp_crypter->ctr, error_details);
+    if (status != GRPC_STATUS_OK) {
+      return nullptr;
+    }
+    rp_crypter->crypter = crypter;
+    return rp_crypter;
+  }
+  const char error_msg[] = "crypter is nullptr.";
+  maybe_copy_error_msg(error_msg, error_details);
+  return nullptr;
+}
diff --git a/src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h b/src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h
new file mode 100644
index 0000000..682a8f7
--- /dev/null
+++ b/src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h
@@ -0,0 +1,114 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_RECORD_PROTOCOL_CRYPTER_COMMON_H
+#define GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_RECORD_PROTOCOL_CRYPTER_COMMON_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/grpc.h>
+
+#include "src/core/tsi/alts/frame_protector/alts_counter.h"
+#include "src/core/tsi/alts/frame_protector/alts_crypter.h"
+
+/**
+ * This file contains common implementation that will be used in both seal and
+ * unseal operations.
+ */
+
+/**
+ * Main struct for alts_record_protocol_crypter that will be used in both
+ * seal and unseal operations.
+ */
+typedef struct alts_record_protocol_crypter {
+  alts_crypter base;
+  gsec_aead_crypter* crypter;
+  alts_counter* ctr;
+} alts_record_protocol_crypter;
+
+/**
+ * This method performs input sanity checks on a subset of inputs to
+ * alts_crypter_process_in_place() for both seal and unseal operations.
+ *
+ * - rp_crypter: an alts_record_protocol_crypter instance.
+ * - data: it represents raw data that needs to be sealed in a seal operation or
+ *   protected data that needs to be unsealed in an unseal operation.
+ * - output_size: size of data written to the data buffer after a seal or
+ *   unseal operation.
+ * - error_details: a buffer containing an error message if any of checked
+ *   inputs is nullptr. It is legal to pass nullptr into error_details and
+ *   otherwise, the parameter should be freed with gpr_free.
+ *
+ * On success, the method returns GRPC_STATUS_OK. Otherwise,
+ * it returns an error status code along with its details specified in
+ * error_details (if error_details is not nullptr).
+ */
+grpc_status_code input_sanity_check(
+    const alts_record_protocol_crypter* rp_crypter, const unsigned char* data,
+    size_t* output_size, char** error_details);
+
+/**
+ * This method increments the counter within an alts_record_protocol_crypter
+ * instance.
+ *
+ * - rp_crypter: an alts_record_protocol_crypter instance.
+ * - error_details: a buffer containing an error message if the method does not
+ *   function correctly or the counter is wrapped. It is legal to pass nullptr
+ *   into error_details and otherwise, the parameter should be freed with
+ *   gpr_free.
+ *
+ * On success, the method returns GRPC_STATUS_OK. Otherwise,
+ * it returns an error status code along with its details specified in
+ * error_details (if error_details is not nullptr).
+ */
+grpc_status_code increment_counter(alts_record_protocol_crypter* rp_crypter,
+                                   char** error_details);
+
+/**
+ * This method creates an alts_crypter instance, and populates the fields
+ * that are common to both seal and unseal operations.
+ *
+ * - crypter: a gsec_aead_crypter instance used to perform AEAD decryption. The
+ *   function does not take ownership of crypter.
+ * - is_client: a flag indicating if the alts_crypter instance will be
+ *   used at the client (is_client = true) or server (is_client =
+ *   false) side.
+ * - overflow_size: overflow size of counter in bytes.
+ * - error_details: a buffer containing an error message if the method does
+ *   not function correctly. It is legal to pass nullptr into error_details, and
+ *   otherwise, the parameter should be freed with gpr_free.
+ *
+ * On success of creation, the method returns alts_record_protocol_crypter
+ * instance. Otherwise, it returns nullptr with its details specified in
+ * error_details (if error_details is not nullptr).
+ *
+ */
+alts_record_protocol_crypter* alts_crypter_create_common(
+    gsec_aead_crypter* crypter, bool is_client, size_t overflow_size,
+    char** error_details);
+
+/**
+ * For the following two methods, please refer to the corresponding API in
+ * alts_crypter.h for detailed specifications.
+ */
+size_t alts_record_protocol_crypter_num_overhead_bytes(const alts_crypter* c);
+
+void alts_record_protocol_crypter_destruct(alts_crypter* c);
+
+#endif /* GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_ALTS_RECORD_PROTOCOL_CRYPTER_COMMON_H \
+        */
diff --git a/src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc b/src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc
new file mode 100644
index 0000000..f407831
--- /dev/null
+++ b/src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc
@@ -0,0 +1,105 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include <grpc/support/alloc.h>
+
+#include "src/core/tsi/alts/frame_protector/alts_counter.h"
+#include "src/core/tsi/alts/frame_protector/alts_crypter.h"
+#include "src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h"
+
+static void maybe_copy_error_msg(const char* src, char** dst) {
+  if (dst != nullptr && src != nullptr) {
+    *dst = static_cast<char*>(gpr_malloc(strlen(src) + 1));
+    memcpy(*dst, src, strlen(src) + 1);
+  }
+}
+
+/* Perform input santity check for a seal operation. */
+static grpc_status_code seal_check(alts_crypter* c, const unsigned char* data,
+                                   size_t data_allocated_size, size_t data_size,
+                                   size_t* output_size, char** error_details) {
+  /* Do common input sanity check. */
+  grpc_status_code status = input_sanity_check(
+      reinterpret_cast<const alts_record_protocol_crypter*>(c), data,
+      output_size, error_details);
+  if (status != GRPC_STATUS_OK) return status;
+  /* Do seal-specific check. */
+  size_t num_overhead_bytes =
+      alts_crypter_num_overhead_bytes(reinterpret_cast<const alts_crypter*>(c));
+  if (data_size == 0) {
+    const char error_msg[] = "data_size is zero.";
+    maybe_copy_error_msg(error_msg, error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  if (data_size + num_overhead_bytes > data_allocated_size) {
+    const char error_msg[] =
+        "data_allocated_size is smaller than sum of data_size and "
+        "num_overhead_bytes.";
+    maybe_copy_error_msg(error_msg, error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  return GRPC_STATUS_OK;
+}
+
+static grpc_status_code alts_seal_crypter_process_in_place(
+    alts_crypter* c, unsigned char* data, size_t data_allocated_size,
+    size_t data_size, size_t* output_size, char** error_details) {
+  grpc_status_code status = seal_check(c, data, data_allocated_size, data_size,
+                                       output_size, error_details);
+  if (status != GRPC_STATUS_OK) {
+    return status;
+  }
+  /* Do AEAD encryption. */
+  alts_record_protocol_crypter* rp_crypter =
+      reinterpret_cast<alts_record_protocol_crypter*>(c);
+  status = gsec_aead_crypter_encrypt(
+      rp_crypter->crypter, alts_counter_get_counter(rp_crypter->ctr),
+      alts_counter_get_size(rp_crypter->ctr), nullptr /* aad */,
+      0 /* aad_length */, data, data_size, data, data_allocated_size,
+      output_size, error_details);
+  if (status != GRPC_STATUS_OK) {
+    return status;
+  }
+  /* Increment the crypter counter. */
+  return increment_counter(rp_crypter, error_details);
+}
+
+static const alts_crypter_vtable vtable = {
+    alts_record_protocol_crypter_num_overhead_bytes,
+    alts_seal_crypter_process_in_place, alts_record_protocol_crypter_destruct};
+
+grpc_status_code alts_seal_crypter_create(gsec_aead_crypter* gc, bool is_client,
+                                          size_t overflow_size,
+                                          alts_crypter** crypter,
+                                          char** error_details) {
+  if (crypter == nullptr) {
+    const char error_msg[] = "crypter is nullptr.";
+    maybe_copy_error_msg(error_msg, error_details);
+    return GRPC_STATUS_FAILED_PRECONDITION;
+  }
+  alts_record_protocol_crypter* rp_crypter =
+      alts_crypter_create_common(gc, !is_client, overflow_size, error_details);
+  if (rp_crypter == nullptr) {
+    return GRPC_STATUS_FAILED_PRECONDITION;
+  }
+  rp_crypter->base.vtable = &vtable;
+  *crypter = &rp_crypter->base;
+  return GRPC_STATUS_OK;
+}
diff --git a/src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc b/src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc
new file mode 100644
index 0000000..51bea24
--- /dev/null
+++ b/src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc
@@ -0,0 +1,103 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include <grpc/support/alloc.h>
+
+#include "src/core/tsi/alts/frame_protector/alts_counter.h"
+#include "src/core/tsi/alts/frame_protector/alts_crypter.h"
+#include "src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h"
+
+static void maybe_copy_error_msg(const char* src, char** dst) {
+  if (dst != nullptr && src != nullptr) {
+    *dst = static_cast<char*>(gpr_malloc(strlen(src) + 1));
+    memcpy(*dst, src, strlen(src) + 1);
+  }
+}
+
+/* Perform input santity check. */
+static grpc_status_code unseal_check(alts_crypter* c, const unsigned char* data,
+                                     size_t data_allocated_size,
+                                     size_t data_size, size_t* output_size,
+                                     char** error_details) {
+  /* Do common input sanity check. */
+  grpc_status_code status = input_sanity_check(
+      reinterpret_cast<const alts_record_protocol_crypter*>(c), data,
+      output_size, error_details);
+  if (status != GRPC_STATUS_OK) {
+    return status;
+  }
+  /* Do unseal-specific input check. */
+  size_t num_overhead_bytes =
+      alts_crypter_num_overhead_bytes(reinterpret_cast<const alts_crypter*>(c));
+  if (num_overhead_bytes > data_size) {
+    const char error_msg[] = "data_size is smaller than num_overhead_bytes.";
+    maybe_copy_error_msg(error_msg, error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  return GRPC_STATUS_OK;
+}
+
+static grpc_status_code alts_unseal_crypter_process_in_place(
+    alts_crypter* c, unsigned char* data, size_t data_allocated_size,
+    size_t data_size, size_t* output_size, char** error_details) {
+  grpc_status_code status = unseal_check(c, data, data_allocated_size,
+                                         data_size, output_size, error_details);
+  if (status != GRPC_STATUS_OK) {
+    return status;
+  }
+  /* Do AEAD decryption. */
+  alts_record_protocol_crypter* rp_crypter =
+      reinterpret_cast<alts_record_protocol_crypter*>(c);
+  status = gsec_aead_crypter_decrypt(
+      rp_crypter->crypter, alts_counter_get_counter(rp_crypter->ctr),
+      alts_counter_get_size(rp_crypter->ctr), nullptr /* aad */,
+      0 /* aad_length */, data, data_size, data, data_allocated_size,
+      output_size, error_details);
+  if (status != GRPC_STATUS_OK) {
+    return status;
+  }
+  /* Increment the crypter counter. */
+  return increment_counter(rp_crypter, error_details);
+}
+
+static const alts_crypter_vtable vtable = {
+    alts_record_protocol_crypter_num_overhead_bytes,
+    alts_unseal_crypter_process_in_place,
+    alts_record_protocol_crypter_destruct};
+
+grpc_status_code alts_unseal_crypter_create(gsec_aead_crypter* gc,
+                                            bool is_client,
+                                            size_t overflow_size,
+                                            alts_crypter** crypter,
+                                            char** error_details) {
+  if (crypter == nullptr) {
+    const char error_msg[] = "crypter is nullptr.";
+    maybe_copy_error_msg(error_msg, error_details);
+    return GRPC_STATUS_FAILED_PRECONDITION;
+  }
+  alts_record_protocol_crypter* rp_crypter =
+      alts_crypter_create_common(gc, is_client, overflow_size, error_details);
+  if (rp_crypter == nullptr) {
+    return GRPC_STATUS_FAILED_PRECONDITION;
+  }
+  rp_crypter->base.vtable = &vtable;
+  *crypter = &rp_crypter->base;
+  return GRPC_STATUS_OK;
+}
diff --git a/src/core/tsi/alts/frame_protector/frame_handler.cc b/src/core/tsi/alts/frame_protector/frame_handler.cc
new file mode 100644
index 0000000..d3fda63
--- /dev/null
+++ b/src/core/tsi/alts/frame_protector/frame_handler.cc
@@ -0,0 +1,218 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/frame_protector/frame_handler.h"
+
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/gpr/useful.h"
+
+/* Use little endian to interpret a string of bytes as uint32_t. */
+static uint32_t load_32_le(const unsigned char* buffer) {
+  return (((uint32_t)buffer[3]) << 24) | (((uint32_t)buffer[2]) << 16) |
+         (((uint32_t)buffer[1]) << 8) | ((uint32_t)buffer[0]);
+}
+
+/* Store uint32_t as a string of little endian bytes. */
+static void store_32_le(uint32_t value, unsigned char* buffer) {
+  buffer[3] = (unsigned char)(value >> 24) & 0xFF;
+  buffer[2] = (unsigned char)(value >> 16) & 0xFF;
+  buffer[1] = (unsigned char)(value >> 8) & 0xFF;
+  buffer[0] = (unsigned char)(value)&0xFF;
+}
+
+/* Frame writer implementation. */
+alts_frame_writer* alts_create_frame_writer() {
+  alts_frame_writer* writer =
+      static_cast<alts_frame_writer*>(gpr_zalloc(sizeof(*writer)));
+  return writer;
+}
+
+bool alts_reset_frame_writer(alts_frame_writer* writer,
+                             const unsigned char* buffer, size_t length) {
+  if (buffer == nullptr) return false;
+  size_t max_input_size = SIZE_MAX - kFrameLengthFieldSize;
+  if (length > max_input_size) {
+    gpr_log(GPR_ERROR, "length must be at most %zu", max_input_size);
+    return false;
+  }
+  writer->input_buffer = buffer;
+  writer->input_size = length;
+  writer->input_bytes_written = 0;
+  writer->header_bytes_written = 0;
+  store_32_le(
+      static_cast<uint32_t>(writer->input_size + kFrameMessageTypeFieldSize),
+      writer->header_buffer);
+  store_32_le(kFrameMessageType, writer->header_buffer + kFrameLengthFieldSize);
+  return true;
+}
+
+bool alts_write_frame_bytes(alts_frame_writer* writer, unsigned char* output,
+                            size_t* bytes_size) {
+  if (bytes_size == nullptr || output == nullptr) return false;
+  if (alts_is_frame_writer_done(writer)) {
+    *bytes_size = 0;
+    return true;
+  }
+  size_t bytes_written = 0;
+  /* Write some header bytes, if needed. */
+  if (writer->header_bytes_written != sizeof(writer->header_buffer)) {
+    size_t bytes_to_write =
+        GPR_MIN(*bytes_size,
+                sizeof(writer->header_buffer) - writer->header_bytes_written);
+    memcpy(output, writer->header_buffer + writer->header_bytes_written,
+           bytes_to_write);
+    bytes_written += bytes_to_write;
+    *bytes_size -= bytes_to_write;
+    writer->header_bytes_written += bytes_to_write;
+    output += bytes_to_write;
+    if (writer->header_bytes_written != sizeof(writer->header_buffer)) {
+      *bytes_size = bytes_written;
+      return true;
+    }
+  }
+  /* Write some non-header bytes. */
+  size_t bytes_to_write =
+      GPR_MIN(writer->input_size - writer->input_bytes_written, *bytes_size);
+  memcpy(output, writer->input_buffer, bytes_to_write);
+  writer->input_buffer += bytes_to_write;
+  bytes_written += bytes_to_write;
+  writer->input_bytes_written += bytes_to_write;
+  *bytes_size = bytes_written;
+  return true;
+}
+
+bool alts_is_frame_writer_done(alts_frame_writer* writer) {
+  return writer->input_buffer == nullptr ||
+         writer->input_size == writer->input_bytes_written;
+}
+
+size_t alts_get_num_writer_bytes_remaining(alts_frame_writer* writer) {
+  return (sizeof(writer->header_buffer) - writer->header_bytes_written) +
+         (writer->input_size - writer->input_bytes_written);
+}
+
+void alts_destroy_frame_writer(alts_frame_writer* writer) { gpr_free(writer); }
+
+/* Frame reader implementation. */
+alts_frame_reader* alts_create_frame_reader() {
+  alts_frame_reader* reader =
+      static_cast<alts_frame_reader*>(gpr_zalloc(sizeof(*reader)));
+  return reader;
+}
+
+bool alts_is_frame_reader_done(alts_frame_reader* reader) {
+  return reader->output_buffer == nullptr ||
+         (reader->header_bytes_read == sizeof(reader->header_buffer) &&
+          reader->bytes_remaining == 0);
+}
+
+bool alts_has_read_frame_length(alts_frame_reader* reader) {
+  return sizeof(reader->header_buffer) == reader->header_bytes_read;
+}
+
+size_t alts_get_reader_bytes_remaining(alts_frame_reader* reader) {
+  return alts_has_read_frame_length(reader) ? reader->bytes_remaining : 0;
+}
+
+void alts_reset_reader_output_buffer(alts_frame_reader* reader,
+                                     unsigned char* buffer) {
+  reader->output_buffer = buffer;
+}
+
+bool alts_reset_frame_reader(alts_frame_reader* reader, unsigned char* buffer) {
+  if (buffer == nullptr) return false;
+  reader->output_buffer = buffer;
+  reader->bytes_remaining = 0;
+  reader->header_bytes_read = 0;
+  reader->output_bytes_read = 0;
+  return true;
+}
+
+bool alts_read_frame_bytes(alts_frame_reader* reader,
+                           const unsigned char* bytes, size_t* bytes_size) {
+  if (bytes_size == nullptr) return false;
+  if (bytes == nullptr) {
+    *bytes_size = 0;
+    return false;
+  }
+  if (alts_is_frame_reader_done(reader)) {
+    *bytes_size = 0;
+    return true;
+  }
+  size_t bytes_processed = 0;
+  /* Process the header, if needed. */
+  if (reader->header_bytes_read != sizeof(reader->header_buffer)) {
+    size_t bytes_to_write = GPR_MIN(
+        *bytes_size, sizeof(reader->header_buffer) - reader->header_bytes_read);
+    memcpy(reader->header_buffer + reader->header_bytes_read, bytes,
+           bytes_to_write);
+    reader->header_bytes_read += bytes_to_write;
+    bytes_processed += bytes_to_write;
+    bytes += bytes_to_write;
+    *bytes_size -= bytes_to_write;
+    if (reader->header_bytes_read != sizeof(reader->header_buffer)) {
+      *bytes_size = bytes_processed;
+      return true;
+    }
+    size_t frame_length = load_32_le(reader->header_buffer);
+    if (frame_length < kFrameMessageTypeFieldSize ||
+        frame_length > kFrameMaxSize) {
+      gpr_log(GPR_ERROR,
+              "Bad frame length (should be at least %zu, and at most %zu)",
+              kFrameMessageTypeFieldSize, kFrameMaxSize);
+      *bytes_size = 0;
+      return false;
+    }
+    size_t message_type =
+        load_32_le(reader->header_buffer + kFrameLengthFieldSize);
+    if (message_type != kFrameMessageType) {
+      gpr_log(GPR_ERROR, "Unsupported message type %zu (should be %zu)",
+              message_type, kFrameMessageType);
+      *bytes_size = 0;
+      return false;
+    }
+    reader->bytes_remaining = frame_length - kFrameMessageTypeFieldSize;
+  }
+  /* Process the non-header bytes. */
+  size_t bytes_to_write = GPR_MIN(*bytes_size, reader->bytes_remaining);
+  memcpy(reader->output_buffer, bytes, bytes_to_write);
+  reader->output_buffer += bytes_to_write;
+  bytes_processed += bytes_to_write;
+  reader->bytes_remaining -= bytes_to_write;
+  reader->output_bytes_read += bytes_to_write;
+  *bytes_size = bytes_processed;
+  return true;
+}
+
+size_t alts_get_output_bytes_read(alts_frame_reader* reader) {
+  return reader->output_bytes_read;
+}
+
+unsigned char* alts_get_output_buffer(alts_frame_reader* reader) {
+  return reader->output_buffer;
+}
+
+void alts_destroy_frame_reader(alts_frame_reader* reader) { gpr_free(reader); }
diff --git a/src/core/tsi/alts/frame_protector/frame_handler.h b/src/core/tsi/alts/frame_protector/frame_handler.h
new file mode 100644
index 0000000..a703ff4
--- /dev/null
+++ b/src/core/tsi/alts/frame_protector/frame_handler.h
@@ -0,0 +1,236 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_FRAME_HANDLER_H
+#define GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_FRAME_HANDLER_H
+
+#include <grpc/support/port_platform.h>
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+const size_t kFrameMessageType = 0x06;
+const size_t kFrameLengthFieldSize = 4;
+const size_t kFrameMessageTypeFieldSize = 4;
+const size_t kFrameMaxSize = 1024 * 1024;
+const size_t kFrameHeaderSize =
+    kFrameLengthFieldSize + kFrameMessageTypeFieldSize;
+
+/**
+ * Implementation of frame reader and frame writer. All APIs in the
+ * header are thread-compatible.
+ */
+
+/**
+ * Main struct for a frame writer. It reads frames from an input buffer, and
+ * writes the contents as raw bytes. It does not own the input buffer.
+ */
+typedef struct alts_frame_writer {
+  const unsigned char* input_buffer;
+  unsigned char header_buffer[kFrameHeaderSize];
+  size_t input_bytes_written;
+  size_t header_bytes_written;
+  size_t input_size;
+} alts_frame_writer;
+
+/**
+ * Main struct for a frame reader. It reads raw bytes and puts the framed
+ * result into an output buffer. It does not own the output buffer.
+ */
+typedef struct alts_frame_reader {
+  unsigned char* output_buffer;
+  unsigned char header_buffer[kFrameHeaderSize];
+  size_t header_bytes_read;
+  size_t output_bytes_read;
+  size_t bytes_remaining;
+} alts_frame_reader;
+
+/**
+ * This method creates a frame writer instance and initializes its internal
+ * states.
+ */
+alts_frame_writer* alts_create_frame_writer();
+
+/**
+ * This method resets internal states of a frame writer and prepares to write
+ * a single frame. It does not take ownership of payload_buffer.
+ * The payload_buffer must outlive the writer.
+ *
+ * - writer: a frame writer instance.
+ * - buffer: a buffer storing full payload data to be framed.
+ * - length: size of payload data.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool alts_reset_frame_writer(alts_frame_writer* writer,
+                             const unsigned char* buffer, size_t length);
+
+/**
+ * This method writes up to bytes_size bytes of a frame to output.
+ *
+ * - writer: a frame writer instance.
+ * - output: an output buffer used to store the frame.
+ * - bytes_size: an in/out parameter that stores the size of output buffer
+ *   before the call, and gets written the number of frame bytes written to the
+ *   buffer.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool alts_write_frame_bytes(alts_frame_writer* writer, unsigned char* output,
+                            size_t* bytes_size);
+
+/**
+ * This method checks if a reset can be called to write a new frame. It returns
+ * true if it's the first time to frame a payload, or the current frame has
+ * been finished processing. It returns false if it's not ready yet to start a
+ * new frame (e.g., more payload data needs to be accumulated to process the
+ * current frame).
+ *
+ * if (alts_is_frame_writer_done(writer)) {
+ *   // a new frame can be written, call reset.
+ *   alts_reset_frame_writer(writer, payload_buffer, payload_size);
+ * } else {
+ *   // accumulate more payload data until a full frame can be written.
+ * }
+ *
+ * - writer: a frame writer instance.
+ */
+bool alts_is_frame_writer_done(alts_frame_writer* writer);
+
+/**
+ * This method returns the number of bytes left to write before a complete frame
+ * is formed.
+ *
+ * - writer: a frame writer instance.
+ */
+size_t alts_get_num_writer_bytes_remaining(alts_frame_writer* writer);
+
+/**
+ * This method destroys a frame writer instance.
+ *
+ * - writer: a frame writer instance.
+ */
+void alts_destroy_frame_writer(alts_frame_writer* writer);
+
+/**
+ * This method creates a frame reader instance and initializes its internal
+ * states.
+ */
+alts_frame_reader* alts_create_frame_reader();
+
+/**
+ * This method resets internal states of a frame reader (including setting its
+ * output_buffer with buffer), and prepares to write processed bytes to
+ * an output_buffer. It does not take ownership of buffer. The buffer must
+ * outlive reader.
+ *
+ * - reader: a frame reader instance.
+ * - buffer: an output buffer used to store deframed results.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool alts_reset_frame_reader(alts_frame_reader* reader, unsigned char* buffer);
+
+/**
+ * This method processes up to the number of bytes given in bytes_size. It may
+ * choose not to process all the bytes, if, for instance, more bytes are
+ * given to the method than required to complete the current frame.
+ *
+ * - reader: a frame reader instance.
+ * - bytes: a buffer that stores data to be processed.
+ * - bytes_size: an in/out parameter that stores the size of bytes before the
+ *   call and gets written the number of bytes processed.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool alts_read_frame_bytes(alts_frame_reader* reader,
+                           const unsigned char* bytes, size_t* bytes_size);
+
+/**
+ * This method checks if a frame length has been read.
+ *
+ * - reader: a frame reader instance.
+ *
+ * The method returns true if a frame length has been read and false otherwise.
+ */
+bool alts_has_read_frame_length(alts_frame_reader* reader);
+
+/**
+ * This method returns the number of bytes the frame reader intends to write.
+ * It may only be called if alts_has_read_frame_length() returns true.
+ *
+ * - reader: a frame reader instance.
+ */
+size_t alts_get_reader_bytes_remaining(alts_frame_reader* reader);
+
+/**
+ * This method resets output_buffer but does not otherwise modify other internal
+ * states of a frame reader instance. After being set, the new output_buffer
+ * will hold the deframed payload held by the original output_buffer. It does
+ * not take ownership of buffer. The buffer must outlive the reader.
+ * To distinguish between two reset methods on a frame reader,
+ *
+ * if (alts_fh_is_frame_reader_done(reader)) {
+ *   // if buffer contains a full payload to be deframed, call reset.
+ *   alts_reset_frame_reader(reader, buffer);
+ * }
+ *
+ * // if remaining buffer space is not enough to hold a full payload
+ * if (buffer_space_remaining < alts_get_reader_bytes_remaining(reader)) {
+ *   // allocate enough space for a new buffer, copy back data processed so far,
+ *   // and call reset.
+ *   alts_reset_reader_output_buffer(reader, new_buffer).
+ * }
+ *
+ * - reader: a frame reader instance.
+ * - buffer: a buffer used to set reader's output_buffer.
+ */
+void alts_reset_reader_output_buffer(alts_frame_reader* reader,
+                                     unsigned char* buffer);
+
+/**
+ * This method checks if reset can be called to start processing a new frame.
+ * If true and reset was previously called, a full frame has been processed and
+ * the content of the frame is available in output_buffer.
+
+ * - reader: a frame reader instance.
+ */
+bool alts_is_frame_reader_done(alts_frame_reader* reader);
+
+/**
+ * This method returns output_bytes_read of a frame reader instance.
+ *
+ * - reader: a frame reader instance.
+ */
+size_t alts_get_output_bytes_read(alts_frame_reader* reader);
+
+/**
+ * This method returns output_buffer of a frame reader instance.
+ *
+ * - reader: a frame reader instance.
+ */
+unsigned char* alts_get_output_buffer(alts_frame_reader* reader);
+
+/**
+ * This method destroys a frame reader instance.
+ *
+ * - reader: a frame reader instance.
+ */
+void alts_destroy_frame_reader(alts_frame_reader* reader);
+
+#endif /* GRPC_CORE_TSI_ALTS_FRAME_PROTECTOR_FRAME_HANDLER_H */
diff --git a/src/core/tsi/alts/handshaker/alts_handshaker_client.cc b/src/core/tsi/alts/handshaker/alts_handshaker_client.cc
new file mode 100644
index 0000000..40f30e4
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/alts_handshaker_client.cc
@@ -0,0 +1,316 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/handshaker/alts_handshaker_client.h"
+
+#include <grpc/byte_buffer.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/tsi/alts/handshaker/alts_handshaker_service_api.h"
+
+const int kHandshakerClientOpNum = 4;
+
+typedef struct alts_grpc_handshaker_client {
+  alts_handshaker_client base;
+  grpc_call* call;
+  alts_grpc_caller grpc_caller;
+} alts_grpc_handshaker_client;
+
+static grpc_call_error grpc_start_batch(grpc_call* call, const grpc_op* ops,
+                                        size_t nops, void* tag) {
+  return grpc_call_start_batch(call, ops, nops, tag, nullptr);
+}
+
+/**
+ * Populate grpc operation data with the fields of ALTS TSI event and make a
+ * grpc call.
+ */
+static tsi_result make_grpc_call(alts_handshaker_client* client,
+                                 alts_tsi_event* event, bool is_start) {
+  GPR_ASSERT(client != nullptr && event != nullptr);
+  alts_grpc_handshaker_client* grpc_client =
+      reinterpret_cast<alts_grpc_handshaker_client*>(client);
+  grpc_op ops[kHandshakerClientOpNum];
+  memset(ops, 0, sizeof(ops));
+  grpc_op* op = ops;
+  if (is_start) {
+    op->op = GRPC_OP_SEND_INITIAL_METADATA;
+    op->data.send_initial_metadata.count = 0;
+    op++;
+    GPR_ASSERT(op - ops <= kHandshakerClientOpNum);
+    op->op = GRPC_OP_RECV_INITIAL_METADATA;
+    op->data.recv_initial_metadata.recv_initial_metadata =
+        &event->initial_metadata;
+    op++;
+    GPR_ASSERT(op - ops <= kHandshakerClientOpNum);
+  }
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = event->send_buffer;
+  op++;
+  GPR_ASSERT(op - ops <= kHandshakerClientOpNum);
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &event->recv_buffer;
+  op++;
+  GPR_ASSERT(op - ops <= kHandshakerClientOpNum);
+  GPR_ASSERT(grpc_client->grpc_caller != nullptr);
+  if (grpc_client->grpc_caller(grpc_client->call, ops,
+                               static_cast<size_t>(op - ops),
+                               (void*)event) != GRPC_CALL_OK) {
+    gpr_log(GPR_ERROR, "Start batch operation failed");
+    return TSI_INTERNAL_ERROR;
+  }
+  return TSI_OK;
+}
+
+/* Create and populate a client_start handshaker request, then serialize it. */
+static grpc_byte_buffer* get_serialized_start_client(alts_tsi_event* event) {
+  bool ok = true;
+  grpc_gcp_handshaker_req* req =
+      grpc_gcp_handshaker_req_create(CLIENT_START_REQ);
+  ok &= grpc_gcp_handshaker_req_set_handshake_protocol(
+      req, grpc_gcp_HandshakeProtocol_ALTS);
+  ok &= grpc_gcp_handshaker_req_add_application_protocol(
+      req, ALTS_APPLICATION_PROTOCOL);
+  ok &= grpc_gcp_handshaker_req_add_record_protocol(req, ALTS_RECORD_PROTOCOL);
+  grpc_gcp_rpc_protocol_versions* versions = &event->options->rpc_versions;
+  ok &= grpc_gcp_handshaker_req_set_rpc_versions(
+      req, versions->max_rpc_version.major, versions->max_rpc_version.minor,
+      versions->min_rpc_version.major, versions->min_rpc_version.minor);
+  char* target_name = grpc_slice_to_c_string(event->target_name);
+  ok &= grpc_gcp_handshaker_req_set_target_name(req, target_name);
+  target_service_account* ptr =
+      (reinterpret_cast<grpc_alts_credentials_client_options*>(event->options))
+          ->target_account_list_head;
+  while (ptr != nullptr) {
+    grpc_gcp_handshaker_req_add_target_identity_service_account(req, ptr->data);
+    ptr = ptr->next;
+  }
+  grpc_slice slice;
+  ok &= grpc_gcp_handshaker_req_encode(req, &slice);
+  grpc_byte_buffer* buffer = nullptr;
+  if (ok) {
+    buffer = grpc_raw_byte_buffer_create(&slice, 1 /* number of slices */);
+  }
+  grpc_slice_unref(slice);
+  gpr_free(target_name);
+  grpc_gcp_handshaker_req_destroy(req);
+  return buffer;
+}
+
+static tsi_result handshaker_client_start_client(alts_handshaker_client* client,
+                                                 alts_tsi_event* event) {
+  if (client == nullptr || event == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid arguments to alts_grpc_handshaker_client_start_client()");
+    return TSI_INVALID_ARGUMENT;
+  }
+  grpc_byte_buffer* buffer = get_serialized_start_client(event);
+  if (buffer == nullptr) {
+    gpr_log(GPR_ERROR, "get_serialized_start_client() failed");
+    return TSI_INTERNAL_ERROR;
+  }
+  event->send_buffer = buffer;
+  tsi_result result = make_grpc_call(client, event, true /* is_start */);
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "make_grpc_call() failed");
+  }
+  return result;
+}
+
+/* Create and populate a start_server handshaker request, then serialize it. */
+static grpc_byte_buffer* get_serialized_start_server(
+    alts_tsi_event* event, grpc_slice* bytes_received) {
+  GPR_ASSERT(bytes_received != nullptr);
+  grpc_gcp_handshaker_req* req =
+      grpc_gcp_handshaker_req_create(SERVER_START_REQ);
+  bool ok = grpc_gcp_handshaker_req_add_application_protocol(
+      req, ALTS_APPLICATION_PROTOCOL);
+  ok &= grpc_gcp_handshaker_req_param_add_record_protocol(
+      req, grpc_gcp_HandshakeProtocol_ALTS, ALTS_RECORD_PROTOCOL);
+  ok &= grpc_gcp_handshaker_req_set_in_bytes(
+      req, reinterpret_cast<const char*> GRPC_SLICE_START_PTR(*bytes_received),
+      GRPC_SLICE_LENGTH(*bytes_received));
+  grpc_gcp_rpc_protocol_versions* versions = &event->options->rpc_versions;
+  ok &= grpc_gcp_handshaker_req_set_rpc_versions(
+      req, versions->max_rpc_version.major, versions->max_rpc_version.minor,
+      versions->min_rpc_version.major, versions->min_rpc_version.minor);
+  grpc_slice req_slice;
+  ok &= grpc_gcp_handshaker_req_encode(req, &req_slice);
+  grpc_byte_buffer* buffer = nullptr;
+  if (ok) {
+    buffer = grpc_raw_byte_buffer_create(&req_slice, 1 /* number of slices */);
+  }
+  grpc_slice_unref(req_slice);
+  grpc_gcp_handshaker_req_destroy(req);
+  return buffer;
+}
+
+static tsi_result handshaker_client_start_server(alts_handshaker_client* client,
+                                                 alts_tsi_event* event,
+                                                 grpc_slice* bytes_received) {
+  if (client == nullptr || event == nullptr || bytes_received == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid arguments to alts_grpc_handshaker_client_start_server()");
+    return TSI_INVALID_ARGUMENT;
+  }
+  grpc_byte_buffer* buffer = get_serialized_start_server(event, bytes_received);
+  if (buffer == nullptr) {
+    gpr_log(GPR_ERROR, "get_serialized_start_server() failed");
+    return TSI_INTERNAL_ERROR;
+  }
+  event->send_buffer = buffer;
+  tsi_result result = make_grpc_call(client, event, true /* is_start */);
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "make_grpc_call() failed");
+  }
+  return result;
+}
+
+/* Create and populate a next handshaker request, then serialize it. */
+static grpc_byte_buffer* get_serialized_next(grpc_slice* bytes_received) {
+  GPR_ASSERT(bytes_received != nullptr);
+  grpc_gcp_handshaker_req* req = grpc_gcp_handshaker_req_create(NEXT_REQ);
+  bool ok = grpc_gcp_handshaker_req_set_in_bytes(
+      req, reinterpret_cast<const char*> GRPC_SLICE_START_PTR(*bytes_received),
+      GRPC_SLICE_LENGTH(*bytes_received));
+  grpc_slice req_slice;
+  ok &= grpc_gcp_handshaker_req_encode(req, &req_slice);
+  grpc_byte_buffer* buffer = nullptr;
+  if (ok) {
+    buffer = grpc_raw_byte_buffer_create(&req_slice, 1 /* number of slices */);
+  }
+  grpc_slice_unref(req_slice);
+  grpc_gcp_handshaker_req_destroy(req);
+  return buffer;
+}
+
+static tsi_result handshaker_client_next(alts_handshaker_client* client,
+                                         alts_tsi_event* event,
+                                         grpc_slice* bytes_received) {
+  if (client == nullptr || event == nullptr || bytes_received == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid arguments to alts_grpc_handshaker_client_next()");
+    return TSI_INVALID_ARGUMENT;
+  }
+  grpc_byte_buffer* buffer = get_serialized_next(bytes_received);
+  if (buffer == nullptr) {
+    gpr_log(GPR_ERROR, "get_serialized_next() failed");
+    return TSI_INTERNAL_ERROR;
+  }
+  event->send_buffer = buffer;
+  tsi_result result = make_grpc_call(client, event, false /* is_start */);
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "make_grpc_call() failed");
+  }
+  return result;
+}
+
+static void handshaker_client_destruct(alts_handshaker_client* client) {
+  if (client == nullptr) {
+    return;
+  }
+  alts_grpc_handshaker_client* grpc_client =
+      reinterpret_cast<alts_grpc_handshaker_client*>(client);
+  grpc_call_unref(grpc_client->call);
+}
+
+static const alts_handshaker_client_vtable vtable = {
+    handshaker_client_start_client, handshaker_client_start_server,
+    handshaker_client_next, handshaker_client_destruct};
+
+alts_handshaker_client* alts_grpc_handshaker_client_create(
+    grpc_channel* channel, grpc_completion_queue* queue,
+    const char* handshaker_service_url) {
+  if (channel == nullptr || queue == nullptr ||
+      handshaker_service_url == nullptr) {
+    gpr_log(GPR_ERROR, "Invalid arguments to alts_handshaker_client_create()");
+    return nullptr;
+  }
+  alts_grpc_handshaker_client* client =
+      static_cast<alts_grpc_handshaker_client*>(gpr_zalloc(sizeof(*client)));
+  client->grpc_caller = grpc_start_batch;
+  grpc_slice slice = grpc_slice_from_copied_string(handshaker_service_url);
+  client->call = grpc_channel_create_call(
+      channel, nullptr, GRPC_PROPAGATE_DEFAULTS, queue,
+      grpc_slice_from_static_string(ALTS_SERVICE_METHOD), &slice,
+      gpr_inf_future(GPR_CLOCK_REALTIME), nullptr);
+  client->base.vtable = &vtable;
+  grpc_slice_unref(slice);
+  return &client->base;
+}
+
+namespace grpc_core {
+namespace internal {
+
+void alts_handshaker_client_set_grpc_caller_for_testing(
+    alts_handshaker_client* client, alts_grpc_caller caller) {
+  GPR_ASSERT(client != nullptr && caller != nullptr);
+  alts_grpc_handshaker_client* grpc_client =
+      reinterpret_cast<alts_grpc_handshaker_client*>(client);
+  grpc_client->grpc_caller = caller;
+}
+
+}  // namespace internal
+}  // namespace grpc_core
+
+tsi_result alts_handshaker_client_start_client(alts_handshaker_client* client,
+                                               alts_tsi_event* event) {
+  if (client != nullptr && client->vtable != nullptr &&
+      client->vtable->client_start != nullptr) {
+    return client->vtable->client_start(client, event);
+  }
+  gpr_log(GPR_ERROR,
+          "client or client->vtable has not been initialized properly");
+  return TSI_INVALID_ARGUMENT;
+}
+
+tsi_result alts_handshaker_client_start_server(alts_handshaker_client* client,
+                                               alts_tsi_event* event,
+                                               grpc_slice* bytes_received) {
+  if (client != nullptr && client->vtable != nullptr &&
+      client->vtable->server_start != nullptr) {
+    return client->vtable->server_start(client, event, bytes_received);
+  }
+  gpr_log(GPR_ERROR,
+          "client or client->vtable has not been initialized properly");
+  return TSI_INVALID_ARGUMENT;
+}
+
+tsi_result alts_handshaker_client_next(alts_handshaker_client* client,
+                                       alts_tsi_event* event,
+                                       grpc_slice* bytes_received) {
+  if (client != nullptr && client->vtable != nullptr &&
+      client->vtable->next != nullptr) {
+    return client->vtable->next(client, event, bytes_received);
+  }
+  gpr_log(GPR_ERROR,
+          "client or client->vtable has not been initialized properly");
+  return TSI_INVALID_ARGUMENT;
+}
+
+void alts_handshaker_client_destroy(alts_handshaker_client* client) {
+  if (client != nullptr) {
+    if (client->vtable != nullptr && client->vtable->destruct != nullptr) {
+      client->vtable->destruct(client);
+    }
+    gpr_free(client);
+  }
+}
diff --git a/src/core/tsi/alts/handshaker/alts_handshaker_client.h b/src/core/tsi/alts/handshaker/alts_handshaker_client.h
new file mode 100644
index 0000000..fb2d2cf
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/alts_handshaker_client.h
@@ -0,0 +1,137 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_CLIENT_H
+#define GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_CLIENT_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/grpc.h>
+
+#include "src/core/tsi/alts/handshaker/alts_tsi_event.h"
+
+#define ALTS_SERVICE_METHOD "/grpc.gcp.HandshakerService/DoHandshake"
+#define ALTS_APPLICATION_PROTOCOL "grpc"
+#define ALTS_RECORD_PROTOCOL "ALTSRP_GCM_AES128_REKEY"
+
+const size_t kAltsAes128GcmRekeyKeyLength = 44;
+
+/**
+ * A ALTS handshaker client interface. It is used to communicate with
+ * ALTS handshaker service by scheduling a handshaker request that could be one
+ * of client_start, server_start, and next handshaker requests. All APIs in the
+ * header are thread-compatible.
+ */
+typedef struct alts_handshaker_client alts_handshaker_client;
+
+/* A function that makes the grpc call to the handshaker service. */
+typedef grpc_call_error (*alts_grpc_caller)(grpc_call* call, const grpc_op* ops,
+                                            size_t nops, void* tag);
+
+/* V-table for ALTS handshaker client operations. */
+typedef struct alts_handshaker_client_vtable {
+  tsi_result (*client_start)(alts_handshaker_client* client,
+                             alts_tsi_event* event);
+  tsi_result (*server_start)(alts_handshaker_client* client,
+                             alts_tsi_event* event, grpc_slice* bytes_received);
+  tsi_result (*next)(alts_handshaker_client* client, alts_tsi_event* event,
+                     grpc_slice* bytes_received);
+  void (*destruct)(alts_handshaker_client* client);
+} alts_handshaker_client_vtable;
+
+struct alts_handshaker_client {
+  const alts_handshaker_client_vtable* vtable;
+};
+
+/**
+ * This method schedules a client_start handshaker request to ALTS handshaker
+ * service.
+ *
+ * - client: ALTS handshaker client instance.
+ * - event: ALTS TSI event instance.
+ *
+ * It returns TSI_OK on success and an error status code on failure.
+ */
+tsi_result alts_handshaker_client_start_client(alts_handshaker_client* client,
+                                               alts_tsi_event* event);
+
+/**
+ * This method schedules a server_start handshaker request to ALTS handshaker
+ * service.
+ *
+ * - client: ALTS handshaker client instance.
+ * - event: ALTS TSI event instance.
+ * - bytes_received: bytes in out_frames returned from the peer's handshaker
+ *   response.
+ *
+ * It returns TSI_OK on success and an error status code on failure.
+ */
+tsi_result alts_handshaker_client_start_server(alts_handshaker_client* client,
+                                               alts_tsi_event* event,
+                                               grpc_slice* bytes_received);
+
+/**
+ * This method schedules a next handshaker request to ALTS handshaker service.
+ *
+ * - client: ALTS handshaker client instance.
+ * - event: ALTS TSI event instance.
+ * - bytes_received: bytes in out_frames returned from the peer's handshaker
+ *   response.
+ *
+ * It returns TSI_OK on success and an error status code on failure.
+ */
+tsi_result alts_handshaker_client_next(alts_handshaker_client* client,
+                                       alts_tsi_event* event,
+                                       grpc_slice* bytes_received);
+
+/**
+ * This method destroys a ALTS handshaker client.
+ *
+ * - client: a ALTS handshaker client instance.
+ */
+void alts_handshaker_client_destroy(alts_handshaker_client* client);
+
+/**
+ * This method creates a ALTS handshaker client.
+ *
+ * - channel: grpc channel to ALTS handshaker service.
+ * - queue: grpc completion queue.
+ * - handshaker_service_url: address of ALTS handshaker service in the format of
+ *   "host:port".
+ *
+ * It returns the created ALTS handshaker client on success, and NULL on
+ * failure.
+ */
+alts_handshaker_client* alts_grpc_handshaker_client_create(
+    grpc_channel* channel, grpc_completion_queue* queue,
+    const char* handshaker_service_url);
+
+namespace grpc_core {
+namespace internal {
+
+/**
+ * Unsafe, use for testing only. It allows the caller to change the way that
+ * GRPC calls are made to the handshaker service.
+ */
+void alts_handshaker_client_set_grpc_caller_for_testing(
+    alts_handshaker_client* client, alts_grpc_caller caller);
+
+}  // namespace internal
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_CLIENT_H */
diff --git a/src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc b/src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc
new file mode 100644
index 0000000..256e414
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc
@@ -0,0 +1,520 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/handshaker/alts_handshaker_service_api.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "src/core/tsi/alts/handshaker/transport_security_common_api.h"
+
+/* HandshakerReq */
+grpc_gcp_handshaker_req* grpc_gcp_handshaker_req_create(
+    grpc_gcp_handshaker_req_type type) {
+  grpc_gcp_handshaker_req* req =
+      static_cast<grpc_gcp_handshaker_req*>(gpr_zalloc(sizeof(*req)));
+  switch (type) {
+    case CLIENT_START_REQ:
+      req->has_client_start = true;
+      break;
+    case SERVER_START_REQ:
+      req->has_server_start = true;
+      break;
+    case NEXT_REQ:
+      req->has_next = true;
+      break;
+  }
+  return req;
+}
+
+void grpc_gcp_handshaker_req_destroy(grpc_gcp_handshaker_req* req) {
+  if (req == nullptr) {
+    return;
+  }
+  if (req->has_client_start) {
+    /* Destroy client_start request. */
+    destroy_repeated_field_list_identity(
+        static_cast<repeated_field*>(req->client_start.target_identities.arg));
+    destroy_repeated_field_list_string(static_cast<repeated_field*>(
+        req->client_start.application_protocols.arg));
+    destroy_repeated_field_list_string(
+        static_cast<repeated_field*>(req->client_start.record_protocols.arg));
+    if (req->client_start.has_local_identity) {
+      destroy_slice(static_cast<grpc_slice*>(
+          req->client_start.local_identity.hostname.arg));
+      destroy_slice(static_cast<grpc_slice*>(
+          req->client_start.local_identity.service_account.arg));
+    }
+    if (req->client_start.has_local_endpoint) {
+      destroy_slice(static_cast<grpc_slice*>(
+          req->client_start.local_endpoint.ip_address.arg));
+    }
+    if (req->client_start.has_remote_endpoint) {
+      destroy_slice(static_cast<grpc_slice*>(
+          req->client_start.remote_endpoint.ip_address.arg));
+    }
+    destroy_slice(static_cast<grpc_slice*>(req->client_start.target_name.arg));
+  } else if (req->has_server_start) {
+    /* Destroy server_start request. */
+    size_t i = 0;
+    for (i = 0; i < req->server_start.handshake_parameters_count; i++) {
+      destroy_repeated_field_list_identity(
+          static_cast<repeated_field*>(req->server_start.handshake_parameters[i]
+                                           .value.local_identities.arg));
+      destroy_repeated_field_list_string(
+          static_cast<repeated_field*>(req->server_start.handshake_parameters[i]
+                                           .value.record_protocols.arg));
+    }
+    destroy_repeated_field_list_string(static_cast<repeated_field*>(
+        req->server_start.application_protocols.arg));
+    if (req->server_start.has_local_endpoint) {
+      destroy_slice(static_cast<grpc_slice*>(
+          req->server_start.local_endpoint.ip_address.arg));
+    }
+    if (req->server_start.has_remote_endpoint) {
+      destroy_slice(static_cast<grpc_slice*>(
+          req->server_start.remote_endpoint.ip_address.arg));
+    }
+    destroy_slice(static_cast<grpc_slice*>(req->server_start.in_bytes.arg));
+  } else {
+    /* Destroy next request. */
+    destroy_slice(static_cast<grpc_slice*>(req->next.in_bytes.arg));
+  }
+  gpr_free(req);
+}
+
+bool grpc_gcp_handshaker_req_set_handshake_protocol(
+    grpc_gcp_handshaker_req* req,
+    grpc_gcp_handshake_protocol handshake_protocol) {
+  if (req == nullptr || !req->has_client_start) {
+    gpr_log(GPR_ERROR,
+            "Invalid arguments to "
+            "grpc_gcp_handshaker_req_set_handshake_protocol().");
+    return false;
+  }
+  req->client_start.has_handshake_security_protocol = true;
+  req->client_start.handshake_security_protocol = handshake_protocol;
+  return true;
+}
+
+bool grpc_gcp_handshaker_req_set_target_name(grpc_gcp_handshaker_req* req,
+                                             const char* target_name) {
+  if (req == nullptr || target_name == nullptr || !req->has_client_start) {
+    gpr_log(GPR_ERROR,
+            "Invalid arguments to "
+            "grpc_gcp_handshaker_req_set_target_name().");
+    return false;
+  }
+  grpc_slice* slice = create_slice(target_name, strlen(target_name));
+  req->client_start.target_name.arg = slice;
+  req->client_start.target_name.funcs.encode = encode_string_or_bytes_cb;
+  return true;
+}
+
+bool grpc_gcp_handshaker_req_add_application_protocol(
+    grpc_gcp_handshaker_req* req, const char* application_protocol) {
+  if (req == nullptr || application_protocol == nullptr || req->has_next) {
+    gpr_log(GPR_ERROR,
+            "Invalid arguments to "
+            "grpc_gcp_handshaker_req_add_application_protocol().");
+    return false;
+  }
+  grpc_slice* slice =
+      create_slice(application_protocol, strlen(application_protocol));
+  if (req->has_client_start) {
+    add_repeated_field(reinterpret_cast<repeated_field**>(
+                           &req->client_start.application_protocols.arg),
+                       slice);
+    req->client_start.application_protocols.funcs.encode =
+        encode_repeated_string_cb;
+  } else {
+    add_repeated_field(reinterpret_cast<repeated_field**>(
+                           &req->server_start.application_protocols.arg),
+                       slice);
+    req->server_start.application_protocols.funcs.encode =
+        encode_repeated_string_cb;
+  }
+  return true;
+}
+
+bool grpc_gcp_handshaker_req_add_record_protocol(grpc_gcp_handshaker_req* req,
+                                                 const char* record_protocol) {
+  if (req == nullptr || record_protocol == nullptr || !req->has_client_start) {
+    gpr_log(GPR_ERROR,
+            "Invalid arguments to "
+            "grpc_gcp_handshaker_req_add_record_protocol().");
+    return false;
+  }
+  grpc_slice* slice = create_slice(record_protocol, strlen(record_protocol));
+  add_repeated_field(reinterpret_cast<repeated_field**>(
+                         &req->client_start.record_protocols.arg),
+                     slice);
+  req->client_start.record_protocols.funcs.encode = encode_repeated_string_cb;
+  return true;
+}
+
+static void set_identity_hostname(grpc_gcp_identity* identity,
+                                  const char* hostname) {
+  grpc_slice* slice = create_slice(hostname, strlen(hostname));
+  identity->hostname.arg = slice;
+  identity->hostname.funcs.encode = encode_string_or_bytes_cb;
+}
+
+static void set_identity_service_account(grpc_gcp_identity* identity,
+                                         const char* service_account) {
+  grpc_slice* slice = create_slice(service_account, strlen(service_account));
+  identity->service_account.arg = slice;
+  identity->service_account.funcs.encode = encode_string_or_bytes_cb;
+}
+
+bool grpc_gcp_handshaker_req_add_target_identity_hostname(
+    grpc_gcp_handshaker_req* req, const char* hostname) {
+  if (req == nullptr || hostname == nullptr || !req->has_client_start) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to "
+            "grpc_gcp_handshaker_req_add_target_identity_hostname().");
+    return false;
+  }
+  grpc_gcp_identity* target_identity =
+      static_cast<grpc_gcp_identity*>(gpr_zalloc(sizeof(*target_identity)));
+  set_identity_hostname(target_identity, hostname);
+  req->client_start.target_identities.funcs.encode =
+      encode_repeated_identity_cb;
+  add_repeated_field(reinterpret_cast<repeated_field**>(
+                         &req->client_start.target_identities.arg),
+                     target_identity);
+  return true;
+}
+
+bool grpc_gcp_handshaker_req_add_target_identity_service_account(
+    grpc_gcp_handshaker_req* req, const char* service_account) {
+  if (req == nullptr || service_account == nullptr || !req->has_client_start) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to "
+            "grpc_gcp_handshaker_req_add_target_identity_service_account().");
+    return false;
+  }
+  grpc_gcp_identity* target_identity =
+      static_cast<grpc_gcp_identity*>(gpr_zalloc(sizeof(*target_identity)));
+  set_identity_service_account(target_identity, service_account);
+  req->client_start.target_identities.funcs.encode =
+      encode_repeated_identity_cb;
+  add_repeated_field(reinterpret_cast<repeated_field**>(
+                         &req->client_start.target_identities.arg),
+                     target_identity);
+  return true;
+}
+
+bool grpc_gcp_handshaker_req_set_local_identity_hostname(
+    grpc_gcp_handshaker_req* req, const char* hostname) {
+  if (req == nullptr || hostname == nullptr || !req->has_client_start) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to "
+            "grpc_gcp_handshaker_req_set_local_identity_hostname().");
+    return false;
+  }
+  req->client_start.has_local_identity = true;
+  set_identity_hostname(&req->client_start.local_identity, hostname);
+  return true;
+}
+
+bool grpc_gcp_handshaker_req_set_local_identity_service_account(
+    grpc_gcp_handshaker_req* req, const char* service_account) {
+  if (req == nullptr || service_account == nullptr || !req->has_client_start) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to "
+            "grpc_gcp_handshaker_req_set_local_identity_service_account().");
+    return false;
+  }
+  req->client_start.has_local_identity = true;
+  set_identity_service_account(&req->client_start.local_identity,
+                               service_account);
+  return true;
+}
+
+static void set_endpoint(grpc_gcp_endpoint* endpoint, const char* ip_address,
+                         size_t port, grpc_gcp_network_protocol protocol) {
+  grpc_slice* slice = create_slice(ip_address, strlen(ip_address));
+  endpoint->ip_address.arg = slice;
+  endpoint->ip_address.funcs.encode = encode_string_or_bytes_cb;
+  endpoint->has_port = true;
+  endpoint->port = static_cast<int32_t>(port);
+  endpoint->has_protocol = true;
+  endpoint->protocol = protocol;
+}
+
+bool grpc_gcp_handshaker_req_set_rpc_versions(grpc_gcp_handshaker_req* req,
+                                              uint32_t max_major,
+                                              uint32_t max_minor,
+                                              uint32_t min_major,
+                                              uint32_t min_minor) {
+  if (req == nullptr || req->has_next) {
+    gpr_log(GPR_ERROR,
+            "Invalid arguments to "
+            "grpc_gcp_handshaker_req_set_rpc_versions().");
+    return false;
+  }
+  if (req->has_client_start) {
+    req->client_start.has_rpc_versions = true;
+    grpc_gcp_rpc_protocol_versions_set_max(&req->client_start.rpc_versions,
+                                           max_major, max_minor);
+    grpc_gcp_rpc_protocol_versions_set_min(&req->client_start.rpc_versions,
+                                           min_major, min_minor);
+  } else {
+    req->server_start.has_rpc_versions = true;
+    grpc_gcp_rpc_protocol_versions_set_max(&req->server_start.rpc_versions,
+                                           max_major, max_minor);
+    grpc_gcp_rpc_protocol_versions_set_min(&req->server_start.rpc_versions,
+                                           min_major, min_minor);
+  }
+  return true;
+}
+
+bool grpc_gcp_handshaker_req_set_local_endpoint(
+    grpc_gcp_handshaker_req* req, const char* ip_address, size_t port,
+    grpc_gcp_network_protocol protocol) {
+  if (req == nullptr || ip_address == nullptr || port > 65535 ||
+      req->has_next) {
+    gpr_log(GPR_ERROR,
+            "Invalid arguments to "
+            "grpc_gcp_handshaker_req_set_local_endpoint().");
+    return false;
+  }
+  if (req->has_client_start) {
+    req->client_start.has_local_endpoint = true;
+    set_endpoint(&req->client_start.local_endpoint, ip_address, port, protocol);
+  } else {
+    req->server_start.has_local_endpoint = true;
+    set_endpoint(&req->server_start.local_endpoint, ip_address, port, protocol);
+  }
+  return true;
+}
+
+bool grpc_gcp_handshaker_req_set_remote_endpoint(
+    grpc_gcp_handshaker_req* req, const char* ip_address, size_t port,
+    grpc_gcp_network_protocol protocol) {
+  if (req == nullptr || ip_address == nullptr || port > 65535 ||
+      req->has_next) {
+    gpr_log(GPR_ERROR,
+            "Invalid arguments to "
+            "grpc_gcp_handshaker_req_set_remote_endpoint().");
+    return false;
+  }
+  if (req->has_client_start) {
+    req->client_start.has_remote_endpoint = true;
+    set_endpoint(&req->client_start.remote_endpoint, ip_address, port,
+                 protocol);
+  } else {
+    req->server_start.has_remote_endpoint = true;
+    set_endpoint(&req->server_start.remote_endpoint, ip_address, port,
+                 protocol);
+  }
+  return true;
+}
+
+bool grpc_gcp_handshaker_req_set_in_bytes(grpc_gcp_handshaker_req* req,
+                                          const char* in_bytes, size_t size) {
+  if (req == nullptr || in_bytes == nullptr || req->has_client_start) {
+    gpr_log(GPR_ERROR,
+            "Invalid arguments to "
+            "grpc_gcp_handshaker_req_set_in_bytes().");
+    return false;
+  }
+  grpc_slice* slice = create_slice(in_bytes, size);
+  if (req->has_next) {
+    req->next.in_bytes.arg = slice;
+    req->next.in_bytes.funcs.encode = &encode_string_or_bytes_cb;
+  } else {
+    req->server_start.in_bytes.arg = slice;
+    req->server_start.in_bytes.funcs.encode = &encode_string_or_bytes_cb;
+  }
+  return true;
+}
+
+static grpc_gcp_server_handshake_parameters* server_start_find_param(
+    grpc_gcp_handshaker_req* req, int32_t key) {
+  size_t i = 0;
+  for (i = 0; i < req->server_start.handshake_parameters_count; i++) {
+    if (req->server_start.handshake_parameters[i].key == key) {
+      return &req->server_start.handshake_parameters[i].value;
+    }
+  }
+  req->server_start
+      .handshake_parameters[req->server_start.handshake_parameters_count]
+      .has_key = true;
+  req->server_start
+      .handshake_parameters[req->server_start.handshake_parameters_count]
+      .has_value = true;
+  req->server_start
+      .handshake_parameters[req->server_start.handshake_parameters_count++]
+      .key = key;
+  return &req->server_start
+              .handshake_parameters
+                  [req->server_start.handshake_parameters_count - 1]
+              .value;
+}
+
+bool grpc_gcp_handshaker_req_param_add_record_protocol(
+    grpc_gcp_handshaker_req* req, grpc_gcp_handshake_protocol key,
+    const char* record_protocol) {
+  if (req == nullptr || record_protocol == nullptr || !req->has_server_start) {
+    gpr_log(GPR_ERROR,
+            "Invalid arguments to "
+            "grpc_gcp_handshaker_req_param_add_record_protocol().");
+    return false;
+  }
+  grpc_gcp_server_handshake_parameters* param =
+      server_start_find_param(req, key);
+  grpc_slice* slice = create_slice(record_protocol, strlen(record_protocol));
+  add_repeated_field(
+      reinterpret_cast<repeated_field**>(&param->record_protocols.arg), slice);
+  param->record_protocols.funcs.encode = &encode_repeated_string_cb;
+  return true;
+}
+
+bool grpc_gcp_handshaker_req_param_add_local_identity_hostname(
+    grpc_gcp_handshaker_req* req, grpc_gcp_handshake_protocol key,
+    const char* hostname) {
+  if (req == nullptr || hostname == nullptr || !req->has_server_start) {
+    gpr_log(GPR_ERROR,
+            "Invalid arguments to "
+            "grpc_gcp_handshaker_req_param_add_local_identity_hostname().");
+    return false;
+  }
+  grpc_gcp_server_handshake_parameters* param =
+      server_start_find_param(req, key);
+  grpc_gcp_identity* local_identity =
+      static_cast<grpc_gcp_identity*>(gpr_zalloc(sizeof(*local_identity)));
+  set_identity_hostname(local_identity, hostname);
+  add_repeated_field(
+      reinterpret_cast<repeated_field**>(&param->local_identities.arg),
+      local_identity);
+  param->local_identities.funcs.encode = &encode_repeated_identity_cb;
+  return true;
+}
+
+bool grpc_gcp_handshaker_req_param_add_local_identity_service_account(
+    grpc_gcp_handshaker_req* req, grpc_gcp_handshake_protocol key,
+    const char* service_account) {
+  if (req == nullptr || service_account == nullptr || !req->has_server_start) {
+    gpr_log(
+        GPR_ERROR,
+        "Invalid arguments to "
+        "grpc_gcp_handshaker_req_param_add_local_identity_service_account().");
+    return false;
+  }
+  grpc_gcp_server_handshake_parameters* param =
+      server_start_find_param(req, key);
+  grpc_gcp_identity* local_identity =
+      static_cast<grpc_gcp_identity*>(gpr_zalloc(sizeof(*local_identity)));
+  set_identity_service_account(local_identity, service_account);
+  add_repeated_field(
+      reinterpret_cast<repeated_field**>(&param->local_identities.arg),
+      local_identity);
+  param->local_identities.funcs.encode = &encode_repeated_identity_cb;
+  return true;
+}
+
+bool grpc_gcp_handshaker_req_encode(grpc_gcp_handshaker_req* req,
+                                    grpc_slice* slice) {
+  if (req == nullptr || slice == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to grpc_gcp_handshaker_req_encode().");
+    return false;
+  }
+  pb_ostream_t size_stream;
+  memset(&size_stream, 0, sizeof(pb_ostream_t));
+  if (!pb_encode(&size_stream, grpc_gcp_HandshakerReq_fields, req)) {
+    gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&size_stream));
+    return false;
+  }
+  size_t encoded_length = size_stream.bytes_written;
+  *slice = grpc_slice_malloc(encoded_length);
+  pb_ostream_t output_stream =
+      pb_ostream_from_buffer(GRPC_SLICE_START_PTR(*slice), encoded_length);
+  if (!pb_encode(&output_stream, grpc_gcp_HandshakerReq_fields, req) != 0) {
+    gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&output_stream));
+    return false;
+  }
+  return true;
+}
+
+/* HandshakerResp. */
+grpc_gcp_handshaker_resp* grpc_gcp_handshaker_resp_create(void) {
+  grpc_gcp_handshaker_resp* resp =
+      static_cast<grpc_gcp_handshaker_resp*>(gpr_zalloc(sizeof(*resp)));
+  return resp;
+}
+
+void grpc_gcp_handshaker_resp_destroy(grpc_gcp_handshaker_resp* resp) {
+  if (resp != nullptr) {
+    destroy_slice(static_cast<grpc_slice*>(resp->out_frames.arg));
+    if (resp->has_status) {
+      destroy_slice(static_cast<grpc_slice*>(resp->status.details.arg));
+    }
+    if (resp->has_result) {
+      destroy_slice(
+          static_cast<grpc_slice*>(resp->result.application_protocol.arg));
+      destroy_slice(static_cast<grpc_slice*>(resp->result.record_protocol.arg));
+      destroy_slice(static_cast<grpc_slice*>(resp->result.key_data.arg));
+      if (resp->result.has_local_identity) {
+        destroy_slice(
+            static_cast<grpc_slice*>(resp->result.local_identity.hostname.arg));
+        destroy_slice(static_cast<grpc_slice*>(
+            resp->result.local_identity.service_account.arg));
+      }
+      if (resp->result.has_peer_identity) {
+        destroy_slice(
+            static_cast<grpc_slice*>(resp->result.peer_identity.hostname.arg));
+        destroy_slice(static_cast<grpc_slice*>(
+            resp->result.peer_identity.service_account.arg));
+      }
+    }
+    gpr_free(resp);
+  }
+}
+
+bool grpc_gcp_handshaker_resp_decode(grpc_slice encoded_handshaker_resp,
+                                     grpc_gcp_handshaker_resp* resp) {
+  if (resp == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr argument to grpc_gcp_handshaker_resp_decode().");
+    return false;
+  }
+  pb_istream_t stream =
+      pb_istream_from_buffer(GRPC_SLICE_START_PTR(encoded_handshaker_resp),
+                             GRPC_SLICE_LENGTH(encoded_handshaker_resp));
+  resp->out_frames.funcs.decode = decode_string_or_bytes_cb;
+  resp->status.details.funcs.decode = decode_string_or_bytes_cb;
+  resp->result.application_protocol.funcs.decode = decode_string_or_bytes_cb;
+  resp->result.record_protocol.funcs.decode = decode_string_or_bytes_cb;
+  resp->result.key_data.funcs.decode = decode_string_or_bytes_cb;
+  resp->result.peer_identity.hostname.funcs.decode = decode_string_or_bytes_cb;
+  resp->result.peer_identity.service_account.funcs.decode =
+      decode_string_or_bytes_cb;
+  resp->result.local_identity.hostname.funcs.decode = decode_string_or_bytes_cb;
+  resp->result.local_identity.service_account.funcs.decode =
+      decode_string_or_bytes_cb;
+  if (!pb_decode(&stream, grpc_gcp_HandshakerResp_fields, resp)) {
+    gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream));
+    return false;
+  }
+  return true;
+}
diff --git a/src/core/tsi/alts/handshaker/alts_handshaker_service_api.h b/src/core/tsi/alts/handshaker/alts_handshaker_service_api.h
new file mode 100644
index 0000000..5df56a8
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/alts_handshaker_service_api.h
@@ -0,0 +1,323 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_SERVICE_API_H
+#define GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_SERVICE_API_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h"
+
+/**
+ * An implementation of nanopb thin wrapper used to set/get and
+ * serialize/de-serialize of ALTS handshake requests and responses.
+ *
+ * All APIs in the header are thread-compatible. A typical usage of this API at
+ * the client side is as follows:
+ *
+ * -----------------------------------------------------------------------------
+ * // Create, populate, and serialize an ALTS client_start handshake request to
+ * // send to the server.
+ * grpc_gcp_handshaker_req* req =
+ *     grpc_gcp_handshaker_req_create(CLIENT_START_REQ);
+ * grpc_gcp_handshaker_req_set_handshake_protocol(
+       req, grpc_gcp_HandshakeProtocol_ALTS);
+ * grpc_gcp_handshaker_req_add_application_protocol(req, "grpc");
+ * grpc_gcp_handshaker_req_add_record_protocol(req, "ALTSRP_GCM_AES128");
+ * grpc_slice client_slice;
+ * if (!grpc_gcp_handshaker_req_encode(req, &client_slice)) {
+ *   fprintf(stderr, "ALTS handshake request encoding failed.";
+ * }
+ *
+ * // De-serialize a data stream received from the server, and store the result
+ * // at ALTS handshake response.
+ * grpc_gcp_handshaker_resp* resp = grpc_gcp_handshaker_resp_create();
+ * if (!grpc_gcp_handshaker_resp_decode(server_slice, resp)) {
+ *    fprintf(stderr, "ALTS handshake response decoding failed.");
+ * }
+ * // To access a variable-length datatype field (i.e., pb_callback_t),
+ * // access its "arg" subfield (if it has been set).
+ * if (resp->out_frames.arg != nullptr) {
+ *   grpc_slice* slice = resp->out_frames.arg;
+ * }
+ * // To access a fixed-length datatype field (i.e., not pb_calback_t),
+ * // access the field directly (if it has been set).
+ * if (resp->has_status && resp->status->has_code) {
+ *   uint32_t code = resp->status->code;
+ * }
+ *------------------------------------------------------------------------------
+ */
+
+/**
+ * This method creates an ALTS handshake request.
+ *
+ * - type: an enum type value that can be either CLIENT_START_REQ,
+ *   SERVER_START_REQ, or NEXT_REQ to indicate the created instance will be
+ *   client_start, server_start, and next handshake request message
+ * respectively.
+ *
+ * The method returns a pointer to the created instance.
+ */
+grpc_gcp_handshaker_req* grpc_gcp_handshaker_req_create(
+    grpc_gcp_handshaker_req_type type);
+
+/**
+ * This method sets the value for handshake_security_protocol field of ALTS
+ * client_start handshake request.
+ *
+ * - req: an ALTS handshake request.
+ * - handshake_protocol: a enum type value representing the handshake security
+ *   protocol.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_handshaker_req_set_handshake_protocol(
+    grpc_gcp_handshaker_req* req,
+    grpc_gcp_handshake_protocol handshake_protocol);
+
+/**
+ * This method sets the value for target_name field of ALTS client_start
+ * handshake request.
+ *
+ * - req: an ALTS handshake request.
+ * - target_name: a target name to be set.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_handshaker_req_set_target_name(grpc_gcp_handshaker_req* req,
+                                             const char* target_name);
+
+/**
+ * This method adds an application protocol supported by the server (or
+ * client) to ALTS server_start (or client_start) handshake request.
+ *
+ * - req: an ALTS handshake request.
+ * - application_protocol: an application protocol (e.g., grpc) to be added.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_handshaker_req_add_application_protocol(
+    grpc_gcp_handshaker_req* req, const char* application_protocol);
+
+/**
+ * This method adds a record protocol supported by the client to ALTS
+ * client_start handshake request.
+ *
+ * - req: an ALTS handshake request.
+ * - record_protocol: a record protocol (e.g., ALTSRP_GCM_AES128) to be
+ *   added.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_handshaker_req_add_record_protocol(grpc_gcp_handshaker_req* req,
+                                                 const char* record_protocol);
+
+/**
+ * This method adds a target server identity represented as hostname and
+ * acceptable by a client to ALTS client_start handshake request.
+ *
+ * - req: an ALTS handshake request.
+ * - hostname: a string representation of hostname at the connection
+ *   endpoint to be added.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_handshaker_req_add_target_identity_hostname(
+    grpc_gcp_handshaker_req* req, const char* hostname);
+
+/**
+ * This method adds a target server identity represented as service account and
+ * acceptable by a client to ALTS client_start handshake request.
+ *
+ * - req: an ALTS handshake request.
+ * - service_account: a string representation of service account at the
+ *   connection endpoint to be added.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_handshaker_req_add_target_identity_service_account(
+    grpc_gcp_handshaker_req* req, const char* service_account);
+
+/**
+ * This method sets the hostname for local_identity field of ALTS client_start
+ * handshake request.
+ *
+ * - req: an ALTS handshake request.
+ * - hostname: a string representation of hostname.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_handshaker_req_set_local_identity_hostname(
+    grpc_gcp_handshaker_req* req, const char* hostname);
+
+/**
+ * This method sets the service account for local_identity field of ALTS
+ * client_start handshake request.
+ *
+ * - req: an ALTS handshake request.
+ * - service_account: a string representation of service account.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_handshaker_req_set_local_identity_service_account(
+    grpc_gcp_handshaker_req* req, const char* service_account);
+
+/**
+ * This method sets the value for local_endpoint field of either ALTS
+ * client_start or server_start handshake request.
+ *
+ * - req: an ALTS handshake request.
+ * - ip_address: a string representation of ip address associated with the
+ *   local endpoint, that could be either IPv4 or IPv6.
+ * - port: a port number associated with the local endpoint.
+ * - protocol: a network protocol (e.g., TCP or UDP) associated with the
+ *   local endpoint.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_handshaker_req_set_local_endpoint(
+    grpc_gcp_handshaker_req* req, const char* ip_address, size_t port,
+    grpc_gcp_network_protocol protocol);
+
+/**
+ * This method sets the value for remote_endpoint field of either ALTS
+ * client_start or server_start handshake request.
+ *
+ * - req: an ALTS handshake request.
+ * - ip_address: a string representation of ip address associated with the
+ *   remote endpoint, that could be either IPv4 or IPv6.
+ * - port: a port number associated with the remote endpoint.
+ * - protocol: a network protocol (e.g., TCP or UDP) associated with the
+ *   remote endpoint.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_handshaker_req_set_remote_endpoint(
+    grpc_gcp_handshaker_req* req, const char* ip_address, size_t port,
+    grpc_gcp_network_protocol protocol);
+
+/**
+ * This method sets the value for in_bytes field of either ALTS server_start or
+ * next handshake request.
+ *
+ * - req: an ALTS handshake request.
+ * - in_bytes: a buffer containing bytes taken from out_frames of the peer's
+ *   ALTS handshake response. It is possible that the peer's out_frames are
+ * split into multiple handshake request messages.
+ * - size: size of in_bytes buffer.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_handshaker_req_set_in_bytes(grpc_gcp_handshaker_req* req,
+                                          const char* in_bytes, size_t size);
+
+/**
+ * This method adds a record protocol to handshake parameters mapped by the
+ * handshake protocol for ALTS server_start handshake request.
+ *
+ * - req: an ALTS handshake request.
+ * - key: an enum type value representing a handshake security protocol.
+ * - record_protocol: a record protocol to be added.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_handshaker_req_param_add_record_protocol(
+    grpc_gcp_handshaker_req* req, grpc_gcp_handshake_protocol key,
+    const char* record_protocol);
+
+/**
+ * This method adds a local identity represented as hostname to handshake
+ * parameters mapped by the handshake protocol for ALTS server_start handshake
+ * request.
+ *
+ * - req: an ALTS handshake request.
+ * - key: an enum type value representing a handshake security protocol.
+ * - hostname: a string representation of hostname to be added.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_handshaker_req_param_add_local_identity_hostname(
+    grpc_gcp_handshaker_req* req, grpc_gcp_handshake_protocol key,
+    const char* hostname);
+
+/**
+ * This method adds a local identity represented as service account to handshake
+ * parameters mapped by the handshake protocol for ALTS server_start handshake
+ * request.
+ *
+ * - req: an ALTS handshake request.
+ * - key: an enum type value representing a handshake security protocol.
+ * - service_account: a string representation of service account to be added.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_handshaker_req_param_add_local_identity_service_account(
+    grpc_gcp_handshaker_req* req, grpc_gcp_handshake_protocol key,
+    const char* service_account);
+
+/**
+ * This method sets the value for rpc_versions field of either ALTS
+ * client_start or server_start handshake request.
+ *
+ * - req: an ALTS handshake request.
+ * - max_major: a major version of maximum supported RPC version.
+ * - max_minor: a minor version of maximum supported RPC version.
+ * - min_major: a major version of minimum supported RPC version.
+ * - min_minor: a minor version of minimum supported RPC version.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_handshaker_req_set_rpc_versions(grpc_gcp_handshaker_req* req,
+                                              uint32_t max_major,
+                                              uint32_t max_minor,
+                                              uint32_t min_major,
+                                              uint32_t min_minor);
+
+/**
+ * This method serializes an ALTS handshake request and returns a data stream.
+ *
+ * - req: an ALTS handshake request.
+ * - slice: a data stream where the serialized result will be written.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_handshaker_req_encode(grpc_gcp_handshaker_req* req,
+                                    grpc_slice* slice);
+
+/* This method destroys an ALTS handshake request. */
+void grpc_gcp_handshaker_req_destroy(grpc_gcp_handshaker_req* req);
+
+/* This method creates an ALTS handshake response. */
+grpc_gcp_handshaker_resp* grpc_gcp_handshaker_resp_create(void);
+
+/**
+ * This method de-serializes a data stream and stores the result
+ * in an ALTS handshake response.
+ *
+ * - slice: a data stream containing a serialized ALTS handshake response.
+ * - resp: an ALTS handshake response used to hold de-serialized result.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_handshaker_resp_decode(grpc_slice slice,
+                                     grpc_gcp_handshaker_resp* resp);
+
+/* This method destroys an ALTS handshake response. */
+void grpc_gcp_handshaker_resp_destroy(grpc_gcp_handshaker_resp* resp);
+
+#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_SERVICE_API_H */
diff --git a/src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc b/src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc
new file mode 100644
index 0000000..e0e4184
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc
@@ -0,0 +1,143 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h"
+
+void add_repeated_field(repeated_field** head, const void* data) {
+  repeated_field* field =
+      static_cast<repeated_field*>(gpr_zalloc(sizeof(*field)));
+  field->data = data;
+  if (*head == nullptr) {
+    *head = field;
+    (*head)->next = nullptr;
+  } else {
+    field->next = *head;
+    *head = field;
+  }
+}
+
+void destroy_repeated_field_list_identity(repeated_field* head) {
+  repeated_field* field = head;
+  while (field != nullptr) {
+    repeated_field* next_field = field->next;
+    const grpc_gcp_identity* identity =
+        static_cast<const grpc_gcp_identity*>(field->data);
+    destroy_slice(static_cast<grpc_slice*>(identity->hostname.arg));
+    destroy_slice(static_cast<grpc_slice*>(identity->service_account.arg));
+    gpr_free((void*)identity);
+    gpr_free(field);
+    field = next_field;
+  }
+}
+
+void destroy_repeated_field_list_string(repeated_field* head) {
+  repeated_field* field = head;
+  while (field != nullptr) {
+    repeated_field* next_field = field->next;
+    destroy_slice((grpc_slice*)field->data);
+    gpr_free(field);
+    field = next_field;
+  }
+}
+
+grpc_slice* create_slice(const char* data, size_t size) {
+  grpc_slice slice = grpc_slice_from_copied_buffer(data, size);
+  grpc_slice* cb_slice =
+      static_cast<grpc_slice*>(gpr_zalloc(sizeof(*cb_slice)));
+  memcpy(cb_slice, &slice, sizeof(*cb_slice));
+  return cb_slice;
+}
+
+void destroy_slice(grpc_slice* slice) {
+  if (slice != nullptr) {
+    grpc_slice_unref(*slice);
+    gpr_free(slice);
+  }
+}
+
+bool encode_string_or_bytes_cb(pb_ostream_t* stream, const pb_field_t* field,
+                               void* const* arg) {
+  grpc_slice* slice = static_cast<grpc_slice*>(*arg);
+  if (!pb_encode_tag_for_field(stream, field)) return false;
+  return pb_encode_string(stream, GRPC_SLICE_START_PTR(*slice),
+                          GRPC_SLICE_LENGTH(*slice));
+}
+
+bool encode_repeated_identity_cb(pb_ostream_t* stream, const pb_field_t* field,
+                                 void* const* arg) {
+  repeated_field* var = static_cast<repeated_field*>(*arg);
+  while (var != nullptr) {
+    if (!pb_encode_tag_for_field(stream, field)) return false;
+    if (!pb_encode_submessage(stream, grpc_gcp_Identity_fields,
+                              (grpc_gcp_identity*)var->data))
+      return false;
+    var = var->next;
+  }
+  return true;
+}
+
+bool encode_repeated_string_cb(pb_ostream_t* stream, const pb_field_t* field,
+                               void* const* arg) {
+  repeated_field* var = static_cast<repeated_field*>(*arg);
+  while (var != nullptr) {
+    if (!pb_encode_tag_for_field(stream, field)) return false;
+    const grpc_slice* slice = static_cast<const grpc_slice*>(var->data);
+    if (!pb_encode_string(stream, GRPC_SLICE_START_PTR(*slice),
+                          GRPC_SLICE_LENGTH(*slice)))
+      return false;
+    var = var->next;
+  }
+  return true;
+}
+
+bool decode_string_or_bytes_cb(pb_istream_t* stream, const pb_field_t* field,
+                               void** arg) {
+  grpc_slice slice = grpc_slice_malloc(stream->bytes_left);
+  grpc_slice* cb_slice =
+      static_cast<grpc_slice*>(gpr_zalloc(sizeof(*cb_slice)));
+  memcpy(cb_slice, &slice, sizeof(*cb_slice));
+  if (!pb_read(stream, GRPC_SLICE_START_PTR(*cb_slice), stream->bytes_left))
+    return false;
+  *arg = cb_slice;
+  return true;
+}
+
+bool decode_repeated_identity_cb(pb_istream_t* stream, const pb_field_t* field,
+                                 void** arg) {
+  grpc_gcp_identity* identity =
+      static_cast<grpc_gcp_identity*>(gpr_zalloc(sizeof(*identity)));
+  identity->hostname.funcs.decode = decode_string_or_bytes_cb;
+  identity->service_account.funcs.decode = decode_string_or_bytes_cb;
+  add_repeated_field(reinterpret_cast<repeated_field**>(arg), identity);
+  if (!pb_decode(stream, grpc_gcp_Identity_fields, identity)) return false;
+  return true;
+}
+
+bool decode_repeated_string_cb(pb_istream_t* stream, const pb_field_t* field,
+                               void** arg) {
+  grpc_slice slice = grpc_slice_malloc(stream->bytes_left);
+  grpc_slice* cb_slice =
+      static_cast<grpc_slice*>(gpr_zalloc(sizeof(*cb_slice)));
+  memcpy(cb_slice, &slice, sizeof(grpc_slice));
+  if (!pb_read(stream, GRPC_SLICE_START_PTR(*cb_slice), stream->bytes_left))
+    return false;
+  add_repeated_field(reinterpret_cast<repeated_field**>(arg), cb_slice);
+  return true;
+}
diff --git a/src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h b/src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h
new file mode 100644
index 0000000..8fe8f73
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h
@@ -0,0 +1,149 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_SERVICE_API_UTIL_H
+#define GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_SERVICE_API_UTIL_H
+
+#include <grpc/support/port_platform.h>
+
+#include "third_party/nanopb/pb_decode.h"
+#include "third_party/nanopb/pb_encode.h"
+
+#include <grpc/slice.h>
+#include <grpc/slice_buffer.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/tsi/alts/handshaker/handshaker.pb.h"
+
+/**
+ * An implementation of utility functions used to serialize/
+ * de-serialize ALTS handshake requests/responses. All APIs in the header
+ * are thread-compatible.
+ */
+
+/* Renaming of message/field structs generated by nanopb compiler. */
+typedef grpc_gcp_HandshakeProtocol grpc_gcp_handshake_protocol;
+typedef grpc_gcp_NetworkProtocol grpc_gcp_network_protocol;
+typedef grpc_gcp_Identity grpc_gcp_identity;
+typedef grpc_gcp_NextHandshakeMessageReq grpc_gcp_next_handshake_message_req;
+typedef grpc_gcp_ServerHandshakeParameters grpc_gcp_server_handshake_parameters;
+typedef grpc_gcp_Endpoint grpc_gcp_endpoint;
+typedef grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry
+    grpc_gcp_handshake_parameters_entry;
+typedef grpc_gcp_StartClientHandshakeReq grpc_gcp_start_client_handshake_req;
+typedef grpc_gcp_StartServerHandshakeReq grpc_gcp_start_server_handshake_req;
+typedef grpc_gcp_HandshakerReq grpc_gcp_handshaker_req;
+typedef grpc_gcp_HandshakerResult grpc_gcp_handshaker_result;
+typedef grpc_gcp_HandshakerStatus grpc_gcp_handshaker_status;
+typedef grpc_gcp_HandshakerResp grpc_gcp_handshaker_resp;
+
+typedef enum {
+  CLIENT_START_REQ = 0, /* StartClientHandshakeReq. */
+  SERVER_START_REQ = 1, /* StartServerHandshakeReq. */
+  NEXT_REQ = 2,         /* NextHandshakeMessageReq. */
+} grpc_gcp_handshaker_req_type;
+
+/**
+ *  A struct representing a repeated field. The struct is used to organize all
+ *  instances of a specific repeated field into a linked list, which then will
+ *  be used at encode/decode phase. For instance at the encode phase, the encode
+ *  function will iterate through the list, encode each field, and then output
+ *  the result to the stream.
+ */
+typedef struct repeated_field_ {
+  struct repeated_field_* next;
+  const void* data;
+} repeated_field;
+
+/**
+ * This method adds a repeated field to the head of repeated field list.
+ *
+ * - head: a head of repeated field list.
+ * - field: a repeated field to be added to the list.
+ */
+void add_repeated_field(repeated_field** head, const void* field);
+
+/**
+ * This method destroys a repeated field list that consists of string type
+ * fields.
+ *
+ * - head: a head of repeated field list.
+ */
+void destroy_repeated_field_list_string(repeated_field* head);
+
+/**
+ * This method destroys a repeated field list that consists of
+ * grpc_gcp_identity type fields.
+ *
+ * - head: a head of repeated field list.
+ */
+void destroy_repeated_field_list_identity(repeated_field* head);
+
+/**
+ * This method creates a grpc_slice instance by copying a data buffer. It is
+ * similar to grpc_slice_from_copied_buffer() except that it returns an instance
+ * allocated from the heap.
+ *
+ * - data: a data buffer to be copied to grpc_slice instance.
+ * - size: size of data buffer.
+ */
+grpc_slice* create_slice(const char* data, size_t size);
+
+/* This method destroys a grpc_slice instance. */
+void destroy_slice(grpc_slice* slice);
+
+/**
+ * The following encode/decode functions will be assigned to encode/decode
+ * function pointers of pb_callback_t struct (defined in
+ * //third_party/nanopb/pb.h), that represent a repeated field with a dynamic
+ * length (e.g., a string type or repeated field).
+ */
+
+/* This method is an encode callback function for a string or byte array. */
+bool encode_string_or_bytes_cb(pb_ostream_t* stream, const pb_field_t* field,
+                               void* const* arg);
+
+/**
+ * This method is an encode callback function for a repeated grpc_gcp_identity
+ * field.
+ */
+bool encode_repeated_identity_cb(pb_ostream_t* stream, const pb_field_t* field,
+                                 void* const* arg);
+
+/* This method is an encode callback function for a repeated string field. */
+bool encode_repeated_string_cb(pb_ostream_t* stream, const pb_field_t* field,
+                               void* const* arg);
+
+/**
+ * This method is a decode callback function for a string or byte array field.
+ */
+bool decode_string_or_bytes_cb(pb_istream_t* stream, const pb_field_t* field,
+                               void** arg);
+/**
+ * This method is a decode callback function for a repeated grpc_gcp_identity
+ * field.
+ */
+bool decode_repeated_identity_cb(pb_istream_t* stream, const pb_field_t* field,
+                                 void** arg);
+
+/* This method is a decode callback function for a repeated string field. */
+bool decode_repeated_string_cb(pb_istream_t* stream, const pb_field_t* field,
+                               void** arg);
+
+#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_SERVICE_API_UTIL_H */
diff --git a/src/core/tsi/alts/handshaker/alts_tsi_event.cc b/src/core/tsi/alts/handshaker/alts_tsi_event.cc
new file mode 100644
index 0000000..ec0bf12
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/alts_tsi_event.cc
@@ -0,0 +1,73 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/handshaker/alts_tsi_event.h"
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+tsi_result alts_tsi_event_create(alts_tsi_handshaker* handshaker,
+                                 tsi_handshaker_on_next_done_cb cb,
+                                 void* user_data,
+                                 grpc_alts_credentials_options* options,
+                                 grpc_slice target_name,
+                                 alts_tsi_event** event) {
+  if (event == nullptr || handshaker == nullptr || cb == nullptr) {
+    gpr_log(GPR_ERROR, "Invalid arguments to alts_tsi_event_create()");
+    return TSI_INVALID_ARGUMENT;
+  }
+  alts_tsi_event* e = static_cast<alts_tsi_event*>(gpr_zalloc(sizeof(*e)));
+  e->handshaker = handshaker;
+  e->cb = cb;
+  e->user_data = user_data;
+  e->options = grpc_alts_credentials_options_copy(options);
+  e->target_name = grpc_slice_copy(target_name);
+  grpc_metadata_array_init(&e->initial_metadata);
+  grpc_metadata_array_init(&e->trailing_metadata);
+  *event = e;
+  return TSI_OK;
+}
+
+void alts_tsi_event_dispatch_to_handshaker(alts_tsi_event* event, bool is_ok) {
+  if (event == nullptr) {
+    gpr_log(
+        GPR_ERROR,
+        "ALTS TSI event is nullptr in alts_tsi_event_dispatch_to_handshaker()");
+    return;
+  }
+  alts_tsi_handshaker_handle_response(event->handshaker, event->recv_buffer,
+                                      event->status, &event->details, event->cb,
+                                      event->user_data, is_ok);
+}
+
+void alts_tsi_event_destroy(alts_tsi_event* event) {
+  if (event == nullptr) {
+    return;
+  }
+  grpc_byte_buffer_destroy(event->send_buffer);
+  grpc_byte_buffer_destroy(event->recv_buffer);
+  grpc_metadata_array_destroy(&event->initial_metadata);
+  grpc_metadata_array_destroy(&event->trailing_metadata);
+  grpc_slice_unref(event->details);
+  grpc_slice_unref(event->target_name);
+  grpc_alts_credentials_options_destroy(event->options);
+  gpr_free(event);
+}
diff --git a/src/core/tsi/alts/handshaker/alts_tsi_event.h b/src/core/tsi/alts/handshaker/alts_tsi_event.h
new file mode 100644
index 0000000..043e75d
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/alts_tsi_event.h
@@ -0,0 +1,93 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_EVENT_H
+#define GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_EVENT_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/byte_buffer_reader.h>
+
+#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h"
+#include "src/core/tsi/transport_security_interface.h"
+
+/**
+ * A ALTS TSI event interface. In asynchronous implementation of
+ * tsi_handshaker_next(), the function will exit after scheduling a handshaker
+ * request to ALTS handshaker service without waiting for response to return.
+ * The event is used to link the scheduled handshaker request with the
+ * corresponding response so that enough context information can be inferred
+ * from it to handle the response. All APIs in the header are thread-compatible.
+ */
+
+/**
+ * Main struct for ALTS TSI event. It retains ownership on send_buffer and
+ * recv_buffer, but not on handshaker.
+ */
+typedef struct alts_tsi_event {
+  alts_tsi_handshaker* handshaker;
+  grpc_byte_buffer* send_buffer;
+  grpc_byte_buffer* recv_buffer;
+  grpc_status_code status;
+  grpc_slice details;
+  grpc_metadata_array initial_metadata;
+  grpc_metadata_array trailing_metadata;
+  tsi_handshaker_on_next_done_cb cb;
+  void* user_data;
+  grpc_alts_credentials_options* options;
+  grpc_slice target_name;
+} alts_tsi_event;
+
+/**
+ * This method creates a ALTS TSI event.
+ *
+ * - handshaker: ALTS TSI handshaker instance associated with the event to be
+ *   created. The created event does not own the handshaker instance.
+ * - cb: callback function to be called when handling data received from ALTS
+ *   handshaker service.
+ * - user_data: argument to callback function.
+ * - options: ALTS credentials options.
+ * - target_name: name of endpoint used for secure naming check.
+ * - event: address of ALTS TSI event instance to be returned from the method.
+ *
+ * It returns TSI_OK on success and an error status code on failure.
+ */
+tsi_result alts_tsi_event_create(alts_tsi_handshaker* handshaker,
+                                 tsi_handshaker_on_next_done_cb cb,
+                                 void* user_data,
+                                 grpc_alts_credentials_options* options,
+                                 grpc_slice target_name,
+                                 alts_tsi_event** event);
+
+/**
+ * This method dispatches a ALTS TSI event received from the handshaker service,
+ * and a boolean flag indicating if the event is valid to read to ALTS TSI
+ * handshaker to process. It is called by TSI thread.
+ *
+ * - event: ALTS TSI event instance.
+ * - is_ok: a boolean value indicating if the event is valid to read.
+ */
+void alts_tsi_event_dispatch_to_handshaker(alts_tsi_event* event, bool is_ok);
+
+/**
+ * This method destroys the ALTS TSI event.
+ */
+void alts_tsi_event_destroy(alts_tsi_event* event);
+
+#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_EVENT_H */
diff --git a/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc b/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc
new file mode 100644
index 0000000..529f210
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc
@@ -0,0 +1,483 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd_id.h>
+
+#include "src/core/lib/gpr/host_port.h"
+#include "src/core/lib/gprpp/thd.h"
+#include "src/core/tsi/alts/frame_protector/alts_frame_protector.h"
+#include "src/core/tsi/alts/handshaker/alts_handshaker_client.h"
+#include "src/core/tsi/alts/handshaker/alts_tsi_utils.h"
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h"
+#include "src/core/tsi/alts_transport_security.h"
+
+#define TSI_ALTS_INITIAL_BUFFER_SIZE 256
+
+static alts_shared_resource* kSharedResource = alts_get_shared_resource();
+
+/* Main struct for ALTS TSI handshaker. */
+typedef struct alts_tsi_handshaker {
+  tsi_handshaker base;
+  alts_handshaker_client* client;
+  grpc_slice recv_bytes;
+  grpc_slice target_name;
+  unsigned char* buffer;
+  size_t buffer_size;
+  bool is_client;
+  bool has_sent_start_message;
+  grpc_alts_credentials_options* options;
+} alts_tsi_handshaker;
+
+/* Main struct for ALTS TSI handshaker result. */
+typedef struct alts_tsi_handshaker_result {
+  tsi_handshaker_result base;
+  char* peer_identity;
+  char* key_data;
+  unsigned char* unused_bytes;
+  size_t unused_bytes_size;
+  grpc_slice rpc_versions;
+  bool is_client;
+} alts_tsi_handshaker_result;
+
+static tsi_result handshaker_result_extract_peer(
+    const tsi_handshaker_result* self, tsi_peer* peer) {
+  if (self == nullptr || peer == nullptr) {
+    gpr_log(GPR_ERROR, "Invalid argument to handshaker_result_extract_peer()");
+    return TSI_INVALID_ARGUMENT;
+  }
+  alts_tsi_handshaker_result* result =
+      reinterpret_cast<alts_tsi_handshaker_result*>(
+          const_cast<tsi_handshaker_result*>(self));
+  GPR_ASSERT(kTsiAltsNumOfPeerProperties == 3);
+  tsi_result ok = tsi_construct_peer(kTsiAltsNumOfPeerProperties, peer);
+  int index = 0;
+  if (ok != TSI_OK) {
+    gpr_log(GPR_ERROR, "Failed to construct tsi peer");
+    return ok;
+  }
+  GPR_ASSERT(&peer->properties[index] != nullptr);
+  ok = tsi_construct_string_peer_property_from_cstring(
+      TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_ALTS_CERTIFICATE_TYPE,
+      &peer->properties[index]);
+  if (ok != TSI_OK) {
+    tsi_peer_destruct(peer);
+    gpr_log(GPR_ERROR, "Failed to set tsi peer property");
+    return ok;
+  }
+  index++;
+  GPR_ASSERT(&peer->properties[index] != nullptr);
+  ok = tsi_construct_string_peer_property_from_cstring(
+      TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY, result->peer_identity,
+      &peer->properties[index]);
+  if (ok != TSI_OK) {
+    tsi_peer_destruct(peer);
+    gpr_log(GPR_ERROR, "Failed to set tsi peer property");
+  }
+  index++;
+  GPR_ASSERT(&peer->properties[index] != nullptr);
+  ok = tsi_construct_string_peer_property(
+      TSI_ALTS_RPC_VERSIONS,
+      reinterpret_cast<char*>(GRPC_SLICE_START_PTR(result->rpc_versions)),
+      GRPC_SLICE_LENGTH(result->rpc_versions), &peer->properties[2]);
+  if (ok != TSI_OK) {
+    tsi_peer_destruct(peer);
+    gpr_log(GPR_ERROR, "Failed to set tsi peer property");
+  }
+  GPR_ASSERT(++index == kTsiAltsNumOfPeerProperties);
+  return ok;
+}
+
+static tsi_result handshaker_result_create_zero_copy_grpc_protector(
+    const tsi_handshaker_result* self, size_t* max_output_protected_frame_size,
+    tsi_zero_copy_grpc_protector** protector) {
+  if (self == nullptr || protector == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid arguments to create_zero_copy_grpc_protector()");
+    return TSI_INVALID_ARGUMENT;
+  }
+  alts_tsi_handshaker_result* result =
+      reinterpret_cast<alts_tsi_handshaker_result*>(
+          const_cast<tsi_handshaker_result*>(self));
+  tsi_result ok = alts_zero_copy_grpc_protector_create(
+      reinterpret_cast<const uint8_t*>(result->key_data),
+      kAltsAes128GcmRekeyKeyLength, /*is_rekey=*/true, result->is_client,
+      /*is_integrity_only=*/false, max_output_protected_frame_size, protector);
+  if (ok != TSI_OK) {
+    gpr_log(GPR_ERROR, "Failed to create zero-copy grpc protector");
+  }
+  return ok;
+}
+
+static tsi_result handshaker_result_create_frame_protector(
+    const tsi_handshaker_result* self, size_t* max_output_protected_frame_size,
+    tsi_frame_protector** protector) {
+  if (self == nullptr || protector == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid arguments to handshaker_result_create_frame_protector()");
+    return TSI_INVALID_ARGUMENT;
+  }
+  alts_tsi_handshaker_result* result =
+      reinterpret_cast<alts_tsi_handshaker_result*>(
+          const_cast<tsi_handshaker_result*>(self));
+  tsi_result ok = alts_create_frame_protector(
+      reinterpret_cast<const uint8_t*>(result->key_data),
+      kAltsAes128GcmRekeyKeyLength, result->is_client, /*is_rekey=*/true,
+      max_output_protected_frame_size, protector);
+  if (ok != TSI_OK) {
+    gpr_log(GPR_ERROR, "Failed to create frame protector");
+  }
+  return ok;
+}
+
+static tsi_result handshaker_result_get_unused_bytes(
+    const tsi_handshaker_result* self, const unsigned char** bytes,
+    size_t* bytes_size) {
+  if (self == nullptr || bytes == nullptr || bytes_size == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid arguments to handshaker_result_get_unused_bytes()");
+    return TSI_INVALID_ARGUMENT;
+  }
+  alts_tsi_handshaker_result* result =
+      reinterpret_cast<alts_tsi_handshaker_result*>(
+          const_cast<tsi_handshaker_result*>(self));
+  *bytes = result->unused_bytes;
+  *bytes_size = result->unused_bytes_size;
+  return TSI_OK;
+}
+
+static void handshaker_result_destroy(tsi_handshaker_result* self) {
+  if (self == nullptr) {
+    return;
+  }
+  alts_tsi_handshaker_result* result =
+      reinterpret_cast<alts_tsi_handshaker_result*>(
+          const_cast<tsi_handshaker_result*>(self));
+  gpr_free(result->peer_identity);
+  gpr_free(result->key_data);
+  gpr_free(result->unused_bytes);
+  grpc_slice_unref(result->rpc_versions);
+  gpr_free(result);
+}
+
+static const tsi_handshaker_result_vtable result_vtable = {
+    handshaker_result_extract_peer,
+    handshaker_result_create_zero_copy_grpc_protector,
+    handshaker_result_create_frame_protector,
+    handshaker_result_get_unused_bytes, handshaker_result_destroy};
+
+static tsi_result create_handshaker_result(grpc_gcp_handshaker_resp* resp,
+                                           bool is_client,
+                                           tsi_handshaker_result** self) {
+  if (self == nullptr || resp == nullptr) {
+    gpr_log(GPR_ERROR, "Invalid arguments to create_handshaker_result()");
+    return TSI_INVALID_ARGUMENT;
+  }
+  grpc_slice* key = static_cast<grpc_slice*>(resp->result.key_data.arg);
+  GPR_ASSERT(key != nullptr);
+  grpc_slice* identity =
+      static_cast<grpc_slice*>(resp->result.peer_identity.service_account.arg);
+  if (identity == nullptr) {
+    gpr_log(GPR_ERROR, "Invalid service account");
+    return TSI_FAILED_PRECONDITION;
+  }
+  if (GRPC_SLICE_LENGTH(*key) < kAltsAes128GcmRekeyKeyLength) {
+    gpr_log(GPR_ERROR, "Bad key length");
+    return TSI_FAILED_PRECONDITION;
+  }
+  alts_tsi_handshaker_result* result =
+      static_cast<alts_tsi_handshaker_result*>(gpr_zalloc(sizeof(*result)));
+  result->key_data =
+      static_cast<char*>(gpr_zalloc(kAltsAes128GcmRekeyKeyLength));
+  memcpy(result->key_data, GRPC_SLICE_START_PTR(*key),
+         kAltsAes128GcmRekeyKeyLength);
+  result->peer_identity = grpc_slice_to_c_string(*identity);
+  if (!resp->result.has_peer_rpc_versions) {
+    gpr_log(GPR_ERROR, "Peer does not set RPC protocol versions.");
+    return TSI_FAILED_PRECONDITION;
+  }
+  if (!grpc_gcp_rpc_protocol_versions_encode(&resp->result.peer_rpc_versions,
+                                             &result->rpc_versions)) {
+    gpr_log(GPR_ERROR, "Failed to serialize peer's RPC protocol versions.");
+    return TSI_FAILED_PRECONDITION;
+  }
+  result->is_client = is_client;
+  result->base.vtable = &result_vtable;
+  *self = &result->base;
+  return TSI_OK;
+}
+
+static tsi_result handshaker_next(
+    tsi_handshaker* self, const unsigned char* received_bytes,
+    size_t received_bytes_size, const unsigned char** bytes_to_send,
+    size_t* bytes_to_send_size, tsi_handshaker_result** result,
+    tsi_handshaker_on_next_done_cb cb, void* user_data) {
+  if (self == nullptr || cb == nullptr) {
+    gpr_log(GPR_ERROR, "Invalid arguments to handshaker_next()");
+    return TSI_INVALID_ARGUMENT;
+  }
+  alts_tsi_handshaker* handshaker =
+      reinterpret_cast<alts_tsi_handshaker*>(self);
+  tsi_result ok = TSI_OK;
+  alts_tsi_event* event = nullptr;
+  ok = alts_tsi_event_create(handshaker, cb, user_data, handshaker->options,
+                             handshaker->target_name, &event);
+  if (ok != TSI_OK) {
+    gpr_log(GPR_ERROR, "Failed to create ALTS TSI event");
+    return ok;
+  }
+  grpc_slice slice = (received_bytes == nullptr || received_bytes_size == 0)
+                         ? grpc_empty_slice()
+                         : grpc_slice_from_copied_buffer(
+                               reinterpret_cast<const char*>(received_bytes),
+                               received_bytes_size);
+  if (!handshaker->has_sent_start_message) {
+    ok = handshaker->is_client
+             ? alts_handshaker_client_start_client(handshaker->client, event)
+             : alts_handshaker_client_start_server(handshaker->client, event,
+                                                   &slice);
+    handshaker->has_sent_start_message = true;
+  } else {
+    if (!GRPC_SLICE_IS_EMPTY(handshaker->recv_bytes)) {
+      grpc_slice_unref(handshaker->recv_bytes);
+    }
+    handshaker->recv_bytes = grpc_slice_ref(slice);
+    ok = alts_handshaker_client_next(handshaker->client, event, &slice);
+  }
+  grpc_slice_unref(slice);
+  if (ok != TSI_OK) {
+    gpr_log(GPR_ERROR, "Failed to schedule ALTS handshaker requests");
+    return ok;
+  }
+  return TSI_ASYNC;
+}
+
+static void handshaker_destroy(tsi_handshaker* self) {
+  if (self == nullptr) {
+    return;
+  }
+  alts_tsi_handshaker* handshaker =
+      reinterpret_cast<alts_tsi_handshaker*>(self);
+  alts_handshaker_client_destroy(handshaker->client);
+  grpc_slice_unref(handshaker->recv_bytes);
+  grpc_slice_unref(handshaker->target_name);
+  grpc_alts_credentials_options_destroy(handshaker->options);
+  gpr_free(handshaker->buffer);
+  gpr_free(handshaker);
+}
+
+static const tsi_handshaker_vtable handshaker_vtable = {
+    nullptr,        nullptr, nullptr, nullptr, nullptr, handshaker_destroy,
+    handshaker_next};
+
+static void thread_worker(void* arg) {
+  while (true) {
+    grpc_event event = grpc_completion_queue_next(
+        kSharedResource->cq, gpr_inf_future(GPR_CLOCK_REALTIME), nullptr);
+    GPR_ASSERT(event.type != GRPC_QUEUE_TIMEOUT);
+    if (event.type == GRPC_QUEUE_SHUTDOWN) {
+      /* signal alts_tsi_shutdown() to destroy completion queue. */
+      grpc_tsi_alts_signal_for_cq_destroy();
+      break;
+    }
+    /* event.type == GRPC_OP_COMPLETE. */
+    alts_tsi_event* alts_event = static_cast<alts_tsi_event*>(event.tag);
+    alts_tsi_event_dispatch_to_handshaker(alts_event, event.success);
+    alts_tsi_event_destroy(alts_event);
+  }
+}
+
+static void init_shared_resources(const char* handshaker_service_url) {
+  GPR_ASSERT(handshaker_service_url != nullptr);
+  gpr_mu_lock(&kSharedResource->mu);
+  if (kSharedResource->channel == nullptr) {
+    gpr_cv_init(&kSharedResource->cv);
+    kSharedResource->channel =
+        grpc_insecure_channel_create(handshaker_service_url, nullptr, nullptr);
+    kSharedResource->cq = grpc_completion_queue_create_for_next(nullptr);
+    kSharedResource->thread =
+        grpc_core::Thread("alts_tsi_handshaker", &thread_worker, nullptr);
+    kSharedResource->thread.Start();
+  }
+  gpr_mu_unlock(&kSharedResource->mu);
+}
+
+tsi_result alts_tsi_handshaker_create(
+    const grpc_alts_credentials_options* options, const char* target_name,
+    const char* handshaker_service_url, bool is_client, tsi_handshaker** self) {
+  if (handshaker_service_url == nullptr || self == nullptr ||
+      options == nullptr || (is_client && target_name == nullptr)) {
+    gpr_log(GPR_ERROR, "Invalid arguments to alts_tsi_handshaker_create()");
+    return TSI_INVALID_ARGUMENT;
+  }
+  init_shared_resources(handshaker_service_url);
+  alts_handshaker_client* client = alts_grpc_handshaker_client_create(
+      kSharedResource->channel, kSharedResource->cq, handshaker_service_url);
+  if (client == nullptr) {
+    gpr_log(GPR_ERROR, "Failed to create ALTS handshaker client");
+    return TSI_FAILED_PRECONDITION;
+  }
+  alts_tsi_handshaker* handshaker =
+      static_cast<alts_tsi_handshaker*>(gpr_zalloc(sizeof(*handshaker)));
+  handshaker->client = client;
+  handshaker->buffer_size = TSI_ALTS_INITIAL_BUFFER_SIZE;
+  handshaker->buffer =
+      static_cast<unsigned char*>(gpr_zalloc(handshaker->buffer_size));
+  handshaker->is_client = is_client;
+  handshaker->has_sent_start_message = false;
+  handshaker->target_name = target_name == nullptr
+                                ? grpc_empty_slice()
+                                : grpc_slice_from_static_string(target_name);
+  handshaker->options = grpc_alts_credentials_options_copy(options);
+  handshaker->base.vtable = &handshaker_vtable;
+  *self = &handshaker->base;
+  return TSI_OK;
+}
+
+static bool is_handshake_finished_properly(grpc_gcp_handshaker_resp* resp) {
+  GPR_ASSERT(resp != nullptr);
+  if (resp->has_result) {
+    return true;
+  }
+  return false;
+}
+
+static void set_unused_bytes(tsi_handshaker_result* self,
+                             grpc_slice* recv_bytes, size_t bytes_consumed) {
+  GPR_ASSERT(recv_bytes != nullptr && self != nullptr);
+  if (GRPC_SLICE_LENGTH(*recv_bytes) == bytes_consumed) {
+    return;
+  }
+  alts_tsi_handshaker_result* result =
+      reinterpret_cast<alts_tsi_handshaker_result*>(self);
+  result->unused_bytes_size = GRPC_SLICE_LENGTH(*recv_bytes) - bytes_consumed;
+  result->unused_bytes =
+      static_cast<unsigned char*>(gpr_zalloc(result->unused_bytes_size));
+  memcpy(result->unused_bytes,
+         GRPC_SLICE_START_PTR(*recv_bytes) + bytes_consumed,
+         result->unused_bytes_size);
+}
+
+void alts_tsi_handshaker_handle_response(alts_tsi_handshaker* handshaker,
+                                         grpc_byte_buffer* recv_buffer,
+                                         grpc_status_code status,
+                                         grpc_slice* details,
+                                         tsi_handshaker_on_next_done_cb cb,
+                                         void* user_data, bool is_ok) {
+  /* Invalid input check. */
+  if (cb == nullptr) {
+    gpr_log(GPR_ERROR,
+            "cb is nullptr in alts_tsi_handshaker_handle_response()");
+    return;
+  }
+  if (handshaker == nullptr || recv_buffer == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid arguments to alts_tsi_handshaker_handle_response()");
+    cb(TSI_INTERNAL_ERROR, user_data, nullptr, 0, nullptr);
+    return;
+  }
+  /* Failed grpc call check. */
+  if (!is_ok || status != GRPC_STATUS_OK) {
+    gpr_log(GPR_ERROR, "grpc call made to handshaker service failed");
+    if (details != nullptr) {
+      char* error_details = grpc_slice_to_c_string(*details);
+      gpr_log(GPR_ERROR, "error details:%s", error_details);
+      gpr_free(error_details);
+    }
+    cb(TSI_INTERNAL_ERROR, user_data, nullptr, 0, nullptr);
+    return;
+  }
+  grpc_gcp_handshaker_resp* resp =
+      alts_tsi_utils_deserialize_response(recv_buffer);
+  /* Invalid handshaker response check. */
+  if (resp == nullptr) {
+    gpr_log(GPR_ERROR, "alts_tsi_utils_deserialize_response() failed");
+    cb(TSI_DATA_CORRUPTED, user_data, nullptr, 0, nullptr);
+    return;
+  }
+  grpc_slice* slice = static_cast<grpc_slice*>(resp->out_frames.arg);
+  unsigned char* bytes_to_send = nullptr;
+  size_t bytes_to_send_size = 0;
+  if (slice != nullptr) {
+    bytes_to_send_size = GRPC_SLICE_LENGTH(*slice);
+    while (bytes_to_send_size > handshaker->buffer_size) {
+      handshaker->buffer_size *= 2;
+      handshaker->buffer = static_cast<unsigned char*>(
+          gpr_realloc(handshaker->buffer, handshaker->buffer_size));
+    }
+    memcpy(handshaker->buffer, GRPC_SLICE_START_PTR(*slice),
+           bytes_to_send_size);
+    bytes_to_send = handshaker->buffer;
+  }
+  tsi_handshaker_result* result = nullptr;
+  if (is_handshake_finished_properly(resp)) {
+    create_handshaker_result(resp, handshaker->is_client, &result);
+    set_unused_bytes(result, &handshaker->recv_bytes, resp->bytes_consumed);
+  }
+  grpc_status_code code = static_cast<grpc_status_code>(resp->status.code);
+  grpc_gcp_handshaker_resp_destroy(resp);
+  cb(alts_tsi_utils_convert_to_tsi_result(code), user_data, bytes_to_send,
+     bytes_to_send_size, result);
+}
+
+namespace grpc_core {
+namespace internal {
+
+bool alts_tsi_handshaker_get_has_sent_start_message_for_testing(
+    alts_tsi_handshaker* handshaker) {
+  GPR_ASSERT(handshaker != nullptr);
+  return handshaker->has_sent_start_message;
+}
+
+bool alts_tsi_handshaker_get_is_client_for_testing(
+    alts_tsi_handshaker* handshaker) {
+  GPR_ASSERT(handshaker != nullptr);
+  return handshaker->is_client;
+}
+
+void alts_tsi_handshaker_set_recv_bytes_for_testing(
+    alts_tsi_handshaker* handshaker, grpc_slice* slice) {
+  GPR_ASSERT(handshaker != nullptr && slice != nullptr);
+  handshaker->recv_bytes = grpc_slice_ref(*slice);
+}
+
+grpc_slice alts_tsi_handshaker_get_recv_bytes_for_testing(
+    alts_tsi_handshaker* handshaker) {
+  GPR_ASSERT(handshaker != nullptr);
+  return handshaker->recv_bytes;
+}
+
+void alts_tsi_handshaker_set_client_for_testing(
+    alts_tsi_handshaker* handshaker, alts_handshaker_client* client) {
+  GPR_ASSERT(handshaker != nullptr && client != nullptr);
+  alts_handshaker_client_destroy(handshaker->client);
+  handshaker->client = client;
+}
+
+}  // namespace internal
+}  // namespace grpc_core
diff --git a/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h b/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h
new file mode 100644
index 0000000..227b30c
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/alts_tsi_handshaker.h
@@ -0,0 +1,83 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_HANDSHAKER_H
+#define GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_HANDSHAKER_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/grpc.h>
+
+#include "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h"
+#include "src/core/tsi/alts_transport_security.h"
+#include "src/core/tsi/transport_security.h"
+#include "src/core/tsi/transport_security_interface.h"
+
+#define TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY "service_accont"
+#define TSI_ALTS_CERTIFICATE_TYPE "ALTS"
+#define TSI_ALTS_RPC_VERSIONS "rpc_versions"
+
+const size_t kTsiAltsNumOfPeerProperties = 3;
+
+/**
+ * Main struct for ALTS TSI handshaker. All APIs in the header are
+ * thread-comptabile.
+ */
+typedef struct alts_tsi_handshaker alts_tsi_handshaker;
+
+/**
+ * This method creates a ALTS TSI handshaker instance.
+ *
+ * - options: ALTS credentials options containing information passed from TSI
+ *   caller (e.g., rpc protocol versions).
+ * - target_name: the name of the endpoint that the channel is connecting to,
+ *   and will be used for secure naming check.
+ * - handshaker_service_url: address of ALTS handshaker service in the format of
+ *   "host:port".
+ * - is_client: boolean value indicating if the handshaker is used at the client
+ *   (is_client = true) or server (is_client = false) side.
+ * - self: address of ALTS TSI handshaker instance to be returned from the
+ *   method.
+ *
+ * It returns TSI_OK on success and an error status code on failure.
+ */
+tsi_result alts_tsi_handshaker_create(
+    const grpc_alts_credentials_options* options, const char* target_name,
+    const char* handshaker_service_url, bool is_client, tsi_handshaker** self);
+
+/**
+ * This method handles handshaker response returned from ALTS handshaker
+ * service.
+ *
+ * - handshaker: ALTS TSI handshaker instance.
+ * - recv_buffer: buffer holding data received from the handshaker service.
+ * - status: status of the grpc call made to the handshaker service.
+ * - details: error details of the grpc call made to the handshaker service.
+ * - cb: callback function of ALTS TSI event.
+ * - user_data: argument of callback function.
+ * - is_ok: a boolean value indicating if the handshaker response is ok to read.
+ *
+ */
+void alts_tsi_handshaker_handle_response(alts_tsi_handshaker* handshaker,
+                                         grpc_byte_buffer* recv_buffer,
+                                         grpc_status_code status,
+                                         grpc_slice* details,
+                                         tsi_handshaker_on_next_done_cb cb,
+                                         void* user_data, bool is_ok);
+
+#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_HANDSHAKER_H */
diff --git a/src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h b/src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h
new file mode 100644
index 0000000..9b7b9bb
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_HANDSHAKER_PRIVATE_H
+#define GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_HANDSHAKER_PRIVATE_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/handshaker/alts_handshaker_client.h"
+
+namespace grpc_core {
+namespace internal {
+
+/**
+ * Unsafe, use for testing only. It allows the caller to change the way the
+ * ALTS TSI handshaker schedules handshaker requests.
+ */
+void alts_tsi_handshaker_set_client_for_testing(alts_tsi_handshaker* handshaker,
+                                                alts_handshaker_client* client);
+
+/* For testing only. */
+bool alts_tsi_handshaker_get_has_sent_start_message_for_testing(
+    alts_tsi_handshaker* handshaker);
+
+bool alts_tsi_handshaker_get_is_client_for_testing(
+    alts_tsi_handshaker* handshaker);
+
+void alts_tsi_handshaker_set_recv_bytes_for_testing(
+    alts_tsi_handshaker* handshaker, grpc_slice* slice);
+
+grpc_slice alts_tsi_handshaker_get_recv_bytes_for_testing(
+    alts_tsi_handshaker* handshaker);
+
+}  // namespace internal
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_HANDSHAKER_PRIVATE_H */
diff --git a/src/core/tsi/alts/handshaker/alts_tsi_utils.cc b/src/core/tsi/alts/handshaker/alts_tsi_utils.cc
new file mode 100644
index 0000000..d9b5e6c
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/alts_tsi_utils.cc
@@ -0,0 +1,58 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/handshaker/alts_tsi_utils.h"
+
+#include <grpc/byte_buffer_reader.h>
+
+tsi_result alts_tsi_utils_convert_to_tsi_result(grpc_status_code code) {
+  switch (code) {
+    case GRPC_STATUS_OK:
+      return TSI_OK;
+    case GRPC_STATUS_UNKNOWN:
+      return TSI_UNKNOWN_ERROR;
+    case GRPC_STATUS_INVALID_ARGUMENT:
+      return TSI_INVALID_ARGUMENT;
+    case GRPC_STATUS_NOT_FOUND:
+      return TSI_NOT_FOUND;
+    case GRPC_STATUS_INTERNAL:
+      return TSI_INTERNAL_ERROR;
+    default:
+      return TSI_UNKNOWN_ERROR;
+  }
+}
+
+grpc_gcp_handshaker_resp* alts_tsi_utils_deserialize_response(
+    grpc_byte_buffer* resp_buffer) {
+  GPR_ASSERT(resp_buffer != nullptr);
+  grpc_byte_buffer_reader bbr;
+  grpc_byte_buffer_reader_init(&bbr, resp_buffer);
+  grpc_slice slice = grpc_byte_buffer_reader_readall(&bbr);
+  grpc_gcp_handshaker_resp* resp = grpc_gcp_handshaker_resp_create();
+  bool ok = grpc_gcp_handshaker_resp_decode(slice, resp);
+  grpc_slice_unref(slice);
+  grpc_byte_buffer_reader_destroy(&bbr);
+  if (!ok) {
+    grpc_gcp_handshaker_resp_destroy(resp);
+    gpr_log(GPR_ERROR, "grpc_gcp_handshaker_resp_decode() failed");
+    return nullptr;
+  }
+  return resp;
+}
diff --git a/src/core/tsi/alts/handshaker/alts_tsi_utils.h b/src/core/tsi/alts/handshaker/alts_tsi_utils.h
new file mode 100644
index 0000000..9ef649d
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/alts_tsi_utils.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_UTILS_H
+#define GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_UTILS_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+
+#include "src/core/tsi/alts/handshaker/alts_handshaker_service_api.h"
+#include "src/core/tsi/transport_security_interface.h"
+
+/**
+ * This method converts grpc_status_code code to the corresponding tsi_result
+ * code.
+ *
+ * - code: grpc_status_code code.
+ *
+ * It returns the converted tsi_result code.
+ */
+tsi_result alts_tsi_utils_convert_to_tsi_result(grpc_status_code code);
+
+/**
+ * This method deserializes a handshaker response returned from ALTS handshaker
+ * service.
+ *
+ * - bytes_received: data returned from ALTS handshaker service.
+ *
+ * It returns a deserialized handshaker response on success and nullptr on
+ * failure.
+ */
+grpc_gcp_handshaker_resp* alts_tsi_utils_deserialize_response(
+    grpc_byte_buffer* resp_buffer);
+
+#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_ALTS_TSI_UTILS_H */
diff --git a/src/core/tsi/alts/handshaker/altscontext.pb.c b/src/core/tsi/alts/handshaker/altscontext.pb.c
new file mode 100644
index 0000000..81a82f5
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/altscontext.pb.c
@@ -0,0 +1,48 @@
+/* Automatically generated nanopb constant definitions */
+/* Generated by nanopb-0.3.7-dev */
+
+#include "src/core/tsi/alts/handshaker/altscontext.pb.h"
+
+/* @@protoc_insertion_point(includes) */
+#if PB_PROTO_HEADER_VERSION != 30
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+
+
+const pb_field_t grpc_gcp_AltsContext_fields[7] = {
+    PB_FIELD(  1, STRING  , OPTIONAL, CALLBACK, FIRST, grpc_gcp_AltsContext, application_protocol, application_protocol, 0),
+    PB_FIELD(  2, STRING  , OPTIONAL, CALLBACK, OTHER, grpc_gcp_AltsContext, record_protocol, application_protocol, 0),
+    PB_FIELD(  3, UENUM   , OPTIONAL, STATIC  , OTHER, grpc_gcp_AltsContext, security_level, record_protocol, 0),
+    PB_FIELD(  4, STRING  , OPTIONAL, CALLBACK, OTHER, grpc_gcp_AltsContext, peer_service_account, security_level, 0),
+    PB_FIELD(  5, STRING  , OPTIONAL, CALLBACK, OTHER, grpc_gcp_AltsContext, local_service_account, peer_service_account, 0),
+    PB_FIELD(  6, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_gcp_AltsContext, peer_rpc_versions, local_service_account, &grpc_gcp_RpcProtocolVersions_fields),
+    PB_LAST_FIELD
+};
+
+
+/* Check that field information fits in pb_field_t */
+#if !defined(PB_FIELD_32BIT)
+/* If you get an error here, it means that you need to define PB_FIELD_32BIT
+ * compile-time option. You can do that in pb.h or on compiler command line.
+ * 
+ * The reason you need to do this is that some of your messages contain tag
+ * numbers or field sizes that are larger than what can fit in 8 or 16 bit
+ * field descriptors.
+ */
+PB_STATIC_ASSERT((pb_membersize(grpc_gcp_AltsContext, peer_rpc_versions) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_grpc_gcp_AltsContext)
+#endif
+
+#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)
+/* If you get an error here, it means that you need to define PB_FIELD_16BIT
+ * compile-time option. You can do that in pb.h or on compiler command line.
+ * 
+ * The reason you need to do this is that some of your messages contain tag
+ * numbers or field sizes that are larger than what can fit in the default
+ * 8 bit descriptors.
+ */
+PB_STATIC_ASSERT((pb_membersize(grpc_gcp_AltsContext, peer_rpc_versions) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_grpc_gcp_AltsContext)
+#endif
+
+
+/* @@protoc_insertion_point(eof) */
diff --git a/src/core/tsi/alts/handshaker/altscontext.pb.h b/src/core/tsi/alts/handshaker/altscontext.pb.h
new file mode 100644
index 0000000..3e72d7f
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/altscontext.pb.h
@@ -0,0 +1,64 @@
+/* Automatically generated nanopb header */
+/* Generated by nanopb-0.3.7-dev */
+
+#ifndef PB_GRPC_GCP_ALTSCONTEXT_PB_H_INCLUDED
+#define PB_GRPC_GCP_ALTSCONTEXT_PB_H_INCLUDED
+#include "third_party/nanopb/pb.h"
+#include "src/core/tsi/alts/handshaker/transport_security_common.pb.h"
+
+/* @@protoc_insertion_point(includes) */
+#if PB_PROTO_HEADER_VERSION != 30
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Struct definitions */
+typedef struct _grpc_gcp_AltsContext {
+    pb_callback_t application_protocol;
+    pb_callback_t record_protocol;
+    bool has_security_level;
+    grpc_gcp_SecurityLevel security_level;
+    pb_callback_t peer_service_account;
+    pb_callback_t local_service_account;
+    bool has_peer_rpc_versions;
+    grpc_gcp_RpcProtocolVersions peer_rpc_versions;
+/* @@protoc_insertion_point(struct:grpc_gcp_AltsContext) */
+} grpc_gcp_AltsContext;
+
+/* Default values for struct fields */
+
+/* Initializer values for message structs */
+#define grpc_gcp_AltsContext_init_default        {{{NULL}, NULL}, {{NULL}, NULL}, false, (grpc_gcp_SecurityLevel)0, {{NULL}, NULL}, {{NULL}, NULL}, false, grpc_gcp_RpcProtocolVersions_init_default}
+#define grpc_gcp_AltsContext_init_zero           {{{NULL}, NULL}, {{NULL}, NULL}, false, (grpc_gcp_SecurityLevel)0, {{NULL}, NULL}, {{NULL}, NULL}, false, grpc_gcp_RpcProtocolVersions_init_zero}
+
+/* Field tags (for use in manual encoding/decoding) */
+#define grpc_gcp_AltsContext_application_protocol_tag 1
+#define grpc_gcp_AltsContext_record_protocol_tag 2
+#define grpc_gcp_AltsContext_security_level_tag  3
+#define grpc_gcp_AltsContext_peer_service_account_tag 4
+#define grpc_gcp_AltsContext_local_service_account_tag 5
+#define grpc_gcp_AltsContext_peer_rpc_versions_tag 6
+
+/* Struct field encoding specification for nanopb */
+extern const pb_field_t grpc_gcp_AltsContext_fields[7];
+
+/* Maximum encoded size of messages (where known) */
+/* grpc_gcp_AltsContext_size depends on runtime parameters */
+
+/* Message IDs (where set with "msgid" option) */
+#ifdef PB_MSGID
+
+#define ALTSCONTEXT_MESSAGES \
+
+
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+/* @@protoc_insertion_point(eof) */
+
+#endif
diff --git a/src/core/tsi/alts/handshaker/handshaker.pb.c b/src/core/tsi/alts/handshaker/handshaker.pb.c
new file mode 100644
index 0000000..bd992df
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/handshaker.pb.c
@@ -0,0 +1,123 @@
+/* Automatically generated nanopb constant definitions */
+/* Generated by nanopb-0.3.7-dev */
+
+#include "src/core/tsi/alts/handshaker/handshaker.pb.h"
+
+/* @@protoc_insertion_point(includes) */
+#if PB_PROTO_HEADER_VERSION != 30
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+
+
+const pb_field_t grpc_gcp_Endpoint_fields[4] = {
+    PB_FIELD(  1, STRING  , OPTIONAL, CALLBACK, FIRST, grpc_gcp_Endpoint, ip_address, ip_address, 0),
+    PB_FIELD(  2, INT32   , OPTIONAL, STATIC  , OTHER, grpc_gcp_Endpoint, port, ip_address, 0),
+    PB_FIELD(  3, UENUM   , OPTIONAL, STATIC  , OTHER, grpc_gcp_Endpoint, protocol, port, 0),
+    PB_LAST_FIELD
+};
+
+const pb_field_t grpc_gcp_Identity_fields[3] = {
+    PB_FIELD(  1, STRING  , OPTIONAL, CALLBACK, FIRST, grpc_gcp_Identity, service_account, service_account, 0),
+    PB_FIELD(  2, STRING  , OPTIONAL, CALLBACK, OTHER, grpc_gcp_Identity, hostname, service_account, 0),
+    PB_LAST_FIELD
+};
+
+const pb_field_t grpc_gcp_StartClientHandshakeReq_fields[10] = {
+    PB_FIELD(  1, UENUM   , OPTIONAL, STATIC  , FIRST, grpc_gcp_StartClientHandshakeReq, handshake_security_protocol, handshake_security_protocol, 0),
+    PB_FIELD(  2, STRING  , REPEATED, CALLBACK, OTHER, grpc_gcp_StartClientHandshakeReq, application_protocols, handshake_security_protocol, 0),
+    PB_FIELD(  3, STRING  , REPEATED, CALLBACK, OTHER, grpc_gcp_StartClientHandshakeReq, record_protocols, application_protocols, 0),
+    PB_FIELD(  4, MESSAGE , REPEATED, CALLBACK, OTHER, grpc_gcp_StartClientHandshakeReq, target_identities, record_protocols, &grpc_gcp_Identity_fields),
+    PB_FIELD(  5, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_gcp_StartClientHandshakeReq, local_identity, target_identities, &grpc_gcp_Identity_fields),
+    PB_FIELD(  6, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_gcp_StartClientHandshakeReq, local_endpoint, local_identity, &grpc_gcp_Endpoint_fields),
+    PB_FIELD(  7, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_gcp_StartClientHandshakeReq, remote_endpoint, local_endpoint, &grpc_gcp_Endpoint_fields),
+    PB_FIELD(  8, STRING  , OPTIONAL, CALLBACK, OTHER, grpc_gcp_StartClientHandshakeReq, target_name, remote_endpoint, 0),
+    PB_FIELD(  9, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_gcp_StartClientHandshakeReq, rpc_versions, target_name, &grpc_gcp_RpcProtocolVersions_fields),
+    PB_LAST_FIELD
+};
+
+const pb_field_t grpc_gcp_ServerHandshakeParameters_fields[3] = {
+    PB_FIELD(  1, STRING  , REPEATED, CALLBACK, FIRST, grpc_gcp_ServerHandshakeParameters, record_protocols, record_protocols, 0),
+    PB_FIELD(  2, MESSAGE , REPEATED, CALLBACK, OTHER, grpc_gcp_ServerHandshakeParameters, local_identities, record_protocols, &grpc_gcp_Identity_fields),
+    PB_LAST_FIELD
+};
+
+const pb_field_t grpc_gcp_StartServerHandshakeReq_fields[7] = {
+    PB_FIELD(  1, STRING  , REPEATED, CALLBACK, FIRST, grpc_gcp_StartServerHandshakeReq, application_protocols, application_protocols, 0),
+    PB_FIELD(  2, MESSAGE , REPEATED, STATIC  , OTHER, grpc_gcp_StartServerHandshakeReq, handshake_parameters, application_protocols, &grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_fields),
+    PB_FIELD(  3, BYTES   , OPTIONAL, CALLBACK, OTHER, grpc_gcp_StartServerHandshakeReq, in_bytes, handshake_parameters, 0),
+    PB_FIELD(  4, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_gcp_StartServerHandshakeReq, local_endpoint, in_bytes, &grpc_gcp_Endpoint_fields),
+    PB_FIELD(  5, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_gcp_StartServerHandshakeReq, remote_endpoint, local_endpoint, &grpc_gcp_Endpoint_fields),
+    PB_FIELD(  6, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_gcp_StartServerHandshakeReq, rpc_versions, remote_endpoint, &grpc_gcp_RpcProtocolVersions_fields),
+    PB_LAST_FIELD
+};
+
+const pb_field_t grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_fields[3] = {
+    PB_FIELD(  1, INT32   , OPTIONAL, STATIC  , FIRST, grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry, key, key, 0),
+    PB_FIELD(  2, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry, value, key, &grpc_gcp_ServerHandshakeParameters_fields),
+    PB_LAST_FIELD
+};
+
+const pb_field_t grpc_gcp_NextHandshakeMessageReq_fields[2] = {
+    PB_FIELD(  1, BYTES   , OPTIONAL, CALLBACK, FIRST, grpc_gcp_NextHandshakeMessageReq, in_bytes, in_bytes, 0),
+    PB_LAST_FIELD
+};
+
+const pb_field_t grpc_gcp_HandshakerReq_fields[4] = {
+    PB_FIELD(  1, MESSAGE , OPTIONAL, STATIC  , FIRST, grpc_gcp_HandshakerReq, client_start, client_start, &grpc_gcp_StartClientHandshakeReq_fields),
+    PB_FIELD(  2, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_gcp_HandshakerReq, server_start, client_start, &grpc_gcp_StartServerHandshakeReq_fields),
+    PB_FIELD(  3, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_gcp_HandshakerReq, next, server_start, &grpc_gcp_NextHandshakeMessageReq_fields),
+    PB_LAST_FIELD
+};
+
+const pb_field_t grpc_gcp_HandshakerResult_fields[8] = {
+    PB_FIELD(  1, STRING  , OPTIONAL, CALLBACK, FIRST, grpc_gcp_HandshakerResult, application_protocol, application_protocol, 0),
+    PB_FIELD(  2, STRING  , OPTIONAL, CALLBACK, OTHER, grpc_gcp_HandshakerResult, record_protocol, application_protocol, 0),
+    PB_FIELD(  3, BYTES   , OPTIONAL, CALLBACK, OTHER, grpc_gcp_HandshakerResult, key_data, record_protocol, 0),
+    PB_FIELD(  4, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_gcp_HandshakerResult, peer_identity, key_data, &grpc_gcp_Identity_fields),
+    PB_FIELD(  5, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_gcp_HandshakerResult, local_identity, peer_identity, &grpc_gcp_Identity_fields),
+    PB_FIELD(  6, BOOL    , OPTIONAL, STATIC  , OTHER, grpc_gcp_HandshakerResult, keep_channel_open, local_identity, 0),
+    PB_FIELD(  7, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_gcp_HandshakerResult, peer_rpc_versions, keep_channel_open, &grpc_gcp_RpcProtocolVersions_fields),
+    PB_LAST_FIELD
+};
+
+const pb_field_t grpc_gcp_HandshakerStatus_fields[3] = {
+    PB_FIELD(  1, UINT32  , OPTIONAL, STATIC  , FIRST, grpc_gcp_HandshakerStatus, code, code, 0),
+    PB_FIELD(  2, STRING  , OPTIONAL, CALLBACK, OTHER, grpc_gcp_HandshakerStatus, details, code, 0),
+    PB_LAST_FIELD
+};
+
+const pb_field_t grpc_gcp_HandshakerResp_fields[5] = {
+    PB_FIELD(  1, BYTES   , OPTIONAL, CALLBACK, FIRST, grpc_gcp_HandshakerResp, out_frames, out_frames, 0),
+    PB_FIELD(  2, UINT32  , OPTIONAL, STATIC  , OTHER, grpc_gcp_HandshakerResp, bytes_consumed, out_frames, 0),
+    PB_FIELD(  3, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_gcp_HandshakerResp, result, bytes_consumed, &grpc_gcp_HandshakerResult_fields),
+    PB_FIELD(  4, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_gcp_HandshakerResp, status, result, &grpc_gcp_HandshakerStatus_fields),
+    PB_LAST_FIELD
+};
+
+
+/* Check that field information fits in pb_field_t */
+#if !defined(PB_FIELD_32BIT)
+/* If you get an error here, it means that you need to define PB_FIELD_32BIT
+ * compile-time option. You can do that in pb.h or on compiler command line.
+ * 
+ * The reason you need to do this is that some of your messages contain tag
+ * numbers or field sizes that are larger than what can fit in 8 or 16 bit
+ * field descriptors.
+ */
+PB_STATIC_ASSERT((pb_membersize(grpc_gcp_StartClientHandshakeReq, target_identities) < 65536 && pb_membersize(grpc_gcp_StartClientHandshakeReq, local_identity) < 65536 && pb_membersize(grpc_gcp_StartClientHandshakeReq, local_endpoint) < 65536 && pb_membersize(grpc_gcp_StartClientHandshakeReq, remote_endpoint) < 65536 && pb_membersize(grpc_gcp_StartClientHandshakeReq, rpc_versions) < 65536 && pb_membersize(grpc_gcp_ServerHandshakeParameters, local_identities) < 65536 && pb_membersize(grpc_gcp_StartServerHandshakeReq, handshake_parameters[0]) < 65536 && pb_membersize(grpc_gcp_StartServerHandshakeReq, local_endpoint) < 65536 && pb_membersize(grpc_gcp_StartServerHandshakeReq, remote_endpoint) < 65536 && pb_membersize(grpc_gcp_StartServerHandshakeReq, rpc_versions) < 65536 && pb_membersize(grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry, value) < 65536 && pb_membersize(grpc_gcp_HandshakerReq, client_start) < 65536 && pb_membersize(grpc_gcp_HandshakerReq, server_start) < 65536 && pb_membersize(grpc_gcp_HandshakerReq, next) < 65536 && pb_membersize(grpc_gcp_HandshakerResult, peer_identity) < 65536 && pb_membersize(grpc_gcp_HandshakerResult, local_identity) < 65536 && pb_membersize(grpc_gcp_HandshakerResult, peer_rpc_versions) < 65536 && pb_membersize(grpc_gcp_HandshakerResp, result) < 65536 && pb_membersize(grpc_gcp_HandshakerResp, status) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_grpc_gcp_Endpoint_grpc_gcp_Identity_grpc_gcp_StartClientHandshakeReq_grpc_gcp_ServerHandshakeParameters_grpc_gcp_StartServerHandshakeReq_grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_grpc_gcp_NextHandshakeMessageReq_grpc_gcp_HandshakerReq_grpc_gcp_HandshakerResult_grpc_gcp_HandshakerStatus_grpc_gcp_HandshakerResp)
+#endif
+
+#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)
+/* If you get an error here, it means that you need to define PB_FIELD_16BIT
+ * compile-time option. You can do that in pb.h or on compiler command line.
+ * 
+ * The reason you need to do this is that some of your messages contain tag
+ * numbers or field sizes that are larger than what can fit in the default
+ * 8 bit descriptors.
+ */
+PB_STATIC_ASSERT((pb_membersize(grpc_gcp_StartClientHandshakeReq, target_identities) < 256 && pb_membersize(grpc_gcp_StartClientHandshakeReq, local_identity) < 256 && pb_membersize(grpc_gcp_StartClientHandshakeReq, local_endpoint) < 256 && pb_membersize(grpc_gcp_StartClientHandshakeReq, remote_endpoint) < 256 && pb_membersize(grpc_gcp_StartClientHandshakeReq, rpc_versions) < 256 && pb_membersize(grpc_gcp_ServerHandshakeParameters, local_identities) < 256 && pb_membersize(grpc_gcp_StartServerHandshakeReq, handshake_parameters[0]) < 256 && pb_membersize(grpc_gcp_StartServerHandshakeReq, local_endpoint) < 256 && pb_membersize(grpc_gcp_StartServerHandshakeReq, remote_endpoint) < 256 && pb_membersize(grpc_gcp_StartServerHandshakeReq, rpc_versions) < 256 && pb_membersize(grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry, value) < 256 && pb_membersize(grpc_gcp_HandshakerReq, client_start) < 256 && pb_membersize(grpc_gcp_HandshakerReq, server_start) < 256 && pb_membersize(grpc_gcp_HandshakerReq, next) < 256 && pb_membersize(grpc_gcp_HandshakerResult, peer_identity) < 256 && pb_membersize(grpc_gcp_HandshakerResult, local_identity) < 256 && pb_membersize(grpc_gcp_HandshakerResult, peer_rpc_versions) < 256 && pb_membersize(grpc_gcp_HandshakerResp, result) < 256 && pb_membersize(grpc_gcp_HandshakerResp, status) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_grpc_gcp_Endpoint_grpc_gcp_Identity_grpc_gcp_StartClientHandshakeReq_grpc_gcp_ServerHandshakeParameters_grpc_gcp_StartServerHandshakeReq_grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_grpc_gcp_NextHandshakeMessageReq_grpc_gcp_HandshakerReq_grpc_gcp_HandshakerResult_grpc_gcp_HandshakerStatus_grpc_gcp_HandshakerResp)
+#endif
+
+
+/* @@protoc_insertion_point(eof) */
diff --git a/src/core/tsi/alts/handshaker/handshaker.pb.h b/src/core/tsi/alts/handshaker/handshaker.pb.h
new file mode 100644
index 0000000..0805a14
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/handshaker.pb.h
@@ -0,0 +1,255 @@
+/* Automatically generated nanopb header */
+/* Generated by nanopb-0.3.7-dev */
+
+#ifndef PB_GRPC_GCP_HANDSHAKER_PB_H_INCLUDED
+#define PB_GRPC_GCP_HANDSHAKER_PB_H_INCLUDED
+#include "third_party/nanopb/pb.h"
+#include "src/core/tsi/alts/handshaker/transport_security_common.pb.h"
+
+/* @@protoc_insertion_point(includes) */
+#if PB_PROTO_HEADER_VERSION != 30
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Enum definitions */
+typedef enum _grpc_gcp_HandshakeProtocol {
+    grpc_gcp_HandshakeProtocol_HANDSHAKE_PROTOCOL_UNSPECIFIED = 0,
+    grpc_gcp_HandshakeProtocol_TLS = 1,
+    grpc_gcp_HandshakeProtocol_ALTS = 2
+} grpc_gcp_HandshakeProtocol;
+#define _grpc_gcp_HandshakeProtocol_MIN grpc_gcp_HandshakeProtocol_HANDSHAKE_PROTOCOL_UNSPECIFIED
+#define _grpc_gcp_HandshakeProtocol_MAX grpc_gcp_HandshakeProtocol_ALTS
+#define _grpc_gcp_HandshakeProtocol_ARRAYSIZE ((grpc_gcp_HandshakeProtocol)(grpc_gcp_HandshakeProtocol_ALTS+1))
+
+typedef enum _grpc_gcp_NetworkProtocol {
+    grpc_gcp_NetworkProtocol_NETWORK_PROTOCOL_UNSPECIFIED = 0,
+    grpc_gcp_NetworkProtocol_TCP = 1,
+    grpc_gcp_NetworkProtocol_UDP = 2
+} grpc_gcp_NetworkProtocol;
+#define _grpc_gcp_NetworkProtocol_MIN grpc_gcp_NetworkProtocol_NETWORK_PROTOCOL_UNSPECIFIED
+#define _grpc_gcp_NetworkProtocol_MAX grpc_gcp_NetworkProtocol_UDP
+#define _grpc_gcp_NetworkProtocol_ARRAYSIZE ((grpc_gcp_NetworkProtocol)(grpc_gcp_NetworkProtocol_UDP+1))
+
+/* Struct definitions */
+typedef struct _grpc_gcp_Identity {
+    pb_callback_t service_account;
+    pb_callback_t hostname;
+/* @@protoc_insertion_point(struct:grpc_gcp_Identity) */
+} grpc_gcp_Identity;
+
+typedef struct _grpc_gcp_NextHandshakeMessageReq {
+    pb_callback_t in_bytes;
+/* @@protoc_insertion_point(struct:grpc_gcp_NextHandshakeMessageReq) */
+} grpc_gcp_NextHandshakeMessageReq;
+
+typedef struct _grpc_gcp_ServerHandshakeParameters {
+    pb_callback_t record_protocols;
+    pb_callback_t local_identities;
+/* @@protoc_insertion_point(struct:grpc_gcp_ServerHandshakeParameters) */
+} grpc_gcp_ServerHandshakeParameters;
+
+typedef struct _grpc_gcp_Endpoint {
+    pb_callback_t ip_address;
+    bool has_port;
+    int32_t port;
+    bool has_protocol;
+    grpc_gcp_NetworkProtocol protocol;
+/* @@protoc_insertion_point(struct:grpc_gcp_Endpoint) */
+} grpc_gcp_Endpoint;
+
+typedef struct _grpc_gcp_HandshakerResult {
+    pb_callback_t application_protocol;
+    pb_callback_t record_protocol;
+    pb_callback_t key_data;
+    bool has_peer_identity;
+    grpc_gcp_Identity peer_identity;
+    bool has_local_identity;
+    grpc_gcp_Identity local_identity;
+    bool has_keep_channel_open;
+    bool keep_channel_open;
+    bool has_peer_rpc_versions;
+    grpc_gcp_RpcProtocolVersions peer_rpc_versions;
+/* @@protoc_insertion_point(struct:grpc_gcp_HandshakerResult) */
+} grpc_gcp_HandshakerResult;
+
+typedef struct _grpc_gcp_HandshakerStatus {
+    bool has_code;
+    uint32_t code;
+    pb_callback_t details;
+/* @@protoc_insertion_point(struct:grpc_gcp_HandshakerStatus) */
+} grpc_gcp_HandshakerStatus;
+
+typedef struct _grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry {
+    bool has_key;
+    int32_t key;
+    bool has_value;
+    grpc_gcp_ServerHandshakeParameters value;
+/* @@protoc_insertion_point(struct:grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry) */
+} grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry;
+
+typedef struct _grpc_gcp_HandshakerResp {
+    pb_callback_t out_frames;
+    bool has_bytes_consumed;
+    uint32_t bytes_consumed;
+    bool has_result;
+    grpc_gcp_HandshakerResult result;
+    bool has_status;
+    grpc_gcp_HandshakerStatus status;
+/* @@protoc_insertion_point(struct:grpc_gcp_HandshakerResp) */
+} grpc_gcp_HandshakerResp;
+
+typedef struct _grpc_gcp_StartClientHandshakeReq {
+    bool has_handshake_security_protocol;
+    grpc_gcp_HandshakeProtocol handshake_security_protocol;
+    pb_callback_t application_protocols;
+    pb_callback_t record_protocols;
+    pb_callback_t target_identities;
+    bool has_local_identity;
+    grpc_gcp_Identity local_identity;
+    bool has_local_endpoint;
+    grpc_gcp_Endpoint local_endpoint;
+    bool has_remote_endpoint;
+    grpc_gcp_Endpoint remote_endpoint;
+    pb_callback_t target_name;
+    bool has_rpc_versions;
+    grpc_gcp_RpcProtocolVersions rpc_versions;
+/* @@protoc_insertion_point(struct:grpc_gcp_StartClientHandshakeReq) */
+} grpc_gcp_StartClientHandshakeReq;
+
+typedef struct _grpc_gcp_StartServerHandshakeReq {
+    pb_callback_t application_protocols;
+    pb_size_t handshake_parameters_count;
+    grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry handshake_parameters[3];
+    pb_callback_t in_bytes;
+    bool has_local_endpoint;
+    grpc_gcp_Endpoint local_endpoint;
+    bool has_remote_endpoint;
+    grpc_gcp_Endpoint remote_endpoint;
+    bool has_rpc_versions;
+    grpc_gcp_RpcProtocolVersions rpc_versions;
+/* @@protoc_insertion_point(struct:grpc_gcp_StartServerHandshakeReq) */
+} grpc_gcp_StartServerHandshakeReq;
+
+typedef struct _grpc_gcp_HandshakerReq {
+    bool has_client_start;
+    grpc_gcp_StartClientHandshakeReq client_start;
+    bool has_server_start;
+    grpc_gcp_StartServerHandshakeReq server_start;
+    bool has_next;
+    grpc_gcp_NextHandshakeMessageReq next;
+/* @@protoc_insertion_point(struct:grpc_gcp_HandshakerReq) */
+} grpc_gcp_HandshakerReq;
+
+/* Default values for struct fields */
+
+/* Initializer values for message structs */
+#define grpc_gcp_Endpoint_init_default           {{{NULL}, NULL}, false, 0, false, (grpc_gcp_NetworkProtocol)0}
+#define grpc_gcp_Identity_init_default           {{{NULL}, NULL}, {{NULL}, NULL}}
+#define grpc_gcp_StartClientHandshakeReq_init_default {false, (grpc_gcp_HandshakeProtocol)0, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, grpc_gcp_Identity_init_default, false, grpc_gcp_Endpoint_init_default, false, grpc_gcp_Endpoint_init_default, {{NULL}, NULL}, false, grpc_gcp_RpcProtocolVersions_init_default}
+#define grpc_gcp_ServerHandshakeParameters_init_default {{{NULL}, NULL}, {{NULL}, NULL}}
+#define grpc_gcp_StartServerHandshakeReq_init_default {{{NULL}, NULL}, 0, {grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_init_default, grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_init_default, grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_init_default}, {{NULL}, NULL}, false, grpc_gcp_Endpoint_init_default, false, grpc_gcp_Endpoint_init_default, false, grpc_gcp_RpcProtocolVersions_init_default}
+#define grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_init_default {false, 0, false, grpc_gcp_ServerHandshakeParameters_init_default}
+#define grpc_gcp_NextHandshakeMessageReq_init_default {{{NULL}, NULL}}
+#define grpc_gcp_HandshakerReq_init_default      {false, grpc_gcp_StartClientHandshakeReq_init_default, false, grpc_gcp_StartServerHandshakeReq_init_default, false, grpc_gcp_NextHandshakeMessageReq_init_default}
+#define grpc_gcp_HandshakerResult_init_default   {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, grpc_gcp_Identity_init_default, false, grpc_gcp_Identity_init_default, false, 0, false, grpc_gcp_RpcProtocolVersions_init_default}
+#define grpc_gcp_HandshakerStatus_init_default   {false, 0, {{NULL}, NULL}}
+#define grpc_gcp_HandshakerResp_init_default     {{{NULL}, NULL}, false, 0, false, grpc_gcp_HandshakerResult_init_default, false, grpc_gcp_HandshakerStatus_init_default}
+#define grpc_gcp_Endpoint_init_zero              {{{NULL}, NULL}, false, 0, false, (grpc_gcp_NetworkProtocol)0}
+#define grpc_gcp_Identity_init_zero              {{{NULL}, NULL}, {{NULL}, NULL}}
+#define grpc_gcp_StartClientHandshakeReq_init_zero {false, (grpc_gcp_HandshakeProtocol)0, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, grpc_gcp_Identity_init_zero, false, grpc_gcp_Endpoint_init_zero, false, grpc_gcp_Endpoint_init_zero, {{NULL}, NULL}, false, grpc_gcp_RpcProtocolVersions_init_zero}
+#define grpc_gcp_ServerHandshakeParameters_init_zero {{{NULL}, NULL}, {{NULL}, NULL}}
+#define grpc_gcp_StartServerHandshakeReq_init_zero {{{NULL}, NULL}, 0, {grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_init_zero, grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_init_zero, grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_init_zero}, {{NULL}, NULL}, false, grpc_gcp_Endpoint_init_zero, false, grpc_gcp_Endpoint_init_zero, false, grpc_gcp_RpcProtocolVersions_init_zero}
+#define grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_init_zero {false, 0, false, grpc_gcp_ServerHandshakeParameters_init_zero}
+#define grpc_gcp_NextHandshakeMessageReq_init_zero {{{NULL}, NULL}}
+#define grpc_gcp_HandshakerReq_init_zero         {false, grpc_gcp_StartClientHandshakeReq_init_zero, false, grpc_gcp_StartServerHandshakeReq_init_zero, false, grpc_gcp_NextHandshakeMessageReq_init_zero}
+#define grpc_gcp_HandshakerResult_init_zero      {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, grpc_gcp_Identity_init_zero, false, grpc_gcp_Identity_init_zero, false, 0, false, grpc_gcp_RpcProtocolVersions_init_zero}
+#define grpc_gcp_HandshakerStatus_init_zero      {false, 0, {{NULL}, NULL}}
+#define grpc_gcp_HandshakerResp_init_zero        {{{NULL}, NULL}, false, 0, false, grpc_gcp_HandshakerResult_init_zero, false, grpc_gcp_HandshakerStatus_init_zero}
+
+/* Field tags (for use in manual encoding/decoding) */
+#define grpc_gcp_Identity_service_account_tag    1
+#define grpc_gcp_Identity_hostname_tag           2
+#define grpc_gcp_NextHandshakeMessageReq_in_bytes_tag 1
+#define grpc_gcp_ServerHandshakeParameters_record_protocols_tag 1
+#define grpc_gcp_ServerHandshakeParameters_local_identities_tag 2
+#define grpc_gcp_Endpoint_ip_address_tag         1
+#define grpc_gcp_Endpoint_port_tag               2
+#define grpc_gcp_Endpoint_protocol_tag           3
+#define grpc_gcp_HandshakerResult_application_protocol_tag 1
+#define grpc_gcp_HandshakerResult_record_protocol_tag 2
+#define grpc_gcp_HandshakerResult_key_data_tag   3
+#define grpc_gcp_HandshakerResult_peer_identity_tag 4
+#define grpc_gcp_HandshakerResult_local_identity_tag 5
+#define grpc_gcp_HandshakerResult_keep_channel_open_tag 6
+#define grpc_gcp_HandshakerResult_peer_rpc_versions_tag 7
+#define grpc_gcp_HandshakerStatus_code_tag       1
+#define grpc_gcp_HandshakerStatus_details_tag    2
+#define grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_key_tag 1
+#define grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_value_tag 2
+#define grpc_gcp_HandshakerResp_out_frames_tag   1
+#define grpc_gcp_HandshakerResp_bytes_consumed_tag 2
+#define grpc_gcp_HandshakerResp_result_tag       3
+#define grpc_gcp_HandshakerResp_status_tag       4
+#define grpc_gcp_StartClientHandshakeReq_handshake_security_protocol_tag 1
+#define grpc_gcp_StartClientHandshakeReq_application_protocols_tag 2
+#define grpc_gcp_StartClientHandshakeReq_record_protocols_tag 3
+#define grpc_gcp_StartClientHandshakeReq_target_identities_tag 4
+#define grpc_gcp_StartClientHandshakeReq_local_identity_tag 5
+#define grpc_gcp_StartClientHandshakeReq_local_endpoint_tag 6
+#define grpc_gcp_StartClientHandshakeReq_remote_endpoint_tag 7
+#define grpc_gcp_StartClientHandshakeReq_target_name_tag 8
+#define grpc_gcp_StartClientHandshakeReq_rpc_versions_tag 9
+#define grpc_gcp_StartServerHandshakeReq_application_protocols_tag 1
+#define grpc_gcp_StartServerHandshakeReq_handshake_parameters_tag 2
+#define grpc_gcp_StartServerHandshakeReq_in_bytes_tag 3
+#define grpc_gcp_StartServerHandshakeReq_local_endpoint_tag 4
+#define grpc_gcp_StartServerHandshakeReq_remote_endpoint_tag 5
+#define grpc_gcp_StartServerHandshakeReq_rpc_versions_tag 6
+#define grpc_gcp_HandshakerReq_client_start_tag  1
+#define grpc_gcp_HandshakerReq_server_start_tag  2
+#define grpc_gcp_HandshakerReq_next_tag          3
+
+/* Struct field encoding specification for nanopb */
+extern const pb_field_t grpc_gcp_Endpoint_fields[4];
+extern const pb_field_t grpc_gcp_Identity_fields[3];
+extern const pb_field_t grpc_gcp_StartClientHandshakeReq_fields[10];
+extern const pb_field_t grpc_gcp_ServerHandshakeParameters_fields[3];
+extern const pb_field_t grpc_gcp_StartServerHandshakeReq_fields[7];
+extern const pb_field_t grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_fields[3];
+extern const pb_field_t grpc_gcp_NextHandshakeMessageReq_fields[2];
+extern const pb_field_t grpc_gcp_HandshakerReq_fields[4];
+extern const pb_field_t grpc_gcp_HandshakerResult_fields[8];
+extern const pb_field_t grpc_gcp_HandshakerStatus_fields[3];
+extern const pb_field_t grpc_gcp_HandshakerResp_fields[5];
+
+/* Maximum encoded size of messages (where known) */
+/* grpc_gcp_Endpoint_size depends on runtime parameters */
+/* grpc_gcp_Identity_size depends on runtime parameters */
+/* grpc_gcp_StartClientHandshakeReq_size depends on runtime parameters */
+/* grpc_gcp_ServerHandshakeParameters_size depends on runtime parameters */
+/* grpc_gcp_StartServerHandshakeReq_size depends on runtime parameters */
+#define grpc_gcp_StartServerHandshakeReq_HandshakeParametersEntry_size (17 + grpc_gcp_ServerHandshakeParameters_size)
+/* grpc_gcp_NextHandshakeMessageReq_size depends on runtime parameters */
+#define grpc_gcp_HandshakerReq_size              (18 + grpc_gcp_StartClientHandshakeReq_size + grpc_gcp_StartServerHandshakeReq_size + grpc_gcp_NextHandshakeMessageReq_size)
+/* grpc_gcp_HandshakerResult_size depends on runtime parameters */
+/* grpc_gcp_HandshakerStatus_size depends on runtime parameters */
+/* grpc_gcp_HandshakerResp_size depends on runtime parameters */
+
+/* Message IDs (where set with "msgid" option) */
+#ifdef PB_MSGID
+
+#define HANDSHAKER_MESSAGES \
+
+
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+/* @@protoc_insertion_point(eof) */
+
+#endif
diff --git a/src/core/tsi/alts/handshaker/proto/altscontext.proto b/src/core/tsi/alts/handshaker/proto/altscontext.proto
new file mode 100644
index 0000000..9a1dad5
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/proto/altscontext.proto
@@ -0,0 +1,41 @@
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+import "transport_security_common.proto";
+
+package grpc.gcp;
+
+option java_package = "io.grpc.alts.internal";
+
+message AltsContext {
+  // The application protocol negotiated for this connection.
+  string application_protocol = 1;
+
+  // The record protocol negotiated for this connection.
+  string record_protocol = 2;
+
+  // The security level of the created secure channel.
+  SecurityLevel security_level = 3;
+
+  // The peer service account.
+  string peer_service_account = 4;
+
+  // The local service account.
+  string local_service_account = 5;
+
+  // The RPC protocol versions supported by the peer.
+  RpcProtocolVersions peer_rpc_versions = 6;
+}
diff --git a/src/core/tsi/alts/handshaker/proto/handshaker.options b/src/core/tsi/alts/handshaker/proto/handshaker.options
new file mode 100644
index 0000000..702ba38
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/proto/handshaker.options
@@ -0,0 +1,2 @@
+handshaker.proto no_unions:true
+grpc.gcp.StartServerHandshakeReq.handshake_parameters max_count:3
diff --git a/src/core/tsi/alts/handshaker/proto/handshaker.proto b/src/core/tsi/alts/handshaker/proto/handshaker.proto
new file mode 100644
index 0000000..84a4153
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/proto/handshaker.proto
@@ -0,0 +1,224 @@
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+import "transport_security_common.proto";
+
+package grpc.gcp;
+
+option java_package = "io.grpc.alts.internal";
+
+enum HandshakeProtocol {
+  // Default value.
+  HANDSHAKE_PROTOCOL_UNSPECIFIED = 0;
+
+  // TLS handshake protocol.
+  TLS = 1;
+
+  // Application Layer Transport Security handshake protocol.
+  ALTS = 2;
+}
+
+enum NetworkProtocol {
+  NETWORK_PROTOCOL_UNSPECIFIED = 0;
+  TCP = 1;
+  UDP = 2;
+}
+
+message Endpoint {
+  // IP address. It should contain an IPv4 or IPv6 string literal, e.g.
+  // "192.168.0.1" or "2001:db8::1".
+  string ip_address = 1;
+
+  // Port number.
+  int32 port = 2;
+
+  // Network protocol (e.g., TCP, UDP) associated with this endpoint.
+  NetworkProtocol protocol = 3;
+}
+
+message Identity {
+  oneof identity_oneof {
+    // Service account of a connection endpoint.
+    string service_account = 1;
+
+    // Hostname of a connection endpoint.
+    string hostname = 2;
+  }
+}
+
+message StartClientHandshakeReq {
+  // Handshake security protocol requested by the client.
+  HandshakeProtocol handshake_security_protocol = 1;
+
+  // The application protocols supported by the client, e.g., "h2" (for http2),
+  // "grpc".
+  repeated string application_protocols = 2;
+
+  // The record protocols supported by the client, e.g.,
+  // "ALTSRP_GCM_AES128".
+  repeated string record_protocols = 3;
+
+  // (Optional) Describes which server identities are acceptable by the client.
+  // If target identities are provided and none of them matches the peer
+  // identity of the server, handshake will fail.
+  repeated Identity target_identities = 4;
+
+  // (Optional) Application may specify a local identity. Otherwise, the
+  // handshaker chooses a default local identity.
+  Identity local_identity = 5;
+
+  // (Optional) Local endpoint information of the connection to the server,
+  // such as local IP address, port number, and network protocol.
+  Endpoint local_endpoint = 6;
+
+  // (Optional) Endpoint information of the remote server, such as IP address,
+  // port number, and network protocol.
+  Endpoint remote_endpoint = 7;
+
+  // (Optional) If target name is provided, a secure naming check is performed
+  // to verify that the peer authenticated identity is indeed authorized to run
+  // the target name.
+  string target_name = 8;
+
+  // (Optional) RPC protocol versions supported by the client.
+  RpcProtocolVersions rpc_versions = 9;
+}
+
+message ServerHandshakeParameters {
+  // The record protocols supported by the server, e.g.,
+  // "ALTSRP_GCM_AES128".
+  repeated string record_protocols = 1;
+
+  // (Optional) A list of local identities supported by the server, if
+  // specified. Otherwise, the handshaker chooses a default local identity.
+  repeated Identity local_identities = 2;
+}
+
+message StartServerHandshakeReq {
+  // The application protocols supported by the server, e.g., "h2" (for http2),
+  // "grpc".
+  repeated string application_protocols = 1;
+
+  // Handshake parameters (record protocols and local identities supported by
+  // the server) mapped by the handshake protocol. Each handshake security
+  // protocol (e.g., TLS or ALTS) has its own set of record protocols and local
+  // identities. Since protobuf does not support enum as key to the map, the key
+  // to handshake_parameters is the integer value of HandshakeProtocol enum.
+  map<int32, ServerHandshakeParameters> handshake_parameters = 2;
+
+  // Bytes in out_frames returned from the peer's HandshakerResp. It is possible
+  // that the peer's out_frames are split into multiple HandshakReq messages.
+  bytes in_bytes = 3;
+
+  // (Optional) Local endpoint information of the connection to the client,
+  // such as local IP address, port number, and network protocol.
+  Endpoint local_endpoint = 4;
+
+  // (Optional) Endpoint information of the remote client, such as IP address,
+  // port number, and network protocol.
+  Endpoint remote_endpoint = 5;
+
+  // (Optional) RPC protocol versions supported by the server.
+  RpcProtocolVersions rpc_versions = 6;
+}
+
+message NextHandshakeMessageReq {
+  // Bytes in out_frames returned from the peer's HandshakerResp. It is possible
+  // that the peer's out_frames are split into multiple NextHandshakerMessageReq
+  // messages.
+  bytes in_bytes = 1;
+}
+
+message HandshakerReq {
+  oneof req_oneof {
+    // The start client handshake request message.
+    StartClientHandshakeReq client_start = 1;
+
+    // The start server handshake request message.
+    StartServerHandshakeReq server_start = 2;
+
+    // The next handshake request message.
+    NextHandshakeMessageReq next = 3;
+  }
+}
+
+message HandshakerResult {
+  // The application protocol negotiated for this connection.
+  string application_protocol = 1;
+
+  // The record protocol negotiated for this connection.
+  string record_protocol = 2;
+
+  // Cryptographic key data. The key data may be more than the key length
+  // required for the record protocol, thus the client of the handshaker
+  // service needs to truncate the key data into the right key length.
+  bytes key_data = 3;
+
+  // The authenticated identity of the peer.
+  Identity peer_identity = 4;
+
+  // The local identity used in the handshake.
+  Identity local_identity = 5;
+
+  // Indicate whether the handshaker service client should keep the channel
+  // between the handshaker service open, e.g., in order to handle
+  // post-handshake messages in the future.
+  bool keep_channel_open = 6;
+
+  // The RPC protocol versions supported by the peer.
+  RpcProtocolVersions peer_rpc_versions = 7;
+}
+
+message HandshakerStatus {
+  // The status code. This could be the gRPC status code.
+  uint32 code = 1;
+
+  // The status details.
+  string details = 2;
+}
+
+message HandshakerResp {
+  // Frames to be given to the peer for the NextHandshakeMessageReq. May be
+  // empty if no out_frames have to be sent to the peer or if in_bytes in the
+  // HandshakerReq are incomplete. All the non-empty out frames must be sent to
+  // the peer even if the handshaker status is not OK as these frames may
+  // contain the alert frames.
+  bytes out_frames = 1;
+
+  // Number of bytes in the in_bytes consumed by the handshaker. It is possible
+  // that part of in_bytes in HandshakerReq was unrelated to the handshake
+  // process.
+  uint32 bytes_consumed = 2;
+
+  // This is set iff the handshake was successful. out_frames may still be set
+  // to frames that needs to be forwarded to the peer.
+  HandshakerResult result = 3;
+
+  // Status of the handshaker.
+  HandshakerStatus status = 4;
+}
+
+service HandshakerService {
+  // Handshaker service accepts a stream of handshaker request, returning a
+  // stream of handshaker response. Client is expected to send exactly one
+  // message with either client_start or server_start followed by one or more
+  // messages with next. Each time client sends a request, the handshaker
+  // service expects to respond. Client does not have to wait for service's
+  // response before sending next request.
+  rpc DoHandshake(stream HandshakerReq)
+      returns (stream HandshakerResp) {
+  }
+}
diff --git a/src/core/tsi/alts/handshaker/proto/transport_security_common.proto b/src/core/tsi/alts/handshaker/proto/transport_security_common.proto
new file mode 100644
index 0000000..d0f861e
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/proto/transport_security_common.proto
@@ -0,0 +1,40 @@
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package grpc.gcp;
+
+option java_package = "io.grpc.alts.internal";
+
+// The security level of the created channel. The list is sorted in increasing
+// level of security. This order must always be maintained.
+enum SecurityLevel {
+  SECURITY_NONE = 0;
+  INTEGRITY_ONLY = 1;
+  INTEGRITY_AND_PRIVACY = 2;
+}
+
+// Max and min supported RPC protocol versions.
+message RpcProtocolVersions {
+  // RPC version contains a major version and a minor version.
+  message Version {
+    uint32 major = 1;
+    uint32 minor = 2;
+  }
+  // Maximum supported RPC version.
+  Version max_rpc_version = 1;
+  // Minimum supported RPC version.
+  Version min_rpc_version = 2;
+}
diff --git a/src/core/tsi/alts/handshaker/transport_security_common.pb.c b/src/core/tsi/alts/handshaker/transport_security_common.pb.c
new file mode 100644
index 0000000..6063c76
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/transport_security_common.pb.c
@@ -0,0 +1,50 @@
+/* Automatically generated nanopb constant definitions */
+/* Generated by nanopb-0.3.7-dev */
+
+#include "src/core/tsi/alts/handshaker/transport_security_common.pb.h"
+
+/* @@protoc_insertion_point(includes) */
+#if PB_PROTO_HEADER_VERSION != 30
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+
+
+const pb_field_t grpc_gcp_RpcProtocolVersions_fields[3] = {
+    PB_FIELD(  1, MESSAGE , OPTIONAL, STATIC  , FIRST, grpc_gcp_RpcProtocolVersions, max_rpc_version, max_rpc_version, &grpc_gcp_RpcProtocolVersions_Version_fields),
+    PB_FIELD(  2, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_gcp_RpcProtocolVersions, min_rpc_version, max_rpc_version, &grpc_gcp_RpcProtocolVersions_Version_fields),
+    PB_LAST_FIELD
+};
+
+const pb_field_t grpc_gcp_RpcProtocolVersions_Version_fields[3] = {
+    PB_FIELD(  1, UINT32  , OPTIONAL, STATIC  , FIRST, grpc_gcp_RpcProtocolVersions_Version, major, major, 0),
+    PB_FIELD(  2, UINT32  , OPTIONAL, STATIC  , OTHER, grpc_gcp_RpcProtocolVersions_Version, minor, major, 0),
+    PB_LAST_FIELD
+};
+
+
+/* Check that field information fits in pb_field_t */
+#if !defined(PB_FIELD_32BIT)
+/* If you get an error here, it means that you need to define PB_FIELD_32BIT
+ * compile-time option. You can do that in pb.h or on compiler command line.
+ * 
+ * The reason you need to do this is that some of your messages contain tag
+ * numbers or field sizes that are larger than what can fit in 8 or 16 bit
+ * field descriptors.
+ */
+PB_STATIC_ASSERT((pb_membersize(grpc_gcp_RpcProtocolVersions, max_rpc_version) < 65536 && pb_membersize(grpc_gcp_RpcProtocolVersions, min_rpc_version) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_grpc_gcp_RpcProtocolVersions_grpc_gcp_RpcProtocolVersions_Version)
+#endif
+
+#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)
+/* If you get an error here, it means that you need to define PB_FIELD_16BIT
+ * compile-time option. You can do that in pb.h or on compiler command line.
+ * 
+ * The reason you need to do this is that some of your messages contain tag
+ * numbers or field sizes that are larger than what can fit in the default
+ * 8 bit descriptors.
+ */
+PB_STATIC_ASSERT((pb_membersize(grpc_gcp_RpcProtocolVersions, max_rpc_version) < 256 && pb_membersize(grpc_gcp_RpcProtocolVersions, min_rpc_version) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_grpc_gcp_RpcProtocolVersions_grpc_gcp_RpcProtocolVersions_Version)
+#endif
+
+
+/* @@protoc_insertion_point(eof) */
diff --git a/src/core/tsi/alts/handshaker/transport_security_common.pb.h b/src/core/tsi/alts/handshaker/transport_security_common.pb.h
new file mode 100644
index 0000000..49096df
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/transport_security_common.pb.h
@@ -0,0 +1,78 @@
+/* Automatically generated nanopb header */
+/* Generated by nanopb-0.3.7-dev */
+
+#ifndef PB_GRPC_GCP_TRANSPORT_SECURITY_COMMON_PB_H_INCLUDED
+#define PB_GRPC_GCP_TRANSPORT_SECURITY_COMMON_PB_H_INCLUDED
+#include "third_party/nanopb/pb.h"
+/* @@protoc_insertion_point(includes) */
+#if PB_PROTO_HEADER_VERSION != 30
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Enum definitions */
+typedef enum _grpc_gcp_SecurityLevel {
+    grpc_gcp_SecurityLevel_SECURITY_NONE = 0,
+    grpc_gcp_SecurityLevel_INTEGRITY_ONLY = 1,
+    grpc_gcp_SecurityLevel_INTEGRITY_AND_PRIVACY = 2
+} grpc_gcp_SecurityLevel;
+#define _grpc_gcp_SecurityLevel_MIN grpc_gcp_SecurityLevel_SECURITY_NONE
+#define _grpc_gcp_SecurityLevel_MAX grpc_gcp_SecurityLevel_INTEGRITY_AND_PRIVACY
+#define _grpc_gcp_SecurityLevel_ARRAYSIZE ((grpc_gcp_SecurityLevel)(grpc_gcp_SecurityLevel_INTEGRITY_AND_PRIVACY+1))
+
+/* Struct definitions */
+typedef struct _grpc_gcp_RpcProtocolVersions_Version {
+    bool has_major;
+    uint32_t major;
+    bool has_minor;
+    uint32_t minor;
+/* @@protoc_insertion_point(struct:grpc_gcp_RpcProtocolVersions_Version) */
+} grpc_gcp_RpcProtocolVersions_Version;
+
+typedef struct _grpc_gcp_RpcProtocolVersions {
+    bool has_max_rpc_version;
+    grpc_gcp_RpcProtocolVersions_Version max_rpc_version;
+    bool has_min_rpc_version;
+    grpc_gcp_RpcProtocolVersions_Version min_rpc_version;
+/* @@protoc_insertion_point(struct:grpc_gcp_RpcProtocolVersions) */
+} grpc_gcp_RpcProtocolVersions;
+
+/* Default values for struct fields */
+
+/* Initializer values for message structs */
+#define grpc_gcp_RpcProtocolVersions_init_default {false, grpc_gcp_RpcProtocolVersions_Version_init_default, false, grpc_gcp_RpcProtocolVersions_Version_init_default}
+#define grpc_gcp_RpcProtocolVersions_Version_init_default {false, 0, false, 0}
+#define grpc_gcp_RpcProtocolVersions_init_zero   {false, grpc_gcp_RpcProtocolVersions_Version_init_zero, false, grpc_gcp_RpcProtocolVersions_Version_init_zero}
+#define grpc_gcp_RpcProtocolVersions_Version_init_zero {false, 0, false, 0}
+
+/* Field tags (for use in manual encoding/decoding) */
+#define grpc_gcp_RpcProtocolVersions_Version_major_tag 1
+#define grpc_gcp_RpcProtocolVersions_Version_minor_tag 2
+#define grpc_gcp_RpcProtocolVersions_max_rpc_version_tag 1
+#define grpc_gcp_RpcProtocolVersions_min_rpc_version_tag 2
+
+/* Struct field encoding specification for nanopb */
+extern const pb_field_t grpc_gcp_RpcProtocolVersions_fields[3];
+extern const pb_field_t grpc_gcp_RpcProtocolVersions_Version_fields[3];
+
+/* Maximum encoded size of messages (where known) */
+#define grpc_gcp_RpcProtocolVersions_size        28
+#define grpc_gcp_RpcProtocolVersions_Version_size 12
+
+/* Message IDs (where set with "msgid" option) */
+#ifdef PB_MSGID
+
+#define TRANSPORT_SECURITY_COMMON_MESSAGES \
+
+
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+/* @@protoc_insertion_point(eof) */
+
+#endif
diff --git a/src/core/tsi/alts/handshaker/transport_security_common_api.cc b/src/core/tsi/alts/handshaker/transport_security_common_api.cc
new file mode 100644
index 0000000..8a7edb5
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/transport_security_common_api.cc
@@ -0,0 +1,196 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/handshaker/transport_security_common_api.h"
+
+bool grpc_gcp_rpc_protocol_versions_set_max(
+    grpc_gcp_rpc_protocol_versions* versions, uint32_t max_major,
+    uint32_t max_minor) {
+  if (versions == nullptr) {
+    gpr_log(GPR_ERROR,
+            "versions is nullptr in "
+            "grpc_gcp_rpc_protocol_versions_set_max().");
+    return false;
+  }
+  versions->has_max_rpc_version = true;
+  versions->max_rpc_version.has_major = true;
+  versions->max_rpc_version.has_minor = true;
+  versions->max_rpc_version.major = max_major;
+  versions->max_rpc_version.minor = max_minor;
+  return true;
+}
+
+bool grpc_gcp_rpc_protocol_versions_set_min(
+    grpc_gcp_rpc_protocol_versions* versions, uint32_t min_major,
+    uint32_t min_minor) {
+  if (versions == nullptr) {
+    gpr_log(GPR_ERROR,
+            "versions is nullptr in "
+            "grpc_gcp_rpc_protocol_versions_set_min().");
+    return false;
+  }
+  versions->has_min_rpc_version = true;
+  versions->min_rpc_version.has_major = true;
+  versions->min_rpc_version.has_minor = true;
+  versions->min_rpc_version.major = min_major;
+  versions->min_rpc_version.minor = min_minor;
+  return true;
+}
+
+size_t grpc_gcp_rpc_protocol_versions_encode_length(
+    const grpc_gcp_rpc_protocol_versions* versions) {
+  if (versions == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to "
+            "grpc_gcp_rpc_protocol_versions_encode_length().");
+    return 0;
+  }
+  pb_ostream_t size_stream;
+  memset(&size_stream, 0, sizeof(pb_ostream_t));
+  if (!pb_encode(&size_stream, grpc_gcp_RpcProtocolVersions_fields, versions)) {
+    gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&size_stream));
+    return 0;
+  }
+  return size_stream.bytes_written;
+}
+
+bool grpc_gcp_rpc_protocol_versions_encode_to_raw_bytes(
+    const grpc_gcp_rpc_protocol_versions* versions, uint8_t* bytes,
+    size_t bytes_length) {
+  if (versions == nullptr || bytes == nullptr || bytes_length == 0) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to "
+            "grpc_gcp_rpc_protocol_versions_encode_to_raw_bytes().");
+    return false;
+  }
+  pb_ostream_t output_stream = pb_ostream_from_buffer(bytes, bytes_length);
+  if (!pb_encode(&output_stream, grpc_gcp_RpcProtocolVersions_fields,
+                 versions)) {
+    gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&output_stream));
+    return false;
+  }
+  return true;
+}
+
+bool grpc_gcp_rpc_protocol_versions_encode(
+    const grpc_gcp_rpc_protocol_versions* versions, grpc_slice* slice) {
+  if (versions == nullptr || slice == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to "
+            "grpc_gcp_rpc_protocol_versions_encode().");
+    return false;
+  }
+  size_t encoded_length =
+      grpc_gcp_rpc_protocol_versions_encode_length(versions);
+  if (encoded_length == 0) return false;
+  *slice = grpc_slice_malloc(encoded_length);
+  return grpc_gcp_rpc_protocol_versions_encode_to_raw_bytes(
+      versions, GRPC_SLICE_START_PTR(*slice), encoded_length);
+}
+
+bool grpc_gcp_rpc_protocol_versions_decode(
+    grpc_slice slice, grpc_gcp_rpc_protocol_versions* versions) {
+  if (versions == nullptr) {
+    gpr_log(GPR_ERROR,
+            "version is nullptr in "
+            "grpc_gcp_rpc_protocol_versions_decode().");
+    return false;
+  }
+  pb_istream_t stream = pb_istream_from_buffer(GRPC_SLICE_START_PTR(slice),
+                                               GRPC_SLICE_LENGTH(slice));
+  if (!pb_decode(&stream, grpc_gcp_RpcProtocolVersions_fields, versions)) {
+    gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream));
+    return false;
+  }
+  return true;
+}
+
+bool grpc_gcp_rpc_protocol_versions_copy(
+    const grpc_gcp_rpc_protocol_versions* src,
+    grpc_gcp_rpc_protocol_versions* dst) {
+  if ((src == nullptr && dst != nullptr) ||
+      (src != nullptr && dst == nullptr)) {
+    gpr_log(GPR_ERROR,
+            "Invalid arguments to "
+            "grpc_gcp_rpc_protocol_versions_copy().");
+    return false;
+  }
+  if (src == nullptr) {
+    return true;
+  }
+  grpc_gcp_rpc_protocol_versions_set_max(dst, src->max_rpc_version.major,
+                                         src->max_rpc_version.minor);
+  grpc_gcp_rpc_protocol_versions_set_min(dst, src->min_rpc_version.major,
+                                         src->min_rpc_version.minor);
+  return true;
+}
+
+namespace grpc_core {
+namespace internal {
+
+int grpc_gcp_rpc_protocol_version_compare(
+    const grpc_gcp_rpc_protocol_versions_version* v1,
+    const grpc_gcp_rpc_protocol_versions_version* v2) {
+  if ((v1->major > v2->major) ||
+      (v1->major == v2->major && v1->minor > v2->minor)) {
+    return 1;
+  }
+  if ((v1->major < v2->major) ||
+      (v1->major == v2->major && v1->minor < v2->minor)) {
+    return -1;
+  }
+  return 0;
+}
+
+}  // namespace internal
+}  // namespace grpc_core
+
+bool grpc_gcp_rpc_protocol_versions_check(
+    const grpc_gcp_rpc_protocol_versions* local_versions,
+    const grpc_gcp_rpc_protocol_versions* peer_versions,
+    grpc_gcp_rpc_protocol_versions_version* highest_common_version) {
+  if (local_versions == nullptr || peer_versions == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid arguments to "
+            "grpc_gcp_rpc_protocol_versions_check().");
+    return false;
+  }
+  /* max_common_version is MIN(local.max, peer.max) */
+  const grpc_gcp_rpc_protocol_versions_version* max_common_version =
+      grpc_core::internal::grpc_gcp_rpc_protocol_version_compare(
+          &local_versions->max_rpc_version, &peer_versions->max_rpc_version) > 0
+          ? &peer_versions->max_rpc_version
+          : &local_versions->max_rpc_version;
+  /* min_common_version is MAX(local.min, peer.min) */
+  const grpc_gcp_rpc_protocol_versions_version* min_common_version =
+      grpc_core::internal::grpc_gcp_rpc_protocol_version_compare(
+          &local_versions->min_rpc_version, &peer_versions->min_rpc_version) > 0
+          ? &local_versions->min_rpc_version
+          : &peer_versions->min_rpc_version;
+  bool result = grpc_core::internal::grpc_gcp_rpc_protocol_version_compare(
+                    max_common_version, min_common_version) >= 0
+                    ? true
+                    : false;
+  if (result && highest_common_version != nullptr) {
+    memcpy(highest_common_version, max_common_version,
+           sizeof(grpc_gcp_rpc_protocol_versions_version));
+  }
+  return result;
+}
diff --git a/src/core/tsi/alts/handshaker/transport_security_common_api.h b/src/core/tsi/alts/handshaker/transport_security_common_api.h
new file mode 100644
index 0000000..68228cb
--- /dev/null
+++ b/src/core/tsi/alts/handshaker/transport_security_common_api.h
@@ -0,0 +1,163 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_ALTS_HANDSHAKER_TRANSPORT_SECURITY_COMMON_API_H
+#define GRPC_CORE_TSI_ALTS_HANDSHAKER_TRANSPORT_SECURITY_COMMON_API_H
+
+#include <grpc/support/port_platform.h>
+
+#include "third_party/nanopb/pb_decode.h"
+#include "third_party/nanopb/pb_encode.h"
+
+#include <grpc/slice.h>
+#include <grpc/slice_buffer.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/tsi/alts/handshaker/transport_security_common.pb.h"
+
+typedef grpc_gcp_RpcProtocolVersions grpc_gcp_rpc_protocol_versions;
+
+typedef grpc_gcp_RpcProtocolVersions_Version
+    grpc_gcp_rpc_protocol_versions_version;
+
+/**
+ * This method sets the value for max_rpc_versions field of rpc protocol
+ * versions.
+ *
+ * - versions: an rpc protocol version instance.
+ * - max_major: a major version of maximum supported RPC version.
+ * - max_minor: a minor version of maximum supported RPC version.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_rpc_protocol_versions_set_max(
+    grpc_gcp_rpc_protocol_versions* versions, uint32_t max_major,
+    uint32_t max_minor);
+
+/**
+ * This method sets the value for min_rpc_versions field of rpc protocol
+ * versions.
+ *
+ * - versions: an rpc protocol version instance.
+ * - min_major: a major version of minimum supported RPC version.
+ * - min_minor: a minor version of minimum supported RPC version.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_rpc_protocol_versions_set_min(
+    grpc_gcp_rpc_protocol_versions* versions, uint32_t min_major,
+    uint32_t min_minor);
+
+/**
+ * This method computes serialized byte length of rpc protocol versions.
+ *
+ * - versions: an rpc protocol versions instance.
+ *
+ * The method returns serialized byte length. It returns 0 on failure.
+ */
+size_t grpc_gcp_rpc_protocol_versions_encode_length(
+    const grpc_gcp_rpc_protocol_versions* versions);
+
+/**
+ * This method serializes rpc protocol versions and writes the result to
+ * the memory buffer provided by the caller. Caller is responsible for
+ * allocating sufficient memory to store the serialized data.
+ *
+ * - versions: an rpc protocol versions instance.
+ * - bytes: bytes buffer where the result will be written to.
+ * - bytes_length: length of the bytes buffer.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_rpc_protocol_versions_encode_to_raw_bytes(
+    const grpc_gcp_rpc_protocol_versions* versions, uint8_t* bytes,
+    size_t bytes_length);
+
+/**
+ * This method serializes an rpc protocol version and returns serialized rpc
+ * versions in grpc slice.
+ *
+ * - versions: an rpc protocol versions instance.
+ * - slice: grpc slice where the serialized result will be written.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_rpc_protocol_versions_encode(
+    const grpc_gcp_rpc_protocol_versions* versions, grpc_slice* slice);
+
+/**
+ * This method de-serializes input in grpc slice form and stores the result
+ * in rpc protocol versions.
+ *
+ * - slice: a data stream containing a serialized rpc protocol version.
+ * - versions: an rpc protocol version instance used to hold de-serialized
+ *   result.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_rpc_protocol_versions_decode(
+    grpc_slice slice, grpc_gcp_rpc_protocol_versions* versions);
+
+/**
+ * This method performs a deep copy operation on rpc protocol versions
+ * instance.
+ *
+ * - src: rpc protocol versions instance that needs to be copied.
+ * - dst: rpc protocol versions instance that stores the copied result.
+ *
+ * The method returns true on success and false otherwise.
+ */
+bool grpc_gcp_rpc_protocol_versions_copy(
+    const grpc_gcp_rpc_protocol_versions* src,
+    grpc_gcp_rpc_protocol_versions* dst);
+
+/**
+ * This method performs a version check between local and peer rpc protocol
+ * versions.
+ *
+ * - local_versions: local rpc protocol versions instance.
+ * - peer_versions: peer rpc protocol versions instance.
+ * - highest_common_version: an output parameter that will store the highest
+ *   common rpc protocol version both parties agreed on.
+ *
+ * The method returns true if the check passes which means both parties agreed
+ * on a common rpc protocol to use, and false otherwise.
+ */
+bool grpc_gcp_rpc_protocol_versions_check(
+    const grpc_gcp_rpc_protocol_versions* local_versions,
+    const grpc_gcp_rpc_protocol_versions* peer_versions,
+    grpc_gcp_rpc_protocol_versions_version* highest_common_version);
+
+namespace grpc_core {
+namespace internal {
+
+/**
+ * Exposed for testing only.
+ * The method returns 0 if v1 = v2,
+ *            returns 1 if v1 > v2,
+ *            returns -1 if v1 < v2.
+ */
+int grpc_gcp_rpc_protocol_version_compare(
+    const grpc_gcp_rpc_protocol_versions_version* v1,
+    const grpc_gcp_rpc_protocol_versions_version* v2);
+
+}  // namespace internal
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_TSI_ALTS_HANDSHAKER_TRANSPORT_SECURITY_COMMON_API_H */
diff --git a/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc b/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc
new file mode 100644
index 0000000..7ba03eb
--- /dev/null
+++ b/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc
@@ -0,0 +1,180 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h"
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h"
+
+/* Main struct for alts_grpc_integrity_only_record_protocol.  */
+typedef struct alts_grpc_integrity_only_record_protocol {
+  alts_grpc_record_protocol base;
+  grpc_slice_buffer data_sb;
+  unsigned char* tag_buf;
+} alts_grpc_integrity_only_record_protocol;
+
+/* --- alts_grpc_record_protocol methods implementation. --- */
+
+static tsi_result alts_grpc_integrity_only_protect(
+    alts_grpc_record_protocol* rp, grpc_slice_buffer* unprotected_slices,
+    grpc_slice_buffer* protected_slices) {
+  /* Input sanity check.  */
+  if (rp == nullptr || unprotected_slices == nullptr ||
+      protected_slices == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to alts_grpc_record_protocol protect.");
+    return TSI_INVALID_ARGUMENT;
+  }
+  /* Allocates memory for header and tag slices.  */
+  grpc_slice header_slice = GRPC_SLICE_MALLOC(rp->header_length);
+  grpc_slice tag_slice = GRPC_SLICE_MALLOC(rp->tag_length);
+  /* Calls alts_iovec_record_protocol protect.  */
+  char* error_details = nullptr;
+  iovec_t header_iovec = {GRPC_SLICE_START_PTR(header_slice),
+                          GRPC_SLICE_LENGTH(header_slice)};
+  iovec_t tag_iovec = {GRPC_SLICE_START_PTR(tag_slice),
+                       GRPC_SLICE_LENGTH(tag_slice)};
+  alts_grpc_record_protocol_convert_slice_buffer_to_iovec(rp,
+                                                          unprotected_slices);
+  grpc_status_code status = alts_iovec_record_protocol_integrity_only_protect(
+      rp->iovec_rp, rp->iovec_buf, unprotected_slices->count, header_iovec,
+      tag_iovec, &error_details);
+  if (status != GRPC_STATUS_OK) {
+    gpr_log(GPR_ERROR, "Failed to protect, %s", error_details);
+    gpr_free(error_details);
+    return TSI_INTERNAL_ERROR;
+  }
+  /* Appends result to protected_slices.  */
+  grpc_slice_buffer_add(protected_slices, header_slice);
+  grpc_slice_buffer_move_into(unprotected_slices, protected_slices);
+  grpc_slice_buffer_add(protected_slices, tag_slice);
+  return TSI_OK;
+}
+
+static tsi_result alts_grpc_integrity_only_unprotect(
+    alts_grpc_record_protocol* rp, grpc_slice_buffer* protected_slices,
+    grpc_slice_buffer* unprotected_slices) {
+  /* Input sanity check.  */
+  if (rp == nullptr || protected_slices == nullptr ||
+      unprotected_slices == nullptr) {
+    gpr_log(
+        GPR_ERROR,
+        "Invalid nullptr arguments to alts_grpc_record_protocol unprotect.");
+    return TSI_INVALID_ARGUMENT;
+  }
+  if (protected_slices->length < rp->header_length + rp->tag_length) {
+    gpr_log(GPR_ERROR, "Protected slices do not have sufficient data.");
+    return TSI_INVALID_ARGUMENT;
+  }
+  /* In this method, rp points to alts_grpc_record_protocol struct
+   * and integrity_only_record_protocol points to
+   * alts_grpc_integrity_only_record_protocol struct.  */
+  alts_grpc_integrity_only_record_protocol* integrity_only_record_protocol =
+      reinterpret_cast<alts_grpc_integrity_only_record_protocol*>(rp);
+  /* Strips frame header from protected slices.  */
+  grpc_slice_buffer_reset_and_unref_internal(&rp->header_sb);
+  grpc_slice_buffer_move_first(protected_slices, rp->header_length,
+                               &rp->header_sb);
+  GPR_ASSERT(rp->header_sb.length == rp->header_length);
+  iovec_t header_iovec = alts_grpc_record_protocol_get_header_iovec(rp);
+  /* Moves protected slices data to data_sb and leaves the remaining tag.  */
+  grpc_slice_buffer_reset_and_unref_internal(
+      &integrity_only_record_protocol->data_sb);
+  grpc_slice_buffer_move_first(protected_slices,
+                               protected_slices->length - rp->tag_length,
+                               &integrity_only_record_protocol->data_sb);
+  GPR_ASSERT(protected_slices->length == rp->tag_length);
+  iovec_t tag_iovec = {nullptr, rp->tag_length};
+  if (protected_slices->count == 1) {
+    tag_iovec.iov_base = GRPC_SLICE_START_PTR(protected_slices->slices[0]);
+  } else {
+    /* Frame tag is in multiple slices, copies the tag bytes from slice
+     * buffer to a single flat buffer.  */
+    alts_grpc_record_protocol_copy_slice_buffer(
+        protected_slices, integrity_only_record_protocol->tag_buf);
+    tag_iovec.iov_base = integrity_only_record_protocol->tag_buf;
+  }
+  /* Calls alts_iovec_record_protocol unprotect.  */
+  char* error_details = nullptr;
+  alts_grpc_record_protocol_convert_slice_buffer_to_iovec(
+      rp, &integrity_only_record_protocol->data_sb);
+  grpc_status_code status = alts_iovec_record_protocol_integrity_only_unprotect(
+      rp->iovec_rp, rp->iovec_buf,
+      integrity_only_record_protocol->data_sb.count, header_iovec, tag_iovec,
+      &error_details);
+  if (status != GRPC_STATUS_OK) {
+    gpr_log(GPR_ERROR, "Failed to unprotect, %s", error_details);
+    gpr_free(error_details);
+    return TSI_INTERNAL_ERROR;
+  }
+  grpc_slice_buffer_reset_and_unref_internal(&rp->header_sb);
+  grpc_slice_buffer_reset_and_unref_internal(protected_slices);
+  grpc_slice_buffer_move_into(&integrity_only_record_protocol->data_sb,
+                              unprotected_slices);
+  return TSI_OK;
+}
+
+static void alts_grpc_integrity_only_destruct(alts_grpc_record_protocol* rp) {
+  if (rp == nullptr) {
+    return;
+  }
+  alts_grpc_integrity_only_record_protocol* integrity_only_rp =
+      reinterpret_cast<alts_grpc_integrity_only_record_protocol*>(rp);
+  grpc_slice_buffer_destroy_internal(&integrity_only_rp->data_sb);
+  gpr_free(integrity_only_rp->tag_buf);
+}
+
+static const alts_grpc_record_protocol_vtable
+    alts_grpc_integrity_only_record_protocol_vtable = {
+        alts_grpc_integrity_only_protect, alts_grpc_integrity_only_unprotect,
+        alts_grpc_integrity_only_destruct};
+
+tsi_result alts_grpc_integrity_only_record_protocol_create(
+    gsec_aead_crypter* crypter, size_t overflow_size, bool is_client,
+    bool is_protect, alts_grpc_record_protocol** rp) {
+  if (crypter == nullptr || rp == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to alts_grpc_record_protocol create.");
+    return TSI_INVALID_ARGUMENT;
+  }
+  alts_grpc_integrity_only_record_protocol* impl =
+      static_cast<alts_grpc_integrity_only_record_protocol*>(
+          gpr_zalloc(sizeof(alts_grpc_integrity_only_record_protocol)));
+  /* Calls alts_grpc_record_protocol init.  */
+  tsi_result result = alts_grpc_record_protocol_init(
+      &impl->base, crypter, overflow_size, is_client,
+      /*is_integrity_only=*/true, is_protect);
+  if (result != TSI_OK) {
+    gpr_free(impl);
+    return result;
+  }
+  /* Initializes slice buffer for data_sb.  */
+  grpc_slice_buffer_init(&impl->data_sb);
+  /* Allocates tag buffer.  */
+  impl->tag_buf =
+      static_cast<unsigned char*>(gpr_malloc(impl->base.tag_length));
+  impl->base.vtable = &alts_grpc_integrity_only_record_protocol_vtable;
+  *rp = &impl->base;
+  return TSI_OK;
+}
diff --git a/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h b/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h
new file mode 100644
index 0000000..8d68b27
--- /dev/null
+++ b/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_INTEGRITY_ONLY_RECORD_PROTOCOL_H
+#define GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_INTEGRITY_ONLY_RECORD_PROTOCOL_H
+
+#include <grpc/support/port_platform.h>
+
+#include <stdbool.h>
+
+#include "src/core/tsi/alts/crypt/gsec.h"
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h"
+
+/**
+ * This method creates an integrity-only alts_grpc_record_protocol instance,
+ * given a gsec_aead_crypter instance and a flag indicating if the created
+ * instance will be used at the client or server side. The ownership of
+ * gsec_aead_crypter instance is transferred to this new object.
+ *
+ * - crypter: a gsec_aead_crypter instance used to perform AEAD decryption.
+ * - overflow_size: overflow size of counter in bytes.
+ * - is_client: a flag indicating if the alts_grpc_record_protocol instance will
+ *   be used at the client or server side.
+ * - is_protect: a flag indicating if the alts_grpc_record_protocol instance
+ *   will be used for protect or unprotect.
+ * - rp: an alts_grpc_record_protocol instance to be returned from
+ *   the method.
+ *
+ * This method returns TSI_OK in case of success or a specific error code in
+ * case of failure.
+ */
+tsi_result alts_grpc_integrity_only_record_protocol_create(
+    gsec_aead_crypter* crypter, size_t overflow_size, bool is_client,
+    bool is_protect, alts_grpc_record_protocol** rp);
+
+#endif /* GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_INTEGRITY_ONLY_RECORD_PROTOCOL_H \
+        */
diff --git a/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc b/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc
new file mode 100644
index 0000000..d4fd88d
--- /dev/null
+++ b/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc
@@ -0,0 +1,144 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h"
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h"
+
+/* Privacy-integrity alts_grpc_record_protocol object uses the same struct
+ * defined in alts_grpc_record_protocol_common.h.  */
+
+/* --- alts_grpc_record_protocol methods implementation. --- */
+
+static tsi_result alts_grpc_privacy_integrity_protect(
+    alts_grpc_record_protocol* rp, grpc_slice_buffer* unprotected_slices,
+    grpc_slice_buffer* protected_slices) {
+  /* Input sanity check.  */
+  if (rp == nullptr || unprotected_slices == nullptr ||
+      protected_slices == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to alts_grpc_record_protocol protect.");
+    return TSI_INVALID_ARGUMENT;
+  }
+  /* Allocates memory for output frame. In privacy-integrity protect, the
+   * protected frame is stored in a newly allocated buffer.  */
+  size_t protected_frame_size =
+      unprotected_slices->length + rp->header_length +
+      alts_iovec_record_protocol_get_tag_length(rp->iovec_rp);
+  grpc_slice protected_slice = GRPC_SLICE_MALLOC(protected_frame_size);
+  iovec_t protected_iovec = {GRPC_SLICE_START_PTR(protected_slice),
+                             GRPC_SLICE_LENGTH(protected_slice)};
+  /* Calls alts_iovec_record_protocol protect.  */
+  char* error_details = nullptr;
+  alts_grpc_record_protocol_convert_slice_buffer_to_iovec(rp,
+                                                          unprotected_slices);
+  grpc_status_code status =
+      alts_iovec_record_protocol_privacy_integrity_protect(
+          rp->iovec_rp, rp->iovec_buf, unprotected_slices->count,
+          protected_iovec, &error_details);
+  if (status != GRPC_STATUS_OK) {
+    gpr_log(GPR_ERROR, "Failed to protect, %s", error_details);
+    gpr_free(error_details);
+    grpc_slice_unref(protected_slice);
+    return TSI_INTERNAL_ERROR;
+  }
+  grpc_slice_buffer_add(protected_slices, protected_slice);
+  grpc_slice_buffer_reset_and_unref_internal(unprotected_slices);
+  return TSI_OK;
+}
+
+static tsi_result alts_grpc_privacy_integrity_unprotect(
+    alts_grpc_record_protocol* rp, grpc_slice_buffer* protected_slices,
+    grpc_slice_buffer* unprotected_slices) {
+  /* Input sanity check.  */
+  if (rp == nullptr || protected_slices == nullptr ||
+      unprotected_slices == nullptr) {
+    gpr_log(
+        GPR_ERROR,
+        "Invalid nullptr arguments to alts_grpc_record_protocol unprotect.");
+    return TSI_INVALID_ARGUMENT;
+  }
+  /* Allocates memory for output frame. In privacy-integrity unprotect, the
+   * unprotected data are stored in a newly allocated buffer.  */
+  if (protected_slices->length < rp->header_length + rp->tag_length) {
+    gpr_log(GPR_ERROR, "Protected slices do not have sufficient data.");
+    return TSI_INVALID_ARGUMENT;
+  }
+  size_t unprotected_frame_size =
+      protected_slices->length - rp->header_length - rp->tag_length;
+  grpc_slice unprotected_slice = GRPC_SLICE_MALLOC(unprotected_frame_size);
+  iovec_t unprotected_iovec = {GRPC_SLICE_START_PTR(unprotected_slice),
+                               GRPC_SLICE_LENGTH(unprotected_slice)};
+  /* Strips frame header from protected slices.  */
+  grpc_slice_buffer_reset_and_unref_internal(&rp->header_sb);
+  grpc_slice_buffer_move_first(protected_slices, rp->header_length,
+                               &rp->header_sb);
+  iovec_t header_iovec = alts_grpc_record_protocol_get_header_iovec(rp);
+  /* Calls alts_iovec_record_protocol unprotect.  */
+  char* error_details = nullptr;
+  alts_grpc_record_protocol_convert_slice_buffer_to_iovec(rp, protected_slices);
+  grpc_status_code status =
+      alts_iovec_record_protocol_privacy_integrity_unprotect(
+          rp->iovec_rp, header_iovec, rp->iovec_buf, protected_slices->count,
+          unprotected_iovec, &error_details);
+  if (status != GRPC_STATUS_OK) {
+    gpr_log(GPR_ERROR, "Failed to unprotect, %s", error_details);
+    gpr_free(error_details);
+    grpc_slice_unref(unprotected_slice);
+    return TSI_INTERNAL_ERROR;
+  }
+  grpc_slice_buffer_reset_and_unref_internal(&rp->header_sb);
+  grpc_slice_buffer_reset_and_unref_internal(protected_slices);
+  grpc_slice_buffer_add(unprotected_slices, unprotected_slice);
+  return TSI_OK;
+}
+
+static const alts_grpc_record_protocol_vtable
+    alts_grpc_privacy_integrity_record_protocol_vtable = {
+        alts_grpc_privacy_integrity_protect,
+        alts_grpc_privacy_integrity_unprotect, nullptr};
+
+tsi_result alts_grpc_privacy_integrity_record_protocol_create(
+    gsec_aead_crypter* crypter, size_t overflow_size, bool is_client,
+    bool is_protect, alts_grpc_record_protocol** rp) {
+  if (crypter == nullptr || rp == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to alts_grpc_record_protocol create.");
+    return TSI_INVALID_ARGUMENT;
+  }
+  auto* impl = static_cast<alts_grpc_record_protocol*>(
+      gpr_zalloc(sizeof(alts_grpc_record_protocol)));
+  /* Calls alts_grpc_record_protocol init.  */
+  tsi_result result =
+      alts_grpc_record_protocol_init(impl, crypter, overflow_size, is_client,
+                                     /*is_integrity_only=*/false, is_protect);
+  if (result != TSI_OK) {
+    gpr_free(impl);
+    return result;
+  }
+  impl->vtable = &alts_grpc_privacy_integrity_record_protocol_vtable;
+  *rp = impl;
+  return TSI_OK;
+}
diff --git a/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h b/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h
new file mode 100644
index 0000000..1e34aef
--- /dev/null
+++ b/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_PRIVACY_INTEGRITY_RECORD_PROTOCOL_H
+#define GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_PRIVACY_INTEGRITY_RECORD_PROTOCOL_H
+
+#include <grpc/support/port_platform.h>
+
+#include <stdbool.h>
+
+#include "src/core/tsi/alts/crypt/gsec.h"
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h"
+
+/**
+ * This method creates a privacy-integrity alts_grpc_record_protocol instance,
+ * given a gsec_aead_crypter instance and a flag indicating if the created
+ * instance will be used at the client or server side. The ownership of
+ * gsec_aead_crypter instance is transferred to this new object.
+ *
+ * - crypter: a gsec_aead_crypter instance used to perform AEAD decryption.
+ * - is_client: a flag indicating if the alts_grpc_record_protocol instance will
+ *   be used at the client or server side.
+ * - rp: an alts_grpc_record_protocol instance to be returned from
+ *   the method.
+ *
+ * This method returns TSI_OK in case of success or a specific error code in
+ * case of failure.
+ */
+tsi_result alts_grpc_privacy_integrity_record_protocol_create(
+    gsec_aead_crypter* crypter, size_t overflow_size, bool is_client,
+    bool is_protect, alts_grpc_record_protocol** rp);
+
+#endif /* GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_PRIVACY_INTEGRITY_RECORD_PROTOCOL_H \
+        */
diff --git a/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h b/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h
new file mode 100644
index 0000000..d1e433d
--- /dev/null
+++ b/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h
@@ -0,0 +1,91 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_RECORD_PROTOCOL_H
+#define GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_RECORD_PROTOCOL_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/slice_buffer.h>
+
+#include "src/core/tsi/transport_security_interface.h"
+
+/**
+ * This alts_grpc_record_protocol object protects and unprotects a single frame
+ * stored in grpc slice buffer with zero or minimized memory copy.
+ * Implementations of this object must be thread compatible.
+ */
+typedef struct alts_grpc_record_protocol alts_grpc_record_protocol;
+
+/**
+ * This methods performs protect operation on unprotected data and appends the
+ * protected frame to protected_slices. The caller needs to ensure the length
+ * of unprotected data plus the frame overhead is less than or equal to the
+ * maximum frame length. The input unprotected data slice buffer will be
+ * cleared, although the actual unprotected data bytes are not modified.
+ *
+ * - self: an alts_grpc_record_protocol instance.
+ * - unprotected_slices: the unprotected data to be protected.
+ * - protected_slices: slice buffer where the protected frame is appended.
+ *
+ * This method returns TSI_OK in case of success or a specific error code in
+ * case of failure.
+ */
+tsi_result alts_grpc_record_protocol_protect(
+    alts_grpc_record_protocol* self, grpc_slice_buffer* unprotected_slices,
+    grpc_slice_buffer* protected_slices);
+
+/**
+ * This methods performs unprotect operation on a full frame of protected data
+ * and appends unprotected data to unprotected_slices. It is the caller's
+ * responsibility to prepare a full frame of data before calling this method.
+ * The input protected frame slice buffer will be cleared, although the actual
+ * protected data bytes are not modified.
+ *
+ * - self: an alts_grpc_record_protocol instance.
+ * - protected_slices: a full frame of protected data in grpc slices.
+ * - unprotected_slices: slice buffer where unprotected data is appended.
+ *
+ * This method returns TSI_OK in case of success or a specific error code in
+ * case of failure.
+ */
+tsi_result alts_grpc_record_protocol_unprotect(
+    alts_grpc_record_protocol* self, grpc_slice_buffer* protected_slices,
+    grpc_slice_buffer* unprotected_slices);
+
+/**
+ * This method returns maximum allowed unprotected data size, given maximum
+ * protected frame size.
+ *
+ * - self: an alts_grpc_record_protocol instance.
+ * - max_protected_frame_size: maximum protected frame size.
+ *
+ * On success, the method returns the maximum allowed unprotected data size.
+ * Otherwise, it returns zero.
+ */
+size_t alts_grpc_record_protocol_max_unprotected_data_size(
+    const alts_grpc_record_protocol* self, size_t max_protected_frame_size);
+
+/**
+ * This method destroys an alts_grpc_record_protocol instance by de-allocating
+ * all of its occupied memory.
+ */
+void alts_grpc_record_protocol_destroy(alts_grpc_record_protocol* self);
+
+#endif /* GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_RECORD_PROTOCOL_H \
+        */
diff --git a/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc b/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc
new file mode 100644
index 0000000..1048b60
--- /dev/null
+++ b/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc
@@ -0,0 +1,174 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/slice/slice_internal.h"
+
+const size_t kInitialIovecBufferSize = 8;
+
+/* Makes sure iovec_buf in alts_grpc_record_protocol is large enough.  */
+static void ensure_iovec_buf_size(alts_grpc_record_protocol* rp,
+                                  const grpc_slice_buffer* sb) {
+  GPR_ASSERT(rp != nullptr && sb != nullptr);
+  if (sb->count <= rp->iovec_buf_length) {
+    return;
+  }
+  /* At least double the iovec buffer size.  */
+  rp->iovec_buf_length = GPR_MAX(sb->count, 2 * rp->iovec_buf_length);
+  rp->iovec_buf = static_cast<iovec_t*>(
+      gpr_realloc(rp->iovec_buf, rp->iovec_buf_length * sizeof(iovec_t)));
+}
+
+/* --- Implementation of methods defined in tsi_grpc_record_protocol_common.h.
+ * --- */
+
+void alts_grpc_record_protocol_convert_slice_buffer_to_iovec(
+    alts_grpc_record_protocol* rp, const grpc_slice_buffer* sb) {
+  GPR_ASSERT(rp != nullptr && sb != nullptr);
+  ensure_iovec_buf_size(rp, sb);
+  for (size_t i = 0; i < sb->count; i++) {
+    rp->iovec_buf[i].iov_base = GRPC_SLICE_START_PTR(sb->slices[i]);
+    rp->iovec_buf[i].iov_len = GRPC_SLICE_LENGTH(sb->slices[i]);
+  }
+}
+
+void alts_grpc_record_protocol_copy_slice_buffer(const grpc_slice_buffer* src,
+                                                 unsigned char* dst) {
+  GPR_ASSERT(src != nullptr && dst != nullptr);
+  for (size_t i = 0; i < src->count; i++) {
+    size_t slice_length = GRPC_SLICE_LENGTH(src->slices[i]);
+    memcpy(dst, GRPC_SLICE_START_PTR(src->slices[i]), slice_length);
+    dst += slice_length;
+  }
+}
+
+iovec_t alts_grpc_record_protocol_get_header_iovec(
+    alts_grpc_record_protocol* rp) {
+  iovec_t header_iovec = {nullptr, 0};
+  if (rp == nullptr) {
+    return header_iovec;
+  }
+  header_iovec.iov_len = rp->header_length;
+  if (rp->header_sb.count == 1) {
+    header_iovec.iov_base = GRPC_SLICE_START_PTR(rp->header_sb.slices[0]);
+  } else {
+    /* Frame header is in multiple slices, copies the header bytes from slice
+     * buffer to a single flat buffer.  */
+    alts_grpc_record_protocol_copy_slice_buffer(&rp->header_sb, rp->header_buf);
+    header_iovec.iov_base = rp->header_buf;
+  }
+  return header_iovec;
+}
+
+tsi_result alts_grpc_record_protocol_init(alts_grpc_record_protocol* rp,
+                                          gsec_aead_crypter* crypter,
+                                          size_t overflow_size, bool is_client,
+                                          bool is_integrity_only,
+                                          bool is_protect) {
+  if (rp == nullptr || crypter == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to alts_grpc_record_protocol init.");
+    return TSI_INVALID_ARGUMENT;
+  }
+  /* Creates alts_iovec_record_protocol.  */
+  char* error_details = nullptr;
+  grpc_status_code status = alts_iovec_record_protocol_create(
+      crypter, overflow_size, is_client, is_integrity_only, is_protect,
+      &rp->iovec_rp, &error_details);
+  if (status != GRPC_STATUS_OK) {
+    gpr_log(GPR_ERROR, "Failed to create alts_iovec_record_protocol, %s.",
+            error_details);
+    gpr_free(error_details);
+    return TSI_INTERNAL_ERROR;
+  }
+  /* Allocates header slice buffer.  */
+  grpc_slice_buffer_init(&rp->header_sb);
+  /* Allocates header buffer.  */
+  rp->header_length = alts_iovec_record_protocol_get_header_length();
+  rp->header_buf = static_cast<unsigned char*>(gpr_malloc(rp->header_length));
+  rp->tag_length = alts_iovec_record_protocol_get_tag_length(rp->iovec_rp);
+  /* Allocates iovec buffer.  */
+  rp->iovec_buf_length = kInitialIovecBufferSize;
+  rp->iovec_buf =
+      static_cast<iovec_t*>(gpr_malloc(rp->iovec_buf_length * sizeof(iovec_t)));
+  return TSI_OK;
+}
+
+/* --- Implementation of methods defined in tsi_grpc_record_protocol.h. --- */
+tsi_result alts_grpc_record_protocol_protect(
+    alts_grpc_record_protocol* self, grpc_slice_buffer* unprotected_slices,
+    grpc_slice_buffer* protected_slices) {
+  if (grpc_core::ExecCtx::Get() == nullptr || self == nullptr ||
+      self->vtable == nullptr || unprotected_slices == nullptr ||
+      protected_slices == nullptr) {
+    return TSI_INVALID_ARGUMENT;
+  }
+  if (self->vtable->protect == nullptr) {
+    return TSI_UNIMPLEMENTED;
+  }
+  return self->vtable->protect(self, unprotected_slices, protected_slices);
+}
+
+tsi_result alts_grpc_record_protocol_unprotect(
+    alts_grpc_record_protocol* self, grpc_slice_buffer* protected_slices,
+    grpc_slice_buffer* unprotected_slices) {
+  if (grpc_core::ExecCtx::Get() == nullptr || self == nullptr ||
+      self->vtable == nullptr || protected_slices == nullptr ||
+      unprotected_slices == nullptr) {
+    return TSI_INVALID_ARGUMENT;
+  }
+  if (self->vtable->unprotect == nullptr) {
+    return TSI_UNIMPLEMENTED;
+  }
+  return self->vtable->unprotect(self, protected_slices, unprotected_slices);
+}
+
+void alts_grpc_record_protocol_destroy(alts_grpc_record_protocol* self) {
+  if (self == nullptr) {
+    return;
+  }
+  if (self->vtable->destruct != nullptr) {
+    self->vtable->destruct(self);
+  }
+  alts_iovec_record_protocol_destroy(self->iovec_rp);
+  grpc_slice_buffer_destroy_internal(&self->header_sb);
+  gpr_free(self->header_buf);
+  gpr_free(self->iovec_buf);
+  gpr_free(self);
+}
+
+/* Integrity-only and privacy-integrity share the same implementation. No need
+ * to call vtable.  */
+size_t alts_grpc_record_protocol_max_unprotected_data_size(
+    const alts_grpc_record_protocol* self, size_t max_protected_frame_size) {
+  if (self == nullptr) {
+    return 0;
+  }
+  return alts_iovec_record_protocol_max_unprotected_data_size(
+      self->iovec_rp, max_protected_frame_size);
+}
diff --git a/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h b/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h
new file mode 100644
index 0000000..43b8a4a
--- /dev/null
+++ b/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h
@@ -0,0 +1,100 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_RECORD_PROTOCOL_COMMON_H
+#define GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_RECORD_PROTOCOL_COMMON_H
+
+/**
+ * this file contains alts_grpc_record_protocol internals and internal-only
+ * helper functions. The public functions of alts_grpc_record_protocol are
+ * defined in the alts_grpc_record_protocol.h.
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h"
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h"
+
+/* V-table for alts_grpc_record_protocol implementations.  */
+typedef struct {
+  tsi_result (*protect)(alts_grpc_record_protocol* self,
+                        grpc_slice_buffer* unprotected_slices,
+                        grpc_slice_buffer* protected_slices);
+  tsi_result (*unprotect)(alts_grpc_record_protocol* self,
+                          grpc_slice_buffer* protected_slices,
+                          grpc_slice_buffer* unprotected_slices);
+  void (*destruct)(alts_grpc_record_protocol* self);
+} alts_grpc_record_protocol_vtable;
+
+/* Main struct for alts_grpc_record_protocol implementation, shared by both
+ * integrity-only record protocol and privacy-integrity record protocol.
+ * Integrity-only record protocol has additional data elements.
+ * Privacy-integrity record protocol uses this struct directly.  */
+struct alts_grpc_record_protocol {
+  const alts_grpc_record_protocol_vtable* vtable;
+  alts_iovec_record_protocol* iovec_rp;
+  grpc_slice_buffer header_sb;
+  unsigned char* header_buf;
+  size_t header_length;
+  size_t tag_length;
+  iovec_t* iovec_buf;
+  size_t iovec_buf_length;
+};
+
+/**
+ * Converts the slices of input sb into iovec_t's and puts the result into
+ * rp->iovec_buf. Note that the actual data are not copied, only
+ * pointers and lengths are copied.
+ */
+void alts_grpc_record_protocol_convert_slice_buffer_to_iovec(
+    alts_grpc_record_protocol* rp, const grpc_slice_buffer* sb);
+
+/**
+ * Copies bytes from slice buffer to destination buffer. Caller is responsible
+ * for allocating enough memory of destination buffer. This method is used for
+ * copying frame header and tag in case they are stored in multiple slices.
+ */
+void alts_grpc_record_protocol_copy_slice_buffer(const grpc_slice_buffer* src,
+                                                 unsigned char* dst);
+
+/**
+ * This method returns an iovec object pointing to the frame header stored in
+ * rp->header_sb. If the frame header is stored in multiple slices,
+ * this method will copy the bytes in rp->header_sb to
+ * rp->header_buf, and return an iovec object pointing to
+ * rp->header_buf.
+ */
+iovec_t alts_grpc_record_protocol_get_header_iovec(
+    alts_grpc_record_protocol* rp);
+
+/**
+ * Initializes an alts_grpc_record_protocol object, given a gsec_aead_crypter
+ * instance, the overflow size of the counter in bytes, a flag indicating if the
+ * object is used for client or server side, a flag indicating if it is used for
+ * integrity-only or privacy-integrity mode, and a flag indicating if it is for
+ * protect or unprotect. The ownership of gsec_aead_crypter object is
+ * transferred to the alts_grpc_record_protocol object.
+ */
+tsi_result alts_grpc_record_protocol_init(alts_grpc_record_protocol* rp,
+                                          gsec_aead_crypter* crypter,
+                                          size_t overflow_size, bool is_client,
+                                          bool is_integrity_only,
+                                          bool is_protect);
+
+#endif /* GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_GRPC_RECORD_PROTOCOL_COMMON_H \
+        */
diff --git a/src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc b/src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc
new file mode 100644
index 0000000..6a548e5
--- /dev/null
+++ b/src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc
@@ -0,0 +1,476 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/tsi/alts/frame_protector/alts_counter.h"
+
+struct alts_iovec_record_protocol {
+  alts_counter* ctr;
+  gsec_aead_crypter* crypter;
+  size_t tag_length;
+  bool is_integrity_only;
+  bool is_protect;
+};
+
+/* Copies error message to destination.  */
+static void maybe_copy_error_msg(const char* src, char** dst) {
+  if (dst != nullptr && src != nullptr) {
+    *dst = static_cast<char*>(gpr_malloc(strlen(src) + 1));
+    memcpy(*dst, src, strlen(src) + 1);
+  }
+}
+
+/* Appends error message to destination.  */
+static void maybe_append_error_msg(const char* appendix, char** dst) {
+  if (dst != nullptr && appendix != nullptr) {
+    int dst_len = static_cast<int>(strlen(*dst));
+    *dst = static_cast<char*>(realloc(*dst, dst_len + strlen(appendix) + 1));
+    assert(*dst != nullptr);
+    memcpy(*dst + dst_len, appendix, strlen(appendix) + 1);
+  }
+}
+
+/* Use little endian to interpret a string of bytes as uint32_t.  */
+static uint32_t load_32_le(const unsigned char* buffer) {
+  return (((uint32_t)buffer[3]) << 24) | (((uint32_t)buffer[2]) << 16) |
+         (((uint32_t)buffer[1]) << 8) | ((uint32_t)buffer[0]);
+}
+
+/* Store uint32_t as a string of little endian bytes.  */
+static void store_32_le(uint32_t value, unsigned char* buffer) {
+  buffer[3] = (unsigned char)(value >> 24) & 0xFF;
+  buffer[2] = (unsigned char)(value >> 16) & 0xFF;
+  buffer[1] = (unsigned char)(value >> 8) & 0xFF;
+  buffer[0] = (unsigned char)(value)&0xFF;
+}
+
+/* Ensures header and tag iovec have sufficient length.  */
+static grpc_status_code ensure_header_and_tag_length(
+    const alts_iovec_record_protocol* rp, iovec_t header, iovec_t tag,
+    char** error_details) {
+  if (rp == nullptr) {
+    return GRPC_STATUS_FAILED_PRECONDITION;
+  }
+  if (header.iov_base == nullptr) {
+    maybe_copy_error_msg("Header is nullptr.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  if (header.iov_len != alts_iovec_record_protocol_get_header_length()) {
+    maybe_copy_error_msg("Header length is incorrect.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  if (tag.iov_base == nullptr) {
+    maybe_copy_error_msg("Tag is nullptr.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  if (tag.iov_len != rp->tag_length) {
+    maybe_copy_error_msg("Tag length is incorrect.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  return GRPC_STATUS_OK;
+}
+
+/* Increments crypter counter and checks overflow.  */
+static grpc_status_code increment_counter(alts_counter* counter,
+                                          char** error_details) {
+  if (counter == nullptr) {
+    return GRPC_STATUS_FAILED_PRECONDITION;
+  }
+  bool is_overflow = false;
+  grpc_status_code status =
+      alts_counter_increment(counter, &is_overflow, error_details);
+  if (status != GRPC_STATUS_OK) {
+    return status;
+  }
+  if (is_overflow) {
+    maybe_copy_error_msg("Crypter counter is overflowed.", error_details);
+    return GRPC_STATUS_INTERNAL;
+  }
+  return GRPC_STATUS_OK;
+}
+
+/* Given an array of iovec, computes the total length of buffer.  */
+static size_t get_total_length(const iovec_t* vec, size_t vec_length) {
+  size_t total_length = 0;
+  for (size_t i = 0; i < vec_length; ++i) {
+    total_length += vec[i].iov_len;
+  }
+  return total_length;
+}
+
+/* Writes frame header given data and tag length.  */
+static grpc_status_code write_frame_header(size_t data_length,
+                                           unsigned char* header,
+                                           char** error_details) {
+  if (header == nullptr) {
+    maybe_copy_error_msg("Header is nullptr.", error_details);
+    return GRPC_STATUS_FAILED_PRECONDITION;
+  }
+  size_t frame_length = kZeroCopyFrameMessageTypeFieldSize + data_length;
+  store_32_le(static_cast<uint32_t>(frame_length), header);
+  store_32_le(kZeroCopyFrameMessageType,
+              header + kZeroCopyFrameLengthFieldSize);
+  return GRPC_STATUS_OK;
+}
+
+/* Verifies frame header given protected data length.  */
+static grpc_status_code verify_frame_header(size_t data_length,
+                                            unsigned char* header,
+                                            char** error_details) {
+  if (header == nullptr) {
+    maybe_copy_error_msg("Header is nullptr.", error_details);
+    return GRPC_STATUS_FAILED_PRECONDITION;
+  }
+  size_t frame_length = load_32_le(header);
+  if (frame_length != kZeroCopyFrameMessageTypeFieldSize + data_length) {
+    maybe_copy_error_msg("Bad frame length.", error_details);
+    return GRPC_STATUS_INTERNAL;
+  }
+  size_t message_type = load_32_le(header + kZeroCopyFrameLengthFieldSize);
+  if (message_type != kZeroCopyFrameMessageType) {
+    maybe_copy_error_msg("Unsupported message type.", error_details);
+    return GRPC_STATUS_INTERNAL;
+  }
+  return GRPC_STATUS_OK;
+}
+
+/* --- alts_iovec_record_protocol methods implementation. --- */
+
+size_t alts_iovec_record_protocol_get_header_length() {
+  return kZeroCopyFrameHeaderSize;
+}
+
+size_t alts_iovec_record_protocol_get_tag_length(
+    const alts_iovec_record_protocol* rp) {
+  if (rp != nullptr) {
+    return rp->tag_length;
+  }
+  return 0;
+}
+
+size_t alts_iovec_record_protocol_max_unprotected_data_size(
+    const alts_iovec_record_protocol* rp, size_t max_protected_frame_size) {
+  if (rp == nullptr) {
+    return 0;
+  }
+  size_t overhead_bytes_size =
+      kZeroCopyFrameMessageTypeFieldSize + rp->tag_length;
+  if (max_protected_frame_size <= overhead_bytes_size) return 0;
+  return max_protected_frame_size - overhead_bytes_size;
+}
+
+grpc_status_code alts_iovec_record_protocol_integrity_only_protect(
+    alts_iovec_record_protocol* rp, const iovec_t* unprotected_vec,
+    size_t unprotected_vec_length, iovec_t header, iovec_t tag,
+    char** error_details) {
+  /* Input sanity checks.  */
+  if (rp == nullptr) {
+    maybe_copy_error_msg("Input iovec_record_protocol is nullptr.",
+                         error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  if (!rp->is_integrity_only) {
+    maybe_copy_error_msg(
+        "Integrity-only operations are not allowed for this object.",
+        error_details);
+    return GRPC_STATUS_FAILED_PRECONDITION;
+  }
+  if (!rp->is_protect) {
+    maybe_copy_error_msg("Protect operations are not allowed for this object.",
+                         error_details);
+    return GRPC_STATUS_FAILED_PRECONDITION;
+  }
+  grpc_status_code status =
+      ensure_header_and_tag_length(rp, header, tag, error_details);
+  if (status != GRPC_STATUS_OK) {
+    return status;
+  }
+  /* Unprotected data should not be zero length.  */
+  size_t data_length =
+      get_total_length(unprotected_vec, unprotected_vec_length);
+  /* Sets frame header.  */
+  status = write_frame_header(data_length + rp->tag_length,
+                              static_cast<unsigned char*>(header.iov_base),
+                              error_details);
+  if (status != GRPC_STATUS_OK) {
+    return status;
+  }
+  /* Computes frame tag by calling AEAD crypter.  */
+  size_t bytes_written = 0;
+  status = gsec_aead_crypter_encrypt_iovec(
+      rp->crypter, alts_counter_get_counter(rp->ctr),
+      alts_counter_get_size(rp->ctr), unprotected_vec, unprotected_vec_length,
+      /* plaintext_vec = */ nullptr, /* plaintext_vec_length = */ 0, tag,
+      &bytes_written, error_details);
+  if (status != GRPC_STATUS_OK) {
+    return status;
+  }
+  if (bytes_written != rp->tag_length) {
+    maybe_copy_error_msg("Bytes written expects to be the same as tag length.",
+                         error_details);
+    return GRPC_STATUS_INTERNAL;
+  }
+  /* Increments the crypter counter.  */
+  return increment_counter(rp->ctr, error_details);
+}
+
+grpc_status_code alts_iovec_record_protocol_integrity_only_unprotect(
+    alts_iovec_record_protocol* rp, const iovec_t* protected_vec,
+    size_t protected_vec_length, iovec_t header, iovec_t tag,
+    char** error_details) {
+  /* Input sanity checks.  */
+  if (rp == nullptr) {
+    maybe_copy_error_msg("Input iovec_record_protocol is nullptr.",
+                         error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  if (!rp->is_integrity_only) {
+    maybe_copy_error_msg(
+        "Integrity-only operations are not allowed for this object.",
+        error_details);
+    return GRPC_STATUS_FAILED_PRECONDITION;
+  }
+  if (rp->is_protect) {
+    maybe_copy_error_msg(
+        "Unprotect operations are not allowed for this object.", error_details);
+    return GRPC_STATUS_FAILED_PRECONDITION;
+  }
+  grpc_status_code status =
+      ensure_header_and_tag_length(rp, header, tag, error_details);
+  if (status != GRPC_STATUS_OK) return status;
+  /* Protected data should not be zero length.  */
+  size_t data_length = get_total_length(protected_vec, protected_vec_length);
+  /* Verifies frame header.  */
+  status = verify_frame_header(data_length + rp->tag_length,
+                               static_cast<unsigned char*>(header.iov_base),
+                               error_details);
+  if (status != GRPC_STATUS_OK) {
+    return status;
+  }
+  /* Verifies frame tag by calling AEAD crypter.  */
+  iovec_t plaintext = {nullptr, 0};
+  size_t bytes_written = 0;
+  status = gsec_aead_crypter_decrypt_iovec(
+      rp->crypter, alts_counter_get_counter(rp->ctr),
+      alts_counter_get_size(rp->ctr), protected_vec, protected_vec_length, &tag,
+      1, plaintext, &bytes_written, error_details);
+  if (status != GRPC_STATUS_OK || bytes_written != 0) {
+    maybe_append_error_msg(" Frame tag verification failed.", error_details);
+    return GRPC_STATUS_INTERNAL;
+  }
+  /* Increments the crypter counter.  */
+  return increment_counter(rp->ctr, error_details);
+}
+
+grpc_status_code alts_iovec_record_protocol_privacy_integrity_protect(
+    alts_iovec_record_protocol* rp, const iovec_t* unprotected_vec,
+    size_t unprotected_vec_length, iovec_t protected_frame,
+    char** error_details) {
+  /* Input sanity checks.  */
+  if (rp == nullptr) {
+    maybe_copy_error_msg("Input iovec_record_protocol is nullptr.",
+                         error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  if (rp->is_integrity_only) {
+    maybe_copy_error_msg(
+        "Privacy-integrity operations are not allowed for this object.",
+        error_details);
+    return GRPC_STATUS_FAILED_PRECONDITION;
+  }
+  if (!rp->is_protect) {
+    maybe_copy_error_msg("Protect operations are not allowed for this object.",
+                         error_details);
+    return GRPC_STATUS_FAILED_PRECONDITION;
+  }
+  /* Unprotected data should not be zero length.  */
+  size_t data_length =
+      get_total_length(unprotected_vec, unprotected_vec_length);
+  /* Ensures protected frame iovec has sufficient size.  */
+  if (protected_frame.iov_base == nullptr) {
+    maybe_copy_error_msg("Protected frame is nullptr.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  if (protected_frame.iov_len !=
+      alts_iovec_record_protocol_get_header_length() + data_length +
+          rp->tag_length) {
+    maybe_copy_error_msg("Protected frame size is incorrect.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  /* Writer frame header.  */
+  grpc_status_code status = write_frame_header(
+      data_length + rp->tag_length,
+      static_cast<unsigned char*>(protected_frame.iov_base), error_details);
+  if (status != GRPC_STATUS_OK) {
+    return status;
+  }
+  /* Encrypt unprotected data by calling AEAD crypter.  */
+  unsigned char* ciphertext_buffer =
+      static_cast<unsigned char*>(protected_frame.iov_base) +
+      alts_iovec_record_protocol_get_header_length();
+  iovec_t ciphertext = {ciphertext_buffer, data_length + rp->tag_length};
+  size_t bytes_written = 0;
+  status = gsec_aead_crypter_encrypt_iovec(
+      rp->crypter, alts_counter_get_counter(rp->ctr),
+      alts_counter_get_size(rp->ctr), /* aad_vec = */ nullptr,
+      /* aad_vec_length = */ 0, unprotected_vec, unprotected_vec_length,
+      ciphertext, &bytes_written, error_details);
+  if (status != GRPC_STATUS_OK) {
+    return status;
+  }
+  if (bytes_written != data_length + rp->tag_length) {
+    maybe_copy_error_msg(
+        "Bytes written expects to be data length plus tag length.",
+        error_details);
+    return GRPC_STATUS_INTERNAL;
+  }
+  /* Increments the crypter counter. */
+  return increment_counter(rp->ctr, error_details);
+}
+
+grpc_status_code alts_iovec_record_protocol_privacy_integrity_unprotect(
+    alts_iovec_record_protocol* rp, iovec_t header,
+    const iovec_t* protected_vec, size_t protected_vec_length,
+    iovec_t unprotected_data, char** error_details) {
+  /* Input sanity checks.  */
+  if (rp == nullptr) {
+    maybe_copy_error_msg("Input iovec_record_protocol is nullptr.",
+                         error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  if (rp->is_integrity_only) {
+    maybe_copy_error_msg(
+        "Privacy-integrity operations are not allowed for this object.",
+        error_details);
+    return GRPC_STATUS_FAILED_PRECONDITION;
+  }
+  if (rp->is_protect) {
+    maybe_copy_error_msg(
+        "Unprotect operations are not allowed for this object.", error_details);
+    return GRPC_STATUS_FAILED_PRECONDITION;
+  }
+  /* Protected data size should be no less than tag size.  */
+  size_t protected_data_length =
+      get_total_length(protected_vec, protected_vec_length);
+  if (protected_data_length < rp->tag_length) {
+    maybe_copy_error_msg(
+        "Protected data length should be more than the tag length.",
+        error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  /* Ensures header has sufficient size.  */
+  if (header.iov_base == nullptr) {
+    maybe_copy_error_msg("Header is nullptr.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  if (header.iov_len != alts_iovec_record_protocol_get_header_length()) {
+    maybe_copy_error_msg("Header length is incorrect.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  /* Ensures unprotected data iovec has sufficient size.  */
+  if (unprotected_data.iov_len != protected_data_length - rp->tag_length) {
+    maybe_copy_error_msg("Unprotected data size is incorrect.", error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  /* Verify frame header.  */
+  grpc_status_code status = verify_frame_header(
+      protected_data_length, static_cast<unsigned char*>(header.iov_base),
+      error_details);
+  if (status != GRPC_STATUS_OK) {
+    return status;
+  }
+  /* Decrypt protected data by calling AEAD crypter.  */
+  size_t bytes_written = 0;
+  status = gsec_aead_crypter_decrypt_iovec(
+      rp->crypter, alts_counter_get_counter(rp->ctr),
+      alts_counter_get_size(rp->ctr), /* aad_vec = */ nullptr,
+      /* aad_vec_length = */ 0, protected_vec, protected_vec_length,
+      unprotected_data, &bytes_written, error_details);
+  if (status != GRPC_STATUS_OK) {
+    maybe_append_error_msg(" Frame decryption failed.", error_details);
+    return GRPC_STATUS_INTERNAL;
+  }
+  if (bytes_written != protected_data_length - rp->tag_length) {
+    maybe_copy_error_msg(
+        "Bytes written expects to be protected data length minus tag length.",
+        error_details);
+    return GRPC_STATUS_INTERNAL;
+  }
+  /* Increments the crypter counter. */
+  return increment_counter(rp->ctr, error_details);
+}
+
+grpc_status_code alts_iovec_record_protocol_create(
+    gsec_aead_crypter* crypter, size_t overflow_size, bool is_client,
+    bool is_integrity_only, bool is_protect, alts_iovec_record_protocol** rp,
+    char** error_details) {
+  if (crypter == nullptr || rp == nullptr) {
+    maybe_copy_error_msg(
+        "Invalid nullptr arguments to alts_iovec_record_protocol create.",
+        error_details);
+    return GRPC_STATUS_INVALID_ARGUMENT;
+  }
+  alts_iovec_record_protocol* impl = static_cast<alts_iovec_record_protocol*>(
+      gpr_zalloc(sizeof(alts_iovec_record_protocol)));
+  /* Gets counter length.  */
+  size_t counter_length = 0;
+  grpc_status_code status =
+      gsec_aead_crypter_nonce_length(crypter, &counter_length, error_details);
+  if (status != GRPC_STATUS_OK) {
+    goto cleanup;
+  }
+  /* Creates counters.  */
+  status =
+      alts_counter_create(is_protect ? !is_client : is_client, counter_length,
+                          overflow_size, &impl->ctr, error_details);
+  if (status != GRPC_STATUS_OK) {
+    goto cleanup;
+  }
+  /* Gets tag length.  */
+  status =
+      gsec_aead_crypter_tag_length(crypter, &impl->tag_length, error_details);
+  if (status != GRPC_STATUS_OK) {
+    goto cleanup;
+  }
+  impl->crypter = crypter;
+  impl->is_integrity_only = is_integrity_only;
+  impl->is_protect = is_protect;
+  *rp = impl;
+  return GRPC_STATUS_OK;
+cleanup:
+  alts_counter_destroy(impl->ctr);
+  gpr_free(impl);
+  return GRPC_STATUS_FAILED_PRECONDITION;
+}
+
+void alts_iovec_record_protocol_destroy(alts_iovec_record_protocol* rp) {
+  if (rp != nullptr) {
+    alts_counter_destroy(rp->ctr);
+    gsec_aead_crypter_destroy(rp->crypter);
+    gpr_free(rp);
+  }
+}
diff --git a/src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h b/src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h
new file mode 100644
index 0000000..0b7d1bf
--- /dev/null
+++ b/src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h
@@ -0,0 +1,199 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_IOVEC_RECORD_PROTOCOL_H
+#define GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_IOVEC_RECORD_PROTOCOL_H
+
+#include <grpc/support/port_platform.h>
+
+#include <stdbool.h>
+
+#include "src/core/tsi/alts/crypt/gsec.h"
+
+constexpr size_t kZeroCopyFrameMessageType = 0x06;
+constexpr size_t kZeroCopyFrameLengthFieldSize = 4;
+constexpr size_t kZeroCopyFrameMessageTypeFieldSize = 4;
+constexpr size_t kZeroCopyFrameHeaderSize =
+    kZeroCopyFrameLengthFieldSize + kZeroCopyFrameMessageTypeFieldSize;
+
+// Limit k on number of frames such that at most 2^(8 * k) frames can be sent.
+constexpr size_t kAltsRecordProtocolRekeyFrameLimit = 8;
+constexpr size_t kAltsRecordProtocolFrameLimit = 5;
+
+/* An implementation of alts record protocol. The API is thread-compatible. */
+
+typedef struct iovec iovec_t;
+
+typedef struct alts_iovec_record_protocol alts_iovec_record_protocol;
+
+/**
+ * This method gets the length of record protocol frame header.
+ */
+size_t alts_iovec_record_protocol_get_header_length();
+
+/**
+ * This method gets the length of record protocol frame tag.
+ *
+ * - rp: an alts_iovec_record_protocol instance.
+ *
+ * On success, the method returns the length of record protocol frame tag.
+ * Otherwise, it returns zero.
+ */
+size_t alts_iovec_record_protocol_get_tag_length(
+    const alts_iovec_record_protocol* rp);
+
+/**
+ * This method returns maximum allowed unprotected data size, given maximum
+ * protected frame size.
+ *
+ * - rp: an alts_iovec_record_protocol instance.
+ * - max_protected_frame_size: maximum protected frame size.
+ *
+ * On success, the method returns the maximum allowed unprotected data size.
+ * Otherwise, it returns zero.
+ */
+size_t alts_iovec_record_protocol_max_unprotected_data_size(
+    const alts_iovec_record_protocol* rp, size_t max_protected_frame_size);
+
+/**
+ * This method performs integrity-only protect operation on a
+ * alts_iovec_record_protocol instance, i.e., compute frame header and tag. The
+ * caller needs to allocate the memory for header and tag prior to calling this
+ * method.
+ *
+ * - rp: an alts_iovec_record_protocol instance.
+ * - unprotected_vec: an iovec array containing unprotected data.
+ * - unprotected_vec_length: the array length of unprotected_vec.
+ * - header: an iovec containing the output frame header.
+ * - tag: an iovec containing the output frame tag.
+ * - error_details: a buffer containing an error message if the method does not
+ *   function correctly. It is OK to pass nullptr into error_details.
+ *
+ * On success, the method returns GRPC_STATUS_OK. Otherwise, it returns an
+ * error status code along with its details specified in error_details (if
+ * error_details is not nullptr).
+ */
+grpc_status_code alts_iovec_record_protocol_integrity_only_protect(
+    alts_iovec_record_protocol* rp, const iovec_t* unprotected_vec,
+    size_t unprotected_vec_length, iovec_t header, iovec_t tag,
+    char** error_details);
+
+/**
+ * This method performs integrity-only unprotect operation on a
+ * alts_iovec_record_protocol instance, i.e., verify frame header and tag.
+ *
+ * - rp: an alts_iovec_record_protocol instance.
+ * - protected_vec: an iovec array containing protected data.
+ * - protected_vec_length: the array length of protected_vec.
+ * - header: an iovec containing the frame header.
+ * - tag: an iovec containing the frame tag.
+ * - error_details: a buffer containing an error message if the method does not
+ *   function correctly. It is OK to pass nullptr into error_details.
+ *
+ * On success, the method returns GRPC_STATUS_OK. Otherwise, it returns an
+ * error status code along with its details specified in error_details (if
+ * error_details is not nullptr).
+ */
+grpc_status_code alts_iovec_record_protocol_integrity_only_unprotect(
+    alts_iovec_record_protocol* rp, const iovec_t* protected_vec,
+    size_t protected_vec_length, iovec_t header, iovec_t tag,
+    char** error_details);
+
+/**
+ * This method performs privacy-integrity protect operation on a
+ * alts_iovec_record_protocol instance, i.e., compute a protected frame. The
+ * caller needs to allocate the memory for the protected frame prior to calling
+ * this method.
+ *
+ * - rp: an alts_iovec_record_protocol instance.
+ * - unprotected_vec: an iovec array containing unprotected data.
+ * - unprotected_vec_length: the array length of unprotected_vec.
+ * - protected_frame: an iovec containing the output protected frame.
+ * - error_details: a buffer containing an error message if the method does not
+ *   function correctly. It is OK to pass nullptr into error_details.
+ *
+ * On success, the method returns GRPC_STATUS_OK. Otherwise, it returns an
+ * error status code along with its details specified in error_details (if
+ * error_details is not nullptr).
+ */
+grpc_status_code alts_iovec_record_protocol_privacy_integrity_protect(
+    alts_iovec_record_protocol* rp, const iovec_t* unprotected_vec,
+    size_t unprotected_vec_length, iovec_t protected_frame,
+    char** error_details);
+
+/**
+ * This method performs privacy-integrity unprotect operation on a
+ * alts_iovec_record_protocol instance given a full protected frame, i.e.,
+ * compute the unprotected data. The caller needs to allocated the memory for
+ * the unprotected data prior to calling this method.
+ *
+ * - rp: an alts_iovec_record_protocol instance.
+ * - header: an iovec containing the frame header.
+ * - protected_vec: an iovec array containing protected data including the tag.
+ * - protected_vec_length: the array length of protected_vec.
+ * - unprotected_data: an iovec containing the output unprotected data.
+ * - error_details: a buffer containing an error message if the method does not
+ *   function correctly. It is OK to pass nullptr into error_details.
+ *
+ * On success, the method returns GRPC_STATUS_OK. Otherwise, it returns an
+ * error status code along with its details specified in error_details (if
+ * error_details is not nullptr).
+ */
+grpc_status_code alts_iovec_record_protocol_privacy_integrity_unprotect(
+    alts_iovec_record_protocol* rp, iovec_t header,
+    const iovec_t* protected_vec, size_t protected_vec_length,
+    iovec_t unprotected_data, char** error_details);
+
+/**
+ * This method creates an alts_iovec_record_protocol instance, given a
+ * gsec_aead_crypter instance, a flag indicating if the created instance will be
+ * used at the client or server side, and a flag indicating if the created
+ * instance will be used for integrity-only mode or privacy-integrity mode. The
+ * ownership of gsec_aead_crypter instance is transferred to this new object.
+ *
+ * - crypter: a gsec_aead_crypter instance used to perform AEAD decryption.
+ * - overflow_size: overflow size of counter in bytes.
+ * - is_client: a flag indicating if the alts_iovec_record_protocol instance
+ *   will be used at the client or server side.
+ * - is_integrity_only: a flag indicating if the alts_iovec_record_protocol
+ *   instance will be used for integrity-only or privacy-integrity mode.
+ * - is_protect: a flag indicating if the alts_grpc_record_protocol instance
+ *   will be used for protect or unprotect.
+ * - rp: an alts_iovec_record_protocol instance to be returned from
+ *   the method.
+ * - error_details: a buffer containing an error message if the method does not
+ *   function correctly. It is OK to pass nullptr into error_details.
+ *
+ * On success, the method returns GRPC_STATUS_OK. Otherwise, it returns an
+ * error status code along with its details specified in error_details (if
+ * error_details is not nullptr).
+ */
+grpc_status_code alts_iovec_record_protocol_create(
+    gsec_aead_crypter* crypter, size_t overflow_size, bool is_client,
+    bool is_integrity_only, bool is_protect, alts_iovec_record_protocol** rp,
+    char** error_details);
+
+/**
+ * This method destroys an alts_iovec_record_protocol instance by de-allocating
+ * all of its occupied memory. A gsec_aead_crypter instance passed in at
+ * gsec_alts_crypter instance creation time will be destroyed in this method.
+ */
+void alts_iovec_record_protocol_destroy(alts_iovec_record_protocol* rp);
+
+#endif /* GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_IOVEC_RECORD_PROTOCOL_H \
+        */
diff --git a/src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc b/src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc
new file mode 100644
index 0000000..6082137
--- /dev/null
+++ b/src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc
@@ -0,0 +1,296 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/tsi/alts/crypt/gsec.h"
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h"
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h"
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h"
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h"
+#include "src/core/tsi/transport_security_grpc.h"
+
+constexpr size_t kMinFrameLength = 1024;
+constexpr size_t kDefaultFrameLength = 16 * 1024;
+constexpr size_t kMaxFrameLength = 1024 * 1024;
+
+/**
+ * Main struct for alts_zero_copy_grpc_protector.
+ * We choose to have two alts_grpc_record_protocol objects and two sets of slice
+ * buffers: one for protect and the other for unprotect, so that protect and
+ * unprotect can be executed in parallel. Implementations of this object must be
+ * thread compatible.
+ */
+typedef struct alts_zero_copy_grpc_protector {
+  tsi_zero_copy_grpc_protector base;
+  alts_grpc_record_protocol* record_protocol;
+  alts_grpc_record_protocol* unrecord_protocol;
+  size_t max_protected_frame_size;
+  size_t max_unprotected_data_size;
+  grpc_slice_buffer unprotected_staging_sb;
+  grpc_slice_buffer protected_sb;
+  grpc_slice_buffer protected_staging_sb;
+  uint32_t parsed_frame_size;
+} alts_zero_copy_grpc_protector;
+
+/**
+ * Given a slice buffer, parses the first 4 bytes little-endian unsigned frame
+ * size and returns the total frame size including the frame field. Caller
+ * needs to make sure the input slice buffer has at least 4 bytes. Returns true
+ * on success and false on failure.
+ */
+static bool read_frame_size(const grpc_slice_buffer* sb,
+                            uint32_t* total_frame_size) {
+  if (sb == nullptr || sb->length < kZeroCopyFrameLengthFieldSize) {
+    return false;
+  }
+  uint8_t frame_size_buffer[kZeroCopyFrameLengthFieldSize];
+  uint8_t* buf = frame_size_buffer;
+  /* Copies the first 4 bytes to a temporary buffer.  */
+  size_t remaining = kZeroCopyFrameLengthFieldSize;
+  for (size_t i = 0; i < sb->count; i++) {
+    size_t slice_length = GRPC_SLICE_LENGTH(sb->slices[i]);
+    if (remaining <= slice_length) {
+      memcpy(buf, GRPC_SLICE_START_PTR(sb->slices[i]), remaining);
+      remaining = 0;
+      break;
+    } else {
+      memcpy(buf, GRPC_SLICE_START_PTR(sb->slices[i]), slice_length);
+      buf += slice_length;
+      remaining -= slice_length;
+    }
+  }
+  GPR_ASSERT(remaining == 0);
+  /* Gets little-endian frame size.  */
+  uint32_t frame_size = (((uint32_t)frame_size_buffer[3]) << 24) |
+                        (((uint32_t)frame_size_buffer[2]) << 16) |
+                        (((uint32_t)frame_size_buffer[1]) << 8) |
+                        ((uint32_t)frame_size_buffer[0]);
+  if (frame_size > kMaxFrameLength) {
+    gpr_log(GPR_ERROR, "Frame size is larger than maximum frame size");
+    return false;
+  }
+  /* Returns frame size including frame length field.  */
+  *total_frame_size =
+      static_cast<uint32_t>(frame_size + kZeroCopyFrameLengthFieldSize);
+  return true;
+}
+
+/**
+ * Creates an alts_grpc_record_protocol object, given key, key size, and flags
+ * to indicate whether the record_protocol object uses the rekeying AEAD,
+ * whether the object is for client or server, whether the object is for
+ * integrity-only or privacy-integrity mode, and whether the object is is used
+ * for protect or unprotect.
+ */
+static tsi_result create_alts_grpc_record_protocol(
+    const uint8_t* key, size_t key_size, bool is_rekey, bool is_client,
+    bool is_integrity_only, bool is_protect,
+    alts_grpc_record_protocol** record_protocol) {
+  if (key == nullptr || record_protocol == nullptr) {
+    return TSI_INVALID_ARGUMENT;
+  }
+  grpc_status_code status;
+  gsec_aead_crypter* crypter = nullptr;
+  char* error_details = nullptr;
+  status = gsec_aes_gcm_aead_crypter_create(key, key_size, kAesGcmNonceLength,
+                                            kAesGcmTagLength, is_rekey,
+                                            &crypter, &error_details);
+  if (status != GRPC_STATUS_OK) {
+    gpr_log(GPR_ERROR, "Failed to create AEAD crypter, %s", error_details);
+    gpr_free(error_details);
+    return TSI_INTERNAL_ERROR;
+  }
+  size_t overflow_limit = is_rekey ? kAltsRecordProtocolRekeyFrameLimit
+                                   : kAltsRecordProtocolFrameLimit;
+  /* Creates alts_grpc_record_protocol with AEAD crypter ownership transferred.
+   */
+  tsi_result result =
+      is_integrity_only
+          ? alts_grpc_integrity_only_record_protocol_create(
+                crypter, overflow_limit, is_client, is_protect, record_protocol)
+          : alts_grpc_privacy_integrity_record_protocol_create(
+                crypter, overflow_limit, is_client, is_protect,
+                record_protocol);
+  if (result != TSI_OK) {
+    gsec_aead_crypter_destroy(crypter);
+    return result;
+  }
+  return TSI_OK;
+}
+
+/* --- tsi_zero_copy_grpc_protector methods implementation. --- */
+
+static tsi_result alts_zero_copy_grpc_protector_protect(
+    tsi_zero_copy_grpc_protector* self, grpc_slice_buffer* unprotected_slices,
+    grpc_slice_buffer* protected_slices) {
+  if (self == nullptr || unprotected_slices == nullptr ||
+      protected_slices == nullptr) {
+    gpr_log(GPR_ERROR, "Invalid nullptr arguments to zero-copy grpc protect.");
+    return TSI_INVALID_ARGUMENT;
+  }
+  alts_zero_copy_grpc_protector* protector =
+      reinterpret_cast<alts_zero_copy_grpc_protector*>(self);
+  /* Calls alts_grpc_record_protocol protect repeatly.  */
+  while (unprotected_slices->length > protector->max_unprotected_data_size) {
+    grpc_slice_buffer_move_first(unprotected_slices,
+                                 protector->max_unprotected_data_size,
+                                 &protector->unprotected_staging_sb);
+    tsi_result status = alts_grpc_record_protocol_protect(
+        protector->record_protocol, &protector->unprotected_staging_sb,
+        protected_slices);
+    if (status != TSI_OK) {
+      return status;
+    }
+  }
+  return alts_grpc_record_protocol_protect(
+      protector->record_protocol, unprotected_slices, protected_slices);
+}
+
+static tsi_result alts_zero_copy_grpc_protector_unprotect(
+    tsi_zero_copy_grpc_protector* self, grpc_slice_buffer* protected_slices,
+    grpc_slice_buffer* unprotected_slices) {
+  if (self == nullptr || unprotected_slices == nullptr ||
+      protected_slices == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to zero-copy grpc unprotect.");
+    return TSI_INVALID_ARGUMENT;
+  }
+  alts_zero_copy_grpc_protector* protector =
+      reinterpret_cast<alts_zero_copy_grpc_protector*>(self);
+  grpc_slice_buffer_move_into(protected_slices, &protector->protected_sb);
+  /* Keep unprotecting each frame if possible.  */
+  while (protector->protected_sb.length >= kZeroCopyFrameLengthFieldSize) {
+    if (protector->parsed_frame_size == 0) {
+      /* We have not parsed frame size yet. Parses frame size.  */
+      if (!read_frame_size(&protector->protected_sb,
+                           &protector->parsed_frame_size)) {
+        grpc_slice_buffer_reset_and_unref_internal(&protector->protected_sb);
+        return TSI_DATA_CORRUPTED;
+      }
+    }
+    if (protector->protected_sb.length < protector->parsed_frame_size) break;
+    /* At this point, protected_sb contains at least one frame of data.  */
+    tsi_result status;
+    if (protector->protected_sb.length == protector->parsed_frame_size) {
+      status = alts_grpc_record_protocol_unprotect(protector->unrecord_protocol,
+                                                   &protector->protected_sb,
+                                                   unprotected_slices);
+    } else {
+      grpc_slice_buffer_move_first(&protector->protected_sb,
+                                   protector->parsed_frame_size,
+                                   &protector->protected_staging_sb);
+      status = alts_grpc_record_protocol_unprotect(
+          protector->unrecord_protocol, &protector->protected_staging_sb,
+          unprotected_slices);
+    }
+    protector->parsed_frame_size = 0;
+    if (status != TSI_OK) {
+      grpc_slice_buffer_reset_and_unref_internal(&protector->protected_sb);
+      return status;
+    }
+  }
+  return TSI_OK;
+}
+
+static void alts_zero_copy_grpc_protector_destroy(
+    tsi_zero_copy_grpc_protector* self) {
+  if (self == nullptr) {
+    return;
+  }
+  alts_zero_copy_grpc_protector* protector =
+      reinterpret_cast<alts_zero_copy_grpc_protector*>(self);
+  alts_grpc_record_protocol_destroy(protector->record_protocol);
+  alts_grpc_record_protocol_destroy(protector->unrecord_protocol);
+  grpc_slice_buffer_destroy_internal(&protector->unprotected_staging_sb);
+  grpc_slice_buffer_destroy_internal(&protector->protected_sb);
+  grpc_slice_buffer_destroy_internal(&protector->protected_staging_sb);
+  gpr_free(protector);
+}
+
+static const tsi_zero_copy_grpc_protector_vtable
+    alts_zero_copy_grpc_protector_vtable = {
+        alts_zero_copy_grpc_protector_protect,
+        alts_zero_copy_grpc_protector_unprotect,
+        alts_zero_copy_grpc_protector_destroy};
+
+tsi_result alts_zero_copy_grpc_protector_create(
+    const uint8_t* key, size_t key_size, bool is_rekey, bool is_client,
+    bool is_integrity_only, size_t* max_protected_frame_size,
+    tsi_zero_copy_grpc_protector** protector) {
+  if (grpc_core::ExecCtx::Get() == nullptr || key == nullptr ||
+      protector == nullptr) {
+    gpr_log(
+        GPR_ERROR,
+        "Invalid nullptr arguments to alts_zero_copy_grpc_protector create.");
+    return TSI_INVALID_ARGUMENT;
+  }
+  /* Creates alts_zero_copy_protector.  */
+  alts_zero_copy_grpc_protector* impl =
+      static_cast<alts_zero_copy_grpc_protector*>(
+          gpr_zalloc(sizeof(alts_zero_copy_grpc_protector)));
+  /* Creates alts_grpc_record_protocol objects.  */
+  tsi_result status = create_alts_grpc_record_protocol(
+      key, key_size, is_rekey, is_client, is_integrity_only,
+      /*is_protect=*/true, &impl->record_protocol);
+  if (status == TSI_OK) {
+    status = create_alts_grpc_record_protocol(
+        key, key_size, is_rekey, is_client, is_integrity_only,
+        /*is_protect=*/false, &impl->unrecord_protocol);
+    if (status == TSI_OK) {
+      /* Sets maximum frame size.  */
+      size_t max_protected_frame_size_to_set = kDefaultFrameLength;
+      if (max_protected_frame_size != nullptr) {
+        *max_protected_frame_size =
+            GPR_MIN(*max_protected_frame_size, kMaxFrameLength);
+        *max_protected_frame_size =
+            GPR_MAX(*max_protected_frame_size, kMinFrameLength);
+        max_protected_frame_size_to_set = *max_protected_frame_size;
+      }
+      impl->max_protected_frame_size = max_protected_frame_size_to_set;
+      impl->max_unprotected_data_size =
+          alts_grpc_record_protocol_max_unprotected_data_size(
+              impl->record_protocol, max_protected_frame_size_to_set);
+      GPR_ASSERT(impl->max_unprotected_data_size > 0);
+      /* Allocates internal slice buffers.  */
+      grpc_slice_buffer_init(&impl->unprotected_staging_sb);
+      grpc_slice_buffer_init(&impl->protected_sb);
+      grpc_slice_buffer_init(&impl->protected_staging_sb);
+      impl->parsed_frame_size = 0;
+      impl->base.vtable = &alts_zero_copy_grpc_protector_vtable;
+      *protector = &impl->base;
+      return TSI_OK;
+    }
+  }
+
+  /* Cleanup if create failed.  */
+  alts_grpc_record_protocol_destroy(impl->record_protocol);
+  alts_grpc_record_protocol_destroy(impl->unrecord_protocol);
+  gpr_free(impl);
+  return TSI_INTERNAL_ERROR;
+}
diff --git a/src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h b/src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h
new file mode 100644
index 0000000..71e953c
--- /dev/null
+++ b/src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_ZERO_COPY_GRPC_PROTECTOR_H
+#define GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_ZERO_COPY_GRPC_PROTECTOR_H
+
+#include <grpc/support/port_platform.h>
+
+#include <stdbool.h>
+
+#include "src/core/tsi/transport_security_grpc.h"
+
+/**
+ * This method creates an ALTS zero-copy grpc protector.
+ *
+ * - key: a symmetric key used to seal/unseal frames.
+ * - key_size: the size of symmetric key.
+ * - is_rekey: use rekeying AEAD crypter.
+ * - is_client: a flag indicating if the protector will be used at client or
+ *   server side.
+ * - is_integrity_only: a flag indicating if the protector instance will be
+ *   used for integrity-only or privacy-integrity mode.
+ * - max_protected_frame_size: an in/out parameter indicating max frame size
+ *   to be used by the protector. If it is nullptr, the default frame size will
+ *   be used. Otherwise, the provided frame size will be adjusted (if not
+ *   falling into a valid frame range) and used.
+ * - protector: a pointer to the zero-copy protector returned from the method.
+ *
+ * This method returns TSI_OK on success or a specific error code otherwise.
+ */
+tsi_result alts_zero_copy_grpc_protector_create(
+    const uint8_t* key, size_t key_size, bool is_rekey, bool is_client,
+    bool is_integrity_only, size_t* max_protected_frame_size,
+    tsi_zero_copy_grpc_protector** protector);
+
+#endif /* GRPC_CORE_TSI_ALTS_ZERO_COPY_FRAME_PROTECTOR_ALTS_ZERO_COPY_GRPC_PROTECTOR_H \
+        */
diff --git a/src/core/tsi/alts_transport_security.cc b/src/core/tsi/alts_transport_security.cc
index ddd75cb..2fd4081 100644
--- a/src/core/tsi/alts_transport_security.cc
+++ b/src/core/tsi/alts_transport_security.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/tsi/alts_transport_security.h"
 
 #include <string.h>
@@ -26,17 +28,36 @@
   return &g_alts_resource;
 }
 
+static void grpc_tsi_alts_wait_for_cq_drain() {
+  gpr_mu_lock(&g_alts_resource.mu);
+  while (!g_alts_resource.is_cq_drained) {
+    gpr_cv_wait(&g_alts_resource.cv, &g_alts_resource.mu,
+                gpr_inf_future(GPR_CLOCK_REALTIME));
+  }
+  gpr_mu_unlock(&g_alts_resource.mu);
+}
+
+void grpc_tsi_alts_signal_for_cq_destroy() {
+  gpr_mu_lock(&g_alts_resource.mu);
+  g_alts_resource.is_cq_drained = true;
+  gpr_cv_signal(&g_alts_resource.cv);
+  gpr_mu_unlock(&g_alts_resource.mu);
+}
+
 void grpc_tsi_alts_init() {
   memset(&g_alts_resource, 0, sizeof(alts_shared_resource));
   gpr_mu_init(&g_alts_resource.mu);
+  gpr_cv_init(&g_alts_resource.cv);
 }
 
 void grpc_tsi_alts_shutdown() {
-  gpr_mu_destroy(&g_alts_resource.mu);
-  if (g_alts_resource.cq == nullptr) {
-    return;
+  if (g_alts_resource.cq != nullptr) {
+    grpc_completion_queue_shutdown(g_alts_resource.cq);
+    grpc_tsi_alts_wait_for_cq_drain();
+    grpc_completion_queue_destroy(g_alts_resource.cq);
+    grpc_channel_destroy(g_alts_resource.channel);
+    g_alts_resource.thread.Join();
   }
-  grpc_completion_queue_destroy(g_alts_resource.cq);
-  grpc_channel_destroy(g_alts_resource.channel);
-  gpr_thd_join(g_alts_resource.thread_id);
+  gpr_cv_destroy(&g_alts_resource.cv);
+  gpr_mu_destroy(&g_alts_resource.mu);
 }
diff --git a/src/core/tsi/alts_transport_security.h b/src/core/tsi/alts_transport_security.h
index c90e314..d6b8e11 100644
--- a/src/core/tsi/alts_transport_security.h
+++ b/src/core/tsi/alts_transport_security.h
@@ -19,19 +19,29 @@
 #ifndef GRPC_CORE_TSI_ALTS_TRANSPORT_SECURITY_H
 #define GRPC_CORE_TSI_ALTS_TRANSPORT_SECURITY_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/grpc.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
+
+#include "src/core/lib/gprpp/thd.h"
 
 typedef struct alts_shared_resource {
-  gpr_thd_id thread_id;
+  grpc_core::Thread thread;
   grpc_channel* channel;
   grpc_completion_queue* cq;
   gpr_mu mu;
+  gpr_cv cv;
+  bool is_cq_drained;
 } alts_shared_resource;
 
 /* This method returns the address of alts_shared_resource object shared by all
  *    TSI handshakes. */
 alts_shared_resource* alts_get_shared_resource(void);
 
+/* This method signals the thread that invokes grpc_tsi_alts_shutdown() to
+ * continue with destroying the cq as a part of shutdown process. */
+
+void grpc_tsi_alts_signal_for_cq_destroy(void);
+
 #endif /* GRPC_CORE_TSI_ALTS_TRANSPORT_SECURITY_H */
diff --git a/src/core/tsi/fake_transport_security.cc b/src/core/tsi/fake_transport_security.cc
index b907636..ad08b50 100644
--- a/src/core/tsi/fake_transport_security.cc
+++ b/src/core/tsi/fake_transport_security.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/tsi/fake_transport_security.h"
 
 #include <stdlib.h>
@@ -23,8 +25,8 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/tsi/transport_security_grpc.h"
 
@@ -101,7 +103,7 @@
   for (int i = 0; i < TSI_FAKE_HANDSHAKE_MESSAGE_MAX; i++) {
     if (strncmp(msg_string, tsi_fake_handshake_message_strings[i],
                 strlen(tsi_fake_handshake_message_strings[i])) == 0) {
-      *msg = (tsi_fake_handshake_message)i;
+      *msg = static_cast<tsi_fake_handshake_message>(i);
       return TSI_OK;
     }
   }
@@ -110,15 +112,16 @@
 }
 
 static uint32_t load32_little_endian(const unsigned char* buf) {
-  return ((uint32_t)(buf[0]) | (uint32_t)(buf[1] << 8) |
-          (uint32_t)(buf[2] << 16) | (uint32_t)(buf[3] << 24));
+  return (static_cast<uint32_t>(buf[0]) | static_cast<uint32_t>(buf[1] << 8) |
+          static_cast<uint32_t>(buf[2] << 16) |
+          static_cast<uint32_t>(buf[3] << 24));
 }
 
 static void store32_little_endian(uint32_t value, unsigned char* buf) {
-  buf[3] = (unsigned char)((value >> 24) & 0xFF);
-  buf[2] = (unsigned char)((value >> 16) & 0xFF);
-  buf[1] = (unsigned char)((value >> 8) & 0xFF);
-  buf[0] = (unsigned char)((value)&0xFF);
+  buf[3] = static_cast<unsigned char>((value >> 24) & 0xFF);
+  buf[2] = static_cast<unsigned char>((value >> 16) & 0xFF);
+  buf[1] = static_cast<unsigned char>((value >> 8) & 0xFF);
+  buf[0] = static_cast<unsigned char>((value)&0xFF);
 }
 
 static uint32_t read_frame_size(const grpc_slice_buffer* sb) {
@@ -154,10 +157,11 @@
 static void tsi_fake_frame_ensure_size(tsi_fake_frame* frame) {
   if (frame->data == nullptr) {
     frame->allocated_size = frame->size;
-    frame->data = (unsigned char*)gpr_malloc(frame->allocated_size);
+    frame->data =
+        static_cast<unsigned char*>(gpr_malloc(frame->allocated_size));
   } else if (frame->size > frame->allocated_size) {
     unsigned char* new_data =
-        (unsigned char*)gpr_realloc(frame->data, frame->size);
+        static_cast<unsigned char*>(gpr_realloc(frame->data, frame->size));
     frame->data = new_data;
     frame->allocated_size = frame->size;
   }
@@ -176,7 +180,8 @@
   if (frame->needs_draining) return TSI_INTERNAL_ERROR;
   if (frame->data == nullptr) {
     frame->allocated_size = TSI_FAKE_FRAME_INITIAL_ALLOCATED_SIZE;
-    frame->data = (unsigned char*)gpr_malloc(frame->allocated_size);
+    frame->data =
+        static_cast<unsigned char*>(gpr_malloc(frame->allocated_size));
   }
 
   if (frame->offset < TSI_FAKE_FRAME_HEADER_SIZE) {
@@ -186,7 +191,7 @@
       memcpy(frame->data + frame->offset, bytes_cursor, available_size);
       bytes_cursor += available_size;
       frame->offset += available_size;
-      *incoming_bytes_size = (size_t)(bytes_cursor - incoming_bytes);
+      *incoming_bytes_size = static_cast<size_t>(bytes_cursor - incoming_bytes);
       return TSI_INCOMPLETE_DATA;
     }
     memcpy(frame->data + frame->offset, bytes_cursor, to_read_size);
@@ -202,12 +207,12 @@
     memcpy(frame->data + frame->offset, bytes_cursor, available_size);
     frame->offset += available_size;
     bytes_cursor += available_size;
-    *incoming_bytes_size = (size_t)(bytes_cursor - incoming_bytes);
+    *incoming_bytes_size = static_cast<size_t>(bytes_cursor - incoming_bytes);
     return TSI_INCOMPLETE_DATA;
   }
   memcpy(frame->data + frame->offset, bytes_cursor, to_read_size);
   bytes_cursor += to_read_size;
-  *incoming_bytes_size = (size_t)(bytes_cursor - incoming_bytes);
+  *incoming_bytes_size = static_cast<size_t>(bytes_cursor - incoming_bytes);
   tsi_fake_frame_reset(frame, 1 /* needs_draining */);
   return TSI_OK;
 }
@@ -238,7 +243,7 @@
   frame->offset = 0;
   frame->size = data_size + TSI_FAKE_FRAME_HEADER_SIZE;
   tsi_fake_frame_ensure_size(frame);
-  store32_little_endian((uint32_t)frame->size, frame->data);
+  store32_little_endian(static_cast<uint32_t>(frame->size), frame->data);
   memcpy(frame->data + TSI_FAKE_FRAME_HEADER_SIZE, data, data_size);
   tsi_fake_frame_reset(frame, 1 /* needs draining */);
   return TSI_OK;
@@ -257,7 +262,8 @@
                                          unsigned char* protected_output_frames,
                                          size_t* protected_output_frames_size) {
   tsi_result result = TSI_OK;
-  tsi_fake_frame_protector* impl = (tsi_fake_frame_protector*)self;
+  tsi_fake_frame_protector* impl =
+      reinterpret_cast<tsi_fake_frame_protector*>(self);
   unsigned char frame_header[TSI_FAKE_FRAME_HEADER_SIZE];
   tsi_fake_frame* frame = &impl->protect_frame;
   size_t saved_output_size = *protected_output_frames_size;
@@ -286,7 +292,8 @@
   if (frame->size == 0) {
     /* New frame, create a header. */
     size_t written_in_frame_size = 0;
-    store32_little_endian((uint32_t)impl->max_frame_size, frame_header);
+    store32_little_endian(static_cast<uint32_t>(impl->max_frame_size),
+                          frame_header);
     written_in_frame_size = TSI_FAKE_FRAME_HEADER_SIZE;
     result = tsi_fake_frame_decode(frame_header, &written_in_frame_size, frame);
     if (result != TSI_INCOMPLETE_DATA) {
@@ -316,14 +323,15 @@
     tsi_frame_protector* self, unsigned char* protected_output_frames,
     size_t* protected_output_frames_size, size_t* still_pending_size) {
   tsi_result result = TSI_OK;
-  tsi_fake_frame_protector* impl = (tsi_fake_frame_protector*)self;
+  tsi_fake_frame_protector* impl =
+      reinterpret_cast<tsi_fake_frame_protector*>(self);
   tsi_fake_frame* frame = &impl->protect_frame;
   if (!frame->needs_draining) {
     /* Create a short frame. */
     frame->size = frame->offset;
     frame->offset = 0;
     frame->needs_draining = 1;
-    store32_little_endian((uint32_t)frame->size,
+    store32_little_endian(static_cast<uint32_t>(frame->size),
                           frame->data); /* Overwrite header. */
   }
   result = tsi_fake_frame_encode(protected_output_frames,
@@ -338,7 +346,8 @@
     size_t* protected_frames_bytes_size, unsigned char* unprotected_bytes,
     size_t* unprotected_bytes_size) {
   tsi_result result = TSI_OK;
-  tsi_fake_frame_protector* impl = (tsi_fake_frame_protector*)self;
+  tsi_fake_frame_protector* impl =
+      reinterpret_cast<tsi_fake_frame_protector*>(self);
   tsi_fake_frame* frame = &impl->unprotect_frame;
   size_t saved_output_size = *unprotected_bytes_size;
   size_t drained_size = 0;
@@ -383,7 +392,8 @@
 }
 
 static void fake_protector_destroy(tsi_frame_protector* self) {
-  tsi_fake_frame_protector* impl = (tsi_fake_frame_protector*)self;
+  tsi_fake_frame_protector* impl =
+      reinterpret_cast<tsi_fake_frame_protector*>(self);
   tsi_fake_frame_destruct(&impl->protect_frame);
   tsi_fake_frame_destruct(&impl->unprotect_frame);
   gpr_free(self);
@@ -406,14 +416,15 @@
     return TSI_INVALID_ARGUMENT;
   }
   tsi_fake_zero_copy_grpc_protector* impl =
-      (tsi_fake_zero_copy_grpc_protector*)self;
+      reinterpret_cast<tsi_fake_zero_copy_grpc_protector*>(self);
   /* Protects each frame. */
   while (unprotected_slices->length > 0) {
     size_t frame_length =
         GPR_MIN(impl->max_frame_size,
                 unprotected_slices->length + TSI_FAKE_FRAME_HEADER_SIZE);
     grpc_slice slice = GRPC_SLICE_MALLOC(TSI_FAKE_FRAME_HEADER_SIZE);
-    store32_little_endian((uint32_t)frame_length, GRPC_SLICE_START_PTR(slice));
+    store32_little_endian(static_cast<uint32_t>(frame_length),
+                          GRPC_SLICE_START_PTR(slice));
     grpc_slice_buffer_add(protected_slices, slice);
     size_t data_length = frame_length - TSI_FAKE_FRAME_HEADER_SIZE;
     grpc_slice_buffer_move_first(unprotected_slices, data_length,
@@ -430,7 +441,7 @@
     return TSI_INVALID_ARGUMENT;
   }
   tsi_fake_zero_copy_grpc_protector* impl =
-      (tsi_fake_zero_copy_grpc_protector*)self;
+      reinterpret_cast<tsi_fake_zero_copy_grpc_protector*>(self);
   grpc_slice_buffer_move_into(protected_slices, &impl->protected_sb);
   /* Unprotect each frame, if we get a full frame. */
   while (impl->protected_sb.length >= TSI_FAKE_FRAME_HEADER_SIZE) {
@@ -461,7 +472,7 @@
     tsi_zero_copy_grpc_protector* self) {
   if (self == nullptr) return;
   tsi_fake_zero_copy_grpc_protector* impl =
-      (tsi_fake_zero_copy_grpc_protector*)self;
+      reinterpret_cast<tsi_fake_zero_copy_grpc_protector*>(self);
   grpc_slice_buffer_destroy_internal(&impl->header_sb);
   grpc_slice_buffer_destroy_internal(&impl->protected_sb);
   gpr_free(impl);
@@ -519,7 +530,8 @@
 }
 
 static void fake_handshaker_result_destroy(tsi_handshaker_result* self) {
-  fake_handshaker_result* result = (fake_handshaker_result*)self;
+  fake_handshaker_result* result =
+      reinterpret_cast<fake_handshaker_result*>(self);
   gpr_free(result->unused_bytes);
   gpr_free(self);
 }
@@ -540,10 +552,11 @@
     return TSI_INVALID_ARGUMENT;
   }
   fake_handshaker_result* result =
-      (fake_handshaker_result*)gpr_zalloc(sizeof(*result));
+      static_cast<fake_handshaker_result*>(gpr_zalloc(sizeof(*result)));
   result->base.vtable = &handshaker_result_vtable;
   if (unused_bytes_size > 0) {
-    result->unused_bytes = (unsigned char*)gpr_malloc(unused_bytes_size);
+    result->unused_bytes =
+        static_cast<unsigned char*>(gpr_malloc(unused_bytes_size));
     memcpy(result->unused_bytes, unused_bytes, unused_bytes_size);
   }
   result->unused_bytes_size = unused_bytes_size;
@@ -555,7 +568,7 @@
 
 static tsi_result fake_handshaker_get_bytes_to_send_to_peer(
     tsi_handshaker* self, unsigned char* bytes, size_t* bytes_size) {
-  tsi_fake_handshaker* impl = (tsi_fake_handshaker*)self;
+  tsi_fake_handshaker* impl = reinterpret_cast<tsi_fake_handshaker*>(self);
   tsi_result result = TSI_OK;
   if (impl->needs_incoming_message || impl->result == TSI_OK) {
     *bytes_size = 0;
@@ -563,7 +576,7 @@
   }
   if (!impl->outgoing_frame.needs_draining) {
     tsi_fake_handshake_message next_message_to_send =
-        (tsi_fake_handshake_message)(impl->next_message_to_send + 2);
+        static_cast<tsi_fake_handshake_message>(impl->next_message_to_send + 2);
     const char* msg_string =
         tsi_fake_handshake_message_to_string(impl->next_message_to_send);
     result = tsi_fake_frame_set_data((unsigned char*)msg_string,
@@ -597,9 +610,9 @@
 static tsi_result fake_handshaker_process_bytes_from_peer(
     tsi_handshaker* self, const unsigned char* bytes, size_t* bytes_size) {
   tsi_result result = TSI_OK;
-  tsi_fake_handshaker* impl = (tsi_fake_handshaker*)self;
+  tsi_fake_handshaker* impl = reinterpret_cast<tsi_fake_handshaker*>(self);
   tsi_fake_handshake_message expected_msg =
-      (tsi_fake_handshake_message)(impl->next_message_to_send - 1);
+      static_cast<tsi_fake_handshake_message>(impl->next_message_to_send - 1);
   tsi_fake_handshake_message received_msg;
 
   if (!impl->needs_incoming_message || impl->result == TSI_OK) {
@@ -611,7 +624,8 @@
 
   /* We now have a complete frame. */
   result = tsi_fake_handshake_message_from_string(
-      (const char*)impl->incoming_frame.data + TSI_FAKE_FRAME_HEADER_SIZE,
+      reinterpret_cast<const char*>(impl->incoming_frame.data) +
+          TSI_FAKE_FRAME_HEADER_SIZE,
       &received_msg);
   if (result != TSI_OK) {
     impl->result = result;
@@ -639,12 +653,12 @@
 }
 
 static tsi_result fake_handshaker_get_result(tsi_handshaker* self) {
-  tsi_fake_handshaker* impl = (tsi_fake_handshaker*)self;
+  tsi_fake_handshaker* impl = reinterpret_cast<tsi_fake_handshaker*>(self);
   return impl->result;
 }
 
 static void fake_handshaker_destroy(tsi_handshaker* self) {
-  tsi_fake_handshaker* impl = (tsi_fake_handshaker*)self;
+  tsi_fake_handshaker* impl = reinterpret_cast<tsi_fake_handshaker*>(self);
   tsi_fake_frame_destruct(&impl->incoming_frame);
   tsi_fake_frame_destruct(&impl->outgoing_frame);
   gpr_free(impl->outgoing_bytes_buffer);
@@ -662,7 +676,8 @@
       handshaker_result == nullptr) {
     return TSI_INVALID_ARGUMENT;
   }
-  tsi_fake_handshaker* handshaker = (tsi_fake_handshaker*)self;
+  tsi_fake_handshaker* handshaker =
+      reinterpret_cast<tsi_fake_handshaker*>(self);
   tsi_result result = TSI_OK;
 
   /* Decode and process a handshake frame from the peer. */
@@ -683,9 +698,9 @@
     offset += sent_bytes_size;
     if (result == TSI_INCOMPLETE_DATA) {
       handshaker->outgoing_bytes_buffer_size *= 2;
-      handshaker->outgoing_bytes_buffer =
-          (unsigned char*)gpr_realloc(handshaker->outgoing_bytes_buffer,
-                                      handshaker->outgoing_bytes_buffer_size);
+      handshaker->outgoing_bytes_buffer = static_cast<unsigned char*>(
+          gpr_realloc(handshaker->outgoing_bytes_buffer,
+                      handshaker->outgoing_bytes_buffer_size));
     }
   } while (result == TSI_INCOMPLETE_DATA);
   if (result != TSI_OK) return result;
@@ -726,14 +741,15 @@
 };
 
 tsi_handshaker* tsi_create_fake_handshaker(int is_client) {
-  tsi_fake_handshaker* impl = (tsi_fake_handshaker*)gpr_zalloc(sizeof(*impl));
+  tsi_fake_handshaker* impl =
+      static_cast<tsi_fake_handshaker*>(gpr_zalloc(sizeof(*impl)));
   impl->base.vtable = &handshaker_vtable;
   impl->is_client = is_client;
   impl->result = TSI_HANDSHAKE_IN_PROGRESS;
   impl->outgoing_bytes_buffer_size =
       TSI_FAKE_HANDSHAKER_OUTGOING_BUFFER_INITIAL_SIZE;
   impl->outgoing_bytes_buffer =
-      (unsigned char*)gpr_malloc(impl->outgoing_bytes_buffer_size);
+      static_cast<unsigned char*>(gpr_malloc(impl->outgoing_bytes_buffer_size));
   if (is_client) {
     impl->needs_incoming_message = 0;
     impl->next_message_to_send = TSI_FAKE_CLIENT_INIT;
@@ -747,7 +763,7 @@
 tsi_frame_protector* tsi_create_fake_frame_protector(
     size_t* max_protected_frame_size) {
   tsi_fake_frame_protector* impl =
-      (tsi_fake_frame_protector*)gpr_zalloc(sizeof(*impl));
+      static_cast<tsi_fake_frame_protector*>(gpr_zalloc(sizeof(*impl)));
   impl->max_frame_size = (max_protected_frame_size == nullptr)
                              ? TSI_FAKE_DEFAULT_FRAME_SIZE
                              : *max_protected_frame_size;
@@ -758,7 +774,8 @@
 tsi_zero_copy_grpc_protector* tsi_create_fake_zero_copy_grpc_protector(
     size_t* max_protected_frame_size) {
   tsi_fake_zero_copy_grpc_protector* impl =
-      (tsi_fake_zero_copy_grpc_protector*)gpr_zalloc(sizeof(*impl));
+      static_cast<tsi_fake_zero_copy_grpc_protector*>(
+          gpr_zalloc(sizeof(*impl)));
   grpc_slice_buffer_init(&impl->header_sb);
   grpc_slice_buffer_init(&impl->protected_sb);
   impl->max_frame_size = (max_protected_frame_size == nullptr)
diff --git a/src/core/tsi/fake_transport_security.h b/src/core/tsi/fake_transport_security.h
index 3848e7c..3779182 100644
--- a/src/core/tsi/fake_transport_security.h
+++ b/src/core/tsi/fake_transport_security.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_TSI_FAKE_TRANSPORT_SECURITY_H
 #define GRPC_CORE_TSI_FAKE_TRANSPORT_SECURITY_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/tsi/transport_security_interface.h"
 
 /* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for FAKE certs. */
diff --git a/src/core/tsi/ssl/session_cache/ssl_session.h b/src/core/tsi/ssl/session_cache/ssl_session.h
new file mode 100644
index 0000000..115221e
--- /dev/null
+++ b/src/core/tsi/ssl/session_cache/ssl_session.h
@@ -0,0 +1,73 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_SSL_SESSION_CACHE_SSL_SESSION_H
+#define GRPC_CORE_TSI_SSL_SESSION_CACHE_SSL_SESSION_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/slice.h>
+
+extern "C" {
+#include <openssl/ssl.h>
+}
+
+#include "src/core/lib/gprpp/ref_counted.h"
+
+// The main purpose of code here is to provide means to cache SSL sessions
+// in a way that they can be shared between connections.
+//
+// SSL_SESSION stands for single instance of session and is not generally safe
+// to share between SSL contexts with different lifetimes. It happens because
+// not all SSL implementations guarantee immutability of SSL_SESSION object.
+// See SSL_SESSION documentation in BoringSSL and OpenSSL for more details.
+
+namespace tsi {
+
+struct SslSessionDeleter {
+  void operator()(SSL_SESSION* session) { SSL_SESSION_free(session); }
+};
+
+typedef std::unique_ptr<SSL_SESSION, SslSessionDeleter> SslSessionPtr;
+
+/// SslCachedSession is an immutable thread-safe storage for single session
+/// representation. It provides means to share SSL session data (e.g. TLS
+/// ticket) between encrypted connections regardless of SSL context lifetime.
+class SslCachedSession {
+ public:
+  // Not copyable nor movable.
+  SslCachedSession(const SslCachedSession&) = delete;
+  SslCachedSession& operator=(const SslCachedSession&) = delete;
+
+  /// Create single cached instance of \a session.
+  static grpc_core::UniquePtr<SslCachedSession> Create(SslSessionPtr session);
+
+  virtual ~SslCachedSession() = default;
+
+  /// Returns a copy of previously cached session.
+  virtual SslSessionPtr CopySession() const GRPC_ABSTRACT;
+
+  GRPC_ABSTRACT_BASE_CLASS
+
+ protected:
+  SslCachedSession() = default;
+};
+
+}  // namespace tsi
+
+#endif /* GRPC_CORE_TSI_SSL_SESSION_CACHE_SSL_SESSION_H */
diff --git a/src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc b/src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc
new file mode 100644
index 0000000..0da5a96
--- /dev/null
+++ b/src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc
@@ -0,0 +1,58 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/ssl/session_cache/ssl_session.h"
+
+#ifdef OPENSSL_IS_BORINGSSL
+
+// BoringSSL allows SSL_SESSION to outlive SSL and SSL_CTX objects which are
+// re-created by gRPC on every certificate rotation or subchannel creation.
+// BoringSSL guarantees that SSL_SESSION is immutable so it's safe to share
+// the same original session object between different threads and connections.
+
+namespace tsi {
+namespace {
+
+class BoringSslCachedSession : public SslCachedSession {
+ public:
+  BoringSslCachedSession(SslSessionPtr session)
+      : session_(std::move(session)) {}
+
+  SslSessionPtr CopySession() const override {
+    // SslSessionPtr will dereference on destruction.
+    SSL_SESSION_up_ref(session_.get());
+    return SslSessionPtr(session_.get());
+  }
+
+ private:
+  SslSessionPtr session_;
+};
+
+}  // namespace
+
+grpc_core::UniquePtr<SslCachedSession> SslCachedSession::Create(
+    SslSessionPtr session) {
+  return grpc_core::UniquePtr<SslCachedSession>(
+      grpc_core::New<BoringSslCachedSession>(std::move(session)));
+}
+
+}  // namespace tsi
+
+#endif /* OPENSSL_IS_BORINGSSL */
diff --git a/src/core/tsi/ssl/session_cache/ssl_session_cache.cc b/src/core/tsi/ssl/session_cache/ssl_session_cache.cc
new file mode 100644
index 0000000..fe4f83a
--- /dev/null
+++ b/src/core/tsi/ssl/session_cache/ssl_session_cache.cc
@@ -0,0 +1,211 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/ssl/session_cache/ssl_session_cache.h"
+
+#include "src/core/tsi/ssl/session_cache/ssl_session.h"
+
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+namespace tsi {
+
+static void cache_key_avl_destroy(void* key, void* unused) {}
+
+static void* cache_key_avl_copy(void* key, void* unused) { return key; }
+
+static long cache_key_avl_compare(void* key1, void* key2, void* unused) {
+  return grpc_slice_cmp(*static_cast<grpc_slice*>(key1),
+                        *static_cast<grpc_slice*>(key2));
+}
+
+static void cache_value_avl_destroy(void* value, void* unused) {}
+
+static void* cache_value_avl_copy(void* value, void* unused) { return value; }
+
+// AVL only stores pointers, ownership belonges to the linked list.
+static const grpc_avl_vtable cache_avl_vtable = {
+    cache_key_avl_destroy,   cache_key_avl_copy,   cache_key_avl_compare,
+    cache_value_avl_destroy, cache_value_avl_copy,
+};
+
+/// Node for single cached session.
+class SslSessionLRUCache::Node {
+ public:
+  Node(const grpc_slice& key, SslSessionPtr session) : key_(key) {
+    SetSession(std::move(session));
+  }
+
+  ~Node() { grpc_slice_unref(key_); }
+
+  // Not copyable nor movable.
+  Node(const Node&) = delete;
+  Node& operator=(const Node&) = delete;
+
+  void* AvlKey() { return &key_; }
+
+  /// Returns a copy of the node's cache session.
+  SslSessionPtr CopySession() const { return session_->CopySession(); }
+
+  /// Set the \a session (which is moved) for the node.
+  void SetSession(SslSessionPtr session) {
+    session_ = SslCachedSession::Create(std::move(session));
+  }
+
+ private:
+  friend class SslSessionLRUCache;
+
+  grpc_slice key_;
+  grpc_core::UniquePtr<SslCachedSession> session_;
+
+  Node* next_ = nullptr;
+  Node* prev_ = nullptr;
+};
+
+SslSessionLRUCache::SslSessionLRUCache(size_t capacity) : capacity_(capacity) {
+  GPR_ASSERT(capacity > 0);
+  gpr_mu_init(&lock_);
+  entry_by_key_ = grpc_avl_create(&cache_avl_vtable);
+}
+
+SslSessionLRUCache::~SslSessionLRUCache() {
+  Node* node = use_order_list_head_;
+  while (node) {
+    Node* next = node->next_;
+    grpc_core::Delete(node);
+    node = next;
+  }
+  grpc_avl_unref(entry_by_key_, nullptr);
+  gpr_mu_destroy(&lock_);
+}
+
+size_t SslSessionLRUCache::Size() {
+  grpc_core::mu_guard guard(&lock_);
+  return use_order_list_size_;
+}
+
+SslSessionLRUCache::Node* SslSessionLRUCache::FindLocked(
+    const grpc_slice& key) {
+  void* value =
+      grpc_avl_get(entry_by_key_, const_cast<grpc_slice*>(&key), nullptr);
+  if (value == nullptr) {
+    return nullptr;
+  }
+  Node* node = static_cast<Node*>(value);
+  // Move to the beginning.
+  Remove(node);
+  PushFront(node);
+  AssertInvariants();
+  return node;
+}
+
+void SslSessionLRUCache::Put(const char* key, SslSessionPtr session) {
+  grpc_core::mu_guard guard(&lock_);
+  Node* node = FindLocked(grpc_slice_from_static_string(key));
+  if (node != nullptr) {
+    node->SetSession(std::move(session));
+    return;
+  }
+  grpc_slice key_slice = grpc_slice_from_copied_string(key);
+  node = grpc_core::New<Node>(key_slice, std::move(session));
+  PushFront(node);
+  entry_by_key_ = grpc_avl_add(entry_by_key_, node->AvlKey(), node, nullptr);
+  AssertInvariants();
+  if (use_order_list_size_ > capacity_) {
+    GPR_ASSERT(use_order_list_tail_);
+    node = use_order_list_tail_;
+    Remove(node);
+    // Order matters, key is destroyed after deleting node.
+    entry_by_key_ = grpc_avl_remove(entry_by_key_, node->AvlKey(), nullptr);
+    grpc_core::Delete(node);
+    AssertInvariants();
+  }
+}
+
+SslSessionPtr SslSessionLRUCache::Get(const char* key) {
+  grpc_core::mu_guard guard(&lock_);
+  // Key is only used for lookups.
+  grpc_slice key_slice = grpc_slice_from_static_string(key);
+  Node* node = FindLocked(key_slice);
+  if (node == nullptr) {
+    return nullptr;
+  }
+  return node->CopySession();
+}
+
+void SslSessionLRUCache::Remove(SslSessionLRUCache::Node* node) {
+  if (node->prev_ == nullptr) {
+    use_order_list_head_ = node->next_;
+  } else {
+    node->prev_->next_ = node->next_;
+  }
+  if (node->next_ == nullptr) {
+    use_order_list_tail_ = node->prev_;
+  } else {
+    node->next_->prev_ = node->prev_;
+  }
+  GPR_ASSERT(use_order_list_size_ >= 1);
+  use_order_list_size_--;
+}
+
+void SslSessionLRUCache::PushFront(SslSessionLRUCache::Node* node) {
+  if (use_order_list_head_ == nullptr) {
+    use_order_list_head_ = node;
+    use_order_list_tail_ = node;
+    node->next_ = nullptr;
+    node->prev_ = nullptr;
+  } else {
+    node->next_ = use_order_list_head_;
+    node->next_->prev_ = node;
+    use_order_list_head_ = node;
+    node->prev_ = nullptr;
+  }
+  use_order_list_size_++;
+}
+
+#ifndef NDEBUG
+static size_t calculate_tree_size(grpc_avl_node* node) {
+  if (node == nullptr) {
+    return 0;
+  }
+  return 1 + calculate_tree_size(node->left) + calculate_tree_size(node->right);
+}
+
+void SslSessionLRUCache::AssertInvariants() {
+  size_t size = 0;
+  Node* prev = nullptr;
+  Node* current = use_order_list_head_;
+  while (current != nullptr) {
+    size++;
+    GPR_ASSERT(current->prev_ == prev);
+    void* node = grpc_avl_get(entry_by_key_, current->AvlKey(), nullptr);
+    GPR_ASSERT(node == current);
+    prev = current;
+    current = current->next_;
+  }
+  GPR_ASSERT(prev == use_order_list_tail_);
+  GPR_ASSERT(size == use_order_list_size_);
+  GPR_ASSERT(calculate_tree_size(entry_by_key_.root) == use_order_list_size_);
+}
+#else
+void SslSessionLRUCache::AssertInvariants() {}
+#endif
+
+}  // namespace tsi
diff --git a/src/core/tsi/ssl/session_cache/ssl_session_cache.h b/src/core/tsi/ssl/session_cache/ssl_session_cache.h
new file mode 100644
index 0000000..488638c
--- /dev/null
+++ b/src/core/tsi/ssl/session_cache/ssl_session_cache.h
@@ -0,0 +1,93 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_CORE_TSI_SSL_SESSION_CACHE_SSL_SESSION_CACHE_H
+#define GRPC_CORE_TSI_SSL_SESSION_CACHE_SSL_SESSION_CACHE_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/slice.h>
+#include <grpc/support/sync.h>
+
+extern "C" {
+#include <openssl/ssl.h>
+}
+
+#include "src/core/lib/avl/avl.h"
+#include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/gprpp/ref_counted.h"
+#include "src/core/tsi/ssl/session_cache/ssl_session.h"
+
+/// Cache for SSL sessions for sessions resumption.
+///
+/// Older sessions may be evicted from the cache using LRU policy if capacity
+/// limit is hit. All sessions are associated with some key, usually server
+/// name. Note that servers are required to share session ticket encryption keys
+/// in order for cache to be effective.
+///
+/// This class is thread safe.
+
+namespace tsi {
+
+class SslSessionLRUCache : public grpc_core::RefCounted<SslSessionLRUCache> {
+ public:
+  /// Create new LRU cache with the given capacity.
+  static grpc_core::RefCountedPtr<SslSessionLRUCache> Create(size_t capacity) {
+    return grpc_core::MakeRefCounted<SslSessionLRUCache>(capacity);
+  }
+
+  // Not copyable nor movable.
+  SslSessionLRUCache(const SslSessionLRUCache&) = delete;
+  SslSessionLRUCache& operator=(const SslSessionLRUCache&) = delete;
+
+  /// Returns current number of sessions in the cache.
+  size_t Size();
+  /// Add \a session in the cache using \a key. This operation may discard older
+  /// sessions.
+  void Put(const char* key, SslSessionPtr session);
+  /// Returns the session from the cache associated with \a key or null if not
+  /// found.
+  SslSessionPtr Get(const char* key);
+
+ private:
+  // So New() can call our private ctor.
+  template <typename T, typename... Args>
+  friend T* grpc_core::New(Args&&... args);
+
+  class Node;
+
+  explicit SslSessionLRUCache(size_t capacity);
+  ~SslSessionLRUCache();
+
+  Node* FindLocked(const grpc_slice& key);
+  void Remove(Node* node);
+  void PushFront(Node* node);
+  void AssertInvariants();
+
+  gpr_mu lock_;
+  size_t capacity_;
+
+  Node* use_order_list_head_ = nullptr;
+  Node* use_order_list_tail_ = nullptr;
+  size_t use_order_list_size_ = 0;
+  grpc_avl entry_by_key_;
+};
+
+}  // namespace tsi
+
+#endif /* GRPC_CORE_TSI_SSL_SESSION_CACHE_SSL_SESSION_CACHE_H */
diff --git a/src/core/tsi/ssl/session_cache/ssl_session_openssl.cc b/src/core/tsi/ssl/session_cache/ssl_session_openssl.cc
new file mode 100644
index 0000000..61c036c
--- /dev/null
+++ b/src/core/tsi/ssl/session_cache/ssl_session_openssl.cc
@@ -0,0 +1,76 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/port_platform.h>
+
+#include "src/core/tsi/ssl/session_cache/ssl_session.h"
+
+#include <grpc/support/log.h>
+
+#ifndef OPENSSL_IS_BORINGSSL
+
+// OpenSSL invalidates SSL_SESSION on SSL destruction making it pointless
+// to cache sessions. The workaround is to serialize (relatively expensive)
+// session into binary blob and re-create it from blob on every handshake.
+// Note that it's safe to keep serialized session outside of SSL lifetime
+// as openssl performs all necessary validation while attempting to use a
+// session and creates a new one if something is wrong (e.g. server changed
+// set of allowed codecs).
+
+namespace tsi {
+namespace {
+
+class OpenSslCachedSession : public SslCachedSession {
+ public:
+  OpenSslCachedSession(SslSessionPtr session) {
+    int size = i2d_SSL_SESSION(session.get(), nullptr);
+    GPR_ASSERT(size > 0);
+    grpc_slice slice = grpc_slice_malloc(size_t(size));
+    unsigned char* start = GRPC_SLICE_START_PTR(slice);
+    int second_size = i2d_SSL_SESSION(session.get(), &start);
+    GPR_ASSERT(size == second_size);
+    serialized_session_ = slice;
+  }
+
+  virtual ~OpenSslCachedSession() { grpc_slice_unref(serialized_session_); }
+
+  SslSessionPtr CopySession() const override {
+    const unsigned char* data = GRPC_SLICE_START_PTR(serialized_session_);
+    size_t length = GRPC_SLICE_LENGTH(serialized_session_);
+    SSL_SESSION* session = d2i_SSL_SESSION(nullptr, &data, length);
+    if (session == nullptr) {
+      return SslSessionPtr();
+    }
+    return SslSessionPtr(session);
+  }
+
+ private:
+  grpc_slice serialized_session_;
+};
+
+}  // namespace
+
+grpc_core::UniquePtr<SslCachedSession> SslCachedSession::Create(
+    SslSessionPtr session) {
+  return grpc_core::UniquePtr<SslCachedSession>(
+      grpc_core::New<OpenSslCachedSession>(std::move(session)));
+}
+
+}  // namespace tsi
+
+#endif /* OPENSSL_IS_BORINGSSL */
diff --git a/src/core/tsi/ssl_transport_security.cc b/src/core/tsi/ssl_transport_security.cc
index b396a62..0ba6587 100644
--- a/src/core/tsi/ssl_transport_security.cc
+++ b/src/core/tsi/ssl_transport_security.cc
@@ -16,10 +16,10 @@
  *
  */
 
-#include "src/core/tsi/ssl_transport_security.h"
-
 #include <grpc/support/port_platform.h>
 
+#include "src/core/tsi/ssl_transport_security.h"
+
 #include <limits.h>
 #include <string.h>
 
@@ -35,9 +35,9 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
+#include <grpc/support/thd_id.h>
 
 extern "C" {
 #include <openssl/bio.h>
@@ -48,6 +48,8 @@
 #include <openssl/x509v3.h>
 }
 
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/tsi/ssl/session_cache/ssl_session_cache.h"
 #include "src/core/tsi/ssl_types.h"
 #include "src/core/tsi/transport_security.h"
 
@@ -69,6 +71,10 @@
 
 /* --- Structure definitions. ---*/
 
+struct tsi_ssl_root_certs_store {
+  X509_STORE* store;
+};
+
 struct tsi_ssl_handshaker_factory {
   const tsi_ssl_handshaker_factory_vtable* vtable;
   gpr_refcount refcount;
@@ -79,6 +85,7 @@
   SSL_CTX* ssl_context;
   unsigned char* alpn_protocol_list;
   size_t alpn_protocol_list_length;
+  grpc_core::RefCountedPtr<tsi::SslSessionLRUCache> session_cache;
 };
 
 struct tsi_ssl_server_handshaker_factory {
@@ -112,22 +119,24 @@
 
 /* --- Library Initialization. ---*/
 
-static gpr_once init_openssl_once = GPR_ONCE_INIT;
-static gpr_mu* openssl_mutexes = nullptr;
+static gpr_once g_init_openssl_once = GPR_ONCE_INIT;
+static gpr_mu* g_openssl_mutexes = nullptr;
+static int g_ssl_ctx_ex_factory_index = -1;
 static void openssl_locking_cb(int mode, int type, const char* file,
                                int line) GRPC_UNUSED;
 static unsigned long openssl_thread_id_cb(void) GRPC_UNUSED;
+static const unsigned char kSslSessionIdContext[] = {'g', 'r', 'p', 'c'};
 
 static void openssl_locking_cb(int mode, int type, const char* file, int line) {
   if (mode & CRYPTO_LOCK) {
-    gpr_mu_lock(&openssl_mutexes[type]);
+    gpr_mu_lock(&g_openssl_mutexes[type]);
   } else {
-    gpr_mu_unlock(&openssl_mutexes[type]);
+    gpr_mu_unlock(&g_openssl_mutexes[type]);
   }
 }
 
 static unsigned long openssl_thread_id_cb(void) {
-  return (unsigned long)gpr_thd_currentid();
+  return static_cast<unsigned long>(gpr_thd_currentid());
 }
 
 static void init_openssl(void) {
@@ -138,12 +147,16 @@
   OpenSSL_add_all_algorithms();
   num_locks = CRYPTO_num_locks();
   GPR_ASSERT(num_locks > 0);
-  openssl_mutexes = (gpr_mu*)gpr_malloc((size_t)num_locks * sizeof(gpr_mu));
+  g_openssl_mutexes = static_cast<gpr_mu*>(
+      gpr_malloc(static_cast<size_t>(num_locks) * sizeof(gpr_mu)));
   for (i = 0; i < CRYPTO_num_locks(); i++) {
-    gpr_mu_init(&openssl_mutexes[i]);
+    gpr_mu_init(&g_openssl_mutexes[i]);
   }
   CRYPTO_set_locking_callback(openssl_locking_cb);
   CRYPTO_set_id_callback(openssl_thread_id_cb);
+  g_ssl_ctx_ex_factory_index =
+      SSL_CTX_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
+  GPR_ASSERT(g_ssl_ctx_ex_factory_index != -1);
 }
 
 /* --- Ssl utils. ---*/
@@ -255,7 +268,7 @@
     gpr_log(GPR_ERROR, "Could not extract utf8 from asn1 string.");
     return TSI_OUT_OF_RESOURCES;
   }
-  *utf8_size = (size_t)utf8_returned_size;
+  *utf8_size = static_cast<size_t>(utf8_returned_size);
   return TSI_OK;
 }
 
@@ -276,8 +289,8 @@
   }
   result = tsi_construct_string_peer_property(
       TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY,
-      common_name == nullptr ? "" : (const char*)common_name, common_name_size,
-      property);
+      common_name == nullptr ? "" : reinterpret_cast<const char*>(common_name),
+      common_name_size, property);
   OPENSSL_free(common_name);
   return result;
 }
@@ -296,7 +309,8 @@
     return TSI_INTERNAL_ERROR;
   }
   tsi_result result = tsi_construct_string_peer_property(
-      TSI_X509_PEM_CERT_PROPERTY, (const char*)contents, (size_t)len, property);
+      TSI_X509_PEM_CERT_PROPERTY, (const char*)contents,
+      static_cast<size_t>(len), property);
   BIO_free(bio);
   return result;
 }
@@ -325,8 +339,9 @@
         break;
       }
       result = tsi_construct_string_peer_property(
-          TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, (const char*)name,
-          (size_t)name_size, &peer->properties[peer->property_count++]);
+          TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY,
+          reinterpret_cast<const char*>(name), static_cast<size_t>(name_size),
+          &peer->properties[peer->property_count++]);
       OPENSSL_free(name);
     } else if (subject_alt_name->type == GEN_IPADD) {
       char ntop_buf[INET6_ADDRSTRLEN];
@@ -362,17 +377,18 @@
 static tsi_result peer_from_x509(X509* cert, int include_certificate_type,
                                  tsi_peer* peer) {
   /* TODO(jboeuf): Maybe add more properties. */
-  GENERAL_NAMES* subject_alt_names = (GENERAL_NAMES*)X509_get_ext_d2i(
-      cert, NID_subject_alt_name, nullptr, nullptr);
-  int subject_alt_name_count = (subject_alt_names != nullptr)
-                                   ? (int)sk_GENERAL_NAME_num(subject_alt_names)
-                                   : 0;
+  GENERAL_NAMES* subject_alt_names = static_cast<GENERAL_NAMES*>(
+      X509_get_ext_d2i(cert, NID_subject_alt_name, nullptr, nullptr));
+  int subject_alt_name_count =
+      (subject_alt_names != nullptr)
+          ? static_cast<int>(sk_GENERAL_NAME_num(subject_alt_names))
+          : 0;
   size_t property_count;
   tsi_result result;
   GPR_ASSERT(subject_alt_name_count >= 0);
-  property_count = (include_certificate_type ? (size_t)1 : 0) +
+  property_count = (include_certificate_type ? static_cast<size_t>(1) : 0) +
                    2 /* common name, certificate */ +
-                   (size_t)subject_alt_name_count;
+                   static_cast<size_t>(subject_alt_name_count);
   result = tsi_construct_peer(property_count, peer);
   if (result != TSI_OK) return result;
   do {
@@ -392,7 +408,7 @@
 
     if (subject_alt_name_count != 0) {
       result = add_subject_alt_names_properties_to_peer(
-          peer, subject_alt_names, (size_t)subject_alt_name_count);
+          peer, subject_alt_names, static_cast<size_t>(subject_alt_name_count));
       if (result != TSI_OK) break;
     }
   } while (0);
@@ -409,7 +425,7 @@
   unsigned long err;
   while ((err = ERR_get_error()) != 0) {
     char details[256];
-    ERR_error_string_n((uint32_t)err, details, sizeof(details));
+    ERR_error_string_n(static_cast<uint32_t>(err), details, sizeof(details));
     gpr_log(GPR_ERROR, "%s", details);
   }
 }
@@ -419,8 +435,8 @@
                               size_t* unprotected_bytes_size) {
   int read_from_ssl;
   GPR_ASSERT(*unprotected_bytes_size <= INT_MAX);
-  read_from_ssl =
-      SSL_read(ssl, unprotected_bytes, (int)*unprotected_bytes_size);
+  read_from_ssl = SSL_read(ssl, unprotected_bytes,
+                           static_cast<int>(*unprotected_bytes_size));
   if (read_from_ssl <= 0) {
     read_from_ssl = SSL_get_error(ssl, read_from_ssl);
     switch (read_from_ssl) {
@@ -443,7 +459,7 @@
         return TSI_PROTOCOL_FAILURE;
     }
   }
-  *unprotected_bytes_size = (size_t)read_from_ssl;
+  *unprotected_bytes_size = static_cast<size_t>(read_from_ssl);
   return TSI_OK;
 }
 
@@ -452,8 +468,8 @@
                                size_t unprotected_bytes_size) {
   int ssl_write_result;
   GPR_ASSERT(unprotected_bytes_size <= INT_MAX);
-  ssl_write_result =
-      SSL_write(ssl, unprotected_bytes, (int)unprotected_bytes_size);
+  ssl_write_result = SSL_write(ssl, unprotected_bytes,
+                               static_cast<int>(unprotected_bytes_size));
   if (ssl_write_result < 0) {
     ssl_write_result = SSL_get_error(ssl, ssl_write_result);
     if (ssl_write_result == SSL_ERROR_WANT_READ) {
@@ -477,7 +493,8 @@
   X509* certificate = nullptr;
   BIO* pem;
   GPR_ASSERT(pem_cert_chain_size <= INT_MAX);
-  pem = BIO_new_mem_buf((void*)pem_cert_chain, (int)pem_cert_chain_size);
+  pem = BIO_new_mem_buf((void*)pem_cert_chain,
+                        static_cast<int>(pem_cert_chain_size));
   if (pem == nullptr) return TSI_OUT_OF_RESOURCES;
 
   do {
@@ -520,7 +537,7 @@
   EVP_PKEY* private_key = nullptr;
   BIO* pem;
   GPR_ASSERT(pem_key_size <= INT_MAX);
-  pem = BIO_new_mem_buf((void*)pem_key, (int)pem_key_size);
+  pem = BIO_new_mem_buf((void*)pem_key, static_cast<int>(pem_key_size));
   if (pem == nullptr) return TSI_OUT_OF_RESOURCES;
   do {
     private_key = PEM_read_bio_PrivateKey(pem, nullptr, nullptr, (void*)"");
@@ -540,21 +557,18 @@
 
 /* Loads in-memory PEM verification certs into the SSL context and optionally
    returns the verification cert names (root_names can be NULL). */
-static tsi_result ssl_ctx_load_verification_certs(SSL_CTX* context,
-                                                  const char* pem_roots,
-                                                  size_t pem_roots_size,
-                                                  STACK_OF(X509_NAME) *
-                                                      *root_names) {
+static tsi_result x509_store_load_certs(X509_STORE* cert_store,
+                                        const char* pem_roots,
+                                        size_t pem_roots_size,
+                                        STACK_OF(X509_NAME) * *root_names) {
   tsi_result result = TSI_OK;
   size_t num_roots = 0;
   X509* root = nullptr;
   X509_NAME* root_name = nullptr;
   BIO* pem;
-  X509_STORE* root_store;
   GPR_ASSERT(pem_roots_size <= INT_MAX);
-  pem = BIO_new_mem_buf((void*)pem_roots, (int)pem_roots_size);
-  root_store = SSL_CTX_get_cert_store(context);
-  if (root_store == nullptr) return TSI_INVALID_ARGUMENT;
+  pem = BIO_new_mem_buf((void*)pem_roots, static_cast<int>(pem_roots_size));
+  if (cert_store == nullptr) return TSI_INVALID_ARGUMENT;
   if (pem == nullptr) return TSI_OUT_OF_RESOURCES;
   if (root_names != nullptr) {
     *root_names = sk_X509_NAME_new_null();
@@ -582,7 +596,7 @@
       sk_X509_NAME_push(*root_names, root_name);
       root_name = nullptr;
     }
-    if (!X509_STORE_add_cert(root_store, root)) {
+    if (!X509_STORE_add_cert(cert_store, root)) {
       gpr_log(GPR_ERROR, "Could not add root certificate to ssl context.");
       result = TSI_INTERNAL_ERROR;
       break;
@@ -608,6 +622,16 @@
   return result;
 }
 
+static tsi_result ssl_ctx_load_verification_certs(SSL_CTX* context,
+                                                  const char* pem_roots,
+                                                  size_t pem_roots_size,
+                                                  STACK_OF(X509_NAME) *
+                                                      *root_name) {
+  X509_STORE* cert_store = SSL_CTX_get_cert_store(context);
+  return x509_store_load_certs(cert_store, pem_roots, pem_roots_size,
+                               root_name);
+}
+
 /* Populates the SSL context with a private key and a cert chain, and sets the
    cipher list and the ephemeral ECDH key. */
 static tsi_result populate_ssl_context(
@@ -656,7 +680,7 @@
   tsi_result result = TSI_OK;
   X509* cert = nullptr;
   BIO* pem;
-  pem = BIO_new_mem_buf((void*)pem_cert, (int)strlen(pem_cert));
+  pem = BIO_new_mem_buf((void*)pem_cert, static_cast<int>(strlen(pem_cert)));
   if (pem == nullptr) return TSI_OUT_OF_RESOURCES;
 
   cert = PEM_read_bio_X509(pem, nullptr, nullptr, (void*)"");
@@ -684,23 +708,25 @@
     size_t length =
         alpn_protocols[i] == nullptr ? 0 : strlen(alpn_protocols[i]);
     if (length == 0 || length > 255) {
-      gpr_log(GPR_ERROR, "Invalid protocol name length: %d.", (int)length);
+      gpr_log(GPR_ERROR, "Invalid protocol name length: %d.",
+              static_cast<int>(length));
       return TSI_INVALID_ARGUMENT;
     }
     *protocol_name_list_length += length + 1;
   }
-  *protocol_name_list = (unsigned char*)gpr_malloc(*protocol_name_list_length);
+  *protocol_name_list =
+      static_cast<unsigned char*>(gpr_malloc(*protocol_name_list_length));
   if (*protocol_name_list == nullptr) return TSI_OUT_OF_RESOURCES;
   current = *protocol_name_list;
   for (i = 0; i < num_alpn_protocols; i++) {
     size_t length = strlen(alpn_protocols[i]);
-    *(current++) = (uint8_t)length; /* max checked above. */
+    *(current++) = static_cast<uint8_t>(length); /* max checked above. */
     memcpy(current, alpn_protocols[i], length);
     current += length;
   }
   /* Safety check. */
   if ((current < *protocol_name_list) ||
-      ((uintptr_t)(current - *protocol_name_list) !=
+      (static_cast<uintptr_t>(current - *protocol_name_list) !=
        *protocol_name_list_length)) {
     return TSI_INTERNAL_ERROR;
   }
@@ -715,6 +741,60 @@
   return 1;
 }
 
+/* --- tsi_ssl_root_certs_store methods implementation. ---*/
+
+tsi_ssl_root_certs_store* tsi_ssl_root_certs_store_create(
+    const char* pem_roots) {
+  if (pem_roots == nullptr) {
+    gpr_log(GPR_ERROR, "The root certificates are empty.");
+    return nullptr;
+  }
+  tsi_ssl_root_certs_store* root_store = static_cast<tsi_ssl_root_certs_store*>(
+      gpr_zalloc(sizeof(tsi_ssl_root_certs_store)));
+  if (root_store == nullptr) {
+    gpr_log(GPR_ERROR, "Could not allocate buffer for ssl_root_certs_store.");
+    return nullptr;
+  }
+  root_store->store = X509_STORE_new();
+  if (root_store->store == nullptr) {
+    gpr_log(GPR_ERROR, "Could not allocate buffer for X509_STORE.");
+    gpr_free(root_store);
+    return nullptr;
+  }
+  tsi_result result = x509_store_load_certs(root_store->store, pem_roots,
+                                            strlen(pem_roots), nullptr);
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "Could not load root certificates.");
+    X509_STORE_free(root_store->store);
+    gpr_free(root_store);
+    return nullptr;
+  }
+  return root_store;
+}
+
+void tsi_ssl_root_certs_store_destroy(tsi_ssl_root_certs_store* self) {
+  if (self == nullptr) return;
+  X509_STORE_free(self->store);
+  gpr_free(self);
+}
+
+/* --- tsi_ssl_session_cache methods implementation. ---*/
+
+tsi_ssl_session_cache* tsi_ssl_session_cache_create_lru(size_t capacity) {
+  /* Pointer will be dereferenced by unref call. */
+  return reinterpret_cast<tsi_ssl_session_cache*>(
+      tsi::SslSessionLRUCache::Create(capacity).release());
+}
+
+void tsi_ssl_session_cache_ref(tsi_ssl_session_cache* cache) {
+  /* Pointer will be dereferenced by unref call. */
+  reinterpret_cast<tsi::SslSessionLRUCache*>(cache)->Ref().release();
+}
+
+void tsi_ssl_session_cache_unref(tsi_ssl_session_cache* cache) {
+  reinterpret_cast<tsi::SslSessionLRUCache*>(cache)->Unref();
+}
+
 /* --- tsi_frame_protector methods implementation. ---*/
 
 static tsi_result ssl_protector_protect(tsi_frame_protector* self,
@@ -722,24 +802,25 @@
                                         size_t* unprotected_bytes_size,
                                         unsigned char* protected_output_frames,
                                         size_t* protected_output_frames_size) {
-  tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self;
+  tsi_ssl_frame_protector* impl =
+      reinterpret_cast<tsi_ssl_frame_protector*>(self);
   int read_from_ssl;
   size_t available;
   tsi_result result = TSI_OK;
 
   /* First see if we have some pending data in the SSL BIO. */
-  int pending_in_ssl = (int)BIO_pending(impl->network_io);
+  int pending_in_ssl = static_cast<int>(BIO_pending(impl->network_io));
   if (pending_in_ssl > 0) {
     *unprotected_bytes_size = 0;
     GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
     read_from_ssl = BIO_read(impl->network_io, protected_output_frames,
-                             (int)*protected_output_frames_size);
+                             static_cast<int>(*protected_output_frames_size));
     if (read_from_ssl < 0) {
       gpr_log(GPR_ERROR,
               "Could not read from BIO even though some data is pending");
       return TSI_INTERNAL_ERROR;
     }
-    *protected_output_frames_size = (size_t)read_from_ssl;
+    *protected_output_frames_size = static_cast<size_t>(read_from_ssl);
     return TSI_OK;
   }
 
@@ -761,12 +842,12 @@
 
   GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
   read_from_ssl = BIO_read(impl->network_io, protected_output_frames,
-                           (int)*protected_output_frames_size);
+                           static_cast<int>(*protected_output_frames_size));
   if (read_from_ssl < 0) {
     gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write.");
     return TSI_INTERNAL_ERROR;
   }
-  *protected_output_frames_size = (size_t)read_from_ssl;
+  *protected_output_frames_size = static_cast<size_t>(read_from_ssl);
   *unprotected_bytes_size = available;
   impl->buffer_offset = 0;
   return TSI_OK;
@@ -776,7 +857,8 @@
     tsi_frame_protector* self, unsigned char* protected_output_frames,
     size_t* protected_output_frames_size, size_t* still_pending_size) {
   tsi_result result = TSI_OK;
-  tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self;
+  tsi_ssl_frame_protector* impl =
+      reinterpret_cast<tsi_ssl_frame_protector*>(self);
   int read_from_ssl = 0;
   int pending;
 
@@ -786,22 +868,22 @@
     impl->buffer_offset = 0;
   }
 
-  pending = (int)BIO_pending(impl->network_io);
+  pending = static_cast<int>(BIO_pending(impl->network_io));
   GPR_ASSERT(pending >= 0);
-  *still_pending_size = (size_t)pending;
+  *still_pending_size = static_cast<size_t>(pending);
   if (*still_pending_size == 0) return TSI_OK;
 
   GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
   read_from_ssl = BIO_read(impl->network_io, protected_output_frames,
-                           (int)*protected_output_frames_size);
+                           static_cast<int>(*protected_output_frames_size));
   if (read_from_ssl <= 0) {
     gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write.");
     return TSI_INTERNAL_ERROR;
   }
-  *protected_output_frames_size = (size_t)read_from_ssl;
-  pending = (int)BIO_pending(impl->network_io);
+  *protected_output_frames_size = static_cast<size_t>(read_from_ssl);
+  pending = static_cast<int>(BIO_pending(impl->network_io));
   GPR_ASSERT(pending >= 0);
-  *still_pending_size = (size_t)pending;
+  *still_pending_size = static_cast<size_t>(pending);
   return TSI_OK;
 }
 
@@ -813,7 +895,8 @@
   int written_into_ssl = 0;
   size_t output_bytes_size = *unprotected_bytes_size;
   size_t output_bytes_offset = 0;
-  tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self;
+  tsi_ssl_frame_protector* impl =
+      reinterpret_cast<tsi_ssl_frame_protector*>(self);
 
   /* First, try to read remaining data from ssl. */
   result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size);
@@ -830,13 +913,13 @@
   /* Then, try to write some data to ssl. */
   GPR_ASSERT(*protected_frames_bytes_size <= INT_MAX);
   written_into_ssl = BIO_write(impl->network_io, protected_frames_bytes,
-                               (int)*protected_frames_bytes_size);
+                               static_cast<int>(*protected_frames_bytes_size));
   if (written_into_ssl < 0) {
     gpr_log(GPR_ERROR, "Sending protected frame to ssl failed with %d",
             written_into_ssl);
     return TSI_INTERNAL_ERROR;
   }
-  *protected_frames_bytes_size = (size_t)written_into_ssl;
+  *protected_frames_bytes_size = static_cast<size_t>(written_into_ssl);
 
   /* Now try to read some data again. */
   result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size);
@@ -848,7 +931,8 @@
 }
 
 static void ssl_protector_destroy(tsi_frame_protector* self) {
-  tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self;
+  tsi_ssl_frame_protector* impl =
+      reinterpret_cast<tsi_ssl_frame_protector*>(self);
   if (impl->buffer != nullptr) gpr_free(impl->buffer);
   if (impl->ssl != nullptr) SSL_free(impl->ssl);
   if (impl->network_io != nullptr) BIO_free(impl->network_io);
@@ -908,14 +992,15 @@
 static tsi_result ssl_handshaker_get_bytes_to_send_to_peer(tsi_handshaker* self,
                                                            unsigned char* bytes,
                                                            size_t* bytes_size) {
-  tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self;
+  tsi_ssl_handshaker* impl = reinterpret_cast<tsi_ssl_handshaker*>(self);
   int bytes_read_from_ssl = 0;
   if (bytes == nullptr || bytes_size == nullptr || *bytes_size == 0 ||
       *bytes_size > INT_MAX) {
     return TSI_INVALID_ARGUMENT;
   }
   GPR_ASSERT(*bytes_size <= INT_MAX);
-  bytes_read_from_ssl = BIO_read(impl->network_io, bytes, (int)*bytes_size);
+  bytes_read_from_ssl =
+      BIO_read(impl->network_io, bytes, static_cast<int>(*bytes_size));
   if (bytes_read_from_ssl < 0) {
     *bytes_size = 0;
     if (!BIO_should_retry(impl->network_io)) {
@@ -925,12 +1010,12 @@
       return TSI_OK;
     }
   }
-  *bytes_size = (size_t)bytes_read_from_ssl;
+  *bytes_size = static_cast<size_t>(bytes_read_from_ssl);
   return BIO_pending(impl->network_io) == 0 ? TSI_OK : TSI_INCOMPLETE_DATA;
 }
 
 static tsi_result ssl_handshaker_get_result(tsi_handshaker* self) {
-  tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self;
+  tsi_ssl_handshaker* impl = reinterpret_cast<tsi_ssl_handshaker*>(self);
   if ((impl->result == TSI_HANDSHAKE_IN_PROGRESS) &&
       SSL_is_init_finished(impl->ssl)) {
     impl->result = TSI_OK;
@@ -940,20 +1025,20 @@
 
 static tsi_result ssl_handshaker_process_bytes_from_peer(
     tsi_handshaker* self, const unsigned char* bytes, size_t* bytes_size) {
-  tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self;
+  tsi_ssl_handshaker* impl = reinterpret_cast<tsi_ssl_handshaker*>(self);
   int bytes_written_into_ssl_size = 0;
   if (bytes == nullptr || bytes_size == nullptr || *bytes_size > INT_MAX) {
     return TSI_INVALID_ARGUMENT;
   }
   GPR_ASSERT(*bytes_size <= INT_MAX);
   bytes_written_into_ssl_size =
-      BIO_write(impl->network_io, bytes, (int)*bytes_size);
+      BIO_write(impl->network_io, bytes, static_cast<int>(*bytes_size));
   if (bytes_written_into_ssl_size < 0) {
     gpr_log(GPR_ERROR, "Could not write to memory BIO.");
     impl->result = TSI_INTERNAL_ERROR;
     return impl->result;
   }
-  *bytes_size = (size_t)bytes_written_into_ssl_size;
+  *bytes_size = static_cast<size_t>(bytes_written_into_ssl_size);
 
   if (!tsi_handshaker_is_in_progress(self)) {
     impl->result = TSI_OK;
@@ -989,7 +1074,7 @@
   tsi_result result = TSI_OK;
   const unsigned char* alpn_selected = nullptr;
   unsigned int alpn_selected_len;
-  tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self;
+  tsi_ssl_handshaker* impl = reinterpret_cast<tsi_ssl_handshaker*>(self);
   X509* peer_cert = SSL_get_peer_certificate(impl->ssl);
   if (peer_cert != nullptr) {
     result = peer_from_x509(peer_cert, 1, peer);
@@ -1004,24 +1089,34 @@
     SSL_get0_next_proto_negotiated(impl->ssl, &alpn_selected,
                                    &alpn_selected_len);
   }
-  if (alpn_selected != nullptr) {
-    size_t i;
-    tsi_peer_property* new_properties = (tsi_peer_property*)gpr_zalloc(
-        sizeof(*new_properties) * (peer->property_count + 1));
-    for (i = 0; i < peer->property_count; i++) {
-      new_properties[i] = peer->properties[i];
-    }
-    result = tsi_construct_string_peer_property(
-        TSI_SSL_ALPN_SELECTED_PROTOCOL, (const char*)alpn_selected,
-        alpn_selected_len, &new_properties[peer->property_count]);
-    if (result != TSI_OK) {
-      gpr_free(new_properties);
-      return result;
-    }
-    if (peer->properties != nullptr) gpr_free(peer->properties);
-    peer->property_count++;
-    peer->properties = new_properties;
+
+  // 1 is for session reused property.
+  size_t new_property_count = peer->property_count + 1;
+  if (alpn_selected != nullptr) new_property_count++;
+  tsi_peer_property* new_properties = static_cast<tsi_peer_property*>(
+      gpr_zalloc(sizeof(*new_properties) * new_property_count));
+  for (size_t i = 0; i < peer->property_count; i++) {
+    new_properties[i] = peer->properties[i];
   }
+  if (peer->properties != nullptr) gpr_free(peer->properties);
+  peer->properties = new_properties;
+
+  if (alpn_selected != nullptr) {
+    result = tsi_construct_string_peer_property(
+        TSI_SSL_ALPN_SELECTED_PROTOCOL,
+        reinterpret_cast<const char*>(alpn_selected), alpn_selected_len,
+        &peer->properties[peer->property_count]);
+    if (result != TSI_OK) return result;
+    peer->property_count++;
+  }
+
+  const char* session_reused = SSL_session_reused(impl->ssl) ? "true" : "false";
+  result = tsi_construct_string_peer_property(
+      TSI_SSL_SESSION_REUSED_PEER_PROPERTY, session_reused,
+      strlen(session_reused) + 1, &peer->properties[peer->property_count]);
+  if (result != TSI_OK) return result;
+  peer->property_count++;
+
   return result;
 }
 
@@ -1030,9 +1125,10 @@
     tsi_frame_protector** protector) {
   size_t actual_max_output_protected_frame_size =
       TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND;
-  tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self;
+  tsi_ssl_handshaker* impl = reinterpret_cast<tsi_ssl_handshaker*>(self);
   tsi_ssl_frame_protector* protector_impl =
-      (tsi_ssl_frame_protector*)gpr_zalloc(sizeof(*protector_impl));
+      static_cast<tsi_ssl_frame_protector*>(
+          gpr_zalloc(sizeof(*protector_impl)));
 
   if (max_output_protected_frame_size != nullptr) {
     if (*max_output_protected_frame_size >
@@ -1049,7 +1145,7 @@
   protector_impl->buffer_size =
       actual_max_output_protected_frame_size - TSI_SSL_MAX_PROTECTION_OVERHEAD;
   protector_impl->buffer =
-      (unsigned char*)gpr_malloc(protector_impl->buffer_size);
+      static_cast<unsigned char*>(gpr_malloc(protector_impl->buffer_size));
   if (protector_impl->buffer == nullptr) {
     gpr_log(GPR_ERROR,
             "Could not allocated buffer for tsi_ssl_frame_protector.");
@@ -1071,7 +1167,7 @@
 }
 
 static void ssl_handshaker_destroy(tsi_handshaker* self) {
-  tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self;
+  tsi_ssl_handshaker* impl = reinterpret_cast<tsi_ssl_handshaker*>(self);
   SSL_free(impl->ssl);
   BIO_free(impl->network_io);
   tsi_ssl_handshaker_factory_unref(impl->factory_ref);
@@ -1090,6 +1186,19 @@
 
 /* --- tsi_ssl_handshaker_factory common methods. --- */
 
+static void tsi_ssl_handshaker_resume_session(
+    SSL* ssl, tsi::SslSessionLRUCache* session_cache) {
+  const char* server_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+  if (server_name == nullptr) {
+    return;
+  }
+  tsi::SslSessionPtr session = session_cache->Get(server_name);
+  if (session != nullptr) {
+    // SSL_set_session internally increments reference counter.
+    SSL_set_session(ssl, session.get());
+  }
+}
+
 static tsi_result create_tsi_ssl_handshaker(SSL_CTX* ctx, int is_client,
                                             const char* server_name_indication,
                                             tsi_ssl_handshaker_factory* factory,
@@ -1126,6 +1235,12 @@
         return TSI_INTERNAL_ERROR;
       }
     }
+    tsi_ssl_client_handshaker_factory* client_factory =
+        reinterpret_cast<tsi_ssl_client_handshaker_factory*>(factory);
+    if (client_factory->session_cache != nullptr) {
+      tsi_ssl_handshaker_resume_session(ssl,
+                                        client_factory->session_cache.get());
+    }
     ssl_result = SSL_do_handshake(ssl);
     ssl_result = SSL_get_error(ssl, ssl_result);
     if (ssl_result != SSL_ERROR_WANT_READ) {
@@ -1140,7 +1255,7 @@
     SSL_set_accept_state(ssl);
   }
 
-  impl = (tsi_ssl_handshaker*)gpr_zalloc(sizeof(*impl));
+  impl = static_cast<tsi_ssl_handshaker*>(gpr_zalloc(sizeof(*impl)));
   impl->ssl = ssl;
   impl->network_io = network_io;
   impl->result = TSI_HANDSHAKE_IN_PROGRESS;
@@ -1158,11 +1273,13 @@
                                 const unsigned char* server_list,
                                 size_t server_list_len) {
   const unsigned char* client_current = client_list;
-  while ((unsigned int)(client_current - client_list) < client_list_len) {
+  while (static_cast<unsigned int>(client_current - client_list) <
+         client_list_len) {
     unsigned char client_current_len = *(client_current++);
     const unsigned char* server_current = server_list;
     while ((server_current >= server_list) &&
-           (uintptr_t)(server_current - server_list) < server_list_len) {
+           static_cast<uintptr_t>(server_current - server_list) <
+               server_list_len) {
       unsigned char server_current_len = *(server_current++);
       if ((client_current_len == server_current_len) &&
           !memcmp(client_current, server_current, server_current_len)) {
@@ -1196,9 +1313,10 @@
     tsi_ssl_handshaker_factory* factory) {
   if (factory == nullptr) return;
   tsi_ssl_client_handshaker_factory* self =
-      (tsi_ssl_client_handshaker_factory*)factory;
+      reinterpret_cast<tsi_ssl_client_handshaker_factory*>(factory);
   if (self->ssl_context != nullptr) SSL_CTX_free(self->ssl_context);
   if (self->alpn_protocol_list != nullptr) gpr_free(self->alpn_protocol_list);
+  self->session_cache.reset();
   gpr_free(self);
 }
 
@@ -1208,7 +1326,7 @@
                                                   unsigned int inlen,
                                                   void* arg) {
   tsi_ssl_client_handshaker_factory* factory =
-      (tsi_ssl_client_handshaker_factory*)arg;
+      static_cast<tsi_ssl_client_handshaker_factory*>(arg);
   return select_protocol_list((const unsigned char**)out, outlen,
                               factory->alpn_protocol_list,
                               factory->alpn_protocol_list_length, in, inlen);
@@ -1235,7 +1353,7 @@
     tsi_ssl_handshaker_factory* factory) {
   if (factory == nullptr) return;
   tsi_ssl_server_handshaker_factory* self =
-      (tsi_ssl_server_handshaker_factory*)factory;
+      reinterpret_cast<tsi_ssl_server_handshaker_factory*>(factory);
   size_t i;
   for (i = 0; i < self->ssl_context_count; i++) {
     if (self->ssl_contexts[i] != nullptr) {
@@ -1302,7 +1420,7 @@
 static int ssl_server_handshaker_factory_servername_callback(SSL* ssl, int* ap,
                                                              void* arg) {
   tsi_ssl_server_handshaker_factory* impl =
-      (tsi_ssl_server_handshaker_factory*)arg;
+      static_cast<tsi_ssl_server_handshaker_factory*>(arg);
   size_t i = 0;
   const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
   if (servername == nullptr || strlen(servername) == 0) {
@@ -1325,7 +1443,7 @@
     SSL* ssl, const unsigned char** out, unsigned char* outlen,
     const unsigned char* in, unsigned int inlen, void* arg) {
   tsi_ssl_server_handshaker_factory* factory =
-      (tsi_ssl_server_handshaker_factory*)arg;
+      static_cast<tsi_ssl_server_handshaker_factory*>(arg);
   return select_protocol_list(out, outlen, in, inlen,
                               factory->alpn_protocol_list,
                               factory->alpn_protocol_list_length);
@@ -1335,13 +1453,37 @@
 static int server_handshaker_factory_npn_advertised_callback(
     SSL* ssl, const unsigned char** out, unsigned int* outlen, void* arg) {
   tsi_ssl_server_handshaker_factory* factory =
-      (tsi_ssl_server_handshaker_factory*)arg;
+      static_cast<tsi_ssl_server_handshaker_factory*>(arg);
   *out = factory->alpn_protocol_list;
   GPR_ASSERT(factory->alpn_protocol_list_length <= UINT_MAX);
-  *outlen = (unsigned int)factory->alpn_protocol_list_length;
+  *outlen = static_cast<unsigned int>(factory->alpn_protocol_list_length);
   return SSL_TLSEXT_ERR_OK;
 }
 
+/// This callback is called when new \a session is established and ready to
+/// be cached. This session can be reused for new connections to similar
+/// servers at later point of time.
+/// It's intended to be used with SSL_CTX_sess_set_new_cb function.
+///
+/// It returns 1 if callback takes ownership over \a session and 0 otherwise.
+static int server_handshaker_factory_new_session_callback(
+    SSL* ssl, SSL_SESSION* session) {
+  SSL_CTX* ssl_context = SSL_get_SSL_CTX(ssl);
+  if (ssl_context == nullptr) {
+    return 0;
+  }
+  void* arg = SSL_CTX_get_ex_data(ssl_context, g_ssl_ctx_ex_factory_index);
+  tsi_ssl_client_handshaker_factory* factory =
+      static_cast<tsi_ssl_client_handshaker_factory*>(arg);
+  const char* server_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+  if (server_name == nullptr) {
+    return 0;
+  }
+  factory->session_cache->Put(server_name, tsi::SslSessionPtr(session));
+  // Return 1 to indicate transfered ownership over the given session.
+  return 1;
+}
+
 /* --- tsi_ssl_handshaker_factory constructors. --- */
 
 static tsi_ssl_handshaker_factory_vtable client_handshaker_factory_vtable = {
@@ -1352,15 +1494,31 @@
     const char* pem_root_certs, const char* cipher_suites,
     const char** alpn_protocols, uint16_t num_alpn_protocols,
     tsi_ssl_client_handshaker_factory** factory) {
+  tsi_ssl_client_handshaker_options options;
+  memset(&options, 0, sizeof(options));
+  options.pem_key_cert_pair = pem_key_cert_pair;
+  options.pem_root_certs = pem_root_certs;
+  options.cipher_suites = cipher_suites;
+  options.alpn_protocols = alpn_protocols;
+  options.num_alpn_protocols = num_alpn_protocols;
+  return tsi_create_ssl_client_handshaker_factory_with_options(&options,
+                                                               factory);
+}
+
+tsi_result tsi_create_ssl_client_handshaker_factory_with_options(
+    const tsi_ssl_client_handshaker_options* options,
+    tsi_ssl_client_handshaker_factory** factory) {
   SSL_CTX* ssl_context = nullptr;
   tsi_ssl_client_handshaker_factory* impl = nullptr;
   tsi_result result = TSI_OK;
 
-  gpr_once_init(&init_openssl_once, init_openssl);
+  gpr_once_init(&g_init_openssl_once, init_openssl);
 
   if (factory == nullptr) return TSI_INVALID_ARGUMENT;
   *factory = nullptr;
-  if (pem_root_certs == nullptr) return TSI_INVALID_ARGUMENT;
+  if (options->pem_root_certs == nullptr && options->root_store == nullptr) {
+    return TSI_INVALID_ARGUMENT;
+  }
 
   ssl_context = SSL_CTX_new(TLSv1_2_method());
   if (ssl_context == nullptr) {
@@ -1368,27 +1526,48 @@
     return TSI_INVALID_ARGUMENT;
   }
 
-  impl = (tsi_ssl_client_handshaker_factory*)gpr_zalloc(sizeof(*impl));
+  impl = static_cast<tsi_ssl_client_handshaker_factory*>(
+      gpr_zalloc(sizeof(*impl)));
   tsi_ssl_handshaker_factory_init(&impl->base);
   impl->base.vtable = &client_handshaker_factory_vtable;
-
   impl->ssl_context = ssl_context;
+  if (options->session_cache != nullptr) {
+    // Unref is called manually on factory destruction.
+    impl->session_cache =
+        reinterpret_cast<tsi::SslSessionLRUCache*>(options->session_cache)
+            ->Ref();
+    SSL_CTX_set_ex_data(ssl_context, g_ssl_ctx_ex_factory_index, impl);
+    SSL_CTX_sess_set_new_cb(ssl_context,
+                            server_handshaker_factory_new_session_callback);
+    SSL_CTX_set_session_cache_mode(ssl_context, SSL_SESS_CACHE_CLIENT);
+  }
 
   do {
-    result =
-        populate_ssl_context(ssl_context, pem_key_cert_pair, cipher_suites);
+    result = populate_ssl_context(ssl_context, options->pem_key_cert_pair,
+                                  options->cipher_suites);
     if (result != TSI_OK) break;
-    result = ssl_ctx_load_verification_certs(ssl_context, pem_root_certs,
-                                             strlen(pem_root_certs), nullptr);
-    if (result != TSI_OK) {
-      gpr_log(GPR_ERROR, "Cannot load server root certificates.");
-      break;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000
+    // X509_STORE_up_ref is only available since OpenSSL 1.1.
+    if (options->root_store != nullptr) {
+      X509_STORE_up_ref(options->root_store->store);
+      SSL_CTX_set_cert_store(ssl_context, options->root_store->store);
+    }
+#endif
+    if (OPENSSL_VERSION_NUMBER < 0x10100000 || options->root_store == nullptr) {
+      result = ssl_ctx_load_verification_certs(
+          ssl_context, options->pem_root_certs, strlen(options->pem_root_certs),
+          nullptr);
+      if (result != TSI_OK) {
+        gpr_log(GPR_ERROR, "Cannot load server root certificates.");
+        break;
+      }
     }
 
-    if (num_alpn_protocols != 0) {
-      result = build_alpn_protocol_name_list(alpn_protocols, num_alpn_protocols,
-                                             &impl->alpn_protocol_list,
-                                             &impl->alpn_protocol_list_length);
+    if (options->num_alpn_protocols != 0) {
+      result = build_alpn_protocol_name_list(
+          options->alpn_protocols, options->num_alpn_protocols,
+          &impl->alpn_protocol_list, &impl->alpn_protocol_list_length);
       if (result != TSI_OK) {
         gpr_log(GPR_ERROR, "Building alpn list failed with error %s.",
                 tsi_result_to_string(result));
@@ -1398,7 +1577,7 @@
       GPR_ASSERT(impl->alpn_protocol_list_length < UINT_MAX);
       if (SSL_CTX_set_alpn_protos(
               ssl_context, impl->alpn_protocol_list,
-              (unsigned int)impl->alpn_protocol_list_length)) {
+              static_cast<unsigned int>(impl->alpn_protocol_list_length))) {
         gpr_log(GPR_ERROR, "Could not set alpn protocol list to context.");
         result = TSI_INVALID_ARGUMENT;
         break;
@@ -1441,44 +1620,62 @@
     tsi_client_certificate_request_type client_certificate_request,
     const char* cipher_suites, const char** alpn_protocols,
     uint16_t num_alpn_protocols, tsi_ssl_server_handshaker_factory** factory) {
+  tsi_ssl_server_handshaker_options options;
+  memset(&options, 0, sizeof(options));
+  options.pem_key_cert_pairs = pem_key_cert_pairs;
+  options.num_key_cert_pairs = num_key_cert_pairs;
+  options.pem_client_root_certs = pem_client_root_certs;
+  options.client_certificate_request = client_certificate_request;
+  options.cipher_suites = cipher_suites;
+  options.alpn_protocols = alpn_protocols;
+  options.num_alpn_protocols = num_alpn_protocols;
+  return tsi_create_ssl_server_handshaker_factory_with_options(&options,
+                                                               factory);
+}
+
+tsi_result tsi_create_ssl_server_handshaker_factory_with_options(
+    const tsi_ssl_server_handshaker_options* options,
+    tsi_ssl_server_handshaker_factory** factory) {
   tsi_ssl_server_handshaker_factory* impl = nullptr;
   tsi_result result = TSI_OK;
   size_t i = 0;
 
-  gpr_once_init(&init_openssl_once, init_openssl);
+  gpr_once_init(&g_init_openssl_once, init_openssl);
 
   if (factory == nullptr) return TSI_INVALID_ARGUMENT;
   *factory = nullptr;
-  if (num_key_cert_pairs == 0 || pem_key_cert_pairs == nullptr) {
+  if (options->num_key_cert_pairs == 0 ||
+      options->pem_key_cert_pairs == nullptr) {
     return TSI_INVALID_ARGUMENT;
   }
 
-  impl = (tsi_ssl_server_handshaker_factory*)gpr_zalloc(sizeof(*impl));
+  impl = static_cast<tsi_ssl_server_handshaker_factory*>(
+      gpr_zalloc(sizeof(*impl)));
   tsi_ssl_handshaker_factory_init(&impl->base);
   impl->base.vtable = &server_handshaker_factory_vtable;
 
-  impl->ssl_contexts =
-      (SSL_CTX**)gpr_zalloc(num_key_cert_pairs * sizeof(SSL_CTX*));
-  impl->ssl_context_x509_subject_names =
-      (tsi_peer*)gpr_zalloc(num_key_cert_pairs * sizeof(tsi_peer));
+  impl->ssl_contexts = static_cast<SSL_CTX**>(
+      gpr_zalloc(options->num_key_cert_pairs * sizeof(SSL_CTX*)));
+  impl->ssl_context_x509_subject_names = static_cast<tsi_peer*>(
+      gpr_zalloc(options->num_key_cert_pairs * sizeof(tsi_peer)));
   if (impl->ssl_contexts == nullptr ||
       impl->ssl_context_x509_subject_names == nullptr) {
     tsi_ssl_handshaker_factory_unref(&impl->base);
     return TSI_OUT_OF_RESOURCES;
   }
-  impl->ssl_context_count = num_key_cert_pairs;
+  impl->ssl_context_count = options->num_key_cert_pairs;
 
-  if (num_alpn_protocols > 0) {
-    result = build_alpn_protocol_name_list(alpn_protocols, num_alpn_protocols,
-                                           &impl->alpn_protocol_list,
-                                           &impl->alpn_protocol_list_length);
+  if (options->num_alpn_protocols > 0) {
+    result = build_alpn_protocol_name_list(
+        options->alpn_protocols, options->num_alpn_protocols,
+        &impl->alpn_protocol_list, &impl->alpn_protocol_list_length);
     if (result != TSI_OK) {
       tsi_ssl_handshaker_factory_unref(&impl->base);
       return result;
     }
   }
 
-  for (i = 0; i < num_key_cert_pairs; i++) {
+  for (i = 0; i < options->num_key_cert_pairs; i++) {
     do {
       impl->ssl_contexts[i] = SSL_CTX_new(TLSv1_2_method());
       if (impl->ssl_contexts[i] == nullptr) {
@@ -1487,20 +1684,44 @@
         break;
       }
       result = populate_ssl_context(impl->ssl_contexts[i],
-                                    &pem_key_cert_pairs[i], cipher_suites);
+                                    &options->pem_key_cert_pairs[i],
+                                    options->cipher_suites);
       if (result != TSI_OK) break;
 
-      if (pem_client_root_certs != nullptr) {
+      // TODO(elessar): Provide ability to disable session ticket keys.
+
+      // Allow client cache sessions (it's needed for OpenSSL only).
+      int set_sid_ctx_result = SSL_CTX_set_session_id_context(
+          impl->ssl_contexts[i], kSslSessionIdContext,
+          GPR_ARRAY_SIZE(kSslSessionIdContext));
+      if (set_sid_ctx_result == 0) {
+        gpr_log(GPR_ERROR, "Failed to set session id context.");
+        result = TSI_INTERNAL_ERROR;
+        break;
+      }
+
+      if (options->session_ticket_key != nullptr) {
+        if (SSL_CTX_set_tlsext_ticket_keys(
+                impl->ssl_contexts[i],
+                const_cast<char*>(options->session_ticket_key),
+                options->session_ticket_key_size) == 0) {
+          gpr_log(GPR_ERROR, "Invalid STEK size.");
+          result = TSI_INVALID_ARGUMENT;
+          break;
+        }
+      }
+
+      if (options->pem_client_root_certs != nullptr) {
         STACK_OF(X509_NAME)* root_names = nullptr;
         result = ssl_ctx_load_verification_certs(
-            impl->ssl_contexts[i], pem_client_root_certs,
-            strlen(pem_client_root_certs), &root_names);
+            impl->ssl_contexts[i], options->pem_client_root_certs,
+            strlen(options->pem_client_root_certs), &root_names);
         if (result != TSI_OK) {
           gpr_log(GPR_ERROR, "Invalid verification certs.");
           break;
         }
         SSL_CTX_set_client_CA_list(impl->ssl_contexts[i], root_names);
-        switch (client_certificate_request) {
+        switch (options->client_certificate_request) {
           case TSI_DONT_REQUEST_CLIENT_CERTIFICATE:
             SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_NONE, nullptr);
             break;
@@ -1527,7 +1748,7 @@
       }
 
       result = extract_x509_subject_names_from_pem_cert(
-          pem_key_cert_pairs[i].cert_chain,
+          options->pem_key_cert_pairs[i].cert_chain,
           &impl->ssl_context_x509_subject_names[i]);
       if (result != TSI_OK) break;
 
diff --git a/src/core/tsi/ssl_transport_security.h b/src/core/tsi/ssl_transport_security.h
index bf211e1..cabf583 100644
--- a/src/core/tsi/ssl_transport_security.h
+++ b/src/core/tsi/ssl_transport_security.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_TSI_SSL_TRANSPORT_SECURITY_H
 #define GRPC_CORE_TSI_SSL_TRANSPORT_SECURITY_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/tsi/transport_security_interface.h"
 
 /* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for X509 certs. */
@@ -28,11 +30,41 @@
 #define TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY "x509_subject_common_name"
 #define TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY \
   "x509_subject_alternative_name"
+#define TSI_SSL_SESSION_REUSED_PEER_PROPERTY "ssl_session_reused"
 
 #define TSI_X509_PEM_CERT_PROPERTY "x509_pem_cert"
 
 #define TSI_SSL_ALPN_SELECTED_PROTOCOL "ssl_alpn_selected_protocol"
 
+/* --- tsi_ssl_root_certs_store object ---
+
+   This object stores SSL root certificates. It can be shared by multiple SSL
+   context. */
+typedef struct tsi_ssl_root_certs_store tsi_ssl_root_certs_store;
+
+/* Given a NULL-terminated string containing the PEM encoding of the root
+   certificates, creates a tsi_ssl_root_certs_store object. */
+tsi_ssl_root_certs_store* tsi_ssl_root_certs_store_create(
+    const char* pem_roots);
+
+/* Destroys the tsi_ssl_root_certs_store object. */
+void tsi_ssl_root_certs_store_destroy(tsi_ssl_root_certs_store* self);
+
+/* --- tsi_ssl_session_cache object ---
+
+   Cache for SSL sessions for sessions resumption.  */
+
+typedef struct tsi_ssl_session_cache tsi_ssl_session_cache;
+
+/* Create LRU cache for SSL sessions with \a capacity.  */
+tsi_ssl_session_cache* tsi_ssl_session_cache_create_lru(size_t capacity);
+
+/* Increment reference counter of \a cache.  */
+void tsi_ssl_session_cache_ref(tsi_ssl_session_cache* cache);
+
+/* Decrement reference counter of \a cache.  */
+void tsi_ssl_session_cache_unref(tsi_ssl_session_cache* cache);
+
 /* --- tsi_ssl_client_handshaker_factory object ---
 
    This object creates a client tsi_handshaker objects implemented in terms of
@@ -52,13 +84,13 @@
   const char* cert_chain;
 } tsi_ssl_pem_key_cert_pair;
 
-/* Creates a client handshaker factory.
+/* TO BE DEPRECATED.
+   Creates a client handshaker factory.
    - pem_key_cert_pair is a pointer to the object containing client's private
      key and certificate chain. This parameter can be NULL if the client does
      not have such a key/cert pair.
    - pem_roots_cert is the NULL-terminated string containing the PEM encoding of
-     the client root certificates. This parameter may be NULL if the server does
-     not want the client to be authenticated with SSL.
+     the server root certificates.
    - cipher_suites contains an optional list of the ciphers that the client
      supports. The format of this string is described in:
      https://www.openssl.org/docs/apps/ciphers.html.
@@ -79,6 +111,47 @@
     const char** alpn_protocols, uint16_t num_alpn_protocols,
     tsi_ssl_client_handshaker_factory** factory);
 
+typedef struct {
+  /* pem_key_cert_pair is a pointer to the object containing client's private
+     key and certificate chain. This parameter can be NULL if the client does
+     not have such a key/cert pair. */
+  const tsi_ssl_pem_key_cert_pair* pem_key_cert_pair;
+  /* pem_roots_cert is the NULL-terminated string containing the PEM encoding of
+     the client root certificates. */
+  const char* pem_root_certs;
+  /* root_store is a pointer to the ssl_root_certs_store object. If root_store
+    is not nullptr and SSL implementation permits, root_store will be used as
+    root certificates. Otherwise, pem_roots_cert will be used to load server
+    root certificates. */
+  const tsi_ssl_root_certs_store* root_store;
+  /* cipher_suites contains an optional list of the ciphers that the client
+     supports. The format of this string is described in:
+     https://www.openssl.org/docs/apps/ciphers.html.
+     This parameter can be set to NULL to use the default set of ciphers.
+     TODO(jboeuf): Revisit the format of this parameter. */
+  const char* cipher_suites;
+  /* alpn_protocols is an array containing the NULL terminated protocol names
+     that the handshakers created with this factory support. This parameter can
+     be NULL. */
+  const char** alpn_protocols;
+  /* num_alpn_protocols is the number of alpn protocols and associated lengths
+     specified. If this parameter is 0, the other alpn parameters must be
+     NULL. */
+  size_t num_alpn_protocols;
+  /* ssl_session_cache is a cache for reusable client-side sessions. */
+  tsi_ssl_session_cache* session_cache;
+} tsi_ssl_client_handshaker_options;
+
+/* Creates a client handshaker factory.
+   - options is the options used to create a factory.
+   - factory is the address of the factory pointer to be created.
+
+   - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case
+     where a parameter is invalid. */
+tsi_result tsi_create_ssl_client_handshaker_factory_with_options(
+    const tsi_ssl_client_handshaker_options* options,
+    tsi_ssl_client_handshaker_factory** factory);
+
 /* Creates a client handshaker.
   - self is the factory from which the handshaker will be created.
   - server_name_indication indicates the name of the server the client is
@@ -105,12 +178,14 @@
 typedef struct tsi_ssl_server_handshaker_factory
     tsi_ssl_server_handshaker_factory;
 
-/* Creates a server handshaker factory.
+/* TO BE DEPRECATED.
+   Creates a server handshaker factory.
    - pem_key_cert_pairs is an array private key / certificate chains of the
      server.
    - num_key_cert_pairs is the number of items in the pem_key_cert_pairs array.
    - pem_root_certs is the NULL-terminated string containing the PEM encoding
-     of the server root certificates.
+     of the client root certificates. This parameter may be NULL if the server
+     does not want the client to be authenticated with SSL.
    - cipher_suites contains an optional list of the ciphers that the server
      supports. The format of this string is described in:
      https://www.openssl.org/docs/apps/ciphers.html.
@@ -132,7 +207,8 @@
     const char** alpn_protocols, uint16_t num_alpn_protocols,
     tsi_ssl_server_handshaker_factory** factory);
 
-/* Same as tsi_create_ssl_server_handshaker_factory method except uses
+/* TO BE DEPRECATED.
+   Same as tsi_create_ssl_server_handshaker_factory method except uses
    tsi_client_certificate_request_type to support more ways to handle client
    certificate authentication.
    - client_certificate_request, if set to non-zero will force the client to
@@ -145,6 +221,52 @@
     const char* cipher_suites, const char** alpn_protocols,
     uint16_t num_alpn_protocols, tsi_ssl_server_handshaker_factory** factory);
 
+typedef struct {
+  /* pem_key_cert_pairs is an array private key / certificate chains of the
+     server. */
+  const tsi_ssl_pem_key_cert_pair* pem_key_cert_pairs;
+  /* num_key_cert_pairs is the number of items in the pem_key_cert_pairs
+     array. */
+  size_t num_key_cert_pairs;
+  /* pem_root_certs is the NULL-terminated string containing the PEM encoding
+     of the server root certificates. This parameter may be NULL if the server
+     does not want the client to be authenticated with SSL. */
+  const char* pem_client_root_certs;
+  /* client_certificate_request, if set to non-zero will force the client to
+     authenticate with an SSL cert. Note that this option is ignored if
+     pem_client_root_certs is NULL or pem_client_roots_certs_size is 0. */
+  tsi_client_certificate_request_type client_certificate_request;
+  /* cipher_suites contains an optional list of the ciphers that the server
+     supports. The format of this string is described in:
+     https://www.openssl.org/docs/apps/ciphers.html.
+     This parameter can be set to NULL to use the default set of ciphers.
+     TODO(jboeuf): Revisit the format of this parameter. */
+  const char* cipher_suites;
+  /* alpn_protocols is an array containing the NULL terminated protocol names
+     that the handshakers created with this factory support. This parameter can
+     be NULL. */
+  const char** alpn_protocols;
+  /* num_alpn_protocols is the number of alpn protocols and associated lengths
+     specified. If this parameter is 0, the other alpn parameters must be
+     NULL. */
+  uint16_t num_alpn_protocols;
+  /* session_ticket_key is optional key for encrypting session keys. If paramter
+     is not specified it must be NULL. */
+  const char* session_ticket_key;
+  /* session_ticket_key_size is a size of session ticket encryption key. */
+  size_t session_ticket_key_size;
+} tsi_ssl_server_handshaker_options;
+
+/* Creates a server handshaker factory.
+   - options is the options used to create a factory.
+   - factory is the address of the factory pointer to be created.
+
+   - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case
+     where a parameter is invalid. */
+tsi_result tsi_create_ssl_server_handshaker_factory_with_options(
+    const tsi_ssl_server_handshaker_options* options,
+    tsi_ssl_server_handshaker_factory** factory);
+
 /* Creates a server handshaker.
   - self is the factory from which the handshaker will be created.
   - handshaker is the address of the handshaker pointer to be created.
diff --git a/src/core/tsi/ssl_types.h b/src/core/tsi/ssl_types.h
index 3788643..b15d02b 100644
--- a/src/core/tsi/ssl_types.h
+++ b/src/core/tsi/ssl_types.h
@@ -27,6 +27,8 @@
  *                      function
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <openssl/ssl.h>
 
 #ifdef OPENSSL_IS_BORINGSSL
diff --git a/src/core/tsi/transport_security.cc b/src/core/tsi/transport_security.cc
index 5abd2f0..129533f 100644
--- a/src/core/tsi/transport_security.cc
+++ b/src/core/tsi/transport_security.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/tsi/transport_security.h"
 
 #include <grpc/support/alloc.h>
@@ -288,7 +290,7 @@
   *property = tsi_init_peer_property();
   if (name != nullptr) property->name = gpr_strdup(name);
   if (value_length > 0) {
-    property->value.data = (char*)gpr_zalloc(value_length);
+    property->value.data = static_cast<char*>(gpr_zalloc(value_length));
     property->value.length = value_length;
   }
   return TSI_OK;
@@ -316,8 +318,8 @@
 tsi_result tsi_construct_peer(size_t property_count, tsi_peer* peer) {
   memset(peer, 0, sizeof(tsi_peer));
   if (property_count > 0) {
-    peer->properties = (tsi_peer_property*)gpr_zalloc(
-        property_count * sizeof(tsi_peer_property));
+    peer->properties = static_cast<tsi_peer_property*>(
+        gpr_zalloc(property_count * sizeof(tsi_peer_property)));
     peer->property_count = property_count;
   }
   return TSI_OK;
diff --git a/src/core/tsi/transport_security.h b/src/core/tsi/transport_security.h
index ed662d4..b1ec82d 100644
--- a/src/core/tsi/transport_security.h
+++ b/src/core/tsi/transport_security.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_TSI_TRANSPORT_SECURITY_H
 #define GRPC_CORE_TSI_TRANSPORT_SECURITY_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stdbool.h>
 
 #include "src/core/lib/debug/trace.h"
diff --git a/src/core/tsi/transport_security_adapter.cc b/src/core/tsi/transport_security_adapter.cc
index 56dec55..25608f0 100644
--- a/src/core/tsi/transport_security_adapter.cc
+++ b/src/core/tsi/transport_security_adapter.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/tsi/transport_security_adapter.h"
 
 #include <string.h>
@@ -59,7 +61,8 @@
 }
 
 static void adapter_result_destroy(tsi_handshaker_result* self) {
-  tsi_adapter_handshaker_result* impl = (tsi_adapter_handshaker_result*)self;
+  tsi_adapter_handshaker_result* impl =
+      reinterpret_cast<tsi_adapter_handshaker_result*>(self);
   tsi_handshaker_destroy(impl->wrapped);
   gpr_free(impl->unused_bytes);
   gpr_free(self);
@@ -82,12 +85,13 @@
     return TSI_INVALID_ARGUMENT;
   }
   tsi_adapter_handshaker_result* impl =
-      (tsi_adapter_handshaker_result*)gpr_zalloc(sizeof(*impl));
+      static_cast<tsi_adapter_handshaker_result*>(gpr_zalloc(sizeof(*impl)));
   impl->base.vtable = &result_vtable;
   impl->wrapped = wrapped;
   impl->unused_bytes_size = unused_bytes_size;
   if (unused_bytes_size > 0) {
-    impl->unused_bytes = (unsigned char*)gpr_malloc(unused_bytes_size);
+    impl->unused_bytes =
+        static_cast<unsigned char*>(gpr_malloc(unused_bytes_size));
     memcpy(impl->unused_bytes, unused_bytes, unused_bytes_size);
   } else {
     impl->unused_bytes = nullptr;
@@ -137,7 +141,8 @@
 }
 
 static void adapter_destroy(tsi_handshaker* self) {
-  tsi_adapter_handshaker* impl = (tsi_adapter_handshaker*)self;
+  tsi_adapter_handshaker* impl =
+      reinterpret_cast<tsi_adapter_handshaker*>(self);
   tsi_handshaker_destroy(impl->wrapped);
   gpr_free(impl->adapter_buffer);
   gpr_free(self);
@@ -156,7 +161,8 @@
   }
 
   /* If there are received bytes, process them first.  */
-  tsi_adapter_handshaker* impl = (tsi_adapter_handshaker*)self;
+  tsi_adapter_handshaker* impl =
+      reinterpret_cast<tsi_adapter_handshaker*>(self);
   tsi_result status = TSI_OK;
   size_t bytes_consumed = received_bytes_size;
   if (received_bytes_size > 0) {
@@ -174,8 +180,8 @@
     offset += to_send_size;
     if (status == TSI_INCOMPLETE_DATA) {
       impl->adapter_buffer_size *= 2;
-      impl->adapter_buffer = (unsigned char*)gpr_realloc(
-          impl->adapter_buffer, impl->adapter_buffer_size);
+      impl->adapter_buffer = static_cast<unsigned char*>(
+          gpr_realloc(impl->adapter_buffer, impl->adapter_buffer_size));
     }
   } while (status == TSI_INCOMPLETE_DATA);
   if (status != TSI_OK) return status;
@@ -212,16 +218,18 @@
 tsi_handshaker* tsi_create_adapter_handshaker(tsi_handshaker* wrapped) {
   GPR_ASSERT(wrapped != nullptr);
   tsi_adapter_handshaker* impl =
-      (tsi_adapter_handshaker*)gpr_zalloc(sizeof(*impl));
+      static_cast<tsi_adapter_handshaker*>(gpr_zalloc(sizeof(*impl)));
   impl->base.vtable = &handshaker_vtable;
   impl->wrapped = wrapped;
   impl->adapter_buffer_size = TSI_ADAPTER_INITIAL_BUFFER_SIZE;
-  impl->adapter_buffer = (unsigned char*)gpr_malloc(impl->adapter_buffer_size);
+  impl->adapter_buffer =
+      static_cast<unsigned char*>(gpr_malloc(impl->adapter_buffer_size));
   return &impl->base;
 }
 
 tsi_handshaker* tsi_adapter_handshaker_get_wrapped(tsi_handshaker* adapter) {
   if (adapter == nullptr) return nullptr;
-  tsi_adapter_handshaker* impl = (tsi_adapter_handshaker*)adapter;
+  tsi_adapter_handshaker* impl =
+      reinterpret_cast<tsi_adapter_handshaker*>(adapter);
   return impl->wrapped;
 }
diff --git a/src/core/tsi/transport_security_adapter.h b/src/core/tsi/transport_security_adapter.h
index 9818fce..f83ecc5 100644
--- a/src/core/tsi/transport_security_adapter.h
+++ b/src/core/tsi/transport_security_adapter.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_TSI_TRANSPORT_SECURITY_ADAPTER_H
 #define GRPC_CORE_TSI_TRANSPORT_SECURITY_ADAPTER_H
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/tsi/transport_security_interface.h"
 
 /* Create a tsi handshaker that takes an implementation of old interface and
diff --git a/src/core/tsi/transport_security_grpc.cc b/src/core/tsi/transport_security_grpc.cc
index 76f7ae7..c73a6e3 100644
--- a/src/core/tsi/transport_security_grpc.cc
+++ b/src/core/tsi/transport_security_grpc.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/tsi/transport_security_grpc.h"
 
 /* This method creates a tsi_zero_copy_grpc_protector object.  */
diff --git a/src/core/tsi/transport_security_grpc.h b/src/core/tsi/transport_security_grpc.h
index 0156ff1..d3bb04d 100644
--- a/src/core/tsi/transport_security_grpc.h
+++ b/src/core/tsi/transport_security_grpc.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_TSI_TRANSPORT_SECURITY_GRPC_H
 #define GRPC_CORE_TSI_TRANSPORT_SECURITY_GRPC_H
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice_buffer.h>
 #include "src/core/tsi/transport_security.h"
 
diff --git a/src/core/tsi/transport_security_interface.h b/src/core/tsi/transport_security_interface.h
index e925598..8c10866 100644
--- a/src/core/tsi/transport_security_interface.h
+++ b/src/core/tsi/transport_security_interface.h
@@ -19,6 +19,8 @@
 #ifndef GRPC_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H
 #define GRPC_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H
 
+#include <grpc/support/port_platform.h>
+
 #include <stdint.h>
 #include <stdlib.h>
 
diff --git a/src/cpp/README.md b/src/cpp/README.md
index d2896ad..ac76bf7 100644
--- a/src/cpp/README.md
+++ b/src/cpp/README.md
@@ -3,56 +3,9 @@
 
 This directory contains source code for C++ implementation of gRPC.
 
-# Pre-requisites
-
-## Linux
-
-```sh
- $ [sudo] apt-get install build-essential autoconf libtool
-```
-
-## Mac OSX
-
-For a Mac system, git is not available by default. You will first need to
-install Xcode from the Mac AppStore and then run the following command from a
-terminal:
-
-```sh
- $ [sudo] xcode-select --install
-```
-
-## Protoc
-
-By default gRPC uses [protocol buffers](https://github.com/google/protobuf),
-you will need the `protoc` compiler to generate stub server and client code.
-
-If you compile gRPC from source, as described below, this also installs the
-`protoc` compiler.
-
-If it hasn't been installed, you can run the following commands to install it.
-
-```sh
-$ cd grpc/third_party/protobuf
-$ sudo make install   # 'make' should have been run by core grpc
-```
-
-Alternatively, you can download `protoc` binaries from
-[the protocol buffers Github repository](https://github.com/google/protobuf/releases).
-
-# Installation
-
-Currently to install gRPC for C++, you need to build from source as described
-below.
-
-# Build from Source
-
-```sh
- $ git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc
- $ cd grpc
- $ git submodule update --init
- $ make
- $ [sudo] make install
-```
+To install gRPC for C++ on your system, follow the instructions to build from source
+[here](../../INSTALL.md). This also installs the protocol buffer compiler
+`protoc` (if you don't have it already), and the C++ gRPC plugin for `protoc`.
 
 # Documentation
 
diff --git a/src/cpp/client/channel_cc.cc b/src/cpp/client/channel_cc.cc
index 362dff6..867f31f 100644
--- a/src/cpp/client/channel_cc.cc
+++ b/src/cpp/client/channel_cc.cc
@@ -16,34 +16,33 @@
  *
  */
 
-#include <grpc++/channel.h>
+#include <grpcpp/channel.h>
 
 #include <chrono>
 #include <condition_variable>
 #include <memory>
 #include <mutex>
 
-#include <grpc++/client_context.h>
-#include <grpc++/completion_queue.h>
-#include <grpc++/impl/call.h>
-#include <grpc++/impl/codegen/completion_queue_tag.h>
-#include <grpc++/impl/grpc_library.h>
-#include <grpc++/impl/rpc_method.h>
-#include <grpc++/security/credentials.h>
-#include <grpc++/support/channel_arguments.h>
-#include <grpc++/support/config.h>
-#include <grpc++/support/status.h>
-#include <grpc++/support/time.h>
 #include <grpc/grpc.h>
 #include <grpc/slice.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/completion_queue.h>
+#include <grpcpp/impl/call.h>
+#include <grpcpp/impl/codegen/completion_queue_tag.h>
+#include <grpcpp/impl/grpc_library.h>
+#include <grpcpp/impl/rpc_method.h>
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/support/channel_arguments.h>
+#include <grpcpp/support/config.h>
+#include <grpcpp/support/status.h>
+#include <grpcpp/support/time.h>
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/profiling/timers.h"
 
 namespace grpc {
diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc
index dafa808..07a04e4 100644
--- a/src/cpp/client/client_context.cc
+++ b/src/cpp/client/client_context.cc
@@ -16,7 +16,7 @@
  *
  */
 
-#include <grpc++/client_context.h>
+#include <grpcpp/client_context.h>
 
 #include <grpc/compression.h>
 #include <grpc/grpc.h>
@@ -24,10 +24,10 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
-#include <grpc++/impl/grpc_library.h>
-#include <grpc++/security/credentials.h>
-#include <grpc++/server_context.h>
-#include <grpc++/support/time.h>
+#include <grpcpp/impl/grpc_library.h>
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/server_context.h>
+#include <grpcpp/support/time.h>
 
 namespace grpc {
 
@@ -96,6 +96,7 @@
 
 void ClientContext::set_compression_algorithm(
     grpc_compression_algorithm algorithm) {
+  compression_algorithm_ = algorithm;
   const char* algorithm_name = nullptr;
   if (!grpc_compression_algorithm_name(algorithm, &algorithm_name)) {
     gpr_log(GPR_ERROR, "Name for compression algorithm '%d' unknown.",
diff --git a/src/cpp/client/create_channel.cc b/src/cpp/client/create_channel.cc
index 9323315..67a46ce 100644
--- a/src/cpp/client/create_channel.cc
+++ b/src/cpp/client/create_channel.cc
@@ -18,10 +18,10 @@
 
 #include <memory>
 
-#include <grpc++/channel.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/impl/grpc_library.h>
-#include <grpc++/support/channel_arguments.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/impl/grpc_library.h>
+#include <grpcpp/support/channel_arguments.h>
 
 #include "src/cpp/client/create_channel_internal.h"
 
diff --git a/src/cpp/client/create_channel_internal.cc b/src/cpp/client/create_channel_internal.cc
index 89e2f8d..aa96edfc 100644
--- a/src/cpp/client/create_channel_internal.cc
+++ b/src/cpp/client/create_channel_internal.cc
@@ -18,7 +18,7 @@
 
 #include <memory>
 
-#include <grpc++/channel.h>
+#include <grpcpp/channel.h>
 
 struct grpc_channel;
 
diff --git a/src/cpp/client/create_channel_internal.h b/src/cpp/client/create_channel_internal.h
index 2cb3163..86e8167 100644
--- a/src/cpp/client/create_channel_internal.h
+++ b/src/cpp/client/create_channel_internal.h
@@ -21,7 +21,7 @@
 
 #include <memory>
 
-#include <grpc++/support/config.h>
+#include <grpcpp/support/config.h>
 
 struct grpc_channel;
 
diff --git a/src/cpp/client/create_channel_posix.cc b/src/cpp/client/create_channel_posix.cc
index cea002f..f9285c9 100644
--- a/src/cpp/client/create_channel_posix.cc
+++ b/src/cpp/client/create_channel_posix.cc
@@ -16,11 +16,11 @@
  *
  */
 
-#include <grpc++/channel.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/impl/grpc_library.h>
 #include <grpc/grpc.h>
 #include <grpc/grpc_posix.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/impl/grpc_library.h>
 
 #include "src/cpp/client/create_channel_internal.h"
 
diff --git a/src/cpp/client/credentials_cc.cc b/src/cpp/client/credentials_cc.cc
index 8d69242..2a0f06f 100644
--- a/src/cpp/client/credentials_cc.cc
+++ b/src/cpp/client/credentials_cc.cc
@@ -16,8 +16,8 @@
  *
  */
 
-#include <grpc++/impl/grpc_library.h>
-#include <grpc++/security/credentials.h>
+#include <grpcpp/impl/grpc_library.h>
+#include <grpcpp/security/credentials.h>
 
 namespace grpc {
 
diff --git a/src/cpp/client/cronet_credentials.cc b/src/cpp/client/cronet_credentials.cc
index a874a6e..5c65ad0 100644
--- a/src/cpp/client/cronet_credentials.cc
+++ b/src/cpp/client/cronet_credentials.cc
@@ -16,11 +16,11 @@
  *
  */
 
-#include <grpc++/security/credentials.h>
+#include <grpcpp/security/credentials.h>
 
-#include <grpc++/channel.h>
-#include <grpc++/support/channel_arguments.h>
 #include <grpc/grpc_cronet.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/support/channel_arguments.h>
 #include "src/cpp/client/create_channel_internal.h"
 
 namespace grpc {
diff --git a/src/cpp/client/generic_stub.cc b/src/cpp/client/generic_stub.cc
index 4b4b8dd..67ef46b 100644
--- a/src/cpp/client/generic_stub.cc
+++ b/src/cpp/client/generic_stub.cc
@@ -16,9 +16,9 @@
  *
  */
 
-#include <grpc++/generic/generic_stub.h>
+#include <grpcpp/generic/generic_stub.h>
 
-#include <grpc++/impl/rpc_method.h>
+#include <grpcpp/impl/rpc_method.h>
 
 namespace grpc {
 
diff --git a/src/cpp/client/insecure_credentials.cc b/src/cpp/client/insecure_credentials.cc
index 2112844..04dc5c0 100644
--- a/src/cpp/client/insecure_credentials.cc
+++ b/src/cpp/client/insecure_credentials.cc
@@ -16,13 +16,13 @@
  *
  */
 
-#include <grpc++/security/credentials.h>
+#include <grpcpp/security/credentials.h>
 
-#include <grpc++/channel.h>
-#include <grpc++/support/channel_arguments.h>
-#include <grpc++/support/config.h>
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/support/channel_arguments.h>
+#include <grpcpp/support/config.h>
 #include "src/cpp/client/create_channel_internal.h"
 
 namespace grpc {
diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc
index 4fb128d..19d67c2 100644
--- a/src/cpp/client/secure_credentials.cc
+++ b/src/cpp/client/secure_credentials.cc
@@ -17,11 +17,11 @@
  */
 
 #include "src/cpp/client/secure_credentials.h"
-#include <grpc++/channel.h>
-#include <grpc++/impl/grpc_library.h>
-#include <grpc++/support/channel_arguments.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/impl/grpc_library.h>
+#include <grpcpp/support/channel_arguments.h>
 #include "src/cpp/client/create_channel_internal.h"
 #include "src/cpp/common/secure_auth_context.h"
 
@@ -168,7 +168,7 @@
 void MetadataCredentialsPluginWrapper::Destroy(void* wrapper) {
   if (wrapper == nullptr) return;
   MetadataCredentialsPluginWrapper* w =
-      reinterpret_cast<MetadataCredentialsPluginWrapper*>(wrapper);
+      static_cast<MetadataCredentialsPluginWrapper*>(wrapper);
   delete w;
 }
 
@@ -180,7 +180,7 @@
     const char** error_details) {
   GPR_ASSERT(wrapper);
   MetadataCredentialsPluginWrapper* w =
-      reinterpret_cast<MetadataCredentialsPluginWrapper*>(wrapper);
+      static_cast<MetadataCredentialsPluginWrapper*>(wrapper);
   if (!w->plugin_) {
     *num_creds_md = 0;
     *status = GRPC_STATUS_OK;
diff --git a/src/cpp/client/secure_credentials.h b/src/cpp/client/secure_credentials.h
index ed9afb3..85cb542 100644
--- a/src/cpp/client/secure_credentials.h
+++ b/src/cpp/client/secure_credentials.h
@@ -21,8 +21,8 @@
 
 #include <grpc/grpc_security.h>
 
-#include <grpc++/security/credentials.h>
-#include <grpc++/support/config.h>
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/support/config.h>
 
 #include "src/cpp/server/thread_pool_interface.h"
 
diff --git a/src/cpp/codegen/codegen_init.cc b/src/cpp/codegen/codegen_init.cc
index 2da1556..684d721 100644
--- a/src/cpp/codegen/codegen_init.cc
+++ b/src/cpp/codegen/codegen_init.cc
@@ -16,8 +16,8 @@
  *
  */
 
-#include <grpc++/impl/codegen/core_codegen_interface.h>
-#include <grpc++/impl/codegen/grpc_library.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/grpc_library.h>
 
 /// Null-initializes the global gRPC variables for the codegen library. These
 /// stay null in the absence of of grpc++ library. In this case, no gRPC
diff --git a/src/cpp/common/alarm.cc b/src/cpp/common/alarm.cc
index 0eecbb6..15a373d 100644
--- a/src/cpp/common/alarm.cc
+++ b/src/cpp/common/alarm.cc
@@ -15,15 +15,15 @@
  *
  */
 
-#include <grpc++/alarm.h>
+#include <grpcpp/alarm.h>
 
 #include <memory>
 
-#include <grpc++/completion_queue.h>
-#include <grpc++/impl/grpc_library.h>
-#include <grpc++/support/time.h>
 #include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
+#include <grpcpp/completion_queue.h>
+#include <grpcpp/impl/grpc_library.h>
+#include <grpcpp/support/time.h>
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/surface/completion_queue.h"
diff --git a/src/cpp/common/auth_property_iterator.cc b/src/cpp/common/auth_property_iterator.cc
index 4f0948c..fbb18e9 100644
--- a/src/cpp/common/auth_property_iterator.cc
+++ b/src/cpp/common/auth_property_iterator.cc
@@ -16,7 +16,7 @@
  *
  */
 
-#include <grpc++/security/auth_context.h>
+#include <grpcpp/security/auth_context.h>
 
 #include <grpc/grpc_security.h>
 
diff --git a/src/cpp/common/channel_arguments.cc b/src/cpp/common/channel_arguments.cc
index b696774..50ee9d8 100644
--- a/src/cpp/common/channel_arguments.cc
+++ b/src/cpp/common/channel_arguments.cc
@@ -15,14 +15,14 @@
  * limitations under the License.
  *
  */
-#include <grpc++/support/channel_arguments.h>
+#include <grpcpp/support/channel_arguments.h>
 
 #include <sstream>
 
-#include <grpc++/grpc++.h>
-#include <grpc++/resource_quota.h>
 #include <grpc/impl/codegen/grpc_types.h>
 #include <grpc/support/log.h>
+#include <grpcpp/grpcpp.h>
+#include <grpcpp/resource_quota.h>
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/socket_mutator.h"
diff --git a/src/cpp/common/channel_filter.cc b/src/cpp/common/channel_filter.cc
index cbe2a20..422e7bb 100644
--- a/src/cpp/common/channel_filter.cc
+++ b/src/cpp/common/channel_filter.cc
@@ -21,7 +21,7 @@
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/cpp/common/channel_filter.h"
 
-#include <grpc++/impl/codegen/slice.h>
+#include <grpcpp/impl/codegen/slice.h>
 
 namespace grpc {
 
@@ -72,7 +72,7 @@
 namespace {
 
 bool MaybeAddFilter(grpc_channel_stack_builder* builder, void* arg) {
-  const FilterRecord& filter = *(FilterRecord*)arg;
+  const FilterRecord& filter = *static_cast<FilterRecord*>(arg);
   if (filter.include_filter) {
     const grpc_channel_args* args =
         grpc_channel_stack_builder_get_channel_arguments(builder);
diff --git a/src/cpp/common/channel_filter.h b/src/cpp/common/channel_filter.h
index a1f42c0..bd0ec96 100644
--- a/src/cpp/common/channel_filter.h
+++ b/src/cpp/common/channel_filter.h
@@ -19,9 +19,9 @@
 #ifndef GRPCXX_CHANNEL_FILTER_H
 #define GRPCXX_CHANNEL_FILTER_H
 
-#include <grpc++/impl/codegen/config.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
+#include <grpcpp/impl/codegen/config.h>
 
 #include <functional>
 #include <vector>
@@ -182,26 +182,29 @@
     op_->payload->recv_initial_metadata.recv_initial_metadata_ready = closure;
   }
 
-  grpc_byte_stream* send_message() const {
-    return op_->send_message ? op_->payload->send_message.send_message
+  grpc_core::OrphanablePtr<grpc_core::ByteStream>* send_message() const {
+    return op_->send_message ? &op_->payload->send_message.send_message
                              : nullptr;
   }
-  void set_send_message(grpc_byte_stream* send_message) {
+  void set_send_message(
+      grpc_core::OrphanablePtr<grpc_core::ByteStream> send_message) {
     op_->send_message = true;
-    op_->payload->send_message.send_message = send_message;
+    op_->payload->send_message.send_message = std::move(send_message);
   }
 
-  grpc_byte_stream** recv_message() const {
+  grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message() const {
     return op_->recv_message ? op_->payload->recv_message.recv_message
                              : nullptr;
   }
-  void set_recv_message(grpc_byte_stream** recv_message) {
+  void set_recv_message(
+      grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message) {
     op_->recv_message = true;
     op_->payload->recv_message.recv_message = recv_message;
   }
 
   census_context* get_census_context() const {
-    return (census_context*)op_->payload->context[GRPC_CONTEXT_TRACING].value;
+    return static_cast<census_context*>(
+        op_->payload->context[GRPC_CONTEXT_TRACING].value);
   }
 
  private:
@@ -282,7 +285,7 @@
 
   static void DestroyChannelElement(grpc_channel_element* elem) {
     ChannelDataType* channel_data =
-        reinterpret_cast<ChannelDataType*>(elem->channel_data);
+        static_cast<ChannelDataType*>(elem->channel_data);
     channel_data->Destroy(elem);
     channel_data->~ChannelDataType();
   }
@@ -290,7 +293,7 @@
   static void StartTransportOp(grpc_channel_element* elem,
                                grpc_transport_op* op) {
     ChannelDataType* channel_data =
-        reinterpret_cast<ChannelDataType*>(elem->channel_data);
+        static_cast<ChannelDataType*>(elem->channel_data);
     TransportOp op_wrapper(op);
     channel_data->StartTransportOp(elem, &op_wrapper);
   }
@@ -298,7 +301,7 @@
   static void GetChannelInfo(grpc_channel_element* elem,
                              const grpc_channel_info* channel_info) {
     ChannelDataType* channel_data =
-        reinterpret_cast<ChannelDataType*>(elem->channel_data);
+        static_cast<ChannelDataType*>(elem->channel_data);
     channel_data->GetInfo(elem, channel_info);
   }
 
@@ -314,21 +317,21 @@
   static void DestroyCallElement(grpc_call_element* elem,
                                  const grpc_call_final_info* final_info,
                                  grpc_closure* then_call_closure) {
-    CallDataType* call_data = reinterpret_cast<CallDataType*>(elem->call_data);
+    CallDataType* call_data = static_cast<CallDataType*>(elem->call_data);
     call_data->Destroy(elem, final_info, then_call_closure);
     call_data->~CallDataType();
   }
 
   static void StartTransportStreamOpBatch(grpc_call_element* elem,
                                           grpc_transport_stream_op_batch* op) {
-    CallDataType* call_data = reinterpret_cast<CallDataType*>(elem->call_data);
+    CallDataType* call_data = static_cast<CallDataType*>(elem->call_data);
     TransportStreamOpBatch op_wrapper(op);
     call_data->StartTransportStreamOpBatch(elem, &op_wrapper);
   }
 
   static void SetPollsetOrPollsetSet(grpc_call_element* elem,
                                      grpc_polling_entity* pollent) {
-    CallDataType* call_data = reinterpret_cast<CallDataType*>(elem->call_data);
+    CallDataType* call_data = static_cast<CallDataType*>(elem->call_data);
     call_data->SetPollsetOrPollsetSet(elem, pollent);
   }
 };
diff --git a/src/cpp/common/completion_queue_cc.cc b/src/cpp/common/completion_queue_cc.cc
index eb6dc8c..6893201 100644
--- a/src/cpp/common/completion_queue_cc.cc
+++ b/src/cpp/common/completion_queue_cc.cc
@@ -15,14 +15,14 @@
  *
  */
 
-#include <grpc++/completion_queue.h>
+#include <grpcpp/completion_queue.h>
 
 #include <memory>
 
-#include <grpc++/impl/grpc_library.h>
-#include <grpc++/support/time.h>
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
+#include <grpcpp/impl/grpc_library.h>
+#include <grpcpp/support/time.h>
 
 namespace grpc {
 
diff --git a/src/cpp/common/core_codegen.cc b/src/cpp/common/core_codegen.cc
index 936d699..aa9788d 100644
--- a/src/cpp/common/core_codegen.cc
+++ b/src/cpp/common/core_codegen.cc
@@ -16,11 +16,10 @@
  *
  */
 
-#include <grpc++/impl/codegen/core_codegen.h>
+#include <grpcpp/impl/codegen/core_codegen.h>
 
 #include <stdlib.h>
 
-#include <grpc++/support/config.h>
 #include <grpc/byte_buffer.h>
 #include <grpc/byte_buffer_reader.h>
 #include <grpc/grpc.h>
@@ -30,6 +29,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
 #include <grpc/support/sync.h>
+#include <grpcpp/support/config.h>
 
 #include "src/core/lib/profiling/timers.h"
 
diff --git a/src/cpp/common/insecure_create_auth_context.cc b/src/cpp/common/insecure_create_auth_context.cc
index 28de47b..4e5cbd0 100644
--- a/src/cpp/common/insecure_create_auth_context.cc
+++ b/src/cpp/common/insecure_create_auth_context.cc
@@ -17,8 +17,8 @@
  */
 #include <memory>
 
-#include <grpc++/security/auth_context.h>
 #include <grpc/grpc.h>
+#include <grpcpp/security/auth_context.h>
 
 namespace grpc {
 
diff --git a/src/cpp/common/resource_quota_cc.cc b/src/cpp/common/resource_quota_cc.cc
index 0e9be15..daeb0ba 100644
--- a/src/cpp/common/resource_quota_cc.cc
+++ b/src/cpp/common/resource_quota_cc.cc
@@ -16,8 +16,8 @@
  *
  */
 
-#include <grpc++/resource_quota.h>
 #include <grpc/grpc.h>
+#include <grpcpp/resource_quota.h>
 
 namespace grpc {
 
diff --git a/src/cpp/common/rpc_method.cc b/src/cpp/common/rpc_method.cc
index d00339a..a47dd3e 100644
--- a/src/cpp/common/rpc_method.cc
+++ b/src/cpp/common/rpc_method.cc
@@ -16,6 +16,6 @@
  *
  */
 
-#include <grpc++/impl/rpc_method.h>
+#include <grpcpp/impl/rpc_method.h>
 
 namespace grpc {}  // namespace grpc
diff --git a/src/cpp/common/secure_auth_context.h b/src/cpp/common/secure_auth_context.h
index 0aea642..1426179 100644
--- a/src/cpp/common/secure_auth_context.h
+++ b/src/cpp/common/secure_auth_context.h
@@ -19,7 +19,7 @@
 #ifndef GRPC_INTERNAL_CPP_COMMON_SECURE_AUTH_CONTEXT_H
 #define GRPC_INTERNAL_CPP_COMMON_SECURE_AUTH_CONTEXT_H
 
-#include <grpc++/security/auth_context.h>
+#include <grpcpp/security/auth_context.h>
 
 struct grpc_auth_context;
 
diff --git a/src/cpp/common/secure_channel_arguments.cc b/src/cpp/common/secure_channel_arguments.cc
index f6cd584..2fb8ea4 100644
--- a/src/cpp/common/secure_channel_arguments.cc
+++ b/src/cpp/common/secure_channel_arguments.cc
@@ -16,7 +16,7 @@
  *
  */
 
-#include <grpc++/support/channel_arguments.h>
+#include <grpcpp/support/channel_arguments.h>
 
 #include <grpc/grpc_security.h>
 #include "src/core/lib/channel/channel_args.h"
diff --git a/src/cpp/common/secure_create_auth_context.cc b/src/cpp/common/secure_create_auth_context.cc
index 4b9e39a..bc1387c 100644
--- a/src/cpp/common/secure_create_auth_context.cc
+++ b/src/cpp/common/secure_create_auth_context.cc
@@ -17,9 +17,9 @@
  */
 #include <memory>
 
-#include <grpc++/security/auth_context.h>
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
+#include <grpcpp/security/auth_context.h>
 #include "src/cpp/common/secure_auth_context.h"
 
 namespace grpc {
diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc
index 8bc9260..fb1723c 100644
--- a/src/cpp/common/version_cc.cc
+++ b/src/cpp/common/version_cc.cc
@@ -19,8 +19,8 @@
 /* This file is autogenerated from:
    templates/src/core/surface/version.c.template */
 
-#include <grpc++/grpc++.h>
+#include <grpcpp/grpcpp.h>
 
 namespace grpc {
-grpc::string Version() { return "1.10.0-dev"; }
+grpc::string Version() { return "1.11.0-dev"; }
 }  // namespace grpc
diff --git a/src/cpp/ext/proto_server_reflection.cc b/src/cpp/ext/proto_server_reflection.cc
index e612211..f26f007 100644
--- a/src/cpp/ext/proto_server_reflection.cc
+++ b/src/cpp/ext/proto_server_reflection.cc
@@ -19,7 +19,7 @@
 #include <unordered_set>
 #include <vector>
 
-#include <grpc++/grpc++.h>
+#include <grpcpp/grpcpp.h>
 
 #include "src/cpp/ext/proto_server_reflection.h"
 
diff --git a/src/cpp/ext/proto_server_reflection.h b/src/cpp/ext/proto_server_reflection.h
index ee2327c..bf40c3c 100644
--- a/src/cpp/ext/proto_server_reflection.h
+++ b/src/cpp/ext/proto_server_reflection.h
@@ -22,7 +22,7 @@
 #include <unordered_set>
 #include <vector>
 
-#include <grpc++/grpc++.h>
+#include <grpcpp/grpcpp.h>
 #include "src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.h"
 
 namespace grpc {
diff --git a/src/cpp/ext/proto_server_reflection_plugin.cc b/src/cpp/ext/proto_server_reflection_plugin.cc
index c299661..ee3ac3f 100644
--- a/src/cpp/ext/proto_server_reflection_plugin.cc
+++ b/src/cpp/ext/proto_server_reflection_plugin.cc
@@ -16,10 +16,10 @@
  *
  */
 
-#include <grpc++/ext/proto_server_reflection_plugin.h>
-#include <grpc++/impl/server_builder_plugin.h>
-#include <grpc++/impl/server_initializer.h>
-#include <grpc++/server.h>
+#include <grpcpp/ext/proto_server_reflection_plugin.h>
+#include <grpcpp/impl/server_builder_plugin.h>
+#include <grpcpp/impl/server_initializer.h>
+#include <grpcpp/server.h>
 
 #include "src/cpp/ext/proto_server_reflection.h"
 
diff --git a/src/cpp/server/async_generic_service.cc b/src/cpp/server/async_generic_service.cc
index 998f516..3061376 100644
--- a/src/cpp/server/async_generic_service.cc
+++ b/src/cpp/server/async_generic_service.cc
@@ -16,9 +16,9 @@
  *
  */
 
-#include <grpc++/generic/async_generic_service.h>
+#include <grpcpp/generic/async_generic_service.h>
 
-#include <grpc++/server.h>
+#include <grpcpp/server.h>
 
 namespace grpc {
 
diff --git a/src/cpp/server/channel_argument_option.cc b/src/cpp/server/channel_argument_option.cc
index dcad253..4d6be90 100644
--- a/src/cpp/server/channel_argument_option.cc
+++ b/src/cpp/server/channel_argument_option.cc
@@ -16,7 +16,7 @@
  *
  */
 
-#include <grpc++/impl/channel_argument_option.h>
+#include <grpcpp/impl/channel_argument_option.h>
 
 namespace grpc {
 
diff --git a/src/cpp/server/dynamic_thread_pool.cc b/src/cpp/server/dynamic_thread_pool.cc
index 81c78fe..ef99d64 100644
--- a/src/cpp/server/dynamic_thread_pool.cc
+++ b/src/cpp/server/dynamic_thread_pool.cc
@@ -19,20 +19,23 @@
 #include "src/cpp/server/dynamic_thread_pool.h"
 
 #include <mutex>
-#include <thread>
 
 #include <grpc/support/log.h>
 
+#include "src/core/lib/gprpp/thd.h"
+
 namespace grpc {
 
 DynamicThreadPool::DynamicThread::DynamicThread(DynamicThreadPool* pool)
     : pool_(pool),
-      thd_(new std::thread(&DynamicThreadPool::DynamicThread::ThreadFunc,
-                           this)) {}
-DynamicThreadPool::DynamicThread::~DynamicThread() {
-  thd_->join();
-  thd_.reset();
+      thd_("grpcpp_dynamic_pool",
+           [](void* th) {
+             static_cast<DynamicThreadPool::DynamicThread*>(th)->ThreadFunc();
+           },
+           this) {
+  thd_.Start();
 }
+DynamicThreadPool::DynamicThread::~DynamicThread() { thd_.Join(); }
 
 void DynamicThreadPool::DynamicThread::ThreadFunc() {
   pool_->ThreadFunc();
diff --git a/src/cpp/server/dynamic_thread_pool.h b/src/cpp/server/dynamic_thread_pool.h
index 9237c6e..5df8cf2 100644
--- a/src/cpp/server/dynamic_thread_pool.h
+++ b/src/cpp/server/dynamic_thread_pool.h
@@ -24,10 +24,10 @@
 #include <memory>
 #include <mutex>
 #include <queue>
-#include <thread>
 
-#include <grpc++/support/config.h>
+#include <grpcpp/support/config.h>
 
+#include "src/core/lib/gprpp/thd.h"
 #include "src/cpp/server/thread_pool_interface.h"
 
 namespace grpc {
@@ -47,7 +47,7 @@
 
    private:
     DynamicThreadPool* pool_;
-    std::unique_ptr<std::thread> thd_;
+    grpc_core::Thread thd_;
     void ThreadFunc();
   };
   std::mutex mu_;
diff --git a/src/cpp/server/health/default_health_check_service.cc b/src/cpp/server/health/default_health_check_service.cc
index 10dbd3c..0b45a8b 100644
--- a/src/cpp/server/health/default_health_check_service.cc
+++ b/src/cpp/server/health/default_health_check_service.cc
@@ -19,10 +19,10 @@
 #include <memory>
 #include <mutex>
 
-#include <grpc++/impl/codegen/method_handler_impl.h>
 #include <grpc/slice.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include <grpcpp/impl/codegen/method_handler_impl.h>
 
 #include "src/cpp/server/health/default_health_check_service.h"
 #include "src/cpp/server/health/health.pb.h"
diff --git a/src/cpp/server/health/default_health_check_service.h b/src/cpp/server/health/default_health_check_service.h
index 99d6680..a1ce5aa 100644
--- a/src/cpp/server/health/default_health_check_service.h
+++ b/src/cpp/server/health/default_health_check_service.h
@@ -21,9 +21,9 @@
 
 #include <mutex>
 
-#include <grpc++/health_check_service_interface.h>
-#include <grpc++/impl/codegen/service_type.h>
-#include <grpc++/support/byte_buffer.h>
+#include <grpcpp/health_check_service_interface.h>
+#include <grpcpp/impl/codegen/service_type.h>
+#include <grpcpp/support/byte_buffer.h>
 
 namespace grpc {
 
diff --git a/src/cpp/server/health/health_check_service.cc b/src/cpp/server/health/health_check_service.cc
index a34b533..a0fa2d6 100644
--- a/src/cpp/server/health/health_check_service.cc
+++ b/src/cpp/server/health/health_check_service.cc
@@ -16,7 +16,7 @@
  *
  */
 
-#include <grpc++/health_check_service_interface.h>
+#include <grpcpp/health_check_service_interface.h>
 
 namespace grpc {
 namespace {
diff --git a/src/cpp/server/health/health_check_service_server_builder_option.cc b/src/cpp/server/health/health_check_service_server_builder_option.cc
index a722eea..7148265 100644
--- a/src/cpp/server/health/health_check_service_server_builder_option.cc
+++ b/src/cpp/server/health/health_check_service_server_builder_option.cc
@@ -16,7 +16,7 @@
  *
  */
 
-#include <grpc++/ext/health_check_service_server_builder_option.h>
+#include <grpcpp/ext/health_check_service_server_builder_option.h>
 
 namespace grpc {
 
diff --git a/src/cpp/server/insecure_server_credentials.cc b/src/cpp/server/insecure_server_credentials.cc
index 87605f8..7d749dd 100644
--- a/src/cpp/server/insecure_server_credentials.cc
+++ b/src/cpp/server/insecure_server_credentials.cc
@@ -16,7 +16,7 @@
  *
  */
 
-#include <grpc++/security/server_credentials.h>
+#include <grpcpp/security/server_credentials.h>
 
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
diff --git a/src/cpp/server/secure_server_credentials.cc b/src/cpp/server/secure_server_credentials.cc
index 0fbe4cc..1887109 100644
--- a/src/cpp/server/secure_server_credentials.cc
+++ b/src/cpp/server/secure_server_credentials.cc
@@ -20,8 +20,8 @@
 #include <map>
 #include <memory>
 
-#include <grpc++/impl/codegen/slice.h>
-#include <grpc++/security/auth_metadata_processor.h>
+#include <grpcpp/impl/codegen/slice.h>
+#include <grpcpp/security/auth_metadata_processor.h>
 
 #include "src/cpp/common/secure_auth_context.h"
 #include "src/cpp/server/secure_server_credentials.h"
@@ -29,14 +29,14 @@
 namespace grpc {
 
 void AuthMetadataProcessorAyncWrapper::Destroy(void* wrapper) {
-  auto* w = reinterpret_cast<AuthMetadataProcessorAyncWrapper*>(wrapper);
+  auto* w = static_cast<AuthMetadataProcessorAyncWrapper*>(wrapper);
   delete w;
 }
 
 void AuthMetadataProcessorAyncWrapper::Process(
     void* wrapper, grpc_auth_context* context, const grpc_metadata* md,
     size_t num_md, grpc_process_auth_metadata_done_cb cb, void* user_data) {
-  auto* w = reinterpret_cast<AuthMetadataProcessorAyncWrapper*>(wrapper);
+  auto* w = static_cast<AuthMetadataProcessorAyncWrapper*>(wrapper);
   if (!w->processor_) {
     // Early exit.
     cb(user_data, nullptr, 0, nullptr, 0, GRPC_STATUS_OK, nullptr);
diff --git a/src/cpp/server/secure_server_credentials.h b/src/cpp/server/secure_server_credentials.h
index 212f0d1..8a81af2 100644
--- a/src/cpp/server/secure_server_credentials.h
+++ b/src/cpp/server/secure_server_credentials.h
@@ -21,7 +21,7 @@
 
 #include <memory>
 
-#include <grpc++/security/server_credentials.h>
+#include <grpcpp/security/server_credentials.h>
 
 #include <grpc/grpc_security.h>
 
diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc
index 200e477..e951801 100644
--- a/src/cpp/server/server_builder.cc
+++ b/src/cpp/server/server_builder.cc
@@ -16,15 +16,15 @@
  *
  */
 
-#include <grpc++/server_builder.h>
+#include <grpcpp/server_builder.h>
 
-#include <grpc++/impl/service_type.h>
-#include <grpc++/resource_quota.h>
-#include <grpc++/server.h>
 #include <grpc/support/cpu.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
+#include <grpcpp/impl/service_type.h>
+#include <grpcpp/resource_quota.h>
+#include <grpcpp/server.h>
 
+#include "src/core/lib/gpr/useful.h"
 #include "src/cpp/server/thread_pool_interface.h"
 
 namespace grpc {
diff --git a/src/cpp/server/server_cc.cc b/src/cpp/server/server_cc.cc
index 4f8f4e0..391ca44 100644
--- a/src/cpp/server/server_cc.cc
+++ b/src/cpp/server/server_cc.cc
@@ -15,27 +15,27 @@
  *
  */
 
-#include <grpc++/server.h>
+#include <grpcpp/server.h>
 
 #include <cstdlib>
 #include <sstream>
 #include <utility>
 
-#include <grpc++/completion_queue.h>
-#include <grpc++/generic/async_generic_service.h>
-#include <grpc++/impl/codegen/async_unary_call.h>
-#include <grpc++/impl/codegen/completion_queue_tag.h>
-#include <grpc++/impl/grpc_library.h>
-#include <grpc++/impl/method_handler_impl.h>
-#include <grpc++/impl/rpc_service_method.h>
-#include <grpc++/impl/server_initializer.h>
-#include <grpc++/impl/service_type.h>
-#include <grpc++/security/server_credentials.h>
-#include <grpc++/server_context.h>
-#include <grpc++/support/time.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include <grpcpp/completion_queue.h>
+#include <grpcpp/generic/async_generic_service.h>
+#include <grpcpp/impl/codegen/async_unary_call.h>
+#include <grpcpp/impl/codegen/completion_queue_tag.h>
+#include <grpcpp/impl/grpc_library.h>
+#include <grpcpp/impl/method_handler_impl.h>
+#include <grpcpp/impl/rpc_service_method.h>
+#include <grpcpp/impl/server_initializer.h>
+#include <grpcpp/impl/service_type.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server_context.h>
+#include <grpcpp/support/time.h>
 
 #include "src/core/ext/transport/inproc/inproc_transport.h"
 #include "src/core/lib/profiling/timers.h"
@@ -45,6 +45,7 @@
 #include "src/cpp/thread_manager/thread_manager.h"
 
 namespace grpc {
+namespace {
 
 class DefaultGlobalCallbacks final : public Server::GlobalCallbacks {
  public:
@@ -53,16 +54,29 @@
   void PostSynchronousRequest(ServerContext* context) override {}
 };
 
-static std::shared_ptr<Server::GlobalCallbacks> g_callbacks = nullptr;
-static gpr_once g_once_init_callbacks = GPR_ONCE_INIT;
+std::shared_ptr<Server::GlobalCallbacks> g_callbacks = nullptr;
+gpr_once g_once_init_callbacks = GPR_ONCE_INIT;
 
-static void InitGlobalCallbacks() {
+void InitGlobalCallbacks() {
   if (!g_callbacks) {
     g_callbacks.reset(new DefaultGlobalCallbacks());
   }
 }
 
-class Server::UnimplementedAsyncRequestContext {
+class ShutdownTag : public internal::CompletionQueueTag {
+ public:
+  bool FinalizeResult(void** tag, bool* status) { return false; }
+};
+
+class DummyTag : public internal::CompletionQueueTag {
+ public:
+  bool FinalizeResult(void** tag, bool* status) {
+    *status = true;
+    return true;
+  }
+};
+
+class UnimplementedAsyncRequestContext {
  protected:
   UnimplementedAsyncRequestContext() : generic_stream_(&server_context_) {}
 
@@ -70,8 +84,14 @@
   GenericServerAsyncReaderWriter generic_stream_;
 };
 
+}  // namespace
+
+/// Use private inheritance rather than composition only to establish order
+/// of construction, since the public base class should be constructed after the
+/// elements belonging to the private base class are constructed. This is not
+/// possible using true composition.
 class Server::UnimplementedAsyncRequest final
-    : public UnimplementedAsyncRequestContext,
+    : private UnimplementedAsyncRequestContext,
       public GenericAsyncRequest {
  public:
   UnimplementedAsyncRequest(Server* server, ServerCompletionQueue* cq)
@@ -90,38 +110,27 @@
   ServerCompletionQueue* const cq_;
 };
 
-typedef internal::SneakyCallOpSet<internal::CallOpSendInitialMetadata,
-                                  internal::CallOpServerSendStatus>
-    UnimplementedAsyncResponseOp;
+/// UnimplementedAsyncResponse should not post user-visible completions to the
+/// C++ completion queue, but is generated as a CQ event by the core
 class Server::UnimplementedAsyncResponse final
-    : public UnimplementedAsyncResponseOp {
+    : public internal::CallOpSet<internal::CallOpSendInitialMetadata,
+                                 internal::CallOpServerSendStatus> {
  public:
   UnimplementedAsyncResponse(UnimplementedAsyncRequest* request);
   ~UnimplementedAsyncResponse() { delete request_; }
 
   bool FinalizeResult(void** tag, bool* status) override {
-    bool r = UnimplementedAsyncResponseOp::FinalizeResult(tag, status);
+    internal::CallOpSet<
+        internal::CallOpSendInitialMetadata,
+        internal::CallOpServerSendStatus>::FinalizeResult(tag, status);
     delete this;
-    return r;
+    return false;
   }
 
  private:
   UnimplementedAsyncRequest* const request_;
 };
 
-class ShutdownTag : public internal::CompletionQueueTag {
- public:
-  bool FinalizeResult(void** tag, bool* status) { return false; }
-};
-
-class DummyTag : public internal::CompletionQueueTag {
- public:
-  bool FinalizeResult(void** tag, bool* status) {
-    *status = true;
-    return true;
-  }
-};
-
 class Server::SyncRequest final : public internal::CompletionQueueTag {
  public:
   SyncRequest(internal::RpcServiceMethod* method, void* tag)
@@ -382,11 +391,12 @@
   global_callbacks_ = g_callbacks;
   global_callbacks_->UpdateArguments(args);
 
-  for (auto it = sync_server_cqs_->begin(); it != sync_server_cqs_->end();
-       it++) {
-    sync_req_mgrs_.emplace_back(new SyncRequestThreadManager(
-        this, (*it).get(), global_callbacks_, min_pollers, max_pollers,
-        sync_cq_timeout_msec));
+  if (sync_server_cqs_ != nullptr) {
+    for (const auto& it : *sync_server_cqs_) {
+      sync_req_mgrs_.emplace_back(new SyncRequestThreadManager(
+          this, it.get(), global_callbacks_, min_pollers, max_pollers,
+          sync_cq_timeout_msec));
+    }
   }
 
   grpc_channel_args channel_args;
@@ -525,7 +535,7 @@
   // explicit one.
   if (health_check_service_ == nullptr && !health_check_service_disabled_ &&
       DefaultHealthCheckServiceEnabled()) {
-    if (sync_server_cqs_->empty()) {
+    if (sync_server_cqs_ == nullptr || sync_server_cqs_->empty()) {
       gpr_log(GPR_INFO,
               "Default health check service disabled at async-only server.");
     } else {
diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc
index f0cbbdb..6f5bde0 100644
--- a/src/cpp/server/server_context.cc
+++ b/src/cpp/server/server_context.cc
@@ -16,20 +16,20 @@
  *
  */
 
-#include <grpc++/server_context.h>
+#include <grpcpp/server_context.h>
 
 #include <algorithm>
 #include <mutex>
 #include <utility>
 
-#include <grpc++/completion_queue.h>
-#include <grpc++/impl/call.h>
-#include <grpc++/support/time.h>
 #include <grpc/compression.h>
 #include <grpc/grpc.h>
 #include <grpc/load_reporting.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include <grpcpp/completion_queue.h>
+#include <grpcpp/impl/call.h>
+#include <grpcpp/support/time.h>
 
 #include "src/core/lib/surface/call.h"
 
@@ -190,6 +190,7 @@
 
 void ServerContext::set_compression_algorithm(
     grpc_compression_algorithm algorithm) {
+  compression_algorithm_ = algorithm;
   const char* algorithm_name = nullptr;
   if (!grpc_compression_algorithm_name(algorithm, &algorithm_name)) {
     gpr_log(GPR_ERROR, "Name for compression algorithm '%d' unknown.",
diff --git a/src/cpp/server/server_credentials.cc b/src/cpp/server/server_credentials.cc
index 158dfa8..c3b3a8b 100644
--- a/src/cpp/server/server_credentials.cc
+++ b/src/cpp/server/server_credentials.cc
@@ -16,7 +16,7 @@
  *
  */
 
-#include <grpc++/security/server_credentials.h>
+#include <grpcpp/security/server_credentials.h>
 
 namespace grpc {
 
diff --git a/src/cpp/server/server_posix.cc b/src/cpp/server/server_posix.cc
index d3ef5cb..7c221ed 100644
--- a/src/cpp/server/server_posix.cc
+++ b/src/cpp/server/server_posix.cc
@@ -16,7 +16,7 @@
  *
  */
 
-#include <grpc++/server_posix.h>
+#include <grpcpp/server_posix.h>
 
 #include <grpc/grpc_posix.h>
 
diff --git a/src/cpp/thread_manager/thread_manager.cc b/src/cpp/thread_manager/thread_manager.cc
index 23264f1..02ac56a 100644
--- a/src/cpp/thread_manager/thread_manager.cc
+++ b/src/cpp/thread_manager/thread_manager.cc
@@ -20,18 +20,22 @@
 
 #include <climits>
 #include <mutex>
-#include <thread>
 
 #include <grpc/support/log.h>
 
+#include "src/core/lib/gprpp/thd.h"
+
 namespace grpc {
 
 ThreadManager::WorkerThread::WorkerThread(ThreadManager* thd_mgr)
     : thd_mgr_(thd_mgr) {
   // Make thread creation exclusive with respect to its join happening in
   // ~WorkerThread().
-  std::lock_guard<std::mutex> lock(wt_mu_);
-  thd_ = std::thread(&ThreadManager::WorkerThread::Run, this);
+  thd_ = grpc_core::Thread(
+      "grpcpp_sync_server",
+      [](void* th) { static_cast<ThreadManager::WorkerThread*>(th)->Run(); },
+      this);
+  thd_.Start();
 }
 
 void ThreadManager::WorkerThread::Run() {
@@ -41,8 +45,7 @@
 
 ThreadManager::WorkerThread::~WorkerThread() {
   // Don't join until the thread is fully constructed.
-  std::lock_guard<std::mutex> lock(wt_mu_);
-  thd_.join();
+  thd_.Join();
 }
 
 ThreadManager::ThreadManager(int min_pollers, int max_pollers)
diff --git a/src/cpp/thread_manager/thread_manager.h b/src/cpp/thread_manager/thread_manager.h
index a206e0b..5a40f2d 100644
--- a/src/cpp/thread_manager/thread_manager.h
+++ b/src/cpp/thread_manager/thread_manager.h
@@ -23,9 +23,10 @@
 #include <list>
 #include <memory>
 #include <mutex>
-#include <thread>
 
-#include <grpc++/support/config.h>
+#include <grpcpp/support/config.h>
+
+#include "src/core/lib/gprpp/thd.h"
 
 namespace grpc {
 
@@ -84,8 +85,8 @@
   virtual void Wait();
 
  private:
-  // Helper wrapper class around std::thread. This takes a ThreadManager object
-  // and starts a new std::thread to calls the Run() function.
+  // Helper wrapper class around grpc_core::Thread. Takes a ThreadManager object
+  // and starts a new grpc_core::Thread to calls the Run() function.
   //
   // The Run() function calls ThreadManager::MainWorkLoop() function and once
   // that completes, it marks the WorkerThread completed by calling
@@ -101,8 +102,7 @@
     void Run();
 
     ThreadManager* const thd_mgr_;
-    std::mutex wt_mu_;
-    std::thread thd_;
+    grpc_core::Thread thd_;
   };
 
   // The main funtion in ThreadManager
diff --git a/src/cpp/util/byte_buffer_cc.cc b/src/cpp/util/byte_buffer_cc.cc
index 180c813..fbc1768 100644
--- a/src/cpp/util/byte_buffer_cc.cc
+++ b/src/cpp/util/byte_buffer_cc.cc
@@ -16,10 +16,10 @@
  *
  */
 
-#include <grpc++/impl/grpc_library.h>
-#include <grpc++/support/byte_buffer.h>
 #include <grpc/byte_buffer.h>
 #include <grpc/byte_buffer_reader.h>
+#include <grpcpp/impl/grpc_library.h>
+#include <grpcpp/support/byte_buffer.h>
 
 namespace grpc {
 
diff --git a/src/cpp/util/error_details.cc b/src/cpp/util/error_details.cc
index f06b475..42c887a 100644
--- a/src/cpp/util/error_details.cc
+++ b/src/cpp/util/error_details.cc
@@ -16,7 +16,7 @@
  *
  */
 
-#include <grpc++/support/error_details.h>
+#include <grpcpp/support/error_details.h>
 
 #include "src/proto/grpc/status/status.pb.h"
 
diff --git a/src/cpp/util/slice_cc.cc b/src/cpp/util/slice_cc.cc
index 3ae17e8..c72dbdb 100644
--- a/src/cpp/util/slice_cc.cc
+++ b/src/cpp/util/slice_cc.cc
@@ -16,8 +16,8 @@
  *
  */
 
-#include <grpc++/support/slice.h>
 #include <grpc/slice.h>
+#include <grpcpp/support/slice.h>
 
 namespace grpc {
 
@@ -32,15 +32,15 @@
 Slice::Slice(size_t len) : slice_(grpc_slice_malloc(len)) {}
 
 Slice::Slice(const void* buf, size_t len)
-    : slice_(grpc_slice_from_copied_buffer(reinterpret_cast<const char*>(buf),
-                                           len)) {}
+    : slice_(
+          grpc_slice_from_copied_buffer(static_cast<const char*>(buf), len)) {}
 
 Slice::Slice(const grpc::string& str)
     : slice_(grpc_slice_from_copied_buffer(str.c_str(), str.length())) {}
 
 Slice::Slice(const void* buf, size_t len, StaticSlice)
-    : slice_(grpc_slice_from_static_buffer(reinterpret_cast<const char*>(buf),
-                                           len)) {}
+    : slice_(
+          grpc_slice_from_static_buffer(static_cast<const char*>(buf), len)) {}
 
 Slice::Slice(const Slice& other) : slice_(grpc_slice_ref(other.slice_)) {}
 
diff --git a/src/cpp/util/status.cc b/src/cpp/util/status.cc
index 0f79336..93696d8 100644
--- a/src/cpp/util/status.cc
+++ b/src/cpp/util/status.cc
@@ -16,7 +16,7 @@
  *
  */
 
-#include <grpc++/support/status.h>
+#include <grpcpp/support/status.h>
 
 namespace grpc {
 
diff --git a/src/cpp/util/string_ref.cc b/src/cpp/util/string_ref.cc
index 30c2ab6..8b09a82 100644
--- a/src/cpp/util/string_ref.cc
+++ b/src/cpp/util/string_ref.cc
@@ -16,7 +16,7 @@
  *
  */
 
-#include <grpc++/support/string_ref.h>
+#include <grpcpp/support/string_ref.h>
 
 namespace grpc {
 
diff --git a/src/cpp/util/time_cc.cc b/src/cpp/util/time_cc.cc
index 3b6e075..6c9c228 100644
--- a/src/cpp/util/time_cc.cc
+++ b/src/cpp/util/time_cc.cc
@@ -16,9 +16,9 @@
  *
  */
 
-#include <grpc++/support/config.h>
-#include <grpc++/support/time.h>
 #include <grpc/support/time.h>
+#include <grpcpp/support/config.h>
+#include <grpcpp/support/time.h>
 
 using std::chrono::duration_cast;
 using std::chrono::high_resolution_clock;
@@ -39,8 +39,8 @@
     return;
   }
   nanoseconds nsecs = duration_cast<nanoseconds>(deadline - secs);
-  to->tv_sec = (int64_t)secs.count();
-  to->tv_nsec = (int32_t)nsecs.count();
+  to->tv_sec = static_cast<int64_t>(secs.count());
+  to->tv_nsec = static_cast<int32_t>(nsecs.count());
   to->clock_type = GPR_CLOCK_REALTIME;
 }
 
@@ -55,8 +55,8 @@
     return;
   }
   nanoseconds nsecs = duration_cast<nanoseconds>(deadline - secs);
-  to->tv_sec = (int64_t)secs.count();
-  to->tv_nsec = (int32_t)nsecs.count();
+  to->tv_sec = static_cast<int64_t>(secs.count());
+  to->tv_nsec = static_cast<int32_t>(nsecs.count());
   to->clock_type = GPR_CLOCK_REALTIME;
 }
 
diff --git a/src/csharp/Grpc.Core.Tests/Interceptors/ClientInterceptorTest.cs b/src/csharp/Grpc.Core.Tests/Interceptors/ClientInterceptorTest.cs
new file mode 100644
index 0000000..02f6f6f
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/Interceptors/ClientInterceptorTest.cs
@@ -0,0 +1,228 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Interceptors;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using Grpc.Core.Tests;
+using NUnit.Framework;
+
+namespace Grpc.Core.Interceptors.Tests
+{
+    public class ClientInterceptorTest
+    {
+        const string Host = "127.0.0.1";
+
+        [Test]
+        public void AddRequestHeaderInClientInterceptor()
+        {
+            const string HeaderKey = "x-client-interceptor";
+            const string HeaderValue = "hello-world";
+            var helper = new MockServiceHelper(Host);
+            helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
+            {
+                var interceptorHeader = context.RequestHeaders.Last(m => (m.Key == HeaderKey)).Value;
+                Assert.AreEqual(interceptorHeader, HeaderValue);
+                return Task.FromResult("PASS");
+            });
+            var server = helper.GetServer();
+            server.Start();
+            var callInvoker = helper.GetChannel().Intercept(metadata =>
+            {
+                metadata = metadata ?? new Metadata();
+                metadata.Add(new Metadata.Entry(HeaderKey, HeaderValue));
+                return metadata;
+            });
+            Assert.AreEqual("PASS", callInvoker.BlockingUnaryCall(new Method<string, string>(MethodType.Unary, MockServiceHelper.ServiceName, "Unary", Marshallers.StringMarshaller, Marshallers.StringMarshaller), Host, new CallOptions(), ""));
+        }
+
+        [Test]
+        public void CheckInterceptorOrderInClientInterceptors()
+        {
+            var helper = new MockServiceHelper(Host);
+            helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
+            {
+                return Task.FromResult("PASS");
+            });
+            var server = helper.GetServer();
+            server.Start();
+            var stringBuilder = new StringBuilder();
+            var callInvoker = helper.GetChannel().Intercept(metadata => {
+                stringBuilder.Append("interceptor1");
+                return metadata;
+            }).Intercept(new CallbackInterceptor(() => stringBuilder.Append("array1")),
+                new CallbackInterceptor(() => stringBuilder.Append("array2")),
+                new CallbackInterceptor(() => stringBuilder.Append("array3")))
+            .Intercept(metadata =>
+            {
+                stringBuilder.Append("interceptor2");
+                return metadata;
+            }).Intercept(metadata =>
+            {
+                stringBuilder.Append("interceptor3");
+                return metadata;
+            });
+            Assert.AreEqual("PASS", callInvoker.BlockingUnaryCall(new Method<string, string>(MethodType.Unary, MockServiceHelper.ServiceName, "Unary", Marshallers.StringMarshaller, Marshallers.StringMarshaller), Host, new CallOptions(), ""));
+            Assert.AreEqual("interceptor3interceptor2array1array2array3interceptor1", stringBuilder.ToString());
+        }
+
+        [Test]
+        public void CheckNullInterceptorRegistrationFails()
+        {
+            var helper = new MockServiceHelper(Host);
+            helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
+            {
+                return Task.FromResult("PASS");
+            });
+            Assert.Throws<ArgumentNullException>(() => helper.GetChannel().Intercept(default(Interceptor)));
+            Assert.Throws<ArgumentNullException>(() => helper.GetChannel().Intercept(new[]{default(Interceptor)}));
+            Assert.Throws<ArgumentNullException>(() => helper.GetChannel().Intercept(new[]{new CallbackInterceptor(()=>{}), null}));
+            Assert.Throws<ArgumentNullException>(() => helper.GetChannel().Intercept(default(Interceptor[])));
+        }
+
+        [Test]
+        public async Task CountNumberOfRequestsInClientInterceptors()
+        {
+            var helper = new MockServiceHelper(Host);
+            helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
+            {
+                var stringBuilder = new StringBuilder();
+                await requestStream.ForEachAsync(request =>
+                {
+                    stringBuilder.Append(request);
+                    return TaskUtils.CompletedTask;
+                });
+                await Task.Delay(100);
+                return stringBuilder.ToString();
+            });
+
+            var callInvoker = helper.GetChannel().Intercept(new ClientStreamingCountingInterceptor());
+
+            var server = helper.GetServer();
+            server.Start();
+            var call = callInvoker.AsyncClientStreamingCall(new Method<string, string>(MethodType.ClientStreaming, MockServiceHelper.ServiceName, "ClientStreaming", Marshallers.StringMarshaller, Marshallers.StringMarshaller), Host, new CallOptions());
+            await call.RequestStream.WriteAllAsync(new string[] { "A", "B", "C" });
+            Assert.AreEqual("3", await call.ResponseAsync);
+
+            Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode);
+            Assert.IsNotNull(call.GetTrailers());
+        }
+
+        private class CallbackInterceptor : Interceptor
+        {
+            readonly Action callback;
+
+            public CallbackInterceptor(Action callback)
+            {
+                this.callback = GrpcPreconditions.CheckNotNull(callback, nameof(callback));
+            }
+
+            public override TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, BlockingUnaryCallContinuation<TRequest, TResponse> continuation)
+            {
+                callback();
+                return continuation(request, context);
+            }
+
+            public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
+            {
+                callback();
+                return continuation(request, context);
+            }
+
+            public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncServerStreamingCallContinuation<TRequest, TResponse> continuation)
+            {
+                callback();
+                return continuation(request, context);
+            }
+
+            public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncClientStreamingCallContinuation<TRequest, TResponse> continuation)
+            {
+                callback();
+                return continuation(context);
+            }
+
+            public override AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncDuplexStreamingCallContinuation<TRequest, TResponse> continuation)
+            {
+                callback();
+                return continuation(context);
+            }
+        }
+
+        private class ClientStreamingCountingInterceptor : Interceptor
+        {
+            public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncClientStreamingCallContinuation<TRequest, TResponse> continuation)
+            {
+                var response = continuation(context);
+                int counter = 0;
+                var requestStream = new WrappedClientStreamWriter<TRequest>(response.RequestStream,
+                    message => { counter++; return message; }, null);
+                var responseAsync = response.ResponseAsync.ContinueWith(
+                    unaryResponse => (TResponse)(object)counter.ToString()  // Cast to object first is needed to satisfy the type-checker    
+                );
+                return new AsyncClientStreamingCall<TRequest, TResponse>(requestStream, responseAsync, response.ResponseHeadersAsync, response.GetStatus, response.GetTrailers, response.Dispose);
+            }
+        }
+
+        private class WrappedClientStreamWriter<T> : IClientStreamWriter<T>
+        {
+            readonly IClientStreamWriter<T> writer;
+            readonly Func<T, T> onMessage;
+            readonly Action onResponseStreamEnd;
+            public WrappedClientStreamWriter(IClientStreamWriter<T> writer, Func<T, T> onMessage, Action onResponseStreamEnd)
+            {
+                this.writer = writer;
+                this.onMessage = onMessage;
+                this.onResponseStreamEnd = onResponseStreamEnd;
+            }
+            public Task CompleteAsync()
+            {
+                if (onResponseStreamEnd != null)
+                {
+                    return writer.CompleteAsync().ContinueWith(x => onResponseStreamEnd());
+                }
+                return writer.CompleteAsync();
+            }
+            public Task WriteAsync(T message)
+            {
+                if (onMessage != null)
+                {
+                    message = onMessage(message);
+                }
+                return writer.WriteAsync(message);
+            }
+            public WriteOptions WriteOptions
+            {
+                get
+                {
+                    return writer.WriteOptions;
+                }
+                set
+                {
+                    writer.WriteOptions = value;
+                }
+            }
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core.Tests/Interceptors/ServerInterceptorTest.cs b/src/csharp/Grpc.Core.Tests/Interceptors/ServerInterceptorTest.cs
new file mode 100644
index 0000000..e76f21d
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/Interceptors/ServerInterceptorTest.cs
@@ -0,0 +1,126 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Interceptors;
+using Grpc.Core.Internal;
+using Grpc.Core.Tests;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Interceptors.Tests
+{
+    public class ServerInterceptorTest
+    {
+        const string Host = "127.0.0.1";
+
+        [Test]
+        public void AddRequestHeaderInServerInterceptor()
+        {
+            var helper = new MockServiceHelper(Host);
+            const string MetadataKey = "x-interceptor";
+            const string MetadataValue = "hello world";
+            var interceptor = new ServerCallContextInterceptor(ctx => ctx.RequestHeaders.Add(new Metadata.Entry(MetadataKey, MetadataValue)));
+            helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
+            {
+                var interceptorHeader = context.RequestHeaders.Last(m => (m.Key == MetadataKey)).Value;
+                Assert.AreEqual(interceptorHeader, MetadataValue);
+                return Task.FromResult("PASS");
+            });
+            helper.ServiceDefinition = helper.ServiceDefinition.Intercept(interceptor);
+            var server = helper.GetServer();
+            server.Start();
+            var channel = helper.GetChannel();
+            Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), ""));
+        }
+
+        [Test]
+        public void VerifyInterceptorOrdering()
+        {
+            var helper = new MockServiceHelper(Host);
+            helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
+            {
+                return Task.FromResult("PASS");
+            });
+            var stringBuilder = new StringBuilder();
+            helper.ServiceDefinition = helper.ServiceDefinition
+                .Intercept(new ServerCallContextInterceptor(ctx => stringBuilder.Append("A")))
+                .Intercept(new ServerCallContextInterceptor(ctx => stringBuilder.Append("B1")),
+                    new ServerCallContextInterceptor(ctx => stringBuilder.Append("B2")),
+                    new ServerCallContextInterceptor(ctx => stringBuilder.Append("B3")))
+                .Intercept(new ServerCallContextInterceptor(ctx => stringBuilder.Append("C")));
+            var server = helper.GetServer();
+            server.Start();
+            var channel = helper.GetChannel();
+            Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), ""));
+            Assert.AreEqual("CB1B2B3A", stringBuilder.ToString());
+        }
+
+        [Test]
+        public void CheckNullInterceptorRegistrationFails()
+        {
+            var helper = new MockServiceHelper(Host);
+            var sd = helper.ServiceDefinition;
+            Assert.Throws<ArgumentNullException>(() => sd.Intercept(default(Interceptor)));
+            Assert.Throws<ArgumentNullException>(() => sd.Intercept(new[]{default(Interceptor)}));
+            Assert.Throws<ArgumentNullException>(() => sd.Intercept(new[]{new ServerCallContextInterceptor(ctx=>{}), null}));
+            Assert.Throws<ArgumentNullException>(() => sd.Intercept(default(Interceptor[])));
+        }
+
+        private class ServerCallContextInterceptor : Interceptor
+        {
+            readonly Action<ServerCallContext> interceptor;
+
+            public ServerCallContextInterceptor(Action<ServerCallContext> interceptor)
+            {
+                GrpcPreconditions.CheckNotNull(interceptor, nameof(interceptor));
+                this.interceptor = interceptor;
+            }
+
+            public override Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation)
+            {
+                interceptor(context);
+                return continuation(request, context);
+            }
+
+            public override Task<TResponse> ClientStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, ServerCallContext context, ClientStreamingServerMethod<TRequest, TResponse> continuation)
+            {
+                interceptor(context);
+                return continuation(requestStream, context);
+            }
+
+            public override Task ServerStreamingServerHandler<TRequest, TResponse>(TRequest request, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, ServerStreamingServerMethod<TRequest, TResponse> continuation)
+            {
+                interceptor(context);
+                return continuation(request, responseStream, context);
+            }
+
+            public override Task DuplexStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, DuplexStreamingServerMethod<TRequest, TResponse> continuation)
+            {
+                interceptor(context);
+                return continuation(requestStream, responseStream, context);
+            }
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
index 7f4677d..a925f86 100644
--- a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
+++ b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
@@ -37,7 +37,6 @@
         public const string ServiceName = "tests.Test";
 
         readonly string host;
-        readonly ServerServiceDefinition serviceDefinition;
         readonly IEnumerable<ChannelOption> channelOptions;
 
         readonly Method<string, string> unaryMethod;
@@ -87,7 +86,7 @@
                 marshaller,
                 marshaller);
 
-            serviceDefinition = ServerServiceDefinition.CreateBuilder()
+            ServiceDefinition = ServerServiceDefinition.CreateBuilder()
                 .AddMethod(unaryMethod, (request, context) => unaryHandler(request, context))
                 .AddMethod(clientStreamingMethod, (requestStream, context) => clientStreamingHandler(requestStream, context))
                 .AddMethod(serverStreamingMethod, (request, responseStream, context) => serverStreamingHandler(request, responseStream, context))
@@ -131,7 +130,7 @@
                 // Disable SO_REUSEPORT to prevent https://github.com/grpc/grpc/issues/10755
                 server = new Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) })
                 {
-                    Services = { serviceDefinition },
+                    Services = { ServiceDefinition },
                     Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
                 };
             }
@@ -178,13 +177,7 @@
             }
         }
 
-        public ServerServiceDefinition ServiceDefinition
-        {
-            get
-            {
-                return this.serviceDefinition;
-            }
-        }
+        public ServerServiceDefinition ServiceDefinition { get; set; }
       
         public UnaryServerMethod<string, string> UnaryHandler
         {
diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs
index e7b30cd..abe19a6 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -160,8 +160,17 @@
             var deadlineTimespec = deadline.HasValue ? Timespec.FromDateTime(deadline.Value) : Timespec.InfFuture;
             lock (myLock)
             {
-                // pass "tcs" as "state" for WatchConnectivityStateHandler.
-                handle.WatchConnectivityState(lastObservedState, deadlineTimespec, completionQueue, WatchConnectivityStateHandler, tcs);
+                if (handle.IsClosed)
+                {
+                    // If channel has been already shutdown and handle was disposed, we would end up with
+                    // an abandoned completion added to the completion registry. Instead, we make sure we fail early.
+                    throw new ObjectDisposedException(nameof(handle), "Channel handle has already been disposed.");
+                }
+                else
+                {
+                    // pass "tcs" as "state" for WatchConnectivityStateHandler.
+                    handle.WatchConnectivityState(lastObservedState, deadlineTimespec, completionQueue, WatchConnectivityStateHandler, tcs);
+                }
             }
             return tcs.Task;
         }
diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs
index 2d41b29..fac3407 100644
--- a/src/csharp/Grpc.Core/ClientBase.cs
+++ b/src/csharp/Grpc.Core/ClientBase.cs
@@ -16,6 +16,8 @@
 
 #endregion
 
+using System;
+using Grpc.Core.Interceptors;
 using Grpc.Core.Internal;
 using Grpc.Core.Utils;
 
@@ -147,6 +149,52 @@
         /// </summary>
         protected internal class ClientBaseConfiguration
         {
+            private class ClientBaseConfigurationInterceptor : Interceptor
+            {
+                readonly Func<IMethod, string, CallOptions, Tuple<string, CallOptions>> interceptor;
+
+                /// <summary>
+                /// Creates a new instance of ClientBaseConfigurationInterceptor given the specified header and host interceptor function.
+                /// </summary>
+                public ClientBaseConfigurationInterceptor(Func<IMethod, string, CallOptions, Tuple<string, CallOptions>> interceptor)
+                {
+                    this.interceptor = GrpcPreconditions.CheckNotNull(interceptor, nameof(interceptor));
+                }
+
+                private ClientInterceptorContext<TRequest, TResponse> GetNewContext<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context)
+                    where TRequest : class
+                    where TResponse : class
+                {
+                    var newHostAndCallOptions = interceptor(context.Method, context.Host, context.Options);
+                    return new ClientInterceptorContext<TRequest, TResponse>(context.Method, newHostAndCallOptions.Item1, newHostAndCallOptions.Item2);
+                }
+
+                public override TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, BlockingUnaryCallContinuation<TRequest, TResponse> continuation)
+                {
+                    return continuation(request, GetNewContext(context));
+                }
+
+                public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
+                {
+                    return continuation(request, GetNewContext(context));
+                }
+
+                public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncServerStreamingCallContinuation<TRequest, TResponse> continuation)
+                {
+                    return continuation(request, GetNewContext(context));
+                }
+
+                public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncClientStreamingCallContinuation<TRequest, TResponse> continuation)
+                {
+                    return continuation(GetNewContext(context));
+                }
+
+                public override AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncDuplexStreamingCallContinuation<TRequest, TResponse> continuation)
+                {
+                    return continuation(GetNewContext(context));
+                }
+            }
+
             readonly CallInvoker undecoratedCallInvoker;
             readonly string host;
 
@@ -158,12 +206,12 @@
 
             internal CallInvoker CreateDecoratedCallInvoker()
             {
-                return new InterceptingCallInvoker(undecoratedCallInvoker, hostInterceptor: (h) => host);
+                return undecoratedCallInvoker.Intercept(new ClientBaseConfigurationInterceptor((method, host, options) => Tuple.Create(this.host, options)));
             }
 
             internal ClientBaseConfiguration WithHost(string host)
             {
-                GrpcPreconditions.CheckNotNull(host, "host");
+                GrpcPreconditions.CheckNotNull(host, nameof(host));
                 return new ClientBaseConfiguration(this.undecoratedCallInvoker, host);
             }
         }
diff --git a/src/csharp/Grpc.Core/Interceptors/CallInvokerExtensions.cs b/src/csharp/Grpc.Core/Interceptors/CallInvokerExtensions.cs
new file mode 100644
index 0000000..421b5d3
--- /dev/null
+++ b/src/csharp/Grpc.Core/Interceptors/CallInvokerExtensions.cs
@@ -0,0 +1,144 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.Linq;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core.Interceptors
+{
+    /// <summary>
+    /// Extends the CallInvoker class to provide the interceptor facility on the client side.
+    /// This is an EXPERIMENTAL API.
+    /// </summary>
+    public static class CallInvokerExtensions
+    {
+        /// <summary>
+        /// Returns a <see cref="Grpc.Core.CallInvoker" /> instance that intercepts
+        /// the invoker with the given interceptor.
+        /// </summary>
+        /// <param name="invoker">The underlying invoker to intercept.</param>
+        /// <param name="interceptor">The interceptor to intercept calls to the invoker with.</param>
+        /// <remarks>
+        /// Multiple interceptors can be added on top of each other by calling
+        /// "invoker.Intercept(a, b, c)".  The order of invocation will be "a", "b", and then "c".
+        /// Interceptors can be later added to an existing intercepted CallInvoker, effectively
+        /// building a chain like "invoker.Intercept(c).Intercept(b).Intercept(a)".  Note that
+        /// in this case, the last interceptor added will be the first to take control.
+        /// </remarks>
+        public static CallInvoker Intercept(this CallInvoker invoker, Interceptor interceptor)
+        {
+            return new InterceptingCallInvoker(invoker, interceptor);
+        }
+
+        /// <summary>
+        /// Returns a <see cref="Grpc.Core.CallInvoker" /> instance that intercepts
+        /// the invoker with the given interceptors.
+        /// </summary>
+        /// <param name="invoker">The channel to intercept.</param>
+        /// <param name="interceptors">
+        /// An array of interceptors to intercept the calls to the invoker with.
+        /// Control is passed to the interceptors in the order specified.
+        /// </param>
+        /// <remarks>
+        /// Multiple interceptors can be added on top of each other by calling
+        /// "invoker.Intercept(a, b, c)".  The order of invocation will be "a", "b", and then "c".
+        /// Interceptors can be later added to an existing intercepted CallInvoker, effectively
+        /// building a chain like "invoker.Intercept(c).Intercept(b).Intercept(a)".  Note that
+        /// in this case, the last interceptor added will be the first to take control.
+        /// </remarks>
+        public static CallInvoker Intercept(this CallInvoker invoker, params Interceptor[] interceptors)
+        {
+            GrpcPreconditions.CheckNotNull(invoker, nameof(invoker));
+            GrpcPreconditions.CheckNotNull(interceptors, nameof(interceptors));
+
+            foreach (var interceptor in interceptors.Reverse())
+            {
+                invoker = Intercept(invoker, interceptor);
+            }
+
+            return invoker;
+        }
+
+        /// <summary>
+        /// Returns a <see cref="Grpc.Core.CallInvoker" /> instance that intercepts
+        /// the invoker with the given interceptor.
+        /// </summary>
+        /// <param name="invoker">The underlying invoker to intercept.</param>
+        /// <param name="interceptor">
+        /// An interceptor delegate that takes the request metadata to be sent with an outgoing call
+        /// and returns a <see cref="Grpc.Core.Metadata" /> instance that will replace the existing
+        /// invocation metadata.
+        /// </param>
+        /// <remarks>
+        /// Multiple interceptors can be added on top of each other by
+        /// building a chain like "invoker.Intercept(c).Intercept(b).Intercept(a)".  Note that
+        /// in this case, the last interceptor added will be the first to take control.
+        /// </remarks>
+        public static CallInvoker Intercept(this CallInvoker invoker, Func<Metadata, Metadata> interceptor)
+        {
+            return new InterceptingCallInvoker(invoker, new MetadataInterceptor(interceptor));
+        }
+
+        private class MetadataInterceptor : Interceptor
+        {
+            readonly Func<Metadata, Metadata> interceptor;
+
+            /// <summary>
+            /// Creates a new instance of MetadataInterceptor given the specified interceptor function.
+            /// </summary>
+            public MetadataInterceptor(Func<Metadata, Metadata> interceptor)
+            {
+                this.interceptor = GrpcPreconditions.CheckNotNull(interceptor, nameof(interceptor));
+            }
+
+            private ClientInterceptorContext<TRequest, TResponse> GetNewContext<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context)
+                where TRequest : class
+                where TResponse : class
+            {
+                var metadata = context.Options.Headers ?? new Metadata();
+                return new ClientInterceptorContext<TRequest, TResponse>(context.Method, context.Host, context.Options.WithHeaders(interceptor(metadata)));
+            }
+
+            public override TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, BlockingUnaryCallContinuation<TRequest, TResponse> continuation)
+            {
+                return continuation(request, GetNewContext(context));
+            }
+
+            public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
+            {
+                return continuation(request, GetNewContext(context));
+            }
+
+            public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncServerStreamingCallContinuation<TRequest, TResponse> continuation)
+            {
+                return continuation(request, GetNewContext(context));
+            }
+
+            public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncClientStreamingCallContinuation<TRequest, TResponse> continuation)
+            {
+                return continuation(GetNewContext(context));
+            }
+
+            public override AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncDuplexStreamingCallContinuation<TRequest, TResponse> continuation)
+            {
+                return continuation(GetNewContext(context));
+            }
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core/Interceptors/ChannelExtensions.cs b/src/csharp/Grpc.Core/Interceptors/ChannelExtensions.cs
new file mode 100644
index 0000000..00b2fa8
--- /dev/null
+++ b/src/csharp/Grpc.Core/Interceptors/ChannelExtensions.cs
@@ -0,0 +1,88 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+
+namespace Grpc.Core.Interceptors
+{
+    /// <summary>
+    /// Provides extension methods to make it easy to register interceptors on Channel objects.
+    /// This is an EXPERIMENTAL API.
+    /// </summary>
+    public static class ChannelExtensions
+    {
+        /// <summary>
+        /// Returns a <see cref="Grpc.Core.CallInvoker" /> instance that intercepts
+        /// the channel with the given interceptor.
+        /// </summary>
+        /// <param name="channel">The channel to intercept.</param>
+        /// <param name="interceptor">The interceptor to intercept the channel with.</param>
+        /// <remarks>
+        /// Multiple interceptors can be added on top of each other by calling
+        /// "channel.Intercept(a, b, c)".  The order of invocation will be "a", "b", and then "c".
+        /// Interceptors can be later added to an existing intercepted channel, effectively
+        /// building a chain like "channel.Intercept(c).Intercept(b).Intercept(a)".  Note that
+        /// in this case, the last interceptor added will be the first to take control.
+        /// </remarks>
+        public static CallInvoker Intercept(this Channel channel, Interceptor interceptor)
+        {
+            return new DefaultCallInvoker(channel).Intercept(interceptor);
+        }
+
+        /// <summary>
+        /// Returns a <see cref="Grpc.Core.CallInvoker" /> instance that intercepts
+        /// the channel with the given interceptors.
+        /// </summary>
+        /// <param name="channel">The channel to intercept.</param>
+        /// <param name="interceptors">
+        /// An array of interceptors to intercept the channel with.
+        /// Control is passed to the interceptors in the order specified.
+        /// </param>
+        /// <remarks>
+        /// Multiple interceptors can be added on top of each other by calling
+        /// "channel.Intercept(a, b, c)".  The order of invocation will be "a", "b", and then "c".
+        /// Interceptors can be later added to an existing intercepted channel, effectively
+        /// building a chain like "channel.Intercept(c).Intercept(b).Intercept(a)".  Note that
+        /// in this case, the last interceptor added will be the first to take control.
+        /// </remarks>
+        public static CallInvoker Intercept(this Channel channel, params Interceptor[] interceptors)
+        {
+            return new DefaultCallInvoker(channel).Intercept(interceptors);
+        }
+
+        /// <summary>
+        /// Returns a <see cref="Grpc.Core.CallInvoker" /> instance that intercepts
+        /// the invoker with the given interceptor.
+        /// </summary>
+        /// <param name="channel">The channel to intercept.</param>
+        /// <param name="interceptor">
+        /// An interceptor delegate that takes the request metadata to be sent with an outgoing call
+        /// and returns a <see cref="Grpc.Core.Metadata" /> instance that will replace the existing
+        /// invocation metadata.
+        /// </param>
+        /// <remarks>
+        /// Multiple interceptors can be added on top of each other by
+        /// building a chain like "channel.Intercept(c).Intercept(b).Intercept(a)".  Note that
+        /// in this case, the last interceptor added will be the first to take control.
+        /// </remarks>
+        public static CallInvoker Intercept(this Channel channel, Func<Metadata, Metadata> interceptor)
+        {
+            return new DefaultCallInvoker(channel).Intercept(interceptor);
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core/Interceptors/ClientInterceptorContext.cs b/src/csharp/Grpc.Core/Interceptors/ClientInterceptorContext.cs
new file mode 100644
index 0000000..de06a77
--- /dev/null
+++ b/src/csharp/Grpc.Core/Interceptors/ClientInterceptorContext.cs
@@ -0,0 +1,65 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.Reflection;
+using System.Threading.Tasks;
+using Grpc.Core.Internal;
+
+namespace Grpc.Core.Interceptors
+{
+    /// <summary>
+    /// Carries along the context associated with intercepted invocations on the client side.
+    /// This is an EXPERIMENTAL API.
+    /// </summary>
+    public struct ClientInterceptorContext<TRequest, TResponse>
+        where TRequest : class
+        where TResponse : class
+    {
+        /// <summary>
+        /// Creates a new instance of <see cref="Grpc.Core.Interceptors.ClientInterceptorContext{TRequest, TResponse}" />
+        /// with the specified method, host, and call options.
+        /// </summary>
+        /// <param name="method">A <see cref="Grpc.Core.Method{TRequest, TResponse}"/> object representing the method to be invoked.</param>
+        /// <param name="host">The host to dispatch the current call to.</param>
+        /// <param name="options">A <see cref="Grpc.Core.CallOptions"/> instance containing the call options of the current call.</param>
+        public ClientInterceptorContext(Method<TRequest, TResponse> method, string host, CallOptions options)
+        {
+            Method = method;
+            Host = host;
+            Options = options;
+        }
+
+        /// <summary>
+        /// Gets the <see cref="Grpc.Core.Method{TRequest, TResponse}"/> instance
+        /// representing the method to be invoked.
+        /// </summary>
+        public Method<TRequest, TResponse> Method { get; }
+
+        /// <summary>
+        /// Gets the host that the currect invocation will be dispatched to.
+        /// </summary>
+        public string Host { get; }
+
+        /// <summary>
+        /// Gets the <see cref="Grpc.Core.CallOptions"/> structure representing the
+        /// call options associated with the current invocation.
+        /// </summary>
+        public CallOptions Options { get; }
+    }
+}
diff --git a/src/csharp/Grpc.Core/Interceptors/InterceptingCallInvoker.cs b/src/csharp/Grpc.Core/Interceptors/InterceptingCallInvoker.cs
new file mode 100644
index 0000000..84d2a0b
--- /dev/null
+++ b/src/csharp/Grpc.Core/Interceptors/InterceptingCallInvoker.cs
@@ -0,0 +1,96 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core.Interceptors
+{
+    /// <summary>
+    /// Decorates an underlying <see cref="Grpc.Core.CallInvoker" /> to
+    /// intercept calls through a given interceptor.
+    /// </summary>
+    internal class InterceptingCallInvoker : CallInvoker
+    {
+        readonly CallInvoker invoker;
+        readonly Interceptor interceptor;
+
+        /// <summary>
+        /// Creates a new instance of <see cref="Grpc.Core.Interceptors.InterceptingCallInvoker" />
+        /// with the given underlying invoker and interceptor instances.
+        /// </summary>
+        public InterceptingCallInvoker(CallInvoker invoker, Interceptor interceptor)
+        {
+            this.invoker = GrpcPreconditions.CheckNotNull(invoker, nameof(invoker));
+            this.interceptor = GrpcPreconditions.CheckNotNull(interceptor, nameof(interceptor));
+        }
+
+        /// <summary>
+        /// Intercepts a simple blocking call with the registered interceptor.
+        /// </summary>
+        public override TResponse BlockingUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+        {
+            return interceptor.BlockingUnaryCall(
+                request,
+                new ClientInterceptorContext<TRequest, TResponse>(method, host, options),
+                (req, ctx) => invoker.BlockingUnaryCall(ctx.Method, ctx.Host, ctx.Options, req));
+        }
+
+        /// <summary>
+        /// Intercepts a simple asynchronous call with the registered interceptor.
+        /// </summary>
+        public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+        {
+            return interceptor.AsyncUnaryCall(
+                request,
+                new ClientInterceptorContext<TRequest, TResponse>(method, host, options),
+                (req, ctx) => invoker.AsyncUnaryCall(ctx.Method, ctx.Host, ctx.Options, req));
+        }
+
+        /// <summary>
+        /// Intercepts an asynchronous server streaming call with the registered interceptor.
+        /// </summary>
+        public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
+        {
+            return interceptor.AsyncServerStreamingCall(
+                request,
+                new ClientInterceptorContext<TRequest, TResponse>(method, host, options),
+                (req, ctx) => invoker.AsyncServerStreamingCall(ctx.Method, ctx.Host, ctx.Options, req));
+        }
+
+        /// <summary>
+        /// Intercepts an asynchronous client streaming call with the registered interceptor.
+        /// </summary>
+        public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
+        {
+            return interceptor.AsyncClientStreamingCall(
+                new ClientInterceptorContext<TRequest, TResponse>(method, host, options),
+                ctx => invoker.AsyncClientStreamingCall(ctx.Method, ctx.Host, ctx.Options));
+        }
+
+        /// <summary>
+        /// Intercepts an asynchronous duplex streaming call with the registered interceptor.
+        /// </summary>
+        public override AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
+        {
+            return interceptor.AsyncDuplexStreamingCall(
+                new ClientInterceptorContext<TRequest, TResponse>(method, host, options),
+                ctx => invoker.AsyncDuplexStreamingCall(ctx.Method, ctx.Host, ctx.Options));
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core/Interceptors/Interceptor.cs b/src/csharp/Grpc.Core/Interceptors/Interceptor.cs
new file mode 100644
index 0000000..56a30c3
--- /dev/null
+++ b/src/csharp/Grpc.Core/Interceptors/Interceptor.cs
@@ -0,0 +1,406 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.Reflection;
+using System.Threading.Tasks;
+using Grpc.Core.Internal;
+
+namespace Grpc.Core.Interceptors
+{
+    /// <summary>
+    /// Serves as the base class for gRPC interceptors.
+    /// This is an EXPERIMENTAL API.
+    /// </summary>
+    public abstract class Interceptor
+    {
+        /// <summary>
+        /// Represents a continuation for intercepting simple blocking invocations.
+        /// A delegate of this type is passed to the BlockingUnaryCall method
+        /// when an outgoing invocation is being intercepted and calling the
+        /// delegate will invoke the next interceptor in the chain, or the underlying
+        /// call invoker if called from the last interceptor. The interceptor is
+        /// allowed to call it zero, one, or multiple times, passing it the appropriate
+        /// context and request values as it sees fit.
+        /// </summary>
+        /// <typeparam name="TRequest">Request message type for this invocation.</typeparam>
+        /// <typeparam name="TResponse">Response message type for this invocation.</typeparam>
+        /// <param name="request">The request value to continue the invocation with.</param>
+        /// <param name="context">
+        /// The <see cref="Grpc.Core.Interceptors.ClientInterceptorContext{TRequest, TResponse}"/>
+        /// instance to pass to the next step in the invocation process.
+        /// </param>
+        /// <returns>
+        /// The response value of the invocation to return to the caller.
+        /// The interceptor can choose to return the return value of the
+        /// continuation delegate or an arbitrary value as it sees fit.
+        /// </returns>
+        public delegate TResponse BlockingUnaryCallContinuation<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context)
+            where TRequest : class
+            where TResponse : class;
+
+        /// <summary>
+        /// Represents a continuation for intercepting simple asynchronous invocations.
+        /// A delegate of this type is passed to the AsyncUnaryCall method
+        /// when an outgoing invocation is being intercepted and calling the
+        /// delegate will invoke the next interceptor in the chain, or the underlying
+        /// call invoker if called from the last interceptor. The interceptor is
+        /// allowed to call it zero, one, or multiple times, passing it the appropriate
+        /// request value and context as it sees fit.
+        /// </summary>
+        /// <typeparam name="TRequest">Request message type for this invocation.</typeparam>
+        /// <typeparam name="TResponse">Response message type for this invocation.</typeparam>
+        /// <param name="request">The request value to continue the invocation with.</param>
+        /// <param name="context">
+        /// The <see cref="Grpc.Core.Interceptors.ClientInterceptorContext{TRequest, TResponse}"/>
+        /// instance to pass to the next step in the invocation process.
+        /// </param>
+        /// <returns>
+        /// An instance of <see cref="Grpc.Core.AsyncUnaryCall{TResponse}" />
+        /// representing an asynchronous invocation of a unary RPC.
+        /// The interceptor can choose to return the same object returned from
+        /// the continuation delegate or an arbitrarily constructed instance as it sees fit.
+        /// </returns>
+        public delegate AsyncUnaryCall<TResponse> AsyncUnaryCallContinuation<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context)
+            where TRequest : class
+            where TResponse : class;
+
+        /// <summary>
+        /// Represents a continuation for intercepting asynchronous server-streaming invocations.
+        /// A delegate of this type is passed to the AsyncServerStreamingCall method
+        /// when an outgoing invocation is being intercepted and calling the
+        /// delegate will invoke the next interceptor in the chain, or the underlying
+        /// call invoker if called from the last interceptor. The interceptor is
+        /// allowed to call it zero, one, or multiple times, passing it the appropriate
+        /// request value and context as it sees fit.
+        /// </summary>
+        /// <typeparam name="TRequest">Request message type for this invocation.</typeparam>
+        /// <typeparam name="TResponse">Response message type for this invocation.</typeparam>
+        /// <param name="request">The request value to continue the invocation with.</param>
+        /// <param name="context">
+        /// The <see cref="Grpc.Core.Interceptors.ClientInterceptorContext{TRequest, TResponse}"/>
+        /// instance to pass to the next step in the invocation process.
+        /// </param>
+        /// <returns>
+        /// An instance of <see cref="Grpc.Core.AsyncServerStreamingCall{TResponse}" />
+        /// representing an asynchronous invocation of a server-streaming RPC.
+        /// The interceptor can choose to return the same object returned from
+        /// the continuation delegate or an arbitrarily constructed instance as it sees fit.
+        /// </returns>
+        public delegate AsyncServerStreamingCall<TResponse> AsyncServerStreamingCallContinuation<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context)
+            where TRequest : class
+            where TResponse : class;
+
+        /// <summary>
+        /// Represents a continuation for intercepting asynchronous client-streaming invocations.
+        /// A delegate of this type is passed to the AsyncClientStreamingCall method
+        /// when an outgoing invocation is being intercepted and calling the
+        /// delegate will invoke the next interceptor in the chain, or the underlying
+        /// call invoker if called from the last interceptor. The interceptor is
+        /// allowed to call it zero, one, or multiple times, passing it the appropriate
+        /// request value and context as it sees fit.
+        /// </summary>
+        /// <typeparam name="TRequest">Request message type for this invocation.</typeparam>
+        /// <typeparam name="TResponse">Response message type for this invocation.</typeparam>
+        /// <param name="context">
+        /// The <see cref="Grpc.Core.Interceptors.ClientInterceptorContext{TRequest, TResponse}"/>
+        /// instance to pass to the next step in the invocation process.
+        /// </param>
+        /// <returns>
+        /// An instance of <see cref="Grpc.Core.AsyncClientStreamingCall{TRequest, TResponse}" />
+        /// representing an asynchronous invocation of a client-streaming RPC.
+        /// The interceptor can choose to return the same object returned from
+        /// the continuation delegate or an arbitrarily constructed instance as it sees fit.
+        /// </returns>
+        public delegate AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCallContinuation<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context)
+            where TRequest : class
+            where TResponse : class;
+
+        /// <summary>
+        /// Represents a continuation for intercepting asynchronous duplex invocations.
+        /// A delegate of this type is passed to the AsyncDuplexStreamingCall method
+        /// when an outgoing invocation is being intercepted and calling the
+        /// delegate will invoke the next interceptor in the chain, or the underlying
+        /// call invoker if called from the last interceptor. The interceptor is
+        /// allowed to call it zero, one, or multiple times, passing it the appropriate
+        /// request value and context as it sees fit.
+        /// </summary>
+        /// <param name="context">
+        /// The <see cref="Grpc.Core.Interceptors.ClientInterceptorContext{TRequest, TResponse}"/>
+        /// instance to pass to the next step in the invocation process.
+        /// </param>
+        /// <returns>
+        /// An instance of <see cref="Grpc.Core.AsyncDuplexStreamingCall{TRequest, TResponse}" />
+        /// representing an asynchronous invocation of a duplex-streaming RPC.
+        /// The interceptor can choose to return the same object returned from
+        /// the continuation delegate or an arbitrarily constructed instance as it sees fit.
+        /// </returns>
+        public delegate AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCallContinuation<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context)
+            where TRequest : class
+            where TResponse : class;
+
+        /// <summary>
+        /// Intercepts a blocking invocation of a simple remote call.
+        /// </summary>
+        /// <param name="request">The request message of the invocation.</param>
+        /// <param name="context">
+        /// The <see cref="Grpc.Core.Interceptors.ClientInterceptorContext{TRequest, TResponse}"/>
+        /// associated with the current invocation.
+        /// </param>
+        /// <param name="continuation">
+        /// The callback that continues the invocation process.
+        /// This can be invoked zero or more times by the interceptor.
+        /// The interceptor can invoke the continuation passing the given
+        /// request value and context arguments, or substitute them as it sees fit.
+        /// </param>
+        /// <returns>
+        /// The response message of the current invocation.
+        /// The interceptor can simply return the return value of the
+        /// continuation delegate passed to it intact, or an arbitrary
+        /// value as it sees fit.
+        /// </returns>
+        public virtual TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, BlockingUnaryCallContinuation<TRequest, TResponse> continuation)
+            where TRequest : class
+            where TResponse : class
+        {
+            return continuation(request, context);
+        }
+
+        /// <summary>
+        /// Intercepts an asynchronous invocation of a simple remote call.
+        /// </summary>
+        /// <param name="request">The request message of the invocation.</param>
+        /// <param name="context">
+        /// The <see cref="Grpc.Core.Interceptors.ClientInterceptorContext{TRequest, TResponse}"/>
+        /// associated with the current invocation.
+        /// </param>
+        /// <param name="continuation">
+        /// The callback that continues the invocation process.
+        /// This can be invoked zero or more times by the interceptor.
+        /// The interceptor can invoke the continuation passing the given
+        /// request value and context arguments, or substitute them as it sees fit.
+        /// </param>
+        /// <returns>
+        /// An instance of <see cref="Grpc.Core.AsyncUnaryCall{TResponse}" />
+        /// representing an asynchronous unary invocation.
+        /// The interceptor can simply return the return value of the
+        /// continuation delegate passed to it intact, or construct its
+        /// own substitute as it sees fit.
+        /// </returns>
+        public virtual AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
+            where TRequest : class
+            where TResponse : class
+        {
+            return continuation(request, context);
+        }
+
+        /// <summary>
+        /// Intercepts an asynchronous invocation of a streaming remote call.
+        /// </summary>
+        /// <param name="request">The request message of the invocation.</param>
+        /// <param name="context">
+        /// The <see cref="Grpc.Core.Interceptors.ClientInterceptorContext{TRequest, TResponse}"/>
+        /// associated with the current invocation.
+        /// </param>
+        /// <param name="continuation">
+        /// The callback that continues the invocation process.
+        /// This can be invoked zero or more times by the interceptor.
+        /// The interceptor can invoke the continuation passing the given
+        /// request value and context arguments, or substitute them as it sees fit.
+        /// </param>
+        /// <returns>
+        /// An instance of <see cref="Grpc.Core.AsyncServerStreamingCall{TResponse}" />
+        /// representing an asynchronous server-streaming invocation.
+        /// The interceptor can simply return the return value of the
+        /// continuation delegate passed to it intact, or construct its
+        /// own substitute as it sees fit.
+        /// </returns>
+        public virtual AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncServerStreamingCallContinuation<TRequest, TResponse> continuation)
+            where TRequest : class
+            where TResponse : class
+        {
+            return continuation(request, context);
+        }
+
+        /// <summary>
+        /// Intercepts an asynchronous invocation of a client streaming call.
+        /// </summary>
+        /// <param name="context">
+        /// The <see cref="Grpc.Core.Interceptors.ClientInterceptorContext{TRequest, TResponse}"/>
+        /// associated with the current invocation.
+        /// </param>
+        /// <param name="continuation">
+        /// The callback that continues the invocation process.
+        /// This can be invoked zero or more times by the interceptor.
+        /// The interceptor can invoke the continuation passing the given
+        /// context argument, or substitute as it sees fit.
+        /// </param>
+        /// <returns>
+        /// An instance of <see cref="Grpc.Core.AsyncClientStreamingCall{TRequest, TResponse}" />
+        /// representing an asynchronous client-streaming invocation.
+        /// The interceptor can simply return the return value of the
+        /// continuation delegate passed to it intact, or construct its
+        /// own substitute as it sees fit.
+        /// </returns>
+        public virtual AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncClientStreamingCallContinuation<TRequest, TResponse> continuation)
+            where TRequest : class
+            where TResponse : class
+        {
+            return continuation(context);
+        }
+
+        /// <summary>
+        /// Intercepts an asynchronous invocation of a duplex streaming call.
+        /// </summary>
+        /// <param name="context">
+        /// The <see cref="Grpc.Core.Interceptors.ClientInterceptorContext{TRequest, TResponse}"/>
+        /// associated with the current invocation.
+        /// </param>
+        /// <param name="continuation">
+        /// The callback that continues the invocation process.
+        /// This can be invoked zero or more times by the interceptor.
+        /// The interceptor can invoke the continuation passing the given
+        /// context argument, or substitute as it sees fit.
+        /// </param>
+        /// <returns>
+        /// An instance of <see cref="Grpc.Core.AsyncDuplexStreamingCall{TRequest, TResponse}" />
+        /// representing an asynchronous duplex-streaming invocation.
+        /// The interceptor can simply return the return value of the
+        /// continuation delegate passed to it intact, or construct its
+        /// own substitute as it sees fit.
+        /// </returns>
+        public virtual AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncDuplexStreamingCallContinuation<TRequest, TResponse> continuation)
+            where TRequest : class
+            where TResponse : class
+        {
+            return continuation(context);
+        }
+
+        /// <summary>
+        /// Server-side handler for intercepting and incoming unary call.
+        /// </summary>
+        /// <typeparam name="TRequest">Request message type for this method.</typeparam>
+        /// <typeparam name="TResponse">Response message type for this method.</typeparam>
+        /// <param name="request">The request value of the incoming invocation.</param>
+        /// <param name="context">
+        /// An instance of <see cref="Grpc.Core.ServerCallContext" /> representing
+        /// the context of the invocation.
+        /// </param>
+        /// <param name="continuation">
+        /// A delegate that asynchronously proceeds with the invocation, calling
+        /// the next interceptor in the chain, or the service request handler,
+        /// in case of the last interceptor and return the response value of
+        /// the RPC. The interceptor can choose to call it zero or more times
+        /// at its discretion.
+        /// </param>
+        /// <returns>
+        /// A future representing the response value of the RPC. The interceptor
+        /// can simply return the return value from the continuation intact,
+        /// or an arbitrary response value as it sees fit.
+        /// </returns>
+        public virtual Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation)
+            where TRequest : class
+            where TResponse : class
+        {
+            return continuation(request, context);
+        }
+
+        /// <summary>
+        /// Server-side handler for intercepting client streaming call.
+        /// </summary>
+        /// <typeparam name="TRequest">Request message type for this method.</typeparam>
+        /// <typeparam name="TResponse">Response message type for this method.</typeparam>
+        /// <param name="requestStream">The request stream of the incoming invocation.</param>
+        /// <param name="context">
+        /// An instance of <see cref="Grpc.Core.ServerCallContext" /> representing
+        /// the context of the invocation.
+        /// </param>
+        /// <param name="continuation">
+        /// A delegate that asynchronously proceeds with the invocation, calling
+        /// the next interceptor in the chain, or the service request handler,
+        /// in case of the last interceptor and return the response value of
+        /// the RPC. The interceptor can choose to call it zero or more times
+        /// at its discretion.
+        /// </param>
+        /// <returns>
+        /// A future representing the response value of the RPC. The interceptor
+        /// can simply return the return value from the continuation intact,
+        /// or an arbitrary response value as it sees fit. The interceptor has
+        /// the ability to wrap or substitute the request stream when calling
+        /// the continuation.
+        /// </returns>
+        public virtual Task<TResponse> ClientStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, ServerCallContext context, ClientStreamingServerMethod<TRequest, TResponse> continuation)
+            where TRequest : class
+            where TResponse : class
+        {
+            return continuation(requestStream, context);
+        }
+
+        /// <summary>
+        /// Server-side handler for intercepting server streaming call.
+        /// </summary>
+        /// <typeparam name="TRequest">Request message type for this method.</typeparam>
+        /// <typeparam name="TResponse">Response message type for this method.</typeparam>
+        /// <param name="request">The request value of the incoming invocation.</param>
+        /// <param name="responseStream">The response stream of the incoming invocation.</param>
+        /// <param name="context">
+        /// An instance of <see cref="Grpc.Core.ServerCallContext" /> representing
+        /// the context of the invocation.
+        /// </param>
+        /// <param name="continuation">
+        /// A delegate that asynchronously proceeds with the invocation, calling
+        /// the next interceptor in the chain, or the service request handler,
+        /// in case of the last interceptor and the interceptor can choose to
+        /// call it zero or more times at its discretion. The interceptor has
+        /// the ability to wrap or substitute the request value and the response stream
+        /// when calling the continuation.
+        /// </param>
+        public virtual Task ServerStreamingServerHandler<TRequest, TResponse>(TRequest request, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, ServerStreamingServerMethod<TRequest, TResponse> continuation)
+            where TRequest : class
+            where TResponse : class
+        {
+            return continuation(request, responseStream, context);
+        }
+
+        /// <summary>
+        /// Server-side handler for intercepting bidirectional streaming calls.
+        /// </summary>
+        /// <typeparam name="TRequest">Request message type for this method.</typeparam>
+        /// <typeparam name="TResponse">Response message type for this method.</typeparam>
+        /// <param name="requestStream">The request stream of the incoming invocation.</param>
+        /// <param name="responseStream">The response stream of the incoming invocation.</param>
+        /// <param name="context">
+        /// An instance of <see cref="Grpc.Core.ServerCallContext" /> representing
+        /// the context of the invocation.
+        /// </param>
+        /// <param name="continuation">
+        /// A delegate that asynchronously proceeds with the invocation, calling
+        /// the next interceptor in the chain, or the service request handler,
+        /// in case of the last interceptor and the interceptor can choose to
+        /// call it zero or more times at its discretion. The interceptor has
+        /// the ability to wrap or substitute the request and response streams
+        /// when calling the continuation.
+        /// </param>
+        public virtual Task DuplexStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, DuplexStreamingServerMethod<TRequest, TResponse> continuation)
+            where TRequest : class
+            where TResponse : class
+        {
+            return continuation(requestStream, responseStream, context);
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core/Interceptors/ServerServiceDefinitionExtensions.cs b/src/csharp/Grpc.Core/Interceptors/ServerServiceDefinitionExtensions.cs
new file mode 100644
index 0000000..b9b5324
--- /dev/null
+++ b/src/csharp/Grpc.Core/Interceptors/ServerServiceDefinitionExtensions.cs
@@ -0,0 +1,82 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.Linq;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core.Interceptors
+{
+    /// <summary>
+    /// Extends the ServerServiceDefinition class to add methods used to register interceptors on the server side.
+    /// This is an EXPERIMENTAL API.
+    /// </summary>
+    public static class ServerServiceDefinitionExtensions
+    {
+        /// <summary>
+        /// Returns a <see cref="Grpc.Core.ServerServiceDefinition" /> instance that
+        /// intercepts incoming calls to the underlying service handler through the given interceptor.
+        /// This is an EXPERIMENTAL API.
+        /// </summary>
+        /// <param name="serverServiceDefinition">The <see cref="Grpc.Core.ServerServiceDefinition" /> instance to register interceptors on.</param>
+        /// <param name="interceptor">The interceptor to intercept the incoming invocations with.</param>
+        /// <remarks>
+        /// Multiple interceptors can be added on top of each other by calling
+        /// "serverServiceDefinition.Intercept(a, b, c)".  The order of invocation will be "a", "b", and then "c".
+        /// Interceptors can be later added to an existing intercepted service definition, effectively
+        /// building a chain like "serverServiceDefinition.Intercept(c).Intercept(b).Intercept(a)".  Note that
+        /// in this case, the last interceptor added will be the first to take control.
+        /// </remarks>
+        public static ServerServiceDefinition Intercept(this ServerServiceDefinition serverServiceDefinition, Interceptor interceptor)
+        {
+            GrpcPreconditions.CheckNotNull(serverServiceDefinition, nameof(serverServiceDefinition));
+            GrpcPreconditions.CheckNotNull(interceptor, nameof(interceptor));
+            return new ServerServiceDefinition(serverServiceDefinition.CallHandlers.ToDictionary(x => x.Key, x => x.Value.Intercept(interceptor)));
+        }
+
+        /// <summary>
+        /// Returns a <see cref="Grpc.Core.ServerServiceDefinition" /> instance that
+        /// intercepts incoming calls to the underlying service handler through the given interceptors.
+        /// This is an EXPERIMENTAL API.
+        /// </summary>
+        /// <param name="serverServiceDefinition">The <see cref="Grpc.Core.ServerServiceDefinition" /> instance to register interceptors on.</param>
+        /// <param name="interceptors">
+        /// An array of interceptors to intercept the incoming invocations with.
+        /// Control is passed to the interceptors in the order specified.
+        /// </param>
+        /// <remarks>
+        /// Multiple interceptors can be added on top of each other by calling
+        /// "serverServiceDefinition.Intercept(a, b, c)".  The order of invocation will be "a", "b", and then "c".
+        /// Interceptors can be later added to an existing intercepted service definition, effectively
+        /// building a chain like "serverServiceDefinition.Intercept(c).Intercept(b).Intercept(a)".  Note that
+        /// in this case, the last interceptor added will be the first to take control.
+        /// </remarks>
+        public static ServerServiceDefinition Intercept(this ServerServiceDefinition serverServiceDefinition, params Interceptor[] interceptors)
+        {
+            GrpcPreconditions.CheckNotNull(serverServiceDefinition, nameof(serverServiceDefinition));
+            GrpcPreconditions.CheckNotNull(interceptors, nameof(interceptors));
+
+            foreach (var interceptor in interceptors.Reverse())
+            {
+                serverServiceDefinition = Intercept(serverServiceDefinition, interceptor);
+            }
+
+            return serverServiceDefinition;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core/Internal/InterceptingCallInvoker.cs b/src/csharp/Grpc.Core/Internal/InterceptingCallInvoker.cs
deleted file mode 100644
index eb4c7d9..0000000
--- a/src/csharp/Grpc.Core/Internal/InterceptingCallInvoker.cs
+++ /dev/null
@@ -1,119 +0,0 @@
-#region Copyright notice and license
-
-// Copyright 2015-2016 gRPC authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#endregion
-
-using System;
-using System.Threading.Tasks;
-using Grpc.Core;
-using Grpc.Core.Utils;
-
-namespace Grpc.Core.Internal
-{
-    /// <summary>
-    /// Decorates an underlying <c>CallInvoker</c> to intercept call invocations.
-    /// </summary>
-    internal class InterceptingCallInvoker : CallInvoker
-    {
-        readonly CallInvoker callInvoker;
-        readonly Func<string, string> hostInterceptor;
-        readonly Func<CallOptions, CallOptions> callOptionsInterceptor;
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="Grpc.Core.Internal.InterceptingCallInvoker"/> class.
-        /// </summary>
-        public InterceptingCallInvoker(CallInvoker callInvoker,
-            Func<string, string> hostInterceptor = null,
-            Func<CallOptions, CallOptions> callOptionsInterceptor = null)
-        {
-            this.callInvoker = GrpcPreconditions.CheckNotNull(callInvoker);
-            this.hostInterceptor = hostInterceptor;
-            this.callOptionsInterceptor = callOptionsInterceptor;
-        }
-
-        /// <summary>
-        /// Intercepts a unary call.
-        /// </summary>
-        public override TResponse BlockingUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
-        {
-            host = InterceptHost(host);
-            options = InterceptCallOptions(options);
-            return callInvoker.BlockingUnaryCall(method, host, options, request);
-        }
-
-        /// <summary>
-        /// Invokes a simple remote call asynchronously.
-        /// </summary>
-        public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
-        {
-            host = InterceptHost(host);
-            options = InterceptCallOptions(options);
-            return callInvoker.AsyncUnaryCall(method, host, options, request);
-        }
-
-        /// <summary>
-        /// Invokes a server streaming call asynchronously.
-        /// In server streaming scenario, client sends on request and server responds with a stream of responses.
-        /// </summary>
-        public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request)
-        {
-            host = InterceptHost(host);
-            options = InterceptCallOptions(options);
-            return callInvoker.AsyncServerStreamingCall(method, host, options, request);
-        }
-
-        /// <summary>
-        /// Invokes a client streaming call asynchronously.
-        /// In client streaming scenario, client sends a stream of requests and server responds with a single response.
-        /// </summary>
-        public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
-        {
-            host = InterceptHost(host);
-            options = InterceptCallOptions(options);
-            return callInvoker.AsyncClientStreamingCall(method, host, options);
-        }
-
-        /// <summary>
-        /// Invokes a duplex streaming call asynchronously.
-        /// In duplex streaming scenario, client sends a stream of requests and server responds with a stream of responses.
-        /// The response stream is completely independent and both side can be sending messages at the same time.
-        /// </summary>
-        public override AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options)
-        {
-            host = InterceptHost(host);
-            options = InterceptCallOptions(options);
-            return callInvoker.AsyncDuplexStreamingCall(method, host, options);
-        }
-
-        private string InterceptHost(string host)
-        {
-            if (hostInterceptor == null)
-            {
-                return host;
-            }
-            return hostInterceptor(host);
-        }
-
-        private CallOptions InterceptCallOptions(CallOptions options)
-        {
-            if (callOptionsInterceptor == null)
-            {
-                return options;
-            }
-            return callOptionsInterceptor(options);
-        }
-    }
-}
diff --git a/src/csharp/Grpc.Core/Internal/NativeExtension.cs b/src/csharp/Grpc.Core/Internal/NativeExtension.cs
index 4cbde90..d5ec998 100644
--- a/src/csharp/Grpc.Core/Internal/NativeExtension.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeExtension.cs
@@ -37,9 +37,9 @@
 
         private NativeExtension()
         {
-            this.nativeMethods = new NativeMethods(Load());
+            this.nativeMethods = LoadNativeMethods();
             
-            // Redirect the the native logs as the very first thing after loading the native extension
+            // Redirect the native logs as the very first thing after loading the native extension
             // to make sure we don't lose any logs.
             NativeLogRedirector.Redirect(this.nativeMethods);
 
@@ -77,7 +77,7 @@
         /// <summary>
         /// Detects which configuration of native extension to load and load it.
         /// </summary>
-        private static UnmanagedLibrary Load()
+        private static UnmanagedLibrary LoadUnmanagedLibrary()
         {
             // TODO: allow customizing path to native extension (possibly through exposing a GrpcEnvironment property).
             // See https://github.com/grpc/grpc/pull/7303 for one option.
@@ -96,11 +96,38 @@
             var netCorePublishedAppStylePath = Path.Combine(assemblyDirectory, runtimesDirectory, GetNativeLibraryFilename());
             var netCoreAppStylePath = Path.Combine(assemblyDirectory, "../..", runtimesDirectory, GetNativeLibraryFilename());
 
-            // Look for all native library in all possible locations in given order.
+            // Look for the native library in all possible locations in given order.
             string[] paths = new[] { classicPath, netCorePublishedAppStylePath, netCoreAppStylePath};
             return new UnmanagedLibrary(paths);
         }
 
+        /// <summary>
+        /// Loads native extension and return native methods delegates.
+        /// </summary>
+        private static NativeMethods LoadNativeMethods()
+        {
+            return PlatformApis.IsUnity ? LoadNativeMethodsUnity() : new NativeMethods(LoadUnmanagedLibrary());
+        }
+
+        /// <summary>
+        /// Return native method delegates when running on Unity platform.
+        /// Unity does not use standard NuGet packages and the native library is treated
+        /// there as a "native plugin" which is (provided it has the right metadata)
+        /// automatically made available to <c>[DllImport]</c> loading logic.
+        /// WARNING: Unity support is experimental and work-in-progress. Don't expect it to work.
+        /// </summary>
+        private static NativeMethods LoadNativeMethodsUnity()
+        {
+            switch (PlatformApis.GetUnityRuntimePlatform())
+            {
+                case "IPhonePlayer":
+                    return new NativeMethods(new NativeMethods.DllImportsFromStaticLib());
+                default:
+                    // most other platforms load unity plugins as a shared library
+                    return new NativeMethods(new NativeMethods.DllImportsFromSharedLib());
+            }
+        }
+
         private static string GetAssemblyPath()
         {
             var assembly = typeof(NativeExtension).GetTypeInfo().Assembly;
diff --git a/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs b/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs
new file mode 100644
index 0000000..153a52f
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs
@@ -0,0 +1,1120 @@
+
+#region Copyright notice and license
+
+// Copyright 2015 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.Collections.Concurrent;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+using Grpc.Core.Logging;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core.Internal
+{
+    internal partial class NativeMethods
+    {
+        #region Native methods
+        
+        public readonly Delegates.grpcsharp_init_delegate grpcsharp_init;
+        public readonly Delegates.grpcsharp_shutdown_delegate grpcsharp_shutdown;
+        public readonly Delegates.grpcsharp_version_string_delegate grpcsharp_version_string;
+        public readonly Delegates.grpcsharp_batch_context_create_delegate grpcsharp_batch_context_create;
+        public readonly Delegates.grpcsharp_batch_context_recv_initial_metadata_delegate grpcsharp_batch_context_recv_initial_metadata;
+        public readonly Delegates.grpcsharp_batch_context_recv_message_length_delegate grpcsharp_batch_context_recv_message_length;
+        public readonly Delegates.grpcsharp_batch_context_recv_message_to_buffer_delegate grpcsharp_batch_context_recv_message_to_buffer;
+        public readonly Delegates.grpcsharp_batch_context_recv_status_on_client_status_delegate grpcsharp_batch_context_recv_status_on_client_status;
+        public readonly Delegates.grpcsharp_batch_context_recv_status_on_client_details_delegate grpcsharp_batch_context_recv_status_on_client_details;
+        public readonly Delegates.grpcsharp_batch_context_recv_status_on_client_trailing_metadata_delegate grpcsharp_batch_context_recv_status_on_client_trailing_metadata;
+        public readonly Delegates.grpcsharp_batch_context_recv_close_on_server_cancelled_delegate grpcsharp_batch_context_recv_close_on_server_cancelled;
+        public readonly Delegates.grpcsharp_batch_context_reset_delegate grpcsharp_batch_context_reset;
+        public readonly Delegates.grpcsharp_batch_context_destroy_delegate grpcsharp_batch_context_destroy;
+        public readonly Delegates.grpcsharp_request_call_context_create_delegate grpcsharp_request_call_context_create;
+        public readonly Delegates.grpcsharp_request_call_context_call_delegate grpcsharp_request_call_context_call;
+        public readonly Delegates.grpcsharp_request_call_context_method_delegate grpcsharp_request_call_context_method;
+        public readonly Delegates.grpcsharp_request_call_context_host_delegate grpcsharp_request_call_context_host;
+        public readonly Delegates.grpcsharp_request_call_context_deadline_delegate grpcsharp_request_call_context_deadline;
+        public readonly Delegates.grpcsharp_request_call_context_request_metadata_delegate grpcsharp_request_call_context_request_metadata;
+        public readonly Delegates.grpcsharp_request_call_context_reset_delegate grpcsharp_request_call_context_reset;
+        public readonly Delegates.grpcsharp_request_call_context_destroy_delegate grpcsharp_request_call_context_destroy;
+        public readonly Delegates.grpcsharp_composite_call_credentials_create_delegate grpcsharp_composite_call_credentials_create;
+        public readonly Delegates.grpcsharp_call_credentials_release_delegate grpcsharp_call_credentials_release;
+        public readonly Delegates.grpcsharp_call_cancel_delegate grpcsharp_call_cancel;
+        public readonly Delegates.grpcsharp_call_cancel_with_status_delegate grpcsharp_call_cancel_with_status;
+        public readonly Delegates.grpcsharp_call_start_unary_delegate grpcsharp_call_start_unary;
+        public readonly Delegates.grpcsharp_call_start_client_streaming_delegate grpcsharp_call_start_client_streaming;
+        public readonly Delegates.grpcsharp_call_start_server_streaming_delegate grpcsharp_call_start_server_streaming;
+        public readonly Delegates.grpcsharp_call_start_duplex_streaming_delegate grpcsharp_call_start_duplex_streaming;
+        public readonly Delegates.grpcsharp_call_send_message_delegate grpcsharp_call_send_message;
+        public readonly Delegates.grpcsharp_call_send_close_from_client_delegate grpcsharp_call_send_close_from_client;
+        public readonly Delegates.grpcsharp_call_send_status_from_server_delegate grpcsharp_call_send_status_from_server;
+        public readonly Delegates.grpcsharp_call_recv_message_delegate grpcsharp_call_recv_message;
+        public readonly Delegates.grpcsharp_call_recv_initial_metadata_delegate grpcsharp_call_recv_initial_metadata;
+        public readonly Delegates.grpcsharp_call_start_serverside_delegate grpcsharp_call_start_serverside;
+        public readonly Delegates.grpcsharp_call_send_initial_metadata_delegate grpcsharp_call_send_initial_metadata;
+        public readonly Delegates.grpcsharp_call_set_credentials_delegate grpcsharp_call_set_credentials;
+        public readonly Delegates.grpcsharp_call_get_peer_delegate grpcsharp_call_get_peer;
+        public readonly Delegates.grpcsharp_call_destroy_delegate grpcsharp_call_destroy;
+        public readonly Delegates.grpcsharp_channel_args_create_delegate grpcsharp_channel_args_create;
+        public readonly Delegates.grpcsharp_channel_args_set_string_delegate grpcsharp_channel_args_set_string;
+        public readonly Delegates.grpcsharp_channel_args_set_integer_delegate grpcsharp_channel_args_set_integer;
+        public readonly Delegates.grpcsharp_channel_args_destroy_delegate grpcsharp_channel_args_destroy;
+        public readonly Delegates.grpcsharp_override_default_ssl_roots_delegate grpcsharp_override_default_ssl_roots;
+        public readonly Delegates.grpcsharp_ssl_credentials_create_delegate grpcsharp_ssl_credentials_create;
+        public readonly Delegates.grpcsharp_composite_channel_credentials_create_delegate grpcsharp_composite_channel_credentials_create;
+        public readonly Delegates.grpcsharp_channel_credentials_release_delegate grpcsharp_channel_credentials_release;
+        public readonly Delegates.grpcsharp_insecure_channel_create_delegate grpcsharp_insecure_channel_create;
+        public readonly Delegates.grpcsharp_secure_channel_create_delegate grpcsharp_secure_channel_create;
+        public readonly Delegates.grpcsharp_channel_create_call_delegate grpcsharp_channel_create_call;
+        public readonly Delegates.grpcsharp_channel_check_connectivity_state_delegate grpcsharp_channel_check_connectivity_state;
+        public readonly Delegates.grpcsharp_channel_watch_connectivity_state_delegate grpcsharp_channel_watch_connectivity_state;
+        public readonly Delegates.grpcsharp_channel_get_target_delegate grpcsharp_channel_get_target;
+        public readonly Delegates.grpcsharp_channel_destroy_delegate grpcsharp_channel_destroy;
+        public readonly Delegates.grpcsharp_sizeof_grpc_event_delegate grpcsharp_sizeof_grpc_event;
+        public readonly Delegates.grpcsharp_completion_queue_create_async_delegate grpcsharp_completion_queue_create_async;
+        public readonly Delegates.grpcsharp_completion_queue_create_sync_delegate grpcsharp_completion_queue_create_sync;
+        public readonly Delegates.grpcsharp_completion_queue_shutdown_delegate grpcsharp_completion_queue_shutdown;
+        public readonly Delegates.grpcsharp_completion_queue_next_delegate grpcsharp_completion_queue_next;
+        public readonly Delegates.grpcsharp_completion_queue_pluck_delegate grpcsharp_completion_queue_pluck;
+        public readonly Delegates.grpcsharp_completion_queue_destroy_delegate grpcsharp_completion_queue_destroy;
+        public readonly Delegates.gprsharp_free_delegate gprsharp_free;
+        public readonly Delegates.grpcsharp_metadata_array_create_delegate grpcsharp_metadata_array_create;
+        public readonly Delegates.grpcsharp_metadata_array_add_delegate grpcsharp_metadata_array_add;
+        public readonly Delegates.grpcsharp_metadata_array_count_delegate grpcsharp_metadata_array_count;
+        public readonly Delegates.grpcsharp_metadata_array_get_key_delegate grpcsharp_metadata_array_get_key;
+        public readonly Delegates.grpcsharp_metadata_array_get_value_delegate grpcsharp_metadata_array_get_value;
+        public readonly Delegates.grpcsharp_metadata_array_destroy_full_delegate grpcsharp_metadata_array_destroy_full;
+        public readonly Delegates.grpcsharp_redirect_log_delegate grpcsharp_redirect_log;
+        public readonly Delegates.grpcsharp_metadata_credentials_create_from_plugin_delegate grpcsharp_metadata_credentials_create_from_plugin;
+        public readonly Delegates.grpcsharp_metadata_credentials_notify_from_plugin_delegate grpcsharp_metadata_credentials_notify_from_plugin;
+        public readonly Delegates.grpcsharp_ssl_server_credentials_create_delegate grpcsharp_ssl_server_credentials_create;
+        public readonly Delegates.grpcsharp_server_credentials_release_delegate grpcsharp_server_credentials_release;
+        public readonly Delegates.grpcsharp_server_create_delegate grpcsharp_server_create;
+        public readonly Delegates.grpcsharp_server_register_completion_queue_delegate grpcsharp_server_register_completion_queue;
+        public readonly Delegates.grpcsharp_server_add_insecure_http2_port_delegate grpcsharp_server_add_insecure_http2_port;
+        public readonly Delegates.grpcsharp_server_add_secure_http2_port_delegate grpcsharp_server_add_secure_http2_port;
+        public readonly Delegates.grpcsharp_server_start_delegate grpcsharp_server_start;
+        public readonly Delegates.grpcsharp_server_request_call_delegate grpcsharp_server_request_call;
+        public readonly Delegates.grpcsharp_server_cancel_all_calls_delegate grpcsharp_server_cancel_all_calls;
+        public readonly Delegates.grpcsharp_server_shutdown_and_notify_callback_delegate grpcsharp_server_shutdown_and_notify_callback;
+        public readonly Delegates.grpcsharp_server_destroy_delegate grpcsharp_server_destroy;
+        public readonly Delegates.grpcsharp_call_auth_context_delegate grpcsharp_call_auth_context;
+        public readonly Delegates.grpcsharp_auth_context_peer_identity_property_name_delegate grpcsharp_auth_context_peer_identity_property_name;
+        public readonly Delegates.grpcsharp_auth_context_property_iterator_delegate grpcsharp_auth_context_property_iterator;
+        public readonly Delegates.grpcsharp_auth_property_iterator_next_delegate grpcsharp_auth_property_iterator_next;
+        public readonly Delegates.grpcsharp_auth_context_release_delegate grpcsharp_auth_context_release;
+        public readonly Delegates.gprsharp_now_delegate gprsharp_now;
+        public readonly Delegates.gprsharp_inf_future_delegate gprsharp_inf_future;
+        public readonly Delegates.gprsharp_inf_past_delegate gprsharp_inf_past;
+        public readonly Delegates.gprsharp_convert_clock_type_delegate gprsharp_convert_clock_type;
+        public readonly Delegates.gprsharp_sizeof_timespec_delegate gprsharp_sizeof_timespec;
+        public readonly Delegates.grpcsharp_test_callback_delegate grpcsharp_test_callback;
+        public readonly Delegates.grpcsharp_test_nop_delegate grpcsharp_test_nop;
+        public readonly Delegates.grpcsharp_test_override_method_delegate grpcsharp_test_override_method;
+
+        #endregion
+
+        public NativeMethods(UnmanagedLibrary library)
+        {
+            this.grpcsharp_init = GetMethodDelegate<Delegates.grpcsharp_init_delegate>(library);
+            this.grpcsharp_shutdown = GetMethodDelegate<Delegates.grpcsharp_shutdown_delegate>(library);
+            this.grpcsharp_version_string = GetMethodDelegate<Delegates.grpcsharp_version_string_delegate>(library);
+            this.grpcsharp_batch_context_create = GetMethodDelegate<Delegates.grpcsharp_batch_context_create_delegate>(library);
+            this.grpcsharp_batch_context_recv_initial_metadata = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_initial_metadata_delegate>(library);
+            this.grpcsharp_batch_context_recv_message_length = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_message_length_delegate>(library);
+            this.grpcsharp_batch_context_recv_message_to_buffer = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_message_to_buffer_delegate>(library);
+            this.grpcsharp_batch_context_recv_status_on_client_status = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_status_on_client_status_delegate>(library);
+            this.grpcsharp_batch_context_recv_status_on_client_details = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_status_on_client_details_delegate>(library);
+            this.grpcsharp_batch_context_recv_status_on_client_trailing_metadata = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_status_on_client_trailing_metadata_delegate>(library);
+            this.grpcsharp_batch_context_recv_close_on_server_cancelled = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_close_on_server_cancelled_delegate>(library);
+            this.grpcsharp_batch_context_reset = GetMethodDelegate<Delegates.grpcsharp_batch_context_reset_delegate>(library);
+            this.grpcsharp_batch_context_destroy = GetMethodDelegate<Delegates.grpcsharp_batch_context_destroy_delegate>(library);
+            this.grpcsharp_request_call_context_create = GetMethodDelegate<Delegates.grpcsharp_request_call_context_create_delegate>(library);
+            this.grpcsharp_request_call_context_call = GetMethodDelegate<Delegates.grpcsharp_request_call_context_call_delegate>(library);
+            this.grpcsharp_request_call_context_method = GetMethodDelegate<Delegates.grpcsharp_request_call_context_method_delegate>(library);
+            this.grpcsharp_request_call_context_host = GetMethodDelegate<Delegates.grpcsharp_request_call_context_host_delegate>(library);
+            this.grpcsharp_request_call_context_deadline = GetMethodDelegate<Delegates.grpcsharp_request_call_context_deadline_delegate>(library);
+            this.grpcsharp_request_call_context_request_metadata = GetMethodDelegate<Delegates.grpcsharp_request_call_context_request_metadata_delegate>(library);
+            this.grpcsharp_request_call_context_reset = GetMethodDelegate<Delegates.grpcsharp_request_call_context_reset_delegate>(library);
+            this.grpcsharp_request_call_context_destroy = GetMethodDelegate<Delegates.grpcsharp_request_call_context_destroy_delegate>(library);
+            this.grpcsharp_composite_call_credentials_create = GetMethodDelegate<Delegates.grpcsharp_composite_call_credentials_create_delegate>(library);
+            this.grpcsharp_call_credentials_release = GetMethodDelegate<Delegates.grpcsharp_call_credentials_release_delegate>(library);
+            this.grpcsharp_call_cancel = GetMethodDelegate<Delegates.grpcsharp_call_cancel_delegate>(library);
+            this.grpcsharp_call_cancel_with_status = GetMethodDelegate<Delegates.grpcsharp_call_cancel_with_status_delegate>(library);
+            this.grpcsharp_call_start_unary = GetMethodDelegate<Delegates.grpcsharp_call_start_unary_delegate>(library);
+            this.grpcsharp_call_start_client_streaming = GetMethodDelegate<Delegates.grpcsharp_call_start_client_streaming_delegate>(library);
+            this.grpcsharp_call_start_server_streaming = GetMethodDelegate<Delegates.grpcsharp_call_start_server_streaming_delegate>(library);
+            this.grpcsharp_call_start_duplex_streaming = GetMethodDelegate<Delegates.grpcsharp_call_start_duplex_streaming_delegate>(library);
+            this.grpcsharp_call_send_message = GetMethodDelegate<Delegates.grpcsharp_call_send_message_delegate>(library);
+            this.grpcsharp_call_send_close_from_client = GetMethodDelegate<Delegates.grpcsharp_call_send_close_from_client_delegate>(library);
+            this.grpcsharp_call_send_status_from_server = GetMethodDelegate<Delegates.grpcsharp_call_send_status_from_server_delegate>(library);
+            this.grpcsharp_call_recv_message = GetMethodDelegate<Delegates.grpcsharp_call_recv_message_delegate>(library);
+            this.grpcsharp_call_recv_initial_metadata = GetMethodDelegate<Delegates.grpcsharp_call_recv_initial_metadata_delegate>(library);
+            this.grpcsharp_call_start_serverside = GetMethodDelegate<Delegates.grpcsharp_call_start_serverside_delegate>(library);
+            this.grpcsharp_call_send_initial_metadata = GetMethodDelegate<Delegates.grpcsharp_call_send_initial_metadata_delegate>(library);
+            this.grpcsharp_call_set_credentials = GetMethodDelegate<Delegates.grpcsharp_call_set_credentials_delegate>(library);
+            this.grpcsharp_call_get_peer = GetMethodDelegate<Delegates.grpcsharp_call_get_peer_delegate>(library);
+            this.grpcsharp_call_destroy = GetMethodDelegate<Delegates.grpcsharp_call_destroy_delegate>(library);
+            this.grpcsharp_channel_args_create = GetMethodDelegate<Delegates.grpcsharp_channel_args_create_delegate>(library);
+            this.grpcsharp_channel_args_set_string = GetMethodDelegate<Delegates.grpcsharp_channel_args_set_string_delegate>(library);
+            this.grpcsharp_channel_args_set_integer = GetMethodDelegate<Delegates.grpcsharp_channel_args_set_integer_delegate>(library);
+            this.grpcsharp_channel_args_destroy = GetMethodDelegate<Delegates.grpcsharp_channel_args_destroy_delegate>(library);
+            this.grpcsharp_override_default_ssl_roots = GetMethodDelegate<Delegates.grpcsharp_override_default_ssl_roots_delegate>(library);
+            this.grpcsharp_ssl_credentials_create = GetMethodDelegate<Delegates.grpcsharp_ssl_credentials_create_delegate>(library);
+            this.grpcsharp_composite_channel_credentials_create = GetMethodDelegate<Delegates.grpcsharp_composite_channel_credentials_create_delegate>(library);
+            this.grpcsharp_channel_credentials_release = GetMethodDelegate<Delegates.grpcsharp_channel_credentials_release_delegate>(library);
+            this.grpcsharp_insecure_channel_create = GetMethodDelegate<Delegates.grpcsharp_insecure_channel_create_delegate>(library);
+            this.grpcsharp_secure_channel_create = GetMethodDelegate<Delegates.grpcsharp_secure_channel_create_delegate>(library);
+            this.grpcsharp_channel_create_call = GetMethodDelegate<Delegates.grpcsharp_channel_create_call_delegate>(library);
+            this.grpcsharp_channel_check_connectivity_state = GetMethodDelegate<Delegates.grpcsharp_channel_check_connectivity_state_delegate>(library);
+            this.grpcsharp_channel_watch_connectivity_state = GetMethodDelegate<Delegates.grpcsharp_channel_watch_connectivity_state_delegate>(library);
+            this.grpcsharp_channel_get_target = GetMethodDelegate<Delegates.grpcsharp_channel_get_target_delegate>(library);
+            this.grpcsharp_channel_destroy = GetMethodDelegate<Delegates.grpcsharp_channel_destroy_delegate>(library);
+            this.grpcsharp_sizeof_grpc_event = GetMethodDelegate<Delegates.grpcsharp_sizeof_grpc_event_delegate>(library);
+            this.grpcsharp_completion_queue_create_async = GetMethodDelegate<Delegates.grpcsharp_completion_queue_create_async_delegate>(library);
+            this.grpcsharp_completion_queue_create_sync = GetMethodDelegate<Delegates.grpcsharp_completion_queue_create_sync_delegate>(library);
+            this.grpcsharp_completion_queue_shutdown = GetMethodDelegate<Delegates.grpcsharp_completion_queue_shutdown_delegate>(library);
+            this.grpcsharp_completion_queue_next = GetMethodDelegate<Delegates.grpcsharp_completion_queue_next_delegate>(library);
+            this.grpcsharp_completion_queue_pluck = GetMethodDelegate<Delegates.grpcsharp_completion_queue_pluck_delegate>(library);
+            this.grpcsharp_completion_queue_destroy = GetMethodDelegate<Delegates.grpcsharp_completion_queue_destroy_delegate>(library);
+            this.gprsharp_free = GetMethodDelegate<Delegates.gprsharp_free_delegate>(library);
+            this.grpcsharp_metadata_array_create = GetMethodDelegate<Delegates.grpcsharp_metadata_array_create_delegate>(library);
+            this.grpcsharp_metadata_array_add = GetMethodDelegate<Delegates.grpcsharp_metadata_array_add_delegate>(library);
+            this.grpcsharp_metadata_array_count = GetMethodDelegate<Delegates.grpcsharp_metadata_array_count_delegate>(library);
+            this.grpcsharp_metadata_array_get_key = GetMethodDelegate<Delegates.grpcsharp_metadata_array_get_key_delegate>(library);
+            this.grpcsharp_metadata_array_get_value = GetMethodDelegate<Delegates.grpcsharp_metadata_array_get_value_delegate>(library);
+            this.grpcsharp_metadata_array_destroy_full = GetMethodDelegate<Delegates.grpcsharp_metadata_array_destroy_full_delegate>(library);
+            this.grpcsharp_redirect_log = GetMethodDelegate<Delegates.grpcsharp_redirect_log_delegate>(library);
+            this.grpcsharp_metadata_credentials_create_from_plugin = GetMethodDelegate<Delegates.grpcsharp_metadata_credentials_create_from_plugin_delegate>(library);
+            this.grpcsharp_metadata_credentials_notify_from_plugin = GetMethodDelegate<Delegates.grpcsharp_metadata_credentials_notify_from_plugin_delegate>(library);
+            this.grpcsharp_ssl_server_credentials_create = GetMethodDelegate<Delegates.grpcsharp_ssl_server_credentials_create_delegate>(library);
+            this.grpcsharp_server_credentials_release = GetMethodDelegate<Delegates.grpcsharp_server_credentials_release_delegate>(library);
+            this.grpcsharp_server_create = GetMethodDelegate<Delegates.grpcsharp_server_create_delegate>(library);
+            this.grpcsharp_server_register_completion_queue = GetMethodDelegate<Delegates.grpcsharp_server_register_completion_queue_delegate>(library);
+            this.grpcsharp_server_add_insecure_http2_port = GetMethodDelegate<Delegates.grpcsharp_server_add_insecure_http2_port_delegate>(library);
+            this.grpcsharp_server_add_secure_http2_port = GetMethodDelegate<Delegates.grpcsharp_server_add_secure_http2_port_delegate>(library);
+            this.grpcsharp_server_start = GetMethodDelegate<Delegates.grpcsharp_server_start_delegate>(library);
+            this.grpcsharp_server_request_call = GetMethodDelegate<Delegates.grpcsharp_server_request_call_delegate>(library);
+            this.grpcsharp_server_cancel_all_calls = GetMethodDelegate<Delegates.grpcsharp_server_cancel_all_calls_delegate>(library);
+            this.grpcsharp_server_shutdown_and_notify_callback = GetMethodDelegate<Delegates.grpcsharp_server_shutdown_and_notify_callback_delegate>(library);
+            this.grpcsharp_server_destroy = GetMethodDelegate<Delegates.grpcsharp_server_destroy_delegate>(library);
+            this.grpcsharp_call_auth_context = GetMethodDelegate<Delegates.grpcsharp_call_auth_context_delegate>(library);
+            this.grpcsharp_auth_context_peer_identity_property_name = GetMethodDelegate<Delegates.grpcsharp_auth_context_peer_identity_property_name_delegate>(library);
+            this.grpcsharp_auth_context_property_iterator = GetMethodDelegate<Delegates.grpcsharp_auth_context_property_iterator_delegate>(library);
+            this.grpcsharp_auth_property_iterator_next = GetMethodDelegate<Delegates.grpcsharp_auth_property_iterator_next_delegate>(library);
+            this.grpcsharp_auth_context_release = GetMethodDelegate<Delegates.grpcsharp_auth_context_release_delegate>(library);
+            this.gprsharp_now = GetMethodDelegate<Delegates.gprsharp_now_delegate>(library);
+            this.gprsharp_inf_future = GetMethodDelegate<Delegates.gprsharp_inf_future_delegate>(library);
+            this.gprsharp_inf_past = GetMethodDelegate<Delegates.gprsharp_inf_past_delegate>(library);
+            this.gprsharp_convert_clock_type = GetMethodDelegate<Delegates.gprsharp_convert_clock_type_delegate>(library);
+            this.gprsharp_sizeof_timespec = GetMethodDelegate<Delegates.gprsharp_sizeof_timespec_delegate>(library);
+            this.grpcsharp_test_callback = GetMethodDelegate<Delegates.grpcsharp_test_callback_delegate>(library);
+            this.grpcsharp_test_nop = GetMethodDelegate<Delegates.grpcsharp_test_nop_delegate>(library);
+            this.grpcsharp_test_override_method = GetMethodDelegate<Delegates.grpcsharp_test_override_method_delegate>(library);
+        }
+        
+        public NativeMethods(DllImportsFromStaticLib unusedInstance)
+        {
+            this.grpcsharp_init = DllImportsFromStaticLib.grpcsharp_init;
+            this.grpcsharp_shutdown = DllImportsFromStaticLib.grpcsharp_shutdown;
+            this.grpcsharp_version_string = DllImportsFromStaticLib.grpcsharp_version_string;
+            this.grpcsharp_batch_context_create = DllImportsFromStaticLib.grpcsharp_batch_context_create;
+            this.grpcsharp_batch_context_recv_initial_metadata = DllImportsFromStaticLib.grpcsharp_batch_context_recv_initial_metadata;
+            this.grpcsharp_batch_context_recv_message_length = DllImportsFromStaticLib.grpcsharp_batch_context_recv_message_length;
+            this.grpcsharp_batch_context_recv_message_to_buffer = DllImportsFromStaticLib.grpcsharp_batch_context_recv_message_to_buffer;
+            this.grpcsharp_batch_context_recv_status_on_client_status = DllImportsFromStaticLib.grpcsharp_batch_context_recv_status_on_client_status;
+            this.grpcsharp_batch_context_recv_status_on_client_details = DllImportsFromStaticLib.grpcsharp_batch_context_recv_status_on_client_details;
+            this.grpcsharp_batch_context_recv_status_on_client_trailing_metadata = DllImportsFromStaticLib.grpcsharp_batch_context_recv_status_on_client_trailing_metadata;
+            this.grpcsharp_batch_context_recv_close_on_server_cancelled = DllImportsFromStaticLib.grpcsharp_batch_context_recv_close_on_server_cancelled;
+            this.grpcsharp_batch_context_reset = DllImportsFromStaticLib.grpcsharp_batch_context_reset;
+            this.grpcsharp_batch_context_destroy = DllImportsFromStaticLib.grpcsharp_batch_context_destroy;
+            this.grpcsharp_request_call_context_create = DllImportsFromStaticLib.grpcsharp_request_call_context_create;
+            this.grpcsharp_request_call_context_call = DllImportsFromStaticLib.grpcsharp_request_call_context_call;
+            this.grpcsharp_request_call_context_method = DllImportsFromStaticLib.grpcsharp_request_call_context_method;
+            this.grpcsharp_request_call_context_host = DllImportsFromStaticLib.grpcsharp_request_call_context_host;
+            this.grpcsharp_request_call_context_deadline = DllImportsFromStaticLib.grpcsharp_request_call_context_deadline;
+            this.grpcsharp_request_call_context_request_metadata = DllImportsFromStaticLib.grpcsharp_request_call_context_request_metadata;
+            this.grpcsharp_request_call_context_reset = DllImportsFromStaticLib.grpcsharp_request_call_context_reset;
+            this.grpcsharp_request_call_context_destroy = DllImportsFromStaticLib.grpcsharp_request_call_context_destroy;
+            this.grpcsharp_composite_call_credentials_create = DllImportsFromStaticLib.grpcsharp_composite_call_credentials_create;
+            this.grpcsharp_call_credentials_release = DllImportsFromStaticLib.grpcsharp_call_credentials_release;
+            this.grpcsharp_call_cancel = DllImportsFromStaticLib.grpcsharp_call_cancel;
+            this.grpcsharp_call_cancel_with_status = DllImportsFromStaticLib.grpcsharp_call_cancel_with_status;
+            this.grpcsharp_call_start_unary = DllImportsFromStaticLib.grpcsharp_call_start_unary;
+            this.grpcsharp_call_start_client_streaming = DllImportsFromStaticLib.grpcsharp_call_start_client_streaming;
+            this.grpcsharp_call_start_server_streaming = DllImportsFromStaticLib.grpcsharp_call_start_server_streaming;
+            this.grpcsharp_call_start_duplex_streaming = DllImportsFromStaticLib.grpcsharp_call_start_duplex_streaming;
+            this.grpcsharp_call_send_message = DllImportsFromStaticLib.grpcsharp_call_send_message;
+            this.grpcsharp_call_send_close_from_client = DllImportsFromStaticLib.grpcsharp_call_send_close_from_client;
+            this.grpcsharp_call_send_status_from_server = DllImportsFromStaticLib.grpcsharp_call_send_status_from_server;
+            this.grpcsharp_call_recv_message = DllImportsFromStaticLib.grpcsharp_call_recv_message;
+            this.grpcsharp_call_recv_initial_metadata = DllImportsFromStaticLib.grpcsharp_call_recv_initial_metadata;
+            this.grpcsharp_call_start_serverside = DllImportsFromStaticLib.grpcsharp_call_start_serverside;
+            this.grpcsharp_call_send_initial_metadata = DllImportsFromStaticLib.grpcsharp_call_send_initial_metadata;
+            this.grpcsharp_call_set_credentials = DllImportsFromStaticLib.grpcsharp_call_set_credentials;
+            this.grpcsharp_call_get_peer = DllImportsFromStaticLib.grpcsharp_call_get_peer;
+            this.grpcsharp_call_destroy = DllImportsFromStaticLib.grpcsharp_call_destroy;
+            this.grpcsharp_channel_args_create = DllImportsFromStaticLib.grpcsharp_channel_args_create;
+            this.grpcsharp_channel_args_set_string = DllImportsFromStaticLib.grpcsharp_channel_args_set_string;
+            this.grpcsharp_channel_args_set_integer = DllImportsFromStaticLib.grpcsharp_channel_args_set_integer;
+            this.grpcsharp_channel_args_destroy = DllImportsFromStaticLib.grpcsharp_channel_args_destroy;
+            this.grpcsharp_override_default_ssl_roots = DllImportsFromStaticLib.grpcsharp_override_default_ssl_roots;
+            this.grpcsharp_ssl_credentials_create = DllImportsFromStaticLib.grpcsharp_ssl_credentials_create;
+            this.grpcsharp_composite_channel_credentials_create = DllImportsFromStaticLib.grpcsharp_composite_channel_credentials_create;
+            this.grpcsharp_channel_credentials_release = DllImportsFromStaticLib.grpcsharp_channel_credentials_release;
+            this.grpcsharp_insecure_channel_create = DllImportsFromStaticLib.grpcsharp_insecure_channel_create;
+            this.grpcsharp_secure_channel_create = DllImportsFromStaticLib.grpcsharp_secure_channel_create;
+            this.grpcsharp_channel_create_call = DllImportsFromStaticLib.grpcsharp_channel_create_call;
+            this.grpcsharp_channel_check_connectivity_state = DllImportsFromStaticLib.grpcsharp_channel_check_connectivity_state;
+            this.grpcsharp_channel_watch_connectivity_state = DllImportsFromStaticLib.grpcsharp_channel_watch_connectivity_state;
+            this.grpcsharp_channel_get_target = DllImportsFromStaticLib.grpcsharp_channel_get_target;
+            this.grpcsharp_channel_destroy = DllImportsFromStaticLib.grpcsharp_channel_destroy;
+            this.grpcsharp_sizeof_grpc_event = DllImportsFromStaticLib.grpcsharp_sizeof_grpc_event;
+            this.grpcsharp_completion_queue_create_async = DllImportsFromStaticLib.grpcsharp_completion_queue_create_async;
+            this.grpcsharp_completion_queue_create_sync = DllImportsFromStaticLib.grpcsharp_completion_queue_create_sync;
+            this.grpcsharp_completion_queue_shutdown = DllImportsFromStaticLib.grpcsharp_completion_queue_shutdown;
+            this.grpcsharp_completion_queue_next = DllImportsFromStaticLib.grpcsharp_completion_queue_next;
+            this.grpcsharp_completion_queue_pluck = DllImportsFromStaticLib.grpcsharp_completion_queue_pluck;
+            this.grpcsharp_completion_queue_destroy = DllImportsFromStaticLib.grpcsharp_completion_queue_destroy;
+            this.gprsharp_free = DllImportsFromStaticLib.gprsharp_free;
+            this.grpcsharp_metadata_array_create = DllImportsFromStaticLib.grpcsharp_metadata_array_create;
+            this.grpcsharp_metadata_array_add = DllImportsFromStaticLib.grpcsharp_metadata_array_add;
+            this.grpcsharp_metadata_array_count = DllImportsFromStaticLib.grpcsharp_metadata_array_count;
+            this.grpcsharp_metadata_array_get_key = DllImportsFromStaticLib.grpcsharp_metadata_array_get_key;
+            this.grpcsharp_metadata_array_get_value = DllImportsFromStaticLib.grpcsharp_metadata_array_get_value;
+            this.grpcsharp_metadata_array_destroy_full = DllImportsFromStaticLib.grpcsharp_metadata_array_destroy_full;
+            this.grpcsharp_redirect_log = DllImportsFromStaticLib.grpcsharp_redirect_log;
+            this.grpcsharp_metadata_credentials_create_from_plugin = DllImportsFromStaticLib.grpcsharp_metadata_credentials_create_from_plugin;
+            this.grpcsharp_metadata_credentials_notify_from_plugin = DllImportsFromStaticLib.grpcsharp_metadata_credentials_notify_from_plugin;
+            this.grpcsharp_ssl_server_credentials_create = DllImportsFromStaticLib.grpcsharp_ssl_server_credentials_create;
+            this.grpcsharp_server_credentials_release = DllImportsFromStaticLib.grpcsharp_server_credentials_release;
+            this.grpcsharp_server_create = DllImportsFromStaticLib.grpcsharp_server_create;
+            this.grpcsharp_server_register_completion_queue = DllImportsFromStaticLib.grpcsharp_server_register_completion_queue;
+            this.grpcsharp_server_add_insecure_http2_port = DllImportsFromStaticLib.grpcsharp_server_add_insecure_http2_port;
+            this.grpcsharp_server_add_secure_http2_port = DllImportsFromStaticLib.grpcsharp_server_add_secure_http2_port;
+            this.grpcsharp_server_start = DllImportsFromStaticLib.grpcsharp_server_start;
+            this.grpcsharp_server_request_call = DllImportsFromStaticLib.grpcsharp_server_request_call;
+            this.grpcsharp_server_cancel_all_calls = DllImportsFromStaticLib.grpcsharp_server_cancel_all_calls;
+            this.grpcsharp_server_shutdown_and_notify_callback = DllImportsFromStaticLib.grpcsharp_server_shutdown_and_notify_callback;
+            this.grpcsharp_server_destroy = DllImportsFromStaticLib.grpcsharp_server_destroy;
+            this.grpcsharp_call_auth_context = DllImportsFromStaticLib.grpcsharp_call_auth_context;
+            this.grpcsharp_auth_context_peer_identity_property_name = DllImportsFromStaticLib.grpcsharp_auth_context_peer_identity_property_name;
+            this.grpcsharp_auth_context_property_iterator = DllImportsFromStaticLib.grpcsharp_auth_context_property_iterator;
+            this.grpcsharp_auth_property_iterator_next = DllImportsFromStaticLib.grpcsharp_auth_property_iterator_next;
+            this.grpcsharp_auth_context_release = DllImportsFromStaticLib.grpcsharp_auth_context_release;
+            this.gprsharp_now = DllImportsFromStaticLib.gprsharp_now;
+            this.gprsharp_inf_future = DllImportsFromStaticLib.gprsharp_inf_future;
+            this.gprsharp_inf_past = DllImportsFromStaticLib.gprsharp_inf_past;
+            this.gprsharp_convert_clock_type = DllImportsFromStaticLib.gprsharp_convert_clock_type;
+            this.gprsharp_sizeof_timespec = DllImportsFromStaticLib.gprsharp_sizeof_timespec;
+            this.grpcsharp_test_callback = DllImportsFromStaticLib.grpcsharp_test_callback;
+            this.grpcsharp_test_nop = DllImportsFromStaticLib.grpcsharp_test_nop;
+            this.grpcsharp_test_override_method = DllImportsFromStaticLib.grpcsharp_test_override_method;
+        }
+        
+        public NativeMethods(DllImportsFromSharedLib unusedInstance)
+        {
+            this.grpcsharp_init = DllImportsFromSharedLib.grpcsharp_init;
+            this.grpcsharp_shutdown = DllImportsFromSharedLib.grpcsharp_shutdown;
+            this.grpcsharp_version_string = DllImportsFromSharedLib.grpcsharp_version_string;
+            this.grpcsharp_batch_context_create = DllImportsFromSharedLib.grpcsharp_batch_context_create;
+            this.grpcsharp_batch_context_recv_initial_metadata = DllImportsFromSharedLib.grpcsharp_batch_context_recv_initial_metadata;
+            this.grpcsharp_batch_context_recv_message_length = DllImportsFromSharedLib.grpcsharp_batch_context_recv_message_length;
+            this.grpcsharp_batch_context_recv_message_to_buffer = DllImportsFromSharedLib.grpcsharp_batch_context_recv_message_to_buffer;
+            this.grpcsharp_batch_context_recv_status_on_client_status = DllImportsFromSharedLib.grpcsharp_batch_context_recv_status_on_client_status;
+            this.grpcsharp_batch_context_recv_status_on_client_details = DllImportsFromSharedLib.grpcsharp_batch_context_recv_status_on_client_details;
+            this.grpcsharp_batch_context_recv_status_on_client_trailing_metadata = DllImportsFromSharedLib.grpcsharp_batch_context_recv_status_on_client_trailing_metadata;
+            this.grpcsharp_batch_context_recv_close_on_server_cancelled = DllImportsFromSharedLib.grpcsharp_batch_context_recv_close_on_server_cancelled;
+            this.grpcsharp_batch_context_reset = DllImportsFromSharedLib.grpcsharp_batch_context_reset;
+            this.grpcsharp_batch_context_destroy = DllImportsFromSharedLib.grpcsharp_batch_context_destroy;
+            this.grpcsharp_request_call_context_create = DllImportsFromSharedLib.grpcsharp_request_call_context_create;
+            this.grpcsharp_request_call_context_call = DllImportsFromSharedLib.grpcsharp_request_call_context_call;
+            this.grpcsharp_request_call_context_method = DllImportsFromSharedLib.grpcsharp_request_call_context_method;
+            this.grpcsharp_request_call_context_host = DllImportsFromSharedLib.grpcsharp_request_call_context_host;
+            this.grpcsharp_request_call_context_deadline = DllImportsFromSharedLib.grpcsharp_request_call_context_deadline;
+            this.grpcsharp_request_call_context_request_metadata = DllImportsFromSharedLib.grpcsharp_request_call_context_request_metadata;
+            this.grpcsharp_request_call_context_reset = DllImportsFromSharedLib.grpcsharp_request_call_context_reset;
+            this.grpcsharp_request_call_context_destroy = DllImportsFromSharedLib.grpcsharp_request_call_context_destroy;
+            this.grpcsharp_composite_call_credentials_create = DllImportsFromSharedLib.grpcsharp_composite_call_credentials_create;
+            this.grpcsharp_call_credentials_release = DllImportsFromSharedLib.grpcsharp_call_credentials_release;
+            this.grpcsharp_call_cancel = DllImportsFromSharedLib.grpcsharp_call_cancel;
+            this.grpcsharp_call_cancel_with_status = DllImportsFromSharedLib.grpcsharp_call_cancel_with_status;
+            this.grpcsharp_call_start_unary = DllImportsFromSharedLib.grpcsharp_call_start_unary;
+            this.grpcsharp_call_start_client_streaming = DllImportsFromSharedLib.grpcsharp_call_start_client_streaming;
+            this.grpcsharp_call_start_server_streaming = DllImportsFromSharedLib.grpcsharp_call_start_server_streaming;
+            this.grpcsharp_call_start_duplex_streaming = DllImportsFromSharedLib.grpcsharp_call_start_duplex_streaming;
+            this.grpcsharp_call_send_message = DllImportsFromSharedLib.grpcsharp_call_send_message;
+            this.grpcsharp_call_send_close_from_client = DllImportsFromSharedLib.grpcsharp_call_send_close_from_client;
+            this.grpcsharp_call_send_status_from_server = DllImportsFromSharedLib.grpcsharp_call_send_status_from_server;
+            this.grpcsharp_call_recv_message = DllImportsFromSharedLib.grpcsharp_call_recv_message;
+            this.grpcsharp_call_recv_initial_metadata = DllImportsFromSharedLib.grpcsharp_call_recv_initial_metadata;
+            this.grpcsharp_call_start_serverside = DllImportsFromSharedLib.grpcsharp_call_start_serverside;
+            this.grpcsharp_call_send_initial_metadata = DllImportsFromSharedLib.grpcsharp_call_send_initial_metadata;
+            this.grpcsharp_call_set_credentials = DllImportsFromSharedLib.grpcsharp_call_set_credentials;
+            this.grpcsharp_call_get_peer = DllImportsFromSharedLib.grpcsharp_call_get_peer;
+            this.grpcsharp_call_destroy = DllImportsFromSharedLib.grpcsharp_call_destroy;
+            this.grpcsharp_channel_args_create = DllImportsFromSharedLib.grpcsharp_channel_args_create;
+            this.grpcsharp_channel_args_set_string = DllImportsFromSharedLib.grpcsharp_channel_args_set_string;
+            this.grpcsharp_channel_args_set_integer = DllImportsFromSharedLib.grpcsharp_channel_args_set_integer;
+            this.grpcsharp_channel_args_destroy = DllImportsFromSharedLib.grpcsharp_channel_args_destroy;
+            this.grpcsharp_override_default_ssl_roots = DllImportsFromSharedLib.grpcsharp_override_default_ssl_roots;
+            this.grpcsharp_ssl_credentials_create = DllImportsFromSharedLib.grpcsharp_ssl_credentials_create;
+            this.grpcsharp_composite_channel_credentials_create = DllImportsFromSharedLib.grpcsharp_composite_channel_credentials_create;
+            this.grpcsharp_channel_credentials_release = DllImportsFromSharedLib.grpcsharp_channel_credentials_release;
+            this.grpcsharp_insecure_channel_create = DllImportsFromSharedLib.grpcsharp_insecure_channel_create;
+            this.grpcsharp_secure_channel_create = DllImportsFromSharedLib.grpcsharp_secure_channel_create;
+            this.grpcsharp_channel_create_call = DllImportsFromSharedLib.grpcsharp_channel_create_call;
+            this.grpcsharp_channel_check_connectivity_state = DllImportsFromSharedLib.grpcsharp_channel_check_connectivity_state;
+            this.grpcsharp_channel_watch_connectivity_state = DllImportsFromSharedLib.grpcsharp_channel_watch_connectivity_state;
+            this.grpcsharp_channel_get_target = DllImportsFromSharedLib.grpcsharp_channel_get_target;
+            this.grpcsharp_channel_destroy = DllImportsFromSharedLib.grpcsharp_channel_destroy;
+            this.grpcsharp_sizeof_grpc_event = DllImportsFromSharedLib.grpcsharp_sizeof_grpc_event;
+            this.grpcsharp_completion_queue_create_async = DllImportsFromSharedLib.grpcsharp_completion_queue_create_async;
+            this.grpcsharp_completion_queue_create_sync = DllImportsFromSharedLib.grpcsharp_completion_queue_create_sync;
+            this.grpcsharp_completion_queue_shutdown = DllImportsFromSharedLib.grpcsharp_completion_queue_shutdown;
+            this.grpcsharp_completion_queue_next = DllImportsFromSharedLib.grpcsharp_completion_queue_next;
+            this.grpcsharp_completion_queue_pluck = DllImportsFromSharedLib.grpcsharp_completion_queue_pluck;
+            this.grpcsharp_completion_queue_destroy = DllImportsFromSharedLib.grpcsharp_completion_queue_destroy;
+            this.gprsharp_free = DllImportsFromSharedLib.gprsharp_free;
+            this.grpcsharp_metadata_array_create = DllImportsFromSharedLib.grpcsharp_metadata_array_create;
+            this.grpcsharp_metadata_array_add = DllImportsFromSharedLib.grpcsharp_metadata_array_add;
+            this.grpcsharp_metadata_array_count = DllImportsFromSharedLib.grpcsharp_metadata_array_count;
+            this.grpcsharp_metadata_array_get_key = DllImportsFromSharedLib.grpcsharp_metadata_array_get_key;
+            this.grpcsharp_metadata_array_get_value = DllImportsFromSharedLib.grpcsharp_metadata_array_get_value;
+            this.grpcsharp_metadata_array_destroy_full = DllImportsFromSharedLib.grpcsharp_metadata_array_destroy_full;
+            this.grpcsharp_redirect_log = DllImportsFromSharedLib.grpcsharp_redirect_log;
+            this.grpcsharp_metadata_credentials_create_from_plugin = DllImportsFromSharedLib.grpcsharp_metadata_credentials_create_from_plugin;
+            this.grpcsharp_metadata_credentials_notify_from_plugin = DllImportsFromSharedLib.grpcsharp_metadata_credentials_notify_from_plugin;
+            this.grpcsharp_ssl_server_credentials_create = DllImportsFromSharedLib.grpcsharp_ssl_server_credentials_create;
+            this.grpcsharp_server_credentials_release = DllImportsFromSharedLib.grpcsharp_server_credentials_release;
+            this.grpcsharp_server_create = DllImportsFromSharedLib.grpcsharp_server_create;
+            this.grpcsharp_server_register_completion_queue = DllImportsFromSharedLib.grpcsharp_server_register_completion_queue;
+            this.grpcsharp_server_add_insecure_http2_port = DllImportsFromSharedLib.grpcsharp_server_add_insecure_http2_port;
+            this.grpcsharp_server_add_secure_http2_port = DllImportsFromSharedLib.grpcsharp_server_add_secure_http2_port;
+            this.grpcsharp_server_start = DllImportsFromSharedLib.grpcsharp_server_start;
+            this.grpcsharp_server_request_call = DllImportsFromSharedLib.grpcsharp_server_request_call;
+            this.grpcsharp_server_cancel_all_calls = DllImportsFromSharedLib.grpcsharp_server_cancel_all_calls;
+            this.grpcsharp_server_shutdown_and_notify_callback = DllImportsFromSharedLib.grpcsharp_server_shutdown_and_notify_callback;
+            this.grpcsharp_server_destroy = DllImportsFromSharedLib.grpcsharp_server_destroy;
+            this.grpcsharp_call_auth_context = DllImportsFromSharedLib.grpcsharp_call_auth_context;
+            this.grpcsharp_auth_context_peer_identity_property_name = DllImportsFromSharedLib.grpcsharp_auth_context_peer_identity_property_name;
+            this.grpcsharp_auth_context_property_iterator = DllImportsFromSharedLib.grpcsharp_auth_context_property_iterator;
+            this.grpcsharp_auth_property_iterator_next = DllImportsFromSharedLib.grpcsharp_auth_property_iterator_next;
+            this.grpcsharp_auth_context_release = DllImportsFromSharedLib.grpcsharp_auth_context_release;
+            this.gprsharp_now = DllImportsFromSharedLib.gprsharp_now;
+            this.gprsharp_inf_future = DllImportsFromSharedLib.gprsharp_inf_future;
+            this.gprsharp_inf_past = DllImportsFromSharedLib.gprsharp_inf_past;
+            this.gprsharp_convert_clock_type = DllImportsFromSharedLib.gprsharp_convert_clock_type;
+            this.gprsharp_sizeof_timespec = DllImportsFromSharedLib.gprsharp_sizeof_timespec;
+            this.grpcsharp_test_callback = DllImportsFromSharedLib.grpcsharp_test_callback;
+            this.grpcsharp_test_nop = DllImportsFromSharedLib.grpcsharp_test_nop;
+            this.grpcsharp_test_override_method = DllImportsFromSharedLib.grpcsharp_test_override_method;
+        }
+
+        /// <summary>
+        /// Delegate types for all published native methods. Declared under inner class to prevent scope pollution.
+        /// </summary>
+        public class Delegates
+        {
+            public delegate void grpcsharp_init_delegate();
+            public delegate void grpcsharp_shutdown_delegate();
+            public delegate IntPtr grpcsharp_version_string_delegate();  // returns not-owned const char*
+            public delegate BatchContextSafeHandle grpcsharp_batch_context_create_delegate();
+            public delegate IntPtr grpcsharp_batch_context_recv_initial_metadata_delegate(BatchContextSafeHandle ctx);
+            public delegate IntPtr grpcsharp_batch_context_recv_message_length_delegate(BatchContextSafeHandle ctx);
+            public delegate void grpcsharp_batch_context_recv_message_to_buffer_delegate(BatchContextSafeHandle ctx, byte[] buffer, UIntPtr bufferLen);
+            public delegate StatusCode grpcsharp_batch_context_recv_status_on_client_status_delegate(BatchContextSafeHandle ctx);
+            public delegate IntPtr grpcsharp_batch_context_recv_status_on_client_details_delegate(BatchContextSafeHandle ctx, out UIntPtr detailsLength);
+            public delegate IntPtr grpcsharp_batch_context_recv_status_on_client_trailing_metadata_delegate(BatchContextSafeHandle ctx);
+            public delegate int grpcsharp_batch_context_recv_close_on_server_cancelled_delegate(BatchContextSafeHandle ctx);
+            public delegate void grpcsharp_batch_context_reset_delegate(BatchContextSafeHandle ctx);
+            public delegate void grpcsharp_batch_context_destroy_delegate(IntPtr ctx);
+            public delegate RequestCallContextSafeHandle grpcsharp_request_call_context_create_delegate();
+            public delegate CallSafeHandle grpcsharp_request_call_context_call_delegate(RequestCallContextSafeHandle ctx);
+            public delegate IntPtr grpcsharp_request_call_context_method_delegate(RequestCallContextSafeHandle ctx, out UIntPtr methodLength);
+            public delegate IntPtr grpcsharp_request_call_context_host_delegate(RequestCallContextSafeHandle ctx, out UIntPtr hostLength);
+            public delegate Timespec grpcsharp_request_call_context_deadline_delegate(RequestCallContextSafeHandle ctx);
+            public delegate IntPtr grpcsharp_request_call_context_request_metadata_delegate(RequestCallContextSafeHandle ctx);
+            public delegate void grpcsharp_request_call_context_reset_delegate(RequestCallContextSafeHandle ctx);
+            public delegate void grpcsharp_request_call_context_destroy_delegate(IntPtr ctx);
+            public delegate CallCredentialsSafeHandle grpcsharp_composite_call_credentials_create_delegate(CallCredentialsSafeHandle creds1, CallCredentialsSafeHandle creds2);
+            public delegate void grpcsharp_call_credentials_release_delegate(IntPtr credentials);
+            public delegate CallError grpcsharp_call_cancel_delegate(CallSafeHandle call);
+            public delegate CallError grpcsharp_call_cancel_with_status_delegate(CallSafeHandle call, StatusCode status, string description);
+            public delegate CallError grpcsharp_call_start_unary_delegate(CallSafeHandle call, BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
+            public delegate CallError grpcsharp_call_start_client_streaming_delegate(CallSafeHandle call, BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
+            public delegate CallError grpcsharp_call_start_server_streaming_delegate(CallSafeHandle call, BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
+            public delegate CallError grpcsharp_call_start_duplex_streaming_delegate(CallSafeHandle call, BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
+            public delegate CallError grpcsharp_call_send_message_delegate(CallSafeHandle call, BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, int sendEmptyInitialMetadata);
+            public delegate CallError grpcsharp_call_send_close_from_client_delegate(CallSafeHandle call, BatchContextSafeHandle ctx);
+            public delegate CallError grpcsharp_call_send_status_from_server_delegate(CallSafeHandle call, BatchContextSafeHandle ctx, StatusCode statusCode, byte[] statusMessage, UIntPtr statusMessageLen, MetadataArraySafeHandle metadataArray, int sendEmptyInitialMetadata, byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags);
+            public delegate CallError grpcsharp_call_recv_message_delegate(CallSafeHandle call, BatchContextSafeHandle ctx);
+            public delegate CallError grpcsharp_call_recv_initial_metadata_delegate(CallSafeHandle call, BatchContextSafeHandle ctx);
+            public delegate CallError grpcsharp_call_start_serverside_delegate(CallSafeHandle call, BatchContextSafeHandle ctx);
+            public delegate CallError grpcsharp_call_send_initial_metadata_delegate(CallSafeHandle call, BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray);
+            public delegate CallError grpcsharp_call_set_credentials_delegate(CallSafeHandle call, CallCredentialsSafeHandle credentials);
+            public delegate CStringSafeHandle grpcsharp_call_get_peer_delegate(CallSafeHandle call);
+            public delegate void grpcsharp_call_destroy_delegate(IntPtr call);
+            public delegate ChannelArgsSafeHandle grpcsharp_channel_args_create_delegate(UIntPtr numArgs);
+            public delegate void grpcsharp_channel_args_set_string_delegate(ChannelArgsSafeHandle args, UIntPtr index, string key, string value);
+            public delegate void grpcsharp_channel_args_set_integer_delegate(ChannelArgsSafeHandle args, UIntPtr index, string key, int value);
+            public delegate void grpcsharp_channel_args_destroy_delegate(IntPtr args);
+            public delegate void grpcsharp_override_default_ssl_roots_delegate(string pemRootCerts);
+            public delegate ChannelCredentialsSafeHandle grpcsharp_ssl_credentials_create_delegate(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey);
+            public delegate ChannelCredentialsSafeHandle grpcsharp_composite_channel_credentials_create_delegate(ChannelCredentialsSafeHandle channelCreds, CallCredentialsSafeHandle callCreds);
+            public delegate void grpcsharp_channel_credentials_release_delegate(IntPtr credentials);
+            public delegate ChannelSafeHandle grpcsharp_insecure_channel_create_delegate(string target, ChannelArgsSafeHandle channelArgs);
+            public delegate ChannelSafeHandle grpcsharp_secure_channel_create_delegate(ChannelCredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs);
+            public delegate CallSafeHandle grpcsharp_channel_create_call_delegate(ChannelSafeHandle channel, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline);
+            public delegate ChannelState grpcsharp_channel_check_connectivity_state_delegate(ChannelSafeHandle channel, int tryToConnect);
+            public delegate void grpcsharp_channel_watch_connectivity_state_delegate(ChannelSafeHandle channel, ChannelState lastObservedState, Timespec deadline, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx);
+            public delegate CStringSafeHandle grpcsharp_channel_get_target_delegate(ChannelSafeHandle call);
+            public delegate void grpcsharp_channel_destroy_delegate(IntPtr channel);
+            public delegate int grpcsharp_sizeof_grpc_event_delegate();
+            public delegate CompletionQueueSafeHandle grpcsharp_completion_queue_create_async_delegate();
+            public delegate CompletionQueueSafeHandle grpcsharp_completion_queue_create_sync_delegate();
+            public delegate void grpcsharp_completion_queue_shutdown_delegate(CompletionQueueSafeHandle cq);
+            public delegate CompletionQueueEvent grpcsharp_completion_queue_next_delegate(CompletionQueueSafeHandle cq);
+            public delegate CompletionQueueEvent grpcsharp_completion_queue_pluck_delegate(CompletionQueueSafeHandle cq, IntPtr tag);
+            public delegate void grpcsharp_completion_queue_destroy_delegate(IntPtr cq);
+            public delegate void gprsharp_free_delegate(IntPtr ptr);
+            public delegate MetadataArraySafeHandle grpcsharp_metadata_array_create_delegate(UIntPtr capacity);
+            public delegate void grpcsharp_metadata_array_add_delegate(MetadataArraySafeHandle array, string key, byte[] value, UIntPtr valueLength);
+            public delegate UIntPtr grpcsharp_metadata_array_count_delegate(IntPtr metadataArray);
+            public delegate IntPtr grpcsharp_metadata_array_get_key_delegate(IntPtr metadataArray, UIntPtr index, out UIntPtr keyLength);
+            public delegate IntPtr grpcsharp_metadata_array_get_value_delegate(IntPtr metadataArray, UIntPtr index, out UIntPtr valueLength);
+            public delegate void grpcsharp_metadata_array_destroy_full_delegate(IntPtr array);
+            public delegate void grpcsharp_redirect_log_delegate(GprLogDelegate callback);
+            public delegate CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin_delegate(NativeMetadataInterceptor interceptor);
+            public delegate void grpcsharp_metadata_credentials_notify_from_plugin_delegate(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails);
+            public delegate ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create_delegate(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, int forceClientAuth);
+            public delegate void grpcsharp_server_credentials_release_delegate(IntPtr credentials);
+            public delegate ServerSafeHandle grpcsharp_server_create_delegate(ChannelArgsSafeHandle args);
+            public delegate void grpcsharp_server_register_completion_queue_delegate(ServerSafeHandle server, CompletionQueueSafeHandle cq);
+            public delegate int grpcsharp_server_add_insecure_http2_port_delegate(ServerSafeHandle server, string addr);
+            public delegate int grpcsharp_server_add_secure_http2_port_delegate(ServerSafeHandle server, string addr, ServerCredentialsSafeHandle creds);
+            public delegate void grpcsharp_server_start_delegate(ServerSafeHandle server);
+            public delegate CallError grpcsharp_server_request_call_delegate(ServerSafeHandle server, CompletionQueueSafeHandle cq, RequestCallContextSafeHandle ctx);
+            public delegate void grpcsharp_server_cancel_all_calls_delegate(ServerSafeHandle server);
+            public delegate void grpcsharp_server_shutdown_and_notify_callback_delegate(ServerSafeHandle server, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx);
+            public delegate void grpcsharp_server_destroy_delegate(IntPtr server);
+            public delegate AuthContextSafeHandle grpcsharp_call_auth_context_delegate(CallSafeHandle call);
+            public delegate IntPtr grpcsharp_auth_context_peer_identity_property_name_delegate(AuthContextSafeHandle authContext);  // returns const char*
+            public delegate AuthContextSafeHandle.NativeAuthPropertyIterator grpcsharp_auth_context_property_iterator_delegate(AuthContextSafeHandle authContext);
+            public delegate IntPtr grpcsharp_auth_property_iterator_next_delegate(ref AuthContextSafeHandle.NativeAuthPropertyIterator iterator);  // returns const auth_property*
+            public delegate void grpcsharp_auth_context_release_delegate(IntPtr authContext);
+            public delegate Timespec gprsharp_now_delegate(ClockType clockType);
+            public delegate Timespec gprsharp_inf_future_delegate(ClockType clockType);
+            public delegate Timespec gprsharp_inf_past_delegate(ClockType clockType);
+            public delegate Timespec gprsharp_convert_clock_type_delegate(Timespec t, ClockType targetClock);
+            public delegate int gprsharp_sizeof_timespec_delegate();
+            public delegate CallError grpcsharp_test_callback_delegate([MarshalAs(UnmanagedType.FunctionPtr)] NativeCallbackTestDelegate callback);
+            public delegate IntPtr grpcsharp_test_nop_delegate(IntPtr ptr);
+            public delegate void grpcsharp_test_override_method_delegate(string methodName, string variant);
+        }
+        
+        /// <summary>
+        /// grpc_csharp_ext used as a static library (e.g Unity iOS).
+        /// </summary>
+        internal class DllImportsFromStaticLib
+        {
+            private const string ImportName = "__Internal";
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_init();
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_shutdown();
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_version_string();
+            
+            [DllImport(ImportName)]
+            public static extern BatchContextSafeHandle grpcsharp_batch_context_create();
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_batch_context_recv_initial_metadata(BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_batch_context_recv_message_length(BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_batch_context_recv_message_to_buffer(BatchContextSafeHandle ctx, byte[] buffer, UIntPtr bufferLen);
+            
+            [DllImport(ImportName)]
+            public static extern StatusCode grpcsharp_batch_context_recv_status_on_client_status(BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_batch_context_recv_status_on_client_details(BatchContextSafeHandle ctx, out UIntPtr detailsLength);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_batch_context_recv_status_on_client_trailing_metadata(BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern int grpcsharp_batch_context_recv_close_on_server_cancelled(BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_batch_context_reset(BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_batch_context_destroy(IntPtr ctx);
+            
+            [DllImport(ImportName)]
+            public static extern RequestCallContextSafeHandle grpcsharp_request_call_context_create();
+            
+            [DllImport(ImportName)]
+            public static extern CallSafeHandle grpcsharp_request_call_context_call(RequestCallContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_request_call_context_method(RequestCallContextSafeHandle ctx, out UIntPtr methodLength);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_request_call_context_host(RequestCallContextSafeHandle ctx, out UIntPtr hostLength);
+            
+            [DllImport(ImportName)]
+            public static extern Timespec grpcsharp_request_call_context_deadline(RequestCallContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_request_call_context_request_metadata(RequestCallContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_request_call_context_reset(RequestCallContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_request_call_context_destroy(IntPtr ctx);
+            
+            [DllImport(ImportName)]
+            public static extern CallCredentialsSafeHandle grpcsharp_composite_call_credentials_create(CallCredentialsSafeHandle creds1, CallCredentialsSafeHandle creds2);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_call_credentials_release(IntPtr credentials);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_cancel(CallSafeHandle call);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_cancel_with_status(CallSafeHandle call, StatusCode status, string description);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_start_unary(CallSafeHandle call, BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_start_client_streaming(CallSafeHandle call, BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_start_server_streaming(CallSafeHandle call, BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_start_duplex_streaming(CallSafeHandle call, BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_send_message(CallSafeHandle call, BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, int sendEmptyInitialMetadata);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_send_close_from_client(CallSafeHandle call, BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_send_status_from_server(CallSafeHandle call, BatchContextSafeHandle ctx, StatusCode statusCode, byte[] statusMessage, UIntPtr statusMessageLen, MetadataArraySafeHandle metadataArray, int sendEmptyInitialMetadata, byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_recv_message(CallSafeHandle call, BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_recv_initial_metadata(CallSafeHandle call, BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_start_serverside(CallSafeHandle call, BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_send_initial_metadata(CallSafeHandle call, BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_set_credentials(CallSafeHandle call, CallCredentialsSafeHandle credentials);
+            
+            [DllImport(ImportName)]
+            public static extern CStringSafeHandle grpcsharp_call_get_peer(CallSafeHandle call);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_call_destroy(IntPtr call);
+            
+            [DllImport(ImportName)]
+            public static extern ChannelArgsSafeHandle grpcsharp_channel_args_create(UIntPtr numArgs);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_channel_args_set_string(ChannelArgsSafeHandle args, UIntPtr index, string key, string value);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_channel_args_set_integer(ChannelArgsSafeHandle args, UIntPtr index, string key, int value);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_channel_args_destroy(IntPtr args);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_override_default_ssl_roots(string pemRootCerts);
+            
+            [DllImport(ImportName)]
+            public static extern ChannelCredentialsSafeHandle grpcsharp_ssl_credentials_create(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey);
+            
+            [DllImport(ImportName)]
+            public static extern ChannelCredentialsSafeHandle grpcsharp_composite_channel_credentials_create(ChannelCredentialsSafeHandle channelCreds, CallCredentialsSafeHandle callCreds);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_channel_credentials_release(IntPtr credentials);
+            
+            [DllImport(ImportName)]
+            public static extern ChannelSafeHandle grpcsharp_insecure_channel_create(string target, ChannelArgsSafeHandle channelArgs);
+            
+            [DllImport(ImportName)]
+            public static extern ChannelSafeHandle grpcsharp_secure_channel_create(ChannelCredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs);
+            
+            [DllImport(ImportName)]
+            public static extern CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline);
+            
+            [DllImport(ImportName)]
+            public static extern ChannelState grpcsharp_channel_check_connectivity_state(ChannelSafeHandle channel, int tryToConnect);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_channel_watch_connectivity_state(ChannelSafeHandle channel, ChannelState lastObservedState, Timespec deadline, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern CStringSafeHandle grpcsharp_channel_get_target(ChannelSafeHandle call);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_channel_destroy(IntPtr channel);
+            
+            [DllImport(ImportName)]
+            public static extern int grpcsharp_sizeof_grpc_event();
+            
+            [DllImport(ImportName)]
+            public static extern CompletionQueueSafeHandle grpcsharp_completion_queue_create_async();
+            
+            [DllImport(ImportName)]
+            public static extern CompletionQueueSafeHandle grpcsharp_completion_queue_create_sync();
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_completion_queue_shutdown(CompletionQueueSafeHandle cq);
+            
+            [DllImport(ImportName)]
+            public static extern CompletionQueueEvent grpcsharp_completion_queue_next(CompletionQueueSafeHandle cq);
+            
+            [DllImport(ImportName)]
+            public static extern CompletionQueueEvent grpcsharp_completion_queue_pluck(CompletionQueueSafeHandle cq, IntPtr tag);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_completion_queue_destroy(IntPtr cq);
+            
+            [DllImport(ImportName)]
+            public static extern void gprsharp_free(IntPtr ptr);
+            
+            [DllImport(ImportName)]
+            public static extern MetadataArraySafeHandle grpcsharp_metadata_array_create(UIntPtr capacity);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_metadata_array_add(MetadataArraySafeHandle array, string key, byte[] value, UIntPtr valueLength);
+            
+            [DllImport(ImportName)]
+            public static extern UIntPtr grpcsharp_metadata_array_count(IntPtr metadataArray);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_metadata_array_get_key(IntPtr metadataArray, UIntPtr index, out UIntPtr keyLength);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_metadata_array_get_value(IntPtr metadataArray, UIntPtr index, out UIntPtr valueLength);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_metadata_array_destroy_full(IntPtr array);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_redirect_log(GprLogDelegate callback);
+            
+            [DllImport(ImportName)]
+            public static extern CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin(NativeMetadataInterceptor interceptor);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails);
+            
+            [DllImport(ImportName)]
+            public static extern ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, int forceClientAuth);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_server_credentials_release(IntPtr credentials);
+            
+            [DllImport(ImportName)]
+            public static extern ServerSafeHandle grpcsharp_server_create(ChannelArgsSafeHandle args);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_server_register_completion_queue(ServerSafeHandle server, CompletionQueueSafeHandle cq);
+            
+            [DllImport(ImportName)]
+            public static extern int grpcsharp_server_add_insecure_http2_port(ServerSafeHandle server, string addr);
+            
+            [DllImport(ImportName)]
+            public static extern int grpcsharp_server_add_secure_http2_port(ServerSafeHandle server, string addr, ServerCredentialsSafeHandle creds);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_server_start(ServerSafeHandle server);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_server_request_call(ServerSafeHandle server, CompletionQueueSafeHandle cq, RequestCallContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_server_cancel_all_calls(ServerSafeHandle server);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_server_shutdown_and_notify_callback(ServerSafeHandle server, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_server_destroy(IntPtr server);
+            
+            [DllImport(ImportName)]
+            public static extern AuthContextSafeHandle grpcsharp_call_auth_context(CallSafeHandle call);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_auth_context_peer_identity_property_name(AuthContextSafeHandle authContext);
+            
+            [DllImport(ImportName)]
+            public static extern AuthContextSafeHandle.NativeAuthPropertyIterator grpcsharp_auth_context_property_iterator(AuthContextSafeHandle authContext);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_auth_property_iterator_next(ref AuthContextSafeHandle.NativeAuthPropertyIterator iterator);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_auth_context_release(IntPtr authContext);
+            
+            [DllImport(ImportName)]
+            public static extern Timespec gprsharp_now(ClockType clockType);
+            
+            [DllImport(ImportName)]
+            public static extern Timespec gprsharp_inf_future(ClockType clockType);
+            
+            [DllImport(ImportName)]
+            public static extern Timespec gprsharp_inf_past(ClockType clockType);
+            
+            [DllImport(ImportName)]
+            public static extern Timespec gprsharp_convert_clock_type(Timespec t, ClockType targetClock);
+            
+            [DllImport(ImportName)]
+            public static extern int gprsharp_sizeof_timespec();
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_test_callback([MarshalAs(UnmanagedType.FunctionPtr)] NativeCallbackTestDelegate callback);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_test_nop(IntPtr ptr);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_test_override_method(string methodName, string variant);
+        }
+        
+        /// <summary>
+        /// grpc_csharp_ext used a shared library (e.g on Unity Standalone and Android).
+        /// </summary>
+        internal class DllImportsFromSharedLib
+        {
+            private const string ImportName = "grpc_csharp_ext";
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_init();
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_shutdown();
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_version_string();
+            
+            [DllImport(ImportName)]
+            public static extern BatchContextSafeHandle grpcsharp_batch_context_create();
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_batch_context_recv_initial_metadata(BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_batch_context_recv_message_length(BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_batch_context_recv_message_to_buffer(BatchContextSafeHandle ctx, byte[] buffer, UIntPtr bufferLen);
+            
+            [DllImport(ImportName)]
+            public static extern StatusCode grpcsharp_batch_context_recv_status_on_client_status(BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_batch_context_recv_status_on_client_details(BatchContextSafeHandle ctx, out UIntPtr detailsLength);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_batch_context_recv_status_on_client_trailing_metadata(BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern int grpcsharp_batch_context_recv_close_on_server_cancelled(BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_batch_context_reset(BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_batch_context_destroy(IntPtr ctx);
+            
+            [DllImport(ImportName)]
+            public static extern RequestCallContextSafeHandle grpcsharp_request_call_context_create();
+            
+            [DllImport(ImportName)]
+            public static extern CallSafeHandle grpcsharp_request_call_context_call(RequestCallContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_request_call_context_method(RequestCallContextSafeHandle ctx, out UIntPtr methodLength);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_request_call_context_host(RequestCallContextSafeHandle ctx, out UIntPtr hostLength);
+            
+            [DllImport(ImportName)]
+            public static extern Timespec grpcsharp_request_call_context_deadline(RequestCallContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_request_call_context_request_metadata(RequestCallContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_request_call_context_reset(RequestCallContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_request_call_context_destroy(IntPtr ctx);
+            
+            [DllImport(ImportName)]
+            public static extern CallCredentialsSafeHandle grpcsharp_composite_call_credentials_create(CallCredentialsSafeHandle creds1, CallCredentialsSafeHandle creds2);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_call_credentials_release(IntPtr credentials);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_cancel(CallSafeHandle call);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_cancel_with_status(CallSafeHandle call, StatusCode status, string description);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_start_unary(CallSafeHandle call, BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_start_client_streaming(CallSafeHandle call, BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_start_server_streaming(CallSafeHandle call, BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_start_duplex_streaming(CallSafeHandle call, BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_send_message(CallSafeHandle call, BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, int sendEmptyInitialMetadata);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_send_close_from_client(CallSafeHandle call, BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_send_status_from_server(CallSafeHandle call, BatchContextSafeHandle ctx, StatusCode statusCode, byte[] statusMessage, UIntPtr statusMessageLen, MetadataArraySafeHandle metadataArray, int sendEmptyInitialMetadata, byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_recv_message(CallSafeHandle call, BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_recv_initial_metadata(CallSafeHandle call, BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_start_serverside(CallSafeHandle call, BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_send_initial_metadata(CallSafeHandle call, BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_call_set_credentials(CallSafeHandle call, CallCredentialsSafeHandle credentials);
+            
+            [DllImport(ImportName)]
+            public static extern CStringSafeHandle grpcsharp_call_get_peer(CallSafeHandle call);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_call_destroy(IntPtr call);
+            
+            [DllImport(ImportName)]
+            public static extern ChannelArgsSafeHandle grpcsharp_channel_args_create(UIntPtr numArgs);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_channel_args_set_string(ChannelArgsSafeHandle args, UIntPtr index, string key, string value);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_channel_args_set_integer(ChannelArgsSafeHandle args, UIntPtr index, string key, int value);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_channel_args_destroy(IntPtr args);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_override_default_ssl_roots(string pemRootCerts);
+            
+            [DllImport(ImportName)]
+            public static extern ChannelCredentialsSafeHandle grpcsharp_ssl_credentials_create(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey);
+            
+            [DllImport(ImportName)]
+            public static extern ChannelCredentialsSafeHandle grpcsharp_composite_channel_credentials_create(ChannelCredentialsSafeHandle channelCreds, CallCredentialsSafeHandle callCreds);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_channel_credentials_release(IntPtr credentials);
+            
+            [DllImport(ImportName)]
+            public static extern ChannelSafeHandle grpcsharp_insecure_channel_create(string target, ChannelArgsSafeHandle channelArgs);
+            
+            [DllImport(ImportName)]
+            public static extern ChannelSafeHandle grpcsharp_secure_channel_create(ChannelCredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs);
+            
+            [DllImport(ImportName)]
+            public static extern CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline);
+            
+            [DllImport(ImportName)]
+            public static extern ChannelState grpcsharp_channel_check_connectivity_state(ChannelSafeHandle channel, int tryToConnect);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_channel_watch_connectivity_state(ChannelSafeHandle channel, ChannelState lastObservedState, Timespec deadline, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern CStringSafeHandle grpcsharp_channel_get_target(ChannelSafeHandle call);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_channel_destroy(IntPtr channel);
+            
+            [DllImport(ImportName)]
+            public static extern int grpcsharp_sizeof_grpc_event();
+            
+            [DllImport(ImportName)]
+            public static extern CompletionQueueSafeHandle grpcsharp_completion_queue_create_async();
+            
+            [DllImport(ImportName)]
+            public static extern CompletionQueueSafeHandle grpcsharp_completion_queue_create_sync();
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_completion_queue_shutdown(CompletionQueueSafeHandle cq);
+            
+            [DllImport(ImportName)]
+            public static extern CompletionQueueEvent grpcsharp_completion_queue_next(CompletionQueueSafeHandle cq);
+            
+            [DllImport(ImportName)]
+            public static extern CompletionQueueEvent grpcsharp_completion_queue_pluck(CompletionQueueSafeHandle cq, IntPtr tag);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_completion_queue_destroy(IntPtr cq);
+            
+            [DllImport(ImportName)]
+            public static extern void gprsharp_free(IntPtr ptr);
+            
+            [DllImport(ImportName)]
+            public static extern MetadataArraySafeHandle grpcsharp_metadata_array_create(UIntPtr capacity);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_metadata_array_add(MetadataArraySafeHandle array, string key, byte[] value, UIntPtr valueLength);
+            
+            [DllImport(ImportName)]
+            public static extern UIntPtr grpcsharp_metadata_array_count(IntPtr metadataArray);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_metadata_array_get_key(IntPtr metadataArray, UIntPtr index, out UIntPtr keyLength);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_metadata_array_get_value(IntPtr metadataArray, UIntPtr index, out UIntPtr valueLength);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_metadata_array_destroy_full(IntPtr array);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_redirect_log(GprLogDelegate callback);
+            
+            [DllImport(ImportName)]
+            public static extern CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin(NativeMetadataInterceptor interceptor);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails);
+            
+            [DllImport(ImportName)]
+            public static extern ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, int forceClientAuth);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_server_credentials_release(IntPtr credentials);
+            
+            [DllImport(ImportName)]
+            public static extern ServerSafeHandle grpcsharp_server_create(ChannelArgsSafeHandle args);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_server_register_completion_queue(ServerSafeHandle server, CompletionQueueSafeHandle cq);
+            
+            [DllImport(ImportName)]
+            public static extern int grpcsharp_server_add_insecure_http2_port(ServerSafeHandle server, string addr);
+            
+            [DllImport(ImportName)]
+            public static extern int grpcsharp_server_add_secure_http2_port(ServerSafeHandle server, string addr, ServerCredentialsSafeHandle creds);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_server_start(ServerSafeHandle server);
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_server_request_call(ServerSafeHandle server, CompletionQueueSafeHandle cq, RequestCallContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_server_cancel_all_calls(ServerSafeHandle server);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_server_shutdown_and_notify_callback(ServerSafeHandle server, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_server_destroy(IntPtr server);
+            
+            [DllImport(ImportName)]
+            public static extern AuthContextSafeHandle grpcsharp_call_auth_context(CallSafeHandle call);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_auth_context_peer_identity_property_name(AuthContextSafeHandle authContext);
+            
+            [DllImport(ImportName)]
+            public static extern AuthContextSafeHandle.NativeAuthPropertyIterator grpcsharp_auth_context_property_iterator(AuthContextSafeHandle authContext);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_auth_property_iterator_next(ref AuthContextSafeHandle.NativeAuthPropertyIterator iterator);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_auth_context_release(IntPtr authContext);
+            
+            [DllImport(ImportName)]
+            public static extern Timespec gprsharp_now(ClockType clockType);
+            
+            [DllImport(ImportName)]
+            public static extern Timespec gprsharp_inf_future(ClockType clockType);
+            
+            [DllImport(ImportName)]
+            public static extern Timespec gprsharp_inf_past(ClockType clockType);
+            
+            [DllImport(ImportName)]
+            public static extern Timespec gprsharp_convert_clock_type(Timespec t, ClockType targetClock);
+            
+            [DllImport(ImportName)]
+            public static extern int gprsharp_sizeof_timespec();
+            
+            [DllImport(ImportName)]
+            public static extern CallError grpcsharp_test_callback([MarshalAs(UnmanagedType.FunctionPtr)] NativeCallbackTestDelegate callback);
+            
+            [DllImport(ImportName)]
+            public static extern IntPtr grpcsharp_test_nop(IntPtr ptr);
+            
+            [DllImport(ImportName)]
+            public static extern void grpcsharp_test_override_method(string methodName, string variant);
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core/Internal/NativeMethods.cs b/src/csharp/Grpc.Core/Internal/NativeMethods.cs
index 8b15c26..4e51244 100644
--- a/src/csharp/Grpc.Core/Internal/NativeMethods.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeMethods.cs
@@ -36,243 +36,10 @@
     /// An extra level of indirection is added to P/Invoke calls to allow intelligent loading
     /// of the right configuration of the native extension based on current platform, architecture etc.
     /// </summary>
-    internal class NativeMethods
+    internal partial class NativeMethods
     {
-        #region Native methods
-
-        public readonly Delegates.grpcsharp_init_delegate grpcsharp_init;
-        public readonly Delegates.grpcsharp_shutdown_delegate grpcsharp_shutdown;
-        public readonly Delegates.grpcsharp_version_string_delegate grpcsharp_version_string;
-
-        public readonly Delegates.grpcsharp_batch_context_create_delegate grpcsharp_batch_context_create;
-        public readonly Delegates.grpcsharp_batch_context_recv_initial_metadata_delegate grpcsharp_batch_context_recv_initial_metadata;
-        public readonly Delegates.grpcsharp_batch_context_recv_message_length_delegate grpcsharp_batch_context_recv_message_length;
-        public readonly Delegates.grpcsharp_batch_context_recv_message_to_buffer_delegate grpcsharp_batch_context_recv_message_to_buffer;
-        public readonly Delegates.grpcsharp_batch_context_recv_status_on_client_status_delegate grpcsharp_batch_context_recv_status_on_client_status;
-        public readonly Delegates.grpcsharp_batch_context_recv_status_on_client_details_delegate grpcsharp_batch_context_recv_status_on_client_details;
-        public readonly Delegates.grpcsharp_batch_context_recv_status_on_client_trailing_metadata_delegate grpcsharp_batch_context_recv_status_on_client_trailing_metadata;
-        public readonly Delegates.grpcsharp_batch_context_recv_close_on_server_cancelled_delegate grpcsharp_batch_context_recv_close_on_server_cancelled;
-        public readonly Delegates.grpcsharp_batch_context_reset_delegate grpcsharp_batch_context_reset;
-        public readonly Delegates.grpcsharp_batch_context_destroy_delegate grpcsharp_batch_context_destroy;
-
-        public readonly Delegates.grpcsharp_request_call_context_create_delegate grpcsharp_request_call_context_create;
-        public readonly Delegates.grpcsharp_request_call_context_call_delegate grpcsharp_request_call_context_call;
-        public readonly Delegates.grpcsharp_request_call_context_method_delegate grpcsharp_request_call_context_method;
-        public readonly Delegates.grpcsharp_request_call_context_host_delegate grpcsharp_request_call_context_host;
-        public readonly Delegates.grpcsharp_request_call_context_deadline_delegate grpcsharp_request_call_context_deadline;
-        public readonly Delegates.grpcsharp_request_call_context_request_metadata_delegate grpcsharp_request_call_context_request_metadata;
-        public readonly Delegates.grpcsharp_request_call_context_reset_delegate grpcsharp_request_call_context_reset;
-        public readonly Delegates.grpcsharp_request_call_context_destroy_delegate grpcsharp_request_call_context_destroy;
-
-        public readonly Delegates.grpcsharp_composite_call_credentials_create_delegate grpcsharp_composite_call_credentials_create;
-        public readonly Delegates.grpcsharp_call_credentials_release_delegate grpcsharp_call_credentials_release;
-
-        public readonly Delegates.grpcsharp_call_cancel_delegate grpcsharp_call_cancel;
-        public readonly Delegates.grpcsharp_call_cancel_with_status_delegate grpcsharp_call_cancel_with_status;
-        public readonly Delegates.grpcsharp_call_start_unary_delegate grpcsharp_call_start_unary;
-        public readonly Delegates.grpcsharp_call_start_client_streaming_delegate grpcsharp_call_start_client_streaming;
-        public readonly Delegates.grpcsharp_call_start_server_streaming_delegate grpcsharp_call_start_server_streaming;
-        public readonly Delegates.grpcsharp_call_start_duplex_streaming_delegate grpcsharp_call_start_duplex_streaming;
-        public readonly Delegates.grpcsharp_call_send_message_delegate grpcsharp_call_send_message;
-        public readonly Delegates.grpcsharp_call_send_close_from_client_delegate grpcsharp_call_send_close_from_client;
-        public readonly Delegates.grpcsharp_call_send_status_from_server_delegate grpcsharp_call_send_status_from_server;
-        public readonly Delegates.grpcsharp_call_recv_message_delegate grpcsharp_call_recv_message;
-        public readonly Delegates.grpcsharp_call_recv_initial_metadata_delegate grpcsharp_call_recv_initial_metadata;
-        public readonly Delegates.grpcsharp_call_start_serverside_delegate grpcsharp_call_start_serverside;
-        public readonly Delegates.grpcsharp_call_send_initial_metadata_delegate grpcsharp_call_send_initial_metadata;
-        public readonly Delegates.grpcsharp_call_set_credentials_delegate grpcsharp_call_set_credentials;
-        public readonly Delegates.grpcsharp_call_get_peer_delegate grpcsharp_call_get_peer;
-        public readonly Delegates.grpcsharp_call_destroy_delegate grpcsharp_call_destroy;
-
-        public readonly Delegates.grpcsharp_channel_args_create_delegate grpcsharp_channel_args_create;
-        public readonly Delegates.grpcsharp_channel_args_set_string_delegate grpcsharp_channel_args_set_string;
-        public readonly Delegates.grpcsharp_channel_args_set_integer_delegate grpcsharp_channel_args_set_integer;
-        public readonly Delegates.grpcsharp_channel_args_destroy_delegate grpcsharp_channel_args_destroy;
-
-        public readonly Delegates.grpcsharp_override_default_ssl_roots grpcsharp_override_default_ssl_roots;
-        public readonly Delegates.grpcsharp_ssl_credentials_create_delegate grpcsharp_ssl_credentials_create;
-        public readonly Delegates.grpcsharp_composite_channel_credentials_create_delegate grpcsharp_composite_channel_credentials_create;
-        public readonly Delegates.grpcsharp_channel_credentials_release_delegate grpcsharp_channel_credentials_release;
-
-        public readonly Delegates.grpcsharp_insecure_channel_create_delegate grpcsharp_insecure_channel_create;
-        public readonly Delegates.grpcsharp_secure_channel_create_delegate grpcsharp_secure_channel_create;
-        public readonly Delegates.grpcsharp_channel_create_call_delegate grpcsharp_channel_create_call;
-        public readonly Delegates.grpcsharp_channel_check_connectivity_state_delegate grpcsharp_channel_check_connectivity_state;
-        public readonly Delegates.grpcsharp_channel_watch_connectivity_state_delegate grpcsharp_channel_watch_connectivity_state;
-        public readonly Delegates.grpcsharp_channel_get_target_delegate grpcsharp_channel_get_target;
-        public readonly Delegates.grpcsharp_channel_destroy_delegate grpcsharp_channel_destroy;
-
-        public readonly Delegates.grpcsharp_sizeof_grpc_event_delegate grpcsharp_sizeof_grpc_event;
-
-        public readonly Delegates.grpcsharp_completion_queue_create_async_delegate grpcsharp_completion_queue_create_async;
-        public readonly Delegates.grpcsharp_completion_queue_create_sync_delegate grpcsharp_completion_queue_create_sync;
-        public readonly Delegates.grpcsharp_completion_queue_shutdown_delegate grpcsharp_completion_queue_shutdown;
-        public readonly Delegates.grpcsharp_completion_queue_next_delegate grpcsharp_completion_queue_next;
-        public readonly Delegates.grpcsharp_completion_queue_pluck_delegate grpcsharp_completion_queue_pluck;
-        public readonly Delegates.grpcsharp_completion_queue_destroy_delegate grpcsharp_completion_queue_destroy;
-
-        public readonly Delegates.gprsharp_free_delegate gprsharp_free;
-
-        public readonly Delegates.grpcsharp_metadata_array_create_delegate grpcsharp_metadata_array_create;
-        public readonly Delegates.grpcsharp_metadata_array_add_delegate grpcsharp_metadata_array_add;
-        public readonly Delegates.grpcsharp_metadata_array_count_delegate grpcsharp_metadata_array_count;
-        public readonly Delegates.grpcsharp_metadata_array_get_key_delegate grpcsharp_metadata_array_get_key;
-        public readonly Delegates.grpcsharp_metadata_array_get_value_delegate grpcsharp_metadata_array_get_value;
-        public readonly Delegates.grpcsharp_metadata_array_destroy_full_delegate grpcsharp_metadata_array_destroy_full;
-
-        public readonly Delegates.grpcsharp_redirect_log_delegate grpcsharp_redirect_log;
-
-        public readonly Delegates.grpcsharp_metadata_credentials_create_from_plugin_delegate grpcsharp_metadata_credentials_create_from_plugin;
-        public readonly Delegates.grpcsharp_metadata_credentials_notify_from_plugin_delegate grpcsharp_metadata_credentials_notify_from_plugin;
-
-        public readonly Delegates.grpcsharp_ssl_server_credentials_create_delegate grpcsharp_ssl_server_credentials_create;
-        public readonly Delegates.grpcsharp_server_credentials_release_delegate grpcsharp_server_credentials_release;
-
-        public readonly Delegates.grpcsharp_server_create_delegate grpcsharp_server_create;
-        public readonly Delegates.grpcsharp_server_register_completion_queue_delegate grpcsharp_server_register_completion_queue;
-        public readonly Delegates.grpcsharp_server_add_insecure_http2_port_delegate grpcsharp_server_add_insecure_http2_port;
-        public readonly Delegates.grpcsharp_server_add_secure_http2_port_delegate grpcsharp_server_add_secure_http2_port;
-        public readonly Delegates.grpcsharp_server_start_delegate grpcsharp_server_start;
-        public readonly Delegates.grpcsharp_server_request_call_delegate grpcsharp_server_request_call;
-        public readonly Delegates.grpcsharp_server_cancel_all_calls_delegate grpcsharp_server_cancel_all_calls;
-        public readonly Delegates.grpcsharp_server_shutdown_and_notify_callback_delegate grpcsharp_server_shutdown_and_notify_callback;
-        public readonly Delegates.grpcsharp_server_destroy_delegate grpcsharp_server_destroy;
-
-        public readonly Delegates.grpcsharp_call_auth_context_delegate grpcsharp_call_auth_context;
-        public readonly Delegates.grpcsharp_auth_context_peer_identity_property_name_delegate grpcsharp_auth_context_peer_identity_property_name;
-        public readonly Delegates.grpcsharp_auth_context_property_iterator_delegate grpcsharp_auth_context_property_iterator;
-        public readonly Delegates.grpcsharp_auth_property_iterator_next_delegate grpcsharp_auth_property_iterator_next;
-        public readonly Delegates.grpcsharp_auth_context_release_delegate grpcsharp_auth_context_release;
-
-        public readonly Delegates.gprsharp_now_delegate gprsharp_now;
-        public readonly Delegates.gprsharp_inf_future_delegate gprsharp_inf_future;
-        public readonly Delegates.gprsharp_inf_past_delegate gprsharp_inf_past;
-        public readonly Delegates.gprsharp_convert_clock_type_delegate gprsharp_convert_clock_type;
-        public readonly Delegates.gprsharp_sizeof_timespec_delegate gprsharp_sizeof_timespec;
-
-        public readonly Delegates.grpcsharp_test_callback_delegate grpcsharp_test_callback;
-        public readonly Delegates.grpcsharp_test_nop_delegate grpcsharp_test_nop;
-
-        public readonly Delegates.grpcsharp_test_override_method_delegate grpcsharp_test_override_method;
-
-        #endregion
-
-        public NativeMethods(UnmanagedLibrary library)
-        {
-            this.grpcsharp_init = GetMethodDelegate<Delegates.grpcsharp_init_delegate>(library);
-            this.grpcsharp_shutdown = GetMethodDelegate<Delegates.grpcsharp_shutdown_delegate>(library);
-            this.grpcsharp_version_string = GetMethodDelegate<Delegates.grpcsharp_version_string_delegate>(library);
-
-            this.grpcsharp_batch_context_create = GetMethodDelegate<Delegates.grpcsharp_batch_context_create_delegate>(library);
-            this.grpcsharp_batch_context_recv_initial_metadata = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_initial_metadata_delegate>(library);
-            this.grpcsharp_batch_context_recv_message_length = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_message_length_delegate>(library);
-            this.grpcsharp_batch_context_recv_message_to_buffer = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_message_to_buffer_delegate>(library);
-            this.grpcsharp_batch_context_recv_status_on_client_status = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_status_on_client_status_delegate>(library);
-            this.grpcsharp_batch_context_recv_status_on_client_details = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_status_on_client_details_delegate>(library);
-            this.grpcsharp_batch_context_recv_status_on_client_trailing_metadata = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_status_on_client_trailing_metadata_delegate>(library);
-            this.grpcsharp_batch_context_recv_close_on_server_cancelled = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_close_on_server_cancelled_delegate>(library);
-            this.grpcsharp_batch_context_reset = GetMethodDelegate<Delegates.grpcsharp_batch_context_reset_delegate>(library);
-            this.grpcsharp_batch_context_destroy = GetMethodDelegate<Delegates.grpcsharp_batch_context_destroy_delegate>(library);
-
-            this.grpcsharp_request_call_context_create = GetMethodDelegate<Delegates.grpcsharp_request_call_context_create_delegate>(library);
-            this.grpcsharp_request_call_context_call = GetMethodDelegate<Delegates.grpcsharp_request_call_context_call_delegate>(library);
-            this.grpcsharp_request_call_context_method = GetMethodDelegate<Delegates.grpcsharp_request_call_context_method_delegate>(library);
-            this.grpcsharp_request_call_context_host = GetMethodDelegate<Delegates.grpcsharp_request_call_context_host_delegate>(library);
-            this.grpcsharp_request_call_context_deadline = GetMethodDelegate<Delegates.grpcsharp_request_call_context_deadline_delegate>(library);
-            this.grpcsharp_request_call_context_request_metadata = GetMethodDelegate<Delegates.grpcsharp_request_call_context_request_metadata_delegate>(library);
-            this.grpcsharp_request_call_context_reset = GetMethodDelegate<Delegates.grpcsharp_request_call_context_reset_delegate>(library);
-            this.grpcsharp_request_call_context_destroy = GetMethodDelegate<Delegates.grpcsharp_request_call_context_destroy_delegate>(library);
-
-            this.grpcsharp_composite_call_credentials_create = GetMethodDelegate<Delegates.grpcsharp_composite_call_credentials_create_delegate>(library);
-            this.grpcsharp_call_credentials_release = GetMethodDelegate<Delegates.grpcsharp_call_credentials_release_delegate>(library);
-
-            this.grpcsharp_call_cancel = GetMethodDelegate<Delegates.grpcsharp_call_cancel_delegate>(library);
-            this.grpcsharp_call_cancel_with_status = GetMethodDelegate<Delegates.grpcsharp_call_cancel_with_status_delegate>(library);
-            this.grpcsharp_call_start_unary = GetMethodDelegate<Delegates.grpcsharp_call_start_unary_delegate>(library);
-            this.grpcsharp_call_start_client_streaming = GetMethodDelegate<Delegates.grpcsharp_call_start_client_streaming_delegate>(library);
-            this.grpcsharp_call_start_server_streaming = GetMethodDelegate<Delegates.grpcsharp_call_start_server_streaming_delegate>(library);
-            this.grpcsharp_call_start_duplex_streaming = GetMethodDelegate<Delegates.grpcsharp_call_start_duplex_streaming_delegate>(library);
-            this.grpcsharp_call_send_message = GetMethodDelegate<Delegates.grpcsharp_call_send_message_delegate>(library);
-            this.grpcsharp_call_send_close_from_client = GetMethodDelegate<Delegates.grpcsharp_call_send_close_from_client_delegate>(library);
-            this.grpcsharp_call_send_status_from_server = GetMethodDelegate<Delegates.grpcsharp_call_send_status_from_server_delegate>(library);
-            this.grpcsharp_call_recv_message = GetMethodDelegate<Delegates.grpcsharp_call_recv_message_delegate>(library);
-            this.grpcsharp_call_recv_initial_metadata = GetMethodDelegate<Delegates.grpcsharp_call_recv_initial_metadata_delegate>(library);
-            this.grpcsharp_call_start_serverside = GetMethodDelegate<Delegates.grpcsharp_call_start_serverside_delegate>(library);
-            this.grpcsharp_call_send_initial_metadata = GetMethodDelegate<Delegates.grpcsharp_call_send_initial_metadata_delegate>(library);
-            this.grpcsharp_call_set_credentials = GetMethodDelegate<Delegates.grpcsharp_call_set_credentials_delegate>(library);
-            this.grpcsharp_call_get_peer = GetMethodDelegate<Delegates.grpcsharp_call_get_peer_delegate>(library);
-            this.grpcsharp_call_destroy = GetMethodDelegate<Delegates.grpcsharp_call_destroy_delegate>(library);
-
-            this.grpcsharp_channel_args_create = GetMethodDelegate<Delegates.grpcsharp_channel_args_create_delegate>(library);
-            this.grpcsharp_channel_args_set_string = GetMethodDelegate<Delegates.grpcsharp_channel_args_set_string_delegate>(library);
-            this.grpcsharp_channel_args_set_integer = GetMethodDelegate<Delegates.grpcsharp_channel_args_set_integer_delegate>(library);
-            this.grpcsharp_channel_args_destroy = GetMethodDelegate<Delegates.grpcsharp_channel_args_destroy_delegate>(library);
-
-            this.grpcsharp_override_default_ssl_roots = GetMethodDelegate<Delegates.grpcsharp_override_default_ssl_roots>(library);
-            this.grpcsharp_ssl_credentials_create = GetMethodDelegate<Delegates.grpcsharp_ssl_credentials_create_delegate>(library);
-            this.grpcsharp_composite_channel_credentials_create = GetMethodDelegate<Delegates.grpcsharp_composite_channel_credentials_create_delegate>(library);
-            this.grpcsharp_channel_credentials_release = GetMethodDelegate<Delegates.grpcsharp_channel_credentials_release_delegate>(library);
-
-            this.grpcsharp_insecure_channel_create = GetMethodDelegate<Delegates.grpcsharp_insecure_channel_create_delegate>(library);
-            this.grpcsharp_secure_channel_create = GetMethodDelegate<Delegates.grpcsharp_secure_channel_create_delegate>(library);
-            this.grpcsharp_channel_create_call = GetMethodDelegate<Delegates.grpcsharp_channel_create_call_delegate>(library);
-            this.grpcsharp_channel_check_connectivity_state = GetMethodDelegate<Delegates.grpcsharp_channel_check_connectivity_state_delegate>(library);
-            this.grpcsharp_channel_watch_connectivity_state = GetMethodDelegate<Delegates.grpcsharp_channel_watch_connectivity_state_delegate>(library);
-            this.grpcsharp_channel_get_target = GetMethodDelegate<Delegates.grpcsharp_channel_get_target_delegate>(library);
-            this.grpcsharp_channel_destroy = GetMethodDelegate<Delegates.grpcsharp_channel_destroy_delegate>(library);
-
-            this.grpcsharp_sizeof_grpc_event = GetMethodDelegate<Delegates.grpcsharp_sizeof_grpc_event_delegate>(library);
-
-            this.grpcsharp_completion_queue_create_async = GetMethodDelegate<Delegates.grpcsharp_completion_queue_create_async_delegate>(library);
-            this.grpcsharp_completion_queue_create_sync = GetMethodDelegate<Delegates.grpcsharp_completion_queue_create_sync_delegate>(library);
-            this.grpcsharp_completion_queue_shutdown = GetMethodDelegate<Delegates.grpcsharp_completion_queue_shutdown_delegate>(library);
-            this.grpcsharp_completion_queue_next = GetMethodDelegate<Delegates.grpcsharp_completion_queue_next_delegate>(library);
-            this.grpcsharp_completion_queue_pluck = GetMethodDelegate<Delegates.grpcsharp_completion_queue_pluck_delegate>(library);
-            this.grpcsharp_completion_queue_destroy = GetMethodDelegate<Delegates.grpcsharp_completion_queue_destroy_delegate>(library);
-
-            this.gprsharp_free = GetMethodDelegate<Delegates.gprsharp_free_delegate>(library);
-
-            this.grpcsharp_metadata_array_create = GetMethodDelegate<Delegates.grpcsharp_metadata_array_create_delegate>(library);
-            this.grpcsharp_metadata_array_add = GetMethodDelegate<Delegates.grpcsharp_metadata_array_add_delegate>(library);
-            this.grpcsharp_metadata_array_count = GetMethodDelegate<Delegates.grpcsharp_metadata_array_count_delegate>(library);
-            this.grpcsharp_metadata_array_get_key = GetMethodDelegate<Delegates.grpcsharp_metadata_array_get_key_delegate>(library);
-            this.grpcsharp_metadata_array_get_value = GetMethodDelegate<Delegates.grpcsharp_metadata_array_get_value_delegate>(library);
-            this.grpcsharp_metadata_array_destroy_full = GetMethodDelegate<Delegates.grpcsharp_metadata_array_destroy_full_delegate>(library);
-
-            this.grpcsharp_redirect_log = GetMethodDelegate<Delegates.grpcsharp_redirect_log_delegate>(library);
-
-            this.grpcsharp_metadata_credentials_create_from_plugin = GetMethodDelegate<Delegates.grpcsharp_metadata_credentials_create_from_plugin_delegate>(library);
-            this.grpcsharp_metadata_credentials_notify_from_plugin = GetMethodDelegate<Delegates.grpcsharp_metadata_credentials_notify_from_plugin_delegate>(library);
-
-            this.grpcsharp_ssl_server_credentials_create = GetMethodDelegate<Delegates.grpcsharp_ssl_server_credentials_create_delegate>(library);
-            this.grpcsharp_server_credentials_release = GetMethodDelegate<Delegates.grpcsharp_server_credentials_release_delegate>(library);
-
-            this.grpcsharp_server_create = GetMethodDelegate<Delegates.grpcsharp_server_create_delegate>(library);
-            this.grpcsharp_server_register_completion_queue = GetMethodDelegate<Delegates.grpcsharp_server_register_completion_queue_delegate>(library);
-            this.grpcsharp_server_add_insecure_http2_port = GetMethodDelegate<Delegates.grpcsharp_server_add_insecure_http2_port_delegate>(library);
-            this.grpcsharp_server_add_secure_http2_port = GetMethodDelegate<Delegates.grpcsharp_server_add_secure_http2_port_delegate>(library);
-            this.grpcsharp_server_start = GetMethodDelegate<Delegates.grpcsharp_server_start_delegate>(library);
-            this.grpcsharp_server_request_call = GetMethodDelegate<Delegates.grpcsharp_server_request_call_delegate>(library);
-            this.grpcsharp_server_cancel_all_calls = GetMethodDelegate<Delegates.grpcsharp_server_cancel_all_calls_delegate>(library);
-            this.grpcsharp_server_shutdown_and_notify_callback = GetMethodDelegate<Delegates.grpcsharp_server_shutdown_and_notify_callback_delegate>(library);
-            this.grpcsharp_server_destroy = GetMethodDelegate<Delegates.grpcsharp_server_destroy_delegate>(library);
-
-            this.grpcsharp_call_auth_context = GetMethodDelegate<Delegates.grpcsharp_call_auth_context_delegate>(library);
-            this.grpcsharp_auth_context_peer_identity_property_name = GetMethodDelegate<Delegates.grpcsharp_auth_context_peer_identity_property_name_delegate>(library);
-            this.grpcsharp_auth_context_property_iterator = GetMethodDelegate<Delegates.grpcsharp_auth_context_property_iterator_delegate>(library);
-            this.grpcsharp_auth_property_iterator_next = GetMethodDelegate<Delegates.grpcsharp_auth_property_iterator_next_delegate>(library);
-            this.grpcsharp_auth_context_release = GetMethodDelegate<Delegates.grpcsharp_auth_context_release_delegate>(library);
-
-            this.gprsharp_now = GetMethodDelegate<Delegates.gprsharp_now_delegate>(library);
-            this.gprsharp_inf_future = GetMethodDelegate<Delegates.gprsharp_inf_future_delegate>(library);
-            this.gprsharp_inf_past = GetMethodDelegate<Delegates.gprsharp_inf_past_delegate>(library);
-            this.gprsharp_convert_clock_type = GetMethodDelegate<Delegates.gprsharp_convert_clock_type_delegate>(library);
-            this.gprsharp_sizeof_timespec = GetMethodDelegate<Delegates.gprsharp_sizeof_timespec_delegate>(library);
-
-            this.grpcsharp_test_callback = GetMethodDelegate<Delegates.grpcsharp_test_callback_delegate>(library);
-            this.grpcsharp_test_nop = GetMethodDelegate<Delegates.grpcsharp_test_nop_delegate>(library);
-            this.grpcsharp_test_override_method = GetMethodDelegate<Delegates.grpcsharp_test_override_method_delegate>(library);
-        }
+        // Signatures of native methods are generated from a template
+        // and can be found in NativeMethods.Generated.cs
 
         /// <summary>
         /// Gets singleton instance of this class.
@@ -297,140 +64,5 @@
             }
             return str.Substring(0, str.Length - toRemove.Length);
         }
-
-        /// <summary>
-        /// Delegate types for all published native methods. Declared under inner class to prevent scope pollution.
-        /// </summary>
-        public class Delegates
-        {
-            public delegate void grpcsharp_init_delegate();
-            public delegate void grpcsharp_shutdown_delegate();
-            public delegate IntPtr grpcsharp_version_string_delegate();  // returns not-owned const char*
-
-            public delegate BatchContextSafeHandle grpcsharp_batch_context_create_delegate();
-            public delegate IntPtr grpcsharp_batch_context_recv_initial_metadata_delegate(BatchContextSafeHandle ctx);
-            public delegate IntPtr grpcsharp_batch_context_recv_message_length_delegate(BatchContextSafeHandle ctx);
-            public delegate void grpcsharp_batch_context_recv_message_to_buffer_delegate(BatchContextSafeHandle ctx, byte[] buffer, UIntPtr bufferLen);
-            public delegate StatusCode grpcsharp_batch_context_recv_status_on_client_status_delegate(BatchContextSafeHandle ctx);
-            public delegate IntPtr grpcsharp_batch_context_recv_status_on_client_details_delegate(BatchContextSafeHandle ctx, out UIntPtr detailsLength);
-            public delegate IntPtr grpcsharp_batch_context_recv_status_on_client_trailing_metadata_delegate(BatchContextSafeHandle ctx);
-            public delegate int grpcsharp_batch_context_recv_close_on_server_cancelled_delegate(BatchContextSafeHandle ctx);
-            public delegate void grpcsharp_batch_context_reset_delegate(BatchContextSafeHandle ctx);
-            public delegate void grpcsharp_batch_context_destroy_delegate(IntPtr ctx);
-
-            public delegate RequestCallContextSafeHandle grpcsharp_request_call_context_create_delegate();
-            public delegate CallSafeHandle grpcsharp_request_call_context_call_delegate(RequestCallContextSafeHandle ctx);
-            public delegate IntPtr grpcsharp_request_call_context_method_delegate(RequestCallContextSafeHandle ctx, out UIntPtr methodLength);
-            public delegate IntPtr grpcsharp_request_call_context_host_delegate(RequestCallContextSafeHandle ctx, out UIntPtr hostLength);
-            public delegate Timespec grpcsharp_request_call_context_deadline_delegate(RequestCallContextSafeHandle ctx);
-            public delegate IntPtr grpcsharp_request_call_context_request_metadata_delegate(RequestCallContextSafeHandle ctx);
-            public delegate void grpcsharp_request_call_context_reset_delegate(RequestCallContextSafeHandle ctx);
-            public delegate void grpcsharp_request_call_context_destroy_delegate(IntPtr ctx);
-
-            public delegate CallCredentialsSafeHandle grpcsharp_composite_call_credentials_create_delegate(CallCredentialsSafeHandle creds1, CallCredentialsSafeHandle creds2);
-            public delegate void grpcsharp_call_credentials_release_delegate(IntPtr credentials);
-
-            public delegate CallError grpcsharp_call_cancel_delegate(CallSafeHandle call);
-            public delegate CallError grpcsharp_call_cancel_with_status_delegate(CallSafeHandle call, StatusCode status, string description);
-            public delegate CallError grpcsharp_call_start_unary_delegate(CallSafeHandle call,
-                BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
-            public delegate CallError grpcsharp_call_start_client_streaming_delegate(CallSafeHandle call,
-                BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
-            public delegate CallError grpcsharp_call_start_server_streaming_delegate(CallSafeHandle call,
-                BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags,
-                MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
-            public delegate CallError grpcsharp_call_start_duplex_streaming_delegate(CallSafeHandle call,
-                BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
-            public delegate CallError grpcsharp_call_send_message_delegate(CallSafeHandle call,
-                BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, int sendEmptyInitialMetadata);
-            public delegate CallError grpcsharp_call_send_close_from_client_delegate(CallSafeHandle call,
-                BatchContextSafeHandle ctx);
-            public delegate CallError grpcsharp_call_send_status_from_server_delegate(CallSafeHandle call,
-                BatchContextSafeHandle ctx, StatusCode statusCode, byte[] statusMessage, UIntPtr statusMessageLen, MetadataArraySafeHandle metadataArray, int sendEmptyInitialMetadata,
-                byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags);
-            public delegate CallError grpcsharp_call_recv_message_delegate(CallSafeHandle call,
-                BatchContextSafeHandle ctx);
-            public delegate CallError grpcsharp_call_recv_initial_metadata_delegate(CallSafeHandle call,
-                BatchContextSafeHandle ctx);
-            public delegate CallError grpcsharp_call_start_serverside_delegate(CallSafeHandle call,
-                BatchContextSafeHandle ctx);
-            public delegate CallError grpcsharp_call_send_initial_metadata_delegate(CallSafeHandle call,
-                BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray);
-            public delegate CallError grpcsharp_call_set_credentials_delegate(CallSafeHandle call, CallCredentialsSafeHandle credentials);
-            public delegate CStringSafeHandle grpcsharp_call_get_peer_delegate(CallSafeHandle call);
-            public delegate void grpcsharp_call_destroy_delegate(IntPtr call);
-
-            public delegate ChannelArgsSafeHandle grpcsharp_channel_args_create_delegate(UIntPtr numArgs);
-            public delegate void grpcsharp_channel_args_set_string_delegate(ChannelArgsSafeHandle args, UIntPtr index, string key, string value);
-            public delegate void grpcsharp_channel_args_set_integer_delegate(ChannelArgsSafeHandle args, UIntPtr index, string key, int value);
-            public delegate void grpcsharp_channel_args_destroy_delegate(IntPtr args);
-
-            public delegate void grpcsharp_override_default_ssl_roots(string pemRootCerts);
-            public delegate ChannelCredentialsSafeHandle grpcsharp_ssl_credentials_create_delegate(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey);
-            public delegate ChannelCredentialsSafeHandle grpcsharp_composite_channel_credentials_create_delegate(ChannelCredentialsSafeHandle channelCreds, CallCredentialsSafeHandle callCreds);
-            public delegate void grpcsharp_channel_credentials_release_delegate(IntPtr credentials);
-
-            public delegate ChannelSafeHandle grpcsharp_insecure_channel_create_delegate(string target, ChannelArgsSafeHandle channelArgs);
-            public delegate ChannelSafeHandle grpcsharp_secure_channel_create_delegate(ChannelCredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs);
-            public delegate CallSafeHandle grpcsharp_channel_create_call_delegate(ChannelSafeHandle channel, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline);
-            public delegate ChannelState grpcsharp_channel_check_connectivity_state_delegate(ChannelSafeHandle channel, int tryToConnect);
-            public delegate void grpcsharp_channel_watch_connectivity_state_delegate(ChannelSafeHandle channel, ChannelState lastObservedState,
-                Timespec deadline, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx);
-            public delegate CStringSafeHandle grpcsharp_channel_get_target_delegate(ChannelSafeHandle call);
-            public delegate void grpcsharp_channel_destroy_delegate(IntPtr channel);
-
-            public delegate int grpcsharp_sizeof_grpc_event_delegate();
-
-            public delegate CompletionQueueSafeHandle grpcsharp_completion_queue_create_async_delegate();
-            public delegate CompletionQueueSafeHandle grpcsharp_completion_queue_create_sync_delegate();
-            public delegate void grpcsharp_completion_queue_shutdown_delegate(CompletionQueueSafeHandle cq);
-            public delegate CompletionQueueEvent grpcsharp_completion_queue_next_delegate(CompletionQueueSafeHandle cq);
-            public delegate CompletionQueueEvent grpcsharp_completion_queue_pluck_delegate(CompletionQueueSafeHandle cq, IntPtr tag);
-            public delegate void grpcsharp_completion_queue_destroy_delegate(IntPtr cq);
-
-            public delegate void gprsharp_free_delegate(IntPtr ptr);
-
-            public delegate MetadataArraySafeHandle grpcsharp_metadata_array_create_delegate(UIntPtr capacity);
-            public delegate void grpcsharp_metadata_array_add_delegate(MetadataArraySafeHandle array, string key, byte[] value, UIntPtr valueLength);
-            public delegate UIntPtr grpcsharp_metadata_array_count_delegate(IntPtr metadataArray);
-            public delegate IntPtr grpcsharp_metadata_array_get_key_delegate(IntPtr metadataArray, UIntPtr index, out UIntPtr keyLength);
-            public delegate IntPtr grpcsharp_metadata_array_get_value_delegate(IntPtr metadataArray, UIntPtr index, out UIntPtr valueLength);
-            public delegate void grpcsharp_metadata_array_destroy_full_delegate(IntPtr array);
-
-            public delegate void grpcsharp_redirect_log_delegate(GprLogDelegate callback);
-
-            public delegate CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin_delegate(NativeMetadataInterceptor interceptor);
-            public delegate void grpcsharp_metadata_credentials_notify_from_plugin_delegate(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails);
-
-            public delegate ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create_delegate(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, int forceClientAuth);
-            public delegate void grpcsharp_server_credentials_release_delegate(IntPtr credentials);
-
-            public delegate ServerSafeHandle grpcsharp_server_create_delegate(ChannelArgsSafeHandle args);
-            public delegate void grpcsharp_server_register_completion_queue_delegate(ServerSafeHandle server, CompletionQueueSafeHandle cq);
-            public delegate int grpcsharp_server_add_insecure_http2_port_delegate(ServerSafeHandle server, string addr);
-            public delegate int grpcsharp_server_add_secure_http2_port_delegate(ServerSafeHandle server, string addr, ServerCredentialsSafeHandle creds);
-            public delegate void grpcsharp_server_start_delegate(ServerSafeHandle server);
-            public delegate CallError grpcsharp_server_request_call_delegate(ServerSafeHandle server, CompletionQueueSafeHandle cq, RequestCallContextSafeHandle ctx);
-            public delegate void grpcsharp_server_cancel_all_calls_delegate(ServerSafeHandle server);
-            public delegate void grpcsharp_server_shutdown_and_notify_callback_delegate(ServerSafeHandle server, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx);
-            public delegate void grpcsharp_server_destroy_delegate(IntPtr server);
-
-            public delegate AuthContextSafeHandle grpcsharp_call_auth_context_delegate(CallSafeHandle call);
-            public delegate IntPtr grpcsharp_auth_context_peer_identity_property_name_delegate(AuthContextSafeHandle authContext);  // returns const char*
-            public delegate AuthContextSafeHandle.NativeAuthPropertyIterator grpcsharp_auth_context_property_iterator_delegate(AuthContextSafeHandle authContext);
-            public delegate IntPtr grpcsharp_auth_property_iterator_next_delegate(ref AuthContextSafeHandle.NativeAuthPropertyIterator iterator);  // returns const auth_property*
-            public delegate void grpcsharp_auth_context_release_delegate(IntPtr authContext);
-
-            public delegate Timespec gprsharp_now_delegate(ClockType clockType);
-            public delegate Timespec gprsharp_inf_future_delegate(ClockType clockType);
-            public delegate Timespec gprsharp_inf_past_delegate(ClockType clockType);
-
-            public delegate Timespec gprsharp_convert_clock_type_delegate(Timespec t, ClockType targetClock);
-            public delegate int gprsharp_sizeof_timespec_delegate();
-
-            public delegate CallError grpcsharp_test_callback_delegate([MarshalAs(UnmanagedType.FunctionPtr)] NativeCallbackTestDelegate callback);
-            public delegate IntPtr grpcsharp_test_nop_delegate(IntPtr ptr);
-            public delegate void grpcsharp_test_override_method_delegate(string methodName, string variant);
-        }
     }
 }
diff --git a/src/csharp/Grpc.Core/Internal/PlatformApis.cs b/src/csharp/Grpc.Core/Internal/PlatformApis.cs
index 6bb4242..b90fbcc 100644
--- a/src/csharp/Grpc.Core/Internal/PlatformApis.cs
+++ b/src/csharp/Grpc.Core/Internal/PlatformApis.cs
@@ -23,6 +23,7 @@
 using System.Reflection;
 using System.Runtime.InteropServices;
 using System.Threading;
+using Grpc.Core.Utils;
 
 namespace Grpc.Core.Internal
 {
@@ -31,11 +32,13 @@
     /// </summary>
     internal static class PlatformApis
     {
+        const string UnityEngineApplicationClassName = "UnityEngine.Application, UnityEngine";
         static readonly bool isLinux;
         static readonly bool isMacOSX;
         static readonly bool isWindows;
         static readonly bool isMono;
         static readonly bool isNetCore;
+        static readonly bool isUnity;
 
         static PlatformApis()
         {
@@ -54,6 +57,7 @@
             isNetCore = false;
 #endif
             isMono = Type.GetType("Mono.Runtime") != null;
+            isUnity = Type.GetType(UnityEngineApplicationClassName) != null;
         }
 
         public static bool IsLinux
@@ -77,6 +81,14 @@
         }
 
         /// <summary>
+        /// true if running on Unity platform.
+        /// </summary>
+        public static bool IsUnity
+        {
+            get { return isUnity; }
+        }
+
+        /// <summary>
         /// true if running on .NET Core (CoreCLR), false otherwise.
         /// </summary>
         public static bool IsNetCore
@@ -89,6 +101,22 @@
             get { return IntPtr.Size == 8; }
         }
 
+        /// <summary>
+        /// Returns <c>UnityEngine.Application.platform</c> as a string.
+        /// See https://docs.unity3d.com/ScriptReference/Application-platform.html for possible values.
+        /// Value is obtained via reflection to avoid compile-time dependency on Unity.
+        /// This method should only be called if <c>IsUnity</c> is <c>true</c>.
+        /// </summary>
+        public static string GetUnityRuntimePlatform()
+        {
+            GrpcPreconditions.CheckState(IsUnity, "Not running on Unity.");
+#if NETSTANDARD1_5
+            return Type.GetType(UnityEngineApplicationClassName).GetTypeInfo().GetProperty("platform").GetValue(null).ToString();
+#else
+            return Type.GetType(UnityEngineApplicationClassName).GetProperty("platform").GetValue(null).ToString();
+#endif
+        }
+
         [DllImport("libc")]
         static extern int uname(IntPtr buf);
 
diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
index 98995a0..81522cf 100644
--- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
@@ -21,6 +21,7 @@
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
+using Grpc.Core.Interceptors;
 using Grpc.Core.Internal;
 using Grpc.Core.Logging;
 using Grpc.Core.Utils;
@@ -30,6 +31,7 @@
     internal interface IServerCallHandler
     {
         Task HandleCall(ServerRpcNew newRpc, CompletionQueueSafeHandle cq);
+        IServerCallHandler Intercept(Interceptor interceptor);
     }
 
     internal class UnaryServerCallHandler<TRequest, TResponse> : IServerCallHandler
@@ -74,7 +76,7 @@
             {
                 if (!(e is RpcException))
                 {
-                    Logger.Warning(e, "Exception occured in handler.");
+                    Logger.Warning(e, "Exception occurred in the handler or an interceptor.");
                 }
                 status = HandlerUtils.GetStatusFromExceptionAndMergeTrailers(e, context.ResponseTrailers);
             }
@@ -89,6 +91,11 @@
             }
             await finishedTask.ConfigureAwait(false);
         }
+
+        public IServerCallHandler Intercept(Interceptor interceptor)
+        {
+            return new UnaryServerCallHandler<TRequest, TResponse>(method, (request, context) => interceptor.UnaryServerHandler(request, context, handler));
+        }
     }
 
     internal class ServerStreamingServerCallHandler<TRequest, TResponse> : IServerCallHandler
@@ -131,7 +138,7 @@
             {
                 if (!(e is RpcException))
                 {
-                    Logger.Warning(e, "Exception occured in handler.");
+                    Logger.Warning(e, "Exception occurred in the handler or an interceptor.");
                 }
                 status = HandlerUtils.GetStatusFromExceptionAndMergeTrailers(e, context.ResponseTrailers);
             }
@@ -147,6 +154,11 @@
             }
             await finishedTask.ConfigureAwait(false);
         }
+
+        public IServerCallHandler Intercept(Interceptor interceptor)
+        {
+            return new ServerStreamingServerCallHandler<TRequest, TResponse>(method, (request, responseStream, context) => interceptor.ServerStreamingServerHandler(request, responseStream, context, handler));
+        }
     }
 
     internal class ClientStreamingServerCallHandler<TRequest, TResponse> : IServerCallHandler
@@ -189,7 +201,7 @@
             {
                 if (!(e is RpcException))
                 {
-                    Logger.Warning(e, "Exception occured in handler.");
+                    Logger.Warning(e, "Exception occurred in the handler or an interceptor.");
                 }
                 status = HandlerUtils.GetStatusFromExceptionAndMergeTrailers(e, context.ResponseTrailers);
             }
@@ -205,6 +217,11 @@
             }
             await finishedTask.ConfigureAwait(false);
         }
+
+        public IServerCallHandler Intercept(Interceptor interceptor)
+        {
+            return new ClientStreamingServerCallHandler<TRequest, TResponse>(method, (requestStream, context) => interceptor.ClientStreamingServerHandler(requestStream, context, handler));
+        }
     }
 
     internal class DuplexStreamingServerCallHandler<TRequest, TResponse> : IServerCallHandler
@@ -245,7 +262,7 @@
             {
                 if (!(e is RpcException))
                 {
-                    Logger.Warning(e, "Exception occured in handler.");
+                    Logger.Warning(e, "Exception occurred in the handler or an interceptor.");
                 }
                 status = HandlerUtils.GetStatusFromExceptionAndMergeTrailers(e, context.ResponseTrailers);
             }
@@ -260,6 +277,11 @@
             }
             await finishedTask.ConfigureAwait(false);
         }
+
+        public IServerCallHandler Intercept(Interceptor interceptor)
+        {
+            return new DuplexStreamingServerCallHandler<TRequest, TResponse>(method, (requestStream, responseStream, context) => interceptor.DuplexStreamingServerHandler(requestStream, responseStream, context, handler));
+        }
     }
 
     internal class UnimplementedMethodCallHandler : IServerCallHandler
@@ -288,6 +310,11 @@
         {
             return callHandlerImpl.HandleCall(newRpc, cq);
         }
+
+        public IServerCallHandler Intercept(Interceptor interceptor)
+        {
+            return this;  // Do not intercept unimplemented methods.
+        }
     }
 
     internal static class HandlerUtils
diff --git a/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs b/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs
index aa5f81e..7185d68 100644
--- a/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs
+++ b/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs
@@ -64,7 +64,7 @@
         /// </summary>
         /// <param name="symbolName"></param>
         /// <returns></returns>
-        public IntPtr LoadSymbol(string symbolName)
+        private IntPtr LoadSymbol(string symbolName)
         {
             if (PlatformApis.IsWindows)
             {
diff --git a/src/csharp/Grpc.Core/ServerServiceDefinition.cs b/src/csharp/Grpc.Core/ServerServiceDefinition.cs
index 59868c1..07c6aa1 100644
--- a/src/csharp/Grpc.Core/ServerServiceDefinition.cs
+++ b/src/csharp/Grpc.Core/ServerServiceDefinition.cs
@@ -19,7 +19,10 @@
 using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
+using System.Linq;
+using Grpc.Core.Interceptors;
 using Grpc.Core.Internal;
+using Grpc.Core.Utils;
 
 namespace Grpc.Core
 {
@@ -32,7 +35,7 @@
     {
         readonly ReadOnlyDictionary<string, IServerCallHandler> callHandlers;
 
-        private ServerServiceDefinition(Dictionary<string, IServerCallHandler> callHandlers)
+        internal ServerServiceDefinition(Dictionary<string, IServerCallHandler> callHandlers)
         {
             this.callHandlers = new ReadOnlyDictionary<string, IServerCallHandler>(callHandlers);
         }
diff --git a/src/csharp/Grpc.Core/SourceLink.csproj.include b/src/csharp/Grpc.Core/SourceLink.csproj.include
index 02ae79f..0ec273f 100755
--- a/src/csharp/Grpc.Core/SourceLink.csproj.include
+++ b/src/csharp/Grpc.Core/SourceLink.csproj.include
@@ -13,7 +13,7 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="SourceLink.Embed.AllSourceFiles" Version="2.7.3" PrivateAssets="all" />
+    <PackageReference Include="SourceLink.Create.CommandLine" Version="2.7.6" PrivateAssets="all" />
   </ItemGroup>
 
 </Project>
diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include
index 539d3a9..9b55f24 100755
--- a/src/csharp/Grpc.Core/Version.csproj.include
+++ b/src/csharp/Grpc.Core/Version.csproj.include
@@ -1,7 +1,7 @@
 <!-- This file is generated -->
 <Project>
   <PropertyGroup>
-    <GrpcCsharpVersion>1.10.0-dev</GrpcCsharpVersion>
+    <GrpcCsharpVersion>1.11.0-dev</GrpcCsharpVersion>
     <GoogleProtobufVersion>3.3.0</GoogleProtobufVersion>
   </PropertyGroup>
 </Project>
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index f1aef46..2902aee 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -33,11 +33,11 @@
         /// <summary>
         /// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies
         /// </summary>
-        public const string CurrentAssemblyFileVersion = "1.10.0.0";
+        public const string CurrentAssemblyFileVersion = "1.11.0.0";
 
         /// <summary>
         /// Current version of gRPC C#
         /// </summary>
-        public const string CurrentVersion = "1.10.0-dev";
+        public const string CurrentVersion = "1.11.0-dev";
     }
 }
diff --git a/src/csharp/Grpc.Examples/MathGrpc.cs b/src/csharp/Grpc.Examples/MathGrpc.cs
index e29b108..045708b 100644
--- a/src/csharp/Grpc.Examples/MathGrpc.cs
+++ b/src/csharp/Grpc.Examples/MathGrpc.cs
@@ -20,9 +20,6 @@
 #pragma warning disable 1591
 #region Designer generated code
 
-using System;
-using System.Threading;
-using System.Threading.Tasks;
 using grpc = global::Grpc.Core;
 
 namespace Math {
@@ -159,7 +156,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The response received from the server.</returns>
-      public virtual global::Math.DivReply Div(global::Math.DivArgs request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual global::Math.DivReply Div(global::Math.DivArgs request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return Div(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -183,7 +180,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return DivAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -208,7 +205,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return DivMany(new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -234,7 +231,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return Fib(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -258,7 +255,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return Sum(new grpc::CallOptions(headers, deadline, cancellationToken));
       }
diff --git a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
index 24a7259..1d80bcd 100644
--- a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
+++ b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
@@ -20,9 +20,6 @@
 #pragma warning disable 1591
 #region Designer generated code
 
-using System;
-using System.Threading;
-using System.Threading.Tasks;
 using grpc = global::Grpc.Core;
 
 namespace Grpc.Health.V1 {
@@ -79,7 +76,7 @@
       {
       }
 
-      public virtual global::Grpc.Health.V1.HealthCheckResponse Check(global::Grpc.Health.V1.HealthCheckRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual global::Grpc.Health.V1.HealthCheckResponse Check(global::Grpc.Health.V1.HealthCheckRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return Check(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -87,7 +84,7 @@
       {
         return CallInvoker.BlockingUnaryCall(__Method_Check, null, options, request);
       }
-      public virtual grpc::AsyncUnaryCall<global::Grpc.Health.V1.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1.HealthCheckRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncUnaryCall<global::Grpc.Health.V1.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1.HealthCheckRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return CheckAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
diff --git a/src/csharp/Grpc.IntegrationTesting/Control.cs b/src/csharp/Grpc.IntegrationTesting/Control.cs
index 8e5da7b..8795728 100644
--- a/src/csharp/Grpc.IntegrationTesting/Control.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Control.cs
@@ -32,7 +32,7 @@
             "U2VjdXJpdHlQYXJhbXMSEwoLdXNlX3Rlc3RfY2EYASABKAgSHAoUc2VydmVy",
             "X2hvc3Rfb3ZlcnJpZGUYAiABKAkSEQoJY3JlZF90eXBlGAMgASgJIk0KCkNo",
             "YW5uZWxBcmcSDAoEbmFtZRgBIAEoCRITCglzdHJfdmFsdWUYAiABKAlIABIT",
-            "CglpbnRfdmFsdWUYAyABKAVIAEIHCgV2YWx1ZSLVBAoMQ2xpZW50Q29uZmln",
+            "CglpbnRfdmFsdWUYAyABKAVIAEIHCgV2YWx1ZSLvBAoMQ2xpZW50Q29uZmln",
             "EhYKDnNlcnZlcl90YXJnZXRzGAEgAygJEi0KC2NsaWVudF90eXBlGAIgASgO",
             "MhguZ3JwYy50ZXN0aW5nLkNsaWVudFR5cGUSNQoPc2VjdXJpdHlfcGFyYW1z",
             "GAMgASgLMhwuZ3JwYy50ZXN0aW5nLlNlY3VyaXR5UGFyYW1zEiQKHG91dHN0",
@@ -45,59 +45,60 @@
             "dG9ncmFtUGFyYW1zEhEKCWNvcmVfbGlzdBgNIAMoBRISCgpjb3JlX2xpbWl0",
             "GA4gASgFEhgKEG90aGVyX2NsaWVudF9hcGkYDyABKAkSLgoMY2hhbm5lbF9h",
             "cmdzGBAgAygLMhguZ3JwYy50ZXN0aW5nLkNoYW5uZWxBcmcSFgoOdGhyZWFk",
-            "c19wZXJfY3EYESABKAUSGwoTbWVzc2FnZXNfcGVyX3N0cmVhbRgSIAEoBSI4",
-            "CgxDbGllbnRTdGF0dXMSKAoFc3RhdHMYASABKAsyGS5ncnBjLnRlc3Rpbmcu",
-            "Q2xpZW50U3RhdHMiFQoETWFyaxINCgVyZXNldBgBIAEoCCJoCgpDbGllbnRB",
-            "cmdzEisKBXNldHVwGAEgASgLMhouZ3JwYy50ZXN0aW5nLkNsaWVudENvbmZp",
-            "Z0gAEiIKBG1hcmsYAiABKAsyEi5ncnBjLnRlc3RpbmcuTWFya0gAQgkKB2Fy",
-            "Z3R5cGUi/QIKDFNlcnZlckNvbmZpZxItCgtzZXJ2ZXJfdHlwZRgBIAEoDjIY",
-            "LmdycGMudGVzdGluZy5TZXJ2ZXJUeXBlEjUKD3NlY3VyaXR5X3BhcmFtcxgC",
-            "IAEoCzIcLmdycGMudGVzdGluZy5TZWN1cml0eVBhcmFtcxIMCgRwb3J0GAQg",
-            "ASgFEhwKFGFzeW5jX3NlcnZlcl90aHJlYWRzGAcgASgFEhIKCmNvcmVfbGlt",
-            "aXQYCCABKAUSMwoOcGF5bG9hZF9jb25maWcYCSABKAsyGy5ncnBjLnRlc3Rp",
-            "bmcuUGF5bG9hZENvbmZpZxIRCgljb3JlX2xpc3QYCiADKAUSGAoQb3RoZXJf",
-            "c2VydmVyX2FwaRgLIAEoCRIWCg50aHJlYWRzX3Blcl9jcRgMIAEoBRIcChNy",
-            "ZXNvdXJjZV9xdW90YV9zaXplGOkHIAEoBRIvCgxjaGFubmVsX2FyZ3MY6gcg",
-            "AygLMhguZ3JwYy50ZXN0aW5nLkNoYW5uZWxBcmciaAoKU2VydmVyQXJncxIr",
-            "CgVzZXR1cBgBIAEoCzIaLmdycGMudGVzdGluZy5TZXJ2ZXJDb25maWdIABIi",
-            "CgRtYXJrGAIgASgLMhIuZ3JwYy50ZXN0aW5nLk1hcmtIAEIJCgdhcmd0eXBl",
-            "IlUKDFNlcnZlclN0YXR1cxIoCgVzdGF0cxgBIAEoCzIZLmdycGMudGVzdGlu",
-            "Zy5TZXJ2ZXJTdGF0cxIMCgRwb3J0GAIgASgFEg0KBWNvcmVzGAMgASgFIg0K",
-            "C0NvcmVSZXF1ZXN0Ih0KDENvcmVSZXNwb25zZRINCgVjb3JlcxgBIAEoBSIG",
-            "CgRWb2lkIv0BCghTY2VuYXJpbxIMCgRuYW1lGAEgASgJEjEKDWNsaWVudF9j",
-            "b25maWcYAiABKAsyGi5ncnBjLnRlc3RpbmcuQ2xpZW50Q29uZmlnEhMKC251",
-            "bV9jbGllbnRzGAMgASgFEjEKDXNlcnZlcl9jb25maWcYBCABKAsyGi5ncnBj",
-            "LnRlc3RpbmcuU2VydmVyQ29uZmlnEhMKC251bV9zZXJ2ZXJzGAUgASgFEhYK",
-            "Dndhcm11cF9zZWNvbmRzGAYgASgFEhkKEWJlbmNobWFya19zZWNvbmRzGAcg",
-            "ASgFEiAKGHNwYXduX2xvY2FsX3dvcmtlcl9jb3VudBgIIAEoBSI2CglTY2Vu",
-            "YXJpb3MSKQoJc2NlbmFyaW9zGAEgAygLMhYuZ3JwYy50ZXN0aW5nLlNjZW5h",
-            "cmlvIoQEChVTY2VuYXJpb1Jlc3VsdFN1bW1hcnkSCwoDcXBzGAEgASgBEhsK",
-            "E3Fwc19wZXJfc2VydmVyX2NvcmUYAiABKAESGgoSc2VydmVyX3N5c3RlbV90",
-            "aW1lGAMgASgBEhgKEHNlcnZlcl91c2VyX3RpbWUYBCABKAESGgoSY2xpZW50",
-            "X3N5c3RlbV90aW1lGAUgASgBEhgKEGNsaWVudF91c2VyX3RpbWUYBiABKAES",
-            "EgoKbGF0ZW5jeV81MBgHIAEoARISCgpsYXRlbmN5XzkwGAggASgBEhIKCmxh",
-            "dGVuY3lfOTUYCSABKAESEgoKbGF0ZW5jeV85ORgKIAEoARITCgtsYXRlbmN5",
-            "Xzk5ORgLIAEoARIYChBzZXJ2ZXJfY3B1X3VzYWdlGAwgASgBEiYKHnN1Y2Nl",
-            "c3NmdWxfcmVxdWVzdHNfcGVyX3NlY29uZBgNIAEoARIiChpmYWlsZWRfcmVx",
-            "dWVzdHNfcGVyX3NlY29uZBgOIAEoARIgChhjbGllbnRfcG9sbHNfcGVyX3Jl",
-            "cXVlc3QYDyABKAESIAoYc2VydmVyX3BvbGxzX3Blcl9yZXF1ZXN0GBAgASgB",
-            "EiIKGnNlcnZlcl9xdWVyaWVzX3Blcl9jcHVfc2VjGBEgASgBEiIKGmNsaWVu",
-            "dF9xdWVyaWVzX3Blcl9jcHVfc2VjGBIgASgBIoMDCg5TY2VuYXJpb1Jlc3Vs",
-            "dBIoCghzY2VuYXJpbxgBIAEoCzIWLmdycGMudGVzdGluZy5TY2VuYXJpbxIu",
-            "CglsYXRlbmNpZXMYAiABKAsyGy5ncnBjLnRlc3RpbmcuSGlzdG9ncmFtRGF0",
-            "YRIvCgxjbGllbnRfc3RhdHMYAyADKAsyGS5ncnBjLnRlc3RpbmcuQ2xpZW50",
-            "U3RhdHMSLwoMc2VydmVyX3N0YXRzGAQgAygLMhkuZ3JwYy50ZXN0aW5nLlNl",
-            "cnZlclN0YXRzEhQKDHNlcnZlcl9jb3JlcxgFIAMoBRI0CgdzdW1tYXJ5GAYg",
-            "ASgLMiMuZ3JwYy50ZXN0aW5nLlNjZW5hcmlvUmVzdWx0U3VtbWFyeRIWCg5j",
-            "bGllbnRfc3VjY2VzcxgHIAMoCBIWCg5zZXJ2ZXJfc3VjY2VzcxgIIAMoCBI5",
-            "Cg9yZXF1ZXN0X3Jlc3VsdHMYCSADKAsyIC5ncnBjLnRlc3RpbmcuUmVxdWVz",
-            "dFJlc3VsdENvdW50KkEKCkNsaWVudFR5cGUSDwoLU1lOQ19DTElFTlQQABIQ",
-            "CgxBU1lOQ19DTElFTlQQARIQCgxPVEhFUl9DTElFTlQQAipbCgpTZXJ2ZXJU",
-            "eXBlEg8KC1NZTkNfU0VSVkVSEAASEAoMQVNZTkNfU0VSVkVSEAESGAoUQVNZ",
-            "TkNfR0VORVJJQ19TRVJWRVIQAhIQCgxPVEhFUl9TRVJWRVIQAypyCgdScGNU",
-            "eXBlEgkKBVVOQVJZEAASDQoJU1RSRUFNSU5HEAESGQoVU1RSRUFNSU5HX0ZS",
-            "T01fQ0xJRU5UEAISGQoVU1RSRUFNSU5HX0ZST01fU0VSVkVSEAMSFwoTU1RS",
-            "RUFNSU5HX0JPVEhfV0FZUxAEYgZwcm90bzM="));
+            "c19wZXJfY3EYESABKAUSGwoTbWVzc2FnZXNfcGVyX3N0cmVhbRgSIAEoBRIY",
+            "ChB1c2VfY29hbGVzY2VfYXBpGBMgASgIIjgKDENsaWVudFN0YXR1cxIoCgVz",
+            "dGF0cxgBIAEoCzIZLmdycGMudGVzdGluZy5DbGllbnRTdGF0cyIVCgRNYXJr",
+            "Eg0KBXJlc2V0GAEgASgIImgKCkNsaWVudEFyZ3MSKwoFc2V0dXAYASABKAsy",
+            "Gi5ncnBjLnRlc3RpbmcuQ2xpZW50Q29uZmlnSAASIgoEbWFyaxgCIAEoCzIS",
+            "LmdycGMudGVzdGluZy5NYXJrSABCCQoHYXJndHlwZSL9AgoMU2VydmVyQ29u",
+            "ZmlnEi0KC3NlcnZlcl90eXBlGAEgASgOMhguZ3JwYy50ZXN0aW5nLlNlcnZl",
+            "clR5cGUSNQoPc2VjdXJpdHlfcGFyYW1zGAIgASgLMhwuZ3JwYy50ZXN0aW5n",
+            "LlNlY3VyaXR5UGFyYW1zEgwKBHBvcnQYBCABKAUSHAoUYXN5bmNfc2VydmVy",
+            "X3RocmVhZHMYByABKAUSEgoKY29yZV9saW1pdBgIIAEoBRIzCg5wYXlsb2Fk",
+            "X2NvbmZpZxgJIAEoCzIbLmdycGMudGVzdGluZy5QYXlsb2FkQ29uZmlnEhEK",
+            "CWNvcmVfbGlzdBgKIAMoBRIYChBvdGhlcl9zZXJ2ZXJfYXBpGAsgASgJEhYK",
+            "DnRocmVhZHNfcGVyX2NxGAwgASgFEhwKE3Jlc291cmNlX3F1b3RhX3NpemUY",
+            "6QcgASgFEi8KDGNoYW5uZWxfYXJncxjqByADKAsyGC5ncnBjLnRlc3Rpbmcu",
+            "Q2hhbm5lbEFyZyJoCgpTZXJ2ZXJBcmdzEisKBXNldHVwGAEgASgLMhouZ3Jw",
+            "Yy50ZXN0aW5nLlNlcnZlckNvbmZpZ0gAEiIKBG1hcmsYAiABKAsyEi5ncnBj",
+            "LnRlc3RpbmcuTWFya0gAQgkKB2FyZ3R5cGUiVQoMU2VydmVyU3RhdHVzEigK",
+            "BXN0YXRzGAEgASgLMhkuZ3JwYy50ZXN0aW5nLlNlcnZlclN0YXRzEgwKBHBv",
+            "cnQYAiABKAUSDQoFY29yZXMYAyABKAUiDQoLQ29yZVJlcXVlc3QiHQoMQ29y",
+            "ZVJlc3BvbnNlEg0KBWNvcmVzGAEgASgFIgYKBFZvaWQi/QEKCFNjZW5hcmlv",
+            "EgwKBG5hbWUYASABKAkSMQoNY2xpZW50X2NvbmZpZxgCIAEoCzIaLmdycGMu",
+            "dGVzdGluZy5DbGllbnRDb25maWcSEwoLbnVtX2NsaWVudHMYAyABKAUSMQoN",
+            "c2VydmVyX2NvbmZpZxgEIAEoCzIaLmdycGMudGVzdGluZy5TZXJ2ZXJDb25m",
+            "aWcSEwoLbnVtX3NlcnZlcnMYBSABKAUSFgoOd2FybXVwX3NlY29uZHMYBiAB",
+            "KAUSGQoRYmVuY2htYXJrX3NlY29uZHMYByABKAUSIAoYc3Bhd25fbG9jYWxf",
+            "d29ya2VyX2NvdW50GAggASgFIjYKCVNjZW5hcmlvcxIpCglzY2VuYXJpb3MY",
+            "ASADKAsyFi5ncnBjLnRlc3RpbmcuU2NlbmFyaW8ihAQKFVNjZW5hcmlvUmVz",
+            "dWx0U3VtbWFyeRILCgNxcHMYASABKAESGwoTcXBzX3Blcl9zZXJ2ZXJfY29y",
+            "ZRgCIAEoARIaChJzZXJ2ZXJfc3lzdGVtX3RpbWUYAyABKAESGAoQc2VydmVy",
+            "X3VzZXJfdGltZRgEIAEoARIaChJjbGllbnRfc3lzdGVtX3RpbWUYBSABKAES",
+            "GAoQY2xpZW50X3VzZXJfdGltZRgGIAEoARISCgpsYXRlbmN5XzUwGAcgASgB",
+            "EhIKCmxhdGVuY3lfOTAYCCABKAESEgoKbGF0ZW5jeV85NRgJIAEoARISCgps",
+            "YXRlbmN5Xzk5GAogASgBEhMKC2xhdGVuY3lfOTk5GAsgASgBEhgKEHNlcnZl",
+            "cl9jcHVfdXNhZ2UYDCABKAESJgoec3VjY2Vzc2Z1bF9yZXF1ZXN0c19wZXJf",
+            "c2Vjb25kGA0gASgBEiIKGmZhaWxlZF9yZXF1ZXN0c19wZXJfc2Vjb25kGA4g",
+            "ASgBEiAKGGNsaWVudF9wb2xsc19wZXJfcmVxdWVzdBgPIAEoARIgChhzZXJ2",
+            "ZXJfcG9sbHNfcGVyX3JlcXVlc3QYECABKAESIgoac2VydmVyX3F1ZXJpZXNf",
+            "cGVyX2NwdV9zZWMYESABKAESIgoaY2xpZW50X3F1ZXJpZXNfcGVyX2NwdV9z",
+            "ZWMYEiABKAEigwMKDlNjZW5hcmlvUmVzdWx0EigKCHNjZW5hcmlvGAEgASgL",
+            "MhYuZ3JwYy50ZXN0aW5nLlNjZW5hcmlvEi4KCWxhdGVuY2llcxgCIAEoCzIb",
+            "LmdycGMudGVzdGluZy5IaXN0b2dyYW1EYXRhEi8KDGNsaWVudF9zdGF0cxgD",
+            "IAMoCzIZLmdycGMudGVzdGluZy5DbGllbnRTdGF0cxIvCgxzZXJ2ZXJfc3Rh",
+            "dHMYBCADKAsyGS5ncnBjLnRlc3RpbmcuU2VydmVyU3RhdHMSFAoMc2VydmVy",
+            "X2NvcmVzGAUgAygFEjQKB3N1bW1hcnkYBiABKAsyIy5ncnBjLnRlc3Rpbmcu",
+            "U2NlbmFyaW9SZXN1bHRTdW1tYXJ5EhYKDmNsaWVudF9zdWNjZXNzGAcgAygI",
+            "EhYKDnNlcnZlcl9zdWNjZXNzGAggAygIEjkKD3JlcXVlc3RfcmVzdWx0cxgJ",
+            "IAMoCzIgLmdycGMudGVzdGluZy5SZXF1ZXN0UmVzdWx0Q291bnQqQQoKQ2xp",
+            "ZW50VHlwZRIPCgtTWU5DX0NMSUVOVBAAEhAKDEFTWU5DX0NMSUVOVBABEhAK",
+            "DE9USEVSX0NMSUVOVBACKlsKClNlcnZlclR5cGUSDwoLU1lOQ19TRVJWRVIQ",
+            "ABIQCgxBU1lOQ19TRVJWRVIQARIYChRBU1lOQ19HRU5FUklDX1NFUlZFUhAC",
+            "EhAKDE9USEVSX1NFUlZFUhADKnIKB1JwY1R5cGUSCQoFVU5BUlkQABINCglT",
+            "VFJFQU1JTkcQARIZChVTVFJFQU1JTkdfRlJPTV9DTElFTlQQAhIZChVTVFJF",
+            "QU1JTkdfRlJPTV9TRVJWRVIQAxIXChNTVFJFQU1JTkdfQk9USF9XQVlTEARi",
+            "BnByb3RvMw=="));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { global::Grpc.Testing.PayloadsReflection.Descriptor, global::Grpc.Testing.StatsReflection.Descriptor, },
           new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Grpc.Testing.ClientType), typeof(global::Grpc.Testing.ServerType), typeof(global::Grpc.Testing.RpcType), }, new pbr::GeneratedClrTypeInfo[] {
@@ -106,7 +107,7 @@
             new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.LoadParams), global::Grpc.Testing.LoadParams.Parser, new[]{ "ClosedLoop", "Poisson" }, new[]{ "Load" }, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.SecurityParams), global::Grpc.Testing.SecurityParams.Parser, new[]{ "UseTestCa", "ServerHostOverride", "CredType" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ChannelArg), global::Grpc.Testing.ChannelArg.Parser, new[]{ "Name", "StrValue", "IntValue" }, new[]{ "Value" }, null, null),
-            new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ClientConfig), global::Grpc.Testing.ClientConfig.Parser, new[]{ "ServerTargets", "ClientType", "SecurityParams", "OutstandingRpcsPerChannel", "ClientChannels", "AsyncClientThreads", "RpcType", "LoadParams", "PayloadConfig", "HistogramParams", "CoreList", "CoreLimit", "OtherClientApi", "ChannelArgs", "ThreadsPerCq", "MessagesPerStream" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ClientConfig), global::Grpc.Testing.ClientConfig.Parser, new[]{ "ServerTargets", "ClientType", "SecurityParams", "OutstandingRpcsPerChannel", "ClientChannels", "AsyncClientThreads", "RpcType", "LoadParams", "PayloadConfig", "HistogramParams", "CoreList", "CoreLimit", "OtherClientApi", "ChannelArgs", "ThreadsPerCq", "MessagesPerStream", "UseCoalesceApi" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ClientStatus), global::Grpc.Testing.ClientStatus.Parser, new[]{ "Stats" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.Mark), global::Grpc.Testing.Mark.Parser, new[]{ "Reset" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ClientArgs), global::Grpc.Testing.ClientArgs.Parser, new[]{ "Setup", "Mark" }, new[]{ "Argtype" }, null, null),
@@ -989,6 +990,7 @@
       channelArgs_ = other.channelArgs_.Clone();
       threadsPerCq_ = other.threadsPerCq_;
       messagesPerStream_ = other.messagesPerStream_;
+      useCoalesceApi_ = other.useCoalesceApi_;
     }
 
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -1198,6 +1200,20 @@
       }
     }
 
+    /// <summary>Field number for the "use_coalesce_api" field.</summary>
+    public const int UseCoalesceApiFieldNumber = 19;
+    private bool useCoalesceApi_;
+    /// <summary>
+    /// Use coalescing API when possible.
+    /// </summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public bool UseCoalesceApi {
+      get { return useCoalesceApi_; }
+      set {
+        useCoalesceApi_ = value;
+      }
+    }
+
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
     public override bool Equals(object other) {
       return Equals(other as ClientConfig);
@@ -1227,6 +1243,7 @@
       if(!channelArgs_.Equals(other.channelArgs_)) return false;
       if (ThreadsPerCq != other.ThreadsPerCq) return false;
       if (MessagesPerStream != other.MessagesPerStream) return false;
+      if (UseCoalesceApi != other.UseCoalesceApi) return false;
       return true;
     }
 
@@ -1249,6 +1266,7 @@
       hash ^= channelArgs_.GetHashCode();
       if (ThreadsPerCq != 0) hash ^= ThreadsPerCq.GetHashCode();
       if (MessagesPerStream != 0) hash ^= MessagesPerStream.GetHashCode();
+      if (UseCoalesceApi != false) hash ^= UseCoalesceApi.GetHashCode();
       return hash;
     }
 
@@ -1314,6 +1332,10 @@
         output.WriteRawTag(144, 1);
         output.WriteInt32(MessagesPerStream);
       }
+      if (UseCoalesceApi != false) {
+        output.WriteRawTag(152, 1);
+        output.WriteBool(UseCoalesceApi);
+      }
     }
 
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -1361,6 +1383,9 @@
       if (MessagesPerStream != 0) {
         size += 2 + pb::CodedOutputStream.ComputeInt32Size(MessagesPerStream);
       }
+      if (UseCoalesceApi != false) {
+        size += 2 + 1;
+      }
       return size;
     }
 
@@ -1423,6 +1448,9 @@
       if (other.MessagesPerStream != 0) {
         MessagesPerStream = other.MessagesPerStream;
       }
+      if (other.UseCoalesceApi != false) {
+        UseCoalesceApi = other.UseCoalesceApi;
+      }
     }
 
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -1510,6 +1538,10 @@
             MessagesPerStream = input.ReadInt32();
             break;
           }
+          case 152: {
+            UseCoalesceApi = input.ReadBool();
+            break;
+          }
         }
       }
     }
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index c02c984..ba2107a 100755
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -19,7 +19,7 @@
   <ItemGroup>
     <PackageReference Include="Google.Protobuf" Version="$(GoogleProtobufVersion)" />
     <PackageReference Include="CommandLineParser" Version="2.1.1-beta" />
-    <PackageReference Include="Moq" Version="4.7.0" />
+    <PackageReference Include="Moq" Version="4.8.2" />
     <PackageReference Include="NUnit" Version="3.6.0" />
     <PackageReference Include="NUnitLite" Version="3.6.0" />
   </ItemGroup>
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index 10c31c4..e83a8a7 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -685,7 +685,7 @@
 
         private static Metadata CreateClientCompressionMetadata(bool compressed)
         {
-            var algorithmName = compressed ? "message/gzip" : "identity";
+            var algorithmName = compressed ? "gzip" : "identity";
             return new Metadata
             {
                 { new Metadata.Entry(Metadata.CompressionRequestAlgorithmMetadataKey, algorithmName) }
diff --git a/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs b/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
index f71d6d1..d18b9e7 100644
--- a/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
@@ -26,9 +26,6 @@
 #pragma warning disable 1591
 #region Designer generated code
 
-using System;
-using System.Threading;
-using System.Threading.Tasks;
 using grpc = global::Grpc.Core;
 
 namespace Grpc.Testing {
@@ -121,7 +118,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return GetAllGauges(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -144,7 +141,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The response received from the server.</returns>
-      public virtual global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return GetGauge(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -166,7 +163,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return GetGaugeAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
diff --git a/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
index d2e4f2e..46b328a 100644
--- a/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
@@ -22,9 +22,6 @@
 #pragma warning disable 1591
 #region Designer generated code
 
-using System;
-using System.Threading;
-using System.Threading.Tasks;
 using grpc = global::Grpc.Core;
 
 namespace Grpc.Testing {
@@ -177,7 +174,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The response received from the server.</returns>
-      public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return UnaryCall(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -201,7 +198,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return UnaryCallAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -225,7 +222,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return StreamingCall(new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -248,7 +245,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncClientStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingFromClient(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncClientStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingFromClient(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return StreamingFromClient(new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -271,7 +268,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncServerStreamingCall<global::Grpc.Testing.SimpleResponse> StreamingFromServer(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncServerStreamingCall<global::Grpc.Testing.SimpleResponse> StreamingFromServer(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return StreamingFromServer(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -294,7 +291,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingBothWays(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingBothWays(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return StreamingBothWays(new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -470,7 +467,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return RunServer(new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -500,7 +497,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return RunClient(new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -526,7 +523,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The response received from the server.</returns>
-      public virtual global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return CoreCount(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -548,7 +545,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return CoreCountAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -570,7 +567,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The response received from the server.</returns>
-      public virtual global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return QuitWorker(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -592,7 +589,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return QuitWorkerAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -692,7 +689,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The response received from the server.</returns>
-      public virtual global::Grpc.Testing.Void ReportScenario(global::Grpc.Testing.ScenarioResult request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual global::Grpc.Testing.Void ReportScenario(global::Grpc.Testing.ScenarioResult request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return ReportScenario(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -714,7 +711,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Void> ReportScenarioAsync(global::Grpc.Testing.ScenarioResult request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Void> ReportScenarioAsync(global::Grpc.Testing.ScenarioResult request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return ReportScenarioAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
diff --git a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
index c0d147c..6c4b77f 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
@@ -23,9 +23,6 @@
 #pragma warning disable 1591
 #region Designer generated code
 
-using System;
-using System.Threading;
-using System.Threading.Tasks;
 using grpc = global::Grpc.Core;
 
 namespace Grpc.Testing {
@@ -244,7 +241,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The response received from the server.</returns>
-      public virtual global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return EmptyCall(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -266,7 +263,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return EmptyCallAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -288,7 +285,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The response received from the server.</returns>
-      public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return UnaryCall(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -310,7 +307,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return UnaryCallAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -334,7 +331,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The response received from the server.</returns>
-      public virtual global::Grpc.Testing.SimpleResponse CacheableUnaryCall(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual global::Grpc.Testing.SimpleResponse CacheableUnaryCall(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return CacheableUnaryCall(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -360,7 +357,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> CacheableUnaryCallAsync(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> CacheableUnaryCallAsync(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return CacheableUnaryCallAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -385,7 +382,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return StreamingOutputCall(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -408,7 +405,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return StreamingInputCall(new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -431,7 +428,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return FullDuplexCall(new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -456,7 +453,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return HalfDuplexCall(new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -481,7 +478,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The response received from the server.</returns>
-      public virtual global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return UnimplementedCall(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -505,7 +502,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return UnimplementedCallAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -613,7 +610,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The response received from the server.</returns>
-      public virtual global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return UnimplementedCall(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -635,7 +632,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return UnimplementedCallAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -734,7 +731,7 @@
       {
       }
 
-      public virtual global::Grpc.Testing.Empty Start(global::Grpc.Testing.ReconnectParams request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual global::Grpc.Testing.Empty Start(global::Grpc.Testing.ReconnectParams request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return Start(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -742,7 +739,7 @@
       {
         return CallInvoker.BlockingUnaryCall(__Method_Start, null, options, request);
       }
-      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.ReconnectParams request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.ReconnectParams request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return StartAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -750,7 +747,7 @@
       {
         return CallInvoker.AsyncUnaryCall(__Method_Start, null, options, request);
       }
-      public virtual global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return Stop(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
@@ -758,7 +755,7 @@
       {
         return CallInvoker.BlockingUnaryCall(__Method_Stop, null, options, request);
       }
-      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return StopAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
       }
diff --git a/src/csharp/Grpc.Reflection/ReflectionGrpc.cs b/src/csharp/Grpc.Reflection/ReflectionGrpc.cs
index 0195186..e2263cf 100644
--- a/src/csharp/Grpc.Reflection/ReflectionGrpc.cs
+++ b/src/csharp/Grpc.Reflection/ReflectionGrpc.cs
@@ -22,9 +22,6 @@
 #pragma warning disable 1591
 #region Designer generated code
 
-using System;
-using System.Threading;
-using System.Threading.Tasks;
 using grpc = global::Grpc.Core;
 
 namespace Grpc.Reflection.V1Alpha {
@@ -97,7 +94,7 @@
       /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
       /// <param name="cancellationToken">An optional token for canceling the call.</param>
       /// <returns>The call object.</returns>
-      public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest, global::Grpc.Reflection.V1Alpha.ServerReflectionResponse> ServerReflectionInfo(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest, global::Grpc.Reflection.V1Alpha.ServerReflectionResponse> ServerReflectionInfo(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
       {
         return ServerReflectionInfo(new grpc::CallOptions(headers, deadline, cancellationToken));
       }
diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat
index 4087d8b..7639173 100755
--- a/src/csharp/build_packages_dotnetcli.bat
+++ b/src/csharp/build_packages_dotnetcli.bat
@@ -13,23 +13,27 @@
 @rem limitations under the License.
 
 @rem Current package versions
-set VERSION=1.10.0-dev
+set VERSION=1.11.0-dev
 
 @rem Adjust the location of nuget.exe
 set NUGET=C:\nuget\nuget.exe
 set DOTNET=dotnet
 
-set -ex
-
 mkdir ..\..\artifacts
 
 @rem Collect the artifacts built by the previous build step if running on Jenkins
 mkdir nativelibs
+@rem Jenkins flow (deprecated)
 powershell -Command "cp -r ..\..\platform=*\artifacts\csharp_ext_* nativelibs"
+@rem Kokoro flow
+powershell -Command "cp -r ..\..\input_artifacts\csharp_ext_* nativelibs"
 
 @rem Collect protoc artifacts built by the previous build step
 mkdir protoc_plugins
+@rem Jenkins flow (deprecated)
 powershell -Command "cp -r ..\..\platform=*\artifacts\protoc_* protoc_plugins"
+@rem Kokoro flow
+powershell -Command "cp -r ..\..\input_artifacts\protoc_* protoc_plugins"
 
 %DOTNET% restore Grpc.sln || goto :error
 
diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh
index 8ccc537..1b73614 100755
--- a/src/csharp/build_packages_dotnetcli.sh
+++ b/src/csharp/build_packages_dotnetcli.sh
@@ -21,11 +21,17 @@
 
 # Collect the artifacts built by the previous build step
 mkdir -p nativelibs
+# Jenkins flow (deprecated)
 cp -r $EXTERNAL_GIT_ROOT/platform={windows,linux,macos}/artifacts/csharp_ext_* nativelibs || true
+# Kokoro flow
+cp -r $EXTERNAL_GIT_ROOT/input_artifacts/csharp_ext_* nativelibs || true
 
 # Collect protoc artifacts built by the previous build step
 mkdir -p protoc_plugins
+# Jenkins flow (deprecated)
 cp -r $EXTERNAL_GIT_ROOT/platform={windows,linux,macos}/artifacts/protoc_* protoc_plugins || true
+# Kokoro flow
+cp -r $EXTERNAL_GIT_ROOT/input_artifacts/protoc_* protoc_plugins || true
 
 dotnet restore Grpc.sln
 
@@ -39,7 +45,7 @@
 dotnet pack --configuration Release Grpc.HealthCheck --output ../../../artifacts
 dotnet pack --configuration Release Grpc.Reflection --output ../../../artifacts
 
-nuget pack Grpc.nuspec -Version "1.10.0-dev" -OutputDirectory ../../artifacts
-nuget pack Grpc.Tools.nuspec -Version "1.10.0-dev" -OutputDirectory ../../artifacts
+nuget pack Grpc.nuspec -Version "1.11.0-dev" -OutputDirectory ../../artifacts
+nuget pack Grpc.Tools.nuspec -Version "1.11.0-dev" -OutputDirectory ../../artifacts
 
 (cd ../../artifacts && zip csharp_nugets_dotnetcli.zip *.nupkg)
diff --git a/src/csharp/experimental/README.md b/src/csharp/experimental/README.md
new file mode 100644
index 0000000..f892a2e
--- /dev/null
+++ b/src/csharp/experimental/README.md
@@ -0,0 +1,16 @@
+This directory contains useful resources for getting gRPC C# to work on
+not-yet-supported platforms.
+
+# Unity & Xamarin
+gRPC C# currently doesn't support Unity or Xamarin, but some proof-of-concept
+work has been done. Some of the resources are shared in this directory to
+ease community work on Unity & Xamarin support.
+
+## Crosscompiling `grpc_csharp_ext` for Android
+
+* Install [Android NDK](https://developer.android.com/ndk/index.html)
+* Run `./build_native_ext_for_android.sh` to crosscompile using cmake.
+
+## Crosscompiling `grpc_csharp_ext` for iOS
+
+TBD
diff --git a/src/csharp/experimental/build_native_ext_for_android.sh b/src/csharp/experimental/build_native_ext_for_android.sh
new file mode 100755
index 0000000..958778e
--- /dev/null
+++ b/src/csharp/experimental/build_native_ext_for_android.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 script to crosscompile grpc_csharp_ext native extension for Android.
+
+set -ex
+
+cd "$(dirname "$0")/../../../cmake"
+
+mkdir -p build
+cd build
+
+# set to the location where Android SDK is installed
+ANDROID_NDK_PATH="$HOME/android-ndk-r16b"
+
+cmake ../.. \
+  -DCMAKE_SYSTEM_NAME=Android \
+  -DCMAKE_SYSTEM_VERSION=15 \
+  -DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a \
+  -DCMAKE_ANDROID_NDK="${ANDROID_NDK_PATH}" \
+  -DCMAKE_ANDROID_STL_TYPE=c++_static \
+  -DRUN_HAVE_POSIX_REGEX=0 \
+  -DRUN_HAVE_STD_REGEX=0 \
+  -DRUN_HAVE_STEADY_CLOCK=0 \
+  -DCMAKE_BUILD_TYPE=Release
+
+make -j4 grpc_csharp_ext
diff --git a/src/csharp/experimental/build_unitypackage.sh b/src/csharp/experimental/build_unitypackage.sh
new file mode 100755
index 0000000..cca5265
--- /dev/null
+++ b/src/csharp/experimental/build_unitypackage.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Builds an experimental .unitypackage file to be imported into Unity projects.
+
+set -ex
+
+cd "$(dirname "$0")/.."
+
+dotnet restore Grpc.sln
+
+mkdir -p GrpcUnity
+dotnet build --configuration Release --framework net45 Grpc.Core --output ../GrpcUnity
+
+#TODO: add ThirdParty/Grpc.Core:
+# - assembly
+# - native libraries (mac dylib need to be renamed to grpc_csharp_ext.bundle)
+
+#TODO: add ThirdParty/Grpc.Tools:
+# - protoc and grpc plugin
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index eb69b58..3e6ec47 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -16,8 +16,6 @@
  *
  */
 
-#include "src/core/lib/gpr/string.h"
-
 #include <grpc/byte_buffer_reader.h>
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
@@ -26,7 +24,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/thd.h>
+#include <grpc/support/thd_id.h>
 
 #include <string.h>
 
diff --git a/src/csharp/global.json b/src/csharp/global.json
index e4b797e..815be4b 100644
--- a/src/csharp/global.json
+++ b/src/csharp/global.json
@@ -1,5 +1,5 @@
 {
   "sdk": {
-    "version": "1.0.0"
+    "version": "2.1.4"
   }
 }
diff --git a/src/csharp/tests.json b/src/csharp/tests.json
index 469328a..60f67ff 100644
--- a/src/csharp/tests.json
+++ b/src/csharp/tests.json
@@ -1,5 +1,7 @@
 {
   "Grpc.Core.Tests": [
+    "Grpc.Core.Interceptors.Tests.ClientInterceptorTest",
+    "Grpc.Core.Interceptors.Tests.ServerInterceptorTest",
     "Grpc.Core.Internal.Tests.AsyncCallServerTest",
     "Grpc.Core.Internal.Tests.AsyncCallTest",
     "Grpc.Core.Internal.Tests.ChannelArgsSafeHandleTest",
@@ -59,4 +61,4 @@
     "Grpc.Reflection.Tests.ReflectionClientServerTest",
     "Grpc.Reflection.Tests.SymbolRegistryTest"
   ]
-}
\ No newline at end of file
+}
diff --git "a/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec" "b/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec"
index 037ad4d..954beed 100644
--- "a/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec"
+++ "b/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec"
@@ -42,7 +42,7 @@
   # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed
   # before them.
   s.name     = '!ProtoCompiler-gRPCPlugin'
-  v = '1.10.0-dev'
+  v = '1.11.0-dev'
   s.version  = v
   s.summary  = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.'
   s.description = <<-DESC
diff --git a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m
index d44e39f..805e54b 100644
--- a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m
+++ b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m
@@ -46,10 +46,10 @@
       hostConfig.compressAlgorithm = GRPC_COMPRESS_NONE;
       break;
     case GRPCCompressDeflate:
-      hostConfig.compressAlgorithm = GRPC_COMPRESS_MESSAGE_DEFLATE;
+      hostConfig.compressAlgorithm = GRPC_COMPRESS_DEFLATE;
       break;
     case GRPCCompressGzip:
-      hostConfig.compressAlgorithm = GRPC_COMPRESS_MESSAGE_GZIP;
+      hostConfig.compressAlgorithm = GRPC_COMPRESS_GZIP;
       break;
     default:
       NSLog(@"Invalid compression algorithm");
diff --git a/src/objective-c/GRPCClient/GRPCCall+MobileLog.h b/src/objective-c/GRPCClient/GRPCCall+MobileLog.h
new file mode 100644
index 0000000..53b347d
--- /dev/null
+++ b/src/objective-c/GRPCClient/GRPCCall+MobileLog.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import "GRPCCall.h"
+
+@interface GRPCCall (MobileLog)
+// Set the object to be passed down along channel stack with channel arg
+// GRPC_ARG_MOBILE_LOG_CONFIG. The setting may be used by custom channel
+// filters for metrics logging.
++ (void)setLogConfig:(id)logConfig;
+
+// Obtain the object to be passed down along channel stack with channel arg
+// GRPC_ARG_MOBILE_LOG_CONFIG.
++ (id)logConfig;
+@end
diff --git a/src/objective-c/GRPCClient/GRPCCall+MobileLog.m b/src/objective-c/GRPCClient/GRPCCall+MobileLog.m
new file mode 100644
index 0000000..4dedb7d
--- /dev/null
+++ b/src/objective-c/GRPCClient/GRPCCall+MobileLog.m
@@ -0,0 +1,33 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import "GRPCCall+MobileLog.h"
+
+static id globalLogConfig = nil;
+
+@implementation GRPCCall (MobileLog)
+
++ (void)setLogConfig:(id)logConfig {
+  globalLogConfig = logConfig;
+}
+
++ (id)logConfig {
+  return globalLogConfig;
+}
+
+@end
diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m
index ac4596d..ea658bc 100644
--- a/src/objective-c/GRPCClient/GRPCCall.m
+++ b/src/objective-c/GRPCClient/GRPCCall.m
@@ -108,6 +108,9 @@
   // The dispatch queue to be used for enqueuing responses to user. Defaulted to the main dispatch
   // queue
   dispatch_queue_t _responseQueue;
+
+  // Whether the call is finished. If it is, should not call finishWithError again.
+  BOOL _finished;
 }
 
 @synthesize state = _state;
@@ -206,6 +209,8 @@
   } else {
     [_responseWriteable enqueueSuccessfulCompletion];
   }
+
+  [GRPCConnectivityMonitor unregisterObserver:self];
 }
 
 - (void)cancelCall {
@@ -214,9 +219,10 @@
 }
 
 - (void)cancel {
-  [self finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
-                                            code:GRPCErrorCodeCancelled
-                                        userInfo:@{NSLocalizedDescriptionKey: @"Canceled by app"}]];
+  [self maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain
+                                                 code:GRPCErrorCodeCancelled
+                                             userInfo:@{NSLocalizedDescriptionKey: @"Canceled by app"}]];
+
   if (!self.isWaitingForToken) {
     [self cancelCall];
   } else {
@@ -224,6 +230,19 @@
   }
 }
 
+- (void)maybeFinishWithError:(NSError *)errorOrNil {
+  BOOL toFinish = NO;
+  @synchronized(self) {
+    if (_finished == NO) {
+      _finished = YES;
+      toFinish = YES;
+    }
+  }
+  if (toFinish == YES) {
+    [self finishWithError:errorOrNil];
+  }
+}
+
 - (void)dealloc {
   __block GRPCWrappedCall *wrappedCall = _wrappedCall;
   dispatch_async(_callQueue, ^{
@@ -250,11 +269,13 @@
   if (self.state == GRXWriterStatePaused) {
     return;
   }
-  __weak GRPCCall *weakSelf = self;
-  __weak GRXConcurrentWriteable *weakWriteable = _responseWriteable;
 
   dispatch_async(_callQueue, ^{
-    [weakSelf startReadWithHandler:^(grpc_byte_buffer *message) {
+    __weak GRPCCall *weakSelf = self;
+    __weak GRXConcurrentWriteable *weakWriteable = self->_responseWriteable;
+    [self startReadWithHandler:^(grpc_byte_buffer *message) {
+      __strong GRPCCall *strongSelf = weakSelf;
+      __strong GRXConcurrentWriteable *strongWriteable = weakWriteable;
       if (message == NULL) {
         // No more messages from the server
         return;
@@ -266,14 +287,14 @@
         // don't want to throw, because the app shouldn't crash for a behavior
         // that's on the hands of any server to have. Instead we finish and ask
         // the server to cancel.
-        [weakSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
-                                                      code:GRPCErrorCodeResourceExhausted
-                                                  userInfo:@{NSLocalizedDescriptionKey: @"Client does not have enough memory to hold the server response."}]];
-        [weakSelf cancelCall];
+        [strongSelf maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain
+                                                             code:GRPCErrorCodeResourceExhausted
+                                                         userInfo:@{NSLocalizedDescriptionKey: @"Client does not have enough memory to hold the server response."}]];
+        [strongSelf cancelCall];
         return;
       }
-      [weakWriteable enqueueValue:data completionHandler:^{
-        [weakSelf startNextRead];
+      [strongWriteable enqueueValue:data completionHandler:^{
+        [strongSelf startNextRead];
       }];
     }];
   });
@@ -333,12 +354,17 @@
     _requestWriter.state = GRXWriterStatePaused;
   }
 
-  __weak GRPCCall *weakSelf = self;
   dispatch_async(_callQueue, ^{
-    [weakSelf writeMessage:value withErrorHandler:^{
-      [weakSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
-                                                    code:GRPCErrorCodeInternal
-                                                userInfo:nil]];
+    __weak GRPCCall *weakSelf = self;
+    [self writeMessage:value withErrorHandler:^{
+      __strong GRPCCall *strongSelf = weakSelf;
+      if (strongSelf != nil) {
+        [strongSelf maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain
+                                                             code:GRPCErrorCodeInternal
+                                                         userInfo:nil]];
+        // Wrapped call must be canceled when error is reported to upper layers
+        [strongSelf cancelCall];
+      }
     }];
   });
 }
@@ -360,12 +386,15 @@
   if (errorOrNil) {
     [self cancel];
   } else {
-    __weak GRPCCall *weakSelf = self;
     dispatch_async(_callQueue, ^{
-      [weakSelf finishRequestWithErrorHandler:^{
-        [weakSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
-                                                      code:GRPCErrorCodeInternal
-                                                  userInfo:nil]];
+      __weak GRPCCall *weakSelf = self;
+      [self finishRequestWithErrorHandler:^{
+        __strong GRPCCall *strongSelf = weakSelf;
+        [strongSelf maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain
+                                                             code:GRPCErrorCodeInternal
+                                                         userInfo:nil]];
+        // Wrapped call must be canceled when error is reported to upper layers
+        [strongSelf cancelCall];
       }];
     });
   }
@@ -387,30 +416,37 @@
 }
 
 - (void)invokeCall {
+  __weak GRPCCall *weakSelf = self;
   [self invokeCallWithHeadersHandler:^(NSDictionary *headers) {
     // Response headers received.
-    self.responseHeaders = headers;
-    [self startNextRead];
-  } completionHandler:^(NSError *error, NSDictionary *trailers) {
-    self.responseTrailers = trailers;
-
-    if (error) {
-      NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
-      if (error.userInfo) {
-        [userInfo addEntriesFromDictionary:error.userInfo];
-      }
-      userInfo[kGRPCTrailersKey] = self.responseTrailers;
-      // TODO(jcanizales): The C gRPC library doesn't guarantee that the headers block will be
-      // called before this one, so an error might end up with trailers but no headers. We
-      // shouldn't call finishWithError until ater both blocks are called. It is also when this is
-      // done that we can provide a merged view of response headers and trailers in a thread-safe
-      // way.
-      if (self.responseHeaders) {
-        userInfo[kGRPCHeadersKey] = self.responseHeaders;
-      }
-      error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
+    __strong GRPCCall *strongSelf = weakSelf;
+    if (strongSelf) {
+      strongSelf.responseHeaders = headers;
+      [strongSelf startNextRead];
     }
-    [self finishWithError:error];
+  } completionHandler:^(NSError *error, NSDictionary *trailers) {
+    __strong GRPCCall *strongSelf = weakSelf;
+    if (strongSelf) {
+      strongSelf.responseTrailers = trailers;
+
+      if (error) {
+        NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
+        if (error.userInfo) {
+          [userInfo addEntriesFromDictionary:error.userInfo];
+        }
+        userInfo[kGRPCTrailersKey] = strongSelf.responseTrailers;
+        // TODO(jcanizales): The C gRPC library doesn't guarantee that the headers block will be
+        // called before this one, so an error might end up with trailers but no headers. We
+        // shouldn't call finishWithError until ater both blocks are called. It is also when this is
+        // done that we can provide a merged view of response headers and trailers in a thread-safe
+        // way.
+        if (strongSelf.responseHeaders) {
+          userInfo[kGRPCHeadersKey] = strongSelf.responseHeaders;
+        }
+        error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
+      }
+      [strongSelf maybeFinishWithError:error];
+    }
   }];
   // Now that the RPC has been initiated, request writes can start.
   @synchronized(_requestWriter) {
@@ -433,22 +469,8 @@
   [self sendHeaders:_requestHeaders];
   [self invokeCall];
 
-  // TODO(jcanizales): Extract this logic somewhere common.
-  NSString *host = [NSURL URLWithString:[@"https://" stringByAppendingString:_host]].host;
-  if (!host) {
-    // TODO(jcanizales): Check this on init.
-    [NSException raise:NSInvalidArgumentException format:@"host of %@ is nil", _host];
-  }
-  _connectivityMonitor = [GRPCConnectivityMonitor monitorWithHost:host];
-  __weak typeof(self) weakSelf = self;
-  void (^handler)(void) = ^{
-    typeof(self) strongSelf = weakSelf;
-    [strongSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
-                                                    code:GRPCErrorCodeUnavailable
-                                                userInfo:@{ NSLocalizedDescriptionKey : @"Connectivity lost." }]];
-  };
-  [_connectivityMonitor handleLossWithHandler:handler
-                      wifiStatusChangeHandler:nil];
+  [GRPCConnectivityMonitor registerObserver:self
+                                   selector:@selector(connectivityChanged:)];
 }
 
 - (void)startWithWriteable:(id<GRXWriteable>)writeable {
@@ -512,4 +534,12 @@
   }
 }
 
+- (void)connectivityChanged:(NSNotification *)note {
+  [self maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain
+                                                 code:GRPCErrorCodeUnavailable
+                                             userInfo:@{ NSLocalizedDescriptionKey : @"Connectivity lost." }]];
+  // Cancel underlying call upon this notification
+  [self cancelCall];
+}
+
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m
index 26efe90..b53d841 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.m
@@ -32,6 +32,24 @@
 #endif
 #import "GRPCCompletionQueue.h"
 
+static void* copy_pointer_arg(void *p) {
+  // Add ref count to the object when making copy
+  id obj = (__bridge id)p;
+  return (__bridge_retained void *)obj;
+}
+
+static void destroy_pointer_arg(void *p) {
+  // Decrease ref count to the object when destroying
+  CFRelease((CFTreeRef)p);
+}
+
+static int cmp_pointer_arg(void *p, void *q) {
+  return p == q;
+}
+
+static const grpc_arg_pointer_vtable objc_arg_vtable = {
+  copy_pointer_arg, destroy_pointer_arg, cmp_pointer_arg};
+
 static void FreeChannelArgs(grpc_channel_args *channel_args) {
   for (size_t i = 0; i < channel_args->num_args; ++i) {
     grpc_arg *arg = &channel_args->args[i];
@@ -75,6 +93,10 @@
     } else if ([value respondsToSelector:@selector(intValue)]) {
       arg->type = GRPC_ARG_INTEGER;
       arg->value.integer = [value intValue];
+    } else if (value != nil) {
+      arg->type = GRPC_ARG_POINTER;
+      arg->value.pointer.p = (__bridge_retained void *)value;
+      arg->value.pointer.vtable = &objc_arg_vtable;
     } else {
       [NSException raise:NSInvalidArgumentException
                   format:@"Invalid value type: %@", [value class]];
@@ -188,8 +210,7 @@
   if (timeout < 0) {
     timeout = 0;
   }
-  grpc_slice host_slice;
-  memset(&host_slice, 0, sizeof(host_slice));
+  grpc_slice host_slice = grpc_empty_slice();
   if (serverName) {
     host_slice = grpc_slice_from_copied_string(serverName.UTF8String);
   }
diff --git a/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h
index cb55e46..394d217 100644
--- a/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h
+++ b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h
@@ -19,44 +19,30 @@
 #import <Foundation/Foundation.h>
 #import <SystemConfiguration/SystemConfiguration.h>
 
-@interface GRPCReachabilityFlags : NSObject
+typedef NS_ENUM(NSInteger, GRPCConnectivityStatus) {
+  GRPCConnectivityUnknown = 0,
+  GRPCConnectivityNoNetwork = 1,
+  GRPCConnectivityCellular = 2,
+  GRPCConnectivityWiFi = 3,
+};
 
-+ (nonnull instancetype)flagsWithFlags:(SCNetworkReachabilityFlags)flags;
+extern NSString * _Nonnull kGRPCConnectivityNotification;
 
-/**
- * One accessor method to query each of the different flags. Example:
-
-@property(nonatomic, readonly) BOOL isCell;
-
- */
-#define GRPC_XMACRO_ITEM(methodName, FlagName) \
-@property(nonatomic, readonly) BOOL methodName;
-
-#include "GRPCReachabilityFlagNames.xmacro.h"
-#undef GRPC_XMACRO_ITEM
-
-@property(nonatomic, readonly) BOOL isHostReachable;
-@end
-
+// This interface monitors OS reachability interface for any network status
+// change. Parties interested in these events should register themselves as
+// observer.
 @interface GRPCConnectivityMonitor : NSObject
 
-+ (nullable instancetype)monitorWithHost:(nonnull NSString *)hostName;
-
 - (nonnull instancetype)init NS_UNAVAILABLE;
 
-/**
- * Queue on which callbacks will be dispatched. Default is the main queue. Set it before calling
- * handleLossWithHandler:.
- */
-// TODO(jcanizales): Default to a serial background queue instead.
-@property(nonatomic, strong, null_resettable) dispatch_queue_t queue;
+// Register an object as observer of network status change. \a observer
+// must have a notification method with one parameter of type
+// (NSNotification *) and should pass it to parameter \a selector. The
+// parameter of this notification method is not used for now.
++ (void)registerObserver:(_Nonnull id)observer
+                selector:(_Nonnull SEL)selector;
 
-/**
- * Calls handler every time the connectivity to this instance's host is lost. If this instance is
- * released before that happens, the handler won't be called.
- * Only one handler is active at a time, so if this method is called again before the previous
- * handler has been called, it might never be called at all (or yes, if it has already been queued).
- */
-- (void)handleLossWithHandler:(nullable void (^)(void))lossHandler
-      wifiStatusChangeHandler:(nullable void (^)(void))wifiStatusChangeHandler;
+// Ungegister an object from observers of network status change.
++ (void)unregisterObserver:(_Nonnull id)observer;
+
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m
index c8e10dd..7f31c7e 100644
--- a/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m
+++ b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m
@@ -18,175 +18,74 @@
 
 #import "GRPCConnectivityMonitor.h"
 
-#pragma mark Flags
+#include <netinet/in.h>
 
-@implementation GRPCReachabilityFlags {
-  SCNetworkReachabilityFlags _flags;
-}
+NSString *kGRPCConnectivityNotification = @"kGRPCConnectivityNotification";
 
-+ (instancetype)flagsWithFlags:(SCNetworkReachabilityFlags)flags {
-  return [[self alloc] initWithFlags:flags];
-}
+static SCNetworkReachabilityRef reachability;
+static GRPCConnectivityStatus currentStatus;
 
-- (instancetype)initWithFlags:(SCNetworkReachabilityFlags)flags {
-  if ((self = [super init])) {
-    _flags = flags;
+// Aggregate information in flags into network status.
+GRPCConnectivityStatus CalculateConnectivityStatus(SCNetworkReachabilityFlags flags) {
+  GRPCConnectivityStatus result = GRPCConnectivityUnknown;
+  if (((flags & kSCNetworkReachabilityFlagsReachable) == 0) ||
+      ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0)) {
+    return GRPCConnectivityNoNetwork;
   }
-  return self;
-}
-
-/*
- * One accessor method implementation per flag. Example:
-
-- (BOOL)isCell { \
-  return !!(_flags & kSCNetworkReachabilityFlagsIsWWAN); \
-}
-
- */
-#define GRPC_XMACRO_ITEM(methodName, FlagName) \
-- (BOOL)methodName { \
-  return !!(_flags & kSCNetworkReachabilityFlags ## FlagName); \
-}
-#include "GRPCReachabilityFlagNames.xmacro.h"
-#undef GRPC_XMACRO_ITEM
-
-- (BOOL)isHostReachable {
-  // Note: connectionOnDemand means it'll be reachable only if using the CFSocketStream API or APIs
-  // on top of it.
-  // connectionRequired means we can't tell until a connection is attempted (e.g. for VPN on
-  // demand).
-  return self.reachable && !self.interventionRequired && !self.connectionOnDemand;
-}
-
-- (NSString *)description {
-  NSMutableArray *activeOptions = [NSMutableArray arrayWithCapacity:9];
-
-  /*
-   * For each flag, add its name to the array if it's ON. Example:
-
-  if (self.isCell) {
-    [activeOptions addObject:@"isCell"];
-  }
-
-   */
-  #define GRPC_XMACRO_ITEM(methodName, FlagName) \
-    if (self.methodName) {                       \
-      [activeOptions addObject:@ #methodName];   \
-    }
-  #include "GRPCReachabilityFlagNames.xmacro.h"
-  #undef GRPC_XMACRO_ITEM
-
-  return activeOptions.count == 0 ? @"(none)" : [activeOptions componentsJoinedByString:@", "];
-}
-
-- (BOOL)isEqual:(id)object {
-  return [object isKindOfClass:[GRPCReachabilityFlags class]] &&
-      _flags == ((GRPCReachabilityFlags *)object)->_flags;
-}
-
-- (NSUInteger)hash {
-  return _flags;
-}
-@end
-
-#pragma mark Connectivity Monitor
-
-// Assumes the third argument is a block that accepts a GRPCReachabilityFlags object, and passes the
-// received ones to it.
-static void PassFlagsToContextInfoBlock(SCNetworkReachabilityRef target,
-                                        SCNetworkReachabilityFlags flags,
-                                        void *info) {
-  #pragma unused (target)
-  // This can be called many times with the same info. The info is retained by SCNetworkReachability
-  // while this function is being executed.
-  void (^handler)(GRPCReachabilityFlags *) = (__bridge void (^)(GRPCReachabilityFlags *))info;
-  handler([[GRPCReachabilityFlags alloc] initWithFlags:flags]);
-}
-
-@implementation GRPCConnectivityMonitor {
-  SCNetworkReachabilityRef _reachabilityRef;
-  GRPCReachabilityFlags *_previousReachabilityFlags;
-}
-
-- (nullable instancetype)initWithReachability:(nullable SCNetworkReachabilityRef)reachability {
-  if (!reachability) {
-    return nil;
-  }
-  if ((self = [super init])) {
-    _reachabilityRef = CFRetain(reachability);
-    _queue = dispatch_get_main_queue();
-    _previousReachabilityFlags = nil;
-  }
-  return self;
-}
-
-+ (nullable instancetype)monitorWithHost:(nonnull NSString *)host {
-  const char *hostName = host.UTF8String;
-  if (!hostName) {
-    [NSException raise:NSInvalidArgumentException
-                format:@"host.UTF8String returns NULL for %@", host];
-  }
-  SCNetworkReachabilityRef reachability =
-      SCNetworkReachabilityCreateWithName(NULL, hostName);
-
-  GRPCConnectivityMonitor *returnValue = [[self alloc] initWithReachability:reachability];
-  if (reachability) {
-    CFRelease(reachability);
-  }
-  return returnValue;
-}
-
-- (void)handleLossWithHandler:(nullable void (^)(void))lossHandler
-      wifiStatusChangeHandler:(nullable void (^)(void))wifiStatusChangeHandler {
-  __weak typeof(self) weakSelf = self;
-  [self startListeningWithHandler:^(GRPCReachabilityFlags *flags) {
-    typeof(self) strongSelf = weakSelf;
-    if (strongSelf) {
-      if (lossHandler && !flags.reachable) {
-        lossHandler();
+  result = GRPCConnectivityWiFi;
 #if TARGET_OS_IPHONE
-      } else if (wifiStatusChangeHandler &&
-                 strongSelf->_previousReachabilityFlags &&
-                 (flags.isWWAN ^
-                  strongSelf->_previousReachabilityFlags.isWWAN)) {
-        wifiStatusChangeHandler();
-#endif
-      }
-      strongSelf->_previousReachabilityFlags = flags;
-    }
-  }];
-}
-
-- (void)startListeningWithHandler:(void (^)(GRPCReachabilityFlags *))handler {
-  // Copy to ensure the handler block is in the heap (and so can't be deallocated when this method
-  // returns).
-  void (^copiedHandler)(GRPCReachabilityFlags *) = [handler copy];
-  SCNetworkReachabilityContext context = {
-    .version = 0,
-    .info = (__bridge void *)copiedHandler,
-    .retain = CFRetain,
-    .release = CFRelease,
-  };
-  // The following will retain context.info, and release it when the callback is set to NULL.
-  SCNetworkReachabilitySetCallback(_reachabilityRef, PassFlagsToContextInfoBlock, &context);
-  SCNetworkReachabilitySetDispatchQueue(_reachabilityRef, _queue);
-}
-
-- (void)stopListening {
-  // This releases the block on context.info.
-  SCNetworkReachabilitySetCallback(_reachabilityRef, NULL, NULL);
-  SCNetworkReachabilitySetDispatchQueue(_reachabilityRef, NULL);
-}
-
-- (void)setQueue:(dispatch_queue_t)queue {
-  _queue = queue ?: dispatch_get_main_queue();
-}
-
-- (void)dealloc {
-  if (_reachabilityRef) {
-    [self stopListening];
-    CFRelease(_reachabilityRef);
+  if (flags & kSCNetworkReachabilityFlagsIsWWAN) {
+    return result = GRPCConnectivityCellular;
   }
+#endif
+  return result;
+}
+
+static void ReachabilityCallback(
+    SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) {
+  GRPCConnectivityStatus newStatus = CalculateConnectivityStatus(flags);
+
+  if (newStatus != currentStatus) {
+    [[NSNotificationCenter defaultCenter] postNotificationName:kGRPCConnectivityNotification
+                                                        object:nil];
+    currentStatus = newStatus;
+  }
+}
+
+@implementation GRPCConnectivityMonitor
+
++ (void)initialize {
+  if (self == [GRPCConnectivityMonitor self]) {
+    struct sockaddr_in addr = {0};
+    addr.sin_len = sizeof(addr);
+    addr.sin_family = AF_INET;
+    reachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&addr);
+    currentStatus = GRPCConnectivityUnknown;
+
+    SCNetworkConnectionFlags flags;
+    if (SCNetworkReachabilityGetFlags(reachability, &flags)) {
+      currentStatus = CalculateConnectivityStatus(flags);
+    }
+
+    SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
+    if (!SCNetworkReachabilitySetCallback(reachability, ReachabilityCallback, &context) ||
+        !SCNetworkReachabilityScheduleWithRunLoop(
+            reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes)) {
+      NSLog(@"gRPC connectivity monitor fail to set");
+    }
+  }
+}
+
++ (void)registerObserver:(_Nonnull id)observer
+                selector:(SEL)selector {
+  [[NSNotificationCenter defaultCenter] addObserver:observer
+                                           selector:selector
+                                               name:kGRPCConnectivityNotification
+                                             object:nil];
+}
+
++ (void)unregisterObserver:(_Nonnull id)observer {
+  [[NSNotificationCenter defaultCenter] removeObserver:observer];
 }
 
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
index ceae960..8568e33 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.m
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -21,6 +21,7 @@
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
 #import <GRPCClient/GRPCCall.h>
+#import <GRPCClient/GRPCCall+MobileLog.h>
 #ifdef GRPC_COMPILE_WITH_CRONET
 #import <GRPCClient/GRPCCall+ChannelArg.h>
 #import <GRPCClient/GRPCCall+Cronet.h>
@@ -36,12 +37,6 @@
 
 static NSMutableDictionary *kHostCache;
 
-// This connectivity monitor flushes the host cache when connectivity status
-// changes or when connection switch between Wifi and Cellular data, so that a
-// new call will use a new channel. Otherwise, a new call will still use the
-// cached channel which is no longer available and will cause gRPC to hang.
-static GRPCConnectivityMonitor *connectivityMonitor = nil;
-
 @implementation GRPCHost {
   // TODO(mlumish): Investigate whether caching channels with strong links is a good idea.
   GRPCChannel *_channel;
@@ -89,17 +84,7 @@
       kHostCache[address] = self;
       _compressAlgorithm = GRPC_COMPRESS_NONE;
     }
-    // Keep a single monitor to flush the cache if the connectivity status changes
-    // Thread safety guarded by @synchronized(kHostCache)
-    if (!connectivityMonitor) {
-      connectivityMonitor =
-      [GRPCConnectivityMonitor monitorWithHost:hostURL.host];
-      void (^handler)(void) = ^{
-        [GRPCHost flushChannelCache];
-      };
-      [connectivityMonitor handleLossWithHandler:handler
-                         wifiStatusChangeHandler:handler];
-    }
+    [GRPCConnectivityMonitor registerObserver:self selector:@selector(connectivityChange:)];
   }
   return self;
 }
@@ -231,6 +216,11 @@
         [NSNumber numberWithInt:_compressAlgorithm];
   }
 
+  id logConfig = [GRPCCall logConfig];
+  if (logConfig != nil) {
+    args[@GRPC_ARG_MOBILE_LOG_CONFIG] = logConfig;
+  }
+
   return args;
 }
 
@@ -275,6 +265,13 @@
   }
 }
 
+// Flushes the host cache when connectivity status changes or when connection switch between Wifi
+// and Cellular data, so that a new call will use a new channel. Otherwise, a new call will still
+// use the cached channel which is no longer available and will cause gRPC to hang.
+- (void)connectivityChange:(NSNotification *)note {
+  [GRPCHost flushChannelCache];
+}
+
 @end
 
 NS_ASSUME_NONNULL_END
diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h
index 5c134e3..405c2ff 100644
--- a/src/objective-c/GRPCClient/private/version.h
+++ b/src/objective-c/GRPCClient/private/version.h
@@ -23,4 +23,4 @@
 // `tools/buildgen/generate_projects.sh`.
 
 
-#define GRPC_OBJC_VERSION_STRING @"1.10.0-dev"
+#define GRPC_OBJC_VERSION_STRING @"1.11.0-dev"
diff --git a/src/objective-c/ProtoRPC/ProtoMethod.m b/src/objective-c/ProtoRPC/ProtoMethod.m
index 4bef10a..ed585ac 100644
--- a/src/objective-c/ProtoRPC/ProtoMethod.m
+++ b/src/objective-c/ProtoRPC/ProtoMethod.m
@@ -18,7 +18,10 @@
 
 #import "ProtoMethod.h"
 
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-implementations"
 @implementation ProtoMethod
+#pragma clang diagnostic pop
 - (instancetype)initWithPackage:(NSString *)package
                         service:(NSString *)service
                          method:(NSString *)method {
diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m
index 1ecfcc5..20b9d04 100644
--- a/src/objective-c/ProtoRPC/ProtoRPC.m
+++ b/src/objective-c/ProtoRPC/ProtoRPC.m
@@ -42,7 +42,10 @@
                          userInfo:info];
 }
 
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-implementations"
 @implementation ProtoRPC {
+#pragma clang diagnostic pop
   id<GRXWriteable> _responseWriteable;
 }
 
diff --git a/src/objective-c/ProtoRPC/ProtoService.m b/src/objective-c/ProtoRPC/ProtoService.m
index be6089f..611cee4 100644
--- a/src/objective-c/ProtoRPC/ProtoService.m
+++ b/src/objective-c/ProtoRPC/ProtoService.m
@@ -24,7 +24,10 @@
 #import "ProtoMethod.h"
 #import "ProtoRPC.h"
 
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-implementations"
 @implementation ProtoService {
+#pragma clang diagnostic pop
   NSString *_host;
   NSString *_packageName;
   NSString *_serviceName;
diff --git a/src/objective-c/RxLibrary/GRXConcurrentWriteable.m b/src/objective-c/RxLibrary/GRXConcurrentWriteable.m
index 37bc975..c262313 100644
--- a/src/objective-c/RxLibrary/GRXConcurrentWriteable.m
+++ b/src/objective-c/RxLibrary/GRXConcurrentWriteable.m
@@ -64,21 +64,25 @@
 }
 
 - (void)enqueueSuccessfulCompletion {
+  __weak typeof(self) weakSelf = self;
   dispatch_async(_writeableQueue, ^{
-    BOOL finished = NO;
-    @synchronized (self) {
-      if (!_alreadyFinished) {
-        _alreadyFinished = YES;
-      } else {
-        finished = YES;
+    typeof(self) strongSelf = weakSelf;
+    if (strongSelf) {
+      BOOL finished = NO;
+      @synchronized (self) {
+        if (!strongSelf->_alreadyFinished) {
+          strongSelf->_alreadyFinished = YES;
+        } else {
+          finished = YES;
+        }
       }
-    }
-    if (!finished) {
-      // Cancellation is now impossible. None of the other three blocks can run concurrently with
-      // this one.
-      [self.writeable writesFinishedWithError:nil];
-      // Skip any possible message to the wrapped writeable enqueued after this one.
-      self.writeable = nil;
+      if (!finished) {
+        // Cancellation is now impossible. None of the other three blocks can run concurrently with
+        // this one.
+        [self.writeable writesFinishedWithError:nil];
+        // Skip any possible message to the wrapped writeable enqueued after this one.
+        self.writeable = nil;
+      }
     }
   });
 }
diff --git a/src/objective-c/tests/Connectivity/Base.lproj/Main.storyboard b/src/objective-c/tests/Connectivity/Base.lproj/Main.storyboard
deleted file mode 100644
index 9a05b86..0000000
--- a/src/objective-c/tests/Connectivity/Base.lproj/Main.storyboard
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11129.15" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
-    <dependencies>
-        <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11103.10"/>
-    </dependencies>
-    <scenes>
-        <!--View Controller-->
-        <scene sceneID="tne-QT-ifu">
-            <objects>
-                <viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController"/>
-                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
-            </objects>
-        </scene>
-    </scenes>
-</document>
diff --git a/src/objective-c/tests/Connectivity/ConnectivityTestingApp.xcodeproj/project.pbxproj b/src/objective-c/tests/Connectivity/ConnectivityTestingApp.xcodeproj/project.pbxproj
index 3f26c98..6a4c351 100644
--- a/src/objective-c/tests/Connectivity/ConnectivityTestingApp.xcodeproj/project.pbxproj
+++ b/src/objective-c/tests/Connectivity/ConnectivityTestingApp.xcodeproj/project.pbxproj
@@ -3,90 +3,104 @@
 	archiveVersion = 1;
 	classes = {
 	};
-	objectVersion = 46;
+	objectVersion = 48;
 	objects = {
 
 /* Begin PBXBuildFile section */
-		500A4E0AC9D489EB214D1ED4 /* libPods-ConnectivityTestingApp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C2AF815D8242A2172891621D /* libPods-ConnectivityTestingApp.a */; };
-		63BFB9CC1D2478DD00E17927 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 63BFB9CB1D2478DD00E17927 /* main.m */; };
-		63BFB9D21D2478DD00E17927 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 63BFB9D11D2478DD00E17927 /* ViewController.m */; };
-		63BFB9D51D2478DD00E17927 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 63BFB9D31D2478DD00E17927 /* Main.storyboard */; };
+		5EC49F992043E46B00ED189A /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EC49F982043E46B00ED189A /* ViewController.m */; };
+		5EC49F9C2043E46B00ED189A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5EC49F9A2043E46B00ED189A /* Main.storyboard */; };
+		5EC49F9E2043E46B00ED189A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5EC49F9D2043E46B00ED189A /* Assets.xcassets */; };
+		5EC49FA12043E46B00ED189A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5EC49F9F2043E46B00ED189A /* LaunchScreen.storyboard */; };
+		5EC49FA42043E46B00ED189A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EC49FA32043E46B00ED189A /* main.m */; };
+		DDCBF00DB326F4FA4706953C /* libPods-ConnectivityTestingApp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EF1DD1BF13CC3E1BDA1A1089 /* libPods-ConnectivityTestingApp.a */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
-		63BFB9C71D2478DD00E17927 /* ConnectivityTestingApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ConnectivityTestingApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
-		63BFB9CB1D2478DD00E17927 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = SOURCE_ROOT; };
-		63BFB9D11D2478DD00E17927 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = SOURCE_ROOT; };
-		63BFB9D41D2478DD00E17927 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
-		63BFB9DB1D2478DD00E17927 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; };
-		BA96CBC1612BD2F70E66246C /* Pods-ConnectivityTestingApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ConnectivityTestingApp.release.xcconfig"; path = "Pods/Target Support Files/Pods-ConnectivityTestingApp/Pods-ConnectivityTestingApp.release.xcconfig"; sourceTree = "<group>"; };
-		C2AF815D8242A2172891621D /* libPods-ConnectivityTestingApp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ConnectivityTestingApp.a"; sourceTree = BUILT_PRODUCTS_DIR; };
-		FC9BD3AE427396EDB4CD13E3 /* Pods-ConnectivityTestingApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ConnectivityTestingApp.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ConnectivityTestingApp/Pods-ConnectivityTestingApp.debug.xcconfig"; sourceTree = "<group>"; };
+		5EC49F912043E46B00ED189A /* ConnectivityTestingApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ConnectivityTestingApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		5EC49F982043E46B00ED189A /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
+		5EC49F9B2043E46B00ED189A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+		5EC49F9D2043E46B00ED189A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+		5EC49FA02043E46B00ED189A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
+		5EC49FA22043E46B00ED189A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		5EC49FA32043E46B00ED189A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+		69B8F09A730364513700F23C /* Pods-ConnectivityTestingApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ConnectivityTestingApp.release.xcconfig"; path = "Pods/Target Support Files/Pods-ConnectivityTestingApp/Pods-ConnectivityTestingApp.release.xcconfig"; sourceTree = "<group>"; };
+		A16A6C6AAAC10A09DFF329F2 /* Pods-ConnectivityTestingApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ConnectivityTestingApp.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ConnectivityTestingApp/Pods-ConnectivityTestingApp.debug.xcconfig"; sourceTree = "<group>"; };
+		EF1DD1BF13CC3E1BDA1A1089 /* libPods-ConnectivityTestingApp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ConnectivityTestingApp.a"; sourceTree = BUILT_PRODUCTS_DIR; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
-		63BFB9C41D2478DD00E17927 /* Frameworks */ = {
+		5EC49F8E2043E46B00ED189A /* Frameworks */ = {
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				500A4E0AC9D489EB214D1ED4 /* libPods-ConnectivityTestingApp.a in Frameworks */,
+				DDCBF00DB326F4FA4706953C /* libPods-ConnectivityTestingApp.a in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
-		16E6C67F2E48B42376DFFD2A /* Pods */ = {
+		1AAFFD715A6EF1FEBF5AD796 /* Pods */ = {
 			isa = PBXGroup;
 			children = (
-				FC9BD3AE427396EDB4CD13E3 /* Pods-ConnectivityTestingApp.debug.xcconfig */,
-				BA96CBC1612BD2F70E66246C /* Pods-ConnectivityTestingApp.release.xcconfig */,
+				A16A6C6AAAC10A09DFF329F2 /* Pods-ConnectivityTestingApp.debug.xcconfig */,
+				69B8F09A730364513700F23C /* Pods-ConnectivityTestingApp.release.xcconfig */,
 			);
 			name = Pods;
 			sourceTree = "<group>";
 		};
-		48F8EC18C66D3416A41F76F5 /* Frameworks */ = {
+		5EC49F882043E46B00ED189A = {
 			isa = PBXGroup;
 			children = (
-				C2AF815D8242A2172891621D /* libPods-ConnectivityTestingApp.a */,
-			);
-			name = Frameworks;
-			sourceTree = "<group>";
-		};
-		63BFB9BE1D2478DD00E17927 = {
-			isa = PBXGroup;
-			children = (
-				63BFB9D11D2478DD00E17927 /* ViewController.m */,
-				63BFB9D31D2478DD00E17927 /* Main.storyboard */,
-				63BFB9DB1D2478DD00E17927 /* Info.plist */,
-				63BFB9CB1D2478DD00E17927 /* main.m */,
-				63BFB9C81D2478DD00E17927 /* Products */,
-				16E6C67F2E48B42376DFFD2A /* Pods */,
-				48F8EC18C66D3416A41F76F5 /* Frameworks */,
+				5EC49F932043E46B00ED189A /* ConnectivityTestingApp */,
+				5EC49F922043E46B00ED189A /* Products */,
+				1AAFFD715A6EF1FEBF5AD796 /* Pods */,
+				99E308FECF6991F75249AD00 /* Frameworks */,
 			);
 			sourceTree = "<group>";
 		};
-		63BFB9C81D2478DD00E17927 /* Products */ = {
+		5EC49F922043E46B00ED189A /* Products */ = {
 			isa = PBXGroup;
 			children = (
-				63BFB9C71D2478DD00E17927 /* ConnectivityTestingApp.app */,
+				5EC49F912043E46B00ED189A /* ConnectivityTestingApp.app */,
 			);
 			name = Products;
 			sourceTree = "<group>";
 		};
+		5EC49F932043E46B00ED189A /* ConnectivityTestingApp */ = {
+			isa = PBXGroup;
+			children = (
+				5EC49F982043E46B00ED189A /* ViewController.m */,
+				5EC49F9A2043E46B00ED189A /* Main.storyboard */,
+				5EC49F9D2043E46B00ED189A /* Assets.xcassets */,
+				5EC49F9F2043E46B00ED189A /* LaunchScreen.storyboard */,
+				5EC49FA22043E46B00ED189A /* Info.plist */,
+				5EC49FA32043E46B00ED189A /* main.m */,
+			);
+			path = ConnectivityTestingApp;
+			sourceTree = "<group>";
+		};
+		99E308FECF6991F75249AD00 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				EF1DD1BF13CC3E1BDA1A1089 /* libPods-ConnectivityTestingApp.a */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
-		63BFB9C61D2478DD00E17927 /* ConnectivityTestingApp */ = {
+		5EC49F902043E46B00ED189A /* ConnectivityTestingApp */ = {
 			isa = PBXNativeTarget;
-			buildConfigurationList = 63BFB9DE1D2478DD00E17927 /* Build configuration list for PBXNativeTarget "ConnectivityTestingApp" */;
+			buildConfigurationList = 5EC49FA72043E46B00ED189A /* Build configuration list for PBXNativeTarget "ConnectivityTestingApp" */;
 			buildPhases = (
-				4DCA2703A0AA5DC1BD2751B8 /* [CP] Check Pods Manifest.lock */,
-				63BFB9C31D2478DD00E17927 /* Sources */,
-				63BFB9C41D2478DD00E17927 /* Frameworks */,
-				63BFB9C51D2478DD00E17927 /* Resources */,
-				8593A2388A8F7BF5A7E98D26 /* [CP] Embed Pods Frameworks */,
-				5347BF6C41E7888C1C05CD88 /* [CP] Copy Pods Resources */,
+				7CABF198C569A04592862390 /* [CP] Check Pods Manifest.lock */,
+				5EC49F8D2043E46B00ED189A /* Sources */,
+				5EC49F8E2043E46B00ED189A /* Frameworks */,
+				5EC49F8F2043E46B00ED189A /* Resources */,
+				9F67C72B6B6BAF2781078886 /* [CP] Embed Pods Frameworks */,
+				735516C793AF7394FBB83B7F /* [CP] Copy Pods Resources */,
 			);
 			buildRules = (
 			);
@@ -94,87 +108,93 @@
 			);
 			name = ConnectivityTestingApp;
 			productName = ConnectivityTestingApp;
-			productReference = 63BFB9C71D2478DD00E17927 /* ConnectivityTestingApp.app */;
+			productReference = 5EC49F912043E46B00ED189A /* ConnectivityTestingApp.app */;
 			productType = "com.apple.product-type.application";
 		};
 /* End PBXNativeTarget section */
 
 /* Begin PBXProject section */
-		63BFB9BF1D2478DD00E17927 /* Project object */ = {
+		5EC49F892043E46B00ED189A /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 0800;
+				LastUpgradeCheck = 0920;
 				ORGANIZATIONNAME = gRPC;
 				TargetAttributes = {
-					63BFB9C61D2478DD00E17927 = {
-						CreatedOnToolsVersion = 8.0;
-						DevelopmentTeam = EQHXZ8M8AV;
-						DevelopmentTeamName = "Google, Inc.";
-						ProvisioningStyle = Automatic;
+					5EC49F902043E46B00ED189A = {
+						CreatedOnToolsVersion = 9.2;
+						ProvisioningStyle = Manual;
 					};
 				};
 			};
-			buildConfigurationList = 63BFB9C21D2478DD00E17927 /* Build configuration list for PBXProject "ConnectivityTestingApp" */;
-			compatibilityVersion = "Xcode 3.2";
-			developmentRegion = English;
+			buildConfigurationList = 5EC49F8C2043E46B00ED189A /* Build configuration list for PBXProject "ConnectivityTestingApp" */;
+			compatibilityVersion = "Xcode 8.0";
+			developmentRegion = en;
 			hasScannedForEncodings = 0;
 			knownRegions = (
 				en,
 				Base,
 			);
-			mainGroup = 63BFB9BE1D2478DD00E17927;
-			productRefGroup = 63BFB9C81D2478DD00E17927 /* Products */;
+			mainGroup = 5EC49F882043E46B00ED189A;
+			productRefGroup = 5EC49F922043E46B00ED189A /* Products */;
 			projectDirPath = "";
 			projectRoot = "";
 			targets = (
-				63BFB9C61D2478DD00E17927 /* ConnectivityTestingApp */,
+				5EC49F902043E46B00ED189A /* ConnectivityTestingApp */,
 			);
 		};
 /* End PBXProject section */
 
 /* Begin PBXResourcesBuildPhase section */
-		63BFB9C51D2478DD00E17927 /* Resources */ = {
+		5EC49F8F2043E46B00ED189A /* Resources */ = {
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				63BFB9D51D2478DD00E17927 /* Main.storyboard in Resources */,
+				5EC49FA12043E46B00ED189A /* LaunchScreen.storyboard in Resources */,
+				5EC49F9E2043E46B00ED189A /* Assets.xcassets in Resources */,
+				5EC49F9C2043E46B00ED189A /* Main.storyboard in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXShellScriptBuildPhase section */
-		4DCA2703A0AA5DC1BD2751B8 /* [CP] Check Pods Manifest.lock */ = {
+		735516C793AF7394FBB83B7F /* [CP] Copy Pods Resources */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputPaths = (
-			);
-			name = "[CP] Check Pods Manifest.lock";
-			outputPaths = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-			shellPath = /bin/sh;
-			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n";
-			showEnvVarsInLog = 0;
-		};
-		5347BF6C41E7888C1C05CD88 /* [CP] Copy Pods Resources */ = {
-			isa = PBXShellScriptBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			inputPaths = (
+				"${SRCROOT}/Pods/Target Support Files/Pods-ConnectivityTestingApp/Pods-ConnectivityTestingApp-resources.sh",
+				"${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle",
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
 			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ConnectivityTestingApp/Pods-ConnectivityTestingApp-resources.sh\"\n";
 			showEnvVarsInLog = 0;
 		};
-		8593A2388A8F7BF5A7E98D26 /* [CP] Embed Pods Frameworks */ = {
+		7CABF198C569A04592862390 /* [CP] Check Pods Manifest.lock */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+				"${PODS_ROOT}/Manifest.lock",
+			);
+			name = "[CP] Check Pods Manifest.lock";
+			outputPaths = (
+				"$(DERIVED_FILE_DIR)/Pods-ConnectivityTestingApp-checkManifestLockResult.txt",
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+			showEnvVarsInLog = 0;
+		};
+		9F67C72B6B6BAF2781078886 /* [CP] Embed Pods Frameworks */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
@@ -192,55 +212,72 @@
 /* End PBXShellScriptBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
-		63BFB9C31D2478DD00E17927 /* Sources */ = {
+		5EC49F8D2043E46B00ED189A /* Sources */ = {
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				63BFB9D21D2478DD00E17927 /* ViewController.m in Sources */,
-				63BFB9CC1D2478DD00E17927 /* main.m in Sources */,
+				5EC49F992043E46B00ED189A /* ViewController.m in Sources */,
+				5EC49FA42043E46B00ED189A /* main.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXSourcesBuildPhase section */
 
 /* Begin PBXVariantGroup section */
-		63BFB9D31D2478DD00E17927 /* Main.storyboard */ = {
+		5EC49F9A2043E46B00ED189A /* Main.storyboard */ = {
 			isa = PBXVariantGroup;
 			children = (
-				63BFB9D41D2478DD00E17927 /* Base */,
+				5EC49F9B2043E46B00ED189A /* Base */,
 			);
 			name = Main.storyboard;
-			path = .;
-			sourceTree = SOURCE_ROOT;
+			sourceTree = "<group>";
+		};
+		5EC49F9F2043E46B00ED189A /* LaunchScreen.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				5EC49FA02043E46B00ED189A /* Base */,
+			);
+			name = LaunchScreen.storyboard;
+			sourceTree = "<group>";
 		};
 /* End PBXVariantGroup section */
 
 /* Begin XCBuildConfiguration section */
-		63BFB9DC1D2478DD00E17927 /* Debug */ = {
+		5EC49FA52043E46B00ED189A /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
 				CLANG_ANALYZER_NONNULL = YES;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
 				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
 				CLANG_WARN_CONSTANT_CONVERSION = YES;
 				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
 				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
 				CLANG_WARN_EMPTY_BODY = YES;
 				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
 				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
 				COPY_PHASE_STRIP = NO;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
-				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GCC_DYNAMIC_NO_PIC = NO;
 				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_OPTIMIZATION_LEVEL = 0;
@@ -254,38 +291,48 @@
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
-				IPHONEOS_DEPLOYMENT_TARGET = 10.0;
+				IPHONEOS_DEPLOYMENT_TARGET = 11.2;
 				MTL_ENABLE_DEBUG_INFO = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				SDKROOT = iphoneos;
 			};
 			name = Debug;
 		};
-		63BFB9DD1D2478DD00E17927 /* Release */ = {
+		5EC49FA62043E46B00ED189A /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
 				CLANG_ANALYZER_NONNULL = YES;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
 				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
 				CLANG_WARN_CONSTANT_CONVERSION = YES;
 				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
 				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
 				CLANG_WARN_EMPTY_BODY = YES;
 				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
 				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
 				COPY_PHASE_STRIP = NO;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				ENABLE_NS_ASSERTIONS = NO;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
-				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
@@ -293,61 +340,71 @@
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
-				IPHONEOS_DEPLOYMENT_TARGET = 10.0;
+				IPHONEOS_DEPLOYMENT_TARGET = 11.2;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				SDKROOT = iphoneos;
 				VALIDATE_PRODUCT = YES;
 			};
 			name = Release;
 		};
-		63BFB9DF1D2478DD00E17927 /* Debug */ = {
+		5EC49FA82043E46B00ED189A /* Debug */ = {
 			isa = XCBuildConfiguration;
-			baseConfigurationReference = FC9BD3AE427396EDB4CD13E3 /* Pods-ConnectivityTestingApp.debug.xcconfig */;
+			baseConfigurationReference = A16A6C6AAAC10A09DFF329F2 /* Pods-ConnectivityTestingApp.debug.xcconfig */;
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
-				INFOPLIST_FILE = Info.plist;
-				IPHONEOS_DEPLOYMENT_TARGET = 9.3;
+				CODE_SIGN_STYLE = Manual;
+				DEVELOPMENT_TEAM = EQHXZ8M8AV;
+				INFOPLIST_FILE = ConnectivityTestingApp/Info.plist;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
 				PRODUCT_BUNDLE_IDENTIFIER = io.grpc.ConnectivityTestingApp;
 				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE = "aa306b73-1a89-4299-8ead-c102fd059d96";
+				PROVISIONING_PROFILE_SPECIFIER = "Google Development";
+				TARGETED_DEVICE_FAMILY = "1,2";
+				USER_HEADER_SEARCH_PATHS = ../../../..;
 			};
 			name = Debug;
 		};
-		63BFB9E01D2478DD00E17927 /* Release */ = {
+		5EC49FA92043E46B00ED189A /* Release */ = {
 			isa = XCBuildConfiguration;
-			baseConfigurationReference = BA96CBC1612BD2F70E66246C /* Pods-ConnectivityTestingApp.release.xcconfig */;
+			baseConfigurationReference = 69B8F09A730364513700F23C /* Pods-ConnectivityTestingApp.release.xcconfig */;
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
-				INFOPLIST_FILE = Info.plist;
-				IPHONEOS_DEPLOYMENT_TARGET = 9.3;
+				CODE_SIGN_STYLE = Manual;
+				DEVELOPMENT_TEAM = EQHXZ8M8AV;
+				INFOPLIST_FILE = ConnectivityTestingApp/Info.plist;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
 				PRODUCT_BUNDLE_IDENTIFIER = io.grpc.ConnectivityTestingApp;
 				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE = "aa306b73-1a89-4299-8ead-c102fd059d96";
+				PROVISIONING_PROFILE_SPECIFIER = "Google Development";
+				TARGETED_DEVICE_FAMILY = "1,2";
+				USER_HEADER_SEARCH_PATHS = ../../../..;
 			};
 			name = Release;
 		};
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
-		63BFB9C21D2478DD00E17927 /* Build configuration list for PBXProject "ConnectivityTestingApp" */ = {
+		5EC49F8C2043E46B00ED189A /* Build configuration list for PBXProject "ConnectivityTestingApp" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
-				63BFB9DC1D2478DD00E17927 /* Debug */,
-				63BFB9DD1D2478DD00E17927 /* Release */,
+				5EC49FA52043E46B00ED189A /* Debug */,
+				5EC49FA62043E46B00ED189A /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
-		63BFB9DE1D2478DD00E17927 /* Build configuration list for PBXNativeTarget "ConnectivityTestingApp" */ = {
+		5EC49FA72043E46B00ED189A /* Build configuration list for PBXNativeTarget "ConnectivityTestingApp" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
-				63BFB9DF1D2478DD00E17927 /* Debug */,
-				63BFB9E01D2478DD00E17927 /* Release */,
+				5EC49FA82043E46B00ED189A /* Debug */,
+				5EC49FA92043E46B00ED189A /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
 /* End XCConfigurationList section */
 	};
-	rootObject = 63BFB9BF1D2478DD00E17927 /* Project object */;
+	rootObject = 5EC49F892043E46B00ED189A /* Project object */;
 }
diff --git a/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..1d060ed
--- /dev/null
+++ b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,93 @@
+{
+  "images" : [
+    {
+      "idiom" : "iphone",
+      "size" : "20x20",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "20x20",
+      "scale" : "3x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "29x29",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "29x29",
+      "scale" : "3x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "40x40",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "40x40",
+      "scale" : "3x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "60x60",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "60x60",
+      "scale" : "3x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "20x20",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "20x20",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "29x29",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "29x29",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "40x40",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "40x40",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "76x76",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "76x76",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "83.5x83.5",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Base.lproj/LaunchScreen.storyboard b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 0000000..60a0921
--- /dev/null
+++ b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
+    <device id="retina4_7" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--View Controller-->
+        <scene sceneID="EHf-IW-A2E">
+            <objects>
+                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="q3l-Ud-sIn">
+                                <rect key="frame" x="167" y="131" width="41" height="30"/>
+                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                <state key="normal" title="Unary"/>
+                            </button>
+                            <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="RfU-eq-cee">
+                                <rect key="frame" x="152" y="220" width="70" height="30"/>
+                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                <state key="normal" title="Streaming"/>
+                            </button>
+                        </subviews>
+                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="53" y="375"/>
+        </scene>
+    </scenes>
+</document>
diff --git a/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Base.lproj/Main.storyboard b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..1b4e0d0
--- /dev/null
+++ b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Base.lproj/Main.storyboard
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
+    <device id="retina4_7" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--View Controller-->
+        <scene sceneID="tne-QT-ifu">
+            <objects>
+                <viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8QE-go-1ZJ">
+                                <rect key="frame" x="168" y="160" width="41" height="30"/>
+                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                <state key="normal" title="Unary"/>
+                                <connections>
+                                    <action selector="tapUnary:" destination="BYZ-38-t0r" eventType="touchUpInside" id="OGf-25-OYx"/>
+                                </connections>
+                            </button>
+                            <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="p4l-br-UUo">
+                                <rect key="frame" x="153" y="229" width="70" height="30"/>
+                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                <state key="normal" title="Streaming"/>
+                                <connections>
+                                    <action selector="tapStreaming:" destination="BYZ-38-t0r" eventType="touchUpInside" id="S3O-W8-Fed"/>
+                                </connections>
+                            </button>
+                        </subviews>
+                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+            </objects>
+        </scene>
+    </scenes>
+</document>
diff --git a/src/objective-c/tests/Connectivity/Info.plist b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Info.plist
similarity index 75%
rename from src/objective-c/tests/Connectivity/Info.plist
rename to src/objective-c/tests/Connectivity/ConnectivityTestingApp/Info.plist
index 8a9fb88..16be3b6 100644
--- a/src/objective-c/tests/Connectivity/Info.plist
+++ b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Info.plist
@@ -3,7 +3,7 @@
 <plist version="1.0">
 <dict>
 	<key>CFBundleDevelopmentRegion</key>
-	<string>en</string>
+	<string>$(DEVELOPMENT_LANGUAGE)</string>
 	<key>CFBundleExecutable</key>
 	<string>$(EXECUTABLE_NAME)</string>
 	<key>CFBundleIdentifier</key>
@@ -16,14 +16,12 @@
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
 	<string>1.0</string>
-	<key>CFBundleSignature</key>
-	<string>????</string>
 	<key>CFBundleVersion</key>
 	<string>1</string>
 	<key>LSRequiresIPhoneOS</key>
 	<true/>
 	<key>UILaunchStoryboardName</key>
-	<string>Main</string>
+	<string>LaunchScreen</string>
 	<key>UIMainStoryboardFile</key>
 	<string>Main</string>
 	<key>UIRequiredDeviceCapabilities</key>
@@ -36,5 +34,12 @@
 		<string>UIInterfaceOrientationLandscapeLeft</string>
 		<string>UIInterfaceOrientationLandscapeRight</string>
 	</array>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
 </dict>
 </plist>
diff --git a/src/objective-c/tests/Connectivity/ConnectivityTestingApp/ViewController.m b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/ViewController.m
new file mode 100644
index 0000000..f91d2a6
--- /dev/null
+++ b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/ViewController.m
@@ -0,0 +1,101 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+
+#import <GRPCClient/GRPCCall.h>
+#import <ProtoRPC/ProtoMethod.h>
+#import <RxLibrary/GRXWriter+Immediate.h>
+#import <RxLibrary/GRXWriter+Transformations.h>
+#import <RxLibrary/GRXBufferedPipe.h>
+
+#import "src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h"
+
+NSString *host = @"grpc-test.sandbox.googleapis.com";
+
+@interface ViewController : UIViewController
+@end
+
+@implementation ViewController
+- (void)viewDidLoad {
+  [super viewDidLoad];
+
+  [GRPCConnectivityMonitor registerObserver:self
+                                   selector:@selector(reachabilityChanged:)];
+}
+
+- (void)reachabilityChanged:(NSNotification *)note {
+  NSLog(@"Reachability changed\n");
+}
+
+- (IBAction)tapUnary:(id)sender {
+  // Create a unary call
+
+  // A trivial proto message to generate a response
+  char bytes[] = {0x10, 0x05, 0x1A, 0x07, 0x12, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+  GRPCProtoMethod *method = [[GRPCProtoMethod alloc] initWithPackage:@"grpc.testing"
+                                                             service:@"TestService"
+                                                              method:@"UnaryCall"];
+  GRXWriter *loggingRequestWriter =
+      [[GRXWriter writerWithValue:[NSData dataWithBytes:bytes length:sizeof(bytes)]]
+                              map:^id(id value) {
+                                NSLog(@"Sending request.");
+                                return value;
+                              }];
+  GRPCCall *call = [[GRPCCall alloc] initWithHost:host
+                                             path:method.HTTPPath
+                                   requestsWriter:loggingRequestWriter];
+
+  [call startWithWriteable:[GRXWriteable writeableWithEventHandler:^(BOOL done, id value,
+                                                                       NSError *error) {
+    if (!done) {
+      return;
+    }
+    NSLog(@"Unary call finished with error: %@", error);
+  }]];
+}
+
+- (IBAction)tapStreaming:(id)sender {
+  // Create a streaming call
+
+  // A trivial proto message to generate a response
+  char bytes[] = {0x12, 0x02, 0x08, 0x02, 0x1A, 0x04, 0x12, 0x02, 0x00, 0x00};
+
+  GRPCProtoMethod *method = [[GRPCProtoMethod alloc] initWithPackage:@"grpc.testing"
+                                                             service:@"TestService"
+                                                              method:@"FullDuplexCall"];
+
+  GRXBufferedPipe *requestsBuffer = [[GRXBufferedPipe alloc] init];
+
+  [requestsBuffer writeValue:[NSData dataWithBytes:bytes length:sizeof(bytes)]];
+
+  GRPCCall *call = [[GRPCCall alloc] initWithHost:host
+                                             path:method.HTTPPath
+                                   requestsWriter:requestsBuffer];
+
+  [call startWithWriteable:[GRXWriteable writeableWithEventHandler:^(BOOL done, id value,
+                                                                     NSError *error) {
+    if (!done) {
+      return;
+    }
+    NSLog(@"Streaming call finished with error: %@", error);
+  }]];
+}
+
+@end
diff --git a/src/objective-c/tests/Connectivity/main.m b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/main.m
similarity index 100%
rename from src/objective-c/tests/Connectivity/main.m
rename to src/objective-c/tests/Connectivity/ConnectivityTestingApp/main.m
diff --git a/src/objective-c/tests/Connectivity/README.md b/src/objective-c/tests/Connectivity/README.md
index 851cb9d..907821e 100644
--- a/src/objective-c/tests/Connectivity/README.md
+++ b/src/objective-c/tests/Connectivity/README.md
@@ -2,14 +2,12 @@
 
 It makes RPCs in a loop, logging when the request is sent and the response is received.
 
-To test on the simulator, run `pod install`, open the workspace created by Cocoapods, and run the app.
-Once running, disable WiFi (or ethernet) _in your computer_, then enable it again after a while. Don't
-bother with the simulator's WiFi or cell settings, as they have no effect: Simulator apps are just Mac
-apps running within the simulator UI.
+To test on the simulator, run `pod install`, open the workspace created by Cocoapods, and run the
+app on an iOS device. Once running, tap a few times of each of the two buttons to make a few unary and streaming
+calls. Then disable/enable different network interfaces (WiFi, cellular) on your device.
 
-The expected result is to never see a "hanged" RPC: success or failure should happen almost immediately
-after sending the request. Symptom of a hanged RPC is a log like the following being the last in your
-console:
+The expected behavior is that the pending streaming calls fails immediately with error UNAVAILABLE.
+Moreover, when network comes back, new calls have the same behavior.
 
 ```
 2016-06-29 16:51:29.443 ConnectivityTestingApp[73129:3567949] Sending request.
diff --git a/src/objective-c/tests/Connectivity/ViewController.m b/src/objective-c/tests/Connectivity/ViewController.m
deleted file mode 100644
index e39f3be..0000000
--- a/src/objective-c/tests/Connectivity/ViewController.m
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- *
- * Copyright 2016 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#import <UIKit/UIKit.h>
-
-#import <GRPCClient/GRPCCall.h>
-#import <ProtoRPC/ProtoMethod.h>
-#import <RxLibrary/GRXWriter+Immediate.h>
-#import <RxLibrary/GRXWriter+Transformations.h>
-
-@interface ViewController : UIViewController
-@end
-
-@implementation ViewController
-- (void)viewDidLoad {
-  [super viewDidLoad];
-
-  NSString *host = @"grpc-test.sandbox.googleapis.com";
-
-  GRPCProtoMethod *method = [[GRPCProtoMethod alloc] initWithPackage:@"grpc.testing"
-                                                             service:@"TestService"
-                                                              method:@"StreamingOutputCall"];
-
-  __block void (^startCall)() = ^{
-    GRXWriter *loggingRequestWriter = [[GRXWriter writerWithValue:[NSData data]] map:^id(id value) {
-      NSLog(@"Sending request.");
-      return value;
-    }];
-
-    GRPCCall *call = [[GRPCCall alloc] initWithHost:host
-                                               path:method.HTTPPath
-                                     requestsWriter:loggingRequestWriter];
-
-    [call startWithWriteable:[GRXWriteable writeableWithEventHandler:^(BOOL done, id value,
-                                                                       NSError *error) {
-      if (!done) {
-        return;
-      }
-      if (error) {
-        NSLog(@"Finished with error %@", error);
-      } else {
-        NSLog(@"Finished successfully.");
-      }
-
-      dispatch_time_t oneSecond = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC));
-      dispatch_after(oneSecond, dispatch_get_main_queue(), startCall);
-    }]];
-  };
-
-  startCall();
-}
-@end
diff --git a/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.mm b/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.mm
index 16940a4..33ccdb5 100644
--- a/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.mm
+++ b/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.mm
@@ -34,12 +34,12 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/security/credentials/credentials.h"
 #include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gpr/tmpfile.h"
 #include "test/core/end2end/data/ssl_test_data.h"
@@ -224,8 +224,7 @@
 }
 
 - (void)testBinaryMetadata {
-  // NOT SUPPORTED
-  //[self testIndividualCase:(char *)"binary_metadata"];
+  [self testIndividualCase:(char *)"binary_metadata"];
 }
 
 - (void)testCallCreds {
diff --git a/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m b/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m
index 09ee062..28414b8 100644
--- a/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m
+++ b/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m
@@ -23,7 +23,6 @@
 #import <Cronet/Cronet.h>
 #import <grpc/grpc.h>
 #import <grpc/grpc_cronet.h>
-#import <grpc/support/host_port.h>
 #import "test/core/end2end/cq_verifier.h"
 #import "test/core/util/port.h"
 
@@ -32,6 +31,7 @@
 
 #import "src/core/lib/channel/channel_args.h"
 #import "src/core/lib/gpr/env.h"
+#import "src/core/lib/gpr/host_port.h"
 #import "src/core/lib/gpr/string.h"
 #import "src/core/lib/gpr/tmpfile.h"
 #import "test/core/end2end/data/ssl_test_data.h"
diff --git a/src/objective-c/tests/Podfile b/src/objective-c/tests/Podfile
index 9e9db1f..6e17d9a 100644
--- a/src/objective-c/tests/Podfile
+++ b/src/objective-c/tests/Podfile
@@ -8,7 +8,6 @@
 
 # Install the dependencies in the main target plus all test targets.
 %w(
-  Tests
   AllTests
   RxLibraryUnitTests
   InteropTestsRemote
@@ -44,10 +43,8 @@
   target target_name do
     pod 'BoringSSL', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true
     pod 'CronetFramework', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c"
-    pod 'gRPC-Core', :path => GRPC_LOCAL_SRC
-    pod 'gRPC-Core/Cronet-Interface', :path => GRPC_LOCAL_SRC
     pod 'gRPC-Core/Cronet-Implementation', :path => GRPC_LOCAL_SRC
-    pod 'gRPC-Core/Tests', :path => GRPC_LOCAL_SRC
+    pod 'gRPC-Core/Cronet-Tests', :path => GRPC_LOCAL_SRC
   end
 end
 
diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
index 9a6cb0e..e0f220e 100644
--- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
+++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
@@ -743,11 +743,11 @@
 			);
 			inputPaths = (
 				"${SRCROOT}/Pods/Target Support Files/Pods-CronetUnitTests/Pods-CronetUnitTests-resources.sh",
-				$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
+				"${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle",
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
-				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -845,11 +845,11 @@
 			);
 			inputPaths = (
 				"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL-resources.sh",
-				$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
+				"${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle",
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
-				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -863,11 +863,11 @@
 			);
 			inputPaths = (
 				"${SRCROOT}/Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests-resources.sh",
-				$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
+				"${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle",
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
-				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -935,11 +935,11 @@
 			);
 			inputPaths = (
 				"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext-resources.sh",
-				$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
+				"${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle",
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
-				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -986,11 +986,11 @@
 			);
 			inputPaths = (
 				"${SRCROOT}/Pods/Target Support Files/Pods-AllTests/Pods-AllTests-resources.sh",
-				$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
+				"${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle",
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
-				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -1037,11 +1037,11 @@
 			);
 			inputPaths = (
 				"${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-resources.sh",
-				$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
+				"${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle",
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
-				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -1091,11 +1091,11 @@
 			);
 			inputPaths = (
 				"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote-resources.sh",
-				$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
+				"${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle",
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
-				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -1124,11 +1124,11 @@
 			);
 			inputPaths = (
 				"${SRCROOT}/Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests-resources.sh",
-				$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
+				"${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle",
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
-				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -1142,11 +1142,11 @@
 			);
 			inputPaths = (
 				"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet-resources.sh",
-				$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
+				"${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle",
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
-				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
+				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -1539,6 +1539,18 @@
 				INFOPLIST_FILE = CoreCronetEnd2EndTests/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 9.3;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"\"${PODS_CONFIGURATION_BUILD_DIR}/BoringSSL\"",
+					"\"${PODS_CONFIGURATION_BUILD_DIR}/Protobuf\"",
+					"\"${PODS_CONFIGURATION_BUILD_DIR}/RemoteTest\"",
+					"\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC\"",
+					"\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-Core-072e2d32\"",
+					"\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-ProtoRPC\"",
+					"\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-RxLibrary\"",
+					"\"${PODS_CONFIGURATION_BUILD_DIR}/nanopb\"",
+					"\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-Core\"",
+				);
 				PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CoreCronetEnd2EndTests;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				USER_HEADER_SEARCH_PATHS = "$(inherited) \"${PODS_ROOT}/../../../..\"";
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme
index a1da2e0..e62edd3 100644
--- a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme
+++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme
@@ -26,6 +26,7 @@
       buildConfiguration = "Debug"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      language = ""
       shouldUseLaunchSchemeArgsEnv = "YES">
       <Testables>
          <TestableReference
@@ -55,6 +56,7 @@
       buildConfiguration = "Debug"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      language = ""
       launchStyle = "0"
       useCustomWorkingDirectory = "NO"
       ignoresPersistentStateOnLaunch = "NO"
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests_Asan.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests_Asan.xcscheme
new file mode 100644
index 0000000..0a597e7
--- /dev/null
+++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests_Asan.xcscheme
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0920"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      enableAddressSanitizer = "YES"
+      enableASanStackUseAfterReturn = "YES"
+      language = ""
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
+               BuildableName = "CoreCronetEnd2EndTests.xctest"
+               BlueprintName = "CoreCronetEnd2EndTests"
+               ReferencedContainer = "container:Tests.xcodeproj">
+            </BuildableReference>
+         </TestableReference>
+      </Testables>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      language = ""
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests_Tsan.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests_Tsan.xcscheme
new file mode 100644
index 0000000..5fe60b9
--- /dev/null
+++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests_Tsan.xcscheme
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0920"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      enableThreadSanitizer = "YES"
+      language = ""
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
+               BuildableName = "CoreCronetEnd2EndTests.xctest"
+               BlueprintName = "CoreCronetEnd2EndTests"
+               ReferencedContainer = "container:Tests.xcodeproj">
+            </BuildableReference>
+         </TestableReference>
+      </Testables>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      language = ""
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/src/objective-c/tests/analyze_link_map.py b/src/objective-c/tests/analyze_link_map.py
new file mode 100755
index 0000000..48e3441
--- /dev/null
+++ b/src/objective-c/tests/analyze_link_map.py
@@ -0,0 +1,78 @@
+#!/usr/bin/python
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 script analyzes link map file generated by Xcode. It calculates and
+# prints out the sizes of each dependent library and the total sizes of the
+# symbols.
+# The script takes one parameter, which is the path to the link map file.
+
+import sys
+import re
+
+table_tag = {}
+state = "start"
+
+table_stats_symbol = {}
+table_stats_dead = {}
+section_total_size = 0
+symbol_total_size = 0
+
+
+file_import = sys.argv[1]
+lines = list(open(file_import))
+for line in lines:
+  line_stripped = line[:-1]
+  if "# Object files:" == line_stripped:
+    state = "object"
+    continue
+  elif "# Sections:" == line_stripped:
+    state = "section"
+    continue
+  elif "# Symbols:" == line_stripped:
+    state = "symbol"
+    continue
+  elif "# Dead Stripped Symbols:" == line_stripped:
+    state = "dead"
+    continue
+
+  if state == "object":
+    segs = re.search('(\[ *[0-9]*\]) (.*)', line_stripped)
+    table_tag[segs.group(1)] = segs.group(2)
+
+  if state == "section":
+    if len(line_stripped) == 0 or line_stripped[0] == '#':
+      continue
+    segs = re.search('^(.+?)\s+(.+?)\s+.*', line_stripped)
+    section_total_size += int(segs.group(2), 16)
+
+  if state == "symbol":
+    if len(line_stripped) == 0 or line_stripped[0] == '#':
+      continue
+    segs = re.search('^.+?\s+(.+?)\s+(\[.+?\]).*', line_stripped)
+    target = table_tag[segs.group(2)]
+    target_stripped = re.search('^(.*?)(\(.+?\))?$', target).group(1)
+    size = int(segs.group(1), 16)
+    if not target_stripped in table_stats_symbol:
+      table_stats_symbol[target_stripped] = 0
+    table_stats_symbol[target_stripped] += size
+
+print("Sections total size: %d" % section_total_size)
+
+for target in table_stats_symbol:
+  print(target)
+  print(table_stats_symbol[target])
+  symbol_total_size += table_stats_symbol[target]
+
+print("Symbols total size: %d" % symbol_total_size)
diff --git a/src/objective-c/tests/run_tests.sh b/src/objective-c/tests/run_tests.sh
index cec3478..2fe2326 100755
--- a/src/objective-c/tests/run_tests.sh
+++ b/src/objective-c/tests/run_tests.sh
@@ -92,6 +92,26 @@
 echo "TIME:  $(date)"
 xcodebuild \
     -workspace Tests.xcworkspace \
+    -scheme CoreCronetEnd2EndTests_Asan \
+    -destination name="iPhone 6" \
+    test \
+    | egrep -v "$XCODEBUILD_FILTER" \
+    | egrep -v '^$' \
+    | egrep -v "(GPBDictionary|GPBArray)" -
+
+echo "TIME:  $(date)"
+xcodebuild \
+    -workspace Tests.xcworkspace \
+    -scheme CoreCronetEnd2EndTests_Tsan \
+    -destination name="iPhone 6" \
+    test \
+    | egrep -v "$XCODEBUILD_FILTER" \
+    | egrep -v '^$' \
+    | egrep -v "(GPBDictionary|GPBArray)" -
+
+echo "TIME:  $(date)"
+xcodebuild \
+    -workspace Tests.xcworkspace \
     -scheme CronetUnitTests \
     -destination name="iPhone 6" \
     test \
diff --git a/src/objective-c/tests/version.h b/src/objective-c/tests/version.h
index 5140aa2..6f6cd25 100644
--- a/src/objective-c/tests/version.h
+++ b/src/objective-c/tests/version.h
@@ -23,5 +23,5 @@
 // `tools/buildgen/generate_projects.sh`.
 
 
-#define GRPC_OBJC_VERSION_STRING @"1.10.0-dev"
+#define GRPC_OBJC_VERSION_STRING @"1.11.0-dev"
 #define GRPC_C_VERSION_STRING @"6.0.0-dev"
diff --git a/src/php/composer.json b/src/php/composer.json
index ea21417..dbf0cc3 100644
--- a/src/php/composer.json
+++ b/src/php/composer.json
@@ -2,7 +2,7 @@
   "name": "grpc/grpc-dev",
   "description": "gRPC library for PHP - for Developement use only",
   "license": "Apache-2.0",
-  "version": "1.10.0",
+  "version": "1.11.0",
   "require": {
     "php": ">=5.5.0",
     "google/protobuf": "^v3.3.0"
diff --git a/src/php/ext/grpc/call_credentials.c b/src/php/ext/grpc/call_credentials.c
index 41c488a..d96dc7f 100644
--- a/src/php/ext/grpc/call_credentials.c
+++ b/src/php/ext/grpc/call_credentials.c
@@ -35,6 +35,7 @@
 
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
+#include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
 zend_class_entry *grpc_ce_call_credentials;
@@ -178,8 +179,10 @@
 
   PHP_GRPC_DELREF(arg);
 
+  gpr_log(GPR_INFO, "GRPC_PHP: call credentials plugin function - begin");
   /* call the user callback function */
   zend_call_function(state->fci, state->fci_cache TSRMLS_CC);
+  gpr_log(GPR_INFO, "GRPC_PHP: call credentials plugin function - end");
 
   *num_creds_md = 0;
   *status = GRPC_STATUS_OK;
diff --git a/src/php/ext/grpc/call_credentials.h b/src/php/ext/grpc/call_credentials.h
old mode 100755
new mode 100644
diff --git a/src/php/ext/grpc/channel.h b/src/php/ext/grpc/channel.h
old mode 100755
new mode 100644
diff --git a/src/php/ext/grpc/channel_credentials.h b/src/php/ext/grpc/channel_credentials.h
old mode 100755
new mode 100644
diff --git a/src/php/ext/grpc/server.h b/src/php/ext/grpc/server.h
old mode 100755
new mode 100644
diff --git a/src/php/ext/grpc/server_credentials.h b/src/php/ext/grpc/server_credentials.h
old mode 100755
new mode 100644
diff --git a/src/php/ext/grpc/timeval.h b/src/php/ext/grpc/timeval.h
old mode 100755
new mode 100644
diff --git a/src/php/ext/grpc/version.h b/src/php/ext/grpc/version.h
index 408f2a4..dd2a701 100644
--- a/src/php/ext/grpc/version.h
+++ b/src/php/ext/grpc/version.h
@@ -20,6 +20,6 @@
 #ifndef VERSION_H
 #define VERSION_H
 
-#define PHP_GRPC_VERSION "1.10.0dev"
+#define PHP_GRPC_VERSION "1.11.0dev"
 
 #endif /* VERSION_H */
diff --git a/tools/dockerfile/distribtest/node_ubuntu1504_x64/Dockerfile b/src/proto/grpc/channelz/BUILD
similarity index 61%
copy from tools/dockerfile/distribtest/node_ubuntu1504_x64/Dockerfile
copy to src/proto/grpc/channelz/BUILD
index 399a43a..bdb03d5 100644
--- a/tools/dockerfile/distribtest/node_ubuntu1504_x64/Dockerfile
+++ b/src/proto/grpc/channelz/BUILD
@@ -1,4 +1,4 @@
-# Copyright 2016 gRPC authors.
+# Copyright 2018 gRPC authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -12,10 +12,15 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM ubuntu:15.04
+licenses(["notice"])  # Apache v2
 
-RUN apt-get update && apt-get install -y curl
+load("//bazel:grpc_build_system.bzl", "grpc_proto_library", "grpc_package")
 
-# Install nvm
-RUN touch .profile
-RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash
\ No newline at end of file
+grpc_package(name = "channelz", visibility = "public")
+
+grpc_proto_library(
+    name = "channelz_proto",
+    srcs = ["channelz.proto"],
+    has_services = True,
+    well_known_protos = True,
+)
diff --git a/src/proto/grpc/channelz/channelz.proto b/src/proto/grpc/channelz/channelz.proto
new file mode 100644
index 0000000..14db66a
--- /dev/null
+++ b/src/proto/grpc/channelz/channelz.proto
@@ -0,0 +1,456 @@
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package grpc.channelz;
+
+import "google/protobuf/any.proto";
+import "google/protobuf/duration.proto";
+import "google/protobuf/timestamp.proto";
+import "google/protobuf/wrappers.proto";
+
+// See go/grpc-channelz.
+
+// Channel is a logical grouping of channels, subchannels, and sockets.
+message Channel {
+  // The identifier for this channel.
+  ChannelRef ref = 1;
+  // Data specific to this channel.
+  ChannelData data = 2;
+  // At most one of 'channel_ref+subchannel_ref' and 'socket' is set.
+
+  // There are no ordering guarantees on the order of channel refs.
+  // There may not be cycles in the ref graph.
+  // A channel ref may be present in more than one channel or subchannel.
+  repeated ChannelRef channel_ref = 3;
+
+  // At most one of 'channel_ref+subchannel_ref' and 'socket' is set.
+  // There are no ordering guarantees on the order of subchannel refs.
+  // There may not be cycles in the ref graph.
+  // A sub channel ref may be present in more than one channel or subchannel.
+  repeated SubchannelRef subchannel_ref = 4;
+
+  // There are no ordering guarantees on the order of sockets.
+  repeated SocketRef socket = 5;
+}
+
+// Subchannel is a logical grouping of channels, subchannels, and sockets.
+// A subchannel is load balanced over by it's ancestor
+message Subchannel {
+  // The identifier for this channel.
+  SubchannelRef ref = 1;
+  // Data specific to this channel.
+  ChannelData data = 2;
+  // At most one of 'channel_ref+subchannel_ref' and 'socket' is set.
+
+  // There are no ordering guarantees on the order of channel refs.
+  // There may not be cycles in the ref graph.
+  // A channel ref may be present in more than one channel or subchannel.
+  repeated ChannelRef channel_ref = 3;
+
+  // At most one of 'channel_ref+subchannel_ref' and 'socket' is set.
+  // There are no ordering guarantees on the order of subchannel refs.
+  // There may not be cycles in the ref graph.
+  // A sub channel ref may be present in more than one channel or subchannel.
+  repeated SubchannelRef subchannel_ref = 4;
+
+  // There are no ordering guarantees on the order of sockets.
+  repeated SocketRef socket = 5;
+}
+
+// These come from the specified states in this document:
+// https://github.com/grpc/grpc/blob/master/doc/connectivity-semantics-and-api.md
+message ChannelConnectivityState {
+  enum State {
+    UNKNOWN = 0;
+    IDLE = 1;
+    CONNECTING = 2;
+    READY = 3;
+    TRANSIENT_FAILURE = 4;
+    SHUTDOWN = 5;
+  }
+  State state = 1;
+}
+
+message ChannelData {
+
+  ChannelConnectivityState state = 1;
+
+  // The target this channel originally tried to connect to.  May be absent
+  string target = 2;
+
+  ChannelTrace trace = 3;
+
+  // The number of calls started on the channel
+  int64 calls_started = 4;
+  // The number of calls that have completed with an OK status
+  int64 calls_succeeded = 5;
+  // The number of calls that have a completed with a non-OK status
+  int64 calls_failed = 6;
+
+  // The last time a call was started on the channel.
+  google.protobuf.Timestamp last_call_started_timestamp = 7;
+}
+
+// A trace event is an interesting thing that happened to a channel or
+// subchannel, such as creation, address resolution, subchannel creation, etc.
+message ChannelTraceEvent {
+  // High level description of the event.
+  string description = 1;
+  // The supported severity levels of trace events.
+  enum Severity {
+    CT_UNKNOWN = 0;
+    CT_INFO = 1;
+    CT_WARNING = 2;
+    CT_ERROR = 3;
+  }
+  // the severity of the trace event
+  Severity severity = 2;
+  // When this event occurred.
+  google.protobuf.Timestamp timestamp = 3;
+  // ref of referenced channel or subchannel.
+  // Optional, only present if this event refers to a child object. For example,
+  // this field would be filled if this trace event was for a subchannel being
+  // created.
+  oneof child_ref {
+    ChannelRef channel_ref = 4;
+    SubchannelRef subchannel_ref = 5;
+  }
+}
+
+message ChannelTrace {
+  // Number of events ever logged in this tracing object. This can differ from
+  // events.size() because events can be overwritten or garbage collected by
+  // implementations.
+  int64 num_events_logged = 1;
+  // Time that this channel was created.
+  google.protobuf.Timestamp creation_time = 2;
+  // List of events that have occurred on this channel.
+  repeated ChannelTraceEvent events = 3;
+}
+
+message ChannelRef {
+  // The globally unique id for this channel.  Must be a positive number.
+  int64 channel_id = 1;
+  // An optional name associated with the channel.
+  string name = 2;
+  // Intentionally don't use field numbers from other refs.
+  reserved 3, 4, 5, 6;
+}
+
+message SubchannelRef {
+  // The globally unique id for this subchannel.  Must be a positive number.
+  int64 subchannel_id = 7;
+  // An optional name associated with the subchannel.
+  string name = 8;
+  // Intentionally don't use field numbers from other refs.
+  reserved 1, 2, 3, 4, 5, 6;
+}
+
+message SocketRef {
+  int64 socket_id = 3;
+  // An optional name associated with the socket.
+  string name = 4;
+  // Intentionally don't use field numbers from other refs.
+  reserved 1, 2, 5, 6, 7, 8;
+}
+
+message ServerRef {
+  // A globally unique identifier for this server.   Must be a positive number.
+  int64 server_id = 5;
+  // An optional name associated with the server.
+  string name = 6;
+  // Intentionally don't use field numbers from other refs.
+  reserved 1, 2, 3, 4, 7, 8;
+}
+
+message Server {
+  ServerRef ref = 1;
+  ServerData data = 2;
+
+  // The sockets that the server is listening on.  There are no ordering
+  // guarantees.
+  repeated SocketRef listen_socket = 3;
+}
+
+message ServerData {
+  ChannelTrace trace = 1;
+
+  // The number of incoming calls started on the server
+  int64 calls_started = 2;
+  // The number of incoming calls that have completed with an OK status
+  int64 calls_succeeded = 3;
+  // The number of incoming calls that have a completed with a non-OK status
+  int64 calls_failed = 4;
+
+  // The last time a call was started on the server.
+  google.protobuf.Timestamp last_call_started_timestamp = 5;
+}
+
+// Information about an actual connection.  Pronounced "sock-ay".
+message Socket {
+  SocketRef ref = 1;
+
+  SocketData data = 2;
+  // The locally bound address.
+  Address local = 3;
+  // The remote bound address.  May be absent.
+  Address remote = 4;
+  Security security = 5;
+
+  // Optional, represents the name of the remote endpoint, if different than
+  // the original target name.
+  string remote_name = 6;
+}
+
+message SocketData {
+  // The number of streams that have been started.
+  int64 streams_started = 1;
+  // The number of streams that have ended successfully with the EoS bit set for
+  //  both end points
+  int64 streams_succeeded = 2;
+  // The number of incoming streams that have a completed with a non-OK status
+  int64 streams_failed = 3;
+
+  // The number of messages successfully sent on this socket.
+  int64 messages_sent = 4;
+  int64 messages_received = 5;
+
+  // The number of keep alives sent.  This is typically implemented with HTTP/2
+  // ping messages.
+  int64 keep_alives_sent = 6;
+
+  // The last time a stream was created by this endpoint.  Usually unset for
+  // servers.
+  google.protobuf.Timestamp last_local_stream_created_timestamp = 7;
+  // The last time a stream was created by the remote endpoint.  Usually unset
+  // for clients.
+  google.protobuf.Timestamp last_remote_stream_created_timestamp = 8;
+
+  // The last time a message was sent by this endpoint.
+  google.protobuf.Timestamp last_message_sent_timestamp = 9;
+  // The last time a message was received by this endpoint.
+  google.protobuf.Timestamp last_message_received_timestamp = 10;
+
+  // The amount of window, granted to the local endpoint by the remote endpoint.
+  // This may be slightly out of date due to network latency.  This does NOT
+  // include stream level or TCP level flow control info.
+  google.protobuf.Int64Value local_flow_control_window = 11;
+
+  // The amount of window, granted to the remote endpoint by the local endpoint.
+  // This may be slightly out of date due to network latency.  This does NOT
+  // include stream level or TCP level flow control info.
+  google.protobuf.Int64Value  remote_flow_control_window = 12;
+
+  repeated SocketOption option = 13;
+}
+
+message Address {
+  message TcpIpAddress {
+    // Either the IPv4 or IPv6 address in bytes.  Will either be 4 bytes or 16
+    // bytes in length.
+    bytes ip_address = 1;
+    // 0-64k, or -1 if not appropriate.
+    int32 port = 2;
+  }
+  // A Unix Domain Socket address.
+  message UdsAddress {
+    string filename = 1;
+  }
+  // An address type not included above.
+  message OtherAddress {
+    // The human readable version of the value.
+    string name = 1;
+    // The actual address message.
+    google.protobuf.Any value = 2;
+  }
+
+  oneof address {
+    TcpIpAddress tcpip_address = 1;
+    UdsAddress uds_address = 2;
+    OtherAddress other_address = 3;
+  }
+}
+
+message Security {
+  message Tls {
+    // The key exchange used.  e.g. X25519
+    string key_exchange = 1;
+    // The cipher used. e.g. AES_128_GCM.
+    string cipher = 2;
+    // the certificate used by this endpoint.
+    bytes local_certificate = 3;
+    // the certificate used by the remote endpoint.
+    bytes remote_certificate = 4;
+  }
+  message OtherSecurity {
+    // The human readable version of the value.
+    string name = 1;
+    // The actual security details message.
+    google.protobuf.Any value = 2;
+  }
+  oneof model {
+    Tls tls = 1;
+    OtherSecurity other = 2;
+  }
+}
+
+message SocketOption {
+  string name = 1;
+  // The human readable value of this socket option.  At least one of value or
+  // additional will be set.
+  string value = 2;
+  // Additional data associated with the socket option.  At least one of value
+  // or additional will be set.
+  google.protobuf.Any additional = 3;
+}
+
+// For use with SocketOption's additional field.  This is primarily used for
+// SO_RCVTIMEO and SO_SNDTIMEO
+message SocketOptionTimeout {
+  google.protobuf.Duration duration = 1;
+}
+
+message SocketOptionLinger {
+  bool active = 1;
+  google.protobuf.Duration duration = 2;
+}
+
+// Tcp info for SOL_TCP, TCP_INFO
+message SocketOptionTcpInfo {
+  uint32 tcpi_state = 1;
+
+  uint32 tcpi_ca_state = 2;
+  uint32 tcpi_retransmits = 3;
+  uint32 tcpi_probes = 4;
+  uint32 tcpi_backoff = 5;
+  uint32 tcpi_options = 6;
+  uint32 tcpi_snd_wscale = 7;
+  uint32 tcpi_rcv_wscale = 8;
+
+  uint32 tcpi_rto = 9;
+  uint32 tcpi_ato = 10;
+  uint32 tcpi_snd_mss = 11;
+  uint32 tcpi_rcv_mss = 12;
+
+  uint32 tcpi_unacked = 13;
+  uint32 tcpi_sacked = 14;
+  uint32 tcpi_lost = 15;
+  uint32 tcpi_retrans = 16;
+  uint32 tcpi_fackets = 17;
+
+  uint32 tcpi_last_data_sent = 18;
+  uint32 tcpi_last_ack_sent = 19;
+  uint32 tcpi_last_data_recv = 20;
+  uint32 tcpi_last_ack_recv = 21;
+
+  uint32 tcpi_pmtu = 22;
+  uint32 tcpi_rcv_ssthresh = 23;
+  uint32 tcpi_rtt = 24;
+  uint32 tcpi_rttvar = 25;
+  uint32 tcpi_snd_ssthresh = 26;
+  uint32 tcpi_snd_cwnd = 27;
+  uint32 tcpi_advmss = 28;
+  uint32 tcpi_reordering = 29;
+}
+
+service Channelz {
+  // Gets all root channels (e.g. channels the application has directly
+  // created). This does not include subchannels nor non-top level channels.
+  rpc GetTopChannels(GetTopChannelsRequest) returns (GetTopChannelsResponse);
+  // Gets all servers that exist in the process.
+  rpc GetServers(GetServersRequest) returns (GetServersResponse);
+  // Gets all server sockets that exist in the process.
+  rpc GetServerSockets(GetServerSocketsRequest) returns (GetServerSocketsResponse);
+  // Returns a single Channel, or else a NOT_FOUND code.
+  rpc GetChannel(GetChannelRequest) returns (GetChannelResponse);
+  // Returns a single Subchannel, or else a NOT_FOUND code.
+  rpc GetSubchannel(GetSubchannelRequest) returns (GetSubchannelResponse);
+  // Returns a single Socket or else a NOT_FOUND code.
+  rpc GetSocket(GetSocketRequest) returns (GetSocketResponse);
+}
+
+message GetServersRequest {
+  // start_server_id indicates that only servers at or above this id should be
+  // included in the results.
+  int64 start_server_id = 1;
+}
+
+message GetServersResponse {
+  // list of servers that the connection detail service knows about.  Sorted in
+  // ascending server_id order.
+  repeated Server server = 1;
+  // If set, indicates that the list of servers is the final list.  Requesting
+  // more servers will only return more if they are created after this RPC
+  // completes.
+  bool end = 2;
+}
+
+message GetServerSocketsRequest {
+  int64 server_id = 1;
+  // start_socket_id indicates that only sockets at or above this id should be
+  // included in the results.
+  int64 start_socket_id = 2;
+}
+
+message GetServerSocketsResponse {
+  // list of socket refs that the connection detail service knows about.  Sorted in
+  // ascending socket_id order.
+  repeated SocketRef socket_ref = 1;
+  // If set, indicates that the list of sockets is the final list.  Requesting
+  // more sockets will only return more if they are created after this RPC
+  // completes.
+  bool end = 2;
+}
+
+message GetTopChannelsRequest {
+  // start_channel_id indicates that only channels at or above this id should be
+  // included in the results.
+  int64 start_channel_id = 1;
+}
+
+message GetTopChannelsResponse {
+  // list of channels that the connection detail service knows about.  Sorted in
+  // ascending channel_id order.
+  repeated Channel channel = 1;
+  // If set, indicates that the list of channels is the final list.  Requesting
+  // more channels can only return more if they are created after this RPC
+  // completes.
+  bool end = 2;
+}
+
+message GetChannelRequest {
+  int64 channel_id = 1;
+}
+
+message GetChannelResponse {
+  Channel channel = 1;
+}
+
+message GetSubchannelRequest {
+  int64 subchannel_id = 1;
+}
+
+message GetSubchannelResponse {
+  Subchannel subchannel = 1;
+}
+
+message GetSocketRequest {
+  int64 socket_id = 1;
+}
+
+message GetSocketResponse {
+  Socket socket = 1;
+}
diff --git a/src/proto/grpc/testing/BUILD b/src/proto/grpc/testing/BUILD
index b8e9a22..58412ed 100644
--- a/src/proto/grpc/testing/BUILD
+++ b/src/proto/grpc/testing/BUILD
@@ -26,7 +26,7 @@
 grpc_proto_library(
     name = "compiler_test_proto",
     srcs = ["compiler_test.proto"],
-    generate_mock = True,
+    generate_mocks = True,
 )
 
 grpc_proto_library(
@@ -49,7 +49,7 @@
     name = "echo_proto",
     srcs = ["echo.proto"],
     deps = ["echo_messages_proto"],
-    generate_mock = True,
+    generate_mocks = True,
 )
 
 grpc_proto_library(
diff --git a/src/python/grpcio/grpc/__init__.py b/src/python/grpcio/grpc/__init__.py
index 79793a7..7fa7303 100644
--- a/src/python/grpcio/grpc/__init__.py
+++ b/src/python/grpcio/grpc/__init__.py
@@ -173,7 +173,8 @@
         """Adds a function to be called at completion of the computation.
 
         The callback will be passed this Future object describing the outcome
-        of the computation.
+        of the computation.  Callbacks will be invoked after the future is
+        terimated, whether successfully or not.
 
         If the computation has already completed, the callback will be called
         immediately.
diff --git a/src/python/grpcio/grpc/_channel.py b/src/python/grpcio/grpc/_channel.py
index 25a4210..2eff08a 100644
--- a/src/python/grpcio/grpc/_channel.py
+++ b/src/python/grpcio/grpc/_channel.py
@@ -906,11 +906,6 @@
         self._call_state = _ChannelCallState(self._channel)
         self._connectivity_state = _ChannelConnectivityState(self._channel)
 
-        # TODO(https://github.com/grpc/grpc/issues/9884)
-        # Temporary work around UNAVAILABLE issues
-        # Remove this once c-core has retry support
-        _subscribe(self._connectivity_state, lambda *args: None, None)
-
     def subscribe(self, callback, try_to_connect=None):
         _subscribe(self._connectivity_state, callback, try_to_connect)
 
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
index 0892215..2e02111 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
@@ -30,9 +30,12 @@
         tag, operations, self if retain_self else None)
     batch_operation_tag.prepare()
     cpython.Py_INCREF(batch_operation_tag)
-    return grpc_call_start_batch(
+    cdef grpc_call_error error
+    with nogil:
+      error = grpc_call_start_batch(
           self.c_call, batch_operation_tag.c_ops, batch_operation_tag.c_nops,
           <cpython.PyObject *>batch_operation_tag, NULL)
+    return error
 
   def start_client_batch(self, operations, tag):
     # We don't reference this call in the operations tag because
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
index 30253fc..a4c0319 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
@@ -557,8 +557,8 @@
 
   ctypedef enum grpc_compression_algorithm:
     GRPC_COMPRESS_NONE
-    GRPC_COMPRESS_MESSAGE_DEFLATE
-    GRPC_COMPRESS_MESSAGE_GZIP
+    GRPC_COMPRESS_DEFLATE
+    GRPC_COMPRESS_GZIP
     GRPC_COMPRESS_STREAM_GZIP
     GRPC_COMPRESS_ALGORITHMS_COUNT
 
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
index 1bcea8d..ecd9916 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
@@ -112,8 +112,8 @@
 
 class CompressionAlgorithm:
   none = GRPC_COMPRESS_NONE
-  deflate = GRPC_COMPRESS_MESSAGE_DEFLATE
-  gzip = GRPC_COMPRESS_MESSAGE_GZIP
+  deflate = GRPC_COMPRESS_DEFLATE
+  gzip = GRPC_COMPRESS_GZIP
 
 
 class CompressionLevel:
diff --git a/src/python/grpcio/grpc/_grpcio_metadata.py b/src/python/grpcio/grpc/_grpcio_metadata.py
index 6032828..4a69d85 100644
--- a/src/python/grpcio/grpc/_grpcio_metadata.py
+++ b/src/python/grpcio/grpc/_grpcio_metadata.py
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc/_grpcio_metadata.py.template`!!!
 
-__version__ = """1.10.0.dev0"""
+__version__ = """1.11.0.dev0"""
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 83dd5df..9f4aaff 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -15,11 +15,12 @@
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_core_dependencies.py.template`!!!
 
 CORE_SOURCE_FILES = [
+    'third_party/address_sorting/address_sorting.c',
+    'third_party/address_sorting/address_sorting_posix.c',
+    'third_party/address_sorting/address_sorting_windows.c',
     'src/core/lib/gpr/alloc.cc',
     'src/core/lib/gpr/arena.cc',
     'src/core/lib/gpr/atm.cc',
-    'src/core/lib/gpr/avl.cc',
-    'src/core/lib/gpr/cmdline.cc',
     'src/core/lib/gpr/cpu_iphone.cc',
     'src/core/lib/gpr/cpu_linux.cc',
     'src/core/lib/gpr/cpu_posix.cc',
@@ -40,14 +41,9 @@
     'src/core/lib/gpr/string_posix.cc',
     'src/core/lib/gpr/string_util_windows.cc',
     'src/core/lib/gpr/string_windows.cc',
-    'src/core/lib/gpr/subprocess_posix.cc',
-    'src/core/lib/gpr/subprocess_windows.cc',
     'src/core/lib/gpr/sync.cc',
     'src/core/lib/gpr/sync_posix.cc',
     'src/core/lib/gpr/sync_windows.cc',
-    'src/core/lib/gpr/thd.cc',
-    'src/core/lib/gpr/thd_posix.cc',
-    'src/core/lib/gpr/thd_windows.cc',
     'src/core/lib/gpr/time.cc',
     'src/core/lib/gpr/time_posix.cc',
     'src/core/lib/gpr/time_precise.cc',
@@ -57,20 +53,25 @@
     'src/core/lib/gpr/tmpfile_posix.cc',
     'src/core/lib/gpr/tmpfile_windows.cc',
     'src/core/lib/gpr/wrap_memcpy.cc',
+    'src/core/lib/gprpp/thd_posix.cc',
+    'src/core/lib/gprpp/thd_windows.cc',
     'src/core/lib/profiling/basic_timers.cc',
     'src/core/lib/profiling/stap_timers.cc',
     'src/core/lib/surface/init.cc',
+    'src/core/lib/avl/avl.cc',
     'src/core/lib/backoff/backoff.cc',
     'src/core/lib/channel/channel_args.cc',
     'src/core/lib/channel/channel_stack.cc',
     'src/core/lib/channel/channel_stack_builder.cc',
+    'src/core/lib/channel/channel_trace.cc',
+    'src/core/lib/channel/channel_trace_registry.cc',
     'src/core/lib/channel/connected_channel.cc',
     'src/core/lib/channel/handshaker.cc',
     'src/core/lib/channel/handshaker_factory.cc',
     'src/core/lib/channel/handshaker_registry.cc',
+    'src/core/lib/channel/status_util.cc',
     'src/core/lib/compression/compression.cc',
     'src/core/lib/compression/compression_internal.cc',
-    'src/core/lib/compression/compression_ruby.cc',
     'src/core/lib/compression/message_compress.cc',
     'src/core/lib/compression/stream_compression.cc',
     'src/core/lib/compression/stream_compression_gzip.cc',
@@ -102,6 +103,8 @@
     'src/core/lib/iomgr/gethostname_sysconf.cc',
     'src/core/lib/iomgr/iocp_windows.cc',
     'src/core/lib/iomgr/iomgr.cc',
+    'src/core/lib/iomgr/iomgr_custom.cc',
+    'src/core/lib/iomgr/iomgr_internal.cc',
     'src/core/lib/iomgr/iomgr_posix.cc',
     'src/core/lib/iomgr/iomgr_uv.cc',
     'src/core/lib/iomgr/iomgr_windows.cc',
@@ -110,12 +113,16 @@
     'src/core/lib/iomgr/lockfree_event.cc',
     'src/core/lib/iomgr/network_status_tracker.cc',
     'src/core/lib/iomgr/polling_entity.cc',
-    'src/core/lib/iomgr/pollset_set_uv.cc',
+    'src/core/lib/iomgr/pollset.cc',
+    'src/core/lib/iomgr/pollset_custom.cc',
+    'src/core/lib/iomgr/pollset_set.cc',
+    'src/core/lib/iomgr/pollset_set_custom.cc',
     'src/core/lib/iomgr/pollset_set_windows.cc',
     'src/core/lib/iomgr/pollset_uv.cc',
     'src/core/lib/iomgr/pollset_windows.cc',
+    'src/core/lib/iomgr/resolve_address.cc',
+    'src/core/lib/iomgr/resolve_address_custom.cc',
     'src/core/lib/iomgr/resolve_address_posix.cc',
-    'src/core/lib/iomgr/resolve_address_uv.cc',
     'src/core/lib/iomgr/resolve_address_windows.cc',
     'src/core/lib/iomgr/resource_quota.cc',
     'src/core/lib/iomgr/sockaddr_utils.cc',
@@ -127,19 +134,24 @@
     'src/core/lib/iomgr/socket_utils_uv.cc',
     'src/core/lib/iomgr/socket_utils_windows.cc',
     'src/core/lib/iomgr/socket_windows.cc',
+    'src/core/lib/iomgr/tcp_client.cc',
+    'src/core/lib/iomgr/tcp_client_custom.cc',
     'src/core/lib/iomgr/tcp_client_posix.cc',
-    'src/core/lib/iomgr/tcp_client_uv.cc',
     'src/core/lib/iomgr/tcp_client_windows.cc',
+    'src/core/lib/iomgr/tcp_custom.cc',
     'src/core/lib/iomgr/tcp_posix.cc',
+    'src/core/lib/iomgr/tcp_server.cc',
+    'src/core/lib/iomgr/tcp_server_custom.cc',
     'src/core/lib/iomgr/tcp_server_posix.cc',
     'src/core/lib/iomgr/tcp_server_utils_posix_common.cc',
     'src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc',
     'src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc',
-    'src/core/lib/iomgr/tcp_server_uv.cc',
     'src/core/lib/iomgr/tcp_server_windows.cc',
     'src/core/lib/iomgr/tcp_uv.cc',
     'src/core/lib/iomgr/tcp_windows.cc',
     'src/core/lib/iomgr/time_averaged_stats.cc',
+    'src/core/lib/iomgr/timer.cc',
+    'src/core/lib/iomgr/timer_custom.cc',
     'src/core/lib/iomgr/timer_generic.cc',
     'src/core/lib/iomgr/timer_heap.cc',
     'src/core/lib/iomgr/timer_manager.cc',
@@ -160,7 +172,6 @@
     'src/core/lib/slice/percent_encoding.cc',
     'src/core/lib/slice/slice.cc',
     'src/core/lib/slice/slice_buffer.cc',
-    'src/core/lib/slice/slice_hash_table.cc',
     'src/core/lib/slice/slice_intern.cc',
     'src/core/lib/slice/slice_string_helpers.cc',
     'src/core/lib/surface/api_trace.cc',
@@ -191,6 +202,7 @@
     'src/core/lib/transport/service_config.cc',
     'src/core/lib/transport/static_metadata.cc',
     'src/core/lib/transport/status_conversion.cc',
+    'src/core/lib/transport/status_metadata.cc',
     'src/core/lib/transport/timeout_encoding.cc',
     'src/core/lib/transport/transport.cc',
     'src/core/lib/transport/transport_op_string.cc',
@@ -225,6 +237,7 @@
     'src/core/ext/filters/http/server/http_server_filter.cc',
     'src/core/lib/http/httpcli_security_connector.cc',
     'src/core/lib/security/context/security_context.cc',
+    'src/core/lib/security/credentials/alts/alts_credentials.cc',
     'src/core/lib/security/credentials/composite/composite_credentials.cc',
     'src/core/lib/security/credentials/credentials.cc',
     'src/core/lib/security/credentials/credentials_metadata.cc',
@@ -238,23 +251,55 @@
     'src/core/lib/security/credentials/oauth2/oauth2_credentials.cc',
     'src/core/lib/security/credentials/plugin/plugin_credentials.cc',
     'src/core/lib/security/credentials/ssl/ssl_credentials.cc',
+    'src/core/lib/security/security_connector/alts_security_connector.cc',
+    'src/core/lib/security/security_connector/security_connector.cc',
     'src/core/lib/security/transport/client_auth_filter.cc',
-    'src/core/lib/security/transport/lb_targets_info.cc',
     'src/core/lib/security/transport/secure_endpoint.cc',
-    'src/core/lib/security/transport/security_connector.cc',
     'src/core/lib/security/transport/security_handshaker.cc',
     'src/core/lib/security/transport/server_auth_filter.cc',
+    'src/core/lib/security/transport/target_authority_table.cc',
     'src/core/lib/security/transport/tsi_error.cc',
     'src/core/lib/security/util/json_util.cc',
     'src/core/lib/surface/init_secure.cc',
-    'src/core/tsi/alts_transport_security.cc',
-    'src/core/tsi/fake_transport_security.cc',
-    'src/core/tsi/ssl_transport_security.cc',
-    'src/core/tsi/transport_security_grpc.cc',
+    'src/core/tsi/alts/crypt/aes_gcm.cc',
+    'src/core/tsi/alts/crypt/gsec.cc',
+    'src/core/tsi/alts/frame_protector/alts_counter.cc',
+    'src/core/tsi/alts/frame_protector/alts_crypter.cc',
+    'src/core/tsi/alts/frame_protector/alts_frame_protector.cc',
+    'src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc',
+    'src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc',
+    'src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc',
+    'src/core/tsi/alts/frame_protector/frame_handler.cc',
+    'src/core/tsi/alts/handshaker/alts_handshaker_client.cc',
+    'src/core/tsi/alts/handshaker/alts_tsi_event.cc',
+    'src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc',
+    'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc',
+    'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc',
+    'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc',
+    'src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc',
+    'src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc',
+    'src/core/lib/security/credentials/alts/check_gcp_environment.cc',
+    'src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc',
+    'src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc',
+    'src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc',
+    'src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc',
+    'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc',
+    'src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc',
+    'src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc',
+    'src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc',
+    'src/core/tsi/alts/handshaker/alts_tsi_utils.cc',
+    'src/core/tsi/alts/handshaker/transport_security_common_api.cc',
+    'src/core/tsi/alts/handshaker/altscontext.pb.c',
+    'src/core/tsi/alts/handshaker/handshaker.pb.c',
+    'src/core/tsi/alts/handshaker/transport_security_common.pb.c',
+    'third_party/nanopb/pb_common.c',
+    'third_party/nanopb/pb_decode.c',
+    'third_party/nanopb/pb_encode.c',
     'src/core/tsi/transport_security.cc',
     'src/core/tsi/transport_security_adapter.cc',
-    'src/core/ext/transport/chttp2/server/chttp2_server.cc',
-    'src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc',
+    'src/core/ext/transport/chttp2/client/insecure/channel_create.cc',
+    'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc',
+    'src/core/ext/transport/chttp2/client/chttp2_connector.cc',
     'src/core/ext/filters/client_channel/backup_poller.cc',
     'src/core/ext/filters/client_channel/channel_connectivity.cc',
     'src/core/ext/filters/client_channel/client_channel.cc',
@@ -266,22 +311,28 @@
     'src/core/ext/filters/client_channel/lb_policy.cc',
     'src/core/ext/filters/client_channel/lb_policy_factory.cc',
     'src/core/ext/filters/client_channel/lb_policy_registry.cc',
+    'src/core/ext/filters/client_channel/method_params.cc',
     'src/core/ext/filters/client_channel/parse_address.cc',
     'src/core/ext/filters/client_channel/proxy_mapper.cc',
     'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
     'src/core/ext/filters/client_channel/resolver.cc',
-    'src/core/ext/filters/client_channel/resolver_factory.cc',
     'src/core/ext/filters/client_channel/resolver_registry.cc',
     'src/core/ext/filters/client_channel/retry_throttle.cc',
     'src/core/ext/filters/client_channel/subchannel.cc',
     'src/core/ext/filters/client_channel/subchannel_index.cc',
     'src/core/ext/filters/client_channel/uri_parser.cc',
     'src/core/ext/filters/deadline/deadline_filter.cc',
-    'src/core/ext/transport/chttp2/client/chttp2_connector.cc',
+    'src/core/tsi/alts_transport_security.cc',
+    'src/core/tsi/fake_transport_security.cc',
+    'src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc',
+    'src/core/tsi/ssl/session_cache/ssl_session_cache.cc',
+    'src/core/tsi/ssl/session_cache/ssl_session_openssl.cc',
+    'src/core/tsi/ssl_transport_security.cc',
+    'src/core/tsi/transport_security_grpc.cc',
+    'src/core/ext/transport/chttp2/server/chttp2_server.cc',
+    'src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc',
     'src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc',
     'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc',
-    'src/core/ext/transport/chttp2/client/insecure/channel_create.cc',
-    'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc',
     'src/core/ext/transport/inproc/inproc_plugin.cc',
     'src/core/ext/transport/inproc/inproc_transport.cc',
     'src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc',
@@ -290,9 +341,6 @@
     'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc',
     'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc',
     'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
-    'third_party/nanopb/pb_common.c',
-    'third_party/nanopb/pb_decode.c',
-    'third_party/nanopb/pb_encode.c',
     'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
     'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
     'src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc',
@@ -380,7 +428,6 @@
     'third_party/boringssl/crypto/cpu-intel.c',
     'third_party/boringssl/crypto/cpu-ppc64le.c',
     'third_party/boringssl/crypto/crypto.c',
-    'third_party/boringssl/crypto/curve25519/curve25519.c',
     'third_party/boringssl/crypto/curve25519/spake25519.c',
     'third_party/boringssl/crypto/curve25519/x25519-x86_64.c',
     'third_party/boringssl/crypto/dh/check.c',
@@ -566,6 +613,7 @@
     'third_party/boringssl/ssl/tls13_server.cc',
     'third_party/boringssl/ssl/tls_method.cc',
     'third_party/boringssl/ssl/tls_record.cc',
+    'third_party/boringssl/third_party/fiat/curve25519.c',
     'third_party/zlib/adler32.c',
     'third_party/zlib/compress.c',
     'third_party/zlib/crc32.c',
diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py
index a654eb0..32e8249 100644
--- a/src/python/grpcio/grpc_version.py
+++ b/src/python/grpcio/grpc_version.py
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
 
-VERSION = '1.10.0.dev0'
+VERSION = '1.11.0.dev0'
diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py
index d3185c6..ad4c85c 100644
--- a/src/python/grpcio_health_checking/grpc_version.py
+++ b/src/python/grpcio_health_checking/grpc_version.py
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!!
 
-VERSION = '1.10.0.dev0'
+VERSION = '1.11.0.dev0'
diff --git a/src/python/grpcio_reflection/README.rst b/src/python/grpcio_reflection/README.rst
new file mode 100644
index 0000000..da99a44
--- /dev/null
+++ b/src/python/grpcio_reflection/README.rst
@@ -0,0 +1,10 @@
+gRPC Python Reflection package
+==============================
+
+Reference package for reflection in GRPC Python.
+
+Dependencies
+------------
+
+Depends on the `grpcio` package, available from PyPI via `pip install grpcio`.
+
diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py
index 7203d0d..6322d84 100644
--- a/src/python/grpcio_reflection/grpc_version.py
+++ b/src/python/grpcio_reflection/grpc_version.py
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!!
 
-VERSION = '1.10.0.dev0'
+VERSION = '1.11.0.dev0'
diff --git a/src/python/grpcio_testing/grpc_version.py b/src/python/grpcio_testing/grpc_version.py
index bf9e55e..1e75fea 100644
--- a/src/python/grpcio_testing/grpc_version.py
+++ b/src/python/grpcio_testing/grpc_version.py
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_testing/grpc_version.py.template`!!!
 
-VERSION = '1.10.0.dev0'
+VERSION = '1.11.0.dev0'
diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py
index 2583e42..0cd7bd2 100644
--- a/src/python/grpcio_tests/grpc_version.py
+++ b/src/python/grpcio_tests/grpc_version.py
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!!
 
-VERSION = '1.10.0.dev0'
+VERSION = '1.11.0.dev0'
diff --git a/src/python/grpcio_tests/tests/tests.json b/src/python/grpcio_tests/tests/tests.json
index e033c10..d38ee51 100644
--- a/src/python/grpcio_tests/tests/tests.json
+++ b/src/python/grpcio_tests/tests/tests.json
@@ -56,12 +56,6 @@
   "unit.beta._beta_features_test.BetaFeaturesTest",
   "unit.beta._beta_features_test.ContextManagementAndLifecycleTest",
   "unit.beta._connectivity_channel_test.ConnectivityStatesTest",
-  "unit.beta._face_interface_test.DynamicInvokerBlockingInvocationInlineServiceTest",
-  "unit.beta._face_interface_test.DynamicInvokerFutureInvocationAsynchronousEventServiceTest",
-  "unit.beta._face_interface_test.GenericInvokerBlockingInvocationInlineServiceTest",
-  "unit.beta._face_interface_test.GenericInvokerFutureInvocationAsynchronousEventServiceTest",
-  "unit.beta._face_interface_test.MultiCallableInvokerBlockingInvocationInlineServiceTest",
-  "unit.beta._face_interface_test.MultiCallableInvokerFutureInvocationAsynchronousEventServiceTest",
   "unit.beta._implementations_test.CallCredentialsTest",
   "unit.beta._implementations_test.ChannelCredentialsTest",
   "unit.beta._not_found_test.NotFoundTest",
diff --git a/src/python/grpcio_tests/tests/unit/_auth_context_test.py b/src/python/grpcio_tests/tests/unit/_auth_context_test.py
index 468869a..8c1a30e 100644
--- a/src/python/grpcio_tests/tests/unit/_auth_context_test.py
+++ b/src/python/grpcio_tests/tests/unit/_auth_context_test.py
@@ -102,7 +102,8 @@
         self.assertIsNone(auth_data[_ID])
         self.assertIsNone(auth_data[_ID_KEY])
         self.assertDictEqual({
-            'transport_security_type': [b'ssl']
+            'transport_security_type': [b'ssl'],
+            'ssl_session_reused': [b'false'],
         }, auth_data[_AUTH_CTX])
 
     def testSecureClientCert(self):
diff --git a/src/python/grpcio_tests/tests/unit/_reconnect_test.py b/src/python/grpcio_tests/tests/unit/_reconnect_test.py
index 10aee9f..a708d8d 100644
--- a/src/python/grpcio_tests/tests/unit/_reconnect_test.py
+++ b/src/python/grpcio_tests/tests/unit/_reconnect_test.py
@@ -14,6 +14,7 @@
 """Tests that a channel will reconnect if a connection is dropped"""
 
 import socket
+import time
 import unittest
 
 import grpc
@@ -88,6 +89,10 @@
         multi_callable = channel.unary_unary(_UNARY_UNARY)
         self.assertEqual(_RESPONSE, multi_callable(_REQUEST))
         server.stop(None)
+        # By default, the channel connectivity is checked every 5s
+        # GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS can be set to change
+        # this.
+        time.sleep(5.1)
         server = grpc.server(server_pool, (handler,))
         server.add_insecure_port('[::]:{}'.format(port))
         server.start()
diff --git a/src/python/grpcio_tests/tests/unit/beta/_face_interface_test.py b/src/python/grpcio_tests/tests/unit/beta/_face_interface_test.py
deleted file mode 100644
index c99738e..0000000
--- a/src/python/grpcio_tests/tests/unit/beta/_face_interface_test.py
+++ /dev/null
@@ -1,132 +0,0 @@
-# Copyright 2015 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT 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 Face interface compliance of the gRPC Python Beta API."""
-
-import collections
-import unittest
-
-import six
-
-from grpc.beta import implementations
-from grpc.beta import interfaces
-from tests.unit import resources
-from tests.unit import test_common as grpc_test_common
-from tests.unit.beta import test_utilities
-from tests.unit.framework.common import test_constants
-from tests.unit.framework.interfaces.face import test_cases
-from tests.unit.framework.interfaces.face import test_interfaces
-
-_SERVER_HOST_OVERRIDE = 'foo.test.google.fr'
-
-
-class _SerializationBehaviors(
-        collections.namedtuple('_SerializationBehaviors', (
-            'request_serializers',
-            'request_deserializers',
-            'response_serializers',
-            'response_deserializers',
-        ))):
-    pass
-
-
-def _serialization_behaviors_from_test_methods(test_methods):
-    request_serializers = {}
-    request_deserializers = {}
-    response_serializers = {}
-    response_deserializers = {}
-    for (group, method), test_method in six.iteritems(test_methods):
-        request_serializers[group, method] = test_method.serialize_request
-        request_deserializers[group, method] = test_method.deserialize_request
-        response_serializers[group, method] = test_method.serialize_response
-        response_deserializers[group, method] = test_method.deserialize_response
-    return _SerializationBehaviors(request_serializers, request_deserializers,
-                                   response_serializers, response_deserializers)
-
-
-class _Implementation(test_interfaces.Implementation):
-
-    def instantiate(self, methods, method_implementations,
-                    multi_method_implementation):
-        serialization_behaviors = _serialization_behaviors_from_test_methods(
-            methods)
-        # TODO(nathaniel): Add a "groups" attribute to _digest.TestServiceDigest.
-        service = next(iter(methods))[0]
-        # TODO(nathaniel): Add a "cardinalities_by_group" attribute to
-        # _digest.TestServiceDigest.
-        cardinalities = {
-            method: method_object.cardinality()
-            for (group, method), method_object in six.iteritems(methods)
-        }
-
-        server_options = implementations.server_options(
-            request_deserializers=serialization_behaviors.request_deserializers,
-            response_serializers=serialization_behaviors.response_serializers,
-            thread_pool_size=test_constants.POOL_SIZE)
-        server = implementations.server(
-            method_implementations, options=server_options)
-        server_credentials = implementations.ssl_server_credentials([
-            (
-                resources.private_key(),
-                resources.certificate_chain(),
-            ),
-        ])
-        port = server.add_secure_port('[::]:0', server_credentials)
-        server.start()
-        channel_credentials = implementations.ssl_channel_credentials(
-            resources.test_root_certificates())
-        channel = test_utilities.not_really_secure_channel(
-            'localhost', port, channel_credentials, _SERVER_HOST_OVERRIDE)
-        stub_options = implementations.stub_options(
-            request_serializers=serialization_behaviors.request_serializers,
-            response_deserializers=serialization_behaviors.
-            response_deserializers,
-            thread_pool_size=test_constants.POOL_SIZE)
-        generic_stub = implementations.generic_stub(
-            channel, options=stub_options)
-        dynamic_stub = implementations.dynamic_stub(
-            channel, service, cardinalities, options=stub_options)
-        return generic_stub, {service: dynamic_stub}, server
-
-    def destantiate(self, memo):
-        memo.stop(test_constants.SHORT_TIMEOUT).wait()
-
-    def invocation_metadata(self):
-        return grpc_test_common.INVOCATION_INITIAL_METADATA
-
-    def initial_metadata(self):
-        return grpc_test_common.SERVICE_INITIAL_METADATA
-
-    def terminal_metadata(self):
-        return grpc_test_common.SERVICE_TERMINAL_METADATA
-
-    def code(self):
-        return interfaces.StatusCode.OK
-
-    def details(self):
-        return grpc_test_common.DETAILS
-
-    def metadata_transmitted(self, original_metadata, transmitted_metadata):
-        return original_metadata is None or grpc_test_common.metadata_transmitted(
-            original_metadata, transmitted_metadata)
-
-
-def load_tests(loader, tests, pattern):
-    return unittest.TestSuite(
-        tests=tuple(
-            loader.loadTestsFromTestCase(test_case_class)
-            for test_case_class in test_cases.test_cases(_Implementation())))
-
-
-if __name__ == '__main__':
-    unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/framework/interfaces/face/__init__.py b/src/python/grpcio_tests/tests/unit/framework/interfaces/face/__init__.py
deleted file mode 100644
index 5fb4f3c..0000000
--- a/src/python/grpcio_tests/tests/unit/framework/interfaces/face/__init__.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2015 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
diff --git a/src/python/grpcio_tests/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py b/src/python/grpcio_tests/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py
deleted file mode 100644
index 5d8679a..0000000
--- a/src/python/grpcio_tests/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py
+++ /dev/null
@@ -1,287 +0,0 @@
-# Copyright 2015 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Test code for the Face layer of RPC Framework."""
-
-from __future__ import division
-
-import abc
-import itertools
-import unittest
-from concurrent import futures
-
-import six
-
-# test_interfaces is referenced from specification in this module.
-from grpc.framework.foundation import logging_pool
-from grpc.framework.interfaces.face import face
-from tests.unit.framework.common import test_constants
-from tests.unit.framework.common import test_control
-from tests.unit.framework.common import test_coverage
-from tests.unit.framework.interfaces.face import _3069_test_constant
-from tests.unit.framework.interfaces.face import _digest
-from tests.unit.framework.interfaces.face import _stock_service
-from tests.unit.framework.interfaces.face import test_interfaces  # pylint: disable=unused-import
-
-
-class TestCase(
-        six.with_metaclass(abc.ABCMeta, test_coverage.Coverage,
-                           unittest.TestCase)):
-    """A test of the Face layer of RPC Framework.
-
-  Concrete subclasses must have an "implementation" attribute of type
-  test_interfaces.Implementation and an "invoker_constructor" attribute of type
-  _invocation.InvokerConstructor.
-  """
-
-    NAME = 'BlockingInvocationInlineServiceTest'
-
-    def setUp(self):
-        """See unittest.TestCase.setUp for full specification.
-
-    Overriding implementations must call this implementation.
-    """
-        self._control = test_control.PauseFailControl()
-        self._digest = _digest.digest(_stock_service.STOCK_TEST_SERVICE,
-                                      self._control, None)
-
-        generic_stub, dynamic_stubs, self._memo = self.implementation.instantiate(
-            self._digest.methods, self._digest.inline_method_implementations,
-            None)
-        self._invoker = self.invoker_constructor.construct_invoker(
-            generic_stub, dynamic_stubs, self._digest.methods)
-
-    def tearDown(self):
-        """See unittest.TestCase.tearDown for full specification.
-
-    Overriding implementations must call this implementation.
-    """
-        self._invoker = None
-        self.implementation.destantiate(self._memo)
-
-    def testSuccessfulUnaryRequestUnaryResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.unary_unary_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                request = test_messages.request()
-
-                response, call = self._invoker.blocking(group, method)(
-                    request, test_constants.LONG_TIMEOUT, with_call=True)
-
-                test_messages.verify(request, response, self)
-
-    def testSuccessfulUnaryRequestStreamResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.unary_stream_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                request = test_messages.request()
-
-                response_iterator = self._invoker.blocking(group, method)(
-                    request, test_constants.LONG_TIMEOUT)
-                responses = list(response_iterator)
-
-                test_messages.verify(request, responses, self)
-
-    def testSuccessfulStreamRequestUnaryResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.stream_unary_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                requests = test_messages.requests()
-
-                response, call = self._invoker.blocking(group, method)(
-                    iter(requests), test_constants.LONG_TIMEOUT, with_call=True)
-
-                test_messages.verify(requests, response, self)
-
-    def testSuccessfulStreamRequestStreamResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.stream_stream_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                requests = test_messages.requests()
-
-                response_iterator = self._invoker.blocking(group, method)(
-                    iter(requests), test_constants.LONG_TIMEOUT)
-                responses = list(response_iterator)
-
-                test_messages.verify(requests, responses, self)
-
-    def testSequentialInvocations(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.unary_unary_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                first_request = test_messages.request()
-                second_request = test_messages.request()
-
-                first_response = self._invoker.blocking(group, method)(
-                    first_request, test_constants.LONG_TIMEOUT)
-
-                test_messages.verify(first_request, first_response, self)
-
-                second_response = self._invoker.blocking(group, method)(
-                    second_request, test_constants.LONG_TIMEOUT)
-
-                test_messages.verify(second_request, second_response, self)
-
-    def testParallelInvocations(self):
-        pool = logging_pool.pool(test_constants.THREAD_CONCURRENCY)
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.unary_unary_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                requests = []
-                response_futures = []
-                for _ in range(test_constants.THREAD_CONCURRENCY):
-                    request = test_messages.request()
-                    response_future = pool.submit(
-                        self._invoker.blocking(group, method), request,
-                        test_constants.LONG_TIMEOUT)
-                    requests.append(request)
-                    response_futures.append(response_future)
-
-                responses = [
-                    response_future.result()
-                    for response_future in response_futures
-                ]
-
-                for request, response in zip(requests, responses):
-                    test_messages.verify(request, response, self)
-        pool.shutdown(wait=True)
-
-    def testWaitingForSomeButNotAllParallelInvocations(self):
-        pool = logging_pool.pool(test_constants.THREAD_CONCURRENCY)
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.unary_unary_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                requests = []
-                response_futures_to_indices = {}
-                for index in range(test_constants.THREAD_CONCURRENCY):
-                    request = test_messages.request()
-                    response_future = pool.submit(
-                        self._invoker.blocking(group, method), request,
-                        test_constants.LONG_TIMEOUT)
-                    requests.append(request)
-                    response_futures_to_indices[response_future] = index
-
-                some_completed_response_futures_iterator = itertools.islice(
-                    futures.as_completed(response_futures_to_indices),
-                    test_constants.THREAD_CONCURRENCY // 2)
-                for response_future in some_completed_response_futures_iterator:
-                    index = response_futures_to_indices[response_future]
-                    test_messages.verify(requests[index],
-                                         response_future.result(), self)
-        pool.shutdown(wait=True)
-
-    @unittest.skip('Cancellation impossible with blocking control flow!')
-    def testCancelledUnaryRequestUnaryResponse(self):
-        raise NotImplementedError()
-
-    @unittest.skip('Cancellation impossible with blocking control flow!')
-    def testCancelledUnaryRequestStreamResponse(self):
-        raise NotImplementedError()
-
-    @unittest.skip('Cancellation impossible with blocking control flow!')
-    def testCancelledStreamRequestUnaryResponse(self):
-        raise NotImplementedError()
-
-    @unittest.skip('Cancellation impossible with blocking control flow!')
-    def testCancelledStreamRequestStreamResponse(self):
-        raise NotImplementedError()
-
-    def testExpiredUnaryRequestUnaryResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.unary_unary_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                request = test_messages.request()
-
-                with self._control.pause(), self.assertRaises(
-                        face.ExpirationError):
-                    self._invoker.blocking(group, method)(
-                        request, _3069_test_constant.REALLY_SHORT_TIMEOUT)
-
-    def testExpiredUnaryRequestStreamResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.unary_stream_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                request = test_messages.request()
-
-                with self._control.pause(), self.assertRaises(
-                        face.ExpirationError):
-                    response_iterator = self._invoker.blocking(group, method)(
-                        request, _3069_test_constant.REALLY_SHORT_TIMEOUT)
-                    list(response_iterator)
-
-    def testExpiredStreamRequestUnaryResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.stream_unary_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                requests = test_messages.requests()
-
-                with self._control.pause(), self.assertRaises(
-                        face.ExpirationError):
-                    self._invoker.blocking(
-                        group, method)(iter(requests),
-                                       _3069_test_constant.REALLY_SHORT_TIMEOUT)
-
-    def testExpiredStreamRequestStreamResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.stream_stream_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                requests = test_messages.requests()
-
-                with self._control.pause(), self.assertRaises(
-                        face.ExpirationError):
-                    response_iterator = self._invoker.blocking(
-                        group, method)(iter(requests),
-                                       _3069_test_constant.REALLY_SHORT_TIMEOUT)
-                    list(response_iterator)
-
-    def testFailedUnaryRequestUnaryResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.unary_unary_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                request = test_messages.request()
-
-                with self._control.fail(), self.assertRaises(face.RemoteError):
-                    self._invoker.blocking(group, method)(
-                        request, test_constants.LONG_TIMEOUT)
-
-    def testFailedUnaryRequestStreamResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.unary_stream_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                request = test_messages.request()
-
-                with self._control.fail(), self.assertRaises(face.RemoteError):
-                    response_iterator = self._invoker.blocking(group, method)(
-                        request, test_constants.LONG_TIMEOUT)
-                    list(response_iterator)
-
-    def testFailedStreamRequestUnaryResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.stream_unary_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                requests = test_messages.requests()
-
-                with self._control.fail(), self.assertRaises(face.RemoteError):
-                    self._invoker.blocking(group, method)(
-                        iter(requests), test_constants.LONG_TIMEOUT)
-
-    def testFailedStreamRequestStreamResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.stream_stream_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                requests = test_messages.requests()
-
-                with self._control.fail(), self.assertRaises(face.RemoteError):
-                    response_iterator = self._invoker.blocking(group, method)(
-                        iter(requests), test_constants.LONG_TIMEOUT)
-                    list(response_iterator)
diff --git a/src/python/grpcio_tests/tests/unit/framework/interfaces/face/_digest.py b/src/python/grpcio_tests/tests/unit/framework/interfaces/face/_digest.py
deleted file mode 100644
index b1c33da..0000000
--- a/src/python/grpcio_tests/tests/unit/framework/interfaces/face/_digest.py
+++ /dev/null
@@ -1,432 +0,0 @@
-# Copyright 2015 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Code for making a service.TestService more amenable to use in tests."""
-
-import collections
-import threading
-
-import six
-
-# test_control, _service, and test_interfaces are referenced from specification
-# in this module.
-from grpc.framework.common import cardinality
-from grpc.framework.common import style
-from grpc.framework.foundation import stream
-from grpc.framework.foundation import stream_util
-from grpc.framework.interfaces.face import face
-from tests.unit.framework.common import test_control  # pylint: disable=unused-import
-from tests.unit.framework.interfaces.face import _service  # pylint: disable=unused-import
-from tests.unit.framework.interfaces.face import test_interfaces  # pylint: disable=unused-import
-
-_IDENTITY = lambda x: x
-
-
-class TestServiceDigest(
-        collections.namedtuple('TestServiceDigest', (
-            'methods',
-            'inline_method_implementations',
-            'event_method_implementations',
-            'multi_method_implementation',
-            'unary_unary_messages_sequences',
-            'unary_stream_messages_sequences',
-            'stream_unary_messages_sequences',
-            'stream_stream_messages_sequences',
-        ))):
-    """A transformation of a service.TestService.
-
-  Attributes:
-    methods: A dict from method group-name pair to test_interfaces.Method object
-      describing the RPC methods that may be called during the test.
-    inline_method_implementations: A dict from method group-name pair to
-      face.MethodImplementation object to be used in tests of in-line calls to
-      behaviors under test.
-    event_method_implementations: A dict from method group-name pair to
-      face.MethodImplementation object to be used in tests of event-driven calls
-      to behaviors under test.
-    multi_method_implementation: A face.MultiMethodImplementation to be used in
-      tests of generic calls to behaviors under test.
-    unary_unary_messages_sequences: A dict from method group-name pair to
-      sequence of service.UnaryUnaryTestMessages objects to be used to test the
-      identified method.
-    unary_stream_messages_sequences: A dict from method group-name pair to
-      sequence of service.UnaryStreamTestMessages objects to be used to test the
-      identified method.
-    stream_unary_messages_sequences: A dict from method group-name pair to
-      sequence of service.StreamUnaryTestMessages objects to be used to test the
-      identified method.
-    stream_stream_messages_sequences: A dict from method group-name pair to
-      sequence of service.StreamStreamTestMessages objects to be used to test
-      the identified method.
-  """
-
-
-class _BufferingConsumer(stream.Consumer):
-    """A trivial Consumer that dumps what it consumes in a user-mutable buffer."""
-
-    def __init__(self):
-        self.consumed = []
-        self.terminated = False
-
-    def consume(self, value):
-        self.consumed.append(value)
-
-    def terminate(self):
-        self.terminated = True
-
-    def consume_and_terminate(self, value):
-        self.consumed.append(value)
-        self.terminated = True
-
-
-class _InlineUnaryUnaryMethod(face.MethodImplementation):
-
-    def __init__(self, unary_unary_test_method, control):
-        self._test_method = unary_unary_test_method
-        self._control = control
-
-        self.cardinality = cardinality.Cardinality.UNARY_UNARY
-        self.style = style.Service.INLINE
-
-    def unary_unary_inline(self, request, context):
-        response_list = []
-        self._test_method.service(request, response_list.append, context,
-                                  self._control)
-        return response_list.pop(0)
-
-
-class _EventUnaryUnaryMethod(face.MethodImplementation):
-
-    def __init__(self, unary_unary_test_method, control, pool):
-        self._test_method = unary_unary_test_method
-        self._control = control
-        self._pool = pool
-
-        self.cardinality = cardinality.Cardinality.UNARY_UNARY
-        self.style = style.Service.EVENT
-
-    def unary_unary_event(self, request, response_callback, context):
-        if self._pool is None:
-            self._test_method.service(request, response_callback, context,
-                                      self._control)
-        else:
-            self._pool.submit(self._test_method.service, request,
-                              response_callback, context, self._control)
-
-
-class _InlineUnaryStreamMethod(face.MethodImplementation):
-
-    def __init__(self, unary_stream_test_method, control):
-        self._test_method = unary_stream_test_method
-        self._control = control
-
-        self.cardinality = cardinality.Cardinality.UNARY_STREAM
-        self.style = style.Service.INLINE
-
-    def unary_stream_inline(self, request, context):
-        response_consumer = _BufferingConsumer()
-        self._test_method.service(request, response_consumer, context,
-                                  self._control)
-        for response in response_consumer.consumed:
-            yield response
-
-
-class _EventUnaryStreamMethod(face.MethodImplementation):
-
-    def __init__(self, unary_stream_test_method, control, pool):
-        self._test_method = unary_stream_test_method
-        self._control = control
-        self._pool = pool
-
-        self.cardinality = cardinality.Cardinality.UNARY_STREAM
-        self.style = style.Service.EVENT
-
-    def unary_stream_event(self, request, response_consumer, context):
-        if self._pool is None:
-            self._test_method.service(request, response_consumer, context,
-                                      self._control)
-        else:
-            self._pool.submit(self._test_method.service, request,
-                              response_consumer, context, self._control)
-
-
-class _InlineStreamUnaryMethod(face.MethodImplementation):
-
-    def __init__(self, stream_unary_test_method, control):
-        self._test_method = stream_unary_test_method
-        self._control = control
-
-        self.cardinality = cardinality.Cardinality.STREAM_UNARY
-        self.style = style.Service.INLINE
-
-    def stream_unary_inline(self, request_iterator, context):
-        response_list = []
-        request_consumer = self._test_method.service(response_list.append,
-                                                     context, self._control)
-        for request in request_iterator:
-            request_consumer.consume(request)
-        request_consumer.terminate()
-        return response_list.pop(0)
-
-
-class _EventStreamUnaryMethod(face.MethodImplementation):
-
-    def __init__(self, stream_unary_test_method, control, pool):
-        self._test_method = stream_unary_test_method
-        self._control = control
-        self._pool = pool
-
-        self.cardinality = cardinality.Cardinality.STREAM_UNARY
-        self.style = style.Service.EVENT
-
-    def stream_unary_event(self, response_callback, context):
-        request_consumer = self._test_method.service(response_callback, context,
-                                                     self._control)
-        if self._pool is None:
-            return request_consumer
-        else:
-            return stream_util.ThreadSwitchingConsumer(request_consumer,
-                                                       self._pool)
-
-
-class _InlineStreamStreamMethod(face.MethodImplementation):
-
-    def __init__(self, stream_stream_test_method, control):
-        self._test_method = stream_stream_test_method
-        self._control = control
-
-        self.cardinality = cardinality.Cardinality.STREAM_STREAM
-        self.style = style.Service.INLINE
-
-    def stream_stream_inline(self, request_iterator, context):
-        response_consumer = _BufferingConsumer()
-        request_consumer = self._test_method.service(response_consumer, context,
-                                                     self._control)
-
-        for request in request_iterator:
-            request_consumer.consume(request)
-            while response_consumer.consumed:
-                yield response_consumer.consumed.pop(0)
-        response_consumer.terminate()
-
-
-class _EventStreamStreamMethod(face.MethodImplementation):
-
-    def __init__(self, stream_stream_test_method, control, pool):
-        self._test_method = stream_stream_test_method
-        self._control = control
-        self._pool = pool
-
-        self.cardinality = cardinality.Cardinality.STREAM_STREAM
-        self.style = style.Service.EVENT
-
-    def stream_stream_event(self, response_consumer, context):
-        request_consumer = self._test_method.service(response_consumer, context,
-                                                     self._control)
-        if self._pool is None:
-            return request_consumer
-        else:
-            return stream_util.ThreadSwitchingConsumer(request_consumer,
-                                                       self._pool)
-
-
-class _UnaryConsumer(stream.Consumer):
-    """A Consumer that only allows consumption of exactly one value."""
-
-    def __init__(self, action):
-        self._lock = threading.Lock()
-        self._action = action
-        self._consumed = False
-        self._terminated = False
-
-    def consume(self, value):
-        with self._lock:
-            if self._consumed:
-                raise ValueError('Unary consumer already consumed!')
-            elif self._terminated:
-                raise ValueError('Unary consumer already terminated!')
-            else:
-                self._consumed = True
-
-        self._action(value)
-
-    def terminate(self):
-        with self._lock:
-            if not self._consumed:
-                raise ValueError('Unary consumer hasn\'t yet consumed!')
-            elif self._terminated:
-                raise ValueError('Unary consumer already terminated!')
-            else:
-                self._terminated = True
-
-    def consume_and_terminate(self, value):
-        with self._lock:
-            if self._consumed:
-                raise ValueError('Unary consumer already consumed!')
-            elif self._terminated:
-                raise ValueError('Unary consumer already terminated!')
-            else:
-                self._consumed = True
-                self._terminated = True
-
-        self._action(value)
-
-
-class _UnaryUnaryAdaptation(object):
-
-    def __init__(self, unary_unary_test_method):
-        self._method = unary_unary_test_method
-
-    def service(self, response_consumer, context, control):
-
-        def action(request):
-            self._method.service(request,
-                                 response_consumer.consume_and_terminate,
-                                 context, control)
-
-        return _UnaryConsumer(action)
-
-
-class _UnaryStreamAdaptation(object):
-
-    def __init__(self, unary_stream_test_method):
-        self._method = unary_stream_test_method
-
-    def service(self, response_consumer, context, control):
-
-        def action(request):
-            self._method.service(request, response_consumer, context, control)
-
-        return _UnaryConsumer(action)
-
-
-class _StreamUnaryAdaptation(object):
-
-    def __init__(self, stream_unary_test_method):
-        self._method = stream_unary_test_method
-
-    def service(self, response_consumer, context, control):
-        return self._method.service(response_consumer.consume_and_terminate,
-                                    context, control)
-
-
-class _MultiMethodImplementation(face.MultiMethodImplementation):
-
-    def __init__(self, methods, control, pool):
-        self._methods = methods
-        self._control = control
-        self._pool = pool
-
-    def service(self, group, name, response_consumer, context):
-        method = self._methods.get(group, name, None)
-        if method is None:
-            raise face.NoSuchMethodError(group, name)
-        elif self._pool is None:
-            return method(response_consumer, context, self._control)
-        else:
-            request_consumer = method(response_consumer, context, self._control)
-            return stream_util.ThreadSwitchingConsumer(request_consumer,
-                                                       self._pool)
-
-
-class _Assembly(
-        collections.namedtuple(
-            '_Assembly',
-            ['methods', 'inlines', 'events', 'adaptations', 'messages'])):
-    """An intermediate structure created when creating a TestServiceDigest."""
-
-
-def _assemble(scenarios, identifiers, inline_method_constructor,
-              event_method_constructor, adapter, control, pool):
-    """Creates an _Assembly from the given scenarios."""
-    methods = {}
-    inlines = {}
-    events = {}
-    adaptations = {}
-    messages = {}
-    for identifier, scenario in six.iteritems(scenarios):
-        if identifier in identifiers:
-            raise ValueError('Repeated identifier "(%s, %s)"!' % identifier)
-
-        test_method = scenario[0]
-        inline_method = inline_method_constructor(test_method, control)
-        event_method = event_method_constructor(test_method, control, pool)
-        adaptation = adapter(test_method)
-
-        methods[identifier] = test_method
-        inlines[identifier] = inline_method
-        events[identifier] = event_method
-        adaptations[identifier] = adaptation
-        messages[identifier] = scenario[1]
-
-    return _Assembly(methods, inlines, events, adaptations, messages)
-
-
-def digest(service, control, pool):
-    """Creates a TestServiceDigest from a TestService.
-
-  Args:
-    service: A _service.TestService.
-    control: A test_control.Control.
-    pool: If RPC methods should be serviced in a separate thread, a thread pool.
-      None if RPC methods should be serviced in the thread belonging to the
-      run-time that calls for their service.
-
-  Returns:
-    A TestServiceDigest synthesized from the given service.TestService.
-  """
-    identifiers = set()
-
-    unary_unary = _assemble(service.unary_unary_scenarios(), identifiers,
-                            _InlineUnaryUnaryMethod, _EventUnaryUnaryMethod,
-                            _UnaryUnaryAdaptation, control, pool)
-    identifiers.update(unary_unary.inlines)
-
-    unary_stream = _assemble(service.unary_stream_scenarios(), identifiers,
-                             _InlineUnaryStreamMethod, _EventUnaryStreamMethod,
-                             _UnaryStreamAdaptation, control, pool)
-    identifiers.update(unary_stream.inlines)
-
-    stream_unary = _assemble(service.stream_unary_scenarios(), identifiers,
-                             _InlineStreamUnaryMethod, _EventStreamUnaryMethod,
-                             _StreamUnaryAdaptation, control, pool)
-    identifiers.update(stream_unary.inlines)
-
-    stream_stream = _assemble(service.stream_stream_scenarios(), identifiers,
-                              _InlineStreamStreamMethod,
-                              _EventStreamStreamMethod, _IDENTITY, control,
-                              pool)
-    identifiers.update(stream_stream.inlines)
-
-    methods = dict(unary_unary.methods)
-    methods.update(unary_stream.methods)
-    methods.update(stream_unary.methods)
-    methods.update(stream_stream.methods)
-    adaptations = dict(unary_unary.adaptations)
-    adaptations.update(unary_stream.adaptations)
-    adaptations.update(stream_unary.adaptations)
-    adaptations.update(stream_stream.adaptations)
-    inlines = dict(unary_unary.inlines)
-    inlines.update(unary_stream.inlines)
-    inlines.update(stream_unary.inlines)
-    inlines.update(stream_stream.inlines)
-    events = dict(unary_unary.events)
-    events.update(unary_stream.events)
-    events.update(stream_unary.events)
-    events.update(stream_stream.events)
-
-    return TestServiceDigest(methods, inlines, events,
-                             _MultiMethodImplementation(adaptations, control,
-                                                        pool),
-                             unary_unary.messages, unary_stream.messages,
-                             stream_unary.messages, stream_stream.messages)
diff --git a/src/python/grpcio_tests/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py b/src/python/grpcio_tests/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
deleted file mode 100644
index 3d9b281..0000000
--- a/src/python/grpcio_tests/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
+++ /dev/null
@@ -1,508 +0,0 @@
-# Copyright 2015 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Test code for the Face layer of RPC Framework."""
-
-from __future__ import division
-
-import abc
-import contextlib
-import itertools
-import threading
-import unittest
-from concurrent import futures
-
-import six
-
-# test_interfaces is referenced from specification in this module.
-from grpc.framework.foundation import future
-from grpc.framework.foundation import logging_pool
-from grpc.framework.interfaces.face import face
-from tests.unit.framework.common import test_constants
-from tests.unit.framework.common import test_control
-from tests.unit.framework.common import test_coverage
-from tests.unit.framework.interfaces.face import _3069_test_constant
-from tests.unit.framework.interfaces.face import _digest
-from tests.unit.framework.interfaces.face import _stock_service
-from tests.unit.framework.interfaces.face import test_interfaces  # pylint: disable=unused-import
-
-
-class _PauseableIterator(object):
-
-    def __init__(self, upstream):
-        self._upstream = upstream
-        self._condition = threading.Condition()
-        self._paused = False
-
-    @contextlib.contextmanager
-    def pause(self):
-        with self._condition:
-            self._paused = True
-        yield
-        with self._condition:
-            self._paused = False
-            self._condition.notify_all()
-
-    def __iter__(self):
-        return self
-
-    def __next__(self):
-        return self.next()
-
-    def next(self):
-        with self._condition:
-            while self._paused:
-                self._condition.wait()
-        return next(self._upstream)
-
-
-class _Callback(object):
-
-    def __init__(self):
-        self._condition = threading.Condition()
-        self._called = False
-        self._passed_future = None
-        self._passed_other_stuff = None
-
-    def __call__(self, *args, **kwargs):
-        with self._condition:
-            self._called = True
-            if args:
-                self._passed_future = args[0]
-            if 1 < len(args) or kwargs:
-                self._passed_other_stuff = tuple(args[1:]), dict(kwargs)
-            self._condition.notify_all()
-
-    def future(self):
-        with self._condition:
-            while True:
-                if self._passed_other_stuff is not None:
-                    raise ValueError(
-                        'Test callback passed unexpected values: %s',
-                        self._passed_other_stuff)
-                elif self._called:
-                    return self._passed_future
-                else:
-                    self._condition.wait()
-
-
-class TestCase(
-        six.with_metaclass(abc.ABCMeta, test_coverage.Coverage,
-                           unittest.TestCase)):
-    """A test of the Face layer of RPC Framework.
-
-  Concrete subclasses must have an "implementation" attribute of type
-  test_interfaces.Implementation and an "invoker_constructor" attribute of type
-  _invocation.InvokerConstructor.
-  """
-
-    NAME = 'FutureInvocationAsynchronousEventServiceTest'
-
-    def setUp(self):
-        """See unittest.TestCase.setUp for full specification.
-
-    Overriding implementations must call this implementation.
-    """
-        self._control = test_control.PauseFailControl()
-        self._digest_pool = logging_pool.pool(test_constants.POOL_SIZE)
-        self._digest = _digest.digest(_stock_service.STOCK_TEST_SERVICE,
-                                      self._control, self._digest_pool)
-
-        generic_stub, dynamic_stubs, self._memo = self.implementation.instantiate(
-            self._digest.methods, self._digest.event_method_implementations,
-            None)
-        self._invoker = self.invoker_constructor.construct_invoker(
-            generic_stub, dynamic_stubs, self._digest.methods)
-
-    def tearDown(self):
-        """See unittest.TestCase.tearDown for full specification.
-
-    Overriding implementations must call this implementation.
-    """
-        self._invoker = None
-        self.implementation.destantiate(self._memo)
-        self._digest_pool.shutdown(wait=True)
-
-    def testSuccessfulUnaryRequestUnaryResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.unary_unary_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                request = test_messages.request()
-                callback = _Callback()
-
-                response_future = self._invoker.future(group, method)(
-                    request, test_constants.LONG_TIMEOUT)
-                response_future.add_done_callback(callback)
-                response = response_future.result()
-
-                test_messages.verify(request, response, self)
-                self.assertIs(callback.future(), response_future)
-                self.assertIsNone(response_future.exception())
-                self.assertIsNone(response_future.traceback())
-
-    def testSuccessfulUnaryRequestStreamResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.unary_stream_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                request = test_messages.request()
-
-                response_iterator = self._invoker.future(group, method)(
-                    request, test_constants.LONG_TIMEOUT)
-                responses = list(response_iterator)
-
-                test_messages.verify(request, responses, self)
-
-    def testSuccessfulStreamRequestUnaryResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.stream_unary_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                requests = test_messages.requests()
-                request_iterator = _PauseableIterator(iter(requests))
-                callback = _Callback()
-
-                # Use of a paused iterator of requests allows us to test that control is
-                # returned to calling code before the iterator yields any requests.
-                with request_iterator.pause():
-                    response_future = self._invoker.future(group, method)(
-                        request_iterator, test_constants.LONG_TIMEOUT)
-                    response_future.add_done_callback(callback)
-                future_passed_to_callback = callback.future()
-                response = future_passed_to_callback.result()
-
-                test_messages.verify(requests, response, self)
-                self.assertIs(future_passed_to_callback, response_future)
-                self.assertIsNone(response_future.exception())
-                self.assertIsNone(response_future.traceback())
-
-    def testSuccessfulStreamRequestStreamResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.stream_stream_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                requests = test_messages.requests()
-                request_iterator = _PauseableIterator(iter(requests))
-
-                # Use of a paused iterator of requests allows us to test that control is
-                # returned to calling code before the iterator yields any requests.
-                with request_iterator.pause():
-                    response_iterator = self._invoker.future(group, method)(
-                        request_iterator, test_constants.LONG_TIMEOUT)
-                responses = list(response_iterator)
-
-                test_messages.verify(requests, responses, self)
-
-    def testSequentialInvocations(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.unary_unary_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                first_request = test_messages.request()
-                second_request = test_messages.request()
-
-                first_response_future = self._invoker.future(group, method)(
-                    first_request, test_constants.LONG_TIMEOUT)
-                first_response = first_response_future.result()
-
-                test_messages.verify(first_request, first_response, self)
-
-                second_response_future = self._invoker.future(group, method)(
-                    second_request, test_constants.LONG_TIMEOUT)
-                second_response = second_response_future.result()
-
-                test_messages.verify(second_request, second_response, self)
-
-    def testParallelInvocations(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.unary_unary_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                first_request = test_messages.request()
-                second_request = test_messages.request()
-
-                first_response_future = self._invoker.future(group, method)(
-                    first_request, test_constants.LONG_TIMEOUT)
-                second_response_future = self._invoker.future(group, method)(
-                    second_request, test_constants.LONG_TIMEOUT)
-                first_response = first_response_future.result()
-                second_response = second_response_future.result()
-
-                test_messages.verify(first_request, first_response, self)
-                test_messages.verify(second_request, second_response, self)
-
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.unary_unary_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                requests = []
-                response_futures = []
-                for _ in range(test_constants.THREAD_CONCURRENCY):
-                    request = test_messages.request()
-                    response_future = self._invoker.future(group, method)(
-                        request, test_constants.LONG_TIMEOUT)
-                    requests.append(request)
-                    response_futures.append(response_future)
-
-                responses = [
-                    response_future.result()
-                    for response_future in response_futures
-                ]
-
-                for request, response in zip(requests, responses):
-                    test_messages.verify(request, response, self)
-
-    def testWaitingForSomeButNotAllParallelInvocations(self):
-        pool = logging_pool.pool(test_constants.THREAD_CONCURRENCY)
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.unary_unary_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                requests = []
-                response_futures_to_indices = {}
-                for index in range(test_constants.THREAD_CONCURRENCY):
-                    request = test_messages.request()
-                    inner_response_future = self._invoker.future(group, method)(
-                        request, test_constants.LONG_TIMEOUT)
-                    outer_response_future = pool.submit(
-                        inner_response_future.result)
-                    requests.append(request)
-                    response_futures_to_indices[outer_response_future] = index
-
-                some_completed_response_futures_iterator = itertools.islice(
-                    futures.as_completed(response_futures_to_indices),
-                    test_constants.THREAD_CONCURRENCY // 2)
-                for response_future in some_completed_response_futures_iterator:
-                    index = response_futures_to_indices[response_future]
-                    test_messages.verify(requests[index],
-                                         response_future.result(), self)
-        pool.shutdown(wait=True)
-
-    def testCancelledUnaryRequestUnaryResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.unary_unary_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                request = test_messages.request()
-                callback = _Callback()
-
-                with self._control.pause():
-                    response_future = self._invoker.future(group, method)(
-                        request, test_constants.LONG_TIMEOUT)
-                    response_future.add_done_callback(callback)
-                    cancel_method_return_value = response_future.cancel()
-
-                self.assertIs(callback.future(), response_future)
-                self.assertFalse(cancel_method_return_value)
-                self.assertTrue(response_future.cancelled())
-                with self.assertRaises(future.CancelledError):
-                    response_future.result()
-                with self.assertRaises(future.CancelledError):
-                    response_future.exception()
-                with self.assertRaises(future.CancelledError):
-                    response_future.traceback()
-
-    def testCancelledUnaryRequestStreamResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.unary_stream_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                request = test_messages.request()
-
-                with self._control.pause():
-                    response_iterator = self._invoker.future(group, method)(
-                        request, test_constants.LONG_TIMEOUT)
-                    response_iterator.cancel()
-
-                with self.assertRaises(face.CancellationError):
-                    next(response_iterator)
-
-    def testCancelledStreamRequestUnaryResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.stream_unary_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                requests = test_messages.requests()
-                callback = _Callback()
-
-                with self._control.pause():
-                    response_future = self._invoker.future(group, method)(
-                        iter(requests), test_constants.LONG_TIMEOUT)
-                    response_future.add_done_callback(callback)
-                    cancel_method_return_value = response_future.cancel()
-
-                self.assertIs(callback.future(), response_future)
-                self.assertFalse(cancel_method_return_value)
-                self.assertTrue(response_future.cancelled())
-                with self.assertRaises(future.CancelledError):
-                    response_future.result()
-                with self.assertRaises(future.CancelledError):
-                    response_future.exception()
-                with self.assertRaises(future.CancelledError):
-                    response_future.traceback()
-
-    def testCancelledStreamRequestStreamResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.stream_stream_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                requests = test_messages.requests()
-
-                with self._control.pause():
-                    response_iterator = self._invoker.future(group, method)(
-                        iter(requests), test_constants.LONG_TIMEOUT)
-                    response_iterator.cancel()
-
-                with self.assertRaises(face.CancellationError):
-                    next(response_iterator)
-
-    def testExpiredUnaryRequestUnaryResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.unary_unary_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                request = test_messages.request()
-                callback = _Callback()
-
-                with self._control.pause():
-                    response_future = self._invoker.future(group, method)(
-                        request, _3069_test_constant.REALLY_SHORT_TIMEOUT)
-                    response_future.add_done_callback(callback)
-                    self.assertIs(callback.future(), response_future)
-                    self.assertIsInstance(response_future.exception(),
-                                          face.ExpirationError)
-                    with self.assertRaises(face.ExpirationError):
-                        response_future.result()
-                    self.assertIsInstance(response_future.exception(),
-                                          face.AbortionError)
-                    self.assertIsNotNone(response_future.traceback())
-
-    def testExpiredUnaryRequestStreamResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.unary_stream_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                request = test_messages.request()
-
-                with self._control.pause():
-                    response_iterator = self._invoker.future(group, method)(
-                        request, _3069_test_constant.REALLY_SHORT_TIMEOUT)
-                    with self.assertRaises(face.ExpirationError):
-                        list(response_iterator)
-
-    def testExpiredStreamRequestUnaryResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.stream_unary_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                requests = test_messages.requests()
-                callback = _Callback()
-
-                with self._control.pause():
-                    response_future = self._invoker.future(
-                        group, method)(iter(requests),
-                                       _3069_test_constant.REALLY_SHORT_TIMEOUT)
-                    response_future.add_done_callback(callback)
-                    self.assertIs(callback.future(), response_future)
-                    self.assertIsInstance(response_future.exception(),
-                                          face.ExpirationError)
-                    with self.assertRaises(face.ExpirationError):
-                        response_future.result()
-                    self.assertIsInstance(response_future.exception(),
-                                          face.AbortionError)
-                    self.assertIsNotNone(response_future.traceback())
-
-    def testExpiredStreamRequestStreamResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.stream_stream_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                requests = test_messages.requests()
-
-                with self._control.pause():
-                    response_iterator = self._invoker.future(
-                        group, method)(iter(requests),
-                                       _3069_test_constant.REALLY_SHORT_TIMEOUT)
-                    with self.assertRaises(face.ExpirationError):
-                        list(response_iterator)
-
-    def testFailedUnaryRequestUnaryResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.unary_unary_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                request = test_messages.request()
-                callback = _Callback()
-                abortion_callback = _Callback()
-
-                with self._control.fail():
-                    response_future = self._invoker.future(group, method)(
-                        request, _3069_test_constant.REALLY_SHORT_TIMEOUT)
-                    response_future.add_done_callback(callback)
-                    response_future.add_abortion_callback(abortion_callback)
-
-                    self.assertIs(callback.future(), response_future)
-                    # Because the servicer fails outside of the thread from which the
-                    # servicer-side runtime called into it its failure is
-                    # indistinguishable from simply not having called its
-                    # response_callback before the expiration of the RPC.
-                    self.assertIsInstance(response_future.exception(),
-                                          face.ExpirationError)
-                    with self.assertRaises(face.ExpirationError):
-                        response_future.result()
-                    self.assertIsNotNone(response_future.traceback())
-                    self.assertIsNotNone(abortion_callback.future())
-
-    def testFailedUnaryRequestStreamResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.unary_stream_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                request = test_messages.request()
-
-                # Because the servicer fails outside of the thread from which the
-                # servicer-side runtime called into it its failure is indistinguishable
-                # from simply not having called its response_consumer before the
-                # expiration of the RPC.
-                with self._control.fail(), self.assertRaises(
-                        face.ExpirationError):
-                    response_iterator = self._invoker.future(group, method)(
-                        request, _3069_test_constant.REALLY_SHORT_TIMEOUT)
-                    list(response_iterator)
-
-    def testFailedStreamRequestUnaryResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.stream_unary_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                requests = test_messages.requests()
-                callback = _Callback()
-                abortion_callback = _Callback()
-
-                with self._control.fail():
-                    response_future = self._invoker.future(
-                        group, method)(iter(requests),
-                                       _3069_test_constant.REALLY_SHORT_TIMEOUT)
-                    response_future.add_done_callback(callback)
-                    response_future.add_abortion_callback(abortion_callback)
-
-                    self.assertIs(callback.future(), response_future)
-                    # Because the servicer fails outside of the thread from which the
-                    # servicer-side runtime called into it its failure is
-                    # indistinguishable from simply not having called its
-                    # response_callback before the expiration of the RPC.
-                    self.assertIsInstance(response_future.exception(),
-                                          face.ExpirationError)
-                    with self.assertRaises(face.ExpirationError):
-                        response_future.result()
-                    self.assertIsNotNone(response_future.traceback())
-                    self.assertIsNotNone(abortion_callback.future())
-
-    def testFailedStreamRequestStreamResponse(self):
-        for (group, method), test_messages_sequence in (six.iteritems(
-                self._digest.stream_stream_messages_sequences)):
-            for test_messages in test_messages_sequence:
-                requests = test_messages.requests()
-
-                # Because the servicer fails outside of the thread from which the
-                # servicer-side runtime called into it its failure is indistinguishable
-                # from simply not having called its response_consumer before the
-                # expiration of the RPC.
-                with self._control.fail(), self.assertRaises(
-                        face.ExpirationError):
-                    response_iterator = self._invoker.future(
-                        group, method)(iter(requests),
-                                       _3069_test_constant.REALLY_SHORT_TIMEOUT)
-                    list(response_iterator)
diff --git a/src/python/grpcio_tests/tests/unit/framework/interfaces/face/_invocation.py b/src/python/grpcio_tests/tests/unit/framework/interfaces/face/_invocation.py
deleted file mode 100644
index efc93d5..0000000
--- a/src/python/grpcio_tests/tests/unit/framework/interfaces/face/_invocation.py
+++ /dev/null
@@ -1,198 +0,0 @@
-# Copyright 2015 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Coverage across the Face layer's generic-to-dynamic range for invocation."""
-
-import abc
-
-import six
-
-from grpc.framework.common import cardinality
-
-_CARDINALITY_TO_GENERIC_BLOCKING_BEHAVIOR = {
-    cardinality.Cardinality.UNARY_UNARY: 'blocking_unary_unary',
-    cardinality.Cardinality.UNARY_STREAM: 'inline_unary_stream',
-    cardinality.Cardinality.STREAM_UNARY: 'blocking_stream_unary',
-    cardinality.Cardinality.STREAM_STREAM: 'inline_stream_stream',
-}
-
-_CARDINALITY_TO_GENERIC_FUTURE_BEHAVIOR = {
-    cardinality.Cardinality.UNARY_UNARY: 'future_unary_unary',
-    cardinality.Cardinality.UNARY_STREAM: 'inline_unary_stream',
-    cardinality.Cardinality.STREAM_UNARY: 'future_stream_unary',
-    cardinality.Cardinality.STREAM_STREAM: 'inline_stream_stream',
-}
-
-_CARDINALITY_TO_GENERIC_EVENT_BEHAVIOR = {
-    cardinality.Cardinality.UNARY_UNARY: 'event_unary_unary',
-    cardinality.Cardinality.UNARY_STREAM: 'event_unary_stream',
-    cardinality.Cardinality.STREAM_UNARY: 'event_stream_unary',
-    cardinality.Cardinality.STREAM_STREAM: 'event_stream_stream',
-}
-
-_CARDINALITY_TO_MULTI_CALLABLE_ATTRIBUTE = {
-    cardinality.Cardinality.UNARY_UNARY: 'unary_unary',
-    cardinality.Cardinality.UNARY_STREAM: 'unary_stream',
-    cardinality.Cardinality.STREAM_UNARY: 'stream_unary',
-    cardinality.Cardinality.STREAM_STREAM: 'stream_stream',
-}
-
-
-class Invoker(six.with_metaclass(abc.ABCMeta)):
-    """A type used to invoke test RPCs."""
-
-    @abc.abstractmethod
-    def blocking(self, group, name):
-        """Invokes an RPC with blocking control flow."""
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def future(self, group, name):
-        """Invokes an RPC with future control flow."""
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def event(self, group, name):
-        """Invokes an RPC with event control flow."""
-        raise NotImplementedError()
-
-
-class InvokerConstructor(six.with_metaclass(abc.ABCMeta)):
-    """A type used to create Invokers."""
-
-    @abc.abstractmethod
-    def name(self):
-        """Specifies the name of the Invoker constructed by this object."""
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def construct_invoker(self, generic_stub, dynamic_stubs, methods):
-        """Constructs an Invoker for the given stubs and methods."""
-        raise NotImplementedError()
-
-
-class _GenericInvoker(Invoker):
-
-    def __init__(self, generic_stub, methods):
-        self._stub = generic_stub
-        self._methods = methods
-
-    def _behavior(self, group, name, cardinality_to_generic_method):
-        method_cardinality = self._methods[group, name].cardinality()
-        behavior = getattr(self._stub,
-                           cardinality_to_generic_method[method_cardinality])
-        return lambda *args, **kwargs: behavior(group, name, *args, **kwargs)
-
-    def blocking(self, group, name):
-        return self._behavior(group, name,
-                              _CARDINALITY_TO_GENERIC_BLOCKING_BEHAVIOR)
-
-    def future(self, group, name):
-        return self._behavior(group, name,
-                              _CARDINALITY_TO_GENERIC_FUTURE_BEHAVIOR)
-
-    def event(self, group, name):
-        return self._behavior(group, name,
-                              _CARDINALITY_TO_GENERIC_EVENT_BEHAVIOR)
-
-
-class _GenericInvokerConstructor(InvokerConstructor):
-
-    def name(self):
-        return 'GenericInvoker'
-
-    def construct_invoker(self, generic_stub, dynamic_stub, methods):
-        return _GenericInvoker(generic_stub, methods)
-
-
-class _MultiCallableInvoker(Invoker):
-
-    def __init__(self, generic_stub, methods):
-        self._stub = generic_stub
-        self._methods = methods
-
-    def _multi_callable(self, group, name):
-        method_cardinality = self._methods[group, name].cardinality()
-        behavior = getattr(
-            self._stub,
-            _CARDINALITY_TO_MULTI_CALLABLE_ATTRIBUTE[method_cardinality])
-        return behavior(group, name)
-
-    def blocking(self, group, name):
-        return self._multi_callable(group, name)
-
-    def future(self, group, name):
-        method_cardinality = self._methods[group, name].cardinality()
-        behavior = getattr(
-            self._stub,
-            _CARDINALITY_TO_MULTI_CALLABLE_ATTRIBUTE[method_cardinality])
-        if method_cardinality in (cardinality.Cardinality.UNARY_UNARY,
-                                  cardinality.Cardinality.STREAM_UNARY):
-            return behavior(group, name).future
-        else:
-            return behavior(group, name)
-
-    def event(self, group, name):
-        return self._multi_callable(group, name).event
-
-
-class _MultiCallableInvokerConstructor(InvokerConstructor):
-
-    def name(self):
-        return 'MultiCallableInvoker'
-
-    def construct_invoker(self, generic_stub, dynamic_stub, methods):
-        return _MultiCallableInvoker(generic_stub, methods)
-
-
-class _DynamicInvoker(Invoker):
-
-    def __init__(self, dynamic_stubs, methods):
-        self._stubs = dynamic_stubs
-        self._methods = methods
-
-    def blocking(self, group, name):
-        return getattr(self._stubs[group], name)
-
-    def future(self, group, name):
-        if self._methods[group, name].cardinality() in (
-                cardinality.Cardinality.UNARY_UNARY,
-                cardinality.Cardinality.STREAM_UNARY):
-            return getattr(self._stubs[group], name).future
-        else:
-            return getattr(self._stubs[group], name)
-
-    def event(self, group, name):
-        return getattr(self._stubs[group], name).event
-
-
-class _DynamicInvokerConstructor(InvokerConstructor):
-
-    def name(self):
-        return 'DynamicInvoker'
-
-    def construct_invoker(self, generic_stub, dynamic_stubs, methods):
-        return _DynamicInvoker(dynamic_stubs, methods)
-
-
-def invoker_constructors():
-    """Creates a sequence of InvokerConstructors to use in tests of RPCs.
-
-  Returns:
-    A sequence of InvokerConstructors.
-  """
-    return (
-        _GenericInvokerConstructor(),
-        _MultiCallableInvokerConstructor(),
-        _DynamicInvokerConstructor(),
-    )
diff --git a/src/python/grpcio_tests/tests/unit/framework/interfaces/face/_service.py b/src/python/grpcio_tests/tests/unit/framework/interfaces/face/_service.py
deleted file mode 100644
index f1c96b6..0000000
--- a/src/python/grpcio_tests/tests/unit/framework/interfaces/face/_service.py
+++ /dev/null
@@ -1,304 +0,0 @@
-# Copyright 2015 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Private interfaces implemented by data sets used in Face-layer tests."""
-
-import abc
-
-import six
-
-# face is referenced from specification in this module.
-from grpc.framework.interfaces.face import face  # pylint: disable=unused-import
-from tests.unit.framework.interfaces.face import test_interfaces
-
-
-class UnaryUnaryTestMethodImplementation(
-        six.with_metaclass(abc.ABCMeta, test_interfaces.Method)):
-    """A controllable implementation of a unary-unary method."""
-
-    @abc.abstractmethod
-    def service(self, request, response_callback, context, control):
-        """Services an RPC that accepts one message and produces one message.
-
-    Args:
-      request: The single request message for the RPC.
-      response_callback: A callback to be called to accept the response message
-        of the RPC.
-      context: An face.ServicerContext object.
-      control: A test_control.Control to control execution of this method.
-
-    Raises:
-      abandonment.Abandoned: May or may not be raised when the RPC has been
-        aborted.
-    """
-        raise NotImplementedError()
-
-
-class UnaryUnaryTestMessages(six.with_metaclass(abc.ABCMeta)):
-    """A type for unary-request-unary-response message pairings."""
-
-    @abc.abstractmethod
-    def request(self):
-        """Affords a request message.
-
-    Implementations of this method should return a different message with each
-    call so that multiple test executions of the test method may be made with
-    different inputs.
-
-    Returns:
-      A request message.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def verify(self, request, response, test_case):
-        """Verifies that the computed response matches the given request.
-
-    Args:
-      request: A request message.
-      response: A response message.
-      test_case: A unittest.TestCase object affording useful assertion methods.
-
-    Raises:
-      AssertionError: If the request and response do not match, indicating that
-        there was some problem executing the RPC under test.
-    """
-        raise NotImplementedError()
-
-
-class UnaryStreamTestMethodImplementation(
-        six.with_metaclass(abc.ABCMeta, test_interfaces.Method)):
-    """A controllable implementation of a unary-stream method."""
-
-    @abc.abstractmethod
-    def service(self, request, response_consumer, context, control):
-        """Services an RPC that takes one message and produces a stream of messages.
-
-    Args:
-      request: The single request message for the RPC.
-      response_consumer: A stream.Consumer to be called to accept the response
-        messages of the RPC.
-      context: A face.ServicerContext object.
-      control: A test_control.Control to control execution of this method.
-
-    Raises:
-      abandonment.Abandoned: May or may not be raised when the RPC has been
-        aborted.
-    """
-        raise NotImplementedError()
-
-
-class UnaryStreamTestMessages(six.with_metaclass(abc.ABCMeta)):
-    """A type for unary-request-stream-response message pairings."""
-
-    @abc.abstractmethod
-    def request(self):
-        """Affords a request message.
-
-    Implementations of this method should return a different message with each
-    call so that multiple test executions of the test method may be made with
-    different inputs.
-
-    Returns:
-      A request message.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def verify(self, request, responses, test_case):
-        """Verifies that the computed responses match the given request.
-
-    Args:
-      request: A request message.
-      responses: A sequence of response messages.
-      test_case: A unittest.TestCase object affording useful assertion methods.
-
-    Raises:
-      AssertionError: If the request and responses do not match, indicating that
-        there was some problem executing the RPC under test.
-    """
-        raise NotImplementedError()
-
-
-class StreamUnaryTestMethodImplementation(
-        six.with_metaclass(abc.ABCMeta, test_interfaces.Method)):
-    """A controllable implementation of a stream-unary method."""
-
-    @abc.abstractmethod
-    def service(self, response_callback, context, control):
-        """Services an RPC that takes a stream of messages and produces one message.
-
-    Args:
-      response_callback: A callback to be called to accept the response message
-        of the RPC.
-      context: A face.ServicerContext object.
-      control: A test_control.Control to control execution of this method.
-
-    Returns:
-      A stream.Consumer with which to accept the request messages of the RPC.
-        The consumer returned from this method may or may not be invoked to
-        completion: in the case of RPC abortion, RPC Framework will simply stop
-        passing messages to this object. Implementations must not assume that
-        this object will be called to completion of the request stream or even
-        called at all.
-
-    Raises:
-      abandonment.Abandoned: May or may not be raised when the RPC has been
-        aborted.
-    """
-        raise NotImplementedError()
-
-
-class StreamUnaryTestMessages(six.with_metaclass(abc.ABCMeta)):
-    """A type for stream-request-unary-response message pairings."""
-
-    @abc.abstractmethod
-    def requests(self):
-        """Affords a sequence of request messages.
-
-    Implementations of this method should return a different sequences with each
-    call so that multiple test executions of the test method may be made with
-    different inputs.
-
-    Returns:
-      A sequence of request messages.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def verify(self, requests, response, test_case):
-        """Verifies that the computed response matches the given requests.
-
-    Args:
-      requests: A sequence of request messages.
-      response: A response message.
-      test_case: A unittest.TestCase object affording useful assertion methods.
-
-    Raises:
-      AssertionError: If the requests and response do not match, indicating that
-        there was some problem executing the RPC under test.
-    """
-        raise NotImplementedError()
-
-
-class StreamStreamTestMethodImplementation(
-        six.with_metaclass(abc.ABCMeta, test_interfaces.Method)):
-    """A controllable implementation of a stream-stream method."""
-
-    @abc.abstractmethod
-    def service(self, response_consumer, context, control):
-        """Services an RPC that accepts and produces streams of messages.
-
-    Args:
-      response_consumer: A stream.Consumer to be called to accept the response
-        messages of the RPC.
-      context: A face.ServicerContext object.
-      control: A test_control.Control to control execution of this method.
-
-    Returns:
-      A stream.Consumer with which to accept the request messages of the RPC.
-        The consumer returned from this method may or may not be invoked to
-        completion: in the case of RPC abortion, RPC Framework will simply stop
-        passing messages to this object. Implementations must not assume that
-        this object will be called to completion of the request stream or even
-        called at all.
-
-    Raises:
-      abandonment.Abandoned: May or may not be raised when the RPC has been
-        aborted.
-    """
-        raise NotImplementedError()
-
-
-class StreamStreamTestMessages(six.with_metaclass(abc.ABCMeta)):
-    """A type for stream-request-stream-response message pairings."""
-
-    @abc.abstractmethod
-    def requests(self):
-        """Affords a sequence of request messages.
-
-    Implementations of this method should return a different sequences with each
-    call so that multiple test executions of the test method may be made with
-    different inputs.
-
-    Returns:
-      A sequence of request messages.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def verify(self, requests, responses, test_case):
-        """Verifies that the computed response matches the given requests.
-
-    Args:
-      requests: A sequence of request messages.
-      responses: A sequence of response messages.
-      test_case: A unittest.TestCase object affording useful assertion methods.
-
-    Raises:
-      AssertionError: If the requests and responses do not match, indicating
-        that there was some problem executing the RPC under test.
-    """
-        raise NotImplementedError()
-
-
-class TestService(six.with_metaclass(abc.ABCMeta)):
-    """A specification of implemented methods to use in tests."""
-
-    @abc.abstractmethod
-    def unary_unary_scenarios(self):
-        """Affords unary-request-unary-response test methods and their messages.
-
-    Returns:
-      A dict from method group-name pair to implementation/messages pair. The
-        first element of the pair is a UnaryUnaryTestMethodImplementation object
-        and the second element is a sequence of UnaryUnaryTestMethodMessages
-        objects.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def unary_stream_scenarios(self):
-        """Affords unary-request-stream-response test methods and their messages.
-
-    Returns:
-      A dict from method group-name pair to implementation/messages pair. The
-        first element of the pair is a UnaryStreamTestMethodImplementation
-        object and the second element is a sequence of
-        UnaryStreamTestMethodMessages objects.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def stream_unary_scenarios(self):
-        """Affords stream-request-unary-response test methods and their messages.
-
-    Returns:
-      A dict from method group-name pair to implementation/messages pair. The
-        first element of the pair is a StreamUnaryTestMethodImplementation
-        object and the second element is a sequence of
-        StreamUnaryTestMethodMessages objects.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def stream_stream_scenarios(self):
-        """Affords stream-request-stream-response test methods and their messages.
-
-    Returns:
-      A dict from method group-name pair to implementation/messages pair. The
-        first element of the pair is a StreamStreamTestMethodImplementation
-        object and the second element is a sequence of
-        StreamStreamTestMethodMessages objects.
-    """
-        raise NotImplementedError()
diff --git a/src/python/grpcio_tests/tests/unit/framework/interfaces/face/_stock_service.py b/src/python/grpcio_tests/tests/unit/framework/interfaces/face/_stock_service.py
deleted file mode 100644
index a84e02a..0000000
--- a/src/python/grpcio_tests/tests/unit/framework/interfaces/face/_stock_service.py
+++ /dev/null
@@ -1,390 +0,0 @@
-# Copyright 2015 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Examples of Python implementations of the stock.proto Stock service."""
-
-from grpc.framework.common import cardinality
-from grpc.framework.foundation import abandonment
-from grpc.framework.foundation import stream
-from tests.unit.framework.common import test_constants
-from tests.unit.framework.interfaces.face import _service
-from tests.unit._junkdrawer import stock_pb2
-
-_STOCK_GROUP_NAME = 'Stock'
-_SYMBOL_FORMAT = 'test symbol:%03d'
-
-# A test-appropriate security-pricing function. :-P
-_price = lambda symbol_name: float(hash(symbol_name) % 4096)
-
-
-def _get_last_trade_price(stock_request, stock_reply_callback, control, active):
-    """A unary-request, unary-response test method."""
-    control.control()
-    if active():
-        stock_reply_callback(
-            stock_pb2.StockReply(
-                symbol=stock_request.symbol,
-                price=_price(stock_request.symbol)))
-    else:
-        raise abandonment.Abandoned()
-
-
-def _get_last_trade_price_multiple(stock_reply_consumer, control, active):
-    """A stream-request, stream-response test method."""
-
-    def stock_reply_for_stock_request(stock_request):
-        control.control()
-        if active():
-            return stock_pb2.StockReply(
-                symbol=stock_request.symbol, price=_price(stock_request.symbol))
-        else:
-            raise abandonment.Abandoned()
-
-    class StockRequestConsumer(stream.Consumer):
-
-        def consume(self, stock_request):
-            stock_reply_consumer.consume(
-                stock_reply_for_stock_request(stock_request))
-
-        def terminate(self):
-            control.control()
-            stock_reply_consumer.terminate()
-
-        def consume_and_terminate(self, stock_request):
-            stock_reply_consumer.consume_and_terminate(
-                stock_reply_for_stock_request(stock_request))
-
-    return StockRequestConsumer()
-
-
-def _watch_future_trades(stock_request, stock_reply_consumer, control, active):
-    """A unary-request, stream-response test method."""
-    base_price = _price(stock_request.symbol)
-    for index in range(stock_request.num_trades_to_watch):
-        control.control()
-        if active():
-            stock_reply_consumer.consume(
-                stock_pb2.StockReply(
-                    symbol=stock_request.symbol, price=base_price + index))
-        else:
-            raise abandonment.Abandoned()
-    stock_reply_consumer.terminate()
-
-
-def _get_highest_trade_price(stock_reply_callback, control, active):
-    """A stream-request, unary-response test method."""
-
-    class StockRequestConsumer(stream.Consumer):
-        """Keeps an ongoing record of the most valuable symbol yet consumed."""
-
-        def __init__(self):
-            self._symbol = None
-            self._price = None
-
-        def consume(self, stock_request):
-            control.control()
-            if active():
-                if self._price is None:
-                    self._symbol = stock_request.symbol
-                    self._price = _price(stock_request.symbol)
-                else:
-                    candidate_price = _price(stock_request.symbol)
-                    if self._price < candidate_price:
-                        self._symbol = stock_request.symbol
-                        self._price = candidate_price
-
-        def terminate(self):
-            control.control()
-            if active():
-                if self._symbol is None:
-                    raise ValueError()
-                else:
-                    stock_reply_callback(
-                        stock_pb2.StockReply(
-                            symbol=self._symbol, price=self._price))
-                    self._symbol = None
-                    self._price = None
-
-        def consume_and_terminate(self, stock_request):
-            control.control()
-            if active():
-                if self._price is None:
-                    stock_reply_callback(
-                        stock_pb2.StockReply(
-                            symbol=stock_request.symbol,
-                            price=_price(stock_request.symbol)))
-                else:
-                    candidate_price = _price(stock_request.symbol)
-                    if self._price < candidate_price:
-                        stock_reply_callback(
-                            stock_pb2.StockReply(
-                                symbol=stock_request.symbol,
-                                price=candidate_price))
-                    else:
-                        stock_reply_callback(
-                            stock_pb2.StockReply(
-                                symbol=self._symbol, price=self._price))
-
-                self._symbol = None
-                self._price = None
-
-    return StockRequestConsumer()
-
-
-class GetLastTradePrice(_service.UnaryUnaryTestMethodImplementation):
-    """GetLastTradePrice for use in tests."""
-
-    def group(self):
-        return _STOCK_GROUP_NAME
-
-    def name(self):
-        return 'GetLastTradePrice'
-
-    def cardinality(self):
-        return cardinality.Cardinality.UNARY_UNARY
-
-    def request_class(self):
-        return stock_pb2.StockRequest
-
-    def response_class(self):
-        return stock_pb2.StockReply
-
-    def serialize_request(self, request):
-        return request.SerializeToString()
-
-    def deserialize_request(self, serialized_request):
-        return stock_pb2.StockRequest.FromString(serialized_request)
-
-    def serialize_response(self, response):
-        return response.SerializeToString()
-
-    def deserialize_response(self, serialized_response):
-        return stock_pb2.StockReply.FromString(serialized_response)
-
-    def service(self, request, response_callback, context, control):
-        _get_last_trade_price(request, response_callback, control,
-                              context.is_active)
-
-
-class GetLastTradePriceMessages(_service.UnaryUnaryTestMessages):
-
-    def __init__(self):
-        self._index = 0
-
-    def request(self):
-        symbol = _SYMBOL_FORMAT % self._index
-        self._index += 1
-        return stock_pb2.StockRequest(symbol=symbol)
-
-    def verify(self, request, response, test_case):
-        test_case.assertEqual(request.symbol, response.symbol)
-        test_case.assertEqual(_price(request.symbol), response.price)
-
-
-class GetLastTradePriceMultiple(_service.StreamStreamTestMethodImplementation):
-    """GetLastTradePriceMultiple for use in tests."""
-
-    def group(self):
-        return _STOCK_GROUP_NAME
-
-    def name(self):
-        return 'GetLastTradePriceMultiple'
-
-    def cardinality(self):
-        return cardinality.Cardinality.STREAM_STREAM
-
-    def request_class(self):
-        return stock_pb2.StockRequest
-
-    def response_class(self):
-        return stock_pb2.StockReply
-
-    def serialize_request(self, request):
-        return request.SerializeToString()
-
-    def deserialize_request(self, serialized_request):
-        return stock_pb2.StockRequest.FromString(serialized_request)
-
-    def serialize_response(self, response):
-        return response.SerializeToString()
-
-    def deserialize_response(self, serialized_response):
-        return stock_pb2.StockReply.FromString(serialized_response)
-
-    def service(self, response_consumer, context, control):
-        return _get_last_trade_price_multiple(response_consumer, control,
-                                              context.is_active)
-
-
-class GetLastTradePriceMultipleMessages(_service.StreamStreamTestMessages):
-    """Pairs of message streams for use with GetLastTradePriceMultiple."""
-
-    def __init__(self):
-        self._index = 0
-
-    def requests(self):
-        base_index = self._index
-        self._index += 1
-        return [
-            stock_pb2.StockRequest(symbol=_SYMBOL_FORMAT % (base_index + index))
-            for index in range(test_constants.STREAM_LENGTH)
-        ]
-
-    def verify(self, requests, responses, test_case):
-        test_case.assertEqual(len(requests), len(responses))
-        for stock_request, stock_reply in zip(requests, responses):
-            test_case.assertEqual(stock_request.symbol, stock_reply.symbol)
-            test_case.assertEqual(
-                _price(stock_request.symbol), stock_reply.price)
-
-
-class WatchFutureTrades(_service.UnaryStreamTestMethodImplementation):
-    """WatchFutureTrades for use in tests."""
-
-    def group(self):
-        return _STOCK_GROUP_NAME
-
-    def name(self):
-        return 'WatchFutureTrades'
-
-    def cardinality(self):
-        return cardinality.Cardinality.UNARY_STREAM
-
-    def request_class(self):
-        return stock_pb2.StockRequest
-
-    def response_class(self):
-        return stock_pb2.StockReply
-
-    def serialize_request(self, request):
-        return request.SerializeToString()
-
-    def deserialize_request(self, serialized_request):
-        return stock_pb2.StockRequest.FromString(serialized_request)
-
-    def serialize_response(self, response):
-        return response.SerializeToString()
-
-    def deserialize_response(self, serialized_response):
-        return stock_pb2.StockReply.FromString(serialized_response)
-
-    def service(self, request, response_consumer, context, control):
-        _watch_future_trades(request, response_consumer, control,
-                             context.is_active)
-
-
-class WatchFutureTradesMessages(_service.UnaryStreamTestMessages):
-    """Pairs of a single request message and a sequence of response messages."""
-
-    def __init__(self):
-        self._index = 0
-
-    def request(self):
-        symbol = _SYMBOL_FORMAT % self._index
-        self._index += 1
-        return stock_pb2.StockRequest(
-            symbol=symbol, num_trades_to_watch=test_constants.STREAM_LENGTH)
-
-    def verify(self, request, responses, test_case):
-        test_case.assertEqual(test_constants.STREAM_LENGTH, len(responses))
-        base_price = _price(request.symbol)
-        for index, response in enumerate(responses):
-            test_case.assertEqual(base_price + index, response.price)
-
-
-class GetHighestTradePrice(_service.StreamUnaryTestMethodImplementation):
-    """GetHighestTradePrice for use in tests."""
-
-    def group(self):
-        return _STOCK_GROUP_NAME
-
-    def name(self):
-        return 'GetHighestTradePrice'
-
-    def cardinality(self):
-        return cardinality.Cardinality.STREAM_UNARY
-
-    def request_class(self):
-        return stock_pb2.StockRequest
-
-    def response_class(self):
-        return stock_pb2.StockReply
-
-    def serialize_request(self, request):
-        return request.SerializeToString()
-
-    def deserialize_request(self, serialized_request):
-        return stock_pb2.StockRequest.FromString(serialized_request)
-
-    def serialize_response(self, response):
-        return response.SerializeToString()
-
-    def deserialize_response(self, serialized_response):
-        return stock_pb2.StockReply.FromString(serialized_response)
-
-    def service(self, response_callback, context, control):
-        return _get_highest_trade_price(response_callback, control,
-                                        context.is_active)
-
-
-class GetHighestTradePriceMessages(_service.StreamUnaryTestMessages):
-
-    def requests(self):
-        return [
-            stock_pb2.StockRequest(symbol=_SYMBOL_FORMAT % index)
-            for index in range(test_constants.STREAM_LENGTH)
-        ]
-
-    def verify(self, requests, response, test_case):
-        price = None
-        symbol = None
-        for stock_request in requests:
-            current_symbol = stock_request.symbol
-            current_price = _price(current_symbol)
-            if price is None or price < current_price:
-                price = current_price
-                symbol = current_symbol
-        test_case.assertEqual(price, response.price)
-        test_case.assertEqual(symbol, response.symbol)
-
-
-class StockTestService(_service.TestService):
-    """A corpus of test data with one method of each RPC cardinality."""
-
-    def unary_unary_scenarios(self):
-        return {
-            (_STOCK_GROUP_NAME, 'GetLastTradePrice'):
-            (GetLastTradePrice(), [GetLastTradePriceMessages()]),
-        }
-
-    def unary_stream_scenarios(self):
-        return {
-            (_STOCK_GROUP_NAME, 'WatchFutureTrades'):
-            (WatchFutureTrades(), [WatchFutureTradesMessages()]),
-        }
-
-    def stream_unary_scenarios(self):
-        return {
-            (_STOCK_GROUP_NAME, 'GetHighestTradePrice'):
-            (GetHighestTradePrice(), [GetHighestTradePriceMessages()])
-        }
-
-    def stream_stream_scenarios(self):
-        return {
-            (_STOCK_GROUP_NAME, 'GetLastTradePriceMultiple'):
-            (GetLastTradePriceMultiple(),
-             [GetLastTradePriceMultipleMessages()]),
-        }
-
-
-STOCK_TEST_SERVICE = StockTestService()
diff --git a/src/python/grpcio_tests/tests/unit/framework/interfaces/face/test_cases.py b/src/python/grpcio_tests/tests/unit/framework/interfaces/face/test_cases.py
deleted file mode 100644
index cff4b7c..0000000
--- a/src/python/grpcio_tests/tests/unit/framework/interfaces/face/test_cases.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# Copyright 2015 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Tools for creating tests of implementations of the Face layer."""
-
-# unittest is referenced from specification in this module.
-import unittest  # pylint: disable=unused-import
-
-# test_interfaces is referenced from specification in this module.
-from tests.unit.framework.interfaces.face import _blocking_invocation_inline_service
-from tests.unit.framework.interfaces.face import _future_invocation_asynchronous_event_service
-from tests.unit.framework.interfaces.face import _invocation
-from tests.unit.framework.interfaces.face import test_interfaces  # pylint: disable=unused-import
-
-_TEST_CASE_SUPERCLASSES = (
-    _blocking_invocation_inline_service.TestCase,
-    _future_invocation_asynchronous_event_service.TestCase,
-)
-
-
-def test_cases(implementation):
-    """Creates unittest.TestCase classes for a given Face layer implementation.
-
-  Args:
-    implementation: A test_interfaces.Implementation specifying creation and
-      destruction of a given Face layer implementation.
-
-  Returns:
-    A sequence of subclasses of unittest.TestCase defining tests of the
-      specified Face layer implementation.
-  """
-    test_case_classes = []
-    for invoker_constructor in _invocation.invoker_constructors():
-        for super_class in _TEST_CASE_SUPERCLASSES:
-            test_case_classes.append(
-                type(
-                    invoker_constructor.name() + super_class.NAME,
-                    (super_class,), {
-                        'implementation': implementation,
-                        'invoker_constructor': invoker_constructor,
-                        '__module__': implementation.__module__,
-                    }))
-    return test_case_classes
diff --git a/src/python/grpcio_tests/tests/unit/framework/interfaces/face/test_interfaces.py b/src/python/grpcio_tests/tests/unit/framework/interfaces/face/test_interfaces.py
deleted file mode 100644
index d0de8e1..0000000
--- a/src/python/grpcio_tests/tests/unit/framework/interfaces/face/test_interfaces.py
+++ /dev/null
@@ -1,212 +0,0 @@
-# Copyright 2015 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Interfaces used in tests of implementations of the Face layer."""
-
-import abc
-
-import six
-
-from grpc.framework.common import cardinality  # pylint: disable=unused-import
-from grpc.framework.interfaces.face import face  # pylint: disable=unused-import
-
-
-class Method(six.with_metaclass(abc.ABCMeta)):
-    """Specifies a method to be used in tests."""
-
-    @abc.abstractmethod
-    def group(self):
-        """Identify the group of the method.
-
-    Returns:
-      The group of the method.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def name(self):
-        """Identify the name of the method.
-
-    Returns:
-      The name of the method.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def cardinality(self):
-        """Identify the cardinality of the method.
-
-    Returns:
-      A cardinality.Cardinality value describing the streaming semantics of the
-        method.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def request_class(self):
-        """Identify the class used for the method's request objects.
-
-    Returns:
-      The class object of the class to which the method's request objects
-        belong.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def response_class(self):
-        """Identify the class used for the method's response objects.
-
-    Returns:
-      The class object of the class to which the method's response objects
-        belong.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def serialize_request(self, request):
-        """Serialize the given request object.
-
-    Args:
-      request: A request object appropriate for this method.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def deserialize_request(self, serialized_request):
-        """Synthesize a request object from a given bytestring.
-
-    Args:
-      serialized_request: A bytestring deserializable into a request object
-        appropriate for this method.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def serialize_response(self, response):
-        """Serialize the given response object.
-
-    Args:
-      response: A response object appropriate for this method.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def deserialize_response(self, serialized_response):
-        """Synthesize a response object from a given bytestring.
-
-    Args:
-      serialized_response: A bytestring deserializable into a response object
-        appropriate for this method.
-    """
-        raise NotImplementedError()
-
-
-class Implementation(six.with_metaclass(abc.ABCMeta)):
-    """Specifies an implementation of the Face layer."""
-
-    @abc.abstractmethod
-    def instantiate(self, methods, method_implementations,
-                    multi_method_implementation):
-        """Instantiates the Face layer implementation to be used in a test.
-
-    Args:
-      methods: A sequence of Method objects describing the methods available to
-        be called during the test.
-      method_implementations: A dictionary from group-name pair to
-        face.MethodImplementation object specifying implementation of a method.
-      multi_method_implementation: A face.MultiMethodImplementation or None.
-
-    Returns:
-      A sequence of length three the first element of which is a
-        face.GenericStub, the second element of which is dictionary from groups
-        to face.DynamicStubs affording invocation of the group's methods, and
-        the third element of which is an arbitrary memo object to be kept and
-        passed to destantiate at the conclusion of the test. The returned stubs
-        must be backed by the provided implementations.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def destantiate(self, memo):
-        """Destroys the Face layer implementation under test.
-
-    Args:
-      memo: The object from the third position of the return value of a call to
-        instantiate.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def invocation_metadata(self):
-        """Provides the metadata to be used when invoking a test RPC.
-
-    Returns:
-      An object to use as the supplied-at-invocation-time metadata in a test
-        RPC.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def initial_metadata(self):
-        """Provides the metadata for use as a test RPC's first servicer metadata.
-
-    Returns:
-      An object to use as the from-the-servicer-before-responses metadata in a
-        test RPC.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def terminal_metadata(self):
-        """Provides the metadata for use as a test RPC's second servicer metadata.
-
-    Returns:
-      An object to use as the from-the-servicer-after-all-responses metadata in
-        a test RPC.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def code(self):
-        """Provides the value for use as a test RPC's code.
-
-    Returns:
-      An object to use as the from-the-servicer code in a test RPC.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def details(self):
-        """Provides the value for use as a test RPC's details.
-
-    Returns:
-      An object to use as the from-the-servicer details in a test RPC.
-    """
-        raise NotImplementedError()
-
-    @abc.abstractmethod
-    def metadata_transmitted(self, original_metadata, transmitted_metadata):
-        """Identifies whether or not metadata was properly transmitted.
-
-    Args:
-      original_metadata: A metadata value passed to the Face interface
-        implementation under test.
-      transmitted_metadata: The same metadata value after having been
-        transmitted via an RPC performed by the Face interface implementation
-          under test.
-
-    Returns:
-      Whether or not the metadata was properly transmitted by the Face interface
-        implementation under test.
-    """
-        raise NotImplementedError()
diff --git a/src/ruby/bin/apis/pubsub_demo.rb b/src/ruby/bin/apis/pubsub_demo.rb
index 6f15565..c565771 100755
--- a/src/ruby/bin/apis/pubsub_demo.rb
+++ b/src/ruby/bin/apis/pubsub_demo.rb
@@ -193,7 +193,7 @@
 Args = Struct.new(:host, :port, :action, :project_id, :topic_name,
                   :sub_name)
 
-# validates the the command line options, returning them as an Arg.
+# validates the command line options, returning them as an Arg.
 def parse_args
   args = Args.new('pubsub-staging.googleapis.com',
                    443, 'list_some_topics', 'stoked-keyword-656')
diff --git a/src/ruby/ext/grpc/extconf.rb b/src/ruby/ext/grpc/extconf.rb
index c1a0c56..e8e87e4 100644
--- a/src/ruby/ext/grpc/extconf.rb
+++ b/src/ruby/ext/grpc/extconf.rb
@@ -94,7 +94,6 @@
 $CFLAGS << ' -Wall '
 $CFLAGS << ' -Wextra '
 $CFLAGS << ' -pedantic '
-$CFLAGS << ' -Wno-format '
 
 output = File.join('grpc', 'grpc_c')
 puts 'Generating Makefile for ' + output
diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c
index 1d11a53..e8bfeb3 100644
--- a/src/ruby/ext/grpc/rb_channel.c
+++ b/src/ruby/ext/grpc/rb_channel.c
@@ -362,8 +362,8 @@
 
 /* Wait until the channel's connectivity state becomes different from
  * "last_state", or "deadline" expires.
- * Returns true if the the channel's connectivity state becomes
- * different from "last_state" within "deadline".
+ * Returns true if the channel's connectivity state becomes different
+ * from "last_state" within "deadline".
  * Returns false if "deadline" expires before the channel's connectivity
  * state changes from "last_state".
  * */
@@ -427,16 +427,15 @@
     parent_call = grpc_rb_get_wrapped_call(parent);
   }
 
-  cq = grpc_completion_queue_create_for_pluck(NULL);
   TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
   if (wrapper->bg_wrapped == NULL) {
     rb_raise(rb_eRuntimeError, "closed!");
     return Qnil;
   }
 
+  cq = grpc_completion_queue_create_for_pluck(NULL);
   method_slice =
       grpc_slice_from_copied_buffer(RSTRING_PTR(method), RSTRING_LEN(method));
-
   call = grpc_channel_create_call(wrapper->bg_wrapped->channel, parent_call,
                                   flags, cq, method_slice, host_slice_ptr,
                                   grpc_rb_time_timeval(deadline,
diff --git a/src/ruby/ext/grpc/rb_compression_options.c b/src/ruby/ext/grpc/rb_compression_options.c
index a7e3709..4ba6991 100644
--- a/src/ruby/ext/grpc/rb_compression_options.c
+++ b/src/ruby/ext/grpc/rb_compression_options.c
@@ -23,11 +23,12 @@
 #include "rb_grpc_imports.generated.h"
 
 #include <grpc/compression.h>
-#include <grpc/compression_ruby.h>
 #include <grpc/grpc.h>
 #include <grpc/impl/codegen/compression_types.h>
 #include <grpc/impl/codegen/grpc_types.h>
 #include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
 #include <string.h>
 
 #include "rb_grpc.h"
@@ -160,7 +161,6 @@
     grpc_compression_algorithm* algorithm_value, VALUE algorithm_name) {
   grpc_slice name_slice;
   VALUE algorithm_name_as_string = Qnil;
-  char* tmp_str = NULL;
 
   Check_Type(algorithm_name, T_SYMBOL);
 
@@ -175,9 +175,18 @@
   /* Raise an error if the name isn't recognized as a compression algorithm by
    * the algorithm parse function
    * in GRPC core. */
-  if (!grpc_compression_algorithm_parse_ruby(name_slice, algorithm_value)) {
-    tmp_str = grpc_slice_to_c_string(name_slice);
-    rb_raise(rb_eNameError, "Invalid compression algorithm name: %s", tmp_str);
+  if (!grpc_compression_algorithm_parse(name_slice, algorithm_value)) {
+    char* name_slice_str = grpc_slice_to_c_string(name_slice);
+    char* error_message_str = NULL;
+    VALUE error_message_ruby_str = Qnil;
+    GPR_ASSERT(gpr_asprintf(&error_message_str,
+                            "Invalid compression algorithm name: %s",
+                            name_slice_str) != -1);
+    gpr_free(name_slice_str);
+    error_message_ruby_str =
+        rb_str_new(error_message_str, strlen(error_message_str));
+    gpr_free(error_message_str);
+    rb_raise(rb_eNameError, "%s", StringValueCStr(error_message_ruby_str));
   }
 
   grpc_slice_unref(name_slice);
@@ -287,7 +296,7 @@
     grpc_compression_algorithm internal_value) {
   char* algorithm_name = NULL;
 
-  if (!grpc_compression_algorithm_name_ruby(internal_value, &algorithm_name)) {
+  if (!grpc_compression_algorithm_name(internal_value, &algorithm_name)) {
     rb_raise(rb_eArgError, "Failed to convert algorithm value to name");
   }
 
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
index 0734fb3..a12819e 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
@@ -31,8 +31,6 @@
 grpc_compression_options_enable_algorithm_type grpc_compression_options_enable_algorithm_import;
 grpc_compression_options_disable_algorithm_type grpc_compression_options_disable_algorithm_import;
 grpc_compression_options_is_algorithm_enabled_type grpc_compression_options_is_algorithm_enabled_import;
-grpc_compression_algorithm_parse_ruby_type grpc_compression_algorithm_parse_ruby_import;
-grpc_compression_algorithm_name_ruby_type grpc_compression_algorithm_name_ruby_import;
 grpc_metadata_array_init_type grpc_metadata_array_init_import;
 grpc_metadata_array_destroy_type grpc_metadata_array_destroy_import;
 grpc_call_details_init_type grpc_call_details_init_import;
@@ -70,6 +68,8 @@
 grpc_insecure_channel_create_type grpc_insecure_channel_create_import;
 grpc_lame_client_channel_create_type grpc_lame_client_channel_create_import;
 grpc_channel_destroy_type grpc_channel_destroy_import;
+grpc_channel_get_trace_type grpc_channel_get_trace_import;
+grpc_channel_get_uuid_type grpc_channel_get_uuid_import;
 grpc_call_cancel_type grpc_call_cancel_import;
 grpc_call_cancel_with_status_type grpc_call_cancel_with_status_import;
 grpc_call_ref_type grpc_call_ref_import;
@@ -108,6 +108,9 @@
 grpc_auth_context_add_property_type grpc_auth_context_add_property_import;
 grpc_auth_context_add_cstring_property_type grpc_auth_context_add_cstring_property_import;
 grpc_auth_context_set_peer_identity_property_name_type grpc_auth_context_set_peer_identity_property_name_import;
+grpc_ssl_session_cache_create_lru_type grpc_ssl_session_cache_create_lru_import;
+grpc_ssl_session_cache_destroy_type grpc_ssl_session_cache_destroy_import;
+grpc_ssl_session_cache_create_channel_arg_type grpc_ssl_session_cache_create_channel_arg_import;
 grpc_channel_credentials_release_type grpc_channel_credentials_release_import;
 grpc_google_default_credentials_create_type grpc_google_default_credentials_create_import;
 grpc_set_ssl_roots_override_callback_type grpc_set_ssl_roots_override_callback_import;
@@ -201,27 +204,8 @@
 gpr_free_aligned_type gpr_free_aligned_import;
 gpr_set_allocation_functions_type gpr_set_allocation_functions_import;
 gpr_get_allocation_functions_type gpr_get_allocation_functions_import;
-gpr_avl_create_type gpr_avl_create_import;
-gpr_avl_ref_type gpr_avl_ref_import;
-gpr_avl_unref_type gpr_avl_unref_import;
-gpr_avl_add_type gpr_avl_add_import;
-gpr_avl_remove_type gpr_avl_remove_import;
-gpr_avl_get_type gpr_avl_get_import;
-gpr_avl_maybe_get_type gpr_avl_maybe_get_import;
-gpr_avl_is_empty_type gpr_avl_is_empty_import;
-gpr_cmdline_create_type gpr_cmdline_create_import;
-gpr_cmdline_add_int_type gpr_cmdline_add_int_import;
-gpr_cmdline_add_flag_type gpr_cmdline_add_flag_import;
-gpr_cmdline_add_string_type gpr_cmdline_add_string_import;
-gpr_cmdline_on_extra_arg_type gpr_cmdline_on_extra_arg_import;
-gpr_cmdline_set_survive_failure_type gpr_cmdline_set_survive_failure_import;
-gpr_cmdline_parse_type gpr_cmdline_parse_import;
-gpr_cmdline_destroy_type gpr_cmdline_destroy_import;
-gpr_cmdline_usage_string_type gpr_cmdline_usage_string_import;
 gpr_cpu_num_cores_type gpr_cpu_num_cores_import;
 gpr_cpu_current_cpu_type gpr_cpu_current_cpu_import;
-gpr_join_host_port_type gpr_join_host_port_import;
-gpr_split_host_port_type gpr_split_host_port_import;
 gpr_log_severity_string_type gpr_log_severity_string_import;
 gpr_log_type gpr_log_import;
 gpr_log_message_type gpr_log_message_import;
@@ -231,11 +215,6 @@
 gpr_format_message_type gpr_format_message_import;
 gpr_strdup_type gpr_strdup_import;
 gpr_asprintf_type gpr_asprintf_import;
-gpr_subprocess_binary_extension_type gpr_subprocess_binary_extension_import;
-gpr_subprocess_create_type gpr_subprocess_create_import;
-gpr_subprocess_destroy_type gpr_subprocess_destroy_import;
-gpr_subprocess_join_type gpr_subprocess_join_import;
-gpr_subprocess_interrupt_type gpr_subprocess_interrupt_import;
 gpr_mu_init_type gpr_mu_init_import;
 gpr_mu_destroy_type gpr_mu_destroy_import;
 gpr_mu_lock_type gpr_mu_lock_import;
@@ -260,14 +239,7 @@
 gpr_stats_init_type gpr_stats_init_import;
 gpr_stats_inc_type gpr_stats_inc_import;
 gpr_stats_read_type gpr_stats_read_import;
-gpr_thd_new_type gpr_thd_new_import;
-gpr_thd_options_default_type gpr_thd_options_default_import;
-gpr_thd_options_set_detached_type gpr_thd_options_set_detached_import;
-gpr_thd_options_set_joinable_type gpr_thd_options_set_joinable_import;
-gpr_thd_options_is_detached_type gpr_thd_options_is_detached_import;
-gpr_thd_options_is_joinable_type gpr_thd_options_is_joinable_import;
 gpr_thd_currentid_type gpr_thd_currentid_import;
-gpr_thd_join_type gpr_thd_join_import;
 gpr_time_0_type gpr_time_0_import;
 gpr_inf_future_type gpr_inf_future_import;
 gpr_inf_past_type gpr_inf_past_import;
@@ -300,8 +272,6 @@
   grpc_compression_options_enable_algorithm_import = (grpc_compression_options_enable_algorithm_type) GetProcAddress(library, "grpc_compression_options_enable_algorithm");
   grpc_compression_options_disable_algorithm_import = (grpc_compression_options_disable_algorithm_type) GetProcAddress(library, "grpc_compression_options_disable_algorithm");
   grpc_compression_options_is_algorithm_enabled_import = (grpc_compression_options_is_algorithm_enabled_type) GetProcAddress(library, "grpc_compression_options_is_algorithm_enabled");
-  grpc_compression_algorithm_parse_ruby_import = (grpc_compression_algorithm_parse_ruby_type) GetProcAddress(library, "grpc_compression_algorithm_parse_ruby");
-  grpc_compression_algorithm_name_ruby_import = (grpc_compression_algorithm_name_ruby_type) GetProcAddress(library, "grpc_compression_algorithm_name_ruby");
   grpc_metadata_array_init_import = (grpc_metadata_array_init_type) GetProcAddress(library, "grpc_metadata_array_init");
   grpc_metadata_array_destroy_import = (grpc_metadata_array_destroy_type) GetProcAddress(library, "grpc_metadata_array_destroy");
   grpc_call_details_init_import = (grpc_call_details_init_type) GetProcAddress(library, "grpc_call_details_init");
@@ -339,6 +309,8 @@
   grpc_insecure_channel_create_import = (grpc_insecure_channel_create_type) GetProcAddress(library, "grpc_insecure_channel_create");
   grpc_lame_client_channel_create_import = (grpc_lame_client_channel_create_type) GetProcAddress(library, "grpc_lame_client_channel_create");
   grpc_channel_destroy_import = (grpc_channel_destroy_type) GetProcAddress(library, "grpc_channel_destroy");
+  grpc_channel_get_trace_import = (grpc_channel_get_trace_type) GetProcAddress(library, "grpc_channel_get_trace");
+  grpc_channel_get_uuid_import = (grpc_channel_get_uuid_type) GetProcAddress(library, "grpc_channel_get_uuid");
   grpc_call_cancel_import = (grpc_call_cancel_type) GetProcAddress(library, "grpc_call_cancel");
   grpc_call_cancel_with_status_import = (grpc_call_cancel_with_status_type) GetProcAddress(library, "grpc_call_cancel_with_status");
   grpc_call_ref_import = (grpc_call_ref_type) GetProcAddress(library, "grpc_call_ref");
@@ -377,6 +349,9 @@
   grpc_auth_context_add_property_import = (grpc_auth_context_add_property_type) GetProcAddress(library, "grpc_auth_context_add_property");
   grpc_auth_context_add_cstring_property_import = (grpc_auth_context_add_cstring_property_type) GetProcAddress(library, "grpc_auth_context_add_cstring_property");
   grpc_auth_context_set_peer_identity_property_name_import = (grpc_auth_context_set_peer_identity_property_name_type) GetProcAddress(library, "grpc_auth_context_set_peer_identity_property_name");
+  grpc_ssl_session_cache_create_lru_import = (grpc_ssl_session_cache_create_lru_type) GetProcAddress(library, "grpc_ssl_session_cache_create_lru");
+  grpc_ssl_session_cache_destroy_import = (grpc_ssl_session_cache_destroy_type) GetProcAddress(library, "grpc_ssl_session_cache_destroy");
+  grpc_ssl_session_cache_create_channel_arg_import = (grpc_ssl_session_cache_create_channel_arg_type) GetProcAddress(library, "grpc_ssl_session_cache_create_channel_arg");
   grpc_channel_credentials_release_import = (grpc_channel_credentials_release_type) GetProcAddress(library, "grpc_channel_credentials_release");
   grpc_google_default_credentials_create_import = (grpc_google_default_credentials_create_type) GetProcAddress(library, "grpc_google_default_credentials_create");
   grpc_set_ssl_roots_override_callback_import = (grpc_set_ssl_roots_override_callback_type) GetProcAddress(library, "grpc_set_ssl_roots_override_callback");
@@ -470,27 +445,8 @@
   gpr_free_aligned_import = (gpr_free_aligned_type) GetProcAddress(library, "gpr_free_aligned");
   gpr_set_allocation_functions_import = (gpr_set_allocation_functions_type) GetProcAddress(library, "gpr_set_allocation_functions");
   gpr_get_allocation_functions_import = (gpr_get_allocation_functions_type) GetProcAddress(library, "gpr_get_allocation_functions");
-  gpr_avl_create_import = (gpr_avl_create_type) GetProcAddress(library, "gpr_avl_create");
-  gpr_avl_ref_import = (gpr_avl_ref_type) GetProcAddress(library, "gpr_avl_ref");
-  gpr_avl_unref_import = (gpr_avl_unref_type) GetProcAddress(library, "gpr_avl_unref");
-  gpr_avl_add_import = (gpr_avl_add_type) GetProcAddress(library, "gpr_avl_add");
-  gpr_avl_remove_import = (gpr_avl_remove_type) GetProcAddress(library, "gpr_avl_remove");
-  gpr_avl_get_import = (gpr_avl_get_type) GetProcAddress(library, "gpr_avl_get");
-  gpr_avl_maybe_get_import = (gpr_avl_maybe_get_type) GetProcAddress(library, "gpr_avl_maybe_get");
-  gpr_avl_is_empty_import = (gpr_avl_is_empty_type) GetProcAddress(library, "gpr_avl_is_empty");
-  gpr_cmdline_create_import = (gpr_cmdline_create_type) GetProcAddress(library, "gpr_cmdline_create");
-  gpr_cmdline_add_int_import = (gpr_cmdline_add_int_type) GetProcAddress(library, "gpr_cmdline_add_int");
-  gpr_cmdline_add_flag_import = (gpr_cmdline_add_flag_type) GetProcAddress(library, "gpr_cmdline_add_flag");
-  gpr_cmdline_add_string_import = (gpr_cmdline_add_string_type) GetProcAddress(library, "gpr_cmdline_add_string");
-  gpr_cmdline_on_extra_arg_import = (gpr_cmdline_on_extra_arg_type) GetProcAddress(library, "gpr_cmdline_on_extra_arg");
-  gpr_cmdline_set_survive_failure_import = (gpr_cmdline_set_survive_failure_type) GetProcAddress(library, "gpr_cmdline_set_survive_failure");
-  gpr_cmdline_parse_import = (gpr_cmdline_parse_type) GetProcAddress(library, "gpr_cmdline_parse");
-  gpr_cmdline_destroy_import = (gpr_cmdline_destroy_type) GetProcAddress(library, "gpr_cmdline_destroy");
-  gpr_cmdline_usage_string_import = (gpr_cmdline_usage_string_type) GetProcAddress(library, "gpr_cmdline_usage_string");
   gpr_cpu_num_cores_import = (gpr_cpu_num_cores_type) GetProcAddress(library, "gpr_cpu_num_cores");
   gpr_cpu_current_cpu_import = (gpr_cpu_current_cpu_type) GetProcAddress(library, "gpr_cpu_current_cpu");
-  gpr_join_host_port_import = (gpr_join_host_port_type) GetProcAddress(library, "gpr_join_host_port");
-  gpr_split_host_port_import = (gpr_split_host_port_type) GetProcAddress(library, "gpr_split_host_port");
   gpr_log_severity_string_import = (gpr_log_severity_string_type) GetProcAddress(library, "gpr_log_severity_string");
   gpr_log_import = (gpr_log_type) GetProcAddress(library, "gpr_log");
   gpr_log_message_import = (gpr_log_message_type) GetProcAddress(library, "gpr_log_message");
@@ -500,11 +456,6 @@
   gpr_format_message_import = (gpr_format_message_type) GetProcAddress(library, "gpr_format_message");
   gpr_strdup_import = (gpr_strdup_type) GetProcAddress(library, "gpr_strdup");
   gpr_asprintf_import = (gpr_asprintf_type) GetProcAddress(library, "gpr_asprintf");
-  gpr_subprocess_binary_extension_import = (gpr_subprocess_binary_extension_type) GetProcAddress(library, "gpr_subprocess_binary_extension");
-  gpr_subprocess_create_import = (gpr_subprocess_create_type) GetProcAddress(library, "gpr_subprocess_create");
-  gpr_subprocess_destroy_import = (gpr_subprocess_destroy_type) GetProcAddress(library, "gpr_subprocess_destroy");
-  gpr_subprocess_join_import = (gpr_subprocess_join_type) GetProcAddress(library, "gpr_subprocess_join");
-  gpr_subprocess_interrupt_import = (gpr_subprocess_interrupt_type) GetProcAddress(library, "gpr_subprocess_interrupt");
   gpr_mu_init_import = (gpr_mu_init_type) GetProcAddress(library, "gpr_mu_init");
   gpr_mu_destroy_import = (gpr_mu_destroy_type) GetProcAddress(library, "gpr_mu_destroy");
   gpr_mu_lock_import = (gpr_mu_lock_type) GetProcAddress(library, "gpr_mu_lock");
@@ -529,14 +480,7 @@
   gpr_stats_init_import = (gpr_stats_init_type) GetProcAddress(library, "gpr_stats_init");
   gpr_stats_inc_import = (gpr_stats_inc_type) GetProcAddress(library, "gpr_stats_inc");
   gpr_stats_read_import = (gpr_stats_read_type) GetProcAddress(library, "gpr_stats_read");
-  gpr_thd_new_import = (gpr_thd_new_type) GetProcAddress(library, "gpr_thd_new");
-  gpr_thd_options_default_import = (gpr_thd_options_default_type) GetProcAddress(library, "gpr_thd_options_default");
-  gpr_thd_options_set_detached_import = (gpr_thd_options_set_detached_type) GetProcAddress(library, "gpr_thd_options_set_detached");
-  gpr_thd_options_set_joinable_import = (gpr_thd_options_set_joinable_type) GetProcAddress(library, "gpr_thd_options_set_joinable");
-  gpr_thd_options_is_detached_import = (gpr_thd_options_is_detached_type) GetProcAddress(library, "gpr_thd_options_is_detached");
-  gpr_thd_options_is_joinable_import = (gpr_thd_options_is_joinable_type) GetProcAddress(library, "gpr_thd_options_is_joinable");
   gpr_thd_currentid_import = (gpr_thd_currentid_type) GetProcAddress(library, "gpr_thd_currentid");
-  gpr_thd_join_import = (gpr_thd_join_type) GetProcAddress(library, "gpr_thd_join");
   gpr_time_0_import = (gpr_time_0_type) GetProcAddress(library, "gpr_time_0");
   gpr_inf_future_import = (gpr_inf_future_type) GetProcAddress(library, "gpr_inf_future");
   gpr_inf_past_import = (gpr_inf_past_type) GetProcAddress(library, "gpr_inf_past");
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index 9e5dd2d..089cb8a 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -26,7 +26,6 @@
 #include <windows.h>
 
 #include <grpc/compression.h>
-#include <grpc/compression_ruby.h>
 #include <grpc/grpc.h>
 #include <grpc/grpc_posix.h>
 #include <grpc/grpc_security.h>
@@ -34,16 +33,12 @@
 #include <grpc/slice.h>
 #include <grpc/slice_buffer.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/avl.h>
-#include <grpc/support/cmdline.h>
 #include <grpc/support/cpu.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/log_windows.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/subprocess.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
+#include <grpc/support/thd_id.h>
 #include <grpc/support/time.h>
 
 typedef int(*grpc_compression_algorithm_is_message_type)(grpc_compression_algorithm algorithm);
@@ -73,12 +68,6 @@
 typedef int(*grpc_compression_options_is_algorithm_enabled_type)(const grpc_compression_options* opts, grpc_compression_algorithm algorithm);
 extern grpc_compression_options_is_algorithm_enabled_type grpc_compression_options_is_algorithm_enabled_import;
 #define grpc_compression_options_is_algorithm_enabled grpc_compression_options_is_algorithm_enabled_import
-typedef int(*grpc_compression_algorithm_parse_ruby_type)(grpc_slice value, grpc_compression_algorithm* algorithm);
-extern grpc_compression_algorithm_parse_ruby_type grpc_compression_algorithm_parse_ruby_import;
-#define grpc_compression_algorithm_parse_ruby grpc_compression_algorithm_parse_ruby_import
-typedef int(*grpc_compression_algorithm_name_ruby_type)(grpc_compression_algorithm algorithm, const char** name);
-extern grpc_compression_algorithm_name_ruby_type grpc_compression_algorithm_name_ruby_import;
-#define grpc_compression_algorithm_name_ruby grpc_compression_algorithm_name_ruby_import
 typedef void(*grpc_metadata_array_init_type)(grpc_metadata_array* array);
 extern grpc_metadata_array_init_type grpc_metadata_array_init_import;
 #define grpc_metadata_array_init grpc_metadata_array_init_import
@@ -190,6 +179,12 @@
 typedef void(*grpc_channel_destroy_type)(grpc_channel* channel);
 extern grpc_channel_destroy_type grpc_channel_destroy_import;
 #define grpc_channel_destroy grpc_channel_destroy_import
+typedef char*(*grpc_channel_get_trace_type)(grpc_channel* channel);
+extern grpc_channel_get_trace_type grpc_channel_get_trace_import;
+#define grpc_channel_get_trace grpc_channel_get_trace_import
+typedef intptr_t(*grpc_channel_get_uuid_type)(grpc_channel* channel);
+extern grpc_channel_get_uuid_type grpc_channel_get_uuid_import;
+#define grpc_channel_get_uuid grpc_channel_get_uuid_import
 typedef grpc_call_error(*grpc_call_cancel_type)(grpc_call* call, void* reserved);
 extern grpc_call_cancel_type grpc_call_cancel_import;
 #define grpc_call_cancel grpc_call_cancel_import
@@ -304,6 +299,15 @@
 typedef int(*grpc_auth_context_set_peer_identity_property_name_type)(grpc_auth_context* ctx, const char* name);
 extern grpc_auth_context_set_peer_identity_property_name_type grpc_auth_context_set_peer_identity_property_name_import;
 #define grpc_auth_context_set_peer_identity_property_name grpc_auth_context_set_peer_identity_property_name_import
+typedef grpc_ssl_session_cache*(*grpc_ssl_session_cache_create_lru_type)(size_t capacity);
+extern grpc_ssl_session_cache_create_lru_type grpc_ssl_session_cache_create_lru_import;
+#define grpc_ssl_session_cache_create_lru grpc_ssl_session_cache_create_lru_import
+typedef void(*grpc_ssl_session_cache_destroy_type)(grpc_ssl_session_cache* cache);
+extern grpc_ssl_session_cache_destroy_type grpc_ssl_session_cache_destroy_import;
+#define grpc_ssl_session_cache_destroy grpc_ssl_session_cache_destroy_import
+typedef grpc_arg(*grpc_ssl_session_cache_create_channel_arg_type)(grpc_ssl_session_cache* cache);
+extern grpc_ssl_session_cache_create_channel_arg_type grpc_ssl_session_cache_create_channel_arg_import;
+#define grpc_ssl_session_cache_create_channel_arg grpc_ssl_session_cache_create_channel_arg_import
 typedef void(*grpc_channel_credentials_release_type)(grpc_channel_credentials* creds);
 extern grpc_channel_credentials_release_type grpc_channel_credentials_release_import;
 #define grpc_channel_credentials_release grpc_channel_credentials_release_import
@@ -583,69 +587,12 @@
 typedef gpr_allocation_functions(*gpr_get_allocation_functions_type)(void);
 extern gpr_get_allocation_functions_type gpr_get_allocation_functions_import;
 #define gpr_get_allocation_functions gpr_get_allocation_functions_import
-typedef gpr_avl(*gpr_avl_create_type)(const gpr_avl_vtable* vtable);
-extern gpr_avl_create_type gpr_avl_create_import;
-#define gpr_avl_create gpr_avl_create_import
-typedef gpr_avl(*gpr_avl_ref_type)(gpr_avl avl, void* user_data);
-extern gpr_avl_ref_type gpr_avl_ref_import;
-#define gpr_avl_ref gpr_avl_ref_import
-typedef void(*gpr_avl_unref_type)(gpr_avl avl, void* user_data);
-extern gpr_avl_unref_type gpr_avl_unref_import;
-#define gpr_avl_unref gpr_avl_unref_import
-typedef gpr_avl(*gpr_avl_add_type)(gpr_avl avl, void* key, void* value, void* user_data);
-extern gpr_avl_add_type gpr_avl_add_import;
-#define gpr_avl_add gpr_avl_add_import
-typedef gpr_avl(*gpr_avl_remove_type)(gpr_avl avl, void* key, void* user_data);
-extern gpr_avl_remove_type gpr_avl_remove_import;
-#define gpr_avl_remove gpr_avl_remove_import
-typedef void*(*gpr_avl_get_type)(gpr_avl avl, void* key, void* user_data);
-extern gpr_avl_get_type gpr_avl_get_import;
-#define gpr_avl_get gpr_avl_get_import
-typedef int(*gpr_avl_maybe_get_type)(gpr_avl avl, void* key, void** value, void* user_data);
-extern gpr_avl_maybe_get_type gpr_avl_maybe_get_import;
-#define gpr_avl_maybe_get gpr_avl_maybe_get_import
-typedef int(*gpr_avl_is_empty_type)(gpr_avl avl);
-extern gpr_avl_is_empty_type gpr_avl_is_empty_import;
-#define gpr_avl_is_empty gpr_avl_is_empty_import
-typedef gpr_cmdline*(*gpr_cmdline_create_type)(const char* description);
-extern gpr_cmdline_create_type gpr_cmdline_create_import;
-#define gpr_cmdline_create gpr_cmdline_create_import
-typedef void(*gpr_cmdline_add_int_type)(gpr_cmdline* cl, const char* name, const char* help, int* value);
-extern gpr_cmdline_add_int_type gpr_cmdline_add_int_import;
-#define gpr_cmdline_add_int gpr_cmdline_add_int_import
-typedef void(*gpr_cmdline_add_flag_type)(gpr_cmdline* cl, const char* name, const char* help, int* value);
-extern gpr_cmdline_add_flag_type gpr_cmdline_add_flag_import;
-#define gpr_cmdline_add_flag gpr_cmdline_add_flag_import
-typedef void(*gpr_cmdline_add_string_type)(gpr_cmdline* cl, const char* name, const char* help, const char** value);
-extern gpr_cmdline_add_string_type gpr_cmdline_add_string_import;
-#define gpr_cmdline_add_string gpr_cmdline_add_string_import
-typedef void(*gpr_cmdline_on_extra_arg_type)(gpr_cmdline* cl, const char* name, const char* help, void (*on_extra_arg)(void* user_data, const char* arg), void* user_data);
-extern gpr_cmdline_on_extra_arg_type gpr_cmdline_on_extra_arg_import;
-#define gpr_cmdline_on_extra_arg gpr_cmdline_on_extra_arg_import
-typedef void(*gpr_cmdline_set_survive_failure_type)(gpr_cmdline* cl);
-extern gpr_cmdline_set_survive_failure_type gpr_cmdline_set_survive_failure_import;
-#define gpr_cmdline_set_survive_failure gpr_cmdline_set_survive_failure_import
-typedef int(*gpr_cmdline_parse_type)(gpr_cmdline* cl, int argc, char** argv);
-extern gpr_cmdline_parse_type gpr_cmdline_parse_import;
-#define gpr_cmdline_parse gpr_cmdline_parse_import
-typedef void(*gpr_cmdline_destroy_type)(gpr_cmdline* cl);
-extern gpr_cmdline_destroy_type gpr_cmdline_destroy_import;
-#define gpr_cmdline_destroy gpr_cmdline_destroy_import
-typedef char*(*gpr_cmdline_usage_string_type)(gpr_cmdline* cl, const char* argv0);
-extern gpr_cmdline_usage_string_type gpr_cmdline_usage_string_import;
-#define gpr_cmdline_usage_string gpr_cmdline_usage_string_import
 typedef unsigned(*gpr_cpu_num_cores_type)(void);
 extern gpr_cpu_num_cores_type gpr_cpu_num_cores_import;
 #define gpr_cpu_num_cores gpr_cpu_num_cores_import
 typedef unsigned(*gpr_cpu_current_cpu_type)(void);
 extern gpr_cpu_current_cpu_type gpr_cpu_current_cpu_import;
 #define gpr_cpu_current_cpu gpr_cpu_current_cpu_import
-typedef int(*gpr_join_host_port_type)(char** out, const char* host, int port);
-extern gpr_join_host_port_type gpr_join_host_port_import;
-#define gpr_join_host_port gpr_join_host_port_import
-typedef int(*gpr_split_host_port_type)(const char* name, char** host, char** port);
-extern gpr_split_host_port_type gpr_split_host_port_import;
-#define gpr_split_host_port gpr_split_host_port_import
 typedef const char*(*gpr_log_severity_string_type)(gpr_log_severity severity);
 extern gpr_log_severity_string_type gpr_log_severity_string_import;
 #define gpr_log_severity_string gpr_log_severity_string_import
@@ -673,21 +620,6 @@
 typedef int(*gpr_asprintf_type)(char** strp, const char* format, ...) GPR_PRINT_FORMAT_CHECK(2, 3);
 extern gpr_asprintf_type gpr_asprintf_import;
 #define gpr_asprintf gpr_asprintf_import
-typedef const char*(*gpr_subprocess_binary_extension_type)();
-extern gpr_subprocess_binary_extension_type gpr_subprocess_binary_extension_import;
-#define gpr_subprocess_binary_extension gpr_subprocess_binary_extension_import
-typedef gpr_subprocess*(*gpr_subprocess_create_type)(int argc, const char** argv);
-extern gpr_subprocess_create_type gpr_subprocess_create_import;
-#define gpr_subprocess_create gpr_subprocess_create_import
-typedef void(*gpr_subprocess_destroy_type)(gpr_subprocess* p);
-extern gpr_subprocess_destroy_type gpr_subprocess_destroy_import;
-#define gpr_subprocess_destroy gpr_subprocess_destroy_import
-typedef int(*gpr_subprocess_join_type)(gpr_subprocess* p);
-extern gpr_subprocess_join_type gpr_subprocess_join_import;
-#define gpr_subprocess_join gpr_subprocess_join_import
-typedef void(*gpr_subprocess_interrupt_type)(gpr_subprocess* p);
-extern gpr_subprocess_interrupt_type gpr_subprocess_interrupt_import;
-#define gpr_subprocess_interrupt gpr_subprocess_interrupt_import
 typedef void(*gpr_mu_init_type)(gpr_mu* mu);
 extern gpr_mu_init_type gpr_mu_init_import;
 #define gpr_mu_init gpr_mu_init_import
@@ -760,30 +692,9 @@
 typedef intptr_t(*gpr_stats_read_type)(const gpr_stats_counter* c);
 extern gpr_stats_read_type gpr_stats_read_import;
 #define gpr_stats_read gpr_stats_read_import
-typedef int(*gpr_thd_new_type)(gpr_thd_id* t, const char* thd_name, void (*thd_body)(void* arg), void* arg, const gpr_thd_options* options);
-extern gpr_thd_new_type gpr_thd_new_import;
-#define gpr_thd_new gpr_thd_new_import
-typedef gpr_thd_options(*gpr_thd_options_default_type)(void);
-extern gpr_thd_options_default_type gpr_thd_options_default_import;
-#define gpr_thd_options_default gpr_thd_options_default_import
-typedef void(*gpr_thd_options_set_detached_type)(gpr_thd_options* options);
-extern gpr_thd_options_set_detached_type gpr_thd_options_set_detached_import;
-#define gpr_thd_options_set_detached gpr_thd_options_set_detached_import
-typedef void(*gpr_thd_options_set_joinable_type)(gpr_thd_options* options);
-extern gpr_thd_options_set_joinable_type gpr_thd_options_set_joinable_import;
-#define gpr_thd_options_set_joinable gpr_thd_options_set_joinable_import
-typedef int(*gpr_thd_options_is_detached_type)(const gpr_thd_options* options);
-extern gpr_thd_options_is_detached_type gpr_thd_options_is_detached_import;
-#define gpr_thd_options_is_detached gpr_thd_options_is_detached_import
-typedef int(*gpr_thd_options_is_joinable_type)(const gpr_thd_options* options);
-extern gpr_thd_options_is_joinable_type gpr_thd_options_is_joinable_import;
-#define gpr_thd_options_is_joinable gpr_thd_options_is_joinable_import
 typedef gpr_thd_id(*gpr_thd_currentid_type)(void);
 extern gpr_thd_currentid_type gpr_thd_currentid_import;
 #define gpr_thd_currentid gpr_thd_currentid_import
-typedef void(*gpr_thd_join_type)(gpr_thd_id t);
-extern gpr_thd_join_type gpr_thd_join_import;
-#define gpr_thd_join gpr_thd_join_import
 typedef gpr_timespec(*gpr_time_0_type)(gpr_clock_type type);
 extern gpr_time_0_type gpr_time_0_import;
 #define gpr_time_0 gpr_time_0_import
diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c
index 160c153..88e6a0c 100644
--- a/src/ruby/ext/grpc/rb_server.c
+++ b/src/ruby/ext/grpc/rb_server.c
@@ -46,21 +46,38 @@
   /* The actual server */
   grpc_server* wrapped;
   grpc_completion_queue* queue;
-  gpr_atm shutdown_started;
+  int shutdown_and_notify_done;
+  int destroy_done;
 } grpc_rb_server;
 
-static void destroy_server(grpc_rb_server* server, gpr_timespec deadline) {
+static void grpc_rb_server_maybe_shutdown_and_notify(grpc_rb_server* server,
+                                                     gpr_timespec deadline) {
   grpc_event ev;
-  // This can be started by app or implicitly by GC. Avoid a race between these.
-  if (gpr_atm_full_fetch_add(&server->shutdown_started, (gpr_atm)1) == 0) {
+  void* tag = &ev;
+  if (!server->shutdown_and_notify_done) {
+    server->shutdown_and_notify_done = 1;
     if (server->wrapped != NULL) {
-      grpc_server_shutdown_and_notify(server->wrapped, server->queue, NULL);
-      ev = rb_completion_queue_pluck(server->queue, NULL, deadline, NULL);
+      grpc_server_shutdown_and_notify(server->wrapped, server->queue, tag);
+      ev = rb_completion_queue_pluck(server->queue, tag, deadline, NULL);
       if (ev.type == GRPC_QUEUE_TIMEOUT) {
         grpc_server_cancel_all_calls(server->wrapped);
-        rb_completion_queue_pluck(server->queue, NULL,
-                                  gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+        ev = rb_completion_queue_pluck(
+            server->queue, tag, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
       }
+      if (ev.type != GRPC_OP_COMPLETE) {
+        gpr_log(GPR_INFO,
+                "GRPC_RUBY: bad grpc_server_shutdown_and_notify result:%d",
+                ev.type);
+      }
+    }
+  }
+}
+
+static void grpc_rb_server_maybe_destroy(grpc_rb_server* server) {
+  // This can be started by app or implicitly by GC. Avoid a race between these.
+  if (!server->destroy_done) {
+    server->destroy_done = 1;
+    if (server->wrapped != NULL) {
       grpc_server_destroy(server->wrapped);
       grpc_rb_completion_queue_destroy(server->queue);
       server->wrapped = NULL;
@@ -81,7 +98,8 @@
   deadline = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
                           gpr_time_from_seconds(2, GPR_TIMESPAN));
 
-  destroy_server(svr, deadline);
+  grpc_rb_server_maybe_shutdown_and_notify(svr, deadline);
+  grpc_rb_server_maybe_destroy(svr);
 
   xfree(p);
 }
@@ -107,7 +125,8 @@
 static VALUE grpc_rb_server_alloc(VALUE cls) {
   grpc_rb_server* wrapper = ALLOC(grpc_rb_server);
   wrapper->wrapped = NULL;
-  wrapper->shutdown_started = (gpr_atm)0;
+  wrapper->destroy_done = 0;
+  wrapper->shutdown_and_notify_done = 0;
   return TypedData_Wrap_Struct(cls, &grpc_rb_server_data_type, wrapper);
 }
 
@@ -232,25 +251,10 @@
   return Qnil;
 }
 
-/*
-  call-seq:
-    server = Server.new({'arg1': 'value1'})
-    ... // do stuff with server
-    ...
-    ... // to shutdown the server
-    server.destroy()
-
-    ... // to shutdown the server with a timeout
-    server.destroy(timeout)
-
-  Destroys server instances. */
-static VALUE grpc_rb_server_destroy(int argc, VALUE* argv, VALUE self) {
-  VALUE timeout = Qnil;
+static VALUE grpc_rb_server_shutdown_and_notify(VALUE self, VALUE timeout) {
   gpr_timespec deadline;
   grpc_rb_server* s = NULL;
 
-  /* "01" == 0 mandatory args, 1 (timeout) is optional */
-  rb_scan_args(argc, argv, "01", &timeout);
   TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s);
   if (TYPE(timeout) == T_NIL) {
     deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
@@ -258,13 +262,31 @@
     deadline = grpc_rb_time_timeval(timeout, /* absolute time*/ 0);
   }
 
-  destroy_server(s, deadline);
+  grpc_rb_server_maybe_shutdown_and_notify(s, deadline);
 
   return Qnil;
 }
 
 /*
   call-seq:
+    server = Server.new({'arg1': 'value1'})
+    ... // do stuff with server
+    ...
+    ... // initiate server shutdown
+    server.shutdown_and_notify(timeout)
+    ... // to shutdown the server
+    server.destroy()
+
+  Destroys server instances. */
+static VALUE grpc_rb_server_destroy(VALUE self) {
+  grpc_rb_server* s = NULL;
+  TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s);
+  grpc_rb_server_maybe_destroy(s);
+  return Qnil;
+}
+
+/*
+  call-seq:
     // insecure port
     insecure_server = Server.new(cq, {'arg1': 'value1'})
     insecure_server.add_http2_port('mydomain:50051', :this_port_is_insecure)
@@ -326,7 +348,9 @@
   rb_define_method(grpc_rb_cServer, "request_call", grpc_rb_server_request_call,
                    0);
   rb_define_method(grpc_rb_cServer, "start", grpc_rb_server_start, 0);
-  rb_define_method(grpc_rb_cServer, "destroy", grpc_rb_server_destroy, -1);
+  rb_define_method(grpc_rb_cServer, "shutdown_and_notify",
+                   grpc_rb_server_shutdown_and_notify, 1);
+  rb_define_method(grpc_rb_cServer, "destroy", grpc_rb_server_destroy, 0);
   rb_define_alias(grpc_rb_cServer, "close", "destroy");
   rb_define_method(grpc_rb_cServer, "add_http2_port",
                    grpc_rb_server_add_http2_port, 2);
diff --git a/src/ruby/lib/grpc/core/time_consts.rb b/src/ruby/lib/grpc/core/time_consts.rb
index 92cd323..896b720 100644
--- a/src/ruby/lib/grpc/core/time_consts.rb
+++ b/src/ruby/lib/grpc/core/time_consts.rb
@@ -32,7 +32,7 @@
       # * timish == 0 => TimeConsts.ZERO
       #
       # @param timeish [Number|TimeSpec]
-      # @return timeish [Number|TimeSpec]
+      # @return [Number|TimeSpec]
       def from_relative_time(timeish)
         if timeish.is_a? TimeSpec
           timeish
diff --git a/src/ruby/lib/grpc/generic/bidi_call.rb b/src/ruby/lib/grpc/generic/bidi_call.rb
index 3bdcc00..086455d 100644
--- a/src/ruby/lib/grpc/generic/bidi_call.rb
+++ b/src/ruby/lib/grpc/generic/bidi_call.rb
@@ -64,7 +64,7 @@
     # @param requests the Enumerable of requests to send
     # @param set_input_stream_done [Proc] called back when we're done
     #   reading the input stream
-    # @param set_input_stream_done [Proc] called back when we're done
+    # @param set_output_stream_done [Proc] called back when we're done
     #   sending data on the output stream
     # @return an Enumerator of requests to yield
     def run_on_client(requests,
diff --git a/src/ruby/lib/grpc/generic/client_stub.rb b/src/ruby/lib/grpc/generic/client_stub.rb
index 9a50f8a..b193f5c 100644
--- a/src/ruby/lib/grpc/generic/client_stub.rb
+++ b/src/ruby/lib/grpc/generic/client_stub.rb
@@ -58,8 +58,8 @@
     # Minimally, a stub is created with the just the host of the gRPC service
     # it wishes to access, e.g.,
     #
-    # my_stub = ClientStub.new(example.host.com:50505,
-    #                          :this_channel_is_insecure)
+    #   my_stub = ClientStub.new(example.host.com:50505,
+    #                            :this_channel_is_insecure)
     #
     # If a channel_override argument is passed, it will be used as the
     # underlying channel. Otherwise, the channel_args argument will be used
@@ -376,7 +376,7 @@
     # This is a blocking call.
     #
     # * the call completes when the next call to provided block returns
-    # * [False]
+    #   false
     #
     # * the execution block parameters are two objects for sending and
     #   receiving responses, each of which blocks waiting for flow control.
@@ -398,13 +398,9 @@
     # responses by throwing StopIteration, but can only happen either
     # if bidi_call#writes_done is called.
     #
-    # To terminate the RPC correctly the block:
-    #
-    # * must call bidi#writes_done and then
-    #
-    #    * either return false as soon as there is no need for other responses
-    #
-    #    * loop on responses#next until no further responses are available
+    # To properly terminate the RPC, the responses should be completely iterated
+    # through; one way to do this is to loop on responses#next until no further
+    # responses are available.
     #
     # == Errors ==
     # An RuntimeError is raised if
diff --git a/src/ruby/lib/grpc/generic/interceptors.rb b/src/ruby/lib/grpc/generic/interceptors.rb
index 24482f3..56d3cec 100644
--- a/src/ruby/lib/grpc/generic/interceptors.rb
+++ b/src/ruby/lib/grpc/generic/interceptors.rb
@@ -153,7 +153,7 @@
   #
   class InterceptionContext
     ##
-    # @param [Array<GRPC::Interceptor>]
+    # @param interceptors [Array<GRPC::Interceptor>]
     #
     def initialize(interceptors = [])
       @interceptors = interceptors.dup
diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb
index c80c7fc..31ab6a3 100644
--- a/src/ruby/lib/grpc/generic/rpc_server.rb
+++ b/src/ruby/lib/grpc/generic/rpc_server.rb
@@ -204,7 +204,7 @@
     # * connect_md_proc:
     # when non-nil is a proc for determining metadata to to send back the client
     # on receiving an invocation req.  The proc signature is:
-    # {key: val, ..} func(method_name, {key: val, ...})
+    #   {key: val, ..} func(method_name, {key: val, ...})
     #
     # * server_args:
     # A server arguments hash to be passed down to the underlying core server
@@ -244,9 +244,9 @@
         fail 'Cannot stop before starting' if @running_state == :not_started
         return if @running_state != :running
         transition_running_state(:stopping)
+        deadline = from_relative_time(@poll_period)
+        @server.shutdown_and_notify(deadline)
       end
-      deadline = from_relative_time(@poll_period)
-      @server.close(deadline)
       @pool.stop
     end
 
@@ -283,7 +283,7 @@
     # If run has not been called, this returns immediately.
     #
     # @param timeout [Numeric] number of seconds to wait
-    # @result [true, false] true if the server is running, false otherwise
+    # @return [true, false] true if the server is running, false otherwise
     def wait_till_running(timeout = nil)
       @run_mutex.synchronize do
         @run_cond.wait(@run_mutex, timeout) if @running_state == :not_started
@@ -416,8 +416,11 @@
         end
       end
       # @running_state should be :stopping here
-      @run_mutex.synchronize { transition_running_state(:stopped) }
-      GRPC.logger.info("stopped: #{self}")
+      @run_mutex.synchronize do
+        transition_running_state(:stopped)
+        GRPC.logger.info("stopped: #{self}")
+        @server.close
+      end
     end
 
     def new_active_server_call(an_rpc)
diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb
index 9d9f2f4..256a543 100644
--- a/src/ruby/lib/grpc/version.rb
+++ b/src/ruby/lib/grpc/version.rb
@@ -14,5 +14,5 @@
 
 # GRPC contains the General RPC module.
 module GRPC
-  VERSION = '1.10.0.dev'
+  VERSION = '1.11.0.dev'
 end
diff --git a/src/ruby/pb/test/client.rb b/src/ruby/pb/test/client.rb
index a110fec..63959d9 100755
--- a/src/ruby/pb/test/client.rb
+++ b/src/ruby/pb/test/client.rb
@@ -707,7 +707,7 @@
                   :oauth_scope, :port, :secure, :test_case,
                   :use_test_ca)
 
-# validates the the command line options, returning them as a Hash.
+# validates the command line options, returning them as a Hash.
 def parse_args
   args = Args.new
   args.host_override = 'foo.test.google.fr'
diff --git a/src/ruby/pb/test/server.rb b/src/ruby/pb/test/server.rb
index f3257d3..1c82ba0 100755
--- a/src/ruby/pb/test/server.rb
+++ b/src/ruby/pb/test/server.rb
@@ -211,7 +211,7 @@
   end
 end
 
-# validates the the command line options, returning them as a Hash.
+# validates the command line options, returning them as a Hash.
 def parse_options
   options = {
     'port' => nil,
diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb
index 14ad369..afbfb0b 100644
--- a/src/ruby/spec/client_server_spec.rb
+++ b/src/ruby/spec/client_server_spec.rb
@@ -550,7 +550,8 @@
 
   after(:example) do
     @ch.close
-    @server.close(deadline)
+    @server.shutdown_and_notify(deadline)
+    @server.close
   end
 
   it_behaves_like 'basic GRPC message delivery is OK' do
@@ -583,7 +584,8 @@
   end
 
   after(:example) do
-    @server.close(deadline)
+    @server.shutdown_and_notify(deadline)
+    @server.close
   end
 
   it_behaves_like 'basic GRPC message delivery is OK' do
diff --git a/src/ruby/spec/generic/active_call_spec.rb b/src/ruby/spec/generic/active_call_spec.rb
index 135d1f2..6b44b22 100644
--- a/src/ruby/spec/generic/active_call_spec.rb
+++ b/src/ruby/spec/generic/active_call_spec.rb
@@ -48,7 +48,8 @@
   end
 
   after(:each) do
-    @server.close(deadline)
+    @server.shutdown_and_notify(deadline)
+    @server.close
   end
 
   describe 'restricted view methods' do
diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb
index 5353b53..d858c4e 100644
--- a/src/ruby/spec/generic/client_stub_spec.rb
+++ b/src/ruby/spec/generic/client_stub_spec.rb
@@ -83,7 +83,12 @@
          op_view.deadline.is_a?(Time)).to be(true)
 end
 
-describe 'ClientStub' do
+def close_active_server_call(active_server_call)
+  active_server_call.send(:set_input_stream_done)
+  active_server_call.send(:set_output_stream_done)
+end
+
+describe 'ClientStub' do  # rubocop:disable Metrics/BlockLength
   let(:noop) { proc { |x| x } }
 
   before(:each) do
@@ -96,7 +101,10 @@
   end
 
   after(:each) do
-    @server.close(from_relative_time(2)) unless @server.nil?
+    unless @server.nil?
+      @server.shutdown_and_notify(from_relative_time(2))
+      @server.close
+    end
   end
 
   describe '#new' do
@@ -230,7 +238,15 @@
 
       it 'should receive UNAVAILABLE if call credentials plugin fails' do
         server_port = create_secure_test_server
-        th = run_request_response(@sent_msg, @resp, @pass)
+        server_started_notifier = GRPC::Notifier.new
+        th = Thread.new do
+          @server.start
+          server_started_notifier.notify(nil)
+          # Poll on the server so that the client connection can proceed.
+          # We don't expect the server to actually accept a call though.
+          expect { @server.request_call }.to raise_error(GRPC::Core::CallError)
+        end
+        server_started_notifier.wait
 
         certs = load_test_certs
         secure_channel_creds = GRPC::Core::ChannelCredentials.new(
@@ -249,17 +265,18 @@
         end
         creds = GRPC::Core::CallCredentials.new(failing_auth)
 
-        unauth_error_occured = false
+        unavailable_error_occured = false
         begin
           get_response(stub, credentials: creds)
         rescue GRPC::Unavailable => e
-          unauth_error_occured = true
+          unavailable_error_occured = true
           expect(e.details.include?(error_message)).to be true
         end
-        expect(unauth_error_occured).to eq(true)
+        expect(unavailable_error_occured).to eq(true)
 
-        # Kill the server thread so tests can complete
-        th.kill
+        @server.shutdown_and_notify(Time.now + 3)
+        th.join
+        @server.close
       end
 
       it 'should raise ArgumentError if metadata contains invalid values' do
@@ -493,6 +510,7 @@
             p 'remote_send failed (allowed because call expected to cancel)'
           ensure
             c.send_status(OK, 'OK', true)
+            close_active_server_call(c)
           end
         end
       end
@@ -659,6 +677,7 @@
           end
           # can't fail since initial metadata already sent
           server_call.send_status(@pass, 'OK', true)
+          close_active_server_call(server_call)
         end
 
         def verify_error_from_write_thread(stub, requests_to_push,
@@ -809,6 +828,7 @@
       replys.each { |r| c.remote_send(r) }
       c.send_status(status, status == @pass ? 'OK' : 'NOK', true,
                     metadata: server_trailing_md)
+      close_active_server_call(c)
     end
   end
 
@@ -819,6 +839,7 @@
       expected_inputs.each { |i| expect(c.remote_read).to eq(i) }
       replys.each { |r| c.remote_send(r) }
       c.send_status(status, status == @pass ? 'OK' : 'NOK', true)
+      close_active_server_call(c)
     end
   end
 
@@ -844,6 +865,7 @@
       end
       c.send_status(status, status == @pass ? 'OK' : 'NOK', true,
                     metadata: server_trailing_md)
+      close_active_server_call(c)
     end
   end
 
@@ -862,6 +884,7 @@
       c.remote_send(resp)
       c.send_status(status, status == @pass ? 'OK' : 'NOK', true,
                     metadata: server_trailing_md)
+      close_active_server_call(c)
     end
   end
 
@@ -880,6 +903,7 @@
       c.remote_send(resp)
       c.send_status(status, status == @pass ? 'OK' : 'NOK', true,
                     metadata: server_trailing_md)
+      close_active_server_call(c)
     end
   end
 
diff --git a/src/ruby/spec/server_spec.rb b/src/ruby/spec/server_spec.rb
index a0d27b6..6eaac5d 100644
--- a/src/ruby/spec/server_spec.rb
+++ b/src/ruby/spec/server_spec.rb
@@ -36,45 +36,60 @@
 
     it 'fails if the server is closed' do
       s = new_core_server_for_testing(nil)
+      s.shutdown_and_notify(nil)
       s.close
       expect { s.start }.to raise_error(RuntimeError)
     end
   end
 
-  describe '#destroy' do
+  describe '#shutdown_and_notify and #destroy' do
     it 'destroys a server ok' do
       s = start_a_server
-      blk = proc { s.destroy }
+      blk = proc do
+        s.shutdown_and_notify(nil)
+        s.destroy
+      end
       expect(&blk).to_not raise_error
     end
 
     it 'can be called more than once without error' do
       s = start_a_server
       begin
-        blk = proc { s.destroy }
+        blk = proc do
+          s.shutdown_and_notify(nil)
+          s.destroy
+        end
         expect(&blk).to_not raise_error
         blk.call
         expect(&blk).to_not raise_error
       ensure
+        s.shutdown_and_notify(nil)
         s.close
       end
     end
   end
 
-  describe '#close' do
+  describe '#shutdown_and_notify and #close' do
     it 'closes a server ok' do
       s = start_a_server
       begin
-        blk = proc { s.close }
+        blk = proc do
+          s.shutdown_and_notify(nil)
+          s.close
+        end
         expect(&blk).to_not raise_error
       ensure
-        s.close(@cq)
+        s.shutdown_and_notify(nil)
+        s.close
       end
     end
 
     it 'can be called more than once without error' do
       s = start_a_server
-      blk = proc { s.close }
+      blk = proc do
+        s.shutdown_and_notify(nil)
+        s.close
+      end
       expect(&blk).to_not raise_error
       blk.call
       expect(&blk).to_not raise_error
@@ -87,6 +102,7 @@
         blk = proc do
           s = new_core_server_for_testing(nil)
           s.add_http2_port('localhost:0', :this_port_is_insecure)
+          s.shutdown_and_notify(nil)
           s.close
         end
         expect(&blk).to_not raise_error
@@ -94,6 +110,7 @@
 
       it 'fails if the server is closed' do
         s = new_core_server_for_testing(nil)
+        s.shutdown_and_notify(nil)
         s.close
         blk = proc do
           s.add_http2_port('localhost:0', :this_port_is_insecure)
@@ -108,6 +125,7 @@
         blk = proc do
           s = new_core_server_for_testing(nil)
           s.add_http2_port('localhost:0', cert)
+          s.shutdown_and_notify(nil)
           s.close
         end
         expect(&blk).to_not raise_error
@@ -115,6 +133,7 @@
 
       it 'fails if the server is closed' do
         s = new_core_server_for_testing(nil)
+        s.shutdown_and_notify(nil)
         s.close
         blk = proc { s.add_http2_port('localhost:0', cert) }
         expect(&blk).to raise_error(RuntimeError)
diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb
index 2682294..8dc1623 100644
--- a/src/ruby/tools/version.rb
+++ b/src/ruby/tools/version.rb
@@ -14,6 +14,6 @@
 
 module GRPC
   module Tools
-    VERSION = '1.10.0.dev'
+    VERSION = '1.11.0.dev'
   end
 end
diff --git a/summerofcode/ideas.md b/summerofcode/ideas.md
index d89bc37..de59be8 100644
--- a/summerofcode/ideas.md
+++ b/summerofcode/ideas.md
@@ -29,8 +29,8 @@
 
 1. Support static type-checking of both gRPC Python itself and of code that uses gRPC Python. No one likes dynamic typing and Python is finally outgrowing it! There are probably errors in the implementation of gRPC Python that [pytype](https://github.com/google/pytype) or [mypy](http://mypy-lang.org/) could detect. There are certainly errors in other code that uses gRPC Python that they could detect.
     * **Required skills:** Python programming language, open source development across multiple repositories and projects.
-    * **Likely mentors:** [Nathaniel Manista](https://github.com/nathanielmanistaatgoogle), [Kailash Sethuraman](https://github.com/hsaliak), [Ken Payson](https://github.com/kpayson64), [Mehrdad Afshari](https://github.com/mehrdada).
+    * **Likely mentors:** [Nathaniel Manista](https://github.com/nathanielmanistaatgoogle), [Kailash Sethuraman](https://github.com/hsaliak).
 
 1. [Enable building of gRPC Python with Bazel](https://github.com/grpc/grpc/issues/8079). Bazel is the designated replacement for our constellation of crufty build scripts, but it's still under active development itself. Up for a challenge? gRPC Python could easily be the most complex codebase to be built with Bazel.
     * **Required skills:** Python programming language, Bazel toolchain, Cython, open source development across multiple repositories and projects.
-    * **Likely mentors:** [Nathaniel Manista](https://github.com/nathanielmanistaatgoogle), [Ken Payson](https://github.com/kpayson64), [Mehrdad Afshari](https://github.com/mehrdada).
+    * **Likely mentors:** [Nathaniel Manista](https://github.com/nathanielmanistaatgoogle).
diff --git a/templates/CMakeLists.txt.template b/templates/CMakeLists.txt.template
index de0f2eb..01fe569 100644
--- a/templates/CMakeLists.txt.template
+++ b/templates/CMakeLists.txt.template
@@ -46,6 +46,7 @@
     if target_dict['name'] in ['grpc', 'grpc_cronet', 'grpc_unsecure']:
       deps.append("${_gRPC_ZLIB_LIBRARIES}")
       deps.append("${_gRPC_CARES_LIBRARIES}")
+      deps.append("${_gRPC_ADDRESS_SORTING_LIBRARIES}")
     deps.append("${_gRPC_ALLTARGETS_LIBRARIES}")
     for d in target_dict.get('deps', []):
       if d == 'benchmark':
@@ -77,13 +78,14 @@
   set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/")
   project(<%text>${PACKAGE_NAME}</%text> C CXX)
 
-  set(gRPC_INSTALL_BINDIR "<%text>${CMAKE_INSTALL_PREFIX}</%text>/bin" CACHE PATH "Installation directory for executables")
-  set(gRPC_INSTALL_LIBDIR "<%text>${CMAKE_INSTALL_PREFIX}</%text>/lib" CACHE PATH "Installation directory for libraries")
-  set(gRPC_INSTALL_INCLUDEDIR "<%text>${CMAKE_INSTALL_PREFIX}</%text>/include" CACHE PATH "Installation directory for headers")
-  set(gRPC_INSTALL_CMAKEDIR "<%text>${CMAKE_INSTALL_PREFIX}/lib/cmake/${PACKAGE_NAME}</%text>" CACHE PATH "Installation directory for cmake config files")
+  set(gRPC_INSTALL_BINDIR "bin" CACHE STRING "Installation directory for executables")
+  set(gRPC_INSTALL_LIBDIR "lib" CACHE STRING "Installation directory for libraries")
+  set(gRPC_INSTALL_INCLUDEDIR "include" CACHE STRING "Installation directory for headers")
+  set(gRPC_INSTALL_CMAKEDIR "lib/cmake/<%text>${PACKAGE_NAME}</%text>" CACHE STRING "Installation directory for cmake config files")
 
   # Options
   option(gRPC_BUILD_TESTS "Build tests" OFF)
+  option(gRPC_BUILD_CODEGEN "Build codegen" ON)
 
   set(gRPC_INSTALL_default ON)
   if (NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
@@ -125,6 +127,8 @@
       set(_gRPC_PLATFORM_LINUX ON)
     elseif(<%text>${CMAKE_SYSTEM_NAME}</%text> MATCHES "Darwin")
       set(_gRPC_PLATFORM_MAC ON)
+    elseif(<%text>${CMAKE_SYSTEM_NAME}</%text> MATCHES "Android")
+      set(_gRPC_PLATFORM_ANDROID ON)
     else()
       set(_gRPC_PLATFORM_POSIX ON)
     endif()
@@ -135,6 +139,8 @@
 
   ## Some libraries are shared even with BUILD_SHARED_LIBRARIES=OFF
   set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
+  
+  add_definitions(-DPB_FIELD_16BIT)
 
   if (MSVC)
     include(cmake/msvc_static_runtime.cmake)
@@ -160,6 +166,7 @@
   include(cmake/ssl.cmake)
   include(cmake/gflags.cmake)
   include(cmake/benchmark.cmake)
+  include(cmake/address_sorting.cmake)
 
   if(NOT MSVC)
     set(CMAKE_C_FLAGS   "<%text>${CMAKE_C_FLAGS}</%text> -std=c99")
@@ -168,6 +175,8 @@
 
   if(_gRPC_PLATFORM_MAC)
     set(_gRPC_ALLTARGETS_LIBRARIES <%text>${CMAKE_DL_LIBS}</%text> m pthread)
+  elseif(_gRPC_PLATFORM_ANDROID)
+    set(_gRPC_ALLTARGETS_LIBRARIES <%text>${CMAKE_DL_LIBS}</%text> m)
   elseif(UNIX)
     set(_gRPC_ALLTARGETS_LIBRARIES <%text>${CMAKE_DL_LIBS}</%text> rt m pthread)
   endif()
@@ -304,6 +313,13 @@
   ${cc_binary(tgt)}
   ${get_platforms_condition_end(tgt.platforms)}\
   endif (gRPC_BUILD_TESTS)
+  % elif tgt.build in ["protoc"]:
+  if (gRPC_BUILD_CODEGEN)
+  ${get_platforms_condition_begin(tgt.platforms)}\
+  ${cc_binary(tgt)}
+  ${cc_install(tgt)}
+  ${get_platforms_condition_end(tgt.platforms)}\
+  endif (gRPC_BUILD_CODEGEN)
   % else:
   ${get_platforms_condition_begin(tgt.platforms)}\
   ${cc_binary(tgt)}
@@ -314,6 +330,9 @@
   % endfor
 
   <%def name="cc_library(lib)">
+  % if any(proto_re.match(src) for src in lib.src):
+  if (gRPC_BUILD_CODEGEN)
+  % endif
   add_library(${lib.name}${' SHARED' if lib.get('dll', None) == 'only' else ''}
   % for src in lib.src:
   % if not proto_re.match(src):
@@ -358,6 +377,7 @@
     PRIVATE <%text>${_gRPC_BENCHMARK_INCLUDE_DIR}</%text>
     PRIVATE <%text>${_gRPC_CARES_INCLUDE_DIR}</%text>
     PRIVATE <%text>${_gRPC_GFLAGS_INCLUDE_DIR}</%text>
+    PRIVATE <%text>${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}</%text>
   % if lib.build in ['test', 'private'] and lib.language == 'c++':
     PRIVATE third_party/googletest/googletest/include
     PRIVATE third_party/googletest/googletest
@@ -376,6 +396,14 @@
   % endfor
   )
   % endif
+  % if lib.name in ["gpr"]:
+  if (_gRPC_PLATFORM_ANDROID)
+    target_link_libraries(gpr
+      android
+      log
+    )
+  endif (_gRPC_PLATFORM_ANDROID)
+  % endif
 
   % if len(lib.get('public_headers', [])) > 0:
   foreach(_hdr
@@ -390,6 +418,9 @@
     )
   endforeach()
   % endif
+  % if any(proto_re.match(src) for src in lib.src):
+  endif (gRPC_BUILD_CODEGEN)
+  % endif
   </%def>
 
   <%def name="cc_binary(tgt)">
@@ -427,6 +458,7 @@
     PRIVATE <%text>${_gRPC_BENCHMARK_INCLUDE_DIR}</%text>
     PRIVATE <%text>${_gRPC_CARES_INCLUDE_DIR}</%text>
     PRIVATE <%text>${_gRPC_GFLAGS_INCLUDE_DIR}</%text>
+    PRIVATE <%text>${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}</%text>
   % if tgt.build in ['test', 'private'] and tgt.language == 'c++':
     PRIVATE third_party/googletest/googletest/include
     PRIVATE third_party/googletest/googletest
diff --git a/templates/Makefile.template b/templates/Makefile.template
index b8e26b6..c0ce2e5 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -221,6 +221,8 @@
   %  endif
   % endfor
 
+  DEFINES += PB_FIELD_16BIT
+
   CPPFLAGS += $(CPPFLAGS_$(CONFIG))
   CFLAGS += $(CFLAGS_$(CONFIG))
   CXXFLAGS += $(CXXFLAGS_$(CONFIG))
@@ -588,6 +590,11 @@
   EMBED_CARES ?= false
   endif
 
+  ADDRESS_SORTING_DEP = $(LIBDIR)/$(CONFIG)/libaddress_sorting.a
+  ADDRESS_SORTING_MERGE_OBJS = $(LIBADDRESS_SORTING_OBJS)
+  ADDRESS_SORTING_MERGE_LIBS = $(LIBDIR)/$(CONFIG)/libaddress_sorting.a
+  CPPFLAGS := -Ithird_party/address_sorting/include $(CPPFLAGS)
+
   ifeq ($(EMBED_CARES),true)
   CARES_DEP = $(LIBDIR)/$(CONFIG)/libares.a
   CARES_MERGE_OBJS = $(LIBARES_OBJS)
@@ -1378,6 +1385,11 @@
   % endif
   % endfor
 
+  install-grpc-cli: grpc_cli
+  	$(E) "[INSTALL] Installing grpc cli"
+  	$(Q) $(INSTALL) -d $(prefix)/bin
+  	$(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_cli $(prefix)/bin/grpc_cli
+
   install-pkg-config_c: pc_c pc_c_unsecure
   	$(E) "[INSTALL] Installing C pkg-config files"
   	$(Q) $(INSTALL) -d $(prefix)/lib/pkgconfig
@@ -1473,7 +1485,7 @@
   else
   % endif
 
-  $(LIBDIR)/$(CONFIG)/lib${lib.name}.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP)\
+  $(LIBDIR)/$(CONFIG)/lib${lib.name}.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)\
   ## The else here corresponds to the if secure earlier.
   % else:
   % if lib.language == 'c++':
@@ -1497,6 +1509,9 @@
   % if lib.name != 'ares':
   $(CARES_DEP) \
   % endif
+  % if lib.name != 'address_sorting':
+  $(ADDRESS_SORTING_DEP) \
+  % endif
   % endif
   % if lib.language == 'c++':
    $(PROTOBUF_DEP)\
@@ -1506,6 +1521,7 @@
    $(LIBGPR_OBJS) \
    $(ZLIB_MERGE_OBJS) \
    $(CARES_MERGE_OBJS) \
+   $(ADDRESS_SORTING_MERGE_OBJS) \
   % if lib.get('secure', 'check') == True:
    $(OPENSSL_MERGE_OBJS) \
   % endif
@@ -1519,6 +1535,7 @@
    $(LIBGPR_OBJS) \
    $(ZLIB_MERGE_OBJS) \
    $(CARES_MERGE_OBJS) \
+   $(ADDRESS_SORTING_MERGE_OBJS) \
   % if lib.get('secure', 'check') == True:
    $(OPENSSL_MERGE_OBJS) \
   % endif
@@ -1541,9 +1558,9 @@
     common = '$(LIB' + lib.name.upper() + '_OBJS)'
 
     link_libs = ''
-    lib_deps = ' $(ZLIB_DEP) $(CARES_DEP)'
+    lib_deps = ' $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)'
     mingw_libs = ''
-    mingw_lib_deps = ' $(ZLIB_DEP) $(CARES_DEP)'
+    mingw_lib_deps = ' $(ZLIB_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP)'
     if lib.language == 'c++':
       lib_deps += ' $(PROTOBUF_DEP)'
       mingw_lib_deps += ' $(PROTOBUF_DEP)'
@@ -1568,7 +1585,7 @@
     security = lib.get('secure', 'check')
     if security == True:
       common = common + ' $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE)'
-    common = common + ' $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS)'
+    common = common + ' $(ZLIB_MERGE_LIBS) $(CARES_MERGE_LIBS) $(ADDRESS_SORTING_MERGE_LIBS)'
 
     if security in [True, 'check']:
       for src in lib.src:
diff --git a/templates/config.m4.template b/templates/config.m4.template
index cd93fbd..9877e4b 100644
--- a/templates/config.m4.template
+++ b/templates/config.m4.template
@@ -13,8 +13,8 @@
 
     LIBS="-lpthread $LIBS"
 
-    CFLAGS="-Wall -Werror -Wno-parentheses-equality -Wno-unused-value -std=c11"
-    CXXFLAGS="-std=c++11 -fno-exceptions -fno-rtti"
+    CFLAGS="-Wall -Werror -Wno-parentheses-equality -Wno-unused-value -std=c11 -g -O2 -D PB_FIELD_16BIT=1"
+    CXXFLAGS="-std=c++11 -fno-exceptions -fno-rtti -g -O2 -D PB_FIELD_16BIT=1"
     GRPC_SHARED_LIBADD="-lpthread $GRPC_SHARED_LIBADD"
     PHP_REQUIRE_CXX()
     PHP_ADD_LIBRARY(pthread)
diff --git a/templates/gRPC-C++.podspec.template b/templates/gRPC-C++.podspec.template
index 78adb27..12d5fc1 100644
--- a/templates/gRPC-C++.podspec.template
+++ b/templates/gRPC-C++.podspec.template
@@ -30,6 +30,9 @@
           out += lib.get(group, [])
     return out
 
+  def filter_grpcpp(files):
+    return [file for file in files if not file.startswith("include/grpc++")]
+
   def grpc_private_files(libs):
     out = grpc_lib_files(libs, ("grpc", "gpr"), ("headers", "src"))
     return out
@@ -59,6 +62,9 @@
     # Since some C++ source files directly included private headers in C core, we include all the
     # C core headers in C++ Implementation subspec as well.
     out += [file for file in grpc_private_headers(libs) if not file.startswith("third_party/nanopb/")]
+
+    out = filter_grpcpp(out)
+
     return out
 
   def grpcpp_private_headers(libs, filegroups):
@@ -71,6 +77,8 @@
     # Since some C++ source files directly included private headers in C core, we intentionally
     # keep the C core headers in \a out. But we should exclude nanopb headers.
     out = [file for file in out if not file.startswith("third_party/nanopb/")]
+
+    out = filter_grpcpp(out)
     return out
 
   def grpcpp_public_headers(libs, filegroups):
@@ -81,6 +89,9 @@
     excl_files += grpcpp_proto_files(filegroups)
 
     out = [file for file in out if file not in excl_files]
+
+    out = filter_grpcpp(out)
+
     return out
 
   def grpc_test_util_files(libs):
@@ -91,6 +102,8 @@
     out = grpc_lib_files(libs, ("grpc_test_util", "gpr_test_util"), ("headers",))
     return out
 
+  # Tests subspec is currently disabled since the tests currently use `grpc++` include style instead of `grpcpp`.
+  # TODO (mxyan): enable Tests subspec after the inclusion style is updated in `test/` directory.
   def grpcpp_test_util_files(libs, filegroups):
     out = grpc_lib_files(libs, ("grpc++_test_util",), ("src", "headers"))
     excl_files = grpc_test_util_files(libs) + grpcpp_private_files(libs, filegroups)
@@ -118,7 +131,7 @@
     s.name     = 'gRPC-C++'
     # TODO (mxyan): use version that match gRPC version when pod is stabilized
     # version = '${settings.version}'
-    version = '0.0.1'
+    version = '0.0.2'
     s.version  = version
     s.summary  = 'gRPC C++ library'
     s.homepage = 'https://grpc.io'
@@ -136,8 +149,14 @@
     s.osx.deployment_target = '10.9'
     s.requires_arc = false
 
-    # Add include prefix `grpc++` (i.e. `#include <grpc++/xxx.h>`).
-    s.header_dir = 'grpc++'
+    name = 'grpcpp'
+    # Use `grpcpp` as framework name so that `#include <grpcpp/xxx.h>` works when built as
+    # framework.
+    s.module_name = name
+
+    # Add include prefix `grpcpp` so that `#include <grpcpp/xxx.h>` works when built as static
+    # library.
+    s.header_dir = name
 
     s.pod_target_xcconfig = {
       'HEADER_SEARCH_PATHS' => '"$(inherited)" "$(PODS_TARGET_SRCROOT)/include"',
@@ -157,8 +176,10 @@
 
     s.default_subspecs = 'Interface', 'Implementation'
 
+    s.header_mappings_dir = 'include/grpcpp'
+
     s.subspec 'Interface' do |ss|
-      ss.header_mappings_dir = 'include/grpc++'
+      ss.header_mappings_dir = 'include/grpcpp'
 
       ss.source_files = ${ruby_multiline_list(grpcpp_public_headers(libs, filegroups), 22)}
     end
@@ -174,16 +195,6 @@
       ss.private_header_files = ${ruby_multiline_list(grpcpp_private_headers(libs, filegroups), 30)}
     end
 
-    s.subspec 'Tests' do |ss|
-      ss.header_mappings_dir = '.'
-
-      ss.dependency "#{s.name}/Interface", version
-      ss.dependency "#{s.name}/Implementation", version
-      ss.dependency "gRPC-Core/Tests", grpc_version
-
-      ss.source_files = ${ruby_multiline_list(grpcpp_test_util_files(libs, filegroups), 22)}
-    end
-
     s.prepare_command = <<-END_OF_COMMAND
       find src/cpp/ -type f -exec sed -E -i'.back' 's;#include "third_party/nanopb/(.*)";#include <nanopb/\\1>;g' {} \\\;
       find src/cpp/ -name "*.back" -type f -delete
diff --git a/templates/gRPC-Core.podspec.template b/templates/gRPC-Core.podspec.template
index c28b78d..33a8a8b 100644
--- a/templates/gRPC-Core.podspec.template
+++ b/templates/gRPC-Core.podspec.template
@@ -42,21 +42,21 @@
     out = grpc_lib_files(libs, ("grpc", "gpr"), ("headers",))
     return [file for file in out if not file.startswith("third_party/nanopb/")]
 
-  def grpc_cronet_files(libs):
-    out = grpc_lib_files(libs, ("grpc_cronet",), ("src", "headers"))
-    excl = grpc_private_files(libs)
-    excl += [
-        # We do not need cronet dedicated plugin registry
-        "src/core/plugin_registry/grpc_cronet_plugin_registry.cc",
-        # We do not need dummy cronet API for ObjC
+  def grpc_cronet_private_files(libs):
+    out = grpc_lib_files(libs, ("grpc_cronet", "gpr"), ("headers", "src"))
+    excl = [
+        # We do not want dummy cronet API for ObjC
         "src/core/ext/transport/cronet/transport/cronet_api_dummy.cc",
     ]
     return [file for file in out if not file in excl]
 
   def grpc_cronet_public_headers(libs):
-    out = grpc_lib_files(libs, ("grpc_cronet",), ("public_headers",))
-    excl = grpc_public_headers(libs)
-    return [file for file in out if not file in excl]
+    out = grpc_lib_files(libs, ("grpc_cronet", "gpr"), ("public_headers",))
+    return out
+
+  def grpc_cronet_private_headers(libs):
+    out = grpc_lib_files(libs, ("grpc_cronet", "gpr"), ("headers",))
+    return out
 
   def grpc_test_util_files(libs):
     out = grpc_lib_files(libs, ("grpc_test_util", "gpr_test_util"), ("src", "headers"))
@@ -144,7 +144,7 @@
     }
 
     s.default_subspecs = 'Interface', 'Implementation'
-    s.compiler_flags = '-DGRPC_ARES=0'
+    s.compiler_flags = '-DGRPC_ARES=0', '-DPB_FIELD_16BIT'
     s.libraries = 'c++'
 
     # Like many other C libraries, gRPC-Core has its public headers under `include/<libname>/` and its
@@ -169,7 +169,6 @@
       ss.dependency 'BoringSSL', '~> 10.0'
       ss.dependency 'nanopb', '~> 0.3'
 
-      # To save you from scrolling, this is the last part of the podspec.
       ss.source_files = ${ruby_multiline_list(grpc_private_files(libs), 22)}
 
       ss.private_header_files = ${ruby_multiline_list(grpc_private_headers(libs), 30)}
@@ -182,19 +181,21 @@
 
     s.subspec 'Cronet-Implementation' do |ss|
       ss.header_mappings_dir = '.'
-
-      ss.dependency "#{s.name}/Interface", version
-      ss.dependency "#{s.name}/Implementation", version
+      ss.libraries = 'z'
       ss.dependency "#{s.name}/Cronet-Interface", version
+      ss.dependency 'BoringSSL', '~> 10.0'
+      ss.dependency 'nanopb', '~> 0.3'
 
-      ss.source_files = ${ruby_multiline_list(grpc_cronet_files(libs), 22)}
+      ss.source_files = ${ruby_multiline_list(grpc_cronet_private_files(libs), 22)}
+
+      ss.private_header_files = ${ruby_multiline_list(grpc_cronet_private_headers(libs), 30)}
     end
 
-    s.subspec 'Tests' do |ss|
+    s.subspec 'Cronet-Tests' do |ss|
       ss.header_mappings_dir = '.'
 
-      ss.dependency "#{s.name}/Interface", version
-      ss.dependency "#{s.name}/Implementation", version
+      ss.dependency "#{s.name}/Cronet-Interface", version
+      ss.dependency "#{s.name}/Cronet-Implementation", version
 
       ss.source_files = ${ruby_multiline_list(grpc_test_util_files(libs), 22)},
                         ${ruby_multiline_list(end2end_tests_files(libs), 22)}
@@ -202,6 +203,6 @@
 
     # TODO (mxyan): Instead of this hack, add include path "third_party" to C core's include path?
     s.prepare_command = <<-END_OF_COMMAND
-      find src/core/ -type f -exec sed -E -i'.back' 's;#include "third_party/nanopb/(.*)";#include <nanopb/\\1>;g' {} \\\;
+      find src/core/ -type f ! -path '*.back*' -exec sed -E -i'.back' 's;#include "third_party/nanopb/(.*)";#include <nanopb/\\1>;g' {} \\\;
     END_OF_COMMAND
   end
diff --git a/templates/grpc.gyp.template b/templates/grpc.gyp.template
index 3363082..2ea0d06 100644
--- a/templates/grpc.gyp.template
+++ b/templates/grpc.gyp.template
@@ -60,11 +60,11 @@
       % endfor
       'cflags_c': [
         '-Werror',
-        '-std=c99'
+        '-std=c99',
       ],
       'cflags_cc': [
         '-Werror',
-        '-std=c++11'
+        '-std=c++11',
       ],
       'include_dirs': [
         '.',
@@ -127,7 +127,7 @@
               % endfor
               '-stdlib=libc++',
               '-std=c++11',
-              '-Wno-error=deprecated-declarations'
+              '-Wno-error=deprecated-declarations',
             ],
             % endif
           },
diff --git a/templates/src/core/lib/surface/version.cc.template b/templates/src/core/lib/surface/version.cc.template
index d9fa447..0cb3154 100644
--- a/templates/src/core/lib/surface/version.cc.template
+++ b/templates/src/core/lib/surface/version.cc.template
@@ -21,6 +21,8 @@
   /* This file is autogenerated from:
      templates/src/core/surface/version.c.template */
 
+  #include <grpc/support/port_platform.h>
+
   #include <grpc/grpc.h>
 
   const char* grpc_version_string(void) { return "${settings.core_version}"; }
diff --git a/templates/src/core/plugin_registry.template b/templates/src/core/plugin_registry.template
index 805ae90..a00d204 100644
--- a/templates/src/core/plugin_registry.template
+++ b/templates/src/core/plugin_registry.template
@@ -22,6 +22,8 @@
    *
    */
 
+  #include <grpc/support/port_platform.h>
+
   #include <grpc/grpc.h>
 
   %for plugin in selected.plugins:
diff --git a/templates/src/cpp/common/version_cc.cc.template b/templates/src/cpp/common/version_cc.cc.template
index 9882878..a3b0cf6 100644
--- a/templates/src/cpp/common/version_cc.cc.template
+++ b/templates/src/cpp/common/version_cc.cc.template
@@ -21,7 +21,7 @@
   /* This file is autogenerated from:
      templates/src/core/surface/version.c.template */
 
-  #include <grpc++/grpc++.h>
+  #include <grpcpp/grpcpp.h>
 
   namespace grpc {
   grpc::string Version() { return "${settings.cpp_version}"; }
diff --git a/templates/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs.template b/templates/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs.template
new file mode 100644
index 0000000..8ce2a57
--- /dev/null
+++ b/templates/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs.template
@@ -0,0 +1,208 @@
+%YAML 1.2
+--- |
+  <%
+    native_method_signatures = [
+      'void grpcsharp_init()',
+      'void grpcsharp_shutdown()',
+      'IntPtr grpcsharp_version_string()  // returns not-owned const char*',
+      'BatchContextSafeHandle grpcsharp_batch_context_create()',
+      'IntPtr grpcsharp_batch_context_recv_initial_metadata(BatchContextSafeHandle ctx)',
+      'IntPtr grpcsharp_batch_context_recv_message_length(BatchContextSafeHandle ctx)',
+      'void grpcsharp_batch_context_recv_message_to_buffer(BatchContextSafeHandle ctx, byte[] buffer, UIntPtr bufferLen)',
+      'StatusCode grpcsharp_batch_context_recv_status_on_client_status(BatchContextSafeHandle ctx)',
+      'IntPtr grpcsharp_batch_context_recv_status_on_client_details(BatchContextSafeHandle ctx, out UIntPtr detailsLength)',
+      'IntPtr grpcsharp_batch_context_recv_status_on_client_trailing_metadata(BatchContextSafeHandle ctx)',
+      'int grpcsharp_batch_context_recv_close_on_server_cancelled(BatchContextSafeHandle ctx)',
+      'void grpcsharp_batch_context_reset(BatchContextSafeHandle ctx)',
+      'void grpcsharp_batch_context_destroy(IntPtr ctx)',
+      'RequestCallContextSafeHandle grpcsharp_request_call_context_create()',
+      'CallSafeHandle grpcsharp_request_call_context_call(RequestCallContextSafeHandle ctx)',
+      'IntPtr grpcsharp_request_call_context_method(RequestCallContextSafeHandle ctx, out UIntPtr methodLength)',
+      'IntPtr grpcsharp_request_call_context_host(RequestCallContextSafeHandle ctx, out UIntPtr hostLength)',
+      'Timespec grpcsharp_request_call_context_deadline(RequestCallContextSafeHandle ctx)',
+      'IntPtr grpcsharp_request_call_context_request_metadata(RequestCallContextSafeHandle ctx)',
+      'void grpcsharp_request_call_context_reset(RequestCallContextSafeHandle ctx)',
+      'void grpcsharp_request_call_context_destroy(IntPtr ctx)',
+      'CallCredentialsSafeHandle grpcsharp_composite_call_credentials_create(CallCredentialsSafeHandle creds1, CallCredentialsSafeHandle creds2)',
+      'void grpcsharp_call_credentials_release(IntPtr credentials)',
+      'CallError grpcsharp_call_cancel(CallSafeHandle call)',
+      'CallError grpcsharp_call_cancel_with_status(CallSafeHandle call, StatusCode status, string description)',
+      'CallError grpcsharp_call_start_unary(CallSafeHandle call, BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags)',
+      'CallError grpcsharp_call_start_client_streaming(CallSafeHandle call, BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags)',
+      'CallError grpcsharp_call_start_server_streaming(CallSafeHandle call, BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags)',
+      'CallError grpcsharp_call_start_duplex_streaming(CallSafeHandle call, BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags)',
+      'CallError grpcsharp_call_send_message(CallSafeHandle call, BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, int sendEmptyInitialMetadata)',
+      'CallError grpcsharp_call_send_close_from_client(CallSafeHandle call, BatchContextSafeHandle ctx)',
+      'CallError grpcsharp_call_send_status_from_server(CallSafeHandle call, BatchContextSafeHandle ctx, StatusCode statusCode, byte[] statusMessage, UIntPtr statusMessageLen, MetadataArraySafeHandle metadataArray, int sendEmptyInitialMetadata, byte[] optionalSendBuffer, UIntPtr optionalSendBufferLen, WriteFlags writeFlags)',
+      'CallError grpcsharp_call_recv_message(CallSafeHandle call, BatchContextSafeHandle ctx)',
+      'CallError grpcsharp_call_recv_initial_metadata(CallSafeHandle call, BatchContextSafeHandle ctx)',
+      'CallError grpcsharp_call_start_serverside(CallSafeHandle call, BatchContextSafeHandle ctx)',
+      'CallError grpcsharp_call_send_initial_metadata(CallSafeHandle call, BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray)',
+      'CallError grpcsharp_call_set_credentials(CallSafeHandle call, CallCredentialsSafeHandle credentials)',
+      'CStringSafeHandle grpcsharp_call_get_peer(CallSafeHandle call)',
+      'void grpcsharp_call_destroy(IntPtr call)',
+      'ChannelArgsSafeHandle grpcsharp_channel_args_create(UIntPtr numArgs)',
+      'void grpcsharp_channel_args_set_string(ChannelArgsSafeHandle args, UIntPtr index, string key, string value)',
+      'void grpcsharp_channel_args_set_integer(ChannelArgsSafeHandle args, UIntPtr index, string key, int value)',
+      'void grpcsharp_channel_args_destroy(IntPtr args)',
+      'void grpcsharp_override_default_ssl_roots(string pemRootCerts)',
+      'ChannelCredentialsSafeHandle grpcsharp_ssl_credentials_create(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey)',
+      'ChannelCredentialsSafeHandle grpcsharp_composite_channel_credentials_create(ChannelCredentialsSafeHandle channelCreds, CallCredentialsSafeHandle callCreds)',
+      'void grpcsharp_channel_credentials_release(IntPtr credentials)',
+      'ChannelSafeHandle grpcsharp_insecure_channel_create(string target, ChannelArgsSafeHandle channelArgs)',
+      'ChannelSafeHandle grpcsharp_secure_channel_create(ChannelCredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs)',
+      'CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline)',
+      'ChannelState grpcsharp_channel_check_connectivity_state(ChannelSafeHandle channel, int tryToConnect)',
+      'void grpcsharp_channel_watch_connectivity_state(ChannelSafeHandle channel, ChannelState lastObservedState, Timespec deadline, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx)',
+      'CStringSafeHandle grpcsharp_channel_get_target(ChannelSafeHandle call)',
+      'void grpcsharp_channel_destroy(IntPtr channel)',
+      'int grpcsharp_sizeof_grpc_event()',
+      'CompletionQueueSafeHandle grpcsharp_completion_queue_create_async()',
+      'CompletionQueueSafeHandle grpcsharp_completion_queue_create_sync()',
+      'void grpcsharp_completion_queue_shutdown(CompletionQueueSafeHandle cq)',
+      'CompletionQueueEvent grpcsharp_completion_queue_next(CompletionQueueSafeHandle cq)',
+      'CompletionQueueEvent grpcsharp_completion_queue_pluck(CompletionQueueSafeHandle cq, IntPtr tag)',
+      'void grpcsharp_completion_queue_destroy(IntPtr cq)',
+      'void gprsharp_free(IntPtr ptr)',
+      'MetadataArraySafeHandle grpcsharp_metadata_array_create(UIntPtr capacity)',
+      'void grpcsharp_metadata_array_add(MetadataArraySafeHandle array, string key, byte[] value, UIntPtr valueLength)',
+      'UIntPtr grpcsharp_metadata_array_count(IntPtr metadataArray)',
+      'IntPtr grpcsharp_metadata_array_get_key(IntPtr metadataArray, UIntPtr index, out UIntPtr keyLength)',
+      'IntPtr grpcsharp_metadata_array_get_value(IntPtr metadataArray, UIntPtr index, out UIntPtr valueLength)',
+      'void grpcsharp_metadata_array_destroy_full(IntPtr array)',
+      'void grpcsharp_redirect_log(GprLogDelegate callback)',
+      'CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin(NativeMetadataInterceptor interceptor)',
+      'void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails)',
+      'ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, int forceClientAuth)',
+      'void grpcsharp_server_credentials_release(IntPtr credentials)',
+      'ServerSafeHandle grpcsharp_server_create(ChannelArgsSafeHandle args)',
+      'void grpcsharp_server_register_completion_queue(ServerSafeHandle server, CompletionQueueSafeHandle cq)',
+      'int grpcsharp_server_add_insecure_http2_port(ServerSafeHandle server, string addr)',
+      'int grpcsharp_server_add_secure_http2_port(ServerSafeHandle server, string addr, ServerCredentialsSafeHandle creds)',
+      'void grpcsharp_server_start(ServerSafeHandle server)',
+      'CallError grpcsharp_server_request_call(ServerSafeHandle server, CompletionQueueSafeHandle cq, RequestCallContextSafeHandle ctx)',
+      'void grpcsharp_server_cancel_all_calls(ServerSafeHandle server)',
+      'void grpcsharp_server_shutdown_and_notify_callback(ServerSafeHandle server, CompletionQueueSafeHandle cq, BatchContextSafeHandle ctx)',
+      'void grpcsharp_server_destroy(IntPtr server)',
+      'AuthContextSafeHandle grpcsharp_call_auth_context(CallSafeHandle call)',
+      'IntPtr grpcsharp_auth_context_peer_identity_property_name(AuthContextSafeHandle authContext)  // returns const char*',
+      'AuthContextSafeHandle.NativeAuthPropertyIterator grpcsharp_auth_context_property_iterator(AuthContextSafeHandle authContext)',
+      'IntPtr grpcsharp_auth_property_iterator_next(ref AuthContextSafeHandle.NativeAuthPropertyIterator iterator)  // returns const auth_property*',
+      'void grpcsharp_auth_context_release(IntPtr authContext)',
+      'Timespec gprsharp_now(ClockType clockType)',
+      'Timespec gprsharp_inf_future(ClockType clockType)',
+      'Timespec gprsharp_inf_past(ClockType clockType)',
+      'Timespec gprsharp_convert_clock_type(Timespec t, ClockType targetClock)',
+      'int gprsharp_sizeof_timespec()',
+      'CallError grpcsharp_test_callback([MarshalAs(UnmanagedType.FunctionPtr)] NativeCallbackTestDelegate callback)',
+      'IntPtr grpcsharp_test_nop(IntPtr ptr)',
+      'void grpcsharp_test_override_method(string methodName, string variant)',
+    ]
+    
+    import re
+    native_methods = []
+    for signature in native_method_signatures:
+      match = re.match('([A-Za-z0-9_.]+) +([A-Za-z0-9_]+)\\((.*)\\)(.*)', signature)
+      if not match:
+        raise Exception('Malformed signature "%s"' % signature)
+      native_methods.append({'returntype': match.group(1), 'name': match.group(2), 'params': match.group(3), 'comment': match.group(4)})
+  %>
+  #region Copyright notice and license
+  
+  // Copyright 2015 gRPC authors.
+  //
+  // Licensed under the Apache License, Version 2.0 (the "License");
+  // you may not use this file except in compliance with the License.
+  // You may obtain a copy of the License at
+  //
+  //     http://www.apache.org/licenses/LICENSE-2.0
+  //
+  // Unless required by applicable law or agreed to in writing, software
+  // distributed under the License is distributed on an "AS IS" BASIS,
+  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  // See the License for the specific language governing permissions and
+  // limitations under the License.
+  
+  #endregion
+  
+  using System;
+  using System.Collections.Concurrent;
+  using System.Diagnostics;
+  using System.IO;
+  using System.Reflection;
+  using System.Runtime.InteropServices;
+  using System.Threading;
+  
+  using Grpc.Core.Logging;
+  using Grpc.Core.Utils;
+  
+  namespace Grpc.Core.Internal
+  {
+      internal partial class NativeMethods
+      {
+          #region Native methods
+          
+          % for method in native_methods:
+          public readonly Delegates.${method['name']}_delegate ${method['name']};
+          % endfor
+
+          #endregion
+  
+          public NativeMethods(UnmanagedLibrary library)
+          {
+              % for method in native_methods:
+              this.${method['name']} = GetMethodDelegate<Delegates.${method['name']}_delegate>(library);
+              % endfor
+          }
+          
+          public NativeMethods(DllImportsFromStaticLib unusedInstance)
+          {
+              % for method in native_methods:
+              this.${method['name']} = DllImportsFromStaticLib.${method['name']};
+              % endfor
+          }
+          
+          public NativeMethods(DllImportsFromSharedLib unusedInstance)
+          {
+              % for method in native_methods:
+              this.${method['name']} = DllImportsFromSharedLib.${method['name']};
+              % endfor
+          }
+
+          /// <summary>
+          /// Delegate types for all published native methods. Declared under inner class to prevent scope pollution.
+          /// </summary>
+          public class Delegates
+          {
+              % for method in native_methods:
+              public delegate ${method['returntype']} ${method['name']}_delegate(${method['params']});${method['comment']}
+              % endfor
+          }
+          
+          /// <summary>
+          /// grpc_csharp_ext used as a static library (e.g Unity iOS).
+          /// </summary>
+          internal class DllImportsFromStaticLib
+          {
+              private const string ImportName = "__Internal";
+              % for method in native_methods:
+              
+              [DllImport(ImportName)]
+              public static extern ${method['returntype']} ${method['name']}(${method['params']});
+              % endfor
+          }
+          
+          /// <summary>
+          /// grpc_csharp_ext used a shared library (e.g on Unity Standalone and Android).
+          /// </summary>
+          internal class DllImportsFromSharedLib
+          {
+              private const string ImportName = "grpc_csharp_ext";
+              % for method in native_methods:
+              
+              [DllImport(ImportName)]
+              public static extern ${method['returntype']} ${method['name']}(${method['params']});
+              % endfor
+          }
+      }
+  }
diff --git a/templates/src/csharp/build_packages_dotnetcli.bat.template b/templates/src/csharp/build_packages_dotnetcli.bat.template
index 6671991..1bf78c4 100755
--- a/templates/src/csharp/build_packages_dotnetcli.bat.template
+++ b/templates/src/csharp/build_packages_dotnetcli.bat.template
@@ -21,17 +21,21 @@
   set NUGET=C:\nuget\nuget.exe
   set DOTNET=dotnet
   
-  set -ex
-  
   mkdir ..\..\artifacts
   
   @rem Collect the artifacts built by the previous build step if running on Jenkins
   mkdir nativelibs
+  @rem Jenkins flow (deprecated)
   powershell -Command "cp -r ..\..\platform=*\artifacts\csharp_ext_* nativelibs"
+  @rem Kokoro flow
+  powershell -Command "cp -r ..\..\input_artifacts\csharp_ext_* nativelibs"
   
   @rem Collect protoc artifacts built by the previous build step
   mkdir protoc_plugins
+  @rem Jenkins flow (deprecated)
   powershell -Command "cp -r ..\..\platform=*\artifacts\protoc_* protoc_plugins"
+  @rem Kokoro flow
+  powershell -Command "cp -r ..\..\input_artifacts\protoc_* protoc_plugins"
   
   %%DOTNET% restore Grpc.sln || goto :error
   
diff --git a/templates/src/csharp/build_packages_dotnetcli.sh.template b/templates/src/csharp/build_packages_dotnetcli.sh.template
index be52b46..ddfea74 100755
--- a/templates/src/csharp/build_packages_dotnetcli.sh.template
+++ b/templates/src/csharp/build_packages_dotnetcli.sh.template
@@ -23,11 +23,17 @@
   
   # Collect the artifacts built by the previous build step
   mkdir -p nativelibs
+  # Jenkins flow (deprecated)
   cp -r $EXTERNAL_GIT_ROOT/platform={windows,linux,macos}/artifacts/csharp_ext_* nativelibs || true
+  # Kokoro flow
+  cp -r $EXTERNAL_GIT_ROOT/input_artifacts/csharp_ext_* nativelibs || true
   
   # Collect protoc artifacts built by the previous build step
   mkdir -p protoc_plugins
+  # Jenkins flow (deprecated)
   cp -r $EXTERNAL_GIT_ROOT/platform={windows,linux,macos}/artifacts/protoc_* protoc_plugins || true
+  # Kokoro flow
+  cp -r $EXTERNAL_GIT_ROOT/input_artifacts/protoc_* protoc_plugins || true
   
   dotnet restore Grpc.sln
   
diff --git a/templates/test/cpp/naming/create_private_dns_zone_defs.include b/templates/test/cpp/naming/create_private_dns_zone_defs.include
index 465dd63..76af9ab 100644
--- a/templates/test/cpp/naming/create_private_dns_zone_defs.include
+++ b/templates/test/cpp/naming/create_private_dns_zone_defs.include
@@ -17,7 +17,7 @@
 
 set -ex
 
-cd $(dirname $0)/../../..
+cd "$(dirname "$0")/../../.."
 
 gcloud alpha dns managed-zones create \\
 
diff --git a/templates/test/cpp/naming/private_dns_zone_init_defs.include b/templates/test/cpp/naming/private_dns_zone_init_defs.include
index 06bc8ad..1a6a590 100644
--- a/templates/test/cpp/naming/private_dns_zone_init_defs.include
+++ b/templates/test/cpp/naming/private_dns_zone_init_defs.include
@@ -17,7 +17,7 @@
 
 set -ex
 
-cd $(dirname $0)/../../..
+cd "$(dirname "$0")/../../.."
 
 gcloud dns record-sets transaction start -z=${resolver_gce_integration_tests_zone_id}
 
diff --git a/templates/test/cpp/naming/resolver_component_tests_defs.include b/templates/test/cpp/naming/resolver_component_tests_defs.include
index 6fa91c7..01e1860 100644
--- a/templates/test/cpp/naming/resolver_component_tests_defs.include
+++ b/templates/test/cpp/naming/resolver_component_tests_defs.include
@@ -18,12 +18,14 @@
 set -ex
 
 # all command args required in this set order
-FLAGS_test_bin_path=`echo "$1" | grep '\--test_bin_path=' | cut -d "=" -f 2`
-FLAGS_dns_server_bin_path=`echo "$2" | grep '\--dns_server_bin_path=' | cut -d "=" -f 2`
-FLAGS_records_config_path=`echo "$3" | grep '\--records_config_path=' | cut -d "=" -f 2`
-FLAGS_test_dns_server_port=`echo "$4" | grep '\--test_dns_server_port=' | cut -d "=" -f 2`
+FLAGS_test_bin_path=$(echo "$1" | grep '\--test_bin_path=' | sed 's/^--test_bin_path=//')
+FLAGS_dns_server_bin_path=$(echo "$2" | grep '\--dns_server_bin_path=' | sed 's/^--dns_server_bin_path=//')
+FLAGS_records_config_path=$(echo "$3" | grep '\--records_config_path=' | sed 's/^--records_config_path=//')
+FLAGS_dns_server_port=$(echo "$4" | grep '\--dns_server_port=' | sed 's/^--dns_server_port=//')
+FLAGS_dns_resolver_bin_path=$(echo "$5" | grep '\--dns_resolver_bin_path=' | sed 's/^--dns_resolver_bin_path=//')
+FLAGS_tcp_connect_bin_path=$(echo "$6" | grep '\--tcp_connect_bin_path=' | sed 's/^--tcp_connect_bin_path=//')
 
-for cmd_arg in "$FLAGS_test_bin_path" "$FLAGS_dns_server_bin_path" "$FLAGS_records_config_path" "$FLAGS_test_dns_server_port"; do
+for cmd_arg in "$FLAGS_test_bin_path" "$FLAGS_dns_server_bin_path" "$FLAGS_records_config_path" "$FLAGS_dns_server_port" "$FLAGS_dns_resolver_bin_path" "$FLAGS_tcp_connect_bin_path"; do
   if [[ "$cmd_arg" == "" ]]; then
     echo "Missing a CMD arg" && exit 1
   fi
@@ -34,17 +36,17 @@
 fi
 export GRPC_DNS_RESOLVER=ares
 
-"$FLAGS_dns_server_bin_path" --records_config_path="$FLAGS_records_config_path" --port="$FLAGS_test_dns_server_port" 2>&1 > /dev/null &
+"$FLAGS_dns_server_bin_path" --records_config_path="$FLAGS_records_config_path" --port="$FLAGS_dns_server_port" > /dev/null 2>&1 &
 DNS_SERVER_PID=$!
 echo "Local DNS server started. PID: $DNS_SERVER_PID"
 
 # Health check local DNS server TCP and UDP ports
 for ((i=0;i<30;i++));
 do
-  echo "Retry health-check DNS query to local DNS server over tcp and udp"
+  echo "Retry health-check local DNS server by attempting a DNS query and TCP handshake"
   RETRY=0
-  dig A health-check-local-dns-server-is-alive.resolver-tests.grpctestingexp. @localhost -p "$FLAGS_test_dns_server_port" +tries=1 +timeout=1 | grep '123.123.123.123' || RETRY=1
-  dig A health-check-local-dns-server-is-alive.resolver-tests.grpctestingexp. @localhost -p "$FLAGS_test_dns_server_port" +tries=1 +timeout=1 +tcp | grep '123.123.123.123' || RETRY=1
+  $FLAGS_dns_resolver_bin_path -s 127.0.0.1 -p "$FLAGS_dns_server_port" -n health-check-local-dns-server-is-alive.resolver-tests.grpctestingexp. -t 1 | grep '123.123.123.123' || RETRY=1
+  $FLAGS_tcp_connect_bin_path -s 127.0.0.1 -p "$FLAGS_dns_server_port" -t 1 || RETRY=1
   if [[ "$RETRY" == 0 ]]; then
     break
   fi;
@@ -53,15 +55,15 @@
 
 if [[ $RETRY == 1 ]]; then
   echo "FAILED TO START LOCAL DNS SERVER"
-  kill -SIGTERM $DNS_SERVER_PID
+  kill -SIGTERM "$DNS_SERVER_PID"
   wait
   exit 1
 fi
 
 function terminate_all {
   echo "Received signal. Terminating $! and $DNS_SERVER_PID"
-  kill -SIGTERM $! || true
-  kill -SIGTERM $DNS_SERVER_PID || true
+  kill -SIGTERM "$!" || true
+  kill -SIGTERM "$DNS_SERVER_PID" || true
   wait
   exit 1
 }
@@ -83,10 +85,10 @@
 
   --expected_lb_policy='${test['expected_lb_policy']}' \\
 
-  --local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port &
-wait $! || EXIT_CODE=1
+  --local_dns_server_address="127.0.0.1:$FLAGS_dns_server_port" &
+wait "$!" || EXIT_CODE=1
 
 % endfor
-kill -SIGTERM $DNS_SERVER_PID || true
+kill -SIGTERM "$DNS_SERVER_PID" || true
 wait
 exit $EXIT_CODE</%def>
diff --git a/templates/test/cpp/naming/resolver_gce_integration_tests_defs.include b/templates/test/cpp/naming/resolver_gce_integration_tests_defs.include
index 2413ec5..0cb8a1b 100644
--- a/templates/test/cpp/naming/resolver_gce_integration_tests_defs.include
+++ b/templates/test/cpp/naming/resolver_gce_integration_tests_defs.include
@@ -24,7 +24,7 @@
   exit 1
 fi
 
-cd $(dirname $0)/../../..
+cd "$(dirname "$0")/../../.."
 
 if [[ "$CONFIG" == "" ]]; then
   export CONFIG=opt
diff --git a/templates/tools/dockerfile/grpc_clang_format/Dockerfile.template b/templates/tools/dockerfile/grpc_clang_format/Dockerfile.template
index 4f24a02..c5ec66a 100644
--- a/templates/tools/dockerfile/grpc_clang_format/Dockerfile.template
+++ b/templates/tools/dockerfile/grpc_clang_format/Dockerfile.template
@@ -18,6 +18,11 @@
   
   <%include file="../clang5.include"/>
   ADD clang_format_all_the_things.sh /
+  
+  # When running locally, we'll be impersonating the current user, so we need
+  # to make the script runnable by everyone.
+  RUN chmod a+rx /clang_format_all_the_things.sh
+  
   CMD ["echo 'Run with tools/distrib/clang_format_code.sh'"]
   
   
diff --git a/templates/tools/dockerfile/grpc_clang_tidy/Dockerfile.template b/templates/tools/dockerfile/grpc_clang_tidy/Dockerfile.template
index f5bceaa..bbdba70 100644
--- a/templates/tools/dockerfile/grpc_clang_tidy/Dockerfile.template
+++ b/templates/tools/dockerfile/grpc_clang_tidy/Dockerfile.template
@@ -19,6 +19,11 @@
   <%include file="../clang5.include"/>
   <%include file="../python_deps.include"/>
   ADD clang_tidy_all_the_things.sh /
+  
+  # When running locally, we'll be impersonating the current user, so we need
+  # to make the script runnable by everyone.
+  RUN chmod a+rx /clang_tidy_all_the_things.sh
+  
   CMD ["echo 'Run with tools/distrib/clang_tidy_code.sh'"]
   
   
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_dart/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_dart/Dockerfile.template
new file mode 100644
index 0000000..8b71716
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_dart/Dockerfile.template
@@ -0,0 +1,20 @@
+%YAML 1.2
+--- |
+  # Copyright 2017 gRPC authors.
+  #
+  # Licensed under the Apache License, Version 2.0 (the "License");
+  # you may not use this file except in compliance with the License.
+  # You may obtain a copy of the License at
+  #
+  #     http://www.apache.org/licenses/LICENSE-2.0
+  #
+  # Unless required by applicable law or agreed to in writing, software
+  # distributed under the License is distributed on an "AS IS" BASIS,
+  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  # See the License for the specific language governing permissions and
+  # limitations under the License.
+
+  FROM google/dart:latest
+
+  # Define the default command.
+  CMD ["bash"]
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_dart/build_interop.sh.template b/templates/tools/dockerfile/interoptest/grpc_interop_dart/build_interop.sh.template
new file mode 100644
index 0000000..99f60bf
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_dart/build_interop.sh.template
@@ -0,0 +1,28 @@
+%YAML 1.2
+--- |
+  #!/bin/bash
+  # Copyright 2017 gRPC authors.
+  #
+  # Licensed under the Apache License, Version 2.0 (the "License");
+  # you may not use this file except in compliance with the License.
+  # You may obtain a copy of the License at
+  #
+  #     http://www.apache.org/licenses/LICENSE-2.0
+  #
+  # Unless required by applicable law or agreed to in writing, software
+  # distributed under the License is distributed on an "AS IS" BASIS,
+  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  # See the License for the specific language governing permissions and
+  # limitations under the License.
+  #
+  # Builds Dart interop server and client in a base image.
+  set -e
+
+  mkdir -p /var/local/git
+  git clone /var/local/jenkins/grpc-dart /var/local/git/grpc-dart
+
+  # copy service account keys if available
+  cp -r /var/local/jenkins/service_account $HOME || true
+
+  cd /var/local/git/grpc-dart/interop
+  /usr/lib/dart/bin/pub get
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_nodepurejs/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_nodepurejs/Dockerfile.template
new file mode 100644
index 0000000..e53d863
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_nodepurejs/Dockerfile.template
@@ -0,0 +1,23 @@
+%YAML 1.2
+--- |
+  # Copyright 2015 gRPC authors.
+  #
+  # Licensed under the Apache License, Version 2.0 (the "License");
+  # you may not use this file except in compliance with the License.
+  # You may obtain a copy of the License at
+  #
+  #     http://www.apache.org/licenses/LICENSE-2.0
+  #
+  # Unless required by applicable law or agreed to in writing, software
+  # distributed under the License is distributed on an "AS IS" BASIS,
+  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  # See the License for the specific language governing permissions and
+  # limitations under the License.
+
+  FROM debian:jessie
+
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../node_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
diff --git a/templates/tools/dockerfile/node_deps.include b/templates/tools/dockerfile/node_deps.include
index 2f7d0d3..bee3087 100644
--- a/templates/tools/dockerfile/node_deps.include
+++ b/templates/tools/dockerfile/node_deps.include
@@ -9,4 +9,5 @@
 RUN /bin/bash -l -c "nvm install 5 && npm config set cache /tmp/npm-cache && npm install -g npm"
 RUN /bin/bash -l -c "nvm install 6 && npm config set cache /tmp/npm-cache && npm install -g npm"
 RUN /bin/bash -l -c "nvm install 8 && npm config set cache /tmp/npm-cache && npm install -g npm"
-RUN /bin/bash -l -c "nvm alias default 8"
\ No newline at end of file
+RUN /bin/bash -l -c "nvm install 9 && npm config set cache /tmp/npm-cache && npm install -g npm"
+RUN /bin/bash -l -c "nvm alias default 9"
\ No newline at end of file
diff --git a/templates/tools/dockerfile/test/cxx_alpine_x64/Dockerfile.template b/templates/tools/dockerfile/test/cxx_alpine_x64/Dockerfile.template
new file mode 100644
index 0000000..1bbfdfd
--- /dev/null
+++ b/templates/tools/dockerfile/test/cxx_alpine_x64/Dockerfile.template
@@ -0,0 +1,57 @@
+%YAML 1.2
+--- |
+  # Copyright 2015 gRPC authors.
+  #
+  # Licensed under the Apache License, Version 2.0 (the "License");
+  # you may not use this file except in compliance with the License.
+  # You may obtain a copy of the License at
+  #
+  #     http://www.apache.org/licenses/LICENSE-2.0
+  #
+  # Unless required by applicable law or agreed to in writing, software
+  # distributed under the License is distributed on an "AS IS" BASIS,
+  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  # See the License for the specific language governing permissions and
+  # limitations under the License.
+  
+  FROM alpine:3.5
+  
+  # Install Git and basic packages.
+  RUN apk update && apk add ${'\\'}
+    autoconf ${'\\'}
+    automake ${'\\'}
+    bzip2 ${'\\'}
+    build-base ${'\\'}
+    cmake ${'\\'}
+    ccache ${'\\'}
+    curl ${'\\'}
+    gcc ${'\\'}
+    git ${'\\'}
+    libtool ${'\\'}
+    linux-headers ${'\\'}
+    make ${'\\'}
+    perl ${'\\'}
+    strace ${'\\'}
+    python-dev ${'\\'}
+    py-pip ${'\\'}
+    unzip ${'\\'}
+    wget ${'\\'}
+    zip
+  
+  # Install Python packages from PyPI
+  RUN pip install --upgrade pip==9.0.1
+  RUN pip install virtualenv
+  RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+  
+  # Google Cloud platform API libraries
+  RUN pip install --upgrade google-api-python-client
+  
+  # Install gflags
+  RUN git clone https://github.com/gflags/gflags.git && cd gflags && git checkout v2.2.0
+  RUN cd gflags && cmake . && make && make install
+  RUN ln -s /usr/local/include/gflags /usr/include/gflags
+  
+  <%include file="../../run_tests_addons.include"/>
+  
+  # Define the default command.
+  CMD ["bash"]
diff --git a/templates/tools/dockerfile/test/sanity/Dockerfile.template b/templates/tools/dockerfile/test/sanity/Dockerfile.template
index 7453e6c..69bb7c4 100644
--- a/templates/tools/dockerfile/test/sanity/Dockerfile.template
+++ b/templates/tools/dockerfile/test/sanity/Dockerfile.template
@@ -46,12 +46,12 @@
   RUN apt-get -y update
   RUN apt-get -y install bazel
 
-  # Pin Bazel to 0.4.4
-  # Installing Bazel via apt-get first is required before installing 0.4.4 to
+  # Pin Bazel to 0.9.0
+  # Installing Bazel via apt-get first is required before installing 0.9.0 to
   # allow gRPC to build without errors. See https://github.com/grpc/grpc/issues/10553
-  RUN curl -fSsL -O https://github.com/bazelbuild/bazel/releases/download/0.4.4/bazel-0.4.4-installer-linux-x86_64.sh
-  RUN chmod +x ./bazel-0.4.4-installer-linux-x86_64.sh
-  RUN ./bazel-0.4.4-installer-linux-x86_64.sh
+  RUN curl -fSsL -O https://github.com/bazelbuild/bazel/releases/download/0.9.0/bazel-0.9.0-installer-linux-x86_64.sh
+  RUN chmod +x ./bazel-0.9.0-installer-linux-x86_64.sh
+  RUN ./bazel-0.9.0-installer-linux-x86_64.sh
   
   <%include file="../../clang5.include"/>
   <%include file="../../run_tests_addons.include"/>
diff --git a/templates/tools/openssl/use_openssl.sh.template b/templates/tools/openssl/use_openssl.sh.template
index 8050816..b07ce13 100644
--- a/templates/tools/openssl/use_openssl.sh.template
+++ b/templates/tools/openssl/use_openssl.sh.template
@@ -18,7 +18,7 @@
 
   set -ex
 
-  cd $(dirname $0)/../..
+  cd "$(dirname "$0")/../.."
   set root=`pwd`
   CC=${"${CC:-cc}"}
 
diff --git a/test/core/avl/BUILD b/test/core/avl/BUILD
new file mode 100644
index 0000000..48f5bae
--- /dev/null
+++ b/test/core/avl/BUILD
@@ -0,0 +1,30 @@
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary", "grpc_package")
+
+licenses(["notice"])  # Apache v2
+
+grpc_package(name = "test/core/avl")
+
+grpc_cc_test(
+    name = "avl_test",
+    srcs = ["avl_test.cc"],
+    language = "C++",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+    ],
+)
diff --git a/test/core/avl/avl_test.cc b/test/core/avl/avl_test.cc
new file mode 100644
index 0000000..ecebe83
--- /dev/null
+++ b/test/core/avl/avl_test.cc
@@ -0,0 +1,3661 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/core/lib/avl/avl.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/gpr/useful.h"
+#include "test/core/util/test_config.h"
+
+static int* box(int x) {
+  int* b = static_cast<int*>(gpr_malloc(sizeof(*b)));
+  *b = x;
+  return b;
+}
+
+static long int_compare(void* int1, void* int2, void* unused) {
+  return (*static_cast<int*>(int1)) - (*static_cast<int*>(int2));
+}
+static void* int_copy(void* p, void* unused) {
+  return box(*static_cast<int*>(p));
+}
+
+static void destroy(void* p, void* unused) { gpr_free(p); }
+
+static const grpc_avl_vtable int_int_vtable = {destroy, int_copy, int_compare,
+                                               destroy, int_copy};
+
+static void check_get(grpc_avl avl, int key, int value) {
+  int* k = box(key);
+  GPR_ASSERT(*(int*)grpc_avl_get(avl, k, nullptr) == value);
+  gpr_free(k);
+}
+
+static void check_negget(grpc_avl avl, int key) {
+  int* k = box(key);
+  GPR_ASSERT(grpc_avl_get(avl, k, nullptr) == nullptr);
+  gpr_free(k);
+}
+
+static grpc_avl remove_int(grpc_avl avl, int key) {
+  int* k = box(key);
+  avl = grpc_avl_remove(avl, k, nullptr);
+  gpr_free(k);
+  return avl;
+}
+
+static void test_get(void) {
+  grpc_avl avl;
+  gpr_log(GPR_DEBUG, "test_get");
+  avl = grpc_avl_create(&int_int_vtable);
+  avl = grpc_avl_add(avl, box(1), box(11), nullptr);
+  avl = grpc_avl_add(avl, box(2), box(22), nullptr);
+  avl = grpc_avl_add(avl, box(3), box(33), nullptr);
+  check_get(avl, 1, 11);
+  check_get(avl, 2, 22);
+  check_get(avl, 3, 33);
+  check_negget(avl, 4);
+  grpc_avl_unref(avl, nullptr);
+}
+
+static void test_ll(void) {
+  grpc_avl avl;
+  gpr_log(GPR_DEBUG, "test_ll");
+  avl = grpc_avl_create(&int_int_vtable);
+  avl = grpc_avl_add(avl, box(5), box(1), nullptr);
+  avl = grpc_avl_add(avl, box(4), box(2), nullptr);
+  avl = grpc_avl_add(avl, box(3), box(3), nullptr);
+  GPR_ASSERT(*(int*)avl.root->key == 4);
+  GPR_ASSERT(*(int*)avl.root->left->key == 3);
+  GPR_ASSERT(*(int*)avl.root->right->key == 5);
+  grpc_avl_unref(avl, nullptr);
+}
+
+static void test_lr(void) {
+  grpc_avl avl;
+  gpr_log(GPR_DEBUG, "test_lr");
+  avl = grpc_avl_create(&int_int_vtable);
+  avl = grpc_avl_add(avl, box(5), box(1), nullptr);
+  avl = grpc_avl_add(avl, box(3), box(2), nullptr);
+  avl = grpc_avl_add(avl, box(4), box(3), nullptr);
+  GPR_ASSERT(*(int*)avl.root->key == 4);
+  GPR_ASSERT(*(int*)avl.root->left->key == 3);
+  GPR_ASSERT(*(int*)avl.root->right->key == 5);
+  grpc_avl_unref(avl, nullptr);
+}
+
+static void test_rr(void) {
+  grpc_avl avl;
+  gpr_log(GPR_DEBUG, "test_rr");
+  avl = grpc_avl_create(&int_int_vtable);
+  avl = grpc_avl_add(avl, box(3), box(1), nullptr);
+  avl = grpc_avl_add(avl, box(4), box(2), nullptr);
+  avl = grpc_avl_add(avl, box(5), box(3), nullptr);
+  GPR_ASSERT(*(int*)avl.root->key == 4);
+  GPR_ASSERT(*(int*)avl.root->left->key == 3);
+  GPR_ASSERT(*(int*)avl.root->right->key == 5);
+  grpc_avl_unref(avl, nullptr);
+}
+
+static void test_rl(void) {
+  grpc_avl avl;
+  gpr_log(GPR_DEBUG, "test_rl");
+  avl = grpc_avl_create(&int_int_vtable);
+  avl = grpc_avl_add(avl, box(3), box(1), nullptr);
+  avl = grpc_avl_add(avl, box(5), box(2), nullptr);
+  avl = grpc_avl_add(avl, box(4), box(3), nullptr);
+  GPR_ASSERT(*(int*)avl.root->key == 4);
+  GPR_ASSERT(*(int*)avl.root->left->key == 3);
+  GPR_ASSERT(*(int*)avl.root->right->key == 5);
+  grpc_avl_unref(avl, nullptr);
+}
+
+static void test_unbalanced(void) {
+  grpc_avl avl;
+  gpr_log(GPR_DEBUG, "test_unbalanced");
+  avl = grpc_avl_create(&int_int_vtable);
+  avl = grpc_avl_add(avl, box(5), box(1), nullptr);
+  avl = grpc_avl_add(avl, box(4), box(2), nullptr);
+  avl = grpc_avl_add(avl, box(3), box(3), nullptr);
+  avl = grpc_avl_add(avl, box(2), box(4), nullptr);
+  avl = grpc_avl_add(avl, box(1), box(5), nullptr);
+  GPR_ASSERT(*(int*)avl.root->key == 4);
+  GPR_ASSERT(*(int*)avl.root->left->key == 2);
+  GPR_ASSERT(*(int*)avl.root->left->left->key == 1);
+  GPR_ASSERT(*(int*)avl.root->left->right->key == 3);
+  GPR_ASSERT(*(int*)avl.root->right->key == 5);
+  grpc_avl_unref(avl, nullptr);
+}
+
+static void test_replace(void) {
+  grpc_avl avl;
+  gpr_log(GPR_DEBUG, "test_replace");
+  avl = grpc_avl_create(&int_int_vtable);
+  avl = grpc_avl_add(avl, box(1), box(1), nullptr);
+  avl = grpc_avl_add(avl, box(1), box(2), nullptr);
+  check_get(avl, 1, 2);
+  check_negget(avl, 2);
+  grpc_avl_unref(avl, nullptr);
+}
+
+static void test_remove(void) {
+  grpc_avl avl;
+  grpc_avl avl3, avl4, avl5, avln;
+  gpr_log(GPR_DEBUG, "test_remove");
+  avl = grpc_avl_create(&int_int_vtable);
+  avl = grpc_avl_add(avl, box(3), box(1), nullptr);
+  avl = grpc_avl_add(avl, box(4), box(2), nullptr);
+  avl = grpc_avl_add(avl, box(5), box(3), nullptr);
+
+  avl3 = remove_int(grpc_avl_ref(avl, nullptr), 3);
+  avl4 = remove_int(grpc_avl_ref(avl, nullptr), 4);
+  avl5 = remove_int(grpc_avl_ref(avl, nullptr), 5);
+  avln = remove_int(grpc_avl_ref(avl, nullptr), 1);
+
+  grpc_avl_unref(avl, nullptr);
+
+  check_negget(avl3, 3);
+  check_get(avl3, 4, 2);
+  check_get(avl3, 5, 3);
+  grpc_avl_unref(avl3, nullptr);
+
+  check_get(avl4, 3, 1);
+  check_negget(avl4, 4);
+  check_get(avl4, 5, 3);
+  grpc_avl_unref(avl4, nullptr);
+
+  check_get(avl5, 3, 1);
+  check_get(avl5, 4, 2);
+  check_negget(avl5, 5);
+  grpc_avl_unref(avl5, nullptr);
+
+  check_get(avln, 3, 1);
+  check_get(avln, 4, 2);
+  check_get(avln, 5, 3);
+  grpc_avl_unref(avln, nullptr);
+}
+
+static void test_badcase1(void) {
+  grpc_avl avl;
+
+  gpr_log(GPR_DEBUG, "test_badcase1");
+
+  avl = grpc_avl_create(&int_int_vtable);
+  avl = grpc_avl_add(avl, box(88), box(1), nullptr);
+  avl = remove_int(avl, 643);
+  avl = remove_int(avl, 983);
+  avl = grpc_avl_add(avl, box(985), box(4), nullptr);
+  avl = grpc_avl_add(avl, box(640), box(5), nullptr);
+  avl = grpc_avl_add(avl, box(41), box(6), nullptr);
+  avl = grpc_avl_add(avl, box(112), box(7), nullptr);
+  avl = grpc_avl_add(avl, box(342), box(8), nullptr);
+  avl = remove_int(avl, 1013);
+  avl = grpc_avl_add(avl, box(434), box(10), nullptr);
+  avl = grpc_avl_add(avl, box(520), box(11), nullptr);
+  avl = grpc_avl_add(avl, box(231), box(12), nullptr);
+  avl = grpc_avl_add(avl, box(852), box(13), nullptr);
+  avl = remove_int(avl, 461);
+  avl = grpc_avl_add(avl, box(108), box(15), nullptr);
+  avl = grpc_avl_add(avl, box(806), box(16), nullptr);
+  avl = grpc_avl_add(avl, box(827), box(17), nullptr);
+  avl = remove_int(avl, 796);
+  avl = grpc_avl_add(avl, box(340), box(19), nullptr);
+  avl = grpc_avl_add(avl, box(498), box(20), nullptr);
+  avl = grpc_avl_add(avl, box(203), box(21), nullptr);
+  avl = grpc_avl_add(avl, box(751), box(22), nullptr);
+  avl = grpc_avl_add(avl, box(150), box(23), nullptr);
+  avl = remove_int(avl, 237);
+  avl = grpc_avl_add(avl, box(830), box(25), nullptr);
+  avl = remove_int(avl, 1007);
+  avl = remove_int(avl, 394);
+  avl = grpc_avl_add(avl, box(65), box(28), nullptr);
+  avl = remove_int(avl, 904);
+  avl = remove_int(avl, 123);
+  avl = grpc_avl_add(avl, box(238), box(31), nullptr);
+  avl = grpc_avl_add(avl, box(184), box(32), nullptr);
+  avl = remove_int(avl, 331);
+  avl = grpc_avl_add(avl, box(827), box(34), nullptr);
+
+  check_get(avl, 830, 25);
+
+  grpc_avl_unref(avl, nullptr);
+}
+
+static void test_badcase2(void) {
+  grpc_avl avl;
+
+  gpr_log(GPR_DEBUG, "test_badcase2");
+
+  avl = grpc_avl_create(&int_int_vtable);
+  avl = grpc_avl_add(avl, box(288), box(1), nullptr);
+  avl = remove_int(avl, 415);
+  avl = grpc_avl_add(avl, box(953), box(3), nullptr);
+  avl = grpc_avl_add(avl, box(101), box(4), nullptr);
+  avl = grpc_avl_add(avl, box(516), box(5), nullptr);
+  avl = grpc_avl_add(avl, box(547), box(6), nullptr);
+  avl = grpc_avl_add(avl, box(467), box(7), nullptr);
+  avl = grpc_avl_add(avl, box(793), box(8), nullptr);
+  avl = remove_int(avl, 190);
+  avl = grpc_avl_add(avl, box(687), box(10), nullptr);
+  avl = grpc_avl_add(avl, box(242), box(11), nullptr);
+  avl = grpc_avl_add(avl, box(142), box(12), nullptr);
+  avl = remove_int(avl, 705);
+  avl = remove_int(avl, 578);
+  avl = remove_int(avl, 767);
+  avl = remove_int(avl, 183);
+  avl = grpc_avl_add(avl, box(950), box(17), nullptr);
+  avl = grpc_avl_add(avl, box(622), box(18), nullptr);
+  avl = remove_int(avl, 513);
+  avl = remove_int(avl, 429);
+  avl = grpc_avl_add(avl, box(205), box(21), nullptr);
+  avl = remove_int(avl, 663);
+  avl = remove_int(avl, 953);
+  avl = remove_int(avl, 892);
+  avl = grpc_avl_add(avl, box(236), box(25), nullptr);
+  avl = remove_int(avl, 982);
+  avl = remove_int(avl, 201);
+  avl = remove_int(avl, 684);
+  avl = grpc_avl_add(avl, box(572), box(29), nullptr);
+  avl = remove_int(avl, 817);
+  avl = grpc_avl_add(avl, box(970), box(31), nullptr);
+  avl = remove_int(avl, 347);
+  avl = remove_int(avl, 574);
+  avl = grpc_avl_add(avl, box(752), box(34), nullptr);
+  avl = grpc_avl_add(avl, box(670), box(35), nullptr);
+  avl = grpc_avl_add(avl, box(69), box(36), nullptr);
+  avl = remove_int(avl, 111);
+  avl = remove_int(avl, 523);
+  avl = grpc_avl_add(avl, box(141), box(39), nullptr);
+  avl = remove_int(avl, 159);
+  avl = grpc_avl_add(avl, box(947), box(41), nullptr);
+  avl = grpc_avl_add(avl, box(855), box(42), nullptr);
+  avl = remove_int(avl, 218);
+  avl = remove_int(avl, 6);
+  avl = grpc_avl_add(avl, box(753), box(45), nullptr);
+  avl = remove_int(avl, 82);
+  avl = remove_int(avl, 799);
+  avl = grpc_avl_add(avl, box(572), box(48), nullptr);
+  avl = remove_int(avl, 376);
+  avl = remove_int(avl, 413);
+  avl = grpc_avl_add(avl, box(458), box(51), nullptr);
+  avl = remove_int(avl, 897);
+  avl = grpc_avl_add(avl, box(191), box(53), nullptr);
+  avl = grpc_avl_add(avl, box(609), box(54), nullptr);
+  avl = remove_int(avl, 787);
+  avl = remove_int(avl, 710);
+  avl = remove_int(avl, 886);
+  avl = remove_int(avl, 835);
+  avl = remove_int(avl, 33);
+  avl = grpc_avl_add(avl, box(871), box(60), nullptr);
+  avl = remove_int(avl, 641);
+  avl = grpc_avl_add(avl, box(462), box(62), nullptr);
+  avl = remove_int(avl, 359);
+  avl = remove_int(avl, 767);
+  avl = grpc_avl_add(avl, box(310), box(65), nullptr);
+  avl = remove_int(avl, 757);
+  avl = remove_int(avl, 639);
+  avl = remove_int(avl, 314);
+  avl = grpc_avl_add(avl, box(2), box(69), nullptr);
+  avl = remove_int(avl, 138);
+  avl = grpc_avl_add(avl, box(669), box(71), nullptr);
+  avl = remove_int(avl, 477);
+  avl = grpc_avl_add(avl, box(366), box(73), nullptr);
+  avl = grpc_avl_add(avl, box(612), box(74), nullptr);
+  avl = grpc_avl_add(avl, box(106), box(75), nullptr);
+  avl = remove_int(avl, 161);
+  avl = grpc_avl_add(avl, box(388), box(77), nullptr);
+  avl = grpc_avl_add(avl, box(141), box(78), nullptr);
+  avl = remove_int(avl, 633);
+  avl = remove_int(avl, 459);
+  avl = grpc_avl_add(avl, box(40), box(81), nullptr);
+  avl = remove_int(avl, 689);
+  avl = grpc_avl_add(avl, box(823), box(83), nullptr);
+  avl = remove_int(avl, 485);
+  avl = grpc_avl_add(avl, box(903), box(85), nullptr);
+  avl = grpc_avl_add(avl, box(592), box(86), nullptr);
+  avl = remove_int(avl, 448);
+  avl = grpc_avl_add(avl, box(56), box(88), nullptr);
+  avl = remove_int(avl, 333);
+  avl = grpc_avl_add(avl, box(189), box(90), nullptr);
+  avl = grpc_avl_add(avl, box(103), box(91), nullptr);
+  avl = remove_int(avl, 164);
+  avl = remove_int(avl, 974);
+  avl = grpc_avl_add(avl, box(215), box(94), nullptr);
+  avl = remove_int(avl, 189);
+  avl = remove_int(avl, 504);
+  avl = grpc_avl_add(avl, box(868), box(97), nullptr);
+  avl = remove_int(avl, 909);
+  avl = remove_int(avl, 148);
+  avl = remove_int(avl, 469);
+  avl = grpc_avl_add(avl, box(994), box(101), nullptr);
+  avl = grpc_avl_add(avl, box(576), box(102), nullptr);
+  avl = remove_int(avl, 82);
+  avl = remove_int(avl, 209);
+  avl = grpc_avl_add(avl, box(276), box(105), nullptr);
+  avl = remove_int(avl, 856);
+  avl = grpc_avl_add(avl, box(750), box(107), nullptr);
+  avl = remove_int(avl, 871);
+  avl = grpc_avl_add(avl, box(301), box(109), nullptr);
+  avl = remove_int(avl, 260);
+  avl = remove_int(avl, 737);
+  avl = remove_int(avl, 719);
+  avl = grpc_avl_add(avl, box(933), box(113), nullptr);
+  avl = grpc_avl_add(avl, box(225), box(114), nullptr);
+  avl = grpc_avl_add(avl, box(975), box(115), nullptr);
+  avl = grpc_avl_add(avl, box(86), box(116), nullptr);
+  avl = remove_int(avl, 732);
+  avl = grpc_avl_add(avl, box(340), box(118), nullptr);
+  avl = grpc_avl_add(avl, box(271), box(119), nullptr);
+  avl = remove_int(avl, 206);
+  avl = grpc_avl_add(avl, box(949), box(121), nullptr);
+  avl = grpc_avl_add(avl, box(927), box(122), nullptr);
+  avl = grpc_avl_add(avl, box(34), box(123), nullptr);
+  avl = grpc_avl_add(avl, box(351), box(124), nullptr);
+  avl = remove_int(avl, 836);
+  avl = grpc_avl_add(avl, box(825), box(126), nullptr);
+  avl = grpc_avl_add(avl, box(352), box(127), nullptr);
+  avl = remove_int(avl, 107);
+  avl = remove_int(avl, 101);
+  avl = grpc_avl_add(avl, box(320), box(130), nullptr);
+  avl = grpc_avl_add(avl, box(3), box(131), nullptr);
+  avl = remove_int(avl, 998);
+  avl = remove_int(avl, 44);
+  avl = grpc_avl_add(avl, box(525), box(134), nullptr);
+  avl = grpc_avl_add(avl, box(864), box(135), nullptr);
+  avl = grpc_avl_add(avl, box(863), box(136), nullptr);
+  avl = remove_int(avl, 770);
+  avl = grpc_avl_add(avl, box(440), box(138), nullptr);
+  avl = remove_int(avl, 516);
+  avl = grpc_avl_add(avl, box(116), box(140), nullptr);
+  avl = remove_int(avl, 380);
+  avl = grpc_avl_add(avl, box(878), box(142), nullptr);
+  avl = remove_int(avl, 439);
+  avl = grpc_avl_add(avl, box(994), box(144), nullptr);
+  avl = remove_int(avl, 294);
+  avl = remove_int(avl, 593);
+  avl = grpc_avl_add(avl, box(696), box(147), nullptr);
+  avl = remove_int(avl, 8);
+  avl = grpc_avl_add(avl, box(881), box(149), nullptr);
+  avl = remove_int(avl, 32);
+  avl = remove_int(avl, 242);
+  avl = grpc_avl_add(avl, box(487), box(152), nullptr);
+  avl = grpc_avl_add(avl, box(637), box(153), nullptr);
+  avl = grpc_avl_add(avl, box(793), box(154), nullptr);
+  avl = grpc_avl_add(avl, box(696), box(155), nullptr);
+  avl = remove_int(avl, 458);
+  avl = grpc_avl_add(avl, box(828), box(157), nullptr);
+  avl = remove_int(avl, 784);
+  avl = remove_int(avl, 274);
+  avl = grpc_avl_add(avl, box(783), box(160), nullptr);
+  avl = remove_int(avl, 21);
+  avl = grpc_avl_add(avl, box(866), box(162), nullptr);
+  avl = remove_int(avl, 919);
+  avl = grpc_avl_add(avl, box(435), box(164), nullptr);
+  avl = remove_int(avl, 385);
+  avl = grpc_avl_add(avl, box(475), box(166), nullptr);
+  avl = remove_int(avl, 339);
+  avl = grpc_avl_add(avl, box(615), box(168), nullptr);
+  avl = remove_int(avl, 866);
+  avl = remove_int(avl, 82);
+  avl = remove_int(avl, 271);
+  avl = grpc_avl_add(avl, box(590), box(172), nullptr);
+  avl = grpc_avl_add(avl, box(852), box(173), nullptr);
+  avl = remove_int(avl, 318);
+  avl = remove_int(avl, 82);
+  avl = grpc_avl_add(avl, box(672), box(176), nullptr);
+  avl = remove_int(avl, 430);
+  avl = grpc_avl_add(avl, box(821), box(178), nullptr);
+  avl = grpc_avl_add(avl, box(365), box(179), nullptr);
+  avl = remove_int(avl, 78);
+  avl = grpc_avl_add(avl, box(700), box(181), nullptr);
+  avl = grpc_avl_add(avl, box(353), box(182), nullptr);
+  avl = remove_int(avl, 492);
+  avl = grpc_avl_add(avl, box(991), box(184), nullptr);
+  avl = remove_int(avl, 330);
+  avl = grpc_avl_add(avl, box(873), box(186), nullptr);
+  avl = remove_int(avl, 589);
+  avl = grpc_avl_add(avl, box(676), box(188), nullptr);
+  avl = grpc_avl_add(avl, box(790), box(189), nullptr);
+  avl = remove_int(avl, 521);
+  avl = remove_int(avl, 47);
+  avl = grpc_avl_add(avl, box(976), box(192), nullptr);
+  avl = grpc_avl_add(avl, box(683), box(193), nullptr);
+  avl = remove_int(avl, 803);
+  avl = remove_int(avl, 1006);
+  avl = grpc_avl_add(avl, box(775), box(196), nullptr);
+  avl = grpc_avl_add(avl, box(411), box(197), nullptr);
+  avl = grpc_avl_add(avl, box(697), box(198), nullptr);
+  avl = remove_int(avl, 50);
+  avl = grpc_avl_add(avl, box(213), box(200), nullptr);
+  avl = remove_int(avl, 714);
+  avl = grpc_avl_add(avl, box(981), box(202), nullptr);
+  avl = grpc_avl_add(avl, box(502), box(203), nullptr);
+  avl = grpc_avl_add(avl, box(697), box(204), nullptr);
+  avl = grpc_avl_add(avl, box(603), box(205), nullptr);
+  avl = grpc_avl_add(avl, box(117), box(206), nullptr);
+  avl = remove_int(avl, 363);
+  avl = grpc_avl_add(avl, box(104), box(208), nullptr);
+  avl = remove_int(avl, 842);
+  avl = grpc_avl_add(avl, box(48), box(210), nullptr);
+  avl = remove_int(avl, 764);
+  avl = grpc_avl_add(avl, box(482), box(212), nullptr);
+  avl = grpc_avl_add(avl, box(928), box(213), nullptr);
+  avl = grpc_avl_add(avl, box(30), box(214), nullptr);
+  avl = grpc_avl_add(avl, box(820), box(215), nullptr);
+  avl = grpc_avl_add(avl, box(334), box(216), nullptr);
+  avl = remove_int(avl, 306);
+  avl = grpc_avl_add(avl, box(789), box(218), nullptr);
+  avl = remove_int(avl, 924);
+  avl = grpc_avl_add(avl, box(53), box(220), nullptr);
+  avl = remove_int(avl, 657);
+  avl = grpc_avl_add(avl, box(130), box(222), nullptr);
+  avl = grpc_avl_add(avl, box(239), box(223), nullptr);
+  avl = remove_int(avl, 20);
+  avl = grpc_avl_add(avl, box(117), box(225), nullptr);
+  avl = remove_int(avl, 882);
+  avl = remove_int(avl, 891);
+  avl = grpc_avl_add(avl, box(9), box(228), nullptr);
+  avl = grpc_avl_add(avl, box(496), box(229), nullptr);
+  avl = grpc_avl_add(avl, box(750), box(230), nullptr);
+  avl = grpc_avl_add(avl, box(283), box(231), nullptr);
+  avl = grpc_avl_add(avl, box(802), box(232), nullptr);
+  avl = remove_int(avl, 352);
+  avl = grpc_avl_add(avl, box(374), box(234), nullptr);
+  avl = grpc_avl_add(avl, box(6), box(235), nullptr);
+  avl = grpc_avl_add(avl, box(756), box(236), nullptr);
+  avl = grpc_avl_add(avl, box(597), box(237), nullptr);
+  avl = grpc_avl_add(avl, box(661), box(238), nullptr);
+  avl = remove_int(avl, 96);
+  avl = grpc_avl_add(avl, box(894), box(240), nullptr);
+  avl = remove_int(avl, 749);
+  avl = grpc_avl_add(avl, box(71), box(242), nullptr);
+  avl = remove_int(avl, 68);
+  avl = grpc_avl_add(avl, box(388), box(244), nullptr);
+  avl = remove_int(avl, 119);
+  avl = remove_int(avl, 856);
+  avl = grpc_avl_add(avl, box(176), box(247), nullptr);
+  avl = grpc_avl_add(avl, box(993), box(248), nullptr);
+  avl = remove_int(avl, 178);
+  avl = remove_int(avl, 781);
+  avl = remove_int(avl, 771);
+  avl = remove_int(avl, 848);
+  avl = remove_int(avl, 376);
+  avl = remove_int(avl, 157);
+  avl = remove_int(avl, 142);
+  avl = remove_int(avl, 686);
+  avl = grpc_avl_add(avl, box(779), box(257), nullptr);
+  avl = grpc_avl_add(avl, box(484), box(258), nullptr);
+  avl = remove_int(avl, 837);
+  avl = grpc_avl_add(avl, box(388), box(260), nullptr);
+  avl = remove_int(avl, 987);
+  avl = grpc_avl_add(avl, box(336), box(262), nullptr);
+  avl = remove_int(avl, 855);
+  avl = grpc_avl_add(avl, box(668), box(264), nullptr);
+  avl = remove_int(avl, 648);
+  avl = grpc_avl_add(avl, box(193), box(266), nullptr);
+  avl = remove_int(avl, 939);
+  avl = grpc_avl_add(avl, box(740), box(268), nullptr);
+  avl = grpc_avl_add(avl, box(503), box(269), nullptr);
+  avl = grpc_avl_add(avl, box(765), box(270), nullptr);
+  avl = remove_int(avl, 924);
+  avl = remove_int(avl, 513);
+  avl = grpc_avl_add(avl, box(161), box(273), nullptr);
+  avl = grpc_avl_add(avl, box(502), box(274), nullptr);
+  avl = grpc_avl_add(avl, box(846), box(275), nullptr);
+  avl = remove_int(avl, 931);
+  avl = grpc_avl_add(avl, box(87), box(277), nullptr);
+  avl = grpc_avl_add(avl, box(949), box(278), nullptr);
+  avl = grpc_avl_add(avl, box(548), box(279), nullptr);
+  avl = grpc_avl_add(avl, box(951), box(280), nullptr);
+  avl = remove_int(avl, 1018);
+  avl = remove_int(avl, 568);
+  avl = grpc_avl_add(avl, box(138), box(283), nullptr);
+  avl = grpc_avl_add(avl, box(202), box(284), nullptr);
+  avl = grpc_avl_add(avl, box(157), box(285), nullptr);
+  avl = grpc_avl_add(avl, box(264), box(286), nullptr);
+  avl = grpc_avl_add(avl, box(370), box(287), nullptr);
+  avl = remove_int(avl, 736);
+  avl = remove_int(avl, 751);
+  avl = remove_int(avl, 506);
+  avl = remove_int(avl, 81);
+  avl = remove_int(avl, 358);
+  avl = remove_int(avl, 657);
+  avl = remove_int(avl, 86);
+  avl = grpc_avl_add(avl, box(876), box(295), nullptr);
+  avl = remove_int(avl, 354);
+  avl = grpc_avl_add(avl, box(134), box(297), nullptr);
+  avl = remove_int(avl, 781);
+  avl = remove_int(avl, 183);
+  avl = grpc_avl_add(avl, box(914), box(300), nullptr);
+  avl = remove_int(avl, 926);
+  avl = remove_int(avl, 398);
+  avl = remove_int(avl, 932);
+  avl = remove_int(avl, 804);
+  avl = remove_int(avl, 326);
+  avl = grpc_avl_add(avl, box(208), box(306), nullptr);
+  avl = grpc_avl_add(avl, box(699), box(307), nullptr);
+  avl = remove_int(avl, 576);
+  avl = remove_int(avl, 850);
+  avl = remove_int(avl, 514);
+  avl = remove_int(avl, 676);
+  avl = remove_int(avl, 549);
+  avl = remove_int(avl, 767);
+  avl = grpc_avl_add(avl, box(58), box(314), nullptr);
+  avl = grpc_avl_add(avl, box(265), box(315), nullptr);
+  avl = grpc_avl_add(avl, box(268), box(316), nullptr);
+  avl = grpc_avl_add(avl, box(103), box(317), nullptr);
+  avl = grpc_avl_add(avl, box(440), box(318), nullptr);
+  avl = remove_int(avl, 777);
+  avl = grpc_avl_add(avl, box(670), box(320), nullptr);
+  avl = remove_int(avl, 506);
+  avl = remove_int(avl, 487);
+  avl = grpc_avl_add(avl, box(421), box(323), nullptr);
+  avl = remove_int(avl, 514);
+  avl = grpc_avl_add(avl, box(701), box(325), nullptr);
+  avl = remove_int(avl, 949);
+  avl = remove_int(avl, 872);
+  avl = remove_int(avl, 139);
+  avl = grpc_avl_add(avl, box(781), box(329), nullptr);
+  avl = grpc_avl_add(avl, box(543), box(330), nullptr);
+  avl = grpc_avl_add(avl, box(147), box(331), nullptr);
+  avl = remove_int(avl, 190);
+  avl = grpc_avl_add(avl, box(453), box(333), nullptr);
+  avl = remove_int(avl, 262);
+  avl = remove_int(avl, 850);
+  avl = remove_int(avl, 286);
+  avl = remove_int(avl, 787);
+  avl = grpc_avl_add(avl, box(514), box(338), nullptr);
+  avl = remove_int(avl, 812);
+  avl = grpc_avl_add(avl, box(431), box(340), nullptr);
+  avl = grpc_avl_add(avl, box(8), box(341), nullptr);
+  avl = remove_int(avl, 843);
+  avl = grpc_avl_add(avl, box(831), box(343), nullptr);
+  avl = remove_int(avl, 472);
+  avl = remove_int(avl, 157);
+  avl = grpc_avl_add(avl, box(612), box(346), nullptr);
+  avl = grpc_avl_add(avl, box(802), box(347), nullptr);
+  avl = remove_int(avl, 554);
+  avl = grpc_avl_add(avl, box(409), box(349), nullptr);
+  avl = grpc_avl_add(avl, box(439), box(350), nullptr);
+  avl = grpc_avl_add(avl, box(725), box(351), nullptr);
+  avl = grpc_avl_add(avl, box(568), box(352), nullptr);
+  avl = remove_int(avl, 475);
+  avl = remove_int(avl, 672);
+  avl = remove_int(avl, 62);
+  avl = remove_int(avl, 753);
+  avl = grpc_avl_add(avl, box(435), box(357), nullptr);
+  avl = grpc_avl_add(avl, box(950), box(358), nullptr);
+  avl = grpc_avl_add(avl, box(532), box(359), nullptr);
+  avl = grpc_avl_add(avl, box(832), box(360), nullptr);
+  avl = remove_int(avl, 390);
+  avl = grpc_avl_add(avl, box(993), box(362), nullptr);
+  avl = remove_int(avl, 198);
+  avl = remove_int(avl, 401);
+  avl = grpc_avl_add(avl, box(316), box(365), nullptr);
+  avl = remove_int(avl, 843);
+  avl = grpc_avl_add(avl, box(541), box(367), nullptr);
+  avl = grpc_avl_add(avl, box(505), box(368), nullptr);
+  avl = remove_int(avl, 445);
+  avl = remove_int(avl, 256);
+  avl = grpc_avl_add(avl, box(232), box(371), nullptr);
+  avl = remove_int(avl, 577);
+  avl = remove_int(avl, 558);
+  avl = grpc_avl_add(avl, box(910), box(374), nullptr);
+  avl = remove_int(avl, 902);
+  avl = remove_int(avl, 755);
+  avl = remove_int(avl, 114);
+  avl = remove_int(avl, 438);
+  avl = remove_int(avl, 224);
+  avl = grpc_avl_add(avl, box(920), box(380), nullptr);
+  avl = grpc_avl_add(avl, box(655), box(381), nullptr);
+  avl = remove_int(avl, 557);
+  avl = remove_int(avl, 102);
+  avl = remove_int(avl, 165);
+  avl = grpc_avl_add(avl, box(191), box(385), nullptr);
+  avl = remove_int(avl, 30);
+  avl = grpc_avl_add(avl, box(406), box(387), nullptr);
+  avl = grpc_avl_add(avl, box(66), box(388), nullptr);
+  avl = grpc_avl_add(avl, box(87), box(389), nullptr);
+  avl = remove_int(avl, 7);
+  avl = remove_int(avl, 671);
+  avl = grpc_avl_add(avl, box(234), box(392), nullptr);
+  avl = remove_int(avl, 463);
+  avl = grpc_avl_add(avl, box(75), box(394), nullptr);
+  avl = grpc_avl_add(avl, box(487), box(395), nullptr);
+  avl = remove_int(avl, 203);
+  avl = grpc_avl_add(avl, box(711), box(397), nullptr);
+  avl = remove_int(avl, 291);
+  avl = remove_int(avl, 798);
+  avl = remove_int(avl, 337);
+  avl = grpc_avl_add(avl, box(877), box(401), nullptr);
+  avl = grpc_avl_add(avl, box(388), box(402), nullptr);
+  avl = remove_int(avl, 975);
+  avl = grpc_avl_add(avl, box(200), box(404), nullptr);
+  avl = grpc_avl_add(avl, box(408), box(405), nullptr);
+  avl = grpc_avl_add(avl, box(3), box(406), nullptr);
+  avl = grpc_avl_add(avl, box(971), box(407), nullptr);
+  avl = remove_int(avl, 841);
+  avl = remove_int(avl, 910);
+  avl = remove_int(avl, 74);
+  avl = remove_int(avl, 888);
+  avl = grpc_avl_add(avl, box(492), box(412), nullptr);
+  avl = remove_int(avl, 14);
+  avl = remove_int(avl, 364);
+  avl = grpc_avl_add(avl, box(215), box(415), nullptr);
+  avl = remove_int(avl, 778);
+  avl = remove_int(avl, 45);
+  avl = grpc_avl_add(avl, box(328), box(418), nullptr);
+  avl = grpc_avl_add(avl, box(597), box(419), nullptr);
+  avl = remove_int(avl, 34);
+  avl = grpc_avl_add(avl, box(736), box(421), nullptr);
+  avl = remove_int(avl, 37);
+  avl = grpc_avl_add(avl, box(275), box(423), nullptr);
+  avl = grpc_avl_add(avl, box(70), box(424), nullptr);
+  avl = grpc_avl_add(avl, box(771), box(425), nullptr);
+  avl = remove_int(avl, 536);
+  avl = remove_int(avl, 421);
+  avl = grpc_avl_add(avl, box(186), box(428), nullptr);
+  avl = grpc_avl_add(avl, box(788), box(429), nullptr);
+  avl = grpc_avl_add(avl, box(224), box(430), nullptr);
+  avl = remove_int(avl, 228);
+  avl = grpc_avl_add(avl, box(48), box(432), nullptr);
+  avl = grpc_avl_add(avl, box(120), box(433), nullptr);
+  avl = grpc_avl_add(avl, box(269), box(434), nullptr);
+  avl = grpc_avl_add(avl, box(904), box(435), nullptr);
+  avl = remove_int(avl, 699);
+  avl = grpc_avl_add(avl, box(340), box(437), nullptr);
+  avl = remove_int(avl, 276);
+  avl = grpc_avl_add(avl, box(591), box(439), nullptr);
+  avl = grpc_avl_add(avl, box(778), box(440), nullptr);
+  avl = remove_int(avl, 490);
+  avl = remove_int(avl, 973);
+  avl = grpc_avl_add(avl, box(294), box(443), nullptr);
+  avl = grpc_avl_add(avl, box(323), box(444), nullptr);
+  avl = remove_int(avl, 685);
+  avl = grpc_avl_add(avl, box(38), box(446), nullptr);
+  avl = grpc_avl_add(avl, box(525), box(447), nullptr);
+  avl = remove_int(avl, 162);
+  avl = grpc_avl_add(avl, box(462), box(449), nullptr);
+  avl = grpc_avl_add(avl, box(340), box(450), nullptr);
+  avl = remove_int(avl, 734);
+  avl = remove_int(avl, 959);
+  avl = grpc_avl_add(avl, box(752), box(453), nullptr);
+  avl = grpc_avl_add(avl, box(667), box(454), nullptr);
+  avl = remove_int(avl, 558);
+  avl = remove_int(avl, 657);
+  avl = grpc_avl_add(avl, box(711), box(457), nullptr);
+  avl = remove_int(avl, 937);
+  avl = grpc_avl_add(avl, box(741), box(459), nullptr);
+  avl = grpc_avl_add(avl, box(40), box(460), nullptr);
+  avl = remove_int(avl, 784);
+  avl = grpc_avl_add(avl, box(292), box(462), nullptr);
+  avl = remove_int(avl, 164);
+  avl = remove_int(avl, 931);
+  avl = remove_int(avl, 886);
+  avl = grpc_avl_add(avl, box(968), box(466), nullptr);
+  avl = remove_int(avl, 263);
+  avl = grpc_avl_add(avl, box(647), box(468), nullptr);
+  avl = grpc_avl_add(avl, box(92), box(469), nullptr);
+  avl = remove_int(avl, 310);
+  avl = grpc_avl_add(avl, box(711), box(471), nullptr);
+  avl = grpc_avl_add(avl, box(675), box(472), nullptr);
+  avl = remove_int(avl, 549);
+  avl = grpc_avl_add(avl, box(380), box(474), nullptr);
+  avl = remove_int(avl, 825);
+  avl = grpc_avl_add(avl, box(668), box(476), nullptr);
+  avl = remove_int(avl, 498);
+  avl = grpc_avl_add(avl, box(870), box(478), nullptr);
+  avl = grpc_avl_add(avl, box(391), box(479), nullptr);
+  avl = grpc_avl_add(avl, box(264), box(480), nullptr);
+  avl = remove_int(avl, 1);
+  avl = remove_int(avl, 849);
+  avl = remove_int(avl, 88);
+  avl = remove_int(avl, 255);
+  avl = remove_int(avl, 763);
+  avl = remove_int(avl, 831);
+  avl = grpc_avl_add(avl, box(508), box(487), nullptr);
+  avl = remove_int(avl, 849);
+  avl = remove_int(avl, 47);
+  avl = grpc_avl_add(avl, box(299), box(490), nullptr);
+  avl = remove_int(avl, 625);
+  avl = remove_int(avl, 433);
+  avl = remove_int(avl, 904);
+  avl = remove_int(avl, 761);
+  avl = grpc_avl_add(avl, box(33), box(495), nullptr);
+  avl = grpc_avl_add(avl, box(524), box(496), nullptr);
+  avl = remove_int(avl, 210);
+  avl = remove_int(avl, 299);
+  avl = grpc_avl_add(avl, box(823), box(499), nullptr);
+  avl = remove_int(avl, 479);
+  avl = remove_int(avl, 96);
+  avl = remove_int(avl, 1013);
+  avl = grpc_avl_add(avl, box(768), box(503), nullptr);
+  avl = remove_int(avl, 638);
+  avl = remove_int(avl, 20);
+  avl = grpc_avl_add(avl, box(663), box(506), nullptr);
+  avl = remove_int(avl, 882);
+  avl = grpc_avl_add(avl, box(745), box(508), nullptr);
+  avl = remove_int(avl, 352);
+  avl = grpc_avl_add(avl, box(10), box(510), nullptr);
+  avl = remove_int(avl, 484);
+  avl = grpc_avl_add(avl, box(420), box(512), nullptr);
+  avl = grpc_avl_add(avl, box(884), box(513), nullptr);
+  avl = grpc_avl_add(avl, box(993), box(514), nullptr);
+  avl = grpc_avl_add(avl, box(251), box(515), nullptr);
+  avl = remove_int(avl, 222);
+  avl = grpc_avl_add(avl, box(734), box(517), nullptr);
+  avl = grpc_avl_add(avl, box(952), box(518), nullptr);
+  avl = remove_int(avl, 26);
+  avl = remove_int(avl, 270);
+  avl = remove_int(avl, 481);
+  avl = remove_int(avl, 693);
+  avl = remove_int(avl, 1006);
+  avl = grpc_avl_add(avl, box(77), box(524), nullptr);
+  avl = remove_int(avl, 897);
+  avl = grpc_avl_add(avl, box(719), box(526), nullptr);
+  avl = grpc_avl_add(avl, box(622), box(527), nullptr);
+  avl = remove_int(avl, 28);
+  avl = remove_int(avl, 836);
+  avl = remove_int(avl, 142);
+  avl = grpc_avl_add(avl, box(445), box(531), nullptr);
+  avl = grpc_avl_add(avl, box(410), box(532), nullptr);
+  avl = remove_int(avl, 575);
+  avl = grpc_avl_add(avl, box(634), box(534), nullptr);
+  avl = grpc_avl_add(avl, box(906), box(535), nullptr);
+  avl = remove_int(avl, 649);
+  avl = grpc_avl_add(avl, box(813), box(537), nullptr);
+  avl = remove_int(avl, 702);
+  avl = remove_int(avl, 732);
+  avl = grpc_avl_add(avl, box(105), box(540), nullptr);
+  avl = grpc_avl_add(avl, box(867), box(541), nullptr);
+  avl = remove_int(avl, 964);
+  avl = remove_int(avl, 941);
+  avl = grpc_avl_add(avl, box(947), box(544), nullptr);
+  avl = remove_int(avl, 990);
+  avl = grpc_avl_add(avl, box(816), box(546), nullptr);
+  avl = remove_int(avl, 429);
+  avl = remove_int(avl, 567);
+  avl = remove_int(avl, 541);
+  avl = remove_int(avl, 583);
+  avl = grpc_avl_add(avl, box(57), box(551), nullptr);
+  avl = grpc_avl_add(avl, box(786), box(552), nullptr);
+  avl = grpc_avl_add(avl, box(526), box(553), nullptr);
+  avl = remove_int(avl, 642);
+  avl = remove_int(avl, 220);
+  avl = remove_int(avl, 840);
+  avl = remove_int(avl, 548);
+  avl = grpc_avl_add(avl, box(528), box(558), nullptr);
+  avl = grpc_avl_add(avl, box(749), box(559), nullptr);
+  avl = grpc_avl_add(avl, box(194), box(560), nullptr);
+  avl = remove_int(avl, 517);
+  avl = grpc_avl_add(avl, box(102), box(562), nullptr);
+  avl = remove_int(avl, 189);
+  avl = grpc_avl_add(avl, box(927), box(564), nullptr);
+  avl = remove_int(avl, 846);
+  avl = remove_int(avl, 130);
+  avl = grpc_avl_add(avl, box(694), box(567), nullptr);
+  avl = remove_int(avl, 750);
+  avl = grpc_avl_add(avl, box(357), box(569), nullptr);
+  avl = remove_int(avl, 431);
+  avl = remove_int(avl, 91);
+  avl = grpc_avl_add(avl, box(640), box(572), nullptr);
+  avl = remove_int(avl, 4);
+  avl = grpc_avl_add(avl, box(81), box(574), nullptr);
+  avl = grpc_avl_add(avl, box(595), box(575), nullptr);
+  avl = remove_int(avl, 444);
+  avl = remove_int(avl, 262);
+  avl = remove_int(avl, 11);
+  avl = grpc_avl_add(avl, box(192), box(579), nullptr);
+  avl = grpc_avl_add(avl, box(158), box(580), nullptr);
+  avl = remove_int(avl, 401);
+  avl = remove_int(avl, 918);
+  avl = grpc_avl_add(avl, box(180), box(583), nullptr);
+  avl = remove_int(avl, 268);
+  avl = grpc_avl_add(avl, box(1012), box(585), nullptr);
+  avl = grpc_avl_add(avl, box(90), box(586), nullptr);
+  avl = grpc_avl_add(avl, box(946), box(587), nullptr);
+  avl = remove_int(avl, 719);
+  avl = grpc_avl_add(avl, box(874), box(589), nullptr);
+  avl = grpc_avl_add(avl, box(679), box(590), nullptr);
+  avl = remove_int(avl, 53);
+  avl = remove_int(avl, 534);
+  avl = grpc_avl_add(avl, box(646), box(593), nullptr);
+  avl = grpc_avl_add(avl, box(767), box(594), nullptr);
+  avl = grpc_avl_add(avl, box(460), box(595), nullptr);
+  avl = grpc_avl_add(avl, box(852), box(596), nullptr);
+  avl = grpc_avl_add(avl, box(189), box(597), nullptr);
+  avl = remove_int(avl, 932);
+  avl = remove_int(avl, 366);
+  avl = remove_int(avl, 907);
+  avl = grpc_avl_add(avl, box(875), box(601), nullptr);
+  avl = grpc_avl_add(avl, box(434), box(602), nullptr);
+  avl = grpc_avl_add(avl, box(704), box(603), nullptr);
+  avl = grpc_avl_add(avl, box(724), box(604), nullptr);
+  avl = grpc_avl_add(avl, box(930), box(605), nullptr);
+  avl = grpc_avl_add(avl, box(1000), box(606), nullptr);
+  avl = remove_int(avl, 479);
+  avl = grpc_avl_add(avl, box(275), box(608), nullptr);
+  avl = remove_int(avl, 32);
+  avl = grpc_avl_add(avl, box(939), box(610), nullptr);
+  avl = remove_int(avl, 943);
+  avl = remove_int(avl, 329);
+  avl = grpc_avl_add(avl, box(490), box(613), nullptr);
+  avl = remove_int(avl, 477);
+  avl = remove_int(avl, 414);
+  avl = remove_int(avl, 187);
+  avl = remove_int(avl, 334);
+  avl = grpc_avl_add(avl, box(40), box(618), nullptr);
+  avl = remove_int(avl, 751);
+  avl = grpc_avl_add(avl, box(568), box(620), nullptr);
+  avl = grpc_avl_add(avl, box(120), box(621), nullptr);
+  avl = grpc_avl_add(avl, box(617), box(622), nullptr);
+  avl = grpc_avl_add(avl, box(32), box(623), nullptr);
+  avl = remove_int(avl, 701);
+  avl = grpc_avl_add(avl, box(910), box(625), nullptr);
+  avl = remove_int(avl, 557);
+  avl = remove_int(avl, 361);
+  avl = remove_int(avl, 937);
+  avl = remove_int(avl, 100);
+  avl = remove_int(avl, 684);
+  avl = grpc_avl_add(avl, box(751), box(631), nullptr);
+  avl = remove_int(avl, 781);
+  avl = remove_int(avl, 469);
+  avl = remove_int(avl, 75);
+  avl = remove_int(avl, 561);
+  avl = grpc_avl_add(avl, box(854), box(636), nullptr);
+  avl = remove_int(avl, 164);
+  avl = remove_int(avl, 258);
+  avl = remove_int(avl, 315);
+  avl = remove_int(avl, 261);
+  avl = grpc_avl_add(avl, box(552), box(641), nullptr);
+  avl = grpc_avl_add(avl, box(6), box(642), nullptr);
+  avl = grpc_avl_add(avl, box(680), box(643), nullptr);
+  avl = remove_int(avl, 741);
+  avl = remove_int(avl, 309);
+  avl = remove_int(avl, 272);
+  avl = grpc_avl_add(avl, box(249), box(647), nullptr);
+  avl = remove_int(avl, 97);
+  avl = remove_int(avl, 850);
+  avl = grpc_avl_add(avl, box(915), box(650), nullptr);
+  avl = grpc_avl_add(avl, box(816), box(651), nullptr);
+  avl = grpc_avl_add(avl, box(45), box(652), nullptr);
+  avl = grpc_avl_add(avl, box(168), box(653), nullptr);
+  avl = remove_int(avl, 153);
+  avl = remove_int(avl, 239);
+  avl = grpc_avl_add(avl, box(684), box(656), nullptr);
+  avl = grpc_avl_add(avl, box(208), box(657), nullptr);
+  avl = grpc_avl_add(avl, box(681), box(658), nullptr);
+  avl = grpc_avl_add(avl, box(609), box(659), nullptr);
+  avl = grpc_avl_add(avl, box(645), box(660), nullptr);
+  avl = remove_int(avl, 799);
+  avl = grpc_avl_add(avl, box(955), box(662), nullptr);
+  avl = grpc_avl_add(avl, box(946), box(663), nullptr);
+  avl = grpc_avl_add(avl, box(744), box(664), nullptr);
+  avl = grpc_avl_add(avl, box(201), box(665), nullptr);
+  avl = grpc_avl_add(avl, box(136), box(666), nullptr);
+  avl = remove_int(avl, 357);
+  avl = grpc_avl_add(avl, box(974), box(668), nullptr);
+  avl = remove_int(avl, 485);
+  avl = grpc_avl_add(avl, box(1009), box(670), nullptr);
+  avl = grpc_avl_add(avl, box(517), box(671), nullptr);
+  avl = remove_int(avl, 491);
+  avl = grpc_avl_add(avl, box(336), box(673), nullptr);
+  avl = grpc_avl_add(avl, box(589), box(674), nullptr);
+  avl = remove_int(avl, 546);
+  avl = remove_int(avl, 840);
+  avl = remove_int(avl, 104);
+  avl = remove_int(avl, 347);
+  avl = grpc_avl_add(avl, box(801), box(679), nullptr);
+  avl = remove_int(avl, 799);
+  avl = remove_int(avl, 702);
+  avl = remove_int(avl, 996);
+  avl = remove_int(avl, 93);
+  avl = grpc_avl_add(avl, box(561), box(684), nullptr);
+  avl = grpc_avl_add(avl, box(25), box(685), nullptr);
+  avl = remove_int(avl, 278);
+  avl = grpc_avl_add(avl, box(191), box(687), nullptr);
+  avl = remove_int(avl, 243);
+  avl = remove_int(avl, 918);
+  avl = remove_int(avl, 449);
+  avl = grpc_avl_add(avl, box(19), box(691), nullptr);
+  avl = grpc_avl_add(avl, box(762), box(692), nullptr);
+  avl = grpc_avl_add(avl, box(13), box(693), nullptr);
+  avl = grpc_avl_add(avl, box(151), box(694), nullptr);
+  avl = grpc_avl_add(avl, box(152), box(695), nullptr);
+  avl = grpc_avl_add(avl, box(793), box(696), nullptr);
+  avl = remove_int(avl, 862);
+  avl = remove_int(avl, 890);
+  avl = grpc_avl_add(avl, box(687), box(699), nullptr);
+  avl = grpc_avl_add(avl, box(509), box(700), nullptr);
+  avl = grpc_avl_add(avl, box(973), box(701), nullptr);
+  avl = remove_int(avl, 230);
+  avl = grpc_avl_add(avl, box(532), box(703), nullptr);
+  avl = remove_int(avl, 668);
+  avl = grpc_avl_add(avl, box(281), box(705), nullptr);
+  avl = grpc_avl_add(avl, box(867), box(706), nullptr);
+  avl = grpc_avl_add(avl, box(359), box(707), nullptr);
+  avl = remove_int(avl, 425);
+  avl = grpc_avl_add(avl, box(691), box(709), nullptr);
+  avl = grpc_avl_add(avl, box(163), box(710), nullptr);
+  avl = grpc_avl_add(avl, box(502), box(711), nullptr);
+  avl = remove_int(avl, 674);
+  avl = grpc_avl_add(avl, box(697), box(713), nullptr);
+  avl = remove_int(avl, 271);
+  avl = grpc_avl_add(avl, box(968), box(715), nullptr);
+  avl = grpc_avl_add(avl, box(48), box(716), nullptr);
+  avl = remove_int(avl, 543);
+  avl = grpc_avl_add(avl, box(35), box(718), nullptr);
+  avl = grpc_avl_add(avl, box(751), box(719), nullptr);
+  avl = grpc_avl_add(avl, box(478), box(720), nullptr);
+  avl = remove_int(avl, 797);
+  avl = remove_int(avl, 309);
+  avl = grpc_avl_add(avl, box(927), box(723), nullptr);
+  avl = remove_int(avl, 504);
+  avl = grpc_avl_add(avl, box(286), box(725), nullptr);
+  avl = grpc_avl_add(avl, box(413), box(726), nullptr);
+  avl = grpc_avl_add(avl, box(599), box(727), nullptr);
+  avl = remove_int(avl, 105);
+  avl = remove_int(avl, 605);
+  avl = grpc_avl_add(avl, box(632), box(730), nullptr);
+  avl = grpc_avl_add(avl, box(133), box(731), nullptr);
+  avl = remove_int(avl, 443);
+  avl = grpc_avl_add(avl, box(958), box(733), nullptr);
+  avl = grpc_avl_add(avl, box(729), box(734), nullptr);
+  avl = remove_int(avl, 158);
+  avl = grpc_avl_add(avl, box(694), box(736), nullptr);
+  avl = grpc_avl_add(avl, box(505), box(737), nullptr);
+  avl = remove_int(avl, 63);
+  avl = remove_int(avl, 714);
+  avl = grpc_avl_add(avl, box(1002), box(740), nullptr);
+  avl = remove_int(avl, 211);
+  avl = grpc_avl_add(avl, box(765), box(742), nullptr);
+  avl = grpc_avl_add(avl, box(455), box(743), nullptr);
+  avl = remove_int(avl, 59);
+  avl = remove_int(avl, 224);
+  avl = grpc_avl_add(avl, box(586), box(746), nullptr);
+  avl = grpc_avl_add(avl, box(348), box(747), nullptr);
+  avl = remove_int(avl, 10);
+  avl = remove_int(avl, 484);
+  avl = grpc_avl_add(avl, box(968), box(750), nullptr);
+  avl = grpc_avl_add(avl, box(923), box(751), nullptr);
+  avl = remove_int(avl, 573);
+  avl = remove_int(avl, 617);
+  avl = grpc_avl_add(avl, box(812), box(754), nullptr);
+  avl = grpc_avl_add(avl, box(179), box(755), nullptr);
+  avl = remove_int(avl, 284);
+  avl = remove_int(avl, 157);
+  avl = remove_int(avl, 177);
+  avl = remove_int(avl, 896);
+  avl = grpc_avl_add(avl, box(649), box(760), nullptr);
+  avl = grpc_avl_add(avl, box(927), box(761), nullptr);
+  avl = grpc_avl_add(avl, box(454), box(762), nullptr);
+  avl = grpc_avl_add(avl, box(217), box(763), nullptr);
+  avl = remove_int(avl, 534);
+  avl = grpc_avl_add(avl, box(180), box(765), nullptr);
+  avl = grpc_avl_add(avl, box(319), box(766), nullptr);
+  avl = remove_int(avl, 92);
+  avl = grpc_avl_add(avl, box(483), box(768), nullptr);
+  avl = remove_int(avl, 504);
+  avl = remove_int(avl, 1017);
+  avl = remove_int(avl, 37);
+  avl = remove_int(avl, 50);
+  avl = grpc_avl_add(avl, box(302), box(773), nullptr);
+  avl = remove_int(avl, 807);
+  avl = grpc_avl_add(avl, box(463), box(775), nullptr);
+  avl = grpc_avl_add(avl, box(271), box(776), nullptr);
+  avl = grpc_avl_add(avl, box(644), box(777), nullptr);
+  avl = remove_int(avl, 618);
+  avl = grpc_avl_add(avl, box(166), box(779), nullptr);
+  avl = grpc_avl_add(avl, box(538), box(780), nullptr);
+  avl = remove_int(avl, 606);
+  avl = grpc_avl_add(avl, box(425), box(782), nullptr);
+  avl = remove_int(avl, 725);
+  avl = remove_int(avl, 383);
+  avl = grpc_avl_add(avl, box(155), box(785), nullptr);
+  avl = remove_int(avl, 889);
+  avl = grpc_avl_add(avl, box(653), box(787), nullptr);
+  avl = remove_int(avl, 386);
+  avl = grpc_avl_add(avl, box(142), box(789), nullptr);
+  avl = remove_int(avl, 107);
+  avl = remove_int(avl, 603);
+  avl = remove_int(avl, 971);
+  avl = grpc_avl_add(avl, box(80), box(793), nullptr);
+  avl = grpc_avl_add(avl, box(61), box(794), nullptr);
+  avl = grpc_avl_add(avl, box(693), box(795), nullptr);
+  avl = grpc_avl_add(avl, box(592), box(796), nullptr);
+  avl = grpc_avl_add(avl, box(433), box(797), nullptr);
+  avl = grpc_avl_add(avl, box(973), box(798), nullptr);
+  avl = remove_int(avl, 901);
+  avl = remove_int(avl, 340);
+  avl = remove_int(avl, 709);
+  avl = grpc_avl_add(avl, box(224), box(802), nullptr);
+  avl = remove_int(avl, 120);
+  avl = remove_int(avl, 271);
+  avl = grpc_avl_add(avl, box(780), box(805), nullptr);
+  avl = grpc_avl_add(avl, box(867), box(806), nullptr);
+  avl = grpc_avl_add(avl, box(756), box(807), nullptr);
+  avl = grpc_avl_add(avl, box(583), box(808), nullptr);
+  avl = grpc_avl_add(avl, box(356), box(809), nullptr);
+  avl = grpc_avl_add(avl, box(58), box(810), nullptr);
+  avl = remove_int(avl, 219);
+  avl = grpc_avl_add(avl, box(301), box(812), nullptr);
+  avl = remove_int(avl, 643);
+  avl = remove_int(avl, 787);
+  avl = remove_int(avl, 583);
+  avl = remove_int(avl, 552);
+  avl = remove_int(avl, 308);
+  avl = remove_int(avl, 608);
+  avl = remove_int(avl, 363);
+  avl = remove_int(avl, 690);
+  avl = grpc_avl_add(avl, box(233), box(821), nullptr);
+  avl = grpc_avl_add(avl, box(479), box(822), nullptr);
+  avl = grpc_avl_add(avl, box(323), box(823), nullptr);
+  avl = grpc_avl_add(avl, box(802), box(824), nullptr);
+  avl = remove_int(avl, 682);
+  avl = remove_int(avl, 705);
+  avl = remove_int(avl, 487);
+  avl = grpc_avl_add(avl, box(530), box(828), nullptr);
+  avl = grpc_avl_add(avl, box(232), box(829), nullptr);
+  avl = remove_int(avl, 627);
+  avl = grpc_avl_add(avl, box(396), box(831), nullptr);
+  avl = grpc_avl_add(avl, box(61), box(832), nullptr);
+  avl = grpc_avl_add(avl, box(932), box(833), nullptr);
+  avl = grpc_avl_add(avl, box(108), box(834), nullptr);
+  avl = grpc_avl_add(avl, box(524), box(835), nullptr);
+  avl = remove_int(avl, 390);
+  avl = remove_int(avl, 307);
+  avl = grpc_avl_add(avl, box(722), box(838), nullptr);
+  avl = grpc_avl_add(avl, box(907), box(839), nullptr);
+  avl = remove_int(avl, 286);
+  avl = remove_int(avl, 337);
+  avl = remove_int(avl, 443);
+  avl = grpc_avl_add(avl, box(973), box(843), nullptr);
+  avl = remove_int(avl, 930);
+  avl = remove_int(avl, 242);
+  avl = grpc_avl_add(avl, box(997), box(846), nullptr);
+  avl = grpc_avl_add(avl, box(689), box(847), nullptr);
+  avl = remove_int(avl, 318);
+  avl = grpc_avl_add(avl, box(703), box(849), nullptr);
+  avl = grpc_avl_add(avl, box(868), box(850), nullptr);
+  avl = grpc_avl_add(avl, box(200), box(851), nullptr);
+  avl = grpc_avl_add(avl, box(960), box(852), nullptr);
+  avl = grpc_avl_add(avl, box(80), box(853), nullptr);
+  avl = remove_int(avl, 113);
+  avl = grpc_avl_add(avl, box(135), box(855), nullptr);
+  avl = remove_int(avl, 529);
+  avl = grpc_avl_add(avl, box(366), box(857), nullptr);
+  avl = remove_int(avl, 272);
+  avl = grpc_avl_add(avl, box(921), box(859), nullptr);
+  avl = remove_int(avl, 497);
+  avl = grpc_avl_add(avl, box(712), box(861), nullptr);
+  avl = remove_int(avl, 777);
+  avl = remove_int(avl, 505);
+  avl = remove_int(avl, 974);
+  avl = remove_int(avl, 497);
+  avl = grpc_avl_add(avl, box(388), box(866), nullptr);
+  avl = grpc_avl_add(avl, box(29), box(867), nullptr);
+  avl = grpc_avl_add(avl, box(180), box(868), nullptr);
+  avl = grpc_avl_add(avl, box(983), box(869), nullptr);
+  avl = grpc_avl_add(avl, box(72), box(870), nullptr);
+  avl = grpc_avl_add(avl, box(693), box(871), nullptr);
+  avl = grpc_avl_add(avl, box(567), box(872), nullptr);
+  avl = remove_int(avl, 549);
+  avl = remove_int(avl, 351);
+  avl = grpc_avl_add(avl, box(1019), box(875), nullptr);
+  avl = remove_int(avl, 585);
+  avl = remove_int(avl, 294);
+  avl = remove_int(avl, 61);
+  avl = grpc_avl_add(avl, box(409), box(879), nullptr);
+  avl = grpc_avl_add(avl, box(984), box(880), nullptr);
+  avl = grpc_avl_add(avl, box(830), box(881), nullptr);
+  avl = remove_int(avl, 579);
+  avl = grpc_avl_add(avl, box(672), box(883), nullptr);
+  avl = remove_int(avl, 968);
+
+  grpc_avl_unref(avl, nullptr);
+}
+
+static void test_badcase3(void) {
+  grpc_avl avl;
+
+  gpr_log(GPR_DEBUG, "test_badcase3");
+
+  avl = grpc_avl_create(&int_int_vtable);
+  avl = remove_int(avl, 624);
+  avl = grpc_avl_add(avl, box(59), box(2), nullptr);
+  avl = grpc_avl_add(avl, box(494), box(3), nullptr);
+  avl = grpc_avl_add(avl, box(226), box(4), nullptr);
+  avl = remove_int(avl, 524);
+  avl = grpc_avl_add(avl, box(540), box(6), nullptr);
+  avl = remove_int(avl, 1008);
+  avl = grpc_avl_add(avl, box(502), box(8), nullptr);
+  avl = remove_int(avl, 267);
+  avl = remove_int(avl, 764);
+  avl = remove_int(avl, 443);
+  avl = grpc_avl_add(avl, box(8), box(12), nullptr);
+  avl = remove_int(avl, 291);
+  avl = remove_int(avl, 796);
+  avl = remove_int(avl, 1002);
+  avl = grpc_avl_add(avl, box(778), box(16), nullptr);
+  avl = remove_int(avl, 621);
+  avl = remove_int(avl, 891);
+  avl = remove_int(avl, 880);
+  avl = grpc_avl_add(avl, box(197), box(20), nullptr);
+  avl = grpc_avl_add(avl, box(441), box(21), nullptr);
+  avl = grpc_avl_add(avl, box(719), box(22), nullptr);
+  avl = remove_int(avl, 109);
+  avl = grpc_avl_add(avl, box(458), box(24), nullptr);
+  avl = remove_int(avl, 86);
+  avl = grpc_avl_add(avl, box(897), box(26), nullptr);
+  avl = grpc_avl_add(avl, box(997), box(27), nullptr);
+  avl = remove_int(avl, 235);
+  avl = remove_int(avl, 425);
+  avl = remove_int(avl, 186);
+  avl = grpc_avl_add(avl, box(887), box(31), nullptr);
+  avl = grpc_avl_add(avl, box(1005), box(32), nullptr);
+  avl = grpc_avl_add(avl, box(778), box(33), nullptr);
+  avl = grpc_avl_add(avl, box(575), box(34), nullptr);
+  avl = remove_int(avl, 966);
+  avl = remove_int(avl, 1015);
+  avl = grpc_avl_add(avl, box(486), box(37), nullptr);
+  avl = grpc_avl_add(avl, box(809), box(38), nullptr);
+  avl = grpc_avl_add(avl, box(907), box(39), nullptr);
+  avl = grpc_avl_add(avl, box(971), box(40), nullptr);
+  avl = remove_int(avl, 441);
+  avl = remove_int(avl, 498);
+  avl = grpc_avl_add(avl, box(727), box(43), nullptr);
+  avl = remove_int(avl, 679);
+  avl = remove_int(avl, 740);
+  avl = remove_int(avl, 532);
+  avl = grpc_avl_add(avl, box(805), box(47), nullptr);
+  avl = remove_int(avl, 64);
+  avl = grpc_avl_add(avl, box(362), box(49), nullptr);
+  avl = grpc_avl_add(avl, box(170), box(50), nullptr);
+  avl = grpc_avl_add(avl, box(389), box(51), nullptr);
+  avl = grpc_avl_add(avl, box(689), box(52), nullptr);
+  avl = remove_int(avl, 871);
+  avl = grpc_avl_add(avl, box(447), box(54), nullptr);
+  avl = remove_int(avl, 718);
+  avl = grpc_avl_add(avl, box(724), box(56), nullptr);
+  avl = remove_int(avl, 215);
+  avl = grpc_avl_add(avl, box(550), box(58), nullptr);
+  avl = remove_int(avl, 932);
+  avl = grpc_avl_add(avl, box(47), box(60), nullptr);
+  avl = remove_int(avl, 46);
+  avl = remove_int(avl, 229);
+  avl = grpc_avl_add(avl, box(68), box(63), nullptr);
+  avl = grpc_avl_add(avl, box(387), box(64), nullptr);
+  avl = remove_int(avl, 933);
+  avl = remove_int(avl, 736);
+  avl = remove_int(avl, 719);
+  avl = grpc_avl_add(avl, box(150), box(68), nullptr);
+  avl = remove_int(avl, 875);
+  avl = remove_int(avl, 298);
+  avl = grpc_avl_add(avl, box(991), box(71), nullptr);
+  avl = remove_int(avl, 705);
+  avl = grpc_avl_add(avl, box(197), box(73), nullptr);
+  avl = grpc_avl_add(avl, box(101), box(74), nullptr);
+  avl = remove_int(avl, 436);
+  avl = grpc_avl_add(avl, box(755), box(76), nullptr);
+  avl = grpc_avl_add(avl, box(727), box(77), nullptr);
+  avl = remove_int(avl, 309);
+  avl = remove_int(avl, 253);
+  avl = grpc_avl_add(avl, box(203), box(80), nullptr);
+  avl = remove_int(avl, 231);
+  avl = grpc_avl_add(avl, box(461), box(82), nullptr);
+  avl = remove_int(avl, 316);
+  avl = remove_int(avl, 493);
+  avl = grpc_avl_add(avl, box(184), box(85), nullptr);
+  avl = remove_int(avl, 737);
+  avl = grpc_avl_add(avl, box(790), box(87), nullptr);
+  avl = grpc_avl_add(avl, box(335), box(88), nullptr);
+  avl = remove_int(avl, 649);
+  avl = grpc_avl_add(avl, box(69), box(90), nullptr);
+  avl = remove_int(avl, 585);
+  avl = remove_int(avl, 543);
+  avl = grpc_avl_add(avl, box(784), box(93), nullptr);
+  avl = grpc_avl_add(avl, box(60), box(94), nullptr);
+  avl = grpc_avl_add(avl, box(525), box(95), nullptr);
+  avl = grpc_avl_add(avl, box(177), box(96), nullptr);
+  avl = grpc_avl_add(avl, box(178), box(97), nullptr);
+  avl = grpc_avl_add(avl, box(683), box(98), nullptr);
+  avl = grpc_avl_add(avl, box(226), box(99), nullptr);
+  avl = grpc_avl_add(avl, box(662), box(100), nullptr);
+  avl = remove_int(avl, 944);
+  avl = grpc_avl_add(avl, box(562), box(102), nullptr);
+  avl = grpc_avl_add(avl, box(793), box(103), nullptr);
+  avl = remove_int(avl, 673);
+  avl = grpc_avl_add(avl, box(310), box(105), nullptr);
+  avl = remove_int(avl, 479);
+  avl = remove_int(avl, 543);
+  avl = remove_int(avl, 159);
+  avl = remove_int(avl, 850);
+  avl = grpc_avl_add(avl, box(318), box(110), nullptr);
+  avl = grpc_avl_add(avl, box(483), box(111), nullptr);
+  avl = grpc_avl_add(avl, box(84), box(112), nullptr);
+  avl = remove_int(avl, 109);
+  avl = grpc_avl_add(avl, box(132), box(114), nullptr);
+  avl = grpc_avl_add(avl, box(920), box(115), nullptr);
+  avl = remove_int(avl, 746);
+  avl = grpc_avl_add(avl, box(145), box(117), nullptr);
+  avl = grpc_avl_add(avl, box(526), box(118), nullptr);
+  avl = remove_int(avl, 158);
+  avl = grpc_avl_add(avl, box(332), box(120), nullptr);
+  avl = grpc_avl_add(avl, box(918), box(121), nullptr);
+  avl = remove_int(avl, 339);
+  avl = grpc_avl_add(avl, box(809), box(123), nullptr);
+  avl = grpc_avl_add(avl, box(742), box(124), nullptr);
+  avl = grpc_avl_add(avl, box(718), box(125), nullptr);
+  avl = remove_int(avl, 988);
+  avl = remove_int(avl, 531);
+  avl = remove_int(avl, 840);
+  avl = grpc_avl_add(avl, box(816), box(129), nullptr);
+  avl = grpc_avl_add(avl, box(976), box(130), nullptr);
+  avl = remove_int(avl, 743);
+  avl = remove_int(avl, 528);
+  avl = remove_int(avl, 982);
+  avl = grpc_avl_add(avl, box(803), box(134), nullptr);
+  avl = grpc_avl_add(avl, box(205), box(135), nullptr);
+  avl = grpc_avl_add(avl, box(584), box(136), nullptr);
+  avl = remove_int(avl, 923);
+  avl = remove_int(avl, 538);
+  avl = remove_int(avl, 398);
+  avl = remove_int(avl, 320);
+  avl = remove_int(avl, 292);
+  avl = grpc_avl_add(avl, box(270), box(142), nullptr);
+  avl = grpc_avl_add(avl, box(333), box(143), nullptr);
+  avl = remove_int(avl, 439);
+  avl = grpc_avl_add(avl, box(35), box(145), nullptr);
+  avl = grpc_avl_add(avl, box(837), box(146), nullptr);
+  avl = remove_int(avl, 65);
+  avl = remove_int(avl, 642);
+  avl = remove_int(avl, 371);
+  avl = remove_int(avl, 140);
+  avl = remove_int(avl, 533);
+  avl = remove_int(avl, 676);
+  avl = grpc_avl_add(avl, box(624), box(153), nullptr);
+  avl = grpc_avl_add(avl, box(116), box(154), nullptr);
+  avl = grpc_avl_add(avl, box(446), box(155), nullptr);
+  avl = remove_int(avl, 91);
+  avl = remove_int(avl, 721);
+  avl = remove_int(avl, 537);
+  avl = grpc_avl_add(avl, box(448), box(159), nullptr);
+  avl = remove_int(avl, 155);
+  avl = remove_int(avl, 344);
+  avl = remove_int(avl, 237);
+  avl = grpc_avl_add(avl, box(309), box(163), nullptr);
+  avl = grpc_avl_add(avl, box(434), box(164), nullptr);
+  avl = grpc_avl_add(avl, box(277), box(165), nullptr);
+  avl = remove_int(avl, 233);
+  avl = grpc_avl_add(avl, box(275), box(167), nullptr);
+  avl = grpc_avl_add(avl, box(218), box(168), nullptr);
+  avl = grpc_avl_add(avl, box(76), box(169), nullptr);
+  avl = grpc_avl_add(avl, box(898), box(170), nullptr);
+  avl = remove_int(avl, 771);
+  avl = grpc_avl_add(avl, box(237), box(172), nullptr);
+  avl = remove_int(avl, 327);
+  avl = grpc_avl_add(avl, box(499), box(174), nullptr);
+  avl = remove_int(avl, 727);
+  avl = remove_int(avl, 234);
+  avl = remove_int(avl, 623);
+  avl = remove_int(avl, 458);
+  avl = remove_int(avl, 326);
+  avl = remove_int(avl, 589);
+  avl = grpc_avl_add(avl, box(442), box(181), nullptr);
+  avl = remove_int(avl, 389);
+  avl = grpc_avl_add(avl, box(708), box(183), nullptr);
+  avl = grpc_avl_add(avl, box(594), box(184), nullptr);
+  avl = grpc_avl_add(avl, box(942), box(185), nullptr);
+  avl = grpc_avl_add(avl, box(282), box(186), nullptr);
+  avl = remove_int(avl, 434);
+  avl = remove_int(avl, 134);
+  avl = remove_int(avl, 270);
+  avl = remove_int(avl, 512);
+  avl = remove_int(avl, 265);
+  avl = remove_int(avl, 21);
+  avl = remove_int(avl, 193);
+  avl = remove_int(avl, 797);
+  avl = remove_int(avl, 347);
+  avl = grpc_avl_add(avl, box(99), box(196), nullptr);
+  avl = grpc_avl_add(avl, box(161), box(197), nullptr);
+  avl = remove_int(avl, 484);
+  avl = grpc_avl_add(avl, box(72), box(199), nullptr);
+  avl = remove_int(avl, 629);
+  avl = grpc_avl_add(avl, box(522), box(201), nullptr);
+  avl = remove_int(avl, 679);
+  avl = grpc_avl_add(avl, box(407), box(203), nullptr);
+  avl = remove_int(avl, 693);
+  avl = grpc_avl_add(avl, box(424), box(205), nullptr);
+  avl = grpc_avl_add(avl, box(651), box(206), nullptr);
+  avl = grpc_avl_add(avl, box(927), box(207), nullptr);
+  avl = remove_int(avl, 553);
+  avl = grpc_avl_add(avl, box(128), box(209), nullptr);
+  avl = grpc_avl_add(avl, box(616), box(210), nullptr);
+  avl = grpc_avl_add(avl, box(690), box(211), nullptr);
+  avl = remove_int(avl, 241);
+  avl = remove_int(avl, 179);
+  avl = grpc_avl_add(avl, box(697), box(214), nullptr);
+  avl = remove_int(avl, 779);
+  avl = grpc_avl_add(avl, box(241), box(216), nullptr);
+  avl = remove_int(avl, 190);
+  avl = remove_int(avl, 210);
+  avl = grpc_avl_add(avl, box(711), box(219), nullptr);
+  avl = remove_int(avl, 251);
+  avl = remove_int(avl, 61);
+  avl = grpc_avl_add(avl, box(800), box(222), nullptr);
+  avl = remove_int(avl, 551);
+  avl = grpc_avl_add(avl, box(61), box(224), nullptr);
+  avl = grpc_avl_add(avl, box(656), box(225), nullptr);
+  avl = remove_int(avl, 130);
+  avl = remove_int(avl, 368);
+  avl = remove_int(avl, 150);
+  avl = remove_int(avl, 73);
+  avl = grpc_avl_add(avl, box(799), box(230), nullptr);
+  avl = grpc_avl_add(avl, box(125), box(231), nullptr);
+  avl = remove_int(avl, 107);
+  avl = grpc_avl_add(avl, box(938), box(233), nullptr);
+  avl = grpc_avl_add(avl, box(914), box(234), nullptr);
+  avl = grpc_avl_add(avl, box(197), box(235), nullptr);
+  avl = remove_int(avl, 736);
+  avl = grpc_avl_add(avl, box(20), box(237), nullptr);
+  avl = remove_int(avl, 224);
+  avl = remove_int(avl, 841);
+  avl = grpc_avl_add(avl, box(226), box(240), nullptr);
+  avl = remove_int(avl, 963);
+  avl = remove_int(avl, 796);
+  avl = remove_int(avl, 728);
+  avl = grpc_avl_add(avl, box(855), box(244), nullptr);
+  avl = grpc_avl_add(avl, box(769), box(245), nullptr);
+  avl = grpc_avl_add(avl, box(631), box(246), nullptr);
+  avl = remove_int(avl, 648);
+  avl = grpc_avl_add(avl, box(187), box(248), nullptr);
+  avl = grpc_avl_add(avl, box(31), box(249), nullptr);
+  avl = remove_int(avl, 163);
+  avl = grpc_avl_add(avl, box(218), box(251), nullptr);
+  avl = grpc_avl_add(avl, box(488), box(252), nullptr);
+  avl = grpc_avl_add(avl, box(387), box(253), nullptr);
+  avl = grpc_avl_add(avl, box(809), box(254), nullptr);
+  avl = grpc_avl_add(avl, box(997), box(255), nullptr);
+  avl = remove_int(avl, 678);
+  avl = grpc_avl_add(avl, box(368), box(257), nullptr);
+  avl = grpc_avl_add(avl, box(220), box(258), nullptr);
+  avl = grpc_avl_add(avl, box(373), box(259), nullptr);
+  avl = remove_int(avl, 874);
+  avl = remove_int(avl, 682);
+  avl = remove_int(avl, 1014);
+  avl = remove_int(avl, 195);
+  avl = grpc_avl_add(avl, box(868), box(264), nullptr);
+  avl = remove_int(avl, 254);
+  avl = remove_int(avl, 456);
+  avl = grpc_avl_add(avl, box(906), box(267), nullptr);
+  avl = remove_int(avl, 711);
+  avl = grpc_avl_add(avl, box(632), box(269), nullptr);
+  avl = remove_int(avl, 474);
+  avl = grpc_avl_add(avl, box(508), box(271), nullptr);
+  avl = grpc_avl_add(avl, box(518), box(272), nullptr);
+  avl = remove_int(avl, 579);
+  avl = remove_int(avl, 948);
+  avl = grpc_avl_add(avl, box(789), box(275), nullptr);
+  avl = grpc_avl_add(avl, box(48), box(276), nullptr);
+  avl = grpc_avl_add(avl, box(256), box(277), nullptr);
+  avl = grpc_avl_add(avl, box(754), box(278), nullptr);
+  avl = remove_int(avl, 215);
+  avl = grpc_avl_add(avl, box(679), box(280), nullptr);
+  avl = grpc_avl_add(avl, box(606), box(281), nullptr);
+  avl = remove_int(avl, 941);
+  avl = remove_int(avl, 31);
+  avl = grpc_avl_add(avl, box(758), box(284), nullptr);
+  avl = remove_int(avl, 101);
+  avl = grpc_avl_add(avl, box(244), box(286), nullptr);
+  avl = grpc_avl_add(avl, box(337), box(287), nullptr);
+  avl = grpc_avl_add(avl, box(461), box(288), nullptr);
+  avl = remove_int(avl, 476);
+  avl = grpc_avl_add(avl, box(845), box(290), nullptr);
+  avl = remove_int(avl, 160);
+  avl = grpc_avl_add(avl, box(690), box(292), nullptr);
+  avl = remove_int(avl, 931);
+  avl = grpc_avl_add(avl, box(869), box(294), nullptr);
+  avl = grpc_avl_add(avl, box(1019), box(295), nullptr);
+  avl = remove_int(avl, 591);
+  avl = remove_int(avl, 635);
+  avl = remove_int(avl, 67);
+  avl = grpc_avl_add(avl, box(113), box(299), nullptr);
+  avl = remove_int(avl, 305);
+  avl = grpc_avl_add(avl, box(10), box(301), nullptr);
+  avl = remove_int(avl, 823);
+  avl = remove_int(avl, 288);
+  avl = remove_int(avl, 239);
+  avl = grpc_avl_add(avl, box(646), box(305), nullptr);
+  avl = grpc_avl_add(avl, box(1006), box(306), nullptr);
+  avl = grpc_avl_add(avl, box(954), box(307), nullptr);
+  avl = grpc_avl_add(avl, box(199), box(308), nullptr);
+  avl = grpc_avl_add(avl, box(69), box(309), nullptr);
+  avl = grpc_avl_add(avl, box(984), box(310), nullptr);
+  avl = remove_int(avl, 568);
+  avl = remove_int(avl, 666);
+  avl = remove_int(avl, 37);
+  avl = grpc_avl_add(avl, box(845), box(314), nullptr);
+  avl = remove_int(avl, 535);
+  avl = remove_int(avl, 365);
+  avl = remove_int(avl, 676);
+  avl = remove_int(avl, 892);
+  avl = remove_int(avl, 425);
+  avl = remove_int(avl, 704);
+  avl = remove_int(avl, 168);
+  avl = grpc_avl_add(avl, box(853), box(322), nullptr);
+  avl = grpc_avl_add(avl, box(335), box(323), nullptr);
+  avl = grpc_avl_add(avl, box(961), box(324), nullptr);
+  avl = grpc_avl_add(avl, box(73), box(325), nullptr);
+  avl = remove_int(avl, 469);
+  avl = grpc_avl_add(avl, box(449), box(327), nullptr);
+  avl = remove_int(avl, 821);
+  avl = grpc_avl_add(avl, box(845), box(329), nullptr);
+  avl = remove_int(avl, 637);
+  avl = grpc_avl_add(avl, box(769), box(331), nullptr);
+  avl = grpc_avl_add(avl, box(901), box(332), nullptr);
+  avl = remove_int(avl, 142);
+  avl = remove_int(avl, 361);
+  avl = remove_int(avl, 876);
+  avl = grpc_avl_add(avl, box(614), box(336), nullptr);
+  avl = grpc_avl_add(avl, box(729), box(337), nullptr);
+  avl = remove_int(avl, 120);
+  avl = remove_int(avl, 473);
+  avl = remove_int(avl, 445);
+  avl = grpc_avl_add(avl, box(978), box(341), nullptr);
+  avl = grpc_avl_add(avl, box(164), box(342), nullptr);
+  avl = grpc_avl_add(avl, box(1), box(343), nullptr);
+  avl = remove_int(avl, 890);
+  avl = grpc_avl_add(avl, box(605), box(345), nullptr);
+  avl = grpc_avl_add(avl, box(178), box(346), nullptr);
+  avl = grpc_avl_add(avl, box(481), box(347), nullptr);
+  avl = grpc_avl_add(avl, box(772), box(348), nullptr);
+  avl = remove_int(avl, 824);
+  avl = remove_int(avl, 167);
+  avl = remove_int(avl, 151);
+  avl = grpc_avl_add(avl, box(698), box(352), nullptr);
+  avl = grpc_avl_add(avl, box(202), box(353), nullptr);
+  avl = grpc_avl_add(avl, box(921), box(354), nullptr);
+  avl = grpc_avl_add(avl, box(875), box(355), nullptr);
+  avl = remove_int(avl, 197);
+  avl = remove_int(avl, 232);
+  avl = grpc_avl_add(avl, box(209), box(358), nullptr);
+  avl = remove_int(avl, 324);
+  avl = remove_int(avl, 56);
+  avl = remove_int(avl, 579);
+  avl = remove_int(avl, 255);
+  avl = remove_int(avl, 290);
+  avl = grpc_avl_add(avl, box(661), box(364), nullptr);
+  avl = grpc_avl_add(avl, box(113), box(365), nullptr);
+  avl = remove_int(avl, 767);
+  avl = grpc_avl_add(avl, box(586), box(367), nullptr);
+  avl = grpc_avl_add(avl, box(121), box(368), nullptr);
+  avl = remove_int(avl, 235);
+  avl = remove_int(avl, 439);
+  avl = remove_int(avl, 360);
+  avl = grpc_avl_add(avl, box(916), box(372), nullptr);
+  avl = remove_int(avl, 999);
+  avl = grpc_avl_add(avl, box(825), box(374), nullptr);
+  avl = grpc_avl_add(avl, box(177), box(375), nullptr);
+  avl = remove_int(avl, 204);
+  avl = remove_int(avl, 92);
+  avl = grpc_avl_add(avl, box(794), box(378), nullptr);
+  avl = grpc_avl_add(avl, box(463), box(379), nullptr);
+  avl = grpc_avl_add(avl, box(472), box(380), nullptr);
+  avl = remove_int(avl, 235);
+  avl = grpc_avl_add(avl, box(840), box(382), nullptr);
+  avl = remove_int(avl, 657);
+  avl = grpc_avl_add(avl, box(586), box(384), nullptr);
+  avl = grpc_avl_add(avl, box(979), box(385), nullptr);
+  avl = remove_int(avl, 979);
+  avl = grpc_avl_add(avl, box(639), box(387), nullptr);
+  avl = remove_int(avl, 907);
+  avl = remove_int(avl, 973);
+  avl = grpc_avl_add(avl, box(913), box(390), nullptr);
+  avl = grpc_avl_add(avl, box(566), box(391), nullptr);
+  avl = grpc_avl_add(avl, box(883), box(392), nullptr);
+  avl = grpc_avl_add(avl, box(552), box(393), nullptr);
+  avl = grpc_avl_add(avl, box(16), box(394), nullptr);
+  avl = remove_int(avl, 60);
+  avl = grpc_avl_add(avl, box(567), box(396), nullptr);
+  avl = grpc_avl_add(avl, box(705), box(397), nullptr);
+  avl = grpc_avl_add(avl, box(94), box(398), nullptr);
+  avl = remove_int(avl, 321);
+  avl = grpc_avl_add(avl, box(207), box(400), nullptr);
+  avl = grpc_avl_add(avl, box(682), box(401), nullptr);
+  avl = grpc_avl_add(avl, box(592), box(402), nullptr);
+  avl = grpc_avl_add(avl, box(10), box(403), nullptr);
+  avl = remove_int(avl, 911);
+  avl = remove_int(avl, 161);
+  avl = grpc_avl_add(avl, box(86), box(406), nullptr);
+  avl = remove_int(avl, 893);
+  avl = remove_int(avl, 362);
+  avl = grpc_avl_add(avl, box(599), box(409), nullptr);
+  avl = remove_int(avl, 413);
+  avl = grpc_avl_add(avl, box(867), box(411), nullptr);
+  avl = remove_int(avl, 955);
+  avl = grpc_avl_add(avl, box(341), box(413), nullptr);
+  avl = grpc_avl_add(avl, box(887), box(414), nullptr);
+  avl = remove_int(avl, 706);
+  avl = grpc_avl_add(avl, box(939), box(416), nullptr);
+  avl = remove_int(avl, 233);
+  avl = remove_int(avl, 662);
+  avl = remove_int(avl, 984);
+  avl = remove_int(avl, 203);
+  avl = grpc_avl_add(avl, box(326), box(421), nullptr);
+  avl = remove_int(avl, 848);
+  avl = grpc_avl_add(avl, box(235), box(423), nullptr);
+  avl = remove_int(avl, 617);
+  avl = grpc_avl_add(avl, box(565), box(425), nullptr);
+  avl = remove_int(avl, 469);
+  avl = grpc_avl_add(avl, box(988), box(427), nullptr);
+  avl = remove_int(avl, 957);
+  avl = grpc_avl_add(avl, box(426), box(429), nullptr);
+  avl = remove_int(avl, 967);
+  avl = grpc_avl_add(avl, box(890), box(431), nullptr);
+  avl = grpc_avl_add(avl, box(473), box(432), nullptr);
+  avl = remove_int(avl, 367);
+  avl = remove_int(avl, 344);
+  avl = remove_int(avl, 660);
+  avl = remove_int(avl, 448);
+  avl = remove_int(avl, 837);
+  avl = remove_int(avl, 158);
+  avl = grpc_avl_add(avl, box(459), box(439), nullptr);
+  avl = remove_int(avl, 882);
+  avl = remove_int(avl, 782);
+  avl = grpc_avl_add(avl, box(408), box(442), nullptr);
+  avl = grpc_avl_add(avl, box(728), box(443), nullptr);
+  avl = remove_int(avl, 27);
+  avl = grpc_avl_add(avl, box(137), box(445), nullptr);
+  avl = grpc_avl_add(avl, box(239), box(446), nullptr);
+  avl = remove_int(avl, 854);
+  avl = grpc_avl_add(avl, box(104), box(448), nullptr);
+  avl = grpc_avl_add(avl, box(823), box(449), nullptr);
+  avl = grpc_avl_add(avl, box(524), box(450), nullptr);
+  avl = grpc_avl_add(avl, box(995), box(451), nullptr);
+  avl = remove_int(avl, 422);
+  avl = remove_int(avl, 220);
+  avl = grpc_avl_add(avl, box(856), box(454), nullptr);
+  avl = remove_int(avl, 332);
+  avl = grpc_avl_add(avl, box(679), box(456), nullptr);
+  avl = remove_int(avl, 18);
+  avl = grpc_avl_add(avl, box(837), box(458), nullptr);
+  avl = remove_int(avl, 405);
+  avl = remove_int(avl, 877);
+  avl = remove_int(avl, 835);
+  avl = grpc_avl_add(avl, box(547), box(462), nullptr);
+  avl = remove_int(avl, 805);
+  avl = remove_int(avl, 862);
+  avl = grpc_avl_add(avl, box(75), box(465), nullptr);
+  avl = remove_int(avl, 41);
+  avl = grpc_avl_add(avl, box(310), box(467), nullptr);
+  avl = remove_int(avl, 855);
+  avl = grpc_avl_add(avl, box(20), box(469), nullptr);
+  avl = remove_int(avl, 186);
+  avl = remove_int(avl, 378);
+  avl = remove_int(avl, 442);
+  avl = remove_int(avl, 930);
+  avl = grpc_avl_add(avl, box(118), box(474), nullptr);
+  avl = grpc_avl_add(avl, box(96), box(475), nullptr);
+  avl = remove_int(avl, 854);
+  avl = grpc_avl_add(avl, box(65), box(477), nullptr);
+  avl = grpc_avl_add(avl, box(573), box(478), nullptr);
+  avl = grpc_avl_add(avl, box(4), box(479), nullptr);
+  avl = grpc_avl_add(avl, box(451), box(480), nullptr);
+  avl = grpc_avl_add(avl, box(774), box(481), nullptr);
+  avl = grpc_avl_add(avl, box(126), box(482), nullptr);
+  avl = remove_int(avl, 956);
+  avl = remove_int(avl, 591);
+  avl = remove_int(avl, 644);
+  avl = grpc_avl_add(avl, box(304), box(486), nullptr);
+  avl = remove_int(avl, 620);
+  avl = remove_int(avl, 394);
+  avl = grpc_avl_add(avl, box(1002), box(489), nullptr);
+  avl = grpc_avl_add(avl, box(837), box(490), nullptr);
+  avl = remove_int(avl, 485);
+  avl = grpc_avl_add(avl, box(1005), box(492), nullptr);
+  avl = remove_int(avl, 21);
+  avl = grpc_avl_add(avl, box(396), box(494), nullptr);
+  avl = remove_int(avl, 966);
+  avl = grpc_avl_add(avl, box(105), box(496), nullptr);
+  avl = grpc_avl_add(avl, box(316), box(497), nullptr);
+  avl = remove_int(avl, 776);
+  avl = grpc_avl_add(avl, box(188), box(499), nullptr);
+  avl = remove_int(avl, 200);
+  avl = grpc_avl_add(avl, box(98), box(501), nullptr);
+  avl = grpc_avl_add(avl, box(831), box(502), nullptr);
+  avl = grpc_avl_add(avl, box(227), box(503), nullptr);
+  avl = grpc_avl_add(avl, box(220), box(504), nullptr);
+  avl = remove_int(avl, 715);
+  avl = remove_int(avl, 279);
+  avl = grpc_avl_add(avl, box(701), box(507), nullptr);
+  avl = grpc_avl_add(avl, box(726), box(508), nullptr);
+  avl = grpc_avl_add(avl, box(815), box(509), nullptr);
+  avl = grpc_avl_add(avl, box(749), box(510), nullptr);
+  avl = remove_int(avl, 946);
+  avl = remove_int(avl, 449);
+  avl = remove_int(avl, 62);
+  avl = remove_int(avl, 487);
+  avl = grpc_avl_add(avl, box(545), box(515), nullptr);
+  avl = remove_int(avl, 59);
+  avl = grpc_avl_add(avl, box(168), box(517), nullptr);
+  avl = remove_int(avl, 337);
+  avl = grpc_avl_add(avl, box(69), box(519), nullptr);
+  avl = remove_int(avl, 600);
+  avl = grpc_avl_add(avl, box(591), box(521), nullptr);
+  avl = grpc_avl_add(avl, box(960), box(522), nullptr);
+  avl = grpc_avl_add(avl, box(116), box(523), nullptr);
+  avl = remove_int(avl, 991);
+  avl = grpc_avl_add(avl, box(760), box(525), nullptr);
+  avl = grpc_avl_add(avl, box(664), box(526), nullptr);
+  avl = grpc_avl_add(avl, box(547), box(527), nullptr);
+  avl = remove_int(avl, 922);
+  avl = grpc_avl_add(avl, box(290), box(529), nullptr);
+  avl = grpc_avl_add(avl, box(859), box(530), nullptr);
+  avl = grpc_avl_add(avl, box(49), box(531), nullptr);
+  avl = remove_int(avl, 455);
+  avl = remove_int(avl, 786);
+  avl = grpc_avl_add(avl, box(613), box(534), nullptr);
+  avl = grpc_avl_add(avl, box(326), box(535), nullptr);
+  avl = remove_int(avl, 615);
+  avl = grpc_avl_add(avl, box(45), box(537), nullptr);
+  avl = grpc_avl_add(avl, box(162), box(538), nullptr);
+  avl = grpc_avl_add(avl, box(189), box(539), nullptr);
+  avl = remove_int(avl, 68);
+  avl = remove_int(avl, 846);
+  avl = grpc_avl_add(avl, box(608), box(542), nullptr);
+  avl = remove_int(avl, 821);
+  avl = grpc_avl_add(avl, box(978), box(544), nullptr);
+  avl = grpc_avl_add(avl, box(892), box(545), nullptr);
+  avl = remove_int(avl, 924);
+  avl = grpc_avl_add(avl, box(708), box(547), nullptr);
+  avl = remove_int(avl, 135);
+  avl = remove_int(avl, 124);
+  avl = grpc_avl_add(avl, box(301), box(550), nullptr);
+  avl = grpc_avl_add(avl, box(939), box(551), nullptr);
+  avl = grpc_avl_add(avl, box(344), box(552), nullptr);
+  avl = remove_int(avl, 443);
+  avl = remove_int(avl, 122);
+  avl = grpc_avl_add(avl, box(636), box(555), nullptr);
+  avl = remove_int(avl, 558);
+  avl = grpc_avl_add(avl, box(923), box(557), nullptr);
+  avl = remove_int(avl, 827);
+  avl = grpc_avl_add(avl, box(649), box(559), nullptr);
+  avl = grpc_avl_add(avl, box(808), box(560), nullptr);
+  avl = remove_int(avl, 570);
+  avl = remove_int(avl, 434);
+  avl = grpc_avl_add(avl, box(40), box(563), nullptr);
+  avl = grpc_avl_add(avl, box(725), box(564), nullptr);
+  avl = remove_int(avl, 295);
+  avl = remove_int(avl, 615);
+  avl = remove_int(avl, 919);
+  avl = remove_int(avl, 170);
+  avl = remove_int(avl, 442);
+  avl = remove_int(avl, 971);
+  avl = grpc_avl_add(avl, box(483), box(571), nullptr);
+  avl = grpc_avl_add(avl, box(512), box(572), nullptr);
+  avl = remove_int(avl, 648);
+  avl = remove_int(avl, 78);
+  avl = remove_int(avl, 72);
+  avl = remove_int(avl, 790);
+  avl = remove_int(avl, 571);
+  avl = grpc_avl_add(avl, box(898), box(578), nullptr);
+  avl = remove_int(avl, 770);
+  avl = remove_int(avl, 776);
+  avl = grpc_avl_add(avl, box(602), box(581), nullptr);
+  avl = remove_int(avl, 251);
+  avl = grpc_avl_add(avl, box(303), box(583), nullptr);
+  avl = remove_int(avl, 837);
+  avl = grpc_avl_add(avl, box(714), box(585), nullptr);
+  avl = remove_int(avl, 800);
+  avl = grpc_avl_add(avl, box(266), box(587), nullptr);
+  avl = grpc_avl_add(avl, box(555), box(588), nullptr);
+  avl = remove_int(avl, 604);
+  avl = remove_int(avl, 163);
+  avl = remove_int(avl, 497);
+  avl = grpc_avl_add(avl, box(296), box(592), nullptr);
+  avl = remove_int(avl, 129);
+  avl = grpc_avl_add(avl, box(656), box(594), nullptr);
+  avl = remove_int(avl, 769);
+  avl = remove_int(avl, 941);
+  avl = grpc_avl_add(avl, box(775), box(597), nullptr);
+  avl = grpc_avl_add(avl, box(846), box(598), nullptr);
+  avl = remove_int(avl, 591);
+  avl = remove_int(avl, 801);
+  avl = remove_int(avl, 419);
+  avl = remove_int(avl, 455);
+  avl = grpc_avl_add(avl, box(866), box(603), nullptr);
+  avl = grpc_avl_add(avl, box(575), box(604), nullptr);
+  avl = grpc_avl_add(avl, box(620), box(605), nullptr);
+  avl = remove_int(avl, 100);
+  avl = remove_int(avl, 667);
+  avl = grpc_avl_add(avl, box(138), box(608), nullptr);
+  avl = grpc_avl_add(avl, box(566), box(609), nullptr);
+  avl = grpc_avl_add(avl, box(673), box(610), nullptr);
+  avl = grpc_avl_add(avl, box(178), box(611), nullptr);
+  avl = remove_int(avl, 659);
+  avl = grpc_avl_add(avl, box(759), box(613), nullptr);
+  avl = grpc_avl_add(avl, box(1008), box(614), nullptr);
+  avl = remove_int(avl, 116);
+  avl = grpc_avl_add(avl, box(608), box(616), nullptr);
+  avl = grpc_avl_add(avl, box(339), box(617), nullptr);
+  avl = grpc_avl_add(avl, box(197), box(618), nullptr);
+  avl = remove_int(avl, 25);
+  avl = remove_int(avl, 628);
+  avl = grpc_avl_add(avl, box(487), box(621), nullptr);
+  avl = remove_int(avl, 739);
+  avl = remove_int(avl, 100);
+  avl = remove_int(avl, 928);
+  avl = grpc_avl_add(avl, box(647), box(625), nullptr);
+  avl = remove_int(avl, 978);
+  avl = remove_int(avl, 143);
+  avl = remove_int(avl, 755);
+  avl = grpc_avl_add(avl, box(71), box(629), nullptr);
+  avl = remove_int(avl, 205);
+  avl = grpc_avl_add(avl, box(501), box(631), nullptr);
+  avl = remove_int(avl, 723);
+  avl = remove_int(avl, 852);
+  avl = remove_int(avl, 1021);
+  avl = remove_int(avl, 670);
+  avl = remove_int(avl, 500);
+  avl = grpc_avl_add(avl, box(330), box(637), nullptr);
+  avl = remove_int(avl, 264);
+  avl = grpc_avl_add(avl, box(69), box(639), nullptr);
+  avl = remove_int(avl, 73);
+  avl = grpc_avl_add(avl, box(745), box(641), nullptr);
+  avl = remove_int(avl, 518);
+  avl = remove_int(avl, 641);
+  avl = remove_int(avl, 768);
+  avl = grpc_avl_add(avl, box(988), box(645), nullptr);
+  avl = grpc_avl_add(avl, box(899), box(646), nullptr);
+  avl = remove_int(avl, 763);
+  avl = remove_int(avl, 281);
+  avl = remove_int(avl, 496);
+  avl = grpc_avl_add(avl, box(445), box(650), nullptr);
+  avl = remove_int(avl, 905);
+  avl = grpc_avl_add(avl, box(275), box(652), nullptr);
+  avl = grpc_avl_add(avl, box(137), box(653), nullptr);
+  avl = remove_int(avl, 642);
+  avl = grpc_avl_add(avl, box(708), box(655), nullptr);
+  avl = remove_int(avl, 922);
+  avl = grpc_avl_add(avl, box(743), box(657), nullptr);
+  avl = remove_int(avl, 295);
+  avl = remove_int(avl, 665);
+  avl = remove_int(avl, 48);
+  avl = grpc_avl_add(avl, box(1012), box(661), nullptr);
+  avl = remove_int(avl, 71);
+  avl = remove_int(avl, 523);
+  avl = grpc_avl_add(avl, box(319), box(664), nullptr);
+  avl = remove_int(avl, 632);
+  avl = grpc_avl_add(avl, box(137), box(666), nullptr);
+  avl = grpc_avl_add(avl, box(686), box(667), nullptr);
+  avl = grpc_avl_add(avl, box(724), box(668), nullptr);
+  avl = grpc_avl_add(avl, box(952), box(669), nullptr);
+  avl = grpc_avl_add(avl, box(5), box(670), nullptr);
+  avl = remove_int(avl, 35);
+  avl = grpc_avl_add(avl, box(43), box(672), nullptr);
+  avl = grpc_avl_add(avl, box(320), box(673), nullptr);
+  avl = grpc_avl_add(avl, box(115), box(674), nullptr);
+  avl = remove_int(avl, 377);
+  avl = remove_int(avl, 591);
+  avl = remove_int(avl, 87);
+  avl = remove_int(avl, 93);
+  avl = grpc_avl_add(avl, box(1016), box(679), nullptr);
+  avl = grpc_avl_add(avl, box(605), box(680), nullptr);
+  avl = grpc_avl_add(avl, box(152), box(681), nullptr);
+  avl = grpc_avl_add(avl, box(113), box(682), nullptr);
+  avl = remove_int(avl, 131);
+  avl = remove_int(avl, 637);
+  avl = grpc_avl_add(avl, box(156), box(685), nullptr);
+  avl = remove_int(avl, 696);
+  avl = grpc_avl_add(avl, box(546), box(687), nullptr);
+  avl = remove_int(avl, 970);
+  avl = remove_int(avl, 53);
+  avl = remove_int(avl, 827);
+  avl = remove_int(avl, 224);
+  avl = remove_int(avl, 796);
+  avl = remove_int(avl, 34);
+  avl = remove_int(avl, 922);
+  avl = remove_int(avl, 277);
+  avl = remove_int(avl, 650);
+  avl = remove_int(avl, 222);
+  avl = remove_int(avl, 244);
+  avl = remove_int(avl, 576);
+  avl = remove_int(avl, 413);
+  avl = grpc_avl_add(avl, box(500), box(701), nullptr);
+  avl = remove_int(avl, 924);
+  avl = grpc_avl_add(avl, box(825), box(703), nullptr);
+  avl = remove_int(avl, 888);
+  avl = remove_int(avl, 931);
+  avl = grpc_avl_add(avl, box(285), box(706), nullptr);
+  avl = remove_int(avl, 62);
+  avl = remove_int(avl, 444);
+  avl = remove_int(avl, 946);
+  avl = grpc_avl_add(avl, box(122), box(710), nullptr);
+  avl = grpc_avl_add(avl, box(846), box(711), nullptr);
+  avl = remove_int(avl, 628);
+  avl = grpc_avl_add(avl, box(511), box(713), nullptr);
+  avl = grpc_avl_add(avl, box(398), box(714), nullptr);
+  avl = remove_int(avl, 730);
+  avl = grpc_avl_add(avl, box(797), box(716), nullptr);
+  avl = remove_int(avl, 897);
+  avl = remove_int(avl, 228);
+  avl = remove_int(avl, 544);
+  avl = remove_int(avl, 552);
+  avl = remove_int(avl, 783);
+  avl = remove_int(avl, 583);
+  avl = remove_int(avl, 894);
+  avl = remove_int(avl, 942);
+  avl = grpc_avl_add(avl, box(346), box(725), nullptr);
+  avl = grpc_avl_add(avl, box(1015), box(726), nullptr);
+  avl = remove_int(avl, 813);
+  avl = grpc_avl_add(avl, box(213), box(728), nullptr);
+  avl = remove_int(avl, 468);
+  avl = remove_int(avl, 365);
+  avl = remove_int(avl, 399);
+  avl = grpc_avl_add(avl, box(380), box(732), nullptr);
+  avl = remove_int(avl, 835);
+  avl = remove_int(avl, 970);
+  avl = grpc_avl_add(avl, box(700), box(735), nullptr);
+  avl = grpc_avl_add(avl, box(807), box(736), nullptr);
+  avl = remove_int(avl, 312);
+  avl = remove_int(avl, 282);
+  avl = remove_int(avl, 370);
+  avl = remove_int(avl, 999);
+  avl = remove_int(avl, 241);
+  avl = remove_int(avl, 884);
+  avl = grpc_avl_add(avl, box(587), box(743), nullptr);
+  avl = grpc_avl_add(avl, box(332), box(744), nullptr);
+  avl = remove_int(avl, 686);
+  avl = remove_int(avl, 206);
+  avl = remove_int(avl, 835);
+  avl = grpc_avl_add(avl, box(334), box(748), nullptr);
+  avl = remove_int(avl, 171);
+  avl = grpc_avl_add(avl, box(1002), box(750), nullptr);
+  avl = grpc_avl_add(avl, box(779), box(751), nullptr);
+  avl = grpc_avl_add(avl, box(307), box(752), nullptr);
+  avl = grpc_avl_add(avl, box(127), box(753), nullptr);
+  avl = grpc_avl_add(avl, box(251), box(754), nullptr);
+  avl = remove_int(avl, 790);
+  avl = remove_int(avl, 189);
+  avl = remove_int(avl, 193);
+  avl = remove_int(avl, 38);
+  avl = remove_int(avl, 124);
+  avl = grpc_avl_add(avl, box(812), box(760), nullptr);
+  avl = remove_int(avl, 43);
+  avl = grpc_avl_add(avl, box(871), box(762), nullptr);
+  avl = grpc_avl_add(avl, box(580), box(763), nullptr);
+  avl = remove_int(avl, 501);
+  avl = remove_int(avl, 462);
+  avl = remove_int(avl, 599);
+  avl = grpc_avl_add(avl, box(240), box(767), nullptr);
+  avl = grpc_avl_add(avl, box(285), box(768), nullptr);
+  avl = grpc_avl_add(avl, box(472), box(769), nullptr);
+  avl = remove_int(avl, 865);
+  avl = remove_int(avl, 763);
+  avl = remove_int(avl, 245);
+  avl = remove_int(avl, 80);
+  avl = remove_int(avl, 713);
+  avl = remove_int(avl, 654);
+  avl = remove_int(avl, 1014);
+  avl = grpc_avl_add(avl, box(495), box(777), nullptr);
+  avl = grpc_avl_add(avl, box(552), box(778), nullptr);
+  avl = remove_int(avl, 19);
+  avl = remove_int(avl, 803);
+  avl = grpc_avl_add(avl, box(508), box(781), nullptr);
+  avl = remove_int(avl, 699);
+  avl = remove_int(avl, 260);
+  avl = remove_int(avl, 92);
+  avl = remove_int(avl, 497);
+  avl = grpc_avl_add(avl, box(970), box(786), nullptr);
+  avl = remove_int(avl, 987);
+  avl = remove_int(avl, 168);
+  avl = remove_int(avl, 476);
+  avl = remove_int(avl, 248);
+  avl = grpc_avl_add(avl, box(358), box(791), nullptr);
+  avl = remove_int(avl, 804);
+  avl = remove_int(avl, 77);
+  avl = remove_int(avl, 905);
+  avl = remove_int(avl, 362);
+  avl = grpc_avl_add(avl, box(578), box(796), nullptr);
+  avl = remove_int(avl, 38);
+  avl = remove_int(avl, 595);
+  avl = grpc_avl_add(avl, box(213), box(799), nullptr);
+  avl = remove_int(avl, 7);
+  avl = remove_int(avl, 620);
+  avl = grpc_avl_add(avl, box(946), box(802), nullptr);
+  avl = remove_int(avl, 145);
+  avl = grpc_avl_add(avl, box(628), box(804), nullptr);
+  avl = remove_int(avl, 972);
+  avl = grpc_avl_add(avl, box(728), box(806), nullptr);
+  avl = remove_int(avl, 91);
+  avl = grpc_avl_add(avl, box(136), box(808), nullptr);
+  avl = grpc_avl_add(avl, box(841), box(809), nullptr);
+  avl = grpc_avl_add(avl, box(265), box(810), nullptr);
+  avl = grpc_avl_add(avl, box(701), box(811), nullptr);
+  avl = grpc_avl_add(avl, box(27), box(812), nullptr);
+  avl = remove_int(avl, 72);
+  avl = remove_int(avl, 14);
+  avl = grpc_avl_add(avl, box(286), box(815), nullptr);
+  avl = remove_int(avl, 996);
+  avl = remove_int(avl, 998);
+  avl = grpc_avl_add(avl, box(466), box(818), nullptr);
+  avl = remove_int(avl, 1009);
+  avl = remove_int(avl, 741);
+  avl = remove_int(avl, 947);
+  avl = remove_int(avl, 241);
+  avl = remove_int(avl, 954);
+  avl = remove_int(avl, 183);
+  avl = remove_int(avl, 395);
+  avl = remove_int(avl, 951);
+  avl = grpc_avl_add(avl, box(267), box(827), nullptr);
+  avl = remove_int(avl, 812);
+  avl = grpc_avl_add(avl, box(577), box(829), nullptr);
+  avl = remove_int(avl, 624);
+  avl = remove_int(avl, 847);
+  avl = remove_int(avl, 745);
+  avl = grpc_avl_add(avl, box(491), box(833), nullptr);
+  avl = grpc_avl_add(avl, box(941), box(834), nullptr);
+  avl = remove_int(avl, 258);
+  avl = grpc_avl_add(avl, box(410), box(836), nullptr);
+  avl = grpc_avl_add(avl, box(80), box(837), nullptr);
+  avl = grpc_avl_add(avl, box(196), box(838), nullptr);
+  avl = grpc_avl_add(avl, box(5), box(839), nullptr);
+  avl = remove_int(avl, 782);
+  avl = grpc_avl_add(avl, box(827), box(841), nullptr);
+  avl = remove_int(avl, 472);
+  avl = remove_int(avl, 664);
+  avl = grpc_avl_add(avl, box(409), box(844), nullptr);
+  avl = grpc_avl_add(avl, box(62), box(845), nullptr);
+  avl = remove_int(avl, 56);
+  avl = remove_int(avl, 606);
+  avl = remove_int(avl, 707);
+  avl = remove_int(avl, 989);
+  avl = remove_int(avl, 549);
+  avl = remove_int(avl, 259);
+  avl = grpc_avl_add(avl, box(405), box(852), nullptr);
+  avl = remove_int(avl, 587);
+  avl = remove_int(avl, 350);
+  avl = grpc_avl_add(avl, box(980), box(855), nullptr);
+  avl = grpc_avl_add(avl, box(992), box(856), nullptr);
+  avl = grpc_avl_add(avl, box(818), box(857), nullptr);
+  avl = remove_int(avl, 853);
+  avl = remove_int(avl, 701);
+  avl = grpc_avl_add(avl, box(675), box(860), nullptr);
+  avl = remove_int(avl, 248);
+  avl = remove_int(avl, 649);
+  avl = grpc_avl_add(avl, box(508), box(863), nullptr);
+  avl = remove_int(avl, 927);
+  avl = grpc_avl_add(avl, box(957), box(865), nullptr);
+  avl = grpc_avl_add(avl, box(698), box(866), nullptr);
+  avl = grpc_avl_add(avl, box(388), box(867), nullptr);
+  avl = grpc_avl_add(avl, box(532), box(868), nullptr);
+  avl = grpc_avl_add(avl, box(681), box(869), nullptr);
+  avl = remove_int(avl, 544);
+  avl = remove_int(avl, 991);
+  avl = remove_int(avl, 397);
+  avl = grpc_avl_add(avl, box(954), box(873), nullptr);
+  avl = grpc_avl_add(avl, box(219), box(874), nullptr);
+  avl = grpc_avl_add(avl, box(465), box(875), nullptr);
+  avl = remove_int(avl, 371);
+  avl = grpc_avl_add(avl, box(601), box(877), nullptr);
+  avl = grpc_avl_add(avl, box(543), box(878), nullptr);
+  avl = remove_int(avl, 329);
+  avl = grpc_avl_add(avl, box(560), box(880), nullptr);
+  avl = remove_int(avl, 898);
+  avl = grpc_avl_add(avl, box(455), box(882), nullptr);
+  avl = remove_int(avl, 313);
+  avl = grpc_avl_add(avl, box(215), box(884), nullptr);
+  avl = remove_int(avl, 846);
+  avl = grpc_avl_add(avl, box(608), box(886), nullptr);
+  avl = remove_int(avl, 248);
+  avl = grpc_avl_add(avl, box(575), box(888), nullptr);
+  avl = remove_int(avl, 207);
+  avl = remove_int(avl, 810);
+  avl = remove_int(avl, 665);
+  avl = remove_int(avl, 361);
+  avl = grpc_avl_add(avl, box(154), box(893), nullptr);
+  avl = grpc_avl_add(avl, box(329), box(894), nullptr);
+  avl = grpc_avl_add(avl, box(326), box(895), nullptr);
+  avl = remove_int(avl, 746);
+  avl = remove_int(avl, 99);
+  avl = grpc_avl_add(avl, box(464), box(898), nullptr);
+  avl = grpc_avl_add(avl, box(141), box(899), nullptr);
+  avl = remove_int(avl, 383);
+  avl = grpc_avl_add(avl, box(414), box(901), nullptr);
+  avl = grpc_avl_add(avl, box(777), box(902), nullptr);
+  avl = remove_int(avl, 972);
+  avl = remove_int(avl, 841);
+  avl = remove_int(avl, 100);
+  avl = grpc_avl_add(avl, box(828), box(906), nullptr);
+  avl = remove_int(avl, 785);
+  avl = grpc_avl_add(avl, box(1008), box(908), nullptr);
+  avl = grpc_avl_add(avl, box(46), box(909), nullptr);
+  avl = remove_int(avl, 399);
+  avl = grpc_avl_add(avl, box(178), box(911), nullptr);
+  avl = grpc_avl_add(avl, box(573), box(912), nullptr);
+  avl = remove_int(avl, 299);
+  avl = grpc_avl_add(avl, box(690), box(914), nullptr);
+  avl = grpc_avl_add(avl, box(692), box(915), nullptr);
+  avl = remove_int(avl, 404);
+  avl = remove_int(avl, 16);
+  avl = remove_int(avl, 746);
+  avl = remove_int(avl, 486);
+  avl = remove_int(avl, 119);
+  avl = grpc_avl_add(avl, box(167), box(921), nullptr);
+  avl = remove_int(avl, 328);
+  avl = grpc_avl_add(avl, box(89), box(923), nullptr);
+  avl = remove_int(avl, 867);
+  avl = remove_int(avl, 626);
+  avl = remove_int(avl, 507);
+  avl = grpc_avl_add(avl, box(365), box(927), nullptr);
+  avl = grpc_avl_add(avl, box(58), box(928), nullptr);
+  avl = grpc_avl_add(avl, box(70), box(929), nullptr);
+  avl = remove_int(avl, 81);
+  avl = remove_int(avl, 797);
+  avl = grpc_avl_add(avl, box(846), box(932), nullptr);
+  avl = remove_int(avl, 642);
+  avl = grpc_avl_add(avl, box(777), box(934), nullptr);
+  avl = remove_int(avl, 107);
+  avl = grpc_avl_add(avl, box(691), box(936), nullptr);
+  avl = grpc_avl_add(avl, box(820), box(937), nullptr);
+  avl = grpc_avl_add(avl, box(202), box(938), nullptr);
+  avl = grpc_avl_add(avl, box(308), box(939), nullptr);
+  avl = grpc_avl_add(avl, box(20), box(940), nullptr);
+  avl = remove_int(avl, 289);
+  avl = grpc_avl_add(avl, box(714), box(942), nullptr);
+  avl = grpc_avl_add(avl, box(584), box(943), nullptr);
+  avl = remove_int(avl, 294);
+  avl = grpc_avl_add(avl, box(496), box(945), nullptr);
+  avl = grpc_avl_add(avl, box(394), box(946), nullptr);
+  avl = grpc_avl_add(avl, box(860), box(947), nullptr);
+  avl = grpc_avl_add(avl, box(58), box(948), nullptr);
+  avl = remove_int(avl, 784);
+  avl = remove_int(avl, 584);
+  avl = remove_int(avl, 708);
+  avl = grpc_avl_add(avl, box(142), box(952), nullptr);
+  avl = grpc_avl_add(avl, box(247), box(953), nullptr);
+  avl = grpc_avl_add(avl, box(389), box(954), nullptr);
+  avl = remove_int(avl, 390);
+  avl = grpc_avl_add(avl, box(465), box(956), nullptr);
+  avl = grpc_avl_add(avl, box(936), box(957), nullptr);
+  avl = grpc_avl_add(avl, box(309), box(958), nullptr);
+  avl = remove_int(avl, 928);
+  avl = remove_int(avl, 128);
+  avl = remove_int(avl, 979);
+  avl = remove_int(avl, 670);
+  avl = remove_int(avl, 738);
+  avl = remove_int(avl, 271);
+  avl = remove_int(avl, 540);
+  avl = grpc_avl_add(avl, box(365), box(966), nullptr);
+  avl = remove_int(avl, 82);
+  avl = grpc_avl_add(avl, box(728), box(968), nullptr);
+  avl = remove_int(avl, 852);
+  avl = grpc_avl_add(avl, box(884), box(970), nullptr);
+  avl = grpc_avl_add(avl, box(502), box(971), nullptr);
+  avl = remove_int(avl, 898);
+  avl = remove_int(avl, 481);
+  avl = grpc_avl_add(avl, box(911), box(974), nullptr);
+  avl = remove_int(avl, 787);
+  avl = remove_int(avl, 785);
+  avl = remove_int(avl, 537);
+  avl = remove_int(avl, 535);
+  avl = remove_int(avl, 136);
+  avl = remove_int(avl, 749);
+  avl = remove_int(avl, 637);
+  avl = remove_int(avl, 900);
+  avl = grpc_avl_add(avl, box(598), box(983), nullptr);
+  avl = remove_int(avl, 25);
+  avl = remove_int(avl, 697);
+  avl = grpc_avl_add(avl, box(645), box(986), nullptr);
+  avl = grpc_avl_add(avl, box(211), box(987), nullptr);
+  avl = grpc_avl_add(avl, box(589), box(988), nullptr);
+  avl = remove_int(avl, 702);
+  avl = grpc_avl_add(avl, box(53), box(990), nullptr);
+  avl = remove_int(avl, 492);
+  avl = remove_int(avl, 185);
+  avl = remove_int(avl, 246);
+  avl = remove_int(avl, 257);
+  avl = remove_int(avl, 502);
+  avl = remove_int(avl, 34);
+  avl = grpc_avl_add(avl, box(74), box(997), nullptr);
+  avl = grpc_avl_add(avl, box(834), box(998), nullptr);
+  avl = grpc_avl_add(avl, box(514), box(999), nullptr);
+  avl = grpc_avl_add(avl, box(75), box(1000), nullptr);
+  avl = remove_int(avl, 745);
+  avl = grpc_avl_add(avl, box(362), box(1002), nullptr);
+  avl = remove_int(avl, 215);
+  avl = grpc_avl_add(avl, box(624), box(1004), nullptr);
+  avl = remove_int(avl, 404);
+  avl = remove_int(avl, 359);
+  avl = remove_int(avl, 491);
+  avl = grpc_avl_add(avl, box(903), box(1008), nullptr);
+  avl = grpc_avl_add(avl, box(240), box(1009), nullptr);
+  avl = remove_int(avl, 95);
+  avl = grpc_avl_add(avl, box(119), box(1011), nullptr);
+  avl = grpc_avl_add(avl, box(857), box(1012), nullptr);
+  avl = remove_int(avl, 39);
+  avl = remove_int(avl, 866);
+  avl = grpc_avl_add(avl, box(503), box(1015), nullptr);
+  avl = grpc_avl_add(avl, box(740), box(1016), nullptr);
+  avl = remove_int(avl, 637);
+  avl = remove_int(avl, 156);
+  avl = remove_int(avl, 6);
+  avl = remove_int(avl, 745);
+  avl = remove_int(avl, 433);
+  avl = remove_int(avl, 283);
+  avl = grpc_avl_add(avl, box(625), box(1023), nullptr);
+  avl = remove_int(avl, 638);
+  avl = grpc_avl_add(avl, box(299), box(1025), nullptr);
+  avl = grpc_avl_add(avl, box(584), box(1026), nullptr);
+  avl = remove_int(avl, 863);
+  avl = grpc_avl_add(avl, box(612), box(1028), nullptr);
+  avl = grpc_avl_add(avl, box(62), box(1029), nullptr);
+  avl = grpc_avl_add(avl, box(432), box(1030), nullptr);
+  avl = remove_int(avl, 371);
+  avl = remove_int(avl, 790);
+  avl = remove_int(avl, 227);
+  avl = remove_int(avl, 836);
+  avl = grpc_avl_add(avl, box(703), box(1035), nullptr);
+  avl = grpc_avl_add(avl, box(644), box(1036), nullptr);
+  avl = remove_int(avl, 638);
+  avl = grpc_avl_add(avl, box(13), box(1038), nullptr);
+  avl = remove_int(avl, 66);
+  avl = remove_int(avl, 82);
+  avl = grpc_avl_add(avl, box(362), box(1041), nullptr);
+  avl = grpc_avl_add(avl, box(783), box(1042), nullptr);
+  avl = remove_int(avl, 60);
+  avl = grpc_avl_add(avl, box(80), box(1044), nullptr);
+  avl = grpc_avl_add(avl, box(825), box(1045), nullptr);
+  avl = grpc_avl_add(avl, box(688), box(1046), nullptr);
+  avl = grpc_avl_add(avl, box(662), box(1047), nullptr);
+  avl = remove_int(avl, 156);
+  avl = remove_int(avl, 376);
+  avl = remove_int(avl, 99);
+  avl = grpc_avl_add(avl, box(526), box(1051), nullptr);
+  avl = grpc_avl_add(avl, box(168), box(1052), nullptr);
+  avl = remove_int(avl, 646);
+  avl = remove_int(avl, 380);
+  avl = remove_int(avl, 833);
+  avl = grpc_avl_add(avl, box(53), box(1056), nullptr);
+  avl = remove_int(avl, 105);
+  avl = grpc_avl_add(avl, box(373), box(1058), nullptr);
+  avl = grpc_avl_add(avl, box(184), box(1059), nullptr);
+  avl = remove_int(avl, 288);
+  avl = grpc_avl_add(avl, box(966), box(1061), nullptr);
+  avl = remove_int(avl, 158);
+  avl = grpc_avl_add(avl, box(406), box(1063), nullptr);
+  avl = remove_int(avl, 470);
+  avl = grpc_avl_add(avl, box(283), box(1065), nullptr);
+  avl = grpc_avl_add(avl, box(838), box(1066), nullptr);
+  avl = grpc_avl_add(avl, box(288), box(1067), nullptr);
+  avl = grpc_avl_add(avl, box(950), box(1068), nullptr);
+  avl = grpc_avl_add(avl, box(163), box(1069), nullptr);
+  avl = remove_int(avl, 623);
+  avl = remove_int(avl, 769);
+  avl = grpc_avl_add(avl, box(144), box(1072), nullptr);
+  avl = grpc_avl_add(avl, box(489), box(1073), nullptr);
+  avl = remove_int(avl, 15);
+  avl = grpc_avl_add(avl, box(971), box(1075), nullptr);
+  avl = remove_int(avl, 660);
+  avl = grpc_avl_add(avl, box(255), box(1077), nullptr);
+  avl = remove_int(avl, 494);
+  avl = grpc_avl_add(avl, box(109), box(1079), nullptr);
+  avl = grpc_avl_add(avl, box(420), box(1080), nullptr);
+  avl = grpc_avl_add(avl, box(509), box(1081), nullptr);
+  avl = remove_int(avl, 178);
+  avl = grpc_avl_add(avl, box(216), box(1083), nullptr);
+  avl = grpc_avl_add(avl, box(707), box(1084), nullptr);
+  avl = grpc_avl_add(avl, box(411), box(1085), nullptr);
+  avl = grpc_avl_add(avl, box(352), box(1086), nullptr);
+  avl = remove_int(avl, 983);
+  avl = grpc_avl_add(avl, box(6), box(1088), nullptr);
+  avl = grpc_avl_add(avl, box(1014), box(1089), nullptr);
+  avl = remove_int(avl, 98);
+  avl = remove_int(avl, 325);
+  avl = grpc_avl_add(avl, box(851), box(1092), nullptr);
+  avl = remove_int(avl, 553);
+  avl = grpc_avl_add(avl, box(218), box(1094), nullptr);
+  avl = grpc_avl_add(avl, box(261), box(1095), nullptr);
+  avl = remove_int(avl, 31);
+  avl = grpc_avl_add(avl, box(872), box(1097), nullptr);
+  avl = remove_int(avl, 543);
+  avl = remove_int(avl, 314);
+  avl = remove_int(avl, 443);
+  avl = grpc_avl_add(avl, box(533), box(1101), nullptr);
+  avl = remove_int(avl, 881);
+  avl = remove_int(avl, 269);
+  avl = remove_int(avl, 940);
+  avl = remove_int(avl, 909);
+  avl = remove_int(avl, 197);
+  avl = remove_int(avl, 773);
+  avl = remove_int(avl, 790);
+  avl = remove_int(avl, 345);
+  avl = grpc_avl_add(avl, box(965), box(1110), nullptr);
+  avl = remove_int(avl, 622);
+  avl = grpc_avl_add(avl, box(352), box(1112), nullptr);
+  avl = remove_int(avl, 182);
+  avl = grpc_avl_add(avl, box(534), box(1114), nullptr);
+  avl = grpc_avl_add(avl, box(97), box(1115), nullptr);
+  avl = grpc_avl_add(avl, box(198), box(1116), nullptr);
+  avl = remove_int(avl, 750);
+  avl = grpc_avl_add(avl, box(98), box(1118), nullptr);
+  avl = remove_int(avl, 943);
+  avl = grpc_avl_add(avl, box(254), box(1120), nullptr);
+  avl = grpc_avl_add(avl, box(30), box(1121), nullptr);
+  avl = remove_int(avl, 14);
+  avl = remove_int(avl, 475);
+  avl = remove_int(avl, 82);
+  avl = grpc_avl_add(avl, box(789), box(1125), nullptr);
+  avl = grpc_avl_add(avl, box(402), box(1126), nullptr);
+  avl = remove_int(avl, 1019);
+  avl = grpc_avl_add(avl, box(858), box(1128), nullptr);
+  avl = grpc_avl_add(avl, box(625), box(1129), nullptr);
+  avl = remove_int(avl, 675);
+  avl = remove_int(avl, 323);
+  avl = grpc_avl_add(avl, box(329), box(1132), nullptr);
+  avl = remove_int(avl, 929);
+  avl = remove_int(avl, 44);
+  avl = grpc_avl_add(avl, box(443), box(1135), nullptr);
+  avl = grpc_avl_add(avl, box(653), box(1136), nullptr);
+  avl = grpc_avl_add(avl, box(750), box(1137), nullptr);
+  avl = grpc_avl_add(avl, box(252), box(1138), nullptr);
+  avl = grpc_avl_add(avl, box(449), box(1139), nullptr);
+  avl = remove_int(avl, 1022);
+  avl = remove_int(avl, 357);
+  avl = remove_int(avl, 602);
+  avl = remove_int(avl, 131);
+  avl = grpc_avl_add(avl, box(531), box(1144), nullptr);
+  avl = remove_int(avl, 806);
+  avl = grpc_avl_add(avl, box(455), box(1146), nullptr);
+  avl = remove_int(avl, 31);
+  avl = grpc_avl_add(avl, box(154), box(1148), nullptr);
+  avl = grpc_avl_add(avl, box(189), box(1149), nullptr);
+  avl = remove_int(avl, 786);
+  avl = grpc_avl_add(avl, box(496), box(1151), nullptr);
+  avl = grpc_avl_add(avl, box(81), box(1152), nullptr);
+  avl = grpc_avl_add(avl, box(59), box(1153), nullptr);
+  avl = remove_int(avl, 424);
+  avl = remove_int(avl, 668);
+  avl = grpc_avl_add(avl, box(723), box(1156), nullptr);
+  avl = grpc_avl_add(avl, box(822), box(1157), nullptr);
+  avl = grpc_avl_add(avl, box(354), box(1158), nullptr);
+  avl = remove_int(avl, 738);
+  avl = grpc_avl_add(avl, box(686), box(1160), nullptr);
+  avl = grpc_avl_add(avl, box(43), box(1161), nullptr);
+  avl = grpc_avl_add(avl, box(625), box(1162), nullptr);
+  avl = grpc_avl_add(avl, box(902), box(1163), nullptr);
+  avl = grpc_avl_add(avl, box(12), box(1164), nullptr);
+  avl = grpc_avl_add(avl, box(977), box(1165), nullptr);
+  avl = grpc_avl_add(avl, box(699), box(1166), nullptr);
+  avl = grpc_avl_add(avl, box(189), box(1167), nullptr);
+  avl = remove_int(avl, 672);
+  avl = remove_int(avl, 90);
+  avl = remove_int(avl, 757);
+  avl = remove_int(avl, 494);
+  avl = grpc_avl_add(avl, box(759), box(1172), nullptr);
+  avl = remove_int(avl, 758);
+  avl = remove_int(avl, 222);
+  avl = grpc_avl_add(avl, box(975), box(1175), nullptr);
+  avl = remove_int(avl, 993);
+  avl = grpc_avl_add(avl, box(2), box(1177), nullptr);
+  avl = grpc_avl_add(avl, box(70), box(1178), nullptr);
+  avl = remove_int(avl, 350);
+  avl = remove_int(avl, 972);
+  avl = remove_int(avl, 880);
+  avl = grpc_avl_add(avl, box(753), box(1182), nullptr);
+  avl = remove_int(avl, 404);
+  avl = grpc_avl_add(avl, box(294), box(1184), nullptr);
+  avl = remove_int(avl, 474);
+  avl = grpc_avl_add(avl, box(228), box(1186), nullptr);
+  avl = grpc_avl_add(avl, box(484), box(1187), nullptr);
+  avl = remove_int(avl, 238);
+  avl = remove_int(avl, 53);
+  avl = remove_int(avl, 691);
+  avl = grpc_avl_add(avl, box(345), box(1191), nullptr);
+  avl = remove_int(avl, 0);
+  avl = grpc_avl_add(avl, box(230), box(1193), nullptr);
+  avl = remove_int(avl, 227);
+  avl = remove_int(avl, 152);
+  avl = grpc_avl_add(avl, box(884), box(1196), nullptr);
+  avl = remove_int(avl, 823);
+  avl = remove_int(avl, 53);
+  avl = grpc_avl_add(avl, box(1015), box(1199), nullptr);
+  avl = grpc_avl_add(avl, box(697), box(1200), nullptr);
+  avl = grpc_avl_add(avl, box(376), box(1201), nullptr);
+  avl = remove_int(avl, 411);
+  avl = grpc_avl_add(avl, box(888), box(1203), nullptr);
+  avl = remove_int(avl, 55);
+  avl = grpc_avl_add(avl, box(85), box(1205), nullptr);
+  avl = remove_int(avl, 947);
+  avl = remove_int(avl, 382);
+  avl = remove_int(avl, 777);
+  avl = grpc_avl_add(avl, box(1017), box(1209), nullptr);
+  avl = grpc_avl_add(avl, box(169), box(1210), nullptr);
+  avl = grpc_avl_add(avl, box(156), box(1211), nullptr);
+  avl = remove_int(avl, 153);
+  avl = remove_int(avl, 642);
+  avl = remove_int(avl, 158);
+  avl = grpc_avl_add(avl, box(554), box(1215), nullptr);
+  avl = grpc_avl_add(avl, box(76), box(1216), nullptr);
+  avl = grpc_avl_add(avl, box(756), box(1217), nullptr);
+  avl = remove_int(avl, 767);
+  avl = remove_int(avl, 112);
+  avl = remove_int(avl, 539);
+  avl = remove_int(avl, 544);
+  avl = remove_int(avl, 628);
+  avl = remove_int(avl, 385);
+  avl = remove_int(avl, 514);
+  avl = remove_int(avl, 362);
+  avl = grpc_avl_add(avl, box(523), box(1226), nullptr);
+  avl = grpc_avl_add(avl, box(712), box(1227), nullptr);
+  avl = grpc_avl_add(avl, box(474), box(1228), nullptr);
+  avl = grpc_avl_add(avl, box(882), box(1229), nullptr);
+  avl = grpc_avl_add(avl, box(965), box(1230), nullptr);
+  avl = remove_int(avl, 464);
+  avl = grpc_avl_add(avl, box(319), box(1232), nullptr);
+  avl = grpc_avl_add(avl, box(504), box(1233), nullptr);
+  avl = remove_int(avl, 818);
+  avl = grpc_avl_add(avl, box(884), box(1235), nullptr);
+  avl = grpc_avl_add(avl, box(813), box(1236), nullptr);
+  avl = grpc_avl_add(avl, box(795), box(1237), nullptr);
+  avl = remove_int(avl, 306);
+  avl = grpc_avl_add(avl, box(799), box(1239), nullptr);
+  avl = remove_int(avl, 534);
+  avl = grpc_avl_add(avl, box(480), box(1241), nullptr);
+  avl = grpc_avl_add(avl, box(656), box(1242), nullptr);
+  avl = grpc_avl_add(avl, box(709), box(1243), nullptr);
+  avl = grpc_avl_add(avl, box(500), box(1244), nullptr);
+  avl = remove_int(avl, 740);
+  avl = grpc_avl_add(avl, box(980), box(1246), nullptr);
+  avl = grpc_avl_add(avl, box(458), box(1247), nullptr);
+  avl = remove_int(avl, 377);
+  avl = remove_int(avl, 338);
+  avl = grpc_avl_add(avl, box(554), box(1250), nullptr);
+  avl = grpc_avl_add(avl, box(504), box(1251), nullptr);
+  avl = grpc_avl_add(avl, box(603), box(1252), nullptr);
+  avl = grpc_avl_add(avl, box(761), box(1253), nullptr);
+  avl = remove_int(avl, 431);
+  avl = grpc_avl_add(avl, box(707), box(1255), nullptr);
+  avl = grpc_avl_add(avl, box(673), box(1256), nullptr);
+  avl = remove_int(avl, 998);
+  avl = remove_int(avl, 332);
+  avl = remove_int(avl, 413);
+  avl = remove_int(avl, 227);
+  avl = remove_int(avl, 249);
+  avl = remove_int(avl, 309);
+  avl = remove_int(avl, 459);
+  avl = grpc_avl_add(avl, box(645), box(1264), nullptr);
+  avl = remove_int(avl, 858);
+  avl = remove_int(avl, 997);
+  avl = grpc_avl_add(avl, box(519), box(1267), nullptr);
+  avl = remove_int(avl, 614);
+  avl = remove_int(avl, 462);
+  avl = remove_int(avl, 792);
+  avl = grpc_avl_add(avl, box(987), box(1271), nullptr);
+  avl = grpc_avl_add(avl, box(309), box(1272), nullptr);
+  avl = remove_int(avl, 747);
+  avl = grpc_avl_add(avl, box(621), box(1274), nullptr);
+  avl = grpc_avl_add(avl, box(450), box(1275), nullptr);
+  avl = remove_int(avl, 265);
+  avl = remove_int(avl, 8);
+  avl = remove_int(avl, 383);
+  avl = grpc_avl_add(avl, box(238), box(1279), nullptr);
+  avl = remove_int(avl, 241);
+  avl = grpc_avl_add(avl, box(180), box(1281), nullptr);
+  avl = grpc_avl_add(avl, box(411), box(1282), nullptr);
+  avl = grpc_avl_add(avl, box(791), box(1283), nullptr);
+  avl = grpc_avl_add(avl, box(955), box(1284), nullptr);
+  avl = remove_int(avl, 24);
+  avl = remove_int(avl, 375);
+  avl = grpc_avl_add(avl, box(140), box(1287), nullptr);
+  avl = remove_int(avl, 949);
+  avl = grpc_avl_add(avl, box(301), box(1289), nullptr);
+  avl = grpc_avl_add(avl, box(0), box(1290), nullptr);
+  avl = remove_int(avl, 371);
+  avl = remove_int(avl, 427);
+  avl = remove_int(avl, 841);
+  avl = remove_int(avl, 847);
+  avl = grpc_avl_add(avl, box(814), box(1295), nullptr);
+  avl = grpc_avl_add(avl, box(127), box(1296), nullptr);
+  avl = grpc_avl_add(avl, box(279), box(1297), nullptr);
+  avl = remove_int(avl, 669);
+  avl = remove_int(avl, 541);
+  avl = remove_int(avl, 275);
+  avl = remove_int(avl, 299);
+  avl = remove_int(avl, 552);
+  avl = grpc_avl_add(avl, box(310), box(1303), nullptr);
+  avl = grpc_avl_add(avl, box(304), box(1304), nullptr);
+  avl = grpc_avl_add(avl, box(1), box(1305), nullptr);
+  avl = grpc_avl_add(avl, box(339), box(1306), nullptr);
+  avl = remove_int(avl, 570);
+  avl = remove_int(avl, 752);
+  avl = remove_int(avl, 552);
+  avl = remove_int(avl, 442);
+  avl = remove_int(avl, 639);
+  avl = grpc_avl_add(avl, box(313), box(1312), nullptr);
+  avl = remove_int(avl, 85);
+  avl = grpc_avl_add(avl, box(964), box(1314), nullptr);
+  avl = grpc_avl_add(avl, box(559), box(1315), nullptr);
+  avl = remove_int(avl, 167);
+  avl = grpc_avl_add(avl, box(866), box(1317), nullptr);
+  avl = remove_int(avl, 275);
+  avl = grpc_avl_add(avl, box(173), box(1319), nullptr);
+  avl = grpc_avl_add(avl, box(765), box(1320), nullptr);
+  avl = remove_int(avl, 883);
+  avl = grpc_avl_add(avl, box(547), box(1322), nullptr);
+  avl = grpc_avl_add(avl, box(847), box(1323), nullptr);
+  avl = remove_int(avl, 817);
+  avl = remove_int(avl, 850);
+  avl = remove_int(avl, 718);
+  avl = grpc_avl_add(avl, box(806), box(1327), nullptr);
+  avl = grpc_avl_add(avl, box(360), box(1328), nullptr);
+  avl = remove_int(avl, 991);
+  avl = grpc_avl_add(avl, box(493), box(1330), nullptr);
+  avl = remove_int(avl, 516);
+  avl = grpc_avl_add(avl, box(361), box(1332), nullptr);
+  avl = remove_int(avl, 355);
+  avl = grpc_avl_add(avl, box(512), box(1334), nullptr);
+  avl = grpc_avl_add(avl, box(191), box(1335), nullptr);
+  avl = remove_int(avl, 703);
+  avl = grpc_avl_add(avl, box(333), box(1337), nullptr);
+  avl = remove_int(avl, 481);
+  avl = grpc_avl_add(avl, box(501), box(1339), nullptr);
+  avl = remove_int(avl, 532);
+  avl = remove_int(avl, 510);
+  avl = grpc_avl_add(avl, box(793), box(1342), nullptr);
+  avl = grpc_avl_add(avl, box(234), box(1343), nullptr);
+  avl = remove_int(avl, 159);
+  avl = remove_int(avl, 429);
+  avl = remove_int(avl, 728);
+  avl = remove_int(avl, 288);
+  avl = grpc_avl_add(avl, box(281), box(1348), nullptr);
+  avl = grpc_avl_add(avl, box(702), box(1349), nullptr);
+  avl = grpc_avl_add(avl, box(149), box(1350), nullptr);
+  avl = remove_int(avl, 22);
+  avl = remove_int(avl, 944);
+  avl = remove_int(avl, 55);
+  avl = remove_int(avl, 512);
+  avl = remove_int(avl, 676);
+  avl = remove_int(avl, 884);
+  avl = grpc_avl_add(avl, box(246), box(1357), nullptr);
+  avl = grpc_avl_add(avl, box(455), box(1358), nullptr);
+  avl = remove_int(avl, 782);
+  avl = remove_int(avl, 682);
+  avl = grpc_avl_add(avl, box(243), box(1361), nullptr);
+  avl = grpc_avl_add(avl, box(109), box(1362), nullptr);
+  avl = grpc_avl_add(avl, box(452), box(1363), nullptr);
+  avl = remove_int(avl, 151);
+  avl = grpc_avl_add(avl, box(159), box(1365), nullptr);
+  avl = remove_int(avl, 1023);
+  avl = grpc_avl_add(avl, box(129), box(1367), nullptr);
+  avl = grpc_avl_add(avl, box(537), box(1368), nullptr);
+  avl = remove_int(avl, 321);
+  avl = grpc_avl_add(avl, box(740), box(1370), nullptr);
+  avl = remove_int(avl, 45);
+  avl = remove_int(avl, 136);
+  avl = grpc_avl_add(avl, box(229), box(1373), nullptr);
+  avl = remove_int(avl, 772);
+  avl = grpc_avl_add(avl, box(181), box(1375), nullptr);
+  avl = remove_int(avl, 175);
+  avl = grpc_avl_add(avl, box(817), box(1377), nullptr);
+  avl = remove_int(avl, 956);
+  avl = grpc_avl_add(avl, box(675), box(1379), nullptr);
+  avl = grpc_avl_add(avl, box(375), box(1380), nullptr);
+  avl = remove_int(avl, 384);
+  avl = grpc_avl_add(avl, box(1016), box(1382), nullptr);
+  avl = remove_int(avl, 295);
+  avl = remove_int(avl, 697);
+  avl = remove_int(avl, 554);
+  avl = remove_int(avl, 590);
+  avl = remove_int(avl, 1014);
+  avl = grpc_avl_add(avl, box(890), box(1388), nullptr);
+  avl = grpc_avl_add(avl, box(293), box(1389), nullptr);
+  avl = remove_int(avl, 207);
+  avl = remove_int(avl, 46);
+  avl = grpc_avl_add(avl, box(899), box(1392), nullptr);
+  avl = grpc_avl_add(avl, box(666), box(1393), nullptr);
+  avl = grpc_avl_add(avl, box(85), box(1394), nullptr);
+  avl = grpc_avl_add(avl, box(914), box(1395), nullptr);
+  avl = grpc_avl_add(avl, box(128), box(1396), nullptr);
+  avl = grpc_avl_add(avl, box(835), box(1397), nullptr);
+  avl = grpc_avl_add(avl, box(787), box(1398), nullptr);
+  avl = grpc_avl_add(avl, box(649), box(1399), nullptr);
+  avl = grpc_avl_add(avl, box(723), box(1400), nullptr);
+  avl = remove_int(avl, 874);
+  avl = grpc_avl_add(avl, box(778), box(1402), nullptr);
+  avl = grpc_avl_add(avl, box(1015), box(1403), nullptr);
+  avl = grpc_avl_add(avl, box(59), box(1404), nullptr);
+  avl = grpc_avl_add(avl, box(259), box(1405), nullptr);
+  avl = grpc_avl_add(avl, box(758), box(1406), nullptr);
+  avl = remove_int(avl, 648);
+  avl = grpc_avl_add(avl, box(145), box(1408), nullptr);
+  avl = grpc_avl_add(avl, box(440), box(1409), nullptr);
+  avl = remove_int(avl, 608);
+  avl = remove_int(avl, 690);
+  avl = grpc_avl_add(avl, box(605), box(1412), nullptr);
+  avl = remove_int(avl, 856);
+  avl = remove_int(avl, 608);
+  avl = grpc_avl_add(avl, box(829), box(1415), nullptr);
+  avl = grpc_avl_add(avl, box(660), box(1416), nullptr);
+  avl = remove_int(avl, 596);
+  avl = grpc_avl_add(avl, box(519), box(1418), nullptr);
+  avl = grpc_avl_add(avl, box(35), box(1419), nullptr);
+  avl = grpc_avl_add(avl, box(871), box(1420), nullptr);
+  avl = remove_int(avl, 845);
+  avl = grpc_avl_add(avl, box(600), box(1422), nullptr);
+  avl = grpc_avl_add(avl, box(215), box(1423), nullptr);
+  avl = remove_int(avl, 761);
+  avl = grpc_avl_add(avl, box(975), box(1425), nullptr);
+  avl = remove_int(avl, 987);
+  avl = grpc_avl_add(avl, box(58), box(1427), nullptr);
+  avl = remove_int(avl, 119);
+  avl = grpc_avl_add(avl, box(937), box(1429), nullptr);
+  avl = grpc_avl_add(avl, box(372), box(1430), nullptr);
+  avl = grpc_avl_add(avl, box(11), box(1431), nullptr);
+  avl = grpc_avl_add(avl, box(398), box(1432), nullptr);
+  avl = grpc_avl_add(avl, box(423), box(1433), nullptr);
+  avl = remove_int(avl, 171);
+  avl = grpc_avl_add(avl, box(473), box(1435), nullptr);
+  avl = remove_int(avl, 752);
+  avl = remove_int(avl, 625);
+  avl = remove_int(avl, 764);
+  avl = remove_int(avl, 49);
+  avl = grpc_avl_add(avl, box(472), box(1440), nullptr);
+  avl = remove_int(avl, 847);
+  avl = remove_int(avl, 642);
+  avl = remove_int(avl, 1004);
+  avl = remove_int(avl, 795);
+  avl = remove_int(avl, 465);
+  avl = grpc_avl_add(avl, box(636), box(1446), nullptr);
+  avl = remove_int(avl, 152);
+  avl = grpc_avl_add(avl, box(61), box(1448), nullptr);
+  avl = remove_int(avl, 929);
+  avl = remove_int(avl, 9);
+  avl = grpc_avl_add(avl, box(251), box(1451), nullptr);
+  avl = grpc_avl_add(avl, box(672), box(1452), nullptr);
+  avl = grpc_avl_add(avl, box(66), box(1453), nullptr);
+  avl = remove_int(avl, 693);
+  avl = remove_int(avl, 914);
+  avl = remove_int(avl, 116);
+  avl = remove_int(avl, 577);
+  avl = grpc_avl_add(avl, box(618), box(1458), nullptr);
+  avl = grpc_avl_add(avl, box(495), box(1459), nullptr);
+  avl = remove_int(avl, 450);
+  avl = grpc_avl_add(avl, box(533), box(1461), nullptr);
+  avl = grpc_avl_add(avl, box(414), box(1462), nullptr);
+  avl = remove_int(avl, 74);
+  avl = remove_int(avl, 236);
+  avl = grpc_avl_add(avl, box(707), box(1465), nullptr);
+  avl = grpc_avl_add(avl, box(357), box(1466), nullptr);
+  avl = grpc_avl_add(avl, box(1007), box(1467), nullptr);
+  avl = grpc_avl_add(avl, box(811), box(1468), nullptr);
+  avl = grpc_avl_add(avl, box(418), box(1469), nullptr);
+  avl = grpc_avl_add(avl, box(164), box(1470), nullptr);
+  avl = grpc_avl_add(avl, box(622), box(1471), nullptr);
+  avl = remove_int(avl, 22);
+  avl = remove_int(avl, 14);
+  avl = remove_int(avl, 732);
+  avl = remove_int(avl, 7);
+  avl = remove_int(avl, 447);
+  avl = grpc_avl_add(avl, box(221), box(1477), nullptr);
+  avl = grpc_avl_add(avl, box(202), box(1478), nullptr);
+  avl = grpc_avl_add(avl, box(312), box(1479), nullptr);
+  avl = remove_int(avl, 274);
+  avl = grpc_avl_add(avl, box(684), box(1481), nullptr);
+  avl = grpc_avl_add(avl, box(954), box(1482), nullptr);
+  avl = grpc_avl_add(avl, box(637), box(1483), nullptr);
+  avl = remove_int(avl, 716);
+  avl = grpc_avl_add(avl, box(198), box(1485), nullptr);
+  avl = remove_int(avl, 340);
+  avl = remove_int(avl, 137);
+  avl = remove_int(avl, 995);
+  avl = remove_int(avl, 1004);
+  avl = grpc_avl_add(avl, box(661), box(1490), nullptr);
+  avl = grpc_avl_add(avl, box(862), box(1491), nullptr);
+  avl = remove_int(avl, 527);
+  avl = grpc_avl_add(avl, box(945), box(1493), nullptr);
+  avl = remove_int(avl, 355);
+  avl = remove_int(avl, 144);
+  avl = grpc_avl_add(avl, box(229), box(1496), nullptr);
+  avl = grpc_avl_add(avl, box(237), box(1497), nullptr);
+  avl = remove_int(avl, 471);
+  avl = remove_int(avl, 901);
+  avl = grpc_avl_add(avl, box(905), box(1500), nullptr);
+  avl = remove_int(avl, 19);
+  avl = remove_int(avl, 896);
+  avl = remove_int(avl, 585);
+  avl = remove_int(avl, 308);
+  avl = grpc_avl_add(avl, box(547), box(1505), nullptr);
+  avl = grpc_avl_add(avl, box(552), box(1506), nullptr);
+  avl = grpc_avl_add(avl, box(30), box(1507), nullptr);
+  avl = grpc_avl_add(avl, box(445), box(1508), nullptr);
+  avl = remove_int(avl, 785);
+  avl = remove_int(avl, 185);
+  avl = grpc_avl_add(avl, box(405), box(1511), nullptr);
+  avl = grpc_avl_add(avl, box(733), box(1512), nullptr);
+  avl = grpc_avl_add(avl, box(573), box(1513), nullptr);
+  avl = grpc_avl_add(avl, box(492), box(1514), nullptr);
+  avl = grpc_avl_add(avl, box(343), box(1515), nullptr);
+  avl = grpc_avl_add(avl, box(527), box(1516), nullptr);
+  avl = grpc_avl_add(avl, box(596), box(1517), nullptr);
+  avl = grpc_avl_add(avl, box(519), box(1518), nullptr);
+  avl = remove_int(avl, 243);
+  avl = remove_int(avl, 722);
+  avl = grpc_avl_add(avl, box(772), box(1521), nullptr);
+  avl = remove_int(avl, 152);
+  avl = remove_int(avl, 305);
+  avl = grpc_avl_add(avl, box(754), box(1524), nullptr);
+  avl = grpc_avl_add(avl, box(373), box(1525), nullptr);
+  avl = remove_int(avl, 995);
+  avl = grpc_avl_add(avl, box(329), box(1527), nullptr);
+  avl = remove_int(avl, 397);
+  avl = grpc_avl_add(avl, box(884), box(1529), nullptr);
+  avl = remove_int(avl, 329);
+  avl = remove_int(avl, 240);
+  avl = grpc_avl_add(avl, box(566), box(1532), nullptr);
+  avl = grpc_avl_add(avl, box(232), box(1533), nullptr);
+  avl = remove_int(avl, 993);
+  avl = grpc_avl_add(avl, box(888), box(1535), nullptr);
+  avl = remove_int(avl, 242);
+  avl = grpc_avl_add(avl, box(941), box(1537), nullptr);
+  avl = remove_int(avl, 415);
+  avl = grpc_avl_add(avl, box(992), box(1539), nullptr);
+  avl = remove_int(avl, 289);
+  avl = grpc_avl_add(avl, box(60), box(1541), nullptr);
+  avl = grpc_avl_add(avl, box(97), box(1542), nullptr);
+  avl = remove_int(avl, 965);
+  avl = remove_int(avl, 267);
+  avl = remove_int(avl, 360);
+  avl = grpc_avl_add(avl, box(5), box(1546), nullptr);
+  avl = remove_int(avl, 429);
+  avl = grpc_avl_add(avl, box(412), box(1548), nullptr);
+  avl = remove_int(avl, 632);
+  avl = remove_int(avl, 113);
+  avl = grpc_avl_add(avl, box(48), box(1551), nullptr);
+  avl = grpc_avl_add(avl, box(108), box(1552), nullptr);
+  avl = grpc_avl_add(avl, box(750), box(1553), nullptr);
+  avl = remove_int(avl, 188);
+  avl = grpc_avl_add(avl, box(668), box(1555), nullptr);
+  avl = remove_int(avl, 37);
+  avl = remove_int(avl, 737);
+  avl = grpc_avl_add(avl, box(93), box(1558), nullptr);
+  avl = grpc_avl_add(avl, box(628), box(1559), nullptr);
+  avl = grpc_avl_add(avl, box(480), box(1560), nullptr);
+  avl = remove_int(avl, 958);
+  avl = remove_int(avl, 565);
+  avl = remove_int(avl, 32);
+  avl = remove_int(avl, 1);
+  avl = remove_int(avl, 335);
+  avl = grpc_avl_add(avl, box(136), box(1566), nullptr);
+  avl = grpc_avl_add(avl, box(469), box(1567), nullptr);
+  avl = remove_int(avl, 349);
+  avl = grpc_avl_add(avl, box(768), box(1569), nullptr);
+  avl = grpc_avl_add(avl, box(915), box(1570), nullptr);
+  avl = remove_int(avl, 1014);
+  avl = grpc_avl_add(avl, box(117), box(1572), nullptr);
+  avl = remove_int(avl, 62);
+  avl = grpc_avl_add(avl, box(382), box(1574), nullptr);
+  avl = remove_int(avl, 571);
+  avl = grpc_avl_add(avl, box(655), box(1576), nullptr);
+  avl = grpc_avl_add(avl, box(323), box(1577), nullptr);
+  avl = remove_int(avl, 869);
+  avl = remove_int(avl, 151);
+  avl = grpc_avl_add(avl, box(1019), box(1580), nullptr);
+  avl = grpc_avl_add(avl, box(984), box(1581), nullptr);
+  avl = grpc_avl_add(avl, box(870), box(1582), nullptr);
+  avl = grpc_avl_add(avl, box(376), box(1583), nullptr);
+  avl = remove_int(avl, 625);
+  avl = grpc_avl_add(avl, box(733), box(1585), nullptr);
+  avl = remove_int(avl, 532);
+  avl = remove_int(avl, 444);
+  avl = grpc_avl_add(avl, box(428), box(1588), nullptr);
+  avl = grpc_avl_add(avl, box(860), box(1589), nullptr);
+  avl = grpc_avl_add(avl, box(173), box(1590), nullptr);
+  avl = remove_int(avl, 649);
+  avl = remove_int(avl, 913);
+  avl = remove_int(avl, 1);
+  avl = remove_int(avl, 304);
+  avl = grpc_avl_add(avl, box(604), box(1595), nullptr);
+  avl = grpc_avl_add(avl, box(639), box(1596), nullptr);
+  avl = remove_int(avl, 431);
+  avl = grpc_avl_add(avl, box(993), box(1598), nullptr);
+  avl = remove_int(avl, 681);
+  avl = remove_int(avl, 927);
+  avl = grpc_avl_add(avl, box(87), box(1601), nullptr);
+  avl = grpc_avl_add(avl, box(91), box(1602), nullptr);
+  avl = remove_int(avl, 61);
+  avl = remove_int(avl, 14);
+  avl = remove_int(avl, 305);
+  avl = remove_int(avl, 304);
+  avl = remove_int(avl, 1016);
+  avl = grpc_avl_add(avl, box(903), box(1608), nullptr);
+  avl = grpc_avl_add(avl, box(951), box(1609), nullptr);
+  avl = grpc_avl_add(avl, box(146), box(1610), nullptr);
+  avl = grpc_avl_add(avl, box(482), box(1611), nullptr);
+  avl = grpc_avl_add(avl, box(71), box(1612), nullptr);
+  avl = remove_int(avl, 246);
+  avl = remove_int(avl, 696);
+  avl = grpc_avl_add(avl, box(636), box(1615), nullptr);
+  avl = grpc_avl_add(avl, box(295), box(1616), nullptr);
+  avl = remove_int(avl, 11);
+  avl = remove_int(avl, 231);
+  avl = grpc_avl_add(avl, box(905), box(1619), nullptr);
+  avl = grpc_avl_add(avl, box(993), box(1620), nullptr);
+  avl = grpc_avl_add(avl, box(433), box(1621), nullptr);
+  avl = grpc_avl_add(avl, box(117), box(1622), nullptr);
+  avl = grpc_avl_add(avl, box(467), box(1623), nullptr);
+  avl = remove_int(avl, 419);
+  avl = grpc_avl_add(avl, box(179), box(1625), nullptr);
+  avl = remove_int(avl, 926);
+  avl = remove_int(avl, 326);
+  avl = grpc_avl_add(avl, box(551), box(1628), nullptr);
+  avl = remove_int(avl, 14);
+  avl = remove_int(avl, 476);
+  avl = remove_int(avl, 823);
+  avl = grpc_avl_add(avl, box(350), box(1632), nullptr);
+  avl = grpc_avl_add(avl, box(133), box(1633), nullptr);
+  avl = remove_int(avl, 906);
+  avl = grpc_avl_add(avl, box(827), box(1635), nullptr);
+  avl = grpc_avl_add(avl, box(201), box(1636), nullptr);
+  avl = remove_int(avl, 124);
+  avl = remove_int(avl, 662);
+  avl = grpc_avl_add(avl, box(314), box(1639), nullptr);
+  avl = grpc_avl_add(avl, box(986), box(1640), nullptr);
+  avl = grpc_avl_add(avl, box(622), box(1641), nullptr);
+  avl = remove_int(avl, 130);
+  avl = grpc_avl_add(avl, box(861), box(1643), nullptr);
+  avl = remove_int(avl, 497);
+  avl = remove_int(avl, 905);
+  avl = grpc_avl_add(avl, box(502), box(1646), nullptr);
+  avl = remove_int(avl, 721);
+  avl = grpc_avl_add(avl, box(514), box(1648), nullptr);
+  avl = grpc_avl_add(avl, box(410), box(1649), nullptr);
+  avl = remove_int(avl, 869);
+  avl = remove_int(avl, 247);
+  avl = grpc_avl_add(avl, box(450), box(1652), nullptr);
+  avl = remove_int(avl, 364);
+  avl = grpc_avl_add(avl, box(963), box(1654), nullptr);
+  avl = grpc_avl_add(avl, box(146), box(1655), nullptr);
+  avl = remove_int(avl, 147);
+  avl = remove_int(avl, 789);
+  avl = grpc_avl_add(avl, box(693), box(1658), nullptr);
+  avl = grpc_avl_add(avl, box(959), box(1659), nullptr);
+  avl = remove_int(avl, 478);
+  avl = grpc_avl_add(avl, box(116), box(1661), nullptr);
+  avl = grpc_avl_add(avl, box(520), box(1662), nullptr);
+  avl = grpc_avl_add(avl, box(809), box(1663), nullptr);
+  avl = grpc_avl_add(avl, box(667), box(1664), nullptr);
+  avl = grpc_avl_add(avl, box(406), box(1665), nullptr);
+  avl = remove_int(avl, 409);
+  avl = grpc_avl_add(avl, box(558), box(1667), nullptr);
+  avl = grpc_avl_add(avl, box(0), box(1668), nullptr);
+  avl = grpc_avl_add(avl, box(948), box(1669), nullptr);
+  avl = grpc_avl_add(avl, box(576), box(1670), nullptr);
+  avl = remove_int(avl, 864);
+  avl = remove_int(avl, 840);
+  avl = remove_int(avl, 1001);
+  avl = grpc_avl_add(avl, box(232), box(1674), nullptr);
+  avl = remove_int(avl, 676);
+  avl = remove_int(avl, 752);
+  avl = remove_int(avl, 667);
+  avl = remove_int(avl, 605);
+  avl = grpc_avl_add(avl, box(258), box(1679), nullptr);
+  avl = grpc_avl_add(avl, box(648), box(1680), nullptr);
+  avl = grpc_avl_add(avl, box(761), box(1681), nullptr);
+  avl = remove_int(avl, 293);
+  avl = remove_int(avl, 893);
+  avl = grpc_avl_add(avl, box(194), box(1684), nullptr);
+  avl = remove_int(avl, 233);
+  avl = grpc_avl_add(avl, box(888), box(1686), nullptr);
+  avl = remove_int(avl, 470);
+  avl = remove_int(avl, 703);
+  avl = remove_int(avl, 190);
+  avl = remove_int(avl, 359);
+  avl = grpc_avl_add(avl, box(621), box(1691), nullptr);
+  avl = remove_int(avl, 634);
+  avl = remove_int(avl, 335);
+  avl = grpc_avl_add(avl, box(718), box(1694), nullptr);
+  avl = grpc_avl_add(avl, box(463), box(1695), nullptr);
+  avl = grpc_avl_add(avl, box(233), box(1696), nullptr);
+  avl = remove_int(avl, 376);
+  avl = remove_int(avl, 496);
+  avl = remove_int(avl, 819);
+  avl = remove_int(avl, 38);
+  avl = remove_int(avl, 436);
+  avl = remove_int(avl, 102);
+  avl = grpc_avl_add(avl, box(607), box(1703), nullptr);
+  avl = remove_int(avl, 329);
+  avl = grpc_avl_add(avl, box(716), box(1705), nullptr);
+  avl = remove_int(avl, 639);
+  avl = remove_int(avl, 775);
+  avl = remove_int(avl, 578);
+  avl = remove_int(avl, 464);
+  avl = remove_int(avl, 679);
+  avl = remove_int(avl, 615);
+  avl = remove_int(avl, 104);
+  avl = grpc_avl_add(avl, box(414), box(1713), nullptr);
+  avl = grpc_avl_add(avl, box(212), box(1714), nullptr);
+  avl = grpc_avl_add(avl, box(266), box(1715), nullptr);
+  avl = grpc_avl_add(avl, box(238), box(1716), nullptr);
+  avl = remove_int(avl, 153);
+  avl = grpc_avl_add(avl, box(585), box(1718), nullptr);
+  avl = remove_int(avl, 121);
+  avl = grpc_avl_add(avl, box(534), box(1720), nullptr);
+  avl = remove_int(avl, 579);
+  avl = grpc_avl_add(avl, box(127), box(1722), nullptr);
+  avl = grpc_avl_add(avl, box(399), box(1723), nullptr);
+  avl = remove_int(avl, 417);
+  avl = grpc_avl_add(avl, box(978), box(1725), nullptr);
+  avl = grpc_avl_add(avl, box(768), box(1726), nullptr);
+  avl = remove_int(avl, 985);
+  avl = grpc_avl_add(avl, box(536), box(1728), nullptr);
+  avl = grpc_avl_add(avl, box(449), box(1729), nullptr);
+  avl = grpc_avl_add(avl, box(586), box(1730), nullptr);
+  avl = remove_int(avl, 998);
+  avl = remove_int(avl, 394);
+  avl = remove_int(avl, 141);
+  avl = grpc_avl_add(avl, box(889), box(1734), nullptr);
+  avl = grpc_avl_add(avl, box(871), box(1735), nullptr);
+  avl = grpc_avl_add(avl, box(76), box(1736), nullptr);
+  avl = grpc_avl_add(avl, box(549), box(1737), nullptr);
+  avl = grpc_avl_add(avl, box(757), box(1738), nullptr);
+  avl = remove_int(avl, 908);
+  avl = grpc_avl_add(avl, box(789), box(1740), nullptr);
+  avl = remove_int(avl, 224);
+  avl = grpc_avl_add(avl, box(407), box(1742), nullptr);
+  avl = grpc_avl_add(avl, box(381), box(1743), nullptr);
+  avl = grpc_avl_add(avl, box(561), box(1744), nullptr);
+  avl = grpc_avl_add(avl, box(667), box(1745), nullptr);
+  avl = grpc_avl_add(avl, box(522), box(1746), nullptr);
+  avl = grpc_avl_add(avl, box(948), box(1747), nullptr);
+  avl = remove_int(avl, 770);
+  avl = grpc_avl_add(avl, box(872), box(1749), nullptr);
+  avl = grpc_avl_add(avl, box(327), box(1750), nullptr);
+  avl = remove_int(avl, 10);
+  avl = grpc_avl_add(avl, box(122), box(1752), nullptr);
+  avl = remove_int(avl, 606);
+  avl = grpc_avl_add(avl, box(485), box(1754), nullptr);
+  avl = remove_int(avl, 6);
+  avl = grpc_avl_add(avl, box(329), box(1756), nullptr);
+  avl = grpc_avl_add(avl, box(783), box(1757), nullptr);
+  avl = remove_int(avl, 416);
+  avl = grpc_avl_add(avl, box(656), box(1759), nullptr);
+  avl = grpc_avl_add(avl, box(971), box(1760), nullptr);
+  avl = grpc_avl_add(avl, box(77), box(1761), nullptr);
+  avl = grpc_avl_add(avl, box(942), box(1762), nullptr);
+  avl = remove_int(avl, 361);
+  avl = grpc_avl_add(avl, box(66), box(1764), nullptr);
+  avl = grpc_avl_add(avl, box(299), box(1765), nullptr);
+  avl = grpc_avl_add(avl, box(929), box(1766), nullptr);
+  avl = grpc_avl_add(avl, box(797), box(1767), nullptr);
+  avl = remove_int(avl, 869);
+  avl = remove_int(avl, 907);
+  avl = grpc_avl_add(avl, box(870), box(1770), nullptr);
+  avl = remove_int(avl, 580);
+  avl = remove_int(avl, 120);
+  avl = grpc_avl_add(avl, box(913), box(1773), nullptr);
+  avl = remove_int(avl, 480);
+  avl = grpc_avl_add(avl, box(489), box(1775), nullptr);
+  avl = remove_int(avl, 845);
+  avl = grpc_avl_add(avl, box(896), box(1777), nullptr);
+  avl = remove_int(avl, 567);
+  avl = remove_int(avl, 427);
+  avl = grpc_avl_add(avl, box(443), box(1780), nullptr);
+  avl = grpc_avl_add(avl, box(3), box(1781), nullptr);
+  avl = remove_int(avl, 12);
+  avl = grpc_avl_add(avl, box(376), box(1783), nullptr);
+  avl = grpc_avl_add(avl, box(155), box(1784), nullptr);
+  avl = grpc_avl_add(avl, box(188), box(1785), nullptr);
+  avl = grpc_avl_add(avl, box(149), box(1786), nullptr);
+  avl = grpc_avl_add(avl, box(178), box(1787), nullptr);
+  avl = remove_int(avl, 84);
+  avl = grpc_avl_add(avl, box(805), box(1789), nullptr);
+  avl = grpc_avl_add(avl, box(612), box(1790), nullptr);
+  avl = remove_int(avl, 991);
+  avl = grpc_avl_add(avl, box(837), box(1792), nullptr);
+  avl = remove_int(avl, 173);
+  avl = remove_int(avl, 72);
+  avl = grpc_avl_add(avl, box(1014), box(1795), nullptr);
+  avl = remove_int(avl, 303);
+  avl = grpc_avl_add(avl, box(865), box(1797), nullptr);
+  avl = grpc_avl_add(avl, box(793), box(1798), nullptr);
+  avl = remove_int(avl, 173);
+  avl = remove_int(avl, 477);
+  avl = grpc_avl_add(avl, box(950), box(1801), nullptr);
+  avl = grpc_avl_add(avl, box(105), box(1802), nullptr);
+  avl = grpc_avl_add(avl, box(895), box(1803), nullptr);
+  avl = grpc_avl_add(avl, box(171), box(1804), nullptr);
+  avl = grpc_avl_add(avl, box(753), box(1805), nullptr);
+  avl = grpc_avl_add(avl, box(946), box(1806), nullptr);
+  avl = remove_int(avl, 194);
+  avl = remove_int(avl, 559);
+  avl = remove_int(avl, 116);
+  avl = grpc_avl_add(avl, box(968), box(1810), nullptr);
+  avl = remove_int(avl, 124);
+  avl = remove_int(avl, 99);
+  avl = grpc_avl_add(avl, box(563), box(1813), nullptr);
+  avl = remove_int(avl, 182);
+  avl = grpc_avl_add(avl, box(816), box(1815), nullptr);
+  avl = remove_int(avl, 73);
+  avl = remove_int(avl, 261);
+  avl = grpc_avl_add(avl, box(847), box(1818), nullptr);
+  avl = grpc_avl_add(avl, box(368), box(1819), nullptr);
+  avl = grpc_avl_add(avl, box(808), box(1820), nullptr);
+  avl = grpc_avl_add(avl, box(779), box(1821), nullptr);
+  avl = remove_int(avl, 818);
+  avl = grpc_avl_add(avl, box(466), box(1823), nullptr);
+  avl = remove_int(avl, 316);
+  avl = grpc_avl_add(avl, box(986), box(1825), nullptr);
+  avl = grpc_avl_add(avl, box(688), box(1826), nullptr);
+  avl = grpc_avl_add(avl, box(509), box(1827), nullptr);
+  avl = grpc_avl_add(avl, box(51), box(1828), nullptr);
+  avl = remove_int(avl, 655);
+  avl = remove_int(avl, 785);
+  avl = remove_int(avl, 893);
+  avl = grpc_avl_add(avl, box(167), box(1832), nullptr);
+  avl = remove_int(avl, 13);
+  avl = remove_int(avl, 263);
+  avl = grpc_avl_add(avl, box(1009), box(1835), nullptr);
+  avl = remove_int(avl, 480);
+  avl = remove_int(avl, 778);
+  avl = remove_int(avl, 713);
+  avl = remove_int(avl, 628);
+  avl = grpc_avl_add(avl, box(803), box(1840), nullptr);
+  avl = remove_int(avl, 267);
+  avl = grpc_avl_add(avl, box(676), box(1842), nullptr);
+  avl = grpc_avl_add(avl, box(231), box(1843), nullptr);
+  avl = grpc_avl_add(avl, box(824), box(1844), nullptr);
+  avl = remove_int(avl, 961);
+  avl = grpc_avl_add(avl, box(311), box(1846), nullptr);
+  avl = grpc_avl_add(avl, box(420), box(1847), nullptr);
+  avl = grpc_avl_add(avl, box(960), box(1848), nullptr);
+  avl = grpc_avl_add(avl, box(468), box(1849), nullptr);
+  avl = grpc_avl_add(avl, box(815), box(1850), nullptr);
+  avl = remove_int(avl, 247);
+  avl = remove_int(avl, 194);
+  avl = grpc_avl_add(avl, box(546), box(1853), nullptr);
+  avl = remove_int(avl, 222);
+  avl = remove_int(avl, 914);
+  avl = remove_int(avl, 741);
+  avl = grpc_avl_add(avl, box(470), box(1857), nullptr);
+  avl = grpc_avl_add(avl, box(933), box(1858), nullptr);
+  avl = grpc_avl_add(avl, box(97), box(1859), nullptr);
+  avl = remove_int(avl, 564);
+  avl = remove_int(avl, 295);
+  avl = grpc_avl_add(avl, box(864), box(1862), nullptr);
+  avl = remove_int(avl, 329);
+  avl = grpc_avl_add(avl, box(124), box(1864), nullptr);
+  avl = grpc_avl_add(avl, box(1000), box(1865), nullptr);
+  avl = grpc_avl_add(avl, box(228), box(1866), nullptr);
+  avl = grpc_avl_add(avl, box(187), box(1867), nullptr);
+  avl = remove_int(avl, 224);
+  avl = remove_int(avl, 306);
+  avl = remove_int(avl, 884);
+  avl = grpc_avl_add(avl, box(449), box(1871), nullptr);
+  avl = grpc_avl_add(avl, box(353), box(1872), nullptr);
+  avl = grpc_avl_add(avl, box(994), box(1873), nullptr);
+  avl = grpc_avl_add(avl, box(596), box(1874), nullptr);
+  avl = grpc_avl_add(avl, box(996), box(1875), nullptr);
+  avl = grpc_avl_add(avl, box(101), box(1876), nullptr);
+  avl = grpc_avl_add(avl, box(1012), box(1877), nullptr);
+  avl = grpc_avl_add(avl, box(982), box(1878), nullptr);
+  avl = grpc_avl_add(avl, box(742), box(1879), nullptr);
+  avl = remove_int(avl, 92);
+  avl = remove_int(avl, 1022);
+  avl = grpc_avl_add(avl, box(941), box(1882), nullptr);
+  avl = remove_int(avl, 742);
+  avl = remove_int(avl, 919);
+  avl = grpc_avl_add(avl, box(588), box(1885), nullptr);
+  avl = remove_int(avl, 221);
+  avl = grpc_avl_add(avl, box(356), box(1887), nullptr);
+  avl = grpc_avl_add(avl, box(932), box(1888), nullptr);
+  avl = remove_int(avl, 837);
+  avl = grpc_avl_add(avl, box(394), box(1890), nullptr);
+  avl = grpc_avl_add(avl, box(642), box(1891), nullptr);
+  avl = grpc_avl_add(avl, box(52), box(1892), nullptr);
+  avl = grpc_avl_add(avl, box(437), box(1893), nullptr);
+  avl = grpc_avl_add(avl, box(948), box(1894), nullptr);
+  avl = grpc_avl_add(avl, box(93), box(1895), nullptr);
+  avl = remove_int(avl, 873);
+  avl = remove_int(avl, 336);
+  avl = remove_int(avl, 277);
+  avl = remove_int(avl, 932);
+  avl = grpc_avl_add(avl, box(80), box(1900), nullptr);
+  avl = grpc_avl_add(avl, box(952), box(1901), nullptr);
+  avl = grpc_avl_add(avl, box(510), box(1902), nullptr);
+  avl = remove_int(avl, 876);
+  avl = remove_int(avl, 612);
+  avl = grpc_avl_add(avl, box(923), box(1905), nullptr);
+  avl = grpc_avl_add(avl, box(475), box(1906), nullptr);
+  avl = remove_int(avl, 478);
+  avl = remove_int(avl, 148);
+  avl = grpc_avl_add(avl, box(538), box(1909), nullptr);
+  avl = remove_int(avl, 47);
+  avl = grpc_avl_add(avl, box(89), box(1911), nullptr);
+  avl = remove_int(avl, 723);
+  avl = grpc_avl_add(avl, box(687), box(1913), nullptr);
+  avl = grpc_avl_add(avl, box(480), box(1914), nullptr);
+  avl = grpc_avl_add(avl, box(149), box(1915), nullptr);
+  avl = remove_int(avl, 68);
+  avl = remove_int(avl, 862);
+  avl = remove_int(avl, 363);
+  avl = grpc_avl_add(avl, box(996), box(1919), nullptr);
+  avl = remove_int(avl, 380);
+  avl = grpc_avl_add(avl, box(957), box(1921), nullptr);
+  avl = remove_int(avl, 413);
+  avl = grpc_avl_add(avl, box(360), box(1923), nullptr);
+  avl = grpc_avl_add(avl, box(304), box(1924), nullptr);
+  avl = grpc_avl_add(avl, box(634), box(1925), nullptr);
+  avl = grpc_avl_add(avl, box(506), box(1926), nullptr);
+  avl = remove_int(avl, 248);
+  avl = grpc_avl_add(avl, box(124), box(1928), nullptr);
+  avl = grpc_avl_add(avl, box(181), box(1929), nullptr);
+  avl = remove_int(avl, 507);
+  avl = grpc_avl_add(avl, box(141), box(1931), nullptr);
+  avl = remove_int(avl, 409);
+  avl = remove_int(avl, 129);
+  avl = remove_int(avl, 694);
+  avl = remove_int(avl, 723);
+  avl = grpc_avl_add(avl, box(998), box(1936), nullptr);
+  avl = grpc_avl_add(avl, box(906), box(1937), nullptr);
+  avl = grpc_avl_add(avl, box(44), box(1938), nullptr);
+  avl = remove_int(avl, 949);
+  avl = remove_int(avl, 117);
+  avl = grpc_avl_add(avl, box(700), box(1941), nullptr);
+  avl = grpc_avl_add(avl, box(258), box(1942), nullptr);
+  avl = remove_int(avl, 828);
+  avl = grpc_avl_add(avl, box(860), box(1944), nullptr);
+  avl = grpc_avl_add(avl, box(987), box(1945), nullptr);
+  avl = grpc_avl_add(avl, box(316), box(1946), nullptr);
+  avl = grpc_avl_add(avl, box(919), box(1947), nullptr);
+  avl = remove_int(avl, 84);
+  avl = grpc_avl_add(avl, box(473), box(1949), nullptr);
+  avl = remove_int(avl, 127);
+  avl = remove_int(avl, 829);
+  avl = remove_int(avl, 829);
+  avl = grpc_avl_add(avl, box(488), box(1953), nullptr);
+  avl = grpc_avl_add(avl, box(954), box(1954), nullptr);
+  avl = remove_int(avl, 198);
+  avl = remove_int(avl, 972);
+  avl = remove_int(avl, 670);
+  avl = grpc_avl_add(avl, box(822), box(1958), nullptr);
+  avl = remove_int(avl, 589);
+  avl = remove_int(avl, 459);
+  avl = grpc_avl_add(avl, box(1003), box(1961), nullptr);
+  avl = grpc_avl_add(avl, box(657), box(1962), nullptr);
+  avl = grpc_avl_add(avl, box(477), box(1963), nullptr);
+  avl = grpc_avl_add(avl, box(923), box(1964), nullptr);
+  avl = remove_int(avl, 496);
+  avl = remove_int(avl, 99);
+  avl = grpc_avl_add(avl, box(127), box(1967), nullptr);
+  avl = grpc_avl_add(avl, box(1013), box(1968), nullptr);
+  avl = grpc_avl_add(avl, box(778), box(1969), nullptr);
+  avl = remove_int(avl, 5);
+  avl = remove_int(avl, 990);
+  avl = remove_int(avl, 850);
+  avl = remove_int(avl, 160);
+  avl = remove_int(avl, 86);
+  avl = grpc_avl_add(avl, box(283), box(1975), nullptr);
+  avl = remove_int(avl, 278);
+  avl = remove_int(avl, 297);
+  avl = remove_int(avl, 137);
+  avl = remove_int(avl, 653);
+  avl = grpc_avl_add(avl, box(702), box(1980), nullptr);
+  avl = remove_int(avl, 63);
+  avl = remove_int(avl, 427);
+  avl = remove_int(avl, 706);
+  avl = remove_int(avl, 806);
+  avl = grpc_avl_add(avl, box(335), box(1985), nullptr);
+  avl = grpc_avl_add(avl, box(412), box(1986), nullptr);
+  avl = remove_int(avl, 766);
+  avl = remove_int(avl, 937);
+  avl = remove_int(avl, 886);
+  avl = remove_int(avl, 652);
+  avl = grpc_avl_add(avl, box(545), box(1991), nullptr);
+  avl = grpc_avl_add(avl, box(408), box(1992), nullptr);
+  avl = grpc_avl_add(avl, box(841), box(1993), nullptr);
+  avl = remove_int(avl, 593);
+  avl = grpc_avl_add(avl, box(582), box(1995), nullptr);
+  avl = grpc_avl_add(avl, box(597), box(1996), nullptr);
+  avl = remove_int(avl, 49);
+  avl = remove_int(avl, 835);
+  avl = grpc_avl_add(avl, box(417), box(1999), nullptr);
+  avl = grpc_avl_add(avl, box(191), box(2000), nullptr);
+  avl = remove_int(avl, 406);
+  avl = grpc_avl_add(avl, box(30), box(2002), nullptr);
+  avl = remove_int(avl, 841);
+  avl = remove_int(avl, 50);
+  avl = grpc_avl_add(avl, box(967), box(2005), nullptr);
+  avl = grpc_avl_add(avl, box(849), box(2006), nullptr);
+  avl = remove_int(avl, 608);
+  avl = grpc_avl_add(avl, box(306), box(2008), nullptr);
+  avl = remove_int(avl, 779);
+  avl = grpc_avl_add(avl, box(897), box(2010), nullptr);
+  avl = grpc_avl_add(avl, box(147), box(2011), nullptr);
+  avl = remove_int(avl, 982);
+  avl = grpc_avl_add(avl, box(470), box(2013), nullptr);
+  avl = remove_int(avl, 951);
+  avl = grpc_avl_add(avl, box(388), box(2015), nullptr);
+  avl = remove_int(avl, 616);
+  avl = remove_int(avl, 721);
+  avl = remove_int(avl, 942);
+  avl = remove_int(avl, 589);
+  avl = grpc_avl_add(avl, box(218), box(2020), nullptr);
+  avl = remove_int(avl, 671);
+  avl = grpc_avl_add(avl, box(1020), box(2022), nullptr);
+  avl = remove_int(avl, 277);
+  avl = grpc_avl_add(avl, box(681), box(2024), nullptr);
+  avl = grpc_avl_add(avl, box(179), box(2025), nullptr);
+  avl = grpc_avl_add(avl, box(370), box(2026), nullptr);
+  avl = grpc_avl_add(avl, box(0), box(2027), nullptr);
+  avl = remove_int(avl, 523);
+  avl = grpc_avl_add(avl, box(99), box(2029), nullptr);
+  avl = grpc_avl_add(avl, box(334), box(2030), nullptr);
+  avl = grpc_avl_add(avl, box(569), box(2031), nullptr);
+  avl = grpc_avl_add(avl, box(257), box(2032), nullptr);
+  avl = remove_int(avl, 572);
+  avl = grpc_avl_add(avl, box(805), box(2034), nullptr);
+  avl = grpc_avl_add(avl, box(143), box(2035), nullptr);
+  avl = grpc_avl_add(avl, box(670), box(2036), nullptr);
+  avl = remove_int(avl, 42);
+  avl = grpc_avl_add(avl, box(46), box(2038), nullptr);
+  avl = remove_int(avl, 970);
+  avl = grpc_avl_add(avl, box(353), box(2040), nullptr);
+  avl = remove_int(avl, 258);
+  avl = grpc_avl_add(avl, box(451), box(2042), nullptr);
+  avl = grpc_avl_add(avl, box(28), box(2043), nullptr);
+  avl = grpc_avl_add(avl, box(729), box(2044), nullptr);
+  avl = grpc_avl_add(avl, box(401), box(2045), nullptr);
+  avl = grpc_avl_add(avl, box(614), box(2046), nullptr);
+  avl = remove_int(avl, 990);
+  avl = remove_int(avl, 212);
+  avl = remove_int(avl, 22);
+  avl = remove_int(avl, 677);
+  avl = grpc_avl_add(avl, box(1016), box(2051), nullptr);
+  avl = grpc_avl_add(avl, box(980), box(2052), nullptr);
+  avl = grpc_avl_add(avl, box(990), box(2053), nullptr);
+  avl = grpc_avl_add(avl, box(355), box(2054), nullptr);
+  avl = remove_int(avl, 730);
+  avl = remove_int(avl, 37);
+  avl = grpc_avl_add(avl, box(407), box(2057), nullptr);
+  avl = grpc_avl_add(avl, box(222), box(2058), nullptr);
+  avl = grpc_avl_add(avl, box(439), box(2059), nullptr);
+  avl = grpc_avl_add(avl, box(563), box(2060), nullptr);
+  avl = remove_int(avl, 992);
+  avl = remove_int(avl, 786);
+  avl = grpc_avl_add(avl, box(1), box(2063), nullptr);
+  avl = grpc_avl_add(avl, box(473), box(2064), nullptr);
+  avl = grpc_avl_add(avl, box(992), box(2065), nullptr);
+  avl = remove_int(avl, 190);
+  avl = remove_int(avl, 450);
+  avl = remove_int(avl, 1020);
+  avl = remove_int(avl, 149);
+  avl = grpc_avl_add(avl, box(329), box(2070), nullptr);
+  avl = grpc_avl_add(avl, box(35), box(2071), nullptr);
+  avl = remove_int(avl, 843);
+  avl = grpc_avl_add(avl, box(855), box(2073), nullptr);
+  avl = remove_int(avl, 878);
+  avl = grpc_avl_add(avl, box(993), box(2075), nullptr);
+  avl = grpc_avl_add(avl, box(87), box(2076), nullptr);
+  avl = grpc_avl_add(avl, box(572), box(2077), nullptr);
+  avl = remove_int(avl, 896);
+  avl = grpc_avl_add(avl, box(849), box(2079), nullptr);
+  avl = remove_int(avl, 597);
+  avl = grpc_avl_add(avl, box(472), box(2081), nullptr);
+  avl = remove_int(avl, 778);
+  avl = remove_int(avl, 934);
+  avl = remove_int(avl, 314);
+  avl = grpc_avl_add(avl, box(101), box(2085), nullptr);
+  avl = remove_int(avl, 938);
+  avl = remove_int(avl, 1010);
+  avl = grpc_avl_add(avl, box(579), box(2088), nullptr);
+  avl = remove_int(avl, 798);
+  avl = remove_int(avl, 88);
+  avl = grpc_avl_add(avl, box(851), box(2091), nullptr);
+  avl = remove_int(avl, 705);
+  avl = grpc_avl_add(avl, box(26), box(2093), nullptr);
+  avl = remove_int(avl, 973);
+  avl = grpc_avl_add(avl, box(923), box(2095), nullptr);
+  avl = remove_int(avl, 668);
+  avl = grpc_avl_add(avl, box(310), box(2097), nullptr);
+  avl = grpc_avl_add(avl, box(269), box(2098), nullptr);
+  avl = remove_int(avl, 173);
+  avl = grpc_avl_add(avl, box(279), box(2100), nullptr);
+  avl = remove_int(avl, 203);
+  avl = grpc_avl_add(avl, box(411), box(2102), nullptr);
+  avl = remove_int(avl, 950);
+  avl = grpc_avl_add(avl, box(6), box(2104), nullptr);
+  avl = remove_int(avl, 400);
+  avl = remove_int(avl, 468);
+  avl = remove_int(avl, 271);
+  avl = grpc_avl_add(avl, box(627), box(2108), nullptr);
+  avl = remove_int(avl, 727);
+  avl = remove_int(avl, 148);
+  avl = remove_int(avl, 98);
+  avl = remove_int(avl, 997);
+  avl = remove_int(avl, 215);
+  avl = remove_int(avl, 628);
+  avl = remove_int(avl, 826);
+  avl = remove_int(avl, 664);
+  avl = grpc_avl_add(avl, box(76), box(2117), nullptr);
+  avl = remove_int(avl, 194);
+  avl = remove_int(avl, 18);
+  avl = grpc_avl_add(avl, box(727), box(2120), nullptr);
+  avl = remove_int(avl, 295);
+  avl = grpc_avl_add(avl, box(645), box(2122), nullptr);
+  avl = remove_int(avl, 321);
+  avl = remove_int(avl, 863);
+  avl = grpc_avl_add(avl, box(824), box(2125), nullptr);
+  avl = grpc_avl_add(avl, box(651), box(2126), nullptr);
+  avl = grpc_avl_add(avl, box(804), box(2127), nullptr);
+  avl = remove_int(avl, 307);
+  avl = grpc_avl_add(avl, box(867), box(2129), nullptr);
+  avl = remove_int(avl, 384);
+  avl = grpc_avl_add(avl, box(819), box(2131), nullptr);
+  avl = remove_int(avl, 674);
+  avl = grpc_avl_add(avl, box(76), box(2133), nullptr);
+  avl = remove_int(avl, 898);
+  avl = grpc_avl_add(avl, box(45), box(2135), nullptr);
+  avl = grpc_avl_add(avl, box(512), box(2136), nullptr);
+  avl = remove_int(avl, 773);
+  avl = remove_int(avl, 907);
+  avl = remove_int(avl, 382);
+  avl = remove_int(avl, 95);
+  avl = remove_int(avl, 734);
+  avl = remove_int(avl, 81);
+  avl = grpc_avl_add(avl, box(348), box(2143), nullptr);
+  avl = remove_int(avl, 509);
+  avl = remove_int(avl, 301);
+  avl = grpc_avl_add(avl, box(861), box(2146), nullptr);
+  avl = grpc_avl_add(avl, box(918), box(2147), nullptr);
+  avl = remove_int(avl, 992);
+  avl = grpc_avl_add(avl, box(356), box(2149), nullptr);
+  avl = remove_int(avl, 64);
+  avl = remove_int(avl, 444);
+  avl = remove_int(avl, 741);
+  avl = grpc_avl_add(avl, box(710), box(2153), nullptr);
+  avl = grpc_avl_add(avl, box(264), box(2154), nullptr);
+  avl = remove_int(avl, 347);
+  avl = remove_int(avl, 250);
+  avl = grpc_avl_add(avl, box(82), box(2157), nullptr);
+  avl = grpc_avl_add(avl, box(571), box(2158), nullptr);
+  avl = remove_int(avl, 721);
+  avl = remove_int(avl, 622);
+  avl = grpc_avl_add(avl, box(950), box(2161), nullptr);
+  avl = grpc_avl_add(avl, box(94), box(2162), nullptr);
+  avl = remove_int(avl, 970);
+  avl = grpc_avl_add(avl, box(815), box(2164), nullptr);
+  avl = remove_int(avl, 930);
+  avl = remove_int(avl, 703);
+  avl = grpc_avl_add(avl, box(432), box(2167), nullptr);
+  avl = remove_int(avl, 544);
+  avl = grpc_avl_add(avl, box(21), box(2169), nullptr);
+  avl = grpc_avl_add(avl, box(186), box(2170), nullptr);
+  avl = remove_int(avl, 143);
+  avl = grpc_avl_add(avl, box(425), box(2172), nullptr);
+  avl = remove_int(avl, 769);
+  avl = grpc_avl_add(avl, box(656), box(2174), nullptr);
+  avl = remove_int(avl, 29);
+  avl = grpc_avl_add(avl, box(464), box(2176), nullptr);
+  avl = remove_int(avl, 713);
+  avl = grpc_avl_add(avl, box(800), box(2178), nullptr);
+  avl = remove_int(avl, 621);
+  avl = grpc_avl_add(avl, box(962), box(2180), nullptr);
+  avl = remove_int(avl, 448);
+  avl = grpc_avl_add(avl, box(878), box(2182), nullptr);
+  avl = remove_int(avl, 39);
+  avl = remove_int(avl, 999);
+  avl = grpc_avl_add(avl, box(182), box(2185), nullptr);
+  avl = grpc_avl_add(avl, box(429), box(2186), nullptr);
+  avl = grpc_avl_add(avl, box(598), box(2187), nullptr);
+  avl = remove_int(avl, 551);
+  avl = grpc_avl_add(avl, box(827), box(2189), nullptr);
+  avl = grpc_avl_add(avl, box(809), box(2190), nullptr);
+  avl = remove_int(avl, 438);
+  avl = remove_int(avl, 811);
+  avl = grpc_avl_add(avl, box(808), box(2193), nullptr);
+  avl = grpc_avl_add(avl, box(788), box(2194), nullptr);
+  avl = remove_int(avl, 156);
+  avl = grpc_avl_add(avl, box(933), box(2196), nullptr);
+  avl = grpc_avl_add(avl, box(344), box(2197), nullptr);
+  avl = remove_int(avl, 460);
+  avl = grpc_avl_add(avl, box(161), box(2199), nullptr);
+  avl = grpc_avl_add(avl, box(444), box(2200), nullptr);
+  avl = remove_int(avl, 597);
+  avl = remove_int(avl, 668);
+  avl = grpc_avl_add(avl, box(703), box(2203), nullptr);
+  avl = remove_int(avl, 515);
+  avl = grpc_avl_add(avl, box(380), box(2205), nullptr);
+  avl = grpc_avl_add(avl, box(338), box(2206), nullptr);
+  avl = remove_int(avl, 550);
+  avl = remove_int(avl, 946);
+  avl = remove_int(avl, 714);
+  avl = remove_int(avl, 739);
+  avl = grpc_avl_add(avl, box(413), box(2211), nullptr);
+  avl = remove_int(avl, 450);
+  avl = grpc_avl_add(avl, box(411), box(2213), nullptr);
+  avl = grpc_avl_add(avl, box(117), box(2214), nullptr);
+  avl = grpc_avl_add(avl, box(322), box(2215), nullptr);
+  avl = grpc_avl_add(avl, box(915), box(2216), nullptr);
+  avl = grpc_avl_add(avl, box(410), box(2217), nullptr);
+  avl = grpc_avl_add(avl, box(66), box(2218), nullptr);
+  avl = remove_int(avl, 756);
+  avl = remove_int(avl, 596);
+  avl = grpc_avl_add(avl, box(882), box(2221), nullptr);
+  avl = grpc_avl_add(avl, box(930), box(2222), nullptr);
+  avl = grpc_avl_add(avl, box(36), box(2223), nullptr);
+  avl = remove_int(avl, 742);
+  avl = grpc_avl_add(avl, box(539), box(2225), nullptr);
+  avl = grpc_avl_add(avl, box(596), box(2226), nullptr);
+  avl = remove_int(avl, 82);
+  avl = remove_int(avl, 686);
+  avl = remove_int(avl, 933);
+  avl = remove_int(avl, 42);
+  avl = remove_int(avl, 340);
+  avl = grpc_avl_add(avl, box(126), box(2232), nullptr);
+  avl = grpc_avl_add(avl, box(493), box(2233), nullptr);
+  avl = grpc_avl_add(avl, box(839), box(2234), nullptr);
+  avl = remove_int(avl, 774);
+  avl = grpc_avl_add(avl, box(337), box(2236), nullptr);
+  avl = remove_int(avl, 322);
+  avl = grpc_avl_add(avl, box(16), box(2238), nullptr);
+  avl = remove_int(avl, 73);
+  avl = remove_int(avl, 85);
+  avl = remove_int(avl, 191);
+  avl = remove_int(avl, 541);
+  avl = grpc_avl_add(avl, box(704), box(2243), nullptr);
+  avl = remove_int(avl, 767);
+  avl = remove_int(avl, 1006);
+  avl = remove_int(avl, 844);
+  avl = remove_int(avl, 742);
+  avl = grpc_avl_add(avl, box(48), box(2248), nullptr);
+  avl = grpc_avl_add(avl, box(138), box(2249), nullptr);
+  avl = grpc_avl_add(avl, box(437), box(2250), nullptr);
+  avl = grpc_avl_add(avl, box(275), box(2251), nullptr);
+  avl = remove_int(avl, 520);
+  avl = grpc_avl_add(avl, box(1019), box(2253), nullptr);
+  avl = remove_int(avl, 955);
+  avl = grpc_avl_add(avl, box(270), box(2255), nullptr);
+  avl = remove_int(avl, 680);
+  avl = remove_int(avl, 698);
+  avl = grpc_avl_add(avl, box(735), box(2258), nullptr);
+  avl = grpc_avl_add(avl, box(400), box(2259), nullptr);
+  avl = remove_int(avl, 991);
+  avl = grpc_avl_add(avl, box(263), box(2261), nullptr);
+  avl = remove_int(avl, 704);
+  avl = grpc_avl_add(avl, box(757), box(2263), nullptr);
+  avl = remove_int(avl, 194);
+  avl = remove_int(avl, 616);
+  avl = remove_int(avl, 784);
+  avl = grpc_avl_add(avl, box(382), box(2267), nullptr);
+  avl = grpc_avl_add(avl, box(464), box(2268), nullptr);
+  avl = grpc_avl_add(avl, box(817), box(2269), nullptr);
+  avl = remove_int(avl, 445);
+  avl = grpc_avl_add(avl, box(412), box(2271), nullptr);
+  avl = remove_int(avl, 525);
+  avl = grpc_avl_add(avl, box(299), box(2273), nullptr);
+  avl = grpc_avl_add(avl, box(464), box(2274), nullptr);
+  avl = grpc_avl_add(avl, box(715), box(2275), nullptr);
+  avl = remove_int(avl, 58);
+  avl = remove_int(avl, 218);
+  avl = grpc_avl_add(avl, box(961), box(2278), nullptr);
+  avl = grpc_avl_add(avl, box(491), box(2279), nullptr);
+  avl = remove_int(avl, 846);
+  avl = grpc_avl_add(avl, box(762), box(2281), nullptr);
+  avl = remove_int(avl, 974);
+  avl = remove_int(avl, 887);
+  avl = grpc_avl_add(avl, box(498), box(2284), nullptr);
+  avl = remove_int(avl, 810);
+  avl = remove_int(avl, 743);
+  avl = remove_int(avl, 22);
+  avl = remove_int(avl, 284);
+  avl = grpc_avl_add(avl, box(482), box(2289), nullptr);
+  avl = grpc_avl_add(avl, box(1021), box(2290), nullptr);
+  avl = remove_int(avl, 155);
+  avl = remove_int(avl, 128);
+  avl = grpc_avl_add(avl, box(819), box(2293), nullptr);
+  avl = grpc_avl_add(avl, box(324), box(2294), nullptr);
+  avl = remove_int(avl, 196);
+  avl = remove_int(avl, 370);
+  avl = remove_int(avl, 753);
+  avl = remove_int(avl, 56);
+  avl = remove_int(avl, 735);
+  avl = grpc_avl_add(avl, box(272), box(2300), nullptr);
+  avl = grpc_avl_add(avl, box(474), box(2301), nullptr);
+  avl = grpc_avl_add(avl, box(719), box(2302), nullptr);
+  avl = grpc_avl_add(avl, box(236), box(2303), nullptr);
+  avl = remove_int(avl, 818);
+  avl = grpc_avl_add(avl, box(727), box(2305), nullptr);
+  avl = remove_int(avl, 892);
+  avl = remove_int(avl, 871);
+  avl = remove_int(avl, 231);
+  avl = grpc_avl_add(avl, box(62), box(2309), nullptr);
+  avl = grpc_avl_add(avl, box(953), box(2310), nullptr);
+  avl = remove_int(avl, 701);
+  avl = grpc_avl_add(avl, box(193), box(2312), nullptr);
+  avl = remove_int(avl, 619);
+  avl = remove_int(avl, 22);
+  avl = remove_int(avl, 804);
+  avl = remove_int(avl, 851);
+  avl = grpc_avl_add(avl, box(286), box(2317), nullptr);
+  avl = grpc_avl_add(avl, box(751), box(2318), nullptr);
+  avl = remove_int(avl, 525);
+  avl = grpc_avl_add(avl, box(217), box(2320), nullptr);
+  avl = remove_int(avl, 336);
+  avl = grpc_avl_add(avl, box(86), box(2322), nullptr);
+  avl = grpc_avl_add(avl, box(81), box(2323), nullptr);
+  avl = grpc_avl_add(avl, box(850), box(2324), nullptr);
+  avl = remove_int(avl, 872);
+  avl = grpc_avl_add(avl, box(402), box(2326), nullptr);
+  avl = grpc_avl_add(avl, box(54), box(2327), nullptr);
+  avl = grpc_avl_add(avl, box(980), box(2328), nullptr);
+  avl = grpc_avl_add(avl, box(845), box(2329), nullptr);
+  avl = remove_int(avl, 1004);
+  avl = remove_int(avl, 273);
+  avl = remove_int(avl, 879);
+  avl = grpc_avl_add(avl, box(354), box(2333), nullptr);
+  avl = grpc_avl_add(avl, box(58), box(2334), nullptr);
+  avl = grpc_avl_add(avl, box(127), box(2335), nullptr);
+  avl = remove_int(avl, 84);
+  avl = grpc_avl_add(avl, box(360), box(2337), nullptr);
+  avl = remove_int(avl, 648);
+  avl = remove_int(avl, 488);
+  avl = remove_int(avl, 585);
+  avl = remove_int(avl, 230);
+  avl = grpc_avl_add(avl, box(887), box(2342), nullptr);
+  avl = remove_int(avl, 558);
+  avl = remove_int(avl, 958);
+  avl = grpc_avl_add(avl, box(822), box(2345), nullptr);
+  avl = remove_int(avl, 1004);
+  avl = remove_int(avl, 747);
+  avl = grpc_avl_add(avl, box(631), box(2348), nullptr);
+  avl = grpc_avl_add(avl, box(442), box(2349), nullptr);
+  avl = remove_int(avl, 957);
+  avl = remove_int(avl, 964);
+  avl = grpc_avl_add(avl, box(10), box(2352), nullptr);
+  avl = remove_int(avl, 189);
+  avl = grpc_avl_add(avl, box(742), box(2354), nullptr);
+  avl = remove_int(avl, 108);
+  avl = grpc_avl_add(avl, box(1014), box(2356), nullptr);
+  avl = remove_int(avl, 266);
+  avl = remove_int(avl, 623);
+  avl = remove_int(avl, 697);
+  avl = grpc_avl_add(avl, box(180), box(2360), nullptr);
+  avl = remove_int(avl, 472);
+  avl = grpc_avl_add(avl, box(567), box(2362), nullptr);
+  avl = remove_int(avl, 1020);
+  avl = remove_int(avl, 273);
+  avl = grpc_avl_add(avl, box(864), box(2365), nullptr);
+  avl = grpc_avl_add(avl, box(1009), box(2366), nullptr);
+  avl = remove_int(avl, 224);
+  avl = remove_int(avl, 81);
+  avl = grpc_avl_add(avl, box(653), box(2369), nullptr);
+  avl = remove_int(avl, 67);
+  avl = remove_int(avl, 102);
+  avl = remove_int(avl, 76);
+  avl = remove_int(avl, 935);
+  avl = remove_int(avl, 169);
+  avl = remove_int(avl, 232);
+  avl = remove_int(avl, 79);
+  avl = grpc_avl_add(avl, box(509), box(2377), nullptr);
+  avl = remove_int(avl, 900);
+  avl = remove_int(avl, 822);
+  avl = remove_int(avl, 945);
+  avl = remove_int(avl, 356);
+  avl = grpc_avl_add(avl, box(443), box(2382), nullptr);
+  avl = grpc_avl_add(avl, box(925), box(2383), nullptr);
+  avl = remove_int(avl, 994);
+  avl = remove_int(avl, 324);
+  avl = grpc_avl_add(avl, box(291), box(2386), nullptr);
+  avl = remove_int(avl, 94);
+  avl = remove_int(avl, 795);
+  avl = remove_int(avl, 42);
+  avl = grpc_avl_add(avl, box(613), box(2390), nullptr);
+  avl = remove_int(avl, 289);
+  avl = grpc_avl_add(avl, box(980), box(2392), nullptr);
+  avl = remove_int(avl, 316);
+  avl = grpc_avl_add(avl, box(281), box(2394), nullptr);
+  avl = grpc_avl_add(avl, box(1006), box(2395), nullptr);
+  avl = remove_int(avl, 776);
+  avl = grpc_avl_add(avl, box(108), box(2397), nullptr);
+  avl = grpc_avl_add(avl, box(918), box(2398), nullptr);
+  avl = remove_int(avl, 721);
+  avl = remove_int(avl, 563);
+  avl = grpc_avl_add(avl, box(925), box(2401), nullptr);
+  avl = remove_int(avl, 448);
+  avl = remove_int(avl, 198);
+  avl = remove_int(avl, 1);
+  avl = grpc_avl_add(avl, box(160), box(2405), nullptr);
+  avl = remove_int(avl, 515);
+  avl = grpc_avl_add(avl, box(284), box(2407), nullptr);
+  avl = grpc_avl_add(avl, box(225), box(2408), nullptr);
+  avl = remove_int(avl, 304);
+  avl = grpc_avl_add(avl, box(714), box(2410), nullptr);
+  avl = grpc_avl_add(avl, box(708), box(2411), nullptr);
+  avl = grpc_avl_add(avl, box(624), box(2412), nullptr);
+  avl = remove_int(avl, 662);
+  avl = remove_int(avl, 825);
+  avl = remove_int(avl, 383);
+  avl = remove_int(avl, 381);
+  avl = grpc_avl_add(avl, box(194), box(2417), nullptr);
+  avl = remove_int(avl, 280);
+  avl = remove_int(avl, 25);
+  avl = remove_int(avl, 633);
+  avl = grpc_avl_add(avl, box(897), box(2421), nullptr);
+  avl = remove_int(avl, 636);
+  avl = remove_int(avl, 596);
+  avl = remove_int(avl, 757);
+  avl = remove_int(avl, 343);
+  avl = remove_int(avl, 162);
+  avl = remove_int(avl, 913);
+  avl = remove_int(avl, 843);
+  avl = remove_int(avl, 280);
+  avl = remove_int(avl, 911);
+  avl = grpc_avl_add(avl, box(1008), box(2431), nullptr);
+  avl = remove_int(avl, 948);
+  avl = remove_int(avl, 74);
+  avl = remove_int(avl, 571);
+  avl = grpc_avl_add(avl, box(486), box(2435), nullptr);
+  avl = grpc_avl_add(avl, box(285), box(2436), nullptr);
+  avl = remove_int(avl, 304);
+  avl = remove_int(avl, 516);
+  avl = grpc_avl_add(avl, box(758), box(2439), nullptr);
+  avl = grpc_avl_add(avl, box(776), box(2440), nullptr);
+  avl = remove_int(avl, 696);
+  avl = grpc_avl_add(avl, box(104), box(2442), nullptr);
+  avl = grpc_avl_add(avl, box(700), box(2443), nullptr);
+  avl = grpc_avl_add(avl, box(114), box(2444), nullptr);
+  avl = grpc_avl_add(avl, box(567), box(2445), nullptr);
+  avl = remove_int(avl, 620);
+  avl = grpc_avl_add(avl, box(270), box(2447), nullptr);
+  avl = remove_int(avl, 730);
+  avl = grpc_avl_add(avl, box(749), box(2449), nullptr);
+  avl = grpc_avl_add(avl, box(443), box(2450), nullptr);
+  avl = remove_int(avl, 457);
+  avl = grpc_avl_add(avl, box(571), box(2452), nullptr);
+  avl = grpc_avl_add(avl, box(626), box(2453), nullptr);
+  avl = remove_int(avl, 638);
+  avl = remove_int(avl, 313);
+
+  grpc_avl_unref(avl, nullptr);
+}
+
+static void test_stress(int amount_of_stress) {
+  int added[1024];
+  int i, j;
+  int deletions = 0;
+  grpc_avl avl;
+
+  unsigned seed = static_cast<unsigned>(time(nullptr));
+
+  gpr_log(GPR_DEBUG, "test_stress amount=%d seed=%u", amount_of_stress, seed);
+
+  srand(static_cast<unsigned>(time(nullptr)));
+  avl = grpc_avl_create(&int_int_vtable);
+
+  memset(added, 0, sizeof(added));
+
+  for (i = 1; deletions < amount_of_stress; i++) {
+    int idx = rand() % static_cast<int> GPR_ARRAY_SIZE(added);
+    GPR_ASSERT(i);
+    if (rand() < RAND_MAX / 2) {
+      added[idx] = i;
+      printf("avl = grpc_avl_add(avl, box(%d), box(%d), NULL); /* d=%d */\n",
+             idx, i, deletions);
+      avl = grpc_avl_add(avl, box(idx), box(i), nullptr);
+    } else {
+      deletions += (added[idx] != 0);
+      added[idx] = 0;
+      printf("avl = remove_int(avl, %d); /* d=%d */\n", idx, deletions);
+      avl = remove_int(avl, idx);
+    }
+    for (j = 0; j < static_cast<int> GPR_ARRAY_SIZE(added); j++) {
+      if (added[j] != 0) {
+        check_get(avl, j, added[j]);
+      } else {
+        check_negget(avl, j);
+      }
+    }
+  }
+
+  grpc_avl_unref(avl, nullptr);
+}
+
+int main(int argc, char* argv[]) {
+  grpc_test_init(argc, argv);
+
+  test_get();
+  test_ll();
+  test_lr();
+  test_rr();
+  test_rl();
+  test_unbalanced();
+  test_replace();
+  test_remove();
+  test_badcase1();
+  test_badcase2();
+  test_badcase3();
+  test_stress(10);
+
+  return 0;
+}
diff --git a/test/core/backoff/backoff_test.cc b/test/core/backoff/backoff_test.cc
index 2e61243..1998a83 100644
--- a/test/core/backoff/backoff_test.cc
+++ b/test/core/backoff/backoff_test.cc
@@ -21,7 +21,6 @@
 #include <algorithm>
 
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
 
 #include <gtest/gtest.h>
 #include "test/core/util/test_config.h"
@@ -144,10 +143,10 @@
   grpc_millis next = backoff.NextAttemptTime();
   EXPECT_EQ(next - grpc_core::ExecCtx::Get()->Now(), initial_backoff);
 
-  grpc_millis expected_next_lower_bound =
-      (grpc_millis)((double)current_backoff * (1 - jitter));
-  grpc_millis expected_next_upper_bound =
-      (grpc_millis)((double)current_backoff * (1 + jitter));
+  grpc_millis expected_next_lower_bound = static_cast<grpc_millis>(
+      static_cast<double>(current_backoff) * (1 - jitter));
+  grpc_millis expected_next_upper_bound = static_cast<grpc_millis>(
+      static_cast<double>(current_backoff) * (1 + jitter));
 
   for (int i = 0; i < 10000; i++) {
     next = backoff.NextAttemptTime();
@@ -156,12 +155,14 @@
     const grpc_millis timeout_millis = next - grpc_core::ExecCtx::Get()->Now();
     EXPECT_GE(timeout_millis, expected_next_lower_bound);
     EXPECT_LE(timeout_millis, expected_next_upper_bound);
-    current_backoff = std::min(
-        (grpc_millis)((double)current_backoff * multiplier), max_backoff);
-    expected_next_lower_bound =
-        (grpc_millis)((double)current_backoff * (1 - jitter));
-    expected_next_upper_bound =
-        (grpc_millis)((double)current_backoff * (1 + jitter));
+    current_backoff =
+        std::min(static_cast<grpc_millis>(static_cast<double>(current_backoff) *
+                                          multiplier),
+                 max_backoff);
+    expected_next_lower_bound = static_cast<grpc_millis>(
+        static_cast<double>(current_backoff) * (1 - jitter));
+    expected_next_upper_bound = static_cast<grpc_millis>(
+        static_cast<double>(current_backoff) * (1 + jitter));
   }
 }
 
diff --git a/test/core/bad_client/bad_client.cc b/test/core/bad_client/bad_client.cc
index df803d1..c03ebcf 100644
--- a/test/core/bad_client/bad_client.cc
+++ b/test/core/bad_client/bad_client.cc
@@ -23,13 +23,13 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
 
 #include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/gpr/murmur_hash.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/endpoint_pair.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/surface/completion_queue.h"
@@ -49,7 +49,7 @@
 
 /* Run the server side validator and set done_thd once done */
 static void thd_func(void* arg) {
-  thd_args* a = (thd_args*)arg;
+  thd_args* a = static_cast<thd_args*>(arg);
   if (a->validator != nullptr) {
     a->validator(a->server, a->cq, a->registered_method);
   }
@@ -58,12 +58,12 @@
 
 /* Sets the done_write event */
 static void set_done_write(void* arg, grpc_error* error) {
-  gpr_event* done_write = (gpr_event*)arg;
+  gpr_event* done_write = static_cast<gpr_event*>(arg);
   gpr_event_set(done_write, (void*)1);
 }
 
 static void server_setup_transport(void* ts, grpc_transport* transport) {
-  thd_args* a = (thd_args*)ts;
+  thd_args* a = static_cast<thd_args*>(ts);
   grpc_core::ExecCtx exec_ctx;
   grpc_server_setup_transport(a->server, transport, nullptr,
                               grpc_server_get_channel_args(a->server));
@@ -71,7 +71,7 @@
 
 /* Sets the read_done event */
 static void set_read_done(void* arg, grpc_error* error) {
-  gpr_event* read_done = (gpr_event*)arg;
+  gpr_event* read_done = static_cast<gpr_event*>(arg);
   gpr_event_set(read_done, (void*)1);
 }
 
@@ -220,11 +220,12 @@
   /* Check a ground truth */
   GPR_ASSERT(grpc_server_has_open_connections(a.server));
 
-  gpr_thd_id id;
   gpr_event_init(&a.done_thd);
   a.validator = server_validator;
   /* Start validator */
-  gpr_thd_new(&id, "grpc_bad_client", thd_func, &a, nullptr);
+
+  grpc_core::Thread server_validator_thd("grpc_bad_client", thd_func, &a);
+  server_validator_thd.Start();
   for (int i = 0; i < num_args; i++) {
     grpc_run_client_side_validator(&args[i], i == (num_args - 1) ? flags : 0,
                                    &sfd, client_cq);
@@ -234,6 +235,7 @@
 
   /* Shutdown. */
   shutdown_client(&sfd.client);
+  server_validator_thd.Join();
 
   shutdown_cq = grpc_completion_queue_create_for_pluck(nullptr);
   grpc_server_shutdown_and_notify(a.server, shutdown_cq, nullptr);
diff --git a/test/core/bad_client/gen_build_yaml.py b/test/core/bad_client/gen_build_yaml.py
index a8fd777..32afba5 100755
--- a/test/core/bad_client/gen_build_yaml.py
+++ b/test/core/bad_client/gen_build_yaml.py
@@ -27,6 +27,7 @@
 BAD_CLIENT_TESTS = {
     'badreq': default_test_options,
     'connection_prefix': default_test_options._replace(cpu_cost=0.2),
+    'duplicate_header': default_test_options,
     'headers': default_test_options._replace(cpu_cost=0.2),
     'initial_settings_frame': default_test_options._replace(cpu_cost=0.2),
     'head_of_line_blocking': default_test_options,
diff --git a/test/core/bad_client/generate_tests.bzl b/test/core/bad_client/generate_tests.bzl
index b595def..2769d5c 100755
--- a/test/core/bad_client/generate_tests.bzl
+++ b/test/core/bad_client/generate_tests.bzl
@@ -16,6 +16,7 @@
 
 """Generates the appropriate build.json data for all the bad_client tests."""
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_cc_library")
 
 def test_options():
   return struct()
@@ -25,6 +26,7 @@
 BAD_CLIENT_TESTS = {
     'badreq': test_options(),
     'connection_prefix': test_options(),
+    'duplicate_header': test_options(),
     'headers': test_options(),
     'initial_settings_frame': test_options(),
     'head_of_line_blocking': test_options(),
@@ -36,14 +38,14 @@
 }
 
 def grpc_bad_client_tests():
-  native.cc_library(
+  grpc_cc_library(
       name = 'bad_client_test',
       srcs = ['bad_client.cc'],
       hdrs = ['bad_client.h'],
       deps = ['//test/core/util:grpc_test_util', '//:grpc', '//:gpr', '//test/core/end2end:cq_verifier']
   )
   for t, topt in BAD_CLIENT_TESTS.items():
-    native.cc_test(
+    grpc_cc_test(
         name = '%s_bad_client_test' % t,
         srcs = ['tests/%s.cc' % t],
         deps = [':bad_client_test'],
diff --git a/test/core/bad_client/tests/duplicate_header.cc b/test/core/bad_client/tests/duplicate_header.cc
new file mode 100644
index 0000000..e3cae8b
--- /dev/null
+++ b/test/core/bad_client/tests/duplicate_header.cc
@@ -0,0 +1,136 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "test/core/bad_client/bad_client.h"
+
+#include <string.h>
+
+#include <grpc/grpc.h>
+
+#include "src/core/lib/surface/server.h"
+#include "test/core/end2end/cq_verifier.h"
+
+#define PFX_STR                      \
+  "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" \
+  "\x00\x00\x00\x04\x00\x00\x00\x00\x00" /* settings frame */
+
+#define HEADER_STR                                                         \
+  "\x00\x00\xc9\x01\x04\x00\x00\x00\x01" /* headers: generated from        \
+                                            simple_request.headers in this \
+                                            directory */                   \
+  "\x10\x05:path\x08/foo/bar"                                              \
+  "\x10\x07:scheme\x04http"                                                \
+  "\x10\x07:method\x04POST"                                                \
+  "\x10\x0a:authority\x09localhost"                                        \
+  "\x10\x0c"                                                               \
+  "content-type\x10"                                                       \
+  "application/grpc"                                                       \
+  "\x10\x14grpc-accept-encoding\x15"                                       \
+  "deflate,identity,gzip"                                                  \
+  "\x10\x02te\x08trailers"                                                 \
+  "\x10\x0auser-agent\"bad-client grpc-c/0.12.0.0 (linux)"
+
+#define PAYLOAD_STR                      \
+  "\x00\x00\x20\x00\x00\x00\x00\x00\x01" \
+  "\x00\x00\x00\x00"
+
+static void* tag(intptr_t t) { return (void*)t; }
+
+static void verifier(grpc_server* server, grpc_completion_queue* cq,
+                     void* registered_method) {
+  grpc_call_error error;
+  grpc_call* s;
+  grpc_call_details call_details;
+  grpc_byte_buffer* request_payload_recv = nullptr;
+  grpc_op* op;
+  grpc_op ops[6];
+  cq_verifier* cqv = cq_verifier_create(cq);
+  grpc_metadata_array request_metadata_recv;
+  int was_cancelled = 2;
+
+  grpc_call_details_init(&call_details);
+  grpc_metadata_array_init(&request_metadata_recv);
+
+  error = grpc_server_request_call(server, &s, &call_details,
+                                   &request_metadata_recv, cq, cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
+  cq_verify(cqv);
+
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.host, "localhost"));
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo/bar"));
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &request_payload_recv;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  cq_verify(cqv);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+  op->data.send_status_from_server.status_details = &status_details;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103),
+                                nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
+
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_call_unref(s);
+  cq_verifier_destroy(cqv);
+}
+
+int main(int argc, char** argv) {
+  grpc_test_init(argc, argv);
+  grpc_init();
+
+  /* Verify that sending multiple headers doesn't segfault */
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, nullptr,
+                           PFX_STR HEADER_STR HEADER_STR PAYLOAD_STR, 0);
+  GRPC_RUN_BAD_CLIENT_TEST(verifier, nullptr,
+                           PFX_STR HEADER_STR HEADER_STR HEADER_STR PAYLOAD_STR,
+                           0);
+  grpc_shutdown();
+  return 0;
+}
diff --git a/test/core/bad_client/tests/head_of_line_blocking.cc b/test/core/bad_client/tests/head_of_line_blocking.cc
index 8668e09..427db46 100644
--- a/test/core/bad_client/tests/head_of_line_blocking.cc
+++ b/test/core/bad_client/tests/head_of_line_blocking.cc
@@ -117,9 +117,9 @@
 
   addbuf(prefix, sizeof(prefix) - 1);
   for (i = 0; i < NUM_FRAMES; i++) {
-    uint8_t hdr[9] = {(uint8_t)(FRAME_SIZE >> 16),
-                      (uint8_t)(FRAME_SIZE >> 8),
-                      (uint8_t)FRAME_SIZE,
+    uint8_t hdr[9] = {static_cast<uint8_t>(FRAME_SIZE >> 16),
+                      static_cast<uint8_t>(FRAME_SIZE >> 8),
+                      static_cast<uint8_t>(FRAME_SIZE),
                       0,
                       0,
                       0,
diff --git a/test/core/bad_client/tests/window_overflow.cc b/test/core/bad_client/tests/window_overflow.cc
index fe6b05d..b552704 100644
--- a/test/core/bad_client/tests/window_overflow.cc
+++ b/test/core/bad_client/tests/window_overflow.cc
@@ -76,9 +76,10 @@
 
   addbuf(PFX_STR, sizeof(PFX_STR) - 1);
   for (i = 0; i < NUM_FRAMES; i++) {
-    uint8_t hdr[9] = {(uint8_t)(FRAME_SIZE >> 16),
-                      (uint8_t)(FRAME_SIZE >> 8),
-                      (uint8_t)FRAME_SIZE,
+    uint8_t hdr[9] = {static_cast<uint8_t>(FRAME_SIZE >> 16),
+                      static_cast<uint8_t>(FRAME_SIZE >> 8),
+                      static_cast<uint8_t>
+                          FRAME_SIZE,
                       0,
                       0,
                       0,
diff --git a/test/core/bad_ssl/bad_ssl_test.cc b/test/core/bad_ssl/bad_ssl_test.cc
index 8a7960b..e2ea754 100644
--- a/test/core/bad_ssl/bad_ssl_test.cc
+++ b/test/core/bad_ssl/bad_ssl_test.cc
@@ -22,14 +22,15 @@
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/subprocess.h>
+
 #include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
 #include "test/core/end2end/cq_verifier.h"
 #include "test/core/util/port.h"
+#include "test/core/util/subprocess.h"
 #include "test/core/util/test_config.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -126,7 +127,7 @@
   gpr_subprocess* svr;
   /* figure out where we are */
   if (lslash) {
-    memcpy(root, me, (size_t)(lslash - me));
+    memcpy(root, me, static_cast<size_t>(lslash - me));
     root[lslash - me] = 0;
   } else {
     strcpy(root, ".");
@@ -138,7 +139,7 @@
   tmp = lunder - 1;
   while (*tmp != '_') tmp--;
   tmp++;
-  memcpy(test, tmp, (size_t)(lunder - tmp));
+  memcpy(test, tmp, static_cast<size_t>(lunder - tmp));
   /* start the server */
   gpr_asprintf(&args[0], "%s/bad_ssl_%s_server%s", root, test,
                gpr_subprocess_binary_extension());
diff --git a/test/core/bad_ssl/generate_tests.bzl b/test/core/bad_ssl/generate_tests.bzl
index b7cb8f8..22e7d3a 100755
--- a/test/core/bad_ssl/generate_tests.bzl
+++ b/test/core/bad_ssl/generate_tests.bzl
@@ -13,6 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_cc_library", "grpc_cc_binary")
 
 def test_options():
   return struct()
@@ -22,16 +23,27 @@
 BAD_SSL_TESTS = ['cert', 'alpn']
 
 def grpc_bad_ssl_tests():
-  native.cc_library(
+  grpc_cc_library(
       name = 'bad_ssl_test_server',
       srcs = ['server_common.cc'],
       hdrs = ['server_common.h'],
-      deps = ['//test/core/util:grpc_test_util', '//:grpc', '//test/core/end2end:ssl_test_data']
+      deps = ['//test/core/util:grpc_test_util',
+              '//:grpc',
+              '//test/core/end2end:ssl_test_data']
   )
   for t in BAD_SSL_TESTS:
-    native.cc_test(
+    grpc_cc_binary(
         name = 'bad_ssl_%s_server' % t,
         srcs = ['servers/%s.cc' % t],
         deps = [':bad_ssl_test_server'],
     )
-
+    grpc_cc_test(
+        name = 'bad_ssl_%s_test' % t,
+        srcs = ['bad_ssl_test.cc'],
+        data = [':bad_ssl_%s_server' % t,
+                '//src/core/tsi/test_creds:badserver.key',
+                '//src/core/tsi/test_creds:badserver.pem',],
+        deps = ['//test/core/util:grpc_test_util',
+                '//:gpr',
+                '//test/core/end2end:cq_verifier'],
+    )
diff --git a/test/core/bad_ssl/server_common.cc b/test/core/bad_ssl/server_common.cc
index 08842b8..809539a 100644
--- a/test/core/bad_ssl/server_common.cc
+++ b/test/core/bad_ssl/server_common.cc
@@ -16,11 +16,11 @@
  *
  */
 
-#include <grpc/support/cmdline.h>
 #include <grpc/support/log.h>
 #include <signal.h>
 
 #include "test/core/bad_ssl/server_common.h"
+#include "test/core/util/cmdline.h"
 #include "test/core/util/test_config.h"
 
 /* Common server implementation details for all servers in servers/.
diff --git a/test/core/bad_ssl/servers/alpn.cc b/test/core/bad_ssl/servers/alpn.cc
index 23954d8..4a04178 100644
--- a/test/core/bad_ssl/servers/alpn.cc
+++ b/test/core/bad_ssl/servers/alpn.cc
@@ -21,9 +21,9 @@
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/ext/transport/chttp2/alpn/alpn.h"
+#include "src/core/lib/gpr/useful.h"
 #include "test/core/bad_ssl/server_common.h"
 #include "test/core/end2end/data/ssl_test_data.h"
 
diff --git a/test/core/bad_ssl/servers/cert.cc b/test/core/bad_ssl/servers/cert.cc
index a51dd34..0722d6b 100644
--- a/test/core/bad_ssl/servers/cert.cc
+++ b/test/core/bad_ssl/servers/cert.cc
@@ -21,7 +21,6 @@
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/iomgr/load_file.h"
 
@@ -46,8 +45,10 @@
   GPR_ASSERT(GRPC_LOG_IF_ERROR(
       "load_file",
       grpc_load_file("src/core/tsi/test_creds/badserver.key", 1, &key_slice)));
-  pem_key_cert_pair.private_key = (const char*)GRPC_SLICE_START_PTR(key_slice);
-  pem_key_cert_pair.cert_chain = (const char*)GRPC_SLICE_START_PTR(cert_slice);
+  pem_key_cert_pair.private_key =
+      reinterpret_cast<const char*> GRPC_SLICE_START_PTR(key_slice);
+  pem_key_cert_pair.cert_chain =
+      reinterpret_cast<const char*> GRPC_SLICE_START_PTR(cert_slice);
 
   ssl_creds = grpc_ssl_server_credentials_create(nullptr, &pem_key_cert_pair, 1,
                                                  0, nullptr);
diff --git a/test/core/channel/BUILD b/test/core/channel/BUILD
index 92f5907..6bf4fcd 100644
--- a/test/core/channel/BUILD
+++ b/test/core/channel/BUILD
@@ -53,3 +53,44 @@
         "//test/core/util:grpc_test_util",
     ],
 )
+
+grpc_cc_test(
+    name = "minimal_stack_is_minimal_test",
+    srcs = ["minimal_stack_is_minimal_test.cc"],
+    language = "C++",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+grpc_cc_test(
+    name = "channel_trace_test",
+    srcs = ["channel_trace_test.cc"],
+    language = "C++",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//:grpc++",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+        "//test/cpp/util:channel_trace_proto_helper",
+    ],
+    external_deps = [
+        "gtest",
+    ],
+)
+
+grpc_cc_test(
+    name = "status_util_test",
+    srcs = ["status_util_test.cc"],
+    language = "C++",
+    deps = [
+        "//:grpc",
+    ],
+    external_deps = [
+        "gtest",
+    ],
+)
diff --git a/test/core/channel/channel_args_test.cc b/test/core/channel/channel_args_test.cc
index 5b0a770..57ff737 100644
--- a/test/core/channel/channel_args_test.cc
+++ b/test/core/channel/channel_args_test.cc
@@ -19,9 +19,9 @@
 #include <string.h>
 
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "test/core/util/test_config.h"
 
@@ -62,8 +62,8 @@
   grpc_core::ExecCtx exec_ctx;
   grpc_channel_args* ch_args;
 
-  ch_args = grpc_channel_args_set_compression_algorithm(
-      nullptr, GRPC_COMPRESS_MESSAGE_GZIP);
+  ch_args =
+      grpc_channel_args_set_compression_algorithm(nullptr, GRPC_COMPRESS_GZIP);
   GPR_ASSERT(ch_args->num_args == 1);
   GPR_ASSERT(strcmp(ch_args->args[0].key,
                     GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM) == 0);
@@ -81,29 +81,30 @@
 
   ch_args = grpc_channel_args_copy_and_add(nullptr, nullptr, 0);
   /* by default, all enabled */
-  states_bitset =
-      (unsigned)grpc_channel_args_compression_algorithm_get_states(ch_args);
+  states_bitset = static_cast<unsigned>(
+      grpc_channel_args_compression_algorithm_get_states(ch_args));
 
   for (i = 0; i < GRPC_COMPRESS_ALGORITHMS_COUNT; i++) {
     GPR_ASSERT(GPR_BITGET(states_bitset, i));
   }
 
-  /* disable message/gzip and message/deflate and stream/gzip */
+  /* disable gzip and deflate and stream/gzip */
   ch_args_wo_gzip = grpc_channel_args_compression_algorithm_set_state(
-      &ch_args, GRPC_COMPRESS_MESSAGE_GZIP, 0);
+      &ch_args, GRPC_COMPRESS_GZIP, 0);
   GPR_ASSERT(ch_args == ch_args_wo_gzip);
   ch_args_wo_gzip_deflate = grpc_channel_args_compression_algorithm_set_state(
-      &ch_args_wo_gzip, GRPC_COMPRESS_MESSAGE_DEFLATE, 0);
+      &ch_args_wo_gzip, GRPC_COMPRESS_DEFLATE, 0);
   GPR_ASSERT(ch_args_wo_gzip == ch_args_wo_gzip_deflate);
   ch_args_wo_gzip_deflate_gzip =
       grpc_channel_args_compression_algorithm_set_state(
           &ch_args_wo_gzip_deflate, GRPC_COMPRESS_STREAM_GZIP, 0);
   GPR_ASSERT(ch_args_wo_gzip_deflate == ch_args_wo_gzip_deflate_gzip);
 
-  states_bitset = (unsigned)grpc_channel_args_compression_algorithm_get_states(
-      ch_args_wo_gzip_deflate);
+  states_bitset =
+      static_cast<unsigned>(grpc_channel_args_compression_algorithm_get_states(
+          ch_args_wo_gzip_deflate));
   for (i = 0; i < GRPC_COMPRESS_ALGORITHMS_COUNT; i++) {
-    if (i == GRPC_COMPRESS_MESSAGE_GZIP || i == GRPC_COMPRESS_MESSAGE_DEFLATE ||
+    if (i == GRPC_COMPRESS_GZIP || i == GRPC_COMPRESS_DEFLATE ||
         i == GRPC_COMPRESS_STREAM_GZIP) {
       GPR_ASSERT(GPR_BITGET(states_bitset, i) == 0);
     } else {
@@ -111,17 +112,17 @@
     }
   }
 
-  /* re-enabled message/gzip and stream/gzip only */
+  /* re-enabled gzip and stream/gzip only */
   ch_args_wo_gzip = grpc_channel_args_compression_algorithm_set_state(
-      &ch_args_wo_gzip_deflate_gzip, GRPC_COMPRESS_MESSAGE_GZIP, 1);
+      &ch_args_wo_gzip_deflate_gzip, GRPC_COMPRESS_GZIP, 1);
   ch_args_wo_gzip = grpc_channel_args_compression_algorithm_set_state(
       &ch_args_wo_gzip, GRPC_COMPRESS_STREAM_GZIP, 1);
   GPR_ASSERT(ch_args_wo_gzip == ch_args_wo_gzip_deflate_gzip);
 
-  states_bitset = (unsigned)grpc_channel_args_compression_algorithm_get_states(
-      ch_args_wo_gzip);
+  states_bitset = static_cast<unsigned>(
+      grpc_channel_args_compression_algorithm_get_states(ch_args_wo_gzip));
   for (i = 0; i < GRPC_COMPRESS_ALGORITHMS_COUNT; i++) {
-    if (i == GRPC_COMPRESS_MESSAGE_DEFLATE) {
+    if (i == GRPC_COMPRESS_DEFLATE) {
       GPR_ASSERT(GPR_BITGET(states_bitset, i) == 0);
     } else {
       GPR_ASSERT(GPR_BITGET(states_bitset, i) != 0);
diff --git a/test/core/channel/channel_stack_builder_test.cc b/test/core/channel/channel_stack_builder_test.cc
index ef6db81..aad6d6e 100644
--- a/test/core/channel/channel_stack_builder_test.cc
+++ b/test/core/channel/channel_stack_builder_test.cc
@@ -116,7 +116,7 @@
 static bool add_original_filter(grpc_channel_stack_builder* builder,
                                 void* arg) {
   return grpc_channel_stack_builder_prepend_filter(
-      builder, (const grpc_channel_filter*)arg, set_arg_once_fn,
+      builder, static_cast<const grpc_channel_filter*>(arg), set_arg_once_fn,
       &g_original_fn_called);
 }
 
diff --git a/test/core/channel/channel_stack_test.cc b/test/core/channel/channel_stack_test.cc
index ef43fac..2f5329a 100644
--- a/test/core/channel/channel_stack_test.cc
+++ b/test/core/channel/channel_stack_test.cc
@@ -35,14 +35,14 @@
   GPR_ASSERT(args->channel_args->args[0].value.integer == 42);
   GPR_ASSERT(args->is_first);
   GPR_ASSERT(args->is_last);
-  *(int*)(elem->channel_data) = 0;
+  *static_cast<int*>(elem->channel_data) = 0;
   return GRPC_ERROR_NONE;
 }
 
 static grpc_error* call_init_func(grpc_call_element* elem,
                                   const grpc_call_element_args* args) {
-  ++*(int*)(elem->channel_data);
-  *(int*)(elem->call_data) = 0;
+  ++*static_cast<int*>(elem->channel_data);
+  *static_cast<int*>(elem->call_data) = 0;
   return GRPC_ERROR_NONE;
 }
 
@@ -51,16 +51,16 @@
 static void call_destroy_func(grpc_call_element* elem,
                               const grpc_call_final_info* final_info,
                               grpc_closure* ignored) {
-  ++*(int*)(elem->channel_data);
+  ++*static_cast<int*>(elem->channel_data);
 }
 
 static void call_func(grpc_call_element* elem,
                       grpc_transport_stream_op_batch* op) {
-  ++*(int*)(elem->call_data);
+  ++*static_cast<int*>(elem->call_data);
 }
 
 static void channel_func(grpc_channel_element* elem, grpc_transport_op* op) {
-  ++*(int*)(elem->channel_data);
+  ++*static_cast<int*>(elem->channel_data);
 }
 
 static void free_channel(void* arg, grpc_error* error) {
@@ -111,7 +111,7 @@
                           &chan_args, nullptr, "test", channel_stack);
   GPR_ASSERT(channel_stack->count == 1);
   channel_elem = grpc_channel_stack_element(channel_stack, 0);
-  channel_data = (int*)channel_elem->channel_data;
+  channel_data = static_cast<int*>(channel_elem->channel_data);
   GPR_ASSERT(*channel_data == 0);
 
   call_stack =
@@ -133,7 +133,7 @@
   call_elem = grpc_call_stack_element(call_stack, 0);
   GPR_ASSERT(call_elem->filter == channel_elem->filter);
   GPR_ASSERT(call_elem->channel_data == channel_elem->channel_data);
-  call_data = (int*)call_elem->call_data;
+  call_data = static_cast<int*>(call_elem->call_data);
   GPR_ASSERT(*call_data == 0);
   GPR_ASSERT(*channel_data == 1);
 
diff --git a/test/core/channel/channel_trace_test.cc b/test/core/channel/channel_trace_test.cc
new file mode 100644
index 0000000..3c73e33
--- /dev/null
+++ b/test/core/channel/channel_trace_test.cc
@@ -0,0 +1,240 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <gtest/gtest.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/channel/channel_trace.h"
+#include "src/core/lib/channel/channel_trace_registry.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/json/json.h"
+
+#include "test/core/util/test_config.h"
+#include "test/cpp/util/channel_trace_proto_helper.h"
+
+// remove me
+#include <grpc/support/string_util.h>
+#include <stdlib.h>
+#include <string.h>
+
+namespace grpc_core {
+namespace testing {
+namespace {
+
+grpc_json* GetJsonChild(grpc_json* parent, const char* key) {
+  EXPECT_NE(parent, nullptr);
+  for (grpc_json* child = parent->child; child != nullptr;
+       child = child->next) {
+    if (child->key != nullptr && strcmp(child->key, key) == 0) return child;
+  }
+  return nullptr;
+}
+
+void ValidateJsonArraySize(grpc_json* json, const char* key,
+                           size_t expected_size) {
+  grpc_json* arr = GetJsonChild(json, key);
+  ASSERT_NE(arr, nullptr);
+  ASSERT_EQ(arr->type, GRPC_JSON_ARRAY);
+  size_t count = 0;
+  for (grpc_json* child = arr->child; child != nullptr; child = child->next) {
+    ++count;
+  }
+  ASSERT_EQ(count, expected_size);
+}
+
+void ValidateChannelTraceData(grpc_json* json,
+                              size_t num_events_logged_expected,
+                              size_t actual_num_events_expected) {
+  ASSERT_NE(json, nullptr);
+  grpc_json* num_events_logged_json = GetJsonChild(json, "numEventsLogged");
+  ASSERT_NE(num_events_logged_json, nullptr);
+  grpc_json* start_time = GetJsonChild(json, "creationTime");
+  ASSERT_NE(start_time, nullptr);
+  size_t num_events_logged =
+      (size_t)strtol(num_events_logged_json->value, nullptr, 0);
+  ASSERT_EQ(num_events_logged, num_events_logged_expected);
+  ValidateJsonArraySize(json, "events", actual_num_events_expected);
+}
+
+void AddSimpleTrace(RefCountedPtr<ChannelTrace> tracer) {
+  tracer->AddTraceEvent(ChannelTrace::Severity::Info,
+                        grpc_slice_from_static_string("simple trace"));
+}
+
+// checks for the existence of all the required members of the tracer.
+void ValidateChannelTrace(RefCountedPtr<ChannelTrace> tracer,
+                          size_t expected_num_event_logged, size_t max_nodes) {
+  if (!max_nodes) return;
+  char* json_str = tracer->RenderTrace();
+  grpc::testing::ValidateChannelTraceProtoJsonTranslation(json_str);
+  grpc_json* json = grpc_json_parse_string(json_str);
+  ValidateChannelTraceData(json, expected_num_event_logged,
+                           GPR_MIN(expected_num_event_logged, max_nodes));
+  grpc_json_destroy(json);
+  gpr_free(json_str);
+}
+
+void ValidateTraceDataMatchedUuidLookup(RefCountedPtr<ChannelTrace> tracer) {
+  intptr_t uuid = tracer->GetUuid();
+  if (uuid == -1) return;  // Doesn't make sense to lookup if tracing disabled
+  char* tracer_json_str = tracer->RenderTrace();
+  ChannelTrace* uuid_lookup =
+      grpc_channel_trace_registry_get_channel_trace(uuid);
+  char* uuid_lookup_json_str = uuid_lookup->RenderTrace();
+  EXPECT_EQ(strcmp(tracer_json_str, uuid_lookup_json_str), 0);
+  gpr_free(tracer_json_str);
+  gpr_free(uuid_lookup_json_str);
+}
+
+}  // anonymous namespace
+
+class ChannelTracerTest : public ::testing::TestWithParam<size_t> {};
+
+// Tests basic ChannelTrace functionality like construction, adding trace, and
+// lookups by uuid.
+TEST_P(ChannelTracerTest, BasicTest) {
+  grpc_core::ExecCtx exec_ctx;
+  RefCountedPtr<ChannelTrace> tracer = MakeRefCounted<ChannelTrace>(GetParam());
+  AddSimpleTrace(tracer);
+  AddSimpleTrace(tracer);
+  ValidateTraceDataMatchedUuidLookup(tracer);
+  tracer->AddTraceEvent(ChannelTrace::Severity::Info,
+                        grpc_slice_from_static_string("trace three"));
+  tracer->AddTraceEvent(ChannelTrace::Severity::Error,
+                        grpc_slice_from_static_string("trace four error"));
+  ValidateChannelTrace(tracer, 4, GetParam());
+  AddSimpleTrace(tracer);
+  AddSimpleTrace(tracer);
+  ValidateChannelTrace(tracer, 6, GetParam());
+  AddSimpleTrace(tracer);
+  AddSimpleTrace(tracer);
+  AddSimpleTrace(tracer);
+  AddSimpleTrace(tracer);
+  ValidateChannelTrace(tracer, 10, GetParam());
+  ValidateTraceDataMatchedUuidLookup(tracer);
+  tracer.reset(nullptr);
+}
+
+// Tests more complex functionality, like a parent channel tracking
+// subchannles. This exercises the ref/unref patterns since the parent tracer
+// and this function will both hold refs to the subchannel.
+TEST_P(ChannelTracerTest, ComplexTest) {
+  grpc_core::ExecCtx exec_ctx;
+  RefCountedPtr<ChannelTrace> tracer = MakeRefCounted<ChannelTrace>(GetParam());
+  AddSimpleTrace(tracer);
+  AddSimpleTrace(tracer);
+  RefCountedPtr<ChannelTrace> sc1 = MakeRefCounted<ChannelTrace>(GetParam());
+  tracer->AddTraceEventReferencingSubchannel(
+      ChannelTrace::Severity::Info,
+      grpc_slice_from_static_string("subchannel one created"), sc1);
+  ValidateChannelTrace(tracer, 3, GetParam());
+  AddSimpleTrace(sc1);
+  AddSimpleTrace(sc1);
+  AddSimpleTrace(sc1);
+  ValidateChannelTrace(sc1, 3, GetParam());
+  AddSimpleTrace(sc1);
+  AddSimpleTrace(sc1);
+  AddSimpleTrace(sc1);
+  ValidateChannelTrace(sc1, 6, GetParam());
+  AddSimpleTrace(tracer);
+  AddSimpleTrace(tracer);
+  ValidateChannelTrace(tracer, 5, GetParam());
+  ValidateTraceDataMatchedUuidLookup(tracer);
+  RefCountedPtr<ChannelTrace> sc2 = MakeRefCounted<ChannelTrace>(GetParam());
+  tracer->AddTraceEventReferencingChannel(
+      ChannelTrace::Severity::Info,
+      grpc_slice_from_static_string("LB channel two created"), sc2);
+  tracer->AddTraceEventReferencingSubchannel(
+      ChannelTrace::Severity::Warning,
+      grpc_slice_from_static_string("subchannel one inactive"), sc1);
+  ValidateChannelTrace(tracer, 7, GetParam());
+  AddSimpleTrace(tracer);
+  AddSimpleTrace(tracer);
+  AddSimpleTrace(tracer);
+  AddSimpleTrace(tracer);
+  AddSimpleTrace(tracer);
+  AddSimpleTrace(tracer);
+  ValidateTraceDataMatchedUuidLookup(tracer);
+  tracer.reset(nullptr);
+  sc1.reset(nullptr);
+  sc2.reset(nullptr);
+}
+
+// Test a case in which the parent channel has subchannels and the subchannels
+// have connections. Ensures that everything lives as long as it should then
+// gets deleted.
+TEST_P(ChannelTracerTest, TestNesting) {
+  grpc_core::ExecCtx exec_ctx;
+  RefCountedPtr<ChannelTrace> tracer = MakeRefCounted<ChannelTrace>(GetParam());
+  AddSimpleTrace(tracer);
+  AddSimpleTrace(tracer);
+  ValidateChannelTrace(tracer, 2, GetParam());
+  RefCountedPtr<ChannelTrace> sc1 = MakeRefCounted<ChannelTrace>(GetParam());
+  tracer->AddTraceEventReferencingChannel(
+      ChannelTrace::Severity::Info,
+      grpc_slice_from_static_string("subchannel one created"), sc1);
+  ValidateChannelTrace(tracer, 3, GetParam());
+  AddSimpleTrace(sc1);
+  RefCountedPtr<ChannelTrace> conn1 = MakeRefCounted<ChannelTrace>(GetParam());
+  // nesting one level deeper.
+  sc1->AddTraceEventReferencingSubchannel(
+      ChannelTrace::Severity::Info,
+      grpc_slice_from_static_string("connection one created"), conn1);
+  ValidateChannelTrace(tracer, 3, GetParam());
+  AddSimpleTrace(conn1);
+  AddSimpleTrace(tracer);
+  AddSimpleTrace(tracer);
+  ValidateChannelTrace(tracer, 5, GetParam());
+  ValidateChannelTrace(conn1, 1, GetParam());
+  RefCountedPtr<ChannelTrace> sc2 = MakeRefCounted<ChannelTrace>(GetParam());
+  tracer->AddTraceEventReferencingSubchannel(
+      ChannelTrace::Severity::Info,
+      grpc_slice_from_static_string("subchannel two created"), sc2);
+  // this trace should not get added to the parents children since it is already
+  // present in the tracer.
+  tracer->AddTraceEventReferencingChannel(
+      ChannelTrace::Severity::Warning,
+      grpc_slice_from_static_string("subchannel one inactive"), sc1);
+  AddSimpleTrace(tracer);
+  ValidateChannelTrace(tracer, 8, GetParam());
+  tracer.reset(nullptr);
+  sc1.reset(nullptr);
+  sc2.reset(nullptr);
+  conn1.reset(nullptr);
+}
+
+INSTANTIATE_TEST_CASE_P(ChannelTracerTestSweep, ChannelTracerTest,
+                        ::testing::Values(0, 1, 2, 6, 10, 15));
+
+}  // namespace testing
+}  // namespace grpc_core
+
+int main(int argc, char** argv) {
+  grpc_test_init(argc, argv);
+  grpc_init();
+  ::testing::InitGoogleTest(&argc, argv);
+  int ret = RUN_ALL_TESTS();
+  grpc_shutdown();
+  return ret;
+}
diff --git a/test/core/channel/status_util_test.cc b/test/core/channel/status_util_test.cc
new file mode 100644
index 0000000..1d64bf1
--- /dev/null
+++ b/test/core/channel/status_util_test.cc
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/core/lib/channel/status_util.h"
+
+#include <gtest/gtest.h>
+
+namespace grpc_core {
+namespace internal {
+namespace {
+
+TEST(StatusCodeSet, Basic) {
+  StatusCodeSet set;
+  EXPECT_TRUE(set.Empty());
+  EXPECT_FALSE(set.Contains(GRPC_STATUS_OK));
+  EXPECT_FALSE(set.Contains(GRPC_STATUS_UNAVAILABLE));
+  set.Add(GRPC_STATUS_OK);
+  EXPECT_FALSE(set.Empty());
+  EXPECT_TRUE(set.Contains(GRPC_STATUS_OK));
+  EXPECT_FALSE(set.Contains(GRPC_STATUS_UNAVAILABLE));
+  set.Add(GRPC_STATUS_UNAVAILABLE);
+  EXPECT_FALSE(set.Empty());
+  EXPECT_TRUE(set.Contains(GRPC_STATUS_OK));
+  EXPECT_TRUE(set.Contains(GRPC_STATUS_UNAVAILABLE));
+}
+
+}  // namespace
+}  // namespace internal
+}  // namespace grpc_core
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/test/core/client_channel/BUILD b/test/core/client_channel/BUILD
index 890e03f..5148dc5 100644
--- a/test/core/client_channel/BUILD
+++ b/test/core/client_channel/BUILD
@@ -31,3 +31,25 @@
         "//test/core/util:grpc_test_util",
     ],
 )
+
+grpc_cc_test(
+    name = "parse_address_test",
+    srcs = ["parse_address_test.cc"],
+    language = "C++",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+grpc_cc_test(
+    name = "uri_parser_test",
+    srcs = ["uri_parser_test.cc"],
+    language = "C++",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:grpc_test_util",
+    ],
+)
diff --git a/test/core/client_channel/parse_address_test.cc b/test/core/client_channel/parse_address_test.cc
index 6d56961..ae157fb 100644
--- a/test/core/client_channel/parse_address_test.cc
+++ b/test/core/client_channel/parse_address_test.cc
@@ -18,6 +18,7 @@
 
 #include "src/core/ext/filters/client_channel/parse_address.h"
 #include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/iomgr/socket_utils.h"
 
 #include <string.h>
 #ifdef GRPC_HAVE_UNIX_SOCKET
@@ -39,7 +40,8 @@
   grpc_resolved_address addr;
 
   GPR_ASSERT(1 == grpc_parse_unix(uri, &addr));
-  struct sockaddr_un* addr_un = (struct sockaddr_un*)addr.addr;
+  struct sockaddr_un* addr_un =
+      reinterpret_cast<struct sockaddr_un*>(addr.addr);
   GPR_ASSERT(AF_UNIX == addr_un->sun_family);
   GPR_ASSERT(0 == strcmp(addr_un->sun_path, pathname));
 
@@ -57,15 +59,15 @@
   grpc_core::ExecCtx exec_ctx;
   grpc_uri* uri = grpc_uri_parse(uri_text, 0);
   grpc_resolved_address addr;
-  char ntop_buf[INET_ADDRSTRLEN];
+  char ntop_buf[GRPC_INET_ADDRSTRLEN];
 
   GPR_ASSERT(1 == grpc_parse_ipv4(uri, &addr));
-  struct sockaddr_in* addr_in = (struct sockaddr_in*)addr.addr;
-  GPR_ASSERT(AF_INET == addr_in->sin_family);
-  GPR_ASSERT(nullptr != grpc_inet_ntop(AF_INET, &addr_in->sin_addr, ntop_buf,
-                                       sizeof(ntop_buf)));
+  grpc_sockaddr_in* addr_in = reinterpret_cast<grpc_sockaddr_in*>(addr.addr);
+  GPR_ASSERT(GRPC_AF_INET == addr_in->sin_family);
+  GPR_ASSERT(nullptr != grpc_inet_ntop(GRPC_AF_INET, &addr_in->sin_addr,
+                                       ntop_buf, sizeof(ntop_buf)));
   GPR_ASSERT(0 == strcmp(ntop_buf, host));
-  GPR_ASSERT(ntohs(addr_in->sin_port) == port);
+  GPR_ASSERT(grpc_ntohs(addr_in->sin_port) == port);
 
   grpc_uri_destroy(uri);
 }
@@ -75,15 +77,15 @@
   grpc_core::ExecCtx exec_ctx;
   grpc_uri* uri = grpc_uri_parse(uri_text, 0);
   grpc_resolved_address addr;
-  char ntop_buf[INET6_ADDRSTRLEN];
+  char ntop_buf[GRPC_INET6_ADDRSTRLEN];
 
   GPR_ASSERT(1 == grpc_parse_ipv6(uri, &addr));
-  struct sockaddr_in6* addr_in6 = (struct sockaddr_in6*)addr.addr;
-  GPR_ASSERT(AF_INET6 == addr_in6->sin6_family);
-  GPR_ASSERT(nullptr != grpc_inet_ntop(AF_INET6, &addr_in6->sin6_addr, ntop_buf,
-                                       sizeof(ntop_buf)));
+  grpc_sockaddr_in6* addr_in6 = reinterpret_cast<grpc_sockaddr_in6*>(addr.addr);
+  GPR_ASSERT(GRPC_AF_INET6 == addr_in6->sin6_family);
+  GPR_ASSERT(nullptr != grpc_inet_ntop(GRPC_AF_INET6, &addr_in6->sin6_addr,
+                                       ntop_buf, sizeof(ntop_buf)));
   GPR_ASSERT(0 == strcmp(ntop_buf, host));
-  GPR_ASSERT(ntohs(addr_in6->sin6_port) == port);
+  GPR_ASSERT(grpc_ntohs(addr_in6->sin6_port) == port);
   GPR_ASSERT(addr_in6->sin6_scope_id == scope_id);
 
   grpc_uri_destroy(uri);
diff --git a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc
index 18a795f..e34aa2e 100644
--- a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc
+++ b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc
@@ -57,6 +57,9 @@
   GRPC_CLOSURE_SCHED(on_done, error);
 }
 
+static grpc_address_resolver_vtable test_resolver = {my_resolve_address,
+                                                     nullptr};
+
 static grpc_ares_request* my_dns_lookup_ares(
     const char* dns_server, const char* addr, const char* default_port,
     grpc_pollset_set* interested_parties, grpc_closure* on_done,
@@ -79,23 +82,23 @@
   return nullptr;
 }
 
-static grpc_resolver* create_resolver(const char* name) {
-  grpc_resolver_factory* factory = grpc_resolver_factory_lookup("dns");
+static grpc_core::OrphanablePtr<grpc_core::Resolver> create_resolver(
+    const char* name) {
+  grpc_core::ResolverFactory* factory =
+      grpc_core::ResolverRegistry::LookupResolverFactory("dns");
   grpc_uri* uri = grpc_uri_parse(name, 0);
   GPR_ASSERT(uri);
-  grpc_resolver_args args;
-  memset(&args, 0, sizeof(args));
+  grpc_core::ResolverArgs args;
   args.uri = uri;
   args.combiner = g_combiner;
-  grpc_resolver* resolver =
-      grpc_resolver_factory_create_resolver(factory, &args);
-  grpc_resolver_factory_unref(factory);
+  grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
+      factory->CreateResolver(args);
   grpc_uri_destroy(uri);
   return resolver;
 }
 
 static void on_done(void* ev, grpc_error* error) {
-  gpr_event_set((gpr_event*)ev, (void*)1);
+  gpr_event_set(static_cast<gpr_event*>(ev), (void*)1);
 }
 
 // interleave waiting for an event with a timer check
@@ -112,7 +115,7 @@
 }
 
 typedef struct next_args {
-  grpc_resolver* resolver;
+  grpc_core::Resolver* resolver;
   grpc_channel_args** result;
   grpc_closure* on_complete;
 } next_args;
@@ -120,21 +123,21 @@
 static void call_resolver_next_now_lock_taken(void* arg,
                                               grpc_error* error_unused) {
   next_args* a = static_cast<next_args*>(arg);
-  grpc_resolver_next_locked(a->resolver, a->result, a->on_complete);
+  a->resolver->NextLocked(a->result, a->on_complete);
   gpr_free(a);
 }
 
-static void call_resolver_next_after_locking(grpc_resolver* resolver,
+static void call_resolver_next_after_locking(grpc_core::Resolver* resolver,
                                              grpc_channel_args** result,
-                                             grpc_closure* on_complete) {
+                                             grpc_closure* on_complete,
+                                             grpc_combiner* combiner) {
   next_args* a = static_cast<next_args*>(gpr_malloc(sizeof(*a)));
   a->resolver = resolver;
   a->result = result;
   a->on_complete = on_complete;
-  GRPC_CLOSURE_SCHED(
-      GRPC_CLOSURE_CREATE(call_resolver_next_now_lock_taken, a,
-                          grpc_combiner_scheduler(resolver->combiner)),
-      GRPC_ERROR_NONE);
+  GRPC_CLOSURE_SCHED(GRPC_CLOSURE_CREATE(call_resolver_next_now_lock_taken, a,
+                                         grpc_combiner_scheduler(combiner)),
+                     GRPC_ERROR_NONE);
 }
 
 int main(int argc, char** argv) {
@@ -143,18 +146,20 @@
   grpc_init();
   gpr_mu_init(&g_mu);
   g_combiner = grpc_combiner_create();
-  grpc_resolve_address = my_resolve_address;
+  grpc_set_resolver_impl(&test_resolver);
   grpc_dns_lookup_ares = my_dns_lookup_ares;
   grpc_channel_args* result = (grpc_channel_args*)1;
 
   {
     grpc_core::ExecCtx exec_ctx;
-    grpc_resolver* resolver = create_resolver("dns:test");
+    grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
+        create_resolver("dns:test");
     gpr_event ev1;
     gpr_event_init(&ev1);
     call_resolver_next_after_locking(
-        resolver, &result,
-        GRPC_CLOSURE_CREATE(on_done, &ev1, grpc_schedule_on_exec_ctx));
+        resolver.get(), &result,
+        GRPC_CLOSURE_CREATE(on_done, &ev1, grpc_schedule_on_exec_ctx),
+        g_combiner);
     grpc_core::ExecCtx::Get()->Flush();
     GPR_ASSERT(wait_loop(5, &ev1));
     GPR_ASSERT(result == nullptr);
@@ -162,14 +167,14 @@
     gpr_event ev2;
     gpr_event_init(&ev2);
     call_resolver_next_after_locking(
-        resolver, &result,
-        GRPC_CLOSURE_CREATE(on_done, &ev2, grpc_schedule_on_exec_ctx));
+        resolver.get(), &result,
+        GRPC_CLOSURE_CREATE(on_done, &ev2, grpc_schedule_on_exec_ctx),
+        g_combiner);
     grpc_core::ExecCtx::Get()->Flush();
     GPR_ASSERT(wait_loop(30, &ev2));
     GPR_ASSERT(result != nullptr);
 
     grpc_channel_args_destroy(result);
-    GRPC_RESOLVER_UNREF(resolver, "test");
     GRPC_COMBINER_UNREF(g_combiner, "test");
   }
 
diff --git a/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc b/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc
index 64342b4..01c61a9 100644
--- a/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc
+++ b/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc
@@ -23,16 +23,15 @@
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "test/core/util/test_config.h"
 
-static grpc_combiner* g_combiner;
+extern grpc_address_resolver_vtable* grpc_resolve_address_impl;
+static grpc_address_resolver_vtable* default_resolve_address;
 
-static void (*g_default_grpc_resolve_address)(
-    const char* name, const char* default_port,
-    grpc_pollset_set* interested_parties, grpc_closure* on_done,
-    grpc_resolved_addresses** addrs);
+static grpc_combiner* g_combiner;
 
 grpc_ares_request* (*g_default_dns_lookup_ares)(
     const char* dns_server, const char* name, const char* default_port,
@@ -51,18 +50,28 @@
   grpc_pollset_set* pollset_set;
 } g_iomgr_args;
 
-// Wrapper around g_default_grpc_resolve_address in order to count the number of
+// Wrapper around default resolve_address in order to count the number of
 // times we incur in a system-level name resolution.
 static void test_resolve_address_impl(const char* name,
                                       const char* default_port,
                                       grpc_pollset_set* interested_parties,
                                       grpc_closure* on_done,
                                       grpc_resolved_addresses** addrs) {
-  g_default_grpc_resolve_address(name, default_port, g_iomgr_args.pollset_set,
-                                 on_done, addrs);
+  default_resolve_address->resolve_address(
+      name, default_port, g_iomgr_args.pollset_set, on_done, addrs);
   ++g_resolution_count;
 }
 
+static grpc_error* test_blocking_resolve_address_impl(
+    const char* name, const char* default_port,
+    grpc_resolved_addresses** addresses) {
+  return default_resolve_address->blocking_resolve_address(name, default_port,
+                                                           addresses);
+}
+
+static grpc_address_resolver_vtable test_resolver = {
+    test_resolve_address_impl, test_blocking_resolve_address_impl};
+
 grpc_ares_request* test_dns_lookup_ares(
     const char* dns_server, const char* name, const char* default_port,
     grpc_pollset_set* interested_parties, grpc_closure* on_done,
@@ -131,13 +140,13 @@
   gpr_event_set(&args->ev, (void*)1);
 }
 
-typedef struct on_resolution_cb_arg {
-  const char* uri_str;
-  grpc_resolver* resolver;
-  grpc_channel_args* result;
-  grpc_millis delay_before_second_resolution;
-  bool using_cares;
-} on_resolution_cb_arg;
+struct OnResolutionCallbackArg {
+  const char* uri_str = nullptr;
+  grpc_core::OrphanablePtr<grpc_core::Resolver> resolver;
+  grpc_channel_args* result = nullptr;
+  grpc_millis delay_before_second_resolution = 0;
+  bool using_cares = false;
+};
 
 // Counter for the number of times a resolution notification callback has been
 // invoked.
@@ -147,7 +156,7 @@
 bool g_all_callbacks_invoked;
 
 void on_third_resolution(void* arg, grpc_error* error) {
-  on_resolution_cb_arg* cb_arg = static_cast<on_resolution_cb_arg*>(arg);
+  OnResolutionCallbackArg* cb_arg = static_cast<OnResolutionCallbackArg*>(arg);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   ++g_on_resolution_invocations_count;
   grpc_channel_args_destroy(cb_arg->result);
@@ -159,8 +168,7 @@
   // period.
   GPR_ASSERT(g_on_resolution_invocations_count == 3);
   GPR_ASSERT(g_resolution_count == 2);
-  grpc_resolver_shutdown_locked(cb_arg->resolver);
-  GRPC_RESOLVER_UNREF(cb_arg->resolver, "on_third_resolution");
+  cb_arg->resolver.reset();
   if (cb_arg->using_cares) {
     gpr_atm_rel_store(&g_iomgr_args.done_atm, 1);
     gpr_mu_lock(g_iomgr_args.mu);
@@ -168,12 +176,12 @@
                       grpc_pollset_kick(g_iomgr_args.pollset, nullptr));
     gpr_mu_unlock(g_iomgr_args.mu);
   }
-  gpr_free(cb_arg);
+  grpc_core::Delete(cb_arg);
   g_all_callbacks_invoked = true;
 }
 
 void on_second_resolution(void* arg, grpc_error* error) {
-  on_resolution_cb_arg* cb_arg = static_cast<on_resolution_cb_arg*>(arg);
+  OnResolutionCallbackArg* cb_arg = static_cast<OnResolutionCallbackArg*>(arg);
   ++g_on_resolution_invocations_count;
   grpc_channel_args_destroy(cb_arg->result);
 
@@ -187,11 +195,11 @@
   GPR_ASSERT(g_resolution_count == 1);
   grpc_core::ExecCtx::Get()->TestOnlySetNow(
       cb_arg->delay_before_second_resolution * 2);
-  grpc_resolver_next_locked(
-      cb_arg->resolver, &cb_arg->result,
+  cb_arg->resolver->NextLocked(
+      &cb_arg->result,
       GRPC_CLOSURE_CREATE(on_third_resolution, arg,
                           grpc_combiner_scheduler(g_combiner)));
-  grpc_resolver_channel_saw_error_locked(cb_arg->resolver);
+  cb_arg->resolver->RequestReresolutionLocked();
   if (cb_arg->using_cares) {
     gpr_mu_lock(g_iomgr_args.mu);
     GRPC_LOG_IF_ERROR("pollset_kick",
@@ -201,14 +209,14 @@
 }
 
 void on_first_resolution(void* arg, grpc_error* error) {
-  on_resolution_cb_arg* cb_arg = static_cast<on_resolution_cb_arg*>(arg);
+  OnResolutionCallbackArg* cb_arg = static_cast<OnResolutionCallbackArg*>(arg);
   ++g_on_resolution_invocations_count;
   grpc_channel_args_destroy(cb_arg->result);
-  grpc_resolver_next_locked(
-      cb_arg->resolver, &cb_arg->result,
+  cb_arg->resolver->NextLocked(
+      &cb_arg->result,
       GRPC_CLOSURE_CREATE(on_second_resolution, arg,
                           grpc_combiner_scheduler(g_combiner)));
-  grpc_resolver_channel_saw_error_locked(cb_arg->resolver);
+  cb_arg->resolver->RequestReresolutionLocked();
   gpr_log(GPR_INFO,
           "1st: g_on_resolution_invocations_count: %d, g_resolution_count: %d",
           g_on_resolution_invocations_count, g_resolution_count);
@@ -225,15 +233,16 @@
 }
 
 static void start_test_under_combiner(void* arg, grpc_error* error) {
-  on_resolution_cb_arg* res_cb_arg = static_cast<on_resolution_cb_arg*>(arg);
-  grpc_resolver* resolver;
-  grpc_resolver_factory* factory = grpc_resolver_factory_lookup("dns");
+  OnResolutionCallbackArg* res_cb_arg =
+      static_cast<OnResolutionCallbackArg*>(arg);
+
+  grpc_core::ResolverFactory* factory =
+      grpc_core::ResolverRegistry::LookupResolverFactory("dns");
   grpc_uri* uri = grpc_uri_parse(res_cb_arg->uri_str, 0);
-  grpc_resolver_args args;
   gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", res_cb_arg->uri_str,
-          factory->vtable->scheme);
-  GPR_ASSERT(uri);
-  memset(&args, 0, sizeof(args));
+          factory->scheme());
+  GPR_ASSERT(uri != nullptr);
+  grpc_core::ResolverArgs args;
   args.uri = uri;
   args.combiner = g_combiner;
   g_on_resolution_invocations_count = 0;
@@ -248,25 +257,23 @@
   auto* cooldown_channel_args =
       grpc_channel_args_copy_and_add(nullptr, &cooldown_arg, 1);
   args.args = cooldown_channel_args;
-  resolver = grpc_resolver_factory_create_resolver(factory, &args);
+  res_cb_arg->resolver = factory->CreateResolver(args);
   grpc_channel_args_destroy(cooldown_channel_args);
-  GPR_ASSERT(resolver != nullptr);
-  res_cb_arg->resolver = resolver;
+  GPR_ASSERT(res_cb_arg->resolver != nullptr);
   res_cb_arg->delay_before_second_resolution = kMinResolutionPeriodMs;
   // First resolution, would incur in system-level resolution.
-  grpc_resolver_next_locked(
-      resolver, &res_cb_arg->result,
+  res_cb_arg->resolver->NextLocked(
+      &res_cb_arg->result,
       GRPC_CLOSURE_CREATE(on_first_resolution, res_cb_arg,
                           grpc_combiner_scheduler(g_combiner)));
   grpc_uri_destroy(uri);
-  grpc_resolver_factory_unref(factory);
 }
 
 static void test_cooldown(bool using_cares) {
   grpc_core::ExecCtx exec_ctx;
   if (using_cares) iomgr_args_init(&g_iomgr_args);
-  on_resolution_cb_arg* res_cb_arg =
-      static_cast<on_resolution_cb_arg*>(gpr_zalloc(sizeof(*res_cb_arg)));
+  OnResolutionCallbackArg* res_cb_arg =
+      grpc_core::New<OnResolutionCallbackArg>();
   res_cb_arg->uri_str = "dns:127.0.0.1";
   res_cb_arg->using_cares = using_cares;
 
@@ -286,11 +293,14 @@
 
   g_combiner = grpc_combiner_create();
 
-  const bool using_cares = (grpc_resolve_address == grpc_resolve_address_ares);
-  g_default_grpc_resolve_address = grpc_resolve_address;
+  bool using_cares = false;
+#if GRPC_ARES == 1
+  using_cares = true;
+#endif
   g_default_dns_lookup_ares = grpc_dns_lookup_ares;
   grpc_dns_lookup_ares = test_dns_lookup_ares;
-  grpc_resolve_address = test_resolve_address_impl;
+  default_resolve_address = grpc_resolve_address_impl;
+  grpc_set_resolver_impl(&test_resolver);
 
   test_cooldown(using_cares);
 
diff --git a/test/core/client_channel/resolvers/dns_resolver_test.cc b/test/core/client_channel/resolvers/dns_resolver_test.cc
index 8066790..e3fba28 100644
--- a/test/core/client_channel/resolvers/dns_resolver_test.cc
+++ b/test/core/client_channel/resolvers/dns_resolver_test.cc
@@ -27,47 +27,46 @@
 
 static grpc_combiner* g_combiner;
 
-static void test_succeeds(grpc_resolver_factory* factory, const char* string) {
+static void test_succeeds(grpc_core::ResolverFactory* factory,
+                          const char* string) {
+  gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", string,
+          factory->scheme());
   grpc_core::ExecCtx exec_ctx;
   grpc_uri* uri = grpc_uri_parse(string, 0);
-  grpc_resolver_args args;
-  grpc_resolver* resolver;
-  gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", string,
-          factory->vtable->scheme);
   GPR_ASSERT(uri);
-  memset(&args, 0, sizeof(args));
+  grpc_core::ResolverArgs args;
   args.uri = uri;
   args.combiner = g_combiner;
-  resolver = grpc_resolver_factory_create_resolver(factory, &args);
+  grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
+      factory->CreateResolver(args);
   GPR_ASSERT(resolver != nullptr);
-  GRPC_RESOLVER_UNREF(resolver, "test_succeeds");
   grpc_uri_destroy(uri);
 }
 
-static void test_fails(grpc_resolver_factory* factory, const char* string) {
+static void test_fails(grpc_core::ResolverFactory* factory,
+                       const char* string) {
+  gpr_log(GPR_DEBUG, "test: '%s' should be invalid for '%s'", string,
+          factory->scheme());
   grpc_core::ExecCtx exec_ctx;
   grpc_uri* uri = grpc_uri_parse(string, 0);
-  grpc_resolver_args args;
-  grpc_resolver* resolver;
-  gpr_log(GPR_DEBUG, "test: '%s' should be invalid for '%s'", string,
-          factory->vtable->scheme);
   GPR_ASSERT(uri);
-  memset(&args, 0, sizeof(args));
+  grpc_core::ResolverArgs args;
   args.uri = uri;
   args.combiner = g_combiner;
-  resolver = grpc_resolver_factory_create_resolver(factory, &args);
+  grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
+      factory->CreateResolver(args);
   GPR_ASSERT(resolver == nullptr);
   grpc_uri_destroy(uri);
 }
 
 int main(int argc, char** argv) {
-  grpc_resolver_factory* dns;
   grpc_test_init(argc, argv);
   grpc_init();
 
   g_combiner = grpc_combiner_create();
 
-  dns = grpc_resolver_factory_lookup("dns");
+  grpc_core::ResolverFactory* dns =
+      grpc_core::ResolverRegistry::LookupResolverFactory("dns");
 
   test_succeeds(dns, "dns:10.2.1.1");
   test_succeeds(dns, "dns:10.2.1.1:1234");
@@ -78,7 +77,6 @@
     test_fails(dns, "ipv4://8.8.8.8/8.8.8.8:8888");
   }
 
-  grpc_resolver_factory_unref(dns);
   {
     grpc_core::ExecCtx exec_ctx;
     GRPC_COMBINER_UNREF(g_combiner, "test");
diff --git a/test/core/client_channel/resolvers/fake_resolver_test.cc b/test/core/client_channel/resolvers/fake_resolver_test.cc
index 9c11c01..14caa3e 100644
--- a/test/core/client_channel/resolvers/fake_resolver_test.cc
+++ b/test/core/client_channel/resolvers/fake_resolver_test.cc
@@ -27,25 +27,26 @@
 #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/security/credentials/fake/fake_credentials.h"
 
 #include "test/core/util/test_config.h"
 
-static grpc_resolver* build_fake_resolver(
+static grpc_core::OrphanablePtr<grpc_core::Resolver> build_fake_resolver(
     grpc_combiner* combiner,
-    grpc_fake_resolver_response_generator* response_generator) {
-  grpc_resolver_factory* factory = grpc_resolver_factory_lookup("fake");
+    grpc_core::FakeResolverResponseGenerator* response_generator) {
+  grpc_core::ResolverFactory* factory =
+      grpc_core::ResolverRegistry::LookupResolverFactory("fake");
   grpc_arg generator_arg =
-      grpc_fake_resolver_response_generator_arg(response_generator);
-  grpc_resolver_args args;
-  memset(&args, 0, sizeof(args));
+      grpc_core::FakeResolverResponseGenerator::MakeChannelArg(
+          response_generator);
   grpc_channel_args channel_args = {1, &generator_arg};
+  grpc_core::ResolverArgs args;
   args.args = &channel_args;
   args.combiner = combiner;
-  grpc_resolver* resolver =
-      grpc_resolver_factory_create_resolver(factory, &args);
-  grpc_resolver_factory_unref(factory);
+  grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
+      factory->CreateResolver(args);
   return resolver;
 }
 
@@ -57,10 +58,11 @@
 
 // Callback to check the resolution result is as expected.
 void on_resolution_cb(void* arg, grpc_error* error) {
+  if (error != GRPC_ERROR_NONE) return;
   on_resolution_arg* res = static_cast<on_resolution_arg*>(arg);
   // We only check the addresses channel arg because that's the only one
   // explicitly set by the test via
-  // grpc_fake_resolver_response_generator_set_response.
+  // FakeResolverResponseGenerator::SetResponse().
   const grpc_lb_addresses* actual_lb_addresses =
       grpc_lb_addresses_find_channel_arg(res->resolver_result);
   const grpc_lb_addresses* expected_lb_addresses =
@@ -115,27 +117,27 @@
   grpc_core::ExecCtx exec_ctx;
   grpc_combiner* combiner = grpc_combiner_create();
   // Create resolver.
-  grpc_fake_resolver_response_generator* response_generator =
-      grpc_fake_resolver_response_generator_create();
-  grpc_resolver* resolver = build_fake_resolver(combiner, response_generator);
-  GPR_ASSERT(resolver != nullptr);
+  grpc_core::RefCountedPtr<grpc_core::FakeResolverResponseGenerator>
+      response_generator =
+          grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
+  grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
+      build_fake_resolver(combiner, response_generator.get());
+  GPR_ASSERT(resolver.get() != nullptr);
   // Test 1: normal resolution.
-  // next_results != NULL, results_upon_error == NULL, last_used_results ==
+  // next_results != NULL, reresolution_results == NULL, last_used_results ==
   // NULL. Expected response is next_results.
   grpc_channel_args* results = create_new_resolver_result();
   on_resolution_arg on_res_arg = create_on_resolution_arg(results);
   grpc_closure* on_resolution = GRPC_CLOSURE_CREATE(
       on_resolution_cb, &on_res_arg, grpc_combiner_scheduler(combiner));
   // Resolution won't be triggered until next_results is set.
-  grpc_resolver_next_locked(resolver, &on_res_arg.resolver_result,
-                            on_resolution);
-  grpc_fake_resolver_response_generator_set_response(response_generator,
-                                                     results);
+  resolver->NextLocked(&on_res_arg.resolver_result, on_resolution);
+  response_generator->SetResponse(results);
   grpc_core::ExecCtx::Get()->Flush();
   GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
                             grpc_timeout_seconds_to_deadline(5)) != nullptr);
   // Test 2: update resolution.
-  // next_results != NULL, results_upon_error == NULL, last_used_results !=
+  // next_results != NULL, reresolution_results == NULL, last_used_results !=
   // NULL. Expected response is next_results.
   results = create_new_resolver_result();
   grpc_channel_args* last_used_results = grpc_channel_args_copy(results);
@@ -143,61 +145,55 @@
   on_resolution = GRPC_CLOSURE_CREATE(on_resolution_cb, &on_res_arg,
                                       grpc_combiner_scheduler(combiner));
   // Resolution won't be triggered until next_results is set.
-  grpc_resolver_next_locked(resolver, &on_res_arg.resolver_result,
-                            on_resolution);
-  grpc_fake_resolver_response_generator_set_response(response_generator,
-                                                     results);
+  resolver->NextLocked(&on_res_arg.resolver_result, on_resolution);
+  response_generator->SetResponse(results);
   grpc_core::ExecCtx::Get()->Flush();
   GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
                             grpc_timeout_seconds_to_deadline(5)) != nullptr);
   // Test 3: fallback re-resolution.
-  // next_results == NULL, results_upon_error == NULL, last_used_results !=
+  // next_results == NULL, reresolution_results == NULL, last_used_results !=
   // NULL. Expected response is last_used_results.
   on_res_arg = create_on_resolution_arg(last_used_results);
   on_resolution = GRPC_CLOSURE_CREATE(on_resolution_cb, &on_res_arg,
                                       grpc_combiner_scheduler(combiner));
-  grpc_resolver_next_locked(resolver, &on_res_arg.resolver_result,
-                            on_resolution);
+  resolver->NextLocked(&on_res_arg.resolver_result, on_resolution);
   // Trigger a re-resolution.
-  grpc_resolver_channel_saw_error_locked(resolver);
+  resolver->RequestReresolutionLocked();
   grpc_core::ExecCtx::Get()->Flush();
   GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
                             grpc_timeout_seconds_to_deadline(5)) != nullptr);
   // Test 4: normal re-resolution.
-  // next_results == NULL, results_upon_error != NULL, last_used_results !=
-  // NULL. Expected response is results_upon_error.
-  grpc_channel_args* results_upon_error = create_new_resolver_result();
+  // next_results == NULL, reresolution_results != NULL, last_used_results !=
+  // NULL. Expected response is reresolution_results.
+  grpc_channel_args* reresolution_results = create_new_resolver_result();
   on_res_arg =
-      create_on_resolution_arg(grpc_channel_args_copy(results_upon_error));
+      create_on_resolution_arg(grpc_channel_args_copy(reresolution_results));
   on_resolution = GRPC_CLOSURE_CREATE(on_resolution_cb, &on_res_arg,
                                       grpc_combiner_scheduler(combiner));
-  grpc_resolver_next_locked(resolver, &on_res_arg.resolver_result,
-                            on_resolution);
-  // Set results_upon_error.
-  grpc_fake_resolver_response_generator_set_response_upon_error(
-      response_generator, results_upon_error);
+  resolver->NextLocked(&on_res_arg.resolver_result, on_resolution);
+  // Set reresolution_results.
+  response_generator->SetReresolutionResponse(reresolution_results);
   // Flush here to guarantee that the response has been set.
   grpc_core::ExecCtx::Get()->Flush();
   // Trigger a re-resolution.
-  grpc_resolver_channel_saw_error_locked(resolver);
+  resolver->RequestReresolutionLocked();
   grpc_core::ExecCtx::Get()->Flush();
   GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
                             grpc_timeout_seconds_to_deadline(5)) != nullptr);
   // Test 5: repeat re-resolution.
-  // next_results == NULL, results_upon_error != NULL, last_used_results !=
-  // NULL. Expected response is results_upon_error.
-  on_res_arg = create_on_resolution_arg(results_upon_error);
+  // next_results == NULL, reresolution_results != NULL, last_used_results !=
+  // NULL. Expected response is reresolution_results.
+  on_res_arg = create_on_resolution_arg(reresolution_results);
   on_resolution = GRPC_CLOSURE_CREATE(on_resolution_cb, &on_res_arg,
                                       grpc_combiner_scheduler(combiner));
-  grpc_resolver_next_locked(resolver, &on_res_arg.resolver_result,
-                            on_resolution);
+  resolver->NextLocked(&on_res_arg.resolver_result, on_resolution);
   // Trigger a re-resolution.
-  grpc_resolver_channel_saw_error_locked(resolver);
+  resolver->RequestReresolutionLocked();
   grpc_core::ExecCtx::Get()->Flush();
   GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
                             grpc_timeout_seconds_to_deadline(5)) != nullptr);
   // Test 6: normal resolution.
-  // next_results != NULL, results_upon_error != NULL, last_used_results !=
+  // next_results != NULL, reresolution_results != NULL, last_used_results !=
   // NULL. Expected response is next_results.
   results = create_new_resolver_result();
   last_used_results = grpc_channel_args_copy(results);
@@ -205,28 +201,24 @@
   on_resolution = GRPC_CLOSURE_CREATE(on_resolution_cb, &on_res_arg,
                                       grpc_combiner_scheduler(combiner));
   // Resolution won't be triggered until next_results is set.
-  grpc_resolver_next_locked(resolver, &on_res_arg.resolver_result,
-                            on_resolution);
-  grpc_fake_resolver_response_generator_set_response(response_generator,
-                                                     results);
+  resolver->NextLocked(&on_res_arg.resolver_result, on_resolution);
+  response_generator->SetResponse(results);
   grpc_core::ExecCtx::Get()->Flush();
   GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
                             grpc_timeout_seconds_to_deadline(5)) != nullptr);
   // Test 7: fallback re-resolution.
-  // next_results == NULL, results_upon_error == NULL, last_used_results !=
+  // next_results == NULL, reresolution_results == NULL, last_used_results !=
   // NULL. Expected response is last_used_results.
   on_res_arg = create_on_resolution_arg(last_used_results);
   on_resolution = GRPC_CLOSURE_CREATE(on_resolution_cb, &on_res_arg,
                                       grpc_combiner_scheduler(combiner));
-  grpc_resolver_next_locked(resolver, &on_res_arg.resolver_result,
-                            on_resolution);
-  // Reset results_upon_error.
-  grpc_fake_resolver_response_generator_set_response_upon_error(
-      response_generator, nullptr);
-  // Flush here to guarantee that results_upon_error has been reset.
+  resolver->NextLocked(&on_res_arg.resolver_result, on_resolution);
+  // Reset reresolution_results.
+  response_generator->SetReresolutionResponse(nullptr);
+  // Flush here to guarantee that reresolution_results has been reset.
   grpc_core::ExecCtx::Get()->Flush();
   // Trigger a re-resolution.
-  grpc_resolver_channel_saw_error_locked(resolver);
+  resolver->RequestReresolutionLocked();
   grpc_core::ExecCtx::Get()->Flush();
   GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
                             grpc_timeout_seconds_to_deadline(5)) != nullptr);
@@ -234,16 +226,20 @@
   // Requesting a new resolution without setting the response shouldn't trigger
   // the resolution callback.
   memset(&on_res_arg, 0, sizeof(on_res_arg));
-  grpc_resolver_next_locked(resolver, &on_res_arg.resolver_result,
-                            on_resolution);
+  on_resolution = GRPC_CLOSURE_CREATE(on_resolution_cb, &on_res_arg,
+                                      grpc_combiner_scheduler(combiner));
+  resolver->NextLocked(&on_res_arg.resolver_result, on_resolution);
   grpc_core::ExecCtx::Get()->Flush();
   GPR_ASSERT(gpr_event_wait(&on_res_arg.ev,
                             grpc_timeout_milliseconds_to_deadline(100)) ==
              nullptr);
   // Clean up.
+  // Note: Need to explicitly unref the resolver and flush the exec_ctx
+  // to make sure that the final resolver callback (with error set to
+  // "Resolver Shutdown") is invoked before on_res_arg goes out of scope.
+  resolver.reset();
+  grpc_core::ExecCtx::Get()->Flush();
   GRPC_COMBINER_UNREF(combiner, "test_fake_resolver");
-  GRPC_RESOLVER_UNREF(resolver, "test_fake_resolver");
-  grpc_fake_resolver_response_generator_unref(response_generator);
 }
 
 int main(int argc, char** argv) {
diff --git a/test/core/client_channel/resolvers/sockaddr_resolver_test.cc b/test/core/client_channel/resolvers/sockaddr_resolver_test.cc
index 07ee133..b9287c2 100644
--- a/test/core/client_channel/resolvers/sockaddr_resolver_test.cc
+++ b/test/core/client_channel/resolvers/sockaddr_resolver_test.cc
@@ -40,18 +40,18 @@
   grpc_channel_args_destroy(res->resolver_result);
 }
 
-static void test_succeeds(grpc_resolver_factory* factory, const char* string) {
+static void test_succeeds(grpc_core::ResolverFactory* factory,
+                          const char* string) {
+  gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", string,
+          factory->scheme());
   grpc_core::ExecCtx exec_ctx;
   grpc_uri* uri = grpc_uri_parse(string, 0);
-  grpc_resolver_args args;
-  grpc_resolver* resolver;
-  gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", string,
-          factory->vtable->scheme);
   GPR_ASSERT(uri);
-  memset(&args, 0, sizeof(args));
+  grpc_core::ResolverArgs args;
   args.uri = uri;
   args.combiner = g_combiner;
-  resolver = grpc_resolver_factory_create_resolver(factory, &args);
+  grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
+      factory->CreateResolver(args);
   GPR_ASSERT(resolver != nullptr);
 
   on_resolution_arg on_res_arg;
@@ -60,40 +60,39 @@
   grpc_closure* on_resolution = GRPC_CLOSURE_CREATE(
       on_resolution_cb, &on_res_arg, grpc_schedule_on_exec_ctx);
 
-  grpc_resolver_next_locked(resolver, &on_res_arg.resolver_result,
-                            on_resolution);
-  GRPC_RESOLVER_UNREF(resolver, "test_succeeds");
+  resolver->NextLocked(&on_res_arg.resolver_result, on_resolution);
   grpc_uri_destroy(uri);
   /* Flush ExecCtx to avoid stack-use-after-scope on on_res_arg which is
    * accessed in the closure on_resolution_cb */
   grpc_core::ExecCtx::Get()->Flush();
 }
 
-static void test_fails(grpc_resolver_factory* factory, const char* string) {
+static void test_fails(grpc_core::ResolverFactory* factory,
+                       const char* string) {
+  gpr_log(GPR_DEBUG, "test: '%s' should be invalid for '%s'", string,
+          factory->scheme());
   grpc_core::ExecCtx exec_ctx;
   grpc_uri* uri = grpc_uri_parse(string, 0);
-  grpc_resolver_args args;
-  grpc_resolver* resolver;
-  gpr_log(GPR_DEBUG, "test: '%s' should be invalid for '%s'", string,
-          factory->vtable->scheme);
   GPR_ASSERT(uri);
-  memset(&args, 0, sizeof(args));
+  grpc_core::ResolverArgs args;
   args.uri = uri;
   args.combiner = g_combiner;
-  resolver = grpc_resolver_factory_create_resolver(factory, &args);
+  grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
+      factory->CreateResolver(args);
   GPR_ASSERT(resolver == nullptr);
   grpc_uri_destroy(uri);
 }
 
 int main(int argc, char** argv) {
-  grpc_resolver_factory *ipv4, *ipv6;
   grpc_test_init(argc, argv);
   grpc_init();
 
   g_combiner = grpc_combiner_create();
 
-  ipv4 = grpc_resolver_factory_lookup("ipv4");
-  ipv6 = grpc_resolver_factory_lookup("ipv6");
+  grpc_core::ResolverFactory* ipv4 =
+      grpc_core::ResolverRegistry::LookupResolverFactory("ipv4");
+  grpc_core::ResolverFactory* ipv6 =
+      grpc_core::ResolverRegistry::LookupResolverFactory("ipv6");
 
   test_fails(ipv4, "ipv4:10.2.1.1");
   test_succeeds(ipv4, "ipv4:10.2.1.1:1234");
@@ -109,9 +108,6 @@
   test_fails(ipv6, "ipv6:[::]:123456");
   test_fails(ipv6, "ipv6:www.google.com");
 
-  grpc_resolver_factory_unref(ipv4);
-  grpc_resolver_factory_unref(ipv6);
-
   {
     grpc_core::ExecCtx exec_ctx;
     GRPC_COMBINER_UNREF(g_combiner, "test");
diff --git a/test/core/compression/algorithm_test.cc b/test/core/compression/algorithm_test.cc
index 1699d27..8989a41 100644
--- a/test/core/compression/algorithm_test.cc
+++ b/test/core/compression/algorithm_test.cc
@@ -23,13 +23,13 @@
 
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
 
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/transport/static_metadata.h"
 #include "test/core/util/test_config.h"
 
-const uint32_t message_prefix_length = 8;
+const uint32_t message_prefix_length = 0;
 const uint32_t stream_prefix_length = 7;
 static void test_algorithm_mesh(void) {
   int i;
diff --git a/test/core/compression/compression_test.cc b/test/core/compression/compression_test.cc
index e49a93a..6522988 100644
--- a/test/core/compression/compression_test.cc
+++ b/test/core/compression/compression_test.cc
@@ -22,17 +22,16 @@
 #include <grpc/compression.h>
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
 
+#include "src/core/lib/gpr/useful.h"
 #include "test/core/util/test_config.h"
 
 static void test_compression_algorithm_parse(void) {
   size_t i;
-  const char* valid_names[] = {"identity", "message/gzip", "message/deflate",
-                               "stream/gzip"};
+  const char* valid_names[] = {"identity", "gzip", "deflate", "stream/gzip"};
   const grpc_compression_algorithm valid_algorithms[] = {
-      GRPC_COMPRESS_NONE, GRPC_COMPRESS_MESSAGE_GZIP,
-      GRPC_COMPRESS_MESSAGE_DEFLATE, GRPC_COMPRESS_STREAM_GZIP};
+      GRPC_COMPRESS_NONE, GRPC_COMPRESS_GZIP, GRPC_COMPRESS_DEFLATE,
+      GRPC_COMPRESS_STREAM_GZIP};
   const char* invalid_names[] = {"gzip2", "foo", "", "2gzip"};
 
   gpr_log(GPR_DEBUG, "test_compression_algorithm_parse");
@@ -61,11 +60,10 @@
   int success;
   const char* name;
   size_t i;
-  const char* valid_names[] = {"identity", "message/gzip", "message/deflate",
-                               "stream/gzip"};
+  const char* valid_names[] = {"identity", "gzip", "deflate", "stream/gzip"};
   const grpc_compression_algorithm valid_algorithms[] = {
-      GRPC_COMPRESS_NONE, GRPC_COMPRESS_MESSAGE_GZIP,
-      GRPC_COMPRESS_MESSAGE_DEFLATE, GRPC_COMPRESS_STREAM_GZIP};
+      GRPC_COMPRESS_NONE, GRPC_COMPRESS_GZIP, GRPC_COMPRESS_DEFLATE,
+      GRPC_COMPRESS_STREAM_GZIP};
 
   gpr_log(GPR_DEBUG, "test_compression_algorithm_name");
 
@@ -110,21 +108,21 @@
     /* accept only gzip */
     uint32_t accepted_encodings = 0;
     GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_NONE); /* always */
-    GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_MESSAGE_GZIP);
+    GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_GZIP);
 
     GPR_ASSERT(GRPC_COMPRESS_NONE ==
                grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_NONE,
                                                     accepted_encodings));
 
-    GPR_ASSERT(GRPC_COMPRESS_MESSAGE_GZIP ==
+    GPR_ASSERT(GRPC_COMPRESS_GZIP ==
                grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_LOW,
                                                     accepted_encodings));
 
-    GPR_ASSERT(GRPC_COMPRESS_MESSAGE_GZIP ==
+    GPR_ASSERT(GRPC_COMPRESS_GZIP ==
                grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_MED,
                                                     accepted_encodings));
 
-    GPR_ASSERT(GRPC_COMPRESS_MESSAGE_GZIP ==
+    GPR_ASSERT(GRPC_COMPRESS_GZIP ==
                grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_HIGH,
                                                     accepted_encodings));
   }
@@ -133,21 +131,21 @@
     /* accept only deflate */
     uint32_t accepted_encodings = 0;
     GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_NONE); /* always */
-    GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_MESSAGE_DEFLATE);
+    GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_DEFLATE);
 
     GPR_ASSERT(GRPC_COMPRESS_NONE ==
                grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_NONE,
                                                     accepted_encodings));
 
-    GPR_ASSERT(GRPC_COMPRESS_MESSAGE_DEFLATE ==
+    GPR_ASSERT(GRPC_COMPRESS_DEFLATE ==
                grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_LOW,
                                                     accepted_encodings));
 
-    GPR_ASSERT(GRPC_COMPRESS_MESSAGE_DEFLATE ==
+    GPR_ASSERT(GRPC_COMPRESS_DEFLATE ==
                grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_MED,
                                                     accepted_encodings));
 
-    GPR_ASSERT(GRPC_COMPRESS_MESSAGE_DEFLATE ==
+    GPR_ASSERT(GRPC_COMPRESS_DEFLATE ==
                grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_HIGH,
                                                     accepted_encodings));
   }
@@ -156,22 +154,22 @@
     /* accept gzip and deflate */
     uint32_t accepted_encodings = 0;
     GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_NONE); /* always */
-    GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_MESSAGE_GZIP);
-    GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_MESSAGE_DEFLATE);
+    GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_GZIP);
+    GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_DEFLATE);
 
     GPR_ASSERT(GRPC_COMPRESS_NONE ==
                grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_NONE,
                                                     accepted_encodings));
 
-    GPR_ASSERT(GRPC_COMPRESS_MESSAGE_GZIP ==
+    GPR_ASSERT(GRPC_COMPRESS_GZIP ==
                grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_LOW,
                                                     accepted_encodings));
 
-    GPR_ASSERT(GRPC_COMPRESS_MESSAGE_DEFLATE ==
+    GPR_ASSERT(GRPC_COMPRESS_DEFLATE ==
                grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_MED,
                                                     accepted_encodings));
 
-    GPR_ASSERT(GRPC_COMPRESS_MESSAGE_DEFLATE ==
+    GPR_ASSERT(GRPC_COMPRESS_DEFLATE ==
                grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_HIGH,
                                                     accepted_encodings));
   }
@@ -203,23 +201,23 @@
     /* accept all algorithms */
     uint32_t accepted_encodings = 0;
     GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_NONE); /* always */
-    GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_MESSAGE_GZIP);
-    GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_MESSAGE_DEFLATE);
+    GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_GZIP);
+    GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_DEFLATE);
     GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_STREAM_GZIP);
 
     GPR_ASSERT(GRPC_COMPRESS_NONE ==
                grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_NONE,
                                                     accepted_encodings));
 
-    GPR_ASSERT(GRPC_COMPRESS_MESSAGE_GZIP ==
+    GPR_ASSERT(GRPC_COMPRESS_GZIP ==
                grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_LOW,
                                                     accepted_encodings));
 
-    GPR_ASSERT(GRPC_COMPRESS_MESSAGE_DEFLATE ==
+    GPR_ASSERT(GRPC_COMPRESS_DEFLATE ==
                grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_MED,
                                                     accepted_encodings));
 
-    GPR_ASSERT(GRPC_COMPRESS_MESSAGE_DEFLATE ==
+    GPR_ASSERT(GRPC_COMPRESS_DEFLATE ==
                grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_HIGH,
                                                     accepted_encodings));
   }
diff --git a/test/core/compression/message_compress_test.cc b/test/core/compression/message_compress_test.cc
index bab32e0..e3fe825 100644
--- a/test/core/compression/message_compress_test.cc
+++ b/test/core/compression/message_compress_test.cc
@@ -23,9 +23,9 @@
 
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/gpr/murmur_hash.h"
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "test/core/util/slice_splitter.h"
 #include "test/core/util/test_config.h"
diff --git a/test/core/compression/stream_compression_test.cc b/test/core/compression/stream_compression_test.cc
index 2f30b7f..0b84366 100644
--- a/test/core/compression/stream_compression_test.cc
+++ b/test/core/compression/stream_compression_test.cc
@@ -29,7 +29,7 @@
   size_t i;
   static const char chars[] = "abcdefghijklmnopqrstuvwxyz1234567890";
   for (i = 0; i < size - 1; ++i) {
-    payload[i] = chars[rand() % (int)(sizeof(chars) - 1)];
+    payload[i] = chars[rand() % static_cast<int>(sizeof(chars) - 1)];
   }
   payload[size - 1] = '\0';
 }
@@ -43,8 +43,10 @@
   size_t pointer = 0;
   for (i = 0; i < buf->count; i++) {
     size_t slice_len = GRPC_SLICE_LENGTH(buf->slices[i]);
-    if (0 != strncmp(str + pointer, (char*)GRPC_SLICE_START_PTR(buf->slices[i]),
-                     slice_len)) {
+    if (0 !=
+        strncmp(str + pointer,
+                reinterpret_cast<char*> GRPC_SLICE_START_PTR(buf->slices[i]),
+                slice_len)) {
       return false;
     }
     pointer += slice_len;
@@ -112,7 +114,7 @@
   GPR_ASSERT(output_size == max_output_size);
   GPR_ASSERT(end_of_context == false);
   grpc_slice slice_recv = grpc_slice_buffer_take_first(&sink);
-  char* str_recv = (char*)GRPC_SLICE_START_PTR(slice_recv);
+  char* str_recv = reinterpret_cast<char*> GRPC_SLICE_START_PTR(slice_recv);
   GPR_ASSERT(GRPC_SLICE_LENGTH(slice_recv) == max_output_size);
   GPR_ASSERT(0 == strncmp(test_str, str_recv, max_output_size));
   grpc_slice_unref(slice_recv);
diff --git a/test/core/debug/stats_test.cc b/test/core/debug/stats_test.cc
index e60e54b..949a88f 100644
--- a/test/core/debug/stats_test.cc
+++ b/test/core/debug/stats_test.cc
@@ -47,22 +47,22 @@
 
 TEST(StatsTest, IncCounters) {
   for (int i = 0; i < GRPC_STATS_COUNTER_COUNT; i++) {
-    Snapshot snapshot;
+    std::unique_ptr<Snapshot> snapshot(new Snapshot);
 
     grpc_core::ExecCtx exec_ctx;
     GRPC_STATS_INC_COUNTER((grpc_stats_counters)i);
 
-    EXPECT_EQ(snapshot.delta().counters[i], 1);
+    EXPECT_EQ(snapshot->delta().counters[i], 1);
   }
 }
 
 TEST(StatsTest, IncSpecificCounter) {
-  Snapshot snapshot;
+  std::unique_ptr<Snapshot> snapshot(new Snapshot);
 
   grpc_core::ExecCtx exec_ctx;
   GRPC_STATS_INC_SYSCALL_POLL();
 
-  EXPECT_EQ(snapshot.delta().counters[GRPC_STATS_COUNTER_SYSCALL_POLL], 1);
+  EXPECT_EQ(snapshot->delta().counters[GRPC_STATS_COUNTER_SYSCALL_POLL], 1);
 }
 
 static int FindExpectedBucket(int i, int j) {
@@ -90,12 +90,12 @@
     gpr_log(GPR_DEBUG, "expected_bucket:%d nvalues=%" PRIdPTR, expected_bucket,
             test_values.size());
     for (auto j : test_values) {
-      Snapshot snapshot;
+      std::unique_ptr<Snapshot> snapshot(new Snapshot);
 
       grpc_core::ExecCtx exec_ctx;
       grpc_stats_inc_histogram[kHistogram](j);
 
-      auto delta = snapshot.delta();
+      auto delta = snapshot->delta();
 
       EXPECT_EQ(
           delta
diff --git a/test/core/end2end/BUILD b/test/core/end2end/BUILD
index f8281bf..dd16694 100644
--- a/test/core/end2end/BUILD
+++ b/test/core/end2end/BUILD
@@ -71,4 +71,112 @@
     ],
 )
 
+grpc_cc_test(
+    name = "bad_server_response_test",
+    srcs = ["bad_server_response_test.cc"],
+    language = "C++",
+    deps = [
+        ":cq_verifier",
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+grpc_cc_test(
+    name = "connection_refused_test",
+    srcs = ["connection_refused_test.cc"],
+    language = "C++",
+    deps = [
+        ":cq_verifier",
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+grpc_cc_test(
+    name = "dualstack_socket_test",
+    srcs = ["dualstack_socket_test.cc"],
+    language = "C++",
+    deps = [
+        ":cq_verifier",
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+grpc_cc_test(
+    name = "goaway_server_test",
+    srcs = ["goaway_server_test.cc"],
+    language = "C++",
+    deps = [
+        ":cq_verifier",
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+grpc_cc_test(
+    name = "invalid_call_argument_test",
+    srcs = ["invalid_call_argument_test.cc"],
+    language = "C++",
+    deps = [
+        ":cq_verifier",
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+grpc_cc_test(
+    name = "multiple_server_queues_test",
+    srcs = ["multiple_server_queues_test.cc"],
+    language = "C++",
+    deps = [
+        ":cq_verifier",
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+grpc_cc_test(
+    name = "no_server_test",
+    srcs = ["no_server_test.cc"],
+    language = "C++",
+    deps = [
+        ":cq_verifier",
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
 grpc_end2end_tests()
+
+grpc_cc_test(
+    name = "h2_ssl_session_reuse_test",
+    srcs = ["h2_ssl_session_reuse_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
+    language = "C++",
+    deps = [
+        ':end2end_tests',
+        '//:gpr',
+        '//:grpc',
+        '//:tsi',
+        '//test/core/util:gpr_test_util',
+        '//test/core/util:grpc_test_util',
+    ],
+)
diff --git a/test/core/end2end/bad_server_response_test.cc b/test/core/end2end/bad_server_response_test.cc
index a8e5e29..3d133cf 100644
--- a/test/core/end2end/bad_server_response_test.cc
+++ b/test/core/end2end/bad_server_response_test.cc
@@ -27,11 +27,12 @@
 #include <grpc/grpc.h>
 #include <grpc/slice.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
-#include <grpc/support/thd.h>
 
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
@@ -133,7 +134,7 @@
                        grpc_pollset* accepting_pollset,
                        grpc_tcp_server_acceptor* acceptor) {
   gpr_free(acceptor);
-  test_tcp_server* server = (test_tcp_server*)arg;
+  test_tcp_server* server = static_cast<test_tcp_server*>(arg);
   GRPC_CLOSURE_INIT(&on_read, handle_read, nullptr, grpc_schedule_on_exec_ctx);
   GRPC_CLOSURE_INIT(&on_write, done_write, nullptr, grpc_schedule_on_exec_ctx);
   grpc_slice_buffer_init(&state.temp_incoming_buffer);
@@ -196,8 +197,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(state.call, ops, (size_t)(op - ops), tag(1),
-                                nullptr);
+  error = grpc_call_start_batch(state.call, ops, static_cast<size_t>(op - ops),
+                                tag(1), nullptr);
 
   GPR_ASSERT(GRPC_CALL_OK == error);
 
@@ -236,7 +237,7 @@
 } poll_args;
 
 static void actually_poll_server(void* arg) {
-  poll_args* pa = (poll_args*)arg;
+  poll_args* pa = static_cast<poll_args*>(arg);
   gpr_timespec deadline = n_sec_deadline(10);
   while (true) {
     bool done = gpr_atm_acq_load(&state.done_atm) != 0;
@@ -253,15 +254,17 @@
   gpr_free(pa);
 }
 
-static void poll_server_until_read_done(test_tcp_server* server,
-                                        gpr_event* signal_when_done) {
+static grpc_core::Thread* poll_server_until_read_done(
+    test_tcp_server* server, gpr_event* signal_when_done) {
   gpr_atm_rel_store(&state.done_atm, 0);
   state.write_done = 0;
-  gpr_thd_id id;
-  poll_args* pa = (poll_args*)gpr_malloc(sizeof(*pa));
+  poll_args* pa = static_cast<poll_args*>(gpr_malloc(sizeof(*pa)));
   pa->server = server;
   pa->signal_when_done = signal_when_done;
-  gpr_thd_new(&id, "grpc_poll_server", actually_poll_server, pa, nullptr);
+  auto* th = grpc_core::New<grpc_core::Thread>("grpc_poll_server",
+                                               actually_poll_server, pa);
+  th->Start();
+  return th;
 }
 
 static void run_test(const char* response_payload,
@@ -281,9 +284,11 @@
   state.response_payload_length = response_payload_length;
 
   /* poll server until sending out the response */
-  poll_server_until_read_done(&test_server, &ev);
+  grpc_core::UniquePtr<grpc_core::Thread> thdptr(
+      poll_server_until_read_done(&test_server, &ev));
   start_rpc(server_port, expected_status, expected_detail);
   gpr_event_wait(&ev, gpr_inf_future(GPR_CLOCK_REALTIME));
+  thdptr->Join();
 
   /* clean up */
   grpc_endpoint_shutdown(state.tcp,
diff --git a/test/core/end2end/connection_refused_test.cc b/test/core/end2end/connection_refused_test.cc
index ca6d17e..33812ec 100644
--- a/test/core/end2end/connection_refused_test.cc
+++ b/test/core/end2end/connection_refused_test.cc
@@ -20,11 +20,12 @@
 
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/host_port.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/transport/metadata.h"
 #include "src/core/lib/transport/service_config.h"
diff --git a/test/core/end2end/cq_verifier.cc b/test/core/end2end/cq_verifier.cc
index 7bf8ae0..f7e64ef 100644
--- a/test/core/end2end/cq_verifier.cc
+++ b/test/core/end2end/cq_verifier.cc
@@ -18,6 +18,7 @@
 
 #include "test/core/end2end/cq_verifier.h"
 
+#include <inttypes.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
@@ -28,7 +29,6 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/surface/event_string.h"
 
@@ -62,7 +62,7 @@
 };
 
 cq_verifier* cq_verifier_create(grpc_completion_queue* cq) {
-  cq_verifier* v = (cq_verifier*)gpr_malloc(sizeof(cq_verifier));
+  cq_verifier* v = static_cast<cq_verifier*>(gpr_malloc(sizeof(cq_verifier)));
   v->cq = cq;
   v->first_expectation = nullptr;
   return v;
@@ -306,7 +306,7 @@
 
 static void add(cq_verifier* v, const char* file, int line,
                 grpc_completion_type type, void* tag, bool success) {
-  expectation* e = (expectation*)gpr_malloc(sizeof(expectation));
+  expectation* e = static_cast<expectation*>(gpr_malloc(sizeof(expectation)));
   e->type = type;
   e->file = file;
   e->line = line;
diff --git a/test/core/end2end/cq_verifier_uv.cc b/test/core/end2end/cq_verifier_uv.cc
index e23b3ae..45d827e 100644
--- a/test/core/end2end/cq_verifier_uv.cc
+++ b/test/core/end2end/cq_verifier_uv.cc
@@ -58,7 +58,7 @@
 void cq_verifier_destroy(cq_verifier* v) {
   cq_verify(v);
   uv_close((uv_handle_t*)&v->timer, timer_close_cb);
-  while (reinterpret_cast<timer_state>(v->timer.data) != TIMER_CLOSED) {
+  while (static_cast<timer_state>(v->timer.data) != TIMER_CLOSED) {
     uv_run(uv_default_loop(), UV_RUN_NOWAIT);
   }
   gpr_free(v);
@@ -85,7 +85,7 @@
   ev = grpc_completion_queue_next(v->cq, gpr_inf_past(GPR_CLOCK_MONOTONIC),
                                   NULL);
   // Stop the loop if the timer goes off or we get a non-timeout event
-  while ((reinterpret_cast<timer_state>(v->timer.data) != TIMER_TRIGGERED) &&
+  while ((static_cast<timer_state>(v->timer.data) != TIMER_TRIGGERED) &&
          ev.type == GRPC_QUEUE_TIMEOUT) {
     uv_run(uv_default_loop(), UV_RUN_ONCE);
     ev = grpc_completion_queue_next(v->cq, gpr_inf_past(GPR_CLOCK_MONOTONIC),
diff --git a/test/core/end2end/dualstack_socket_test.cc b/test/core/end2end/dualstack_socket_test.cc
index bb30547..eb1d043 100644
--- a/test/core/end2end/dualstack_socket_test.cc
+++ b/test/core/end2end/dualstack_socket_test.cc
@@ -25,10 +25,10 @@
 
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/resolve_address.h"
@@ -128,8 +128,8 @@
     grpc_slice_buffer uri_parts;
     char** hosts_with_port;
 
-    uri_slice =
-        grpc_slice_new((char*)client_host, strlen(client_host), do_nothing);
+    uri_slice = grpc_slice_new(const_cast<char*>(client_host),
+                               strlen(client_host), do_nothing);
     grpc_slice_buffer_init(&uri_parts);
     grpc_slice_split(uri_slice, ",", &uri_parts);
     hosts_with_port =
@@ -166,7 +166,7 @@
   } else {
     /* Give up faster when failure is expected.
        BUG: Setting this to 1000 reveals a memory leak (b/18608927). */
-    deadline = grpc_timeout_milliseconds_to_deadline(3000);
+    deadline = grpc_timeout_milliseconds_to_deadline(8000);
   }
 
   /* Send a trivial request. */
@@ -199,7 +199,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   if (expect_ok) {
@@ -227,8 +228,8 @@
     op->data.recv_close_on_server.cancelled = &was_cancelled;
     op->flags = 0;
     op++;
-    error =
-        grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+    error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops),
+                                  tag(102), nullptr);
     GPR_ASSERT(GRPC_CALL_OK == error);
 
     CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
diff --git a/test/core/end2end/end2end_nosec_tests.cc b/test/core/end2end/end2end_nosec_tests.cc
index 6318550..78ddcdb 100644
--- a/test/core/end2end/end2end_nosec_tests.cc
+++ b/test/core/end2end/end2end_nosec_tests.cc
@@ -118,6 +118,36 @@
 extern void request_with_payload_pre_init(void);
 extern void resource_quota_server(grpc_end2end_test_config config);
 extern void resource_quota_server_pre_init(void);
+extern void retry(grpc_end2end_test_config config);
+extern void retry_pre_init(void);
+extern void retry_cancellation(grpc_end2end_test_config config);
+extern void retry_cancellation_pre_init(void);
+extern void retry_disabled(grpc_end2end_test_config config);
+extern void retry_disabled_pre_init(void);
+extern void retry_exceeds_buffer_size_in_initial_batch(grpc_end2end_test_config config);
+extern void retry_exceeds_buffer_size_in_initial_batch_pre_init(void);
+extern void retry_exceeds_buffer_size_in_subsequent_batch(grpc_end2end_test_config config);
+extern void retry_exceeds_buffer_size_in_subsequent_batch_pre_init(void);
+extern void retry_non_retriable_status(grpc_end2end_test_config config);
+extern void retry_non_retriable_status_pre_init(void);
+extern void retry_recv_initial_metadata(grpc_end2end_test_config config);
+extern void retry_recv_initial_metadata_pre_init(void);
+extern void retry_recv_message(grpc_end2end_test_config config);
+extern void retry_recv_message_pre_init(void);
+extern void retry_server_pushback_delay(grpc_end2end_test_config config);
+extern void retry_server_pushback_delay_pre_init(void);
+extern void retry_server_pushback_disabled(grpc_end2end_test_config config);
+extern void retry_server_pushback_disabled_pre_init(void);
+extern void retry_streaming(grpc_end2end_test_config config);
+extern void retry_streaming_pre_init(void);
+extern void retry_streaming_after_commit(grpc_end2end_test_config config);
+extern void retry_streaming_after_commit_pre_init(void);
+extern void retry_streaming_succeeds_before_replay_finished(grpc_end2end_test_config config);
+extern void retry_streaming_succeeds_before_replay_finished_pre_init(void);
+extern void retry_throttled(grpc_end2end_test_config config);
+extern void retry_throttled_pre_init(void);
+extern void retry_too_many_attempts(grpc_end2end_test_config config);
+extern void retry_too_many_attempts_pre_init(void);
 extern void server_finishes_request(grpc_end2end_test_config config);
 extern void server_finishes_request_pre_init(void);
 extern void shutdown_finishes_calls(grpc_end2end_test_config config);
@@ -197,6 +227,21 @@
   request_with_flags_pre_init();
   request_with_payload_pre_init();
   resource_quota_server_pre_init();
+  retry_pre_init();
+  retry_cancellation_pre_init();
+  retry_disabled_pre_init();
+  retry_exceeds_buffer_size_in_initial_batch_pre_init();
+  retry_exceeds_buffer_size_in_subsequent_batch_pre_init();
+  retry_non_retriable_status_pre_init();
+  retry_recv_initial_metadata_pre_init();
+  retry_recv_message_pre_init();
+  retry_server_pushback_delay_pre_init();
+  retry_server_pushback_disabled_pre_init();
+  retry_streaming_pre_init();
+  retry_streaming_after_commit_pre_init();
+  retry_streaming_succeeds_before_replay_finished_pre_init();
+  retry_throttled_pre_init();
+  retry_too_many_attempts_pre_init();
   server_finishes_request_pre_init();
   shutdown_finishes_calls_pre_init();
   shutdown_finishes_tags_pre_init();
@@ -265,6 +310,21 @@
     request_with_flags(config);
     request_with_payload(config);
     resource_quota_server(config);
+    retry(config);
+    retry_cancellation(config);
+    retry_disabled(config);
+    retry_exceeds_buffer_size_in_initial_batch(config);
+    retry_exceeds_buffer_size_in_subsequent_batch(config);
+    retry_non_retriable_status(config);
+    retry_recv_initial_metadata(config);
+    retry_recv_message(config);
+    retry_server_pushback_delay(config);
+    retry_server_pushback_disabled(config);
+    retry_streaming(config);
+    retry_streaming_after_commit(config);
+    retry_streaming_succeeds_before_replay_finished(config);
+    retry_throttled(config);
+    retry_too_many_attempts(config);
     server_finishes_request(config);
     shutdown_finishes_calls(config);
     shutdown_finishes_tags(config);
@@ -460,6 +520,66 @@
       resource_quota_server(config);
       continue;
     }
+    if (0 == strcmp("retry", argv[i])) {
+      retry(config);
+      continue;
+    }
+    if (0 == strcmp("retry_cancellation", argv[i])) {
+      retry_cancellation(config);
+      continue;
+    }
+    if (0 == strcmp("retry_disabled", argv[i])) {
+      retry_disabled(config);
+      continue;
+    }
+    if (0 == strcmp("retry_exceeds_buffer_size_in_initial_batch", argv[i])) {
+      retry_exceeds_buffer_size_in_initial_batch(config);
+      continue;
+    }
+    if (0 == strcmp("retry_exceeds_buffer_size_in_subsequent_batch", argv[i])) {
+      retry_exceeds_buffer_size_in_subsequent_batch(config);
+      continue;
+    }
+    if (0 == strcmp("retry_non_retriable_status", argv[i])) {
+      retry_non_retriable_status(config);
+      continue;
+    }
+    if (0 == strcmp("retry_recv_initial_metadata", argv[i])) {
+      retry_recv_initial_metadata(config);
+      continue;
+    }
+    if (0 == strcmp("retry_recv_message", argv[i])) {
+      retry_recv_message(config);
+      continue;
+    }
+    if (0 == strcmp("retry_server_pushback_delay", argv[i])) {
+      retry_server_pushback_delay(config);
+      continue;
+    }
+    if (0 == strcmp("retry_server_pushback_disabled", argv[i])) {
+      retry_server_pushback_disabled(config);
+      continue;
+    }
+    if (0 == strcmp("retry_streaming", argv[i])) {
+      retry_streaming(config);
+      continue;
+    }
+    if (0 == strcmp("retry_streaming_after_commit", argv[i])) {
+      retry_streaming_after_commit(config);
+      continue;
+    }
+    if (0 == strcmp("retry_streaming_succeeds_before_replay_finished", argv[i])) {
+      retry_streaming_succeeds_before_replay_finished(config);
+      continue;
+    }
+    if (0 == strcmp("retry_throttled", argv[i])) {
+      retry_throttled(config);
+      continue;
+    }
+    if (0 == strcmp("retry_too_many_attempts", argv[i])) {
+      retry_too_many_attempts(config);
+      continue;
+    }
     if (0 == strcmp("server_finishes_request", argv[i])) {
       server_finishes_request(config);
       continue;
diff --git a/test/core/end2end/end2end_test.sh b/test/core/end2end/end2end_test.sh
index 3b18ae3..5bfb253 100755
--- a/test/core/end2end/end2end_test.sh
+++ b/test/core/end2end/end2end_test.sh
@@ -15,4 +15,8 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-$1 $2
+if [ -z "$3" ]
+  then
+    export GRPC_POLL_STRATEGY=$3
+fi
+"$1" "$2"
diff --git a/test/core/end2end/end2end_tests.cc b/test/core/end2end/end2end_tests.cc
index 9d8dfd6..fb1e61b 100644
--- a/test/core/end2end/end2end_tests.cc
+++ b/test/core/end2end/end2end_tests.cc
@@ -120,6 +120,36 @@
 extern void request_with_payload_pre_init(void);
 extern void resource_quota_server(grpc_end2end_test_config config);
 extern void resource_quota_server_pre_init(void);
+extern void retry(grpc_end2end_test_config config);
+extern void retry_pre_init(void);
+extern void retry_cancellation(grpc_end2end_test_config config);
+extern void retry_cancellation_pre_init(void);
+extern void retry_disabled(grpc_end2end_test_config config);
+extern void retry_disabled_pre_init(void);
+extern void retry_exceeds_buffer_size_in_initial_batch(grpc_end2end_test_config config);
+extern void retry_exceeds_buffer_size_in_initial_batch_pre_init(void);
+extern void retry_exceeds_buffer_size_in_subsequent_batch(grpc_end2end_test_config config);
+extern void retry_exceeds_buffer_size_in_subsequent_batch_pre_init(void);
+extern void retry_non_retriable_status(grpc_end2end_test_config config);
+extern void retry_non_retriable_status_pre_init(void);
+extern void retry_recv_initial_metadata(grpc_end2end_test_config config);
+extern void retry_recv_initial_metadata_pre_init(void);
+extern void retry_recv_message(grpc_end2end_test_config config);
+extern void retry_recv_message_pre_init(void);
+extern void retry_server_pushback_delay(grpc_end2end_test_config config);
+extern void retry_server_pushback_delay_pre_init(void);
+extern void retry_server_pushback_disabled(grpc_end2end_test_config config);
+extern void retry_server_pushback_disabled_pre_init(void);
+extern void retry_streaming(grpc_end2end_test_config config);
+extern void retry_streaming_pre_init(void);
+extern void retry_streaming_after_commit(grpc_end2end_test_config config);
+extern void retry_streaming_after_commit_pre_init(void);
+extern void retry_streaming_succeeds_before_replay_finished(grpc_end2end_test_config config);
+extern void retry_streaming_succeeds_before_replay_finished_pre_init(void);
+extern void retry_throttled(grpc_end2end_test_config config);
+extern void retry_throttled_pre_init(void);
+extern void retry_too_many_attempts(grpc_end2end_test_config config);
+extern void retry_too_many_attempts_pre_init(void);
 extern void server_finishes_request(grpc_end2end_test_config config);
 extern void server_finishes_request_pre_init(void);
 extern void shutdown_finishes_calls(grpc_end2end_test_config config);
@@ -200,6 +230,21 @@
   request_with_flags_pre_init();
   request_with_payload_pre_init();
   resource_quota_server_pre_init();
+  retry_pre_init();
+  retry_cancellation_pre_init();
+  retry_disabled_pre_init();
+  retry_exceeds_buffer_size_in_initial_batch_pre_init();
+  retry_exceeds_buffer_size_in_subsequent_batch_pre_init();
+  retry_non_retriable_status_pre_init();
+  retry_recv_initial_metadata_pre_init();
+  retry_recv_message_pre_init();
+  retry_server_pushback_delay_pre_init();
+  retry_server_pushback_disabled_pre_init();
+  retry_streaming_pre_init();
+  retry_streaming_after_commit_pre_init();
+  retry_streaming_succeeds_before_replay_finished_pre_init();
+  retry_throttled_pre_init();
+  retry_too_many_attempts_pre_init();
   server_finishes_request_pre_init();
   shutdown_finishes_calls_pre_init();
   shutdown_finishes_tags_pre_init();
@@ -269,6 +314,21 @@
     request_with_flags(config);
     request_with_payload(config);
     resource_quota_server(config);
+    retry(config);
+    retry_cancellation(config);
+    retry_disabled(config);
+    retry_exceeds_buffer_size_in_initial_batch(config);
+    retry_exceeds_buffer_size_in_subsequent_batch(config);
+    retry_non_retriable_status(config);
+    retry_recv_initial_metadata(config);
+    retry_recv_message(config);
+    retry_server_pushback_delay(config);
+    retry_server_pushback_disabled(config);
+    retry_streaming(config);
+    retry_streaming_after_commit(config);
+    retry_streaming_succeeds_before_replay_finished(config);
+    retry_throttled(config);
+    retry_too_many_attempts(config);
     server_finishes_request(config);
     shutdown_finishes_calls(config);
     shutdown_finishes_tags(config);
@@ -468,6 +528,66 @@
       resource_quota_server(config);
       continue;
     }
+    if (0 == strcmp("retry", argv[i])) {
+      retry(config);
+      continue;
+    }
+    if (0 == strcmp("retry_cancellation", argv[i])) {
+      retry_cancellation(config);
+      continue;
+    }
+    if (0 == strcmp("retry_disabled", argv[i])) {
+      retry_disabled(config);
+      continue;
+    }
+    if (0 == strcmp("retry_exceeds_buffer_size_in_initial_batch", argv[i])) {
+      retry_exceeds_buffer_size_in_initial_batch(config);
+      continue;
+    }
+    if (0 == strcmp("retry_exceeds_buffer_size_in_subsequent_batch", argv[i])) {
+      retry_exceeds_buffer_size_in_subsequent_batch(config);
+      continue;
+    }
+    if (0 == strcmp("retry_non_retriable_status", argv[i])) {
+      retry_non_retriable_status(config);
+      continue;
+    }
+    if (0 == strcmp("retry_recv_initial_metadata", argv[i])) {
+      retry_recv_initial_metadata(config);
+      continue;
+    }
+    if (0 == strcmp("retry_recv_message", argv[i])) {
+      retry_recv_message(config);
+      continue;
+    }
+    if (0 == strcmp("retry_server_pushback_delay", argv[i])) {
+      retry_server_pushback_delay(config);
+      continue;
+    }
+    if (0 == strcmp("retry_server_pushback_disabled", argv[i])) {
+      retry_server_pushback_disabled(config);
+      continue;
+    }
+    if (0 == strcmp("retry_streaming", argv[i])) {
+      retry_streaming(config);
+      continue;
+    }
+    if (0 == strcmp("retry_streaming_after_commit", argv[i])) {
+      retry_streaming_after_commit(config);
+      continue;
+    }
+    if (0 == strcmp("retry_streaming_succeeds_before_replay_finished", argv[i])) {
+      retry_streaming_succeeds_before_replay_finished(config);
+      continue;
+    }
+    if (0 == strcmp("retry_throttled", argv[i])) {
+      retry_throttled(config);
+      continue;
+    }
+    if (0 == strcmp("retry_too_many_attempts", argv[i])) {
+      retry_too_many_attempts(config);
+      continue;
+    }
     if (0 == strcmp("server_finishes_request", argv[i])) {
       server_finishes_request(config);
       continue;
diff --git a/test/core/end2end/fixtures/h2_census.cc b/test/core/end2end/fixtures/h2_census.cc
index 75c80aa..b3b4171 100644
--- a/test/core/end2end/fixtures/h2_census.cc
+++ b/test/core/end2end/fixtures/h2_census.cc
@@ -21,16 +21,15 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
+
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
diff --git a/test/core/end2end/fixtures/h2_compress.cc b/test/core/end2end/fixtures/h2_compress.cc
index 3625afe..565c96c 100644
--- a/test/core/end2end/fixtures/h2_compress.cc
+++ b/test/core/end2end/fixtures/h2_compress.cc
@@ -21,16 +21,15 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
+
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
@@ -70,7 +69,7 @@
     grpc_channel_args_destroy(ffd->client_args_compression);
   }
   ffd->client_args_compression = grpc_channel_args_set_compression_algorithm(
-      client_args, GRPC_COMPRESS_MESSAGE_GZIP);
+      client_args, GRPC_COMPRESS_GZIP);
   f->client = grpc_insecure_channel_create(
       ffd->localaddr, ffd->client_args_compression, nullptr);
 }
@@ -84,7 +83,7 @@
     grpc_channel_args_destroy(ffd->server_args_compression);
   }
   ffd->server_args_compression = grpc_channel_args_set_compression_algorithm(
-      server_args, GRPC_COMPRESS_MESSAGE_GZIP);
+      server_args, GRPC_COMPRESS_GZIP);
   if (f->server) {
     grpc_server_destroy(f->server);
   }
diff --git a/test/core/end2end/fixtures/h2_fakesec.cc b/test/core/end2end/fixtures/h2_fakesec.cc
index 87d4668..bbf65fc 100644
--- a/test/core/end2end/fixtures/h2_fakesec.cc
+++ b/test/core/end2end/fixtures/h2_fakesec.cc
@@ -22,9 +22,10 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
+
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/security/credentials/fake/fake_credentials.h"
 #include "test/core/end2end/data/ssl_test_data.h"
 #include "test/core/util/port.h"
diff --git a/test/core/end2end/fixtures/h2_full+pipe.cc b/test/core/end2end/fixtures/h2_full+pipe.cc
index b080591..ed173c1 100644
--- a/test/core/end2end/fixtures/h2_full+pipe.cc
+++ b/test/core/end2end/fixtures/h2_full+pipe.cc
@@ -26,15 +26,14 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
+
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/iomgr/wakeup_fd_posix.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
diff --git a/test/core/end2end/fixtures/h2_full+trace.cc b/test/core/end2end/fixtures/h2_full+trace.cc
index 7104fbc..afb86ea 100644
--- a/test/core/end2end/fixtures/h2_full+trace.cc
+++ b/test/core/end2end/fixtures/h2_full+trace.cc
@@ -26,16 +26,15 @@
 #endif
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
+
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
diff --git a/test/core/end2end/fixtures/h2_full+workarounds.cc b/test/core/end2end/fixtures/h2_full+workarounds.cc
index 237841d..bd9ddff 100644
--- a/test/core/end2end/fixtures/h2_full+workarounds.cc
+++ b/test/core/end2end/fixtures/h2_full+workarounds.cc
@@ -21,16 +21,16 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
+
 #include <grpc/support/workaround_list.h>
+
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
diff --git a/test/core/end2end/fixtures/h2_full.cc b/test/core/end2end/fixtures/h2_full.cc
index 6d15c28..ca61ec8 100644
--- a/test/core/end2end/fixtures/h2_full.cc
+++ b/test/core/end2end/fixtures/h2_full.cc
@@ -21,15 +21,14 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
+
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
diff --git a/test/core/end2end/fixtures/h2_http_proxy.cc b/test/core/end2end/fixtures/h2_http_proxy.cc
index e8e81f0..90d0627 100644
--- a/test/core/end2end/fixtures/h2_http_proxy.cc
+++ b/test/core/end2end/fixtures/h2_http_proxy.cc
@@ -21,17 +21,16 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
+
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/end2end/fixtures/http_proxy_fixture.h"
@@ -72,11 +71,12 @@
   /* If testing for proxy auth, add credentials to proxy uri */
   const grpc_arg* proxy_auth_arg =
       grpc_channel_args_find(client_args, GRPC_ARG_HTTP_PROXY_AUTH_CREDS);
-  if (proxy_auth_arg == nullptr || proxy_auth_arg->type != GRPC_ARG_STRING) {
+  const char* proxy_auth_str = grpc_channel_arg_get_string(proxy_auth_arg);
+  if (proxy_auth_str == nullptr) {
     gpr_asprintf(&proxy_uri, "http://%s",
                  grpc_end2end_http_proxy_get_proxy_name(ffd->proxy));
   } else {
-    gpr_asprintf(&proxy_uri, "http://%s@%s", proxy_auth_arg->value.string,
+    gpr_asprintf(&proxy_uri, "http://%s@%s", proxy_auth_str,
                  grpc_end2end_http_proxy_get_proxy_name(ffd->proxy));
   }
   gpr_setenv("http_proxy", proxy_uri);
diff --git a/test/core/end2end/fixtures/h2_load_reporting.cc b/test/core/end2end/fixtures/h2_load_reporting.cc
index fda5f4b..ec9eedb 100644
--- a/test/core/end2end/fixtures/h2_load_reporting.cc
+++ b/test/core/end2end/fixtures/h2_load_reporting.cc
@@ -21,17 +21,16 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
+
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/filters/load_reporting/server_load_reporting_plugin.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
diff --git a/test/core/end2end/fixtures/h2_oauth2.cc b/test/core/end2end/fixtures/h2_oauth2.cc
index 5fed443..9453f2f 100644
--- a/test/core/end2end/fixtures/h2_oauth2.cc
+++ b/test/core/end2end/fixtures/h2_oauth2.cc
@@ -22,9 +22,10 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
+
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/security/credentials/credentials.h"
 #include "test/core/end2end/data/ssl_test_data.h"
@@ -65,7 +66,7 @@
   test_processor_state* s;
 
   GPR_ASSERT(state != nullptr);
-  s = (test_processor_state*)state;
+  s = static_cast<test_processor_state*>(state);
   GPR_ASSERT(s->pseudo_refcount == 1);
   GPR_ASSERT(oauth2 != nullptr);
   grpc_auth_context_add_cstring_property(ctx, client_identity_property_name,
@@ -83,7 +84,7 @@
       find_metadata(md, md_count, "authorization", oauth2_md);
   test_processor_state* s;
   GPR_ASSERT(state != nullptr);
-  s = (test_processor_state*)state;
+  s = static_cast<test_processor_state*>(state);
   GPR_ASSERT(s->pseudo_refcount == 1);
   GPR_ASSERT(oauth2 != nullptr);
   cb(user_data, oauth2, 1, nullptr, 0, GRPC_STATUS_UNAUTHENTICATED, nullptr);
@@ -176,7 +177,7 @@
 }
 
 static void processor_destroy(void* state) {
-  test_processor_state* s = (test_processor_state*)state;
+  test_processor_state* s = static_cast<test_processor_state*>(state);
   GPR_ASSERT((s->pseudo_refcount--) == 1);
   gpr_free(s);
 }
diff --git a/test/core/end2end/fixtures/h2_proxy.cc b/test/core/end2end/fixtures/h2_proxy.cc
index 295654c..c97188f 100644
--- a/test/core/end2end/fixtures/h2_proxy.cc
+++ b/test/core/end2end/fixtures/h2_proxy.cc
@@ -21,15 +21,14 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
+
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/end2end/fixtures/proxy.h"
@@ -49,7 +48,17 @@
 
 static grpc_channel* create_proxy_client(const char* target,
                                          grpc_channel_args* client_args) {
-  return grpc_insecure_channel_create(target, client_args, nullptr);
+  // Disable retries in proxy client.
+  grpc_arg arg;
+  arg.type = GRPC_ARG_INTEGER;
+  arg.key = const_cast<char*>(GRPC_ARG_ENABLE_RETRIES);
+  arg.value.integer = 0;
+  grpc_channel_args* new_args =
+      grpc_channel_args_copy_and_add(client_args, &arg, 1);
+  grpc_channel* channel =
+      grpc_insecure_channel_create(target, new_args, nullptr);
+  grpc_channel_args_destroy(new_args);
+  return channel;
 }
 
 static const grpc_end2end_proxy_def proxy_def = {create_proxy_server,
diff --git a/test/core/end2end/fixtures/h2_sockpair+trace.cc b/test/core/end2end/fixtures/h2_sockpair+trace.cc
index 236780b..d539dda 100644
--- a/test/core/end2end/fixtures/h2_sockpair+trace.cc
+++ b/test/core/end2end/fixtures/h2_sockpair+trace.cc
@@ -28,8 +28,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
+
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/http/client/http_client_filter.h"
 #include "src/core/ext/filters/http/message_compress/message_compress_filter.h"
diff --git a/test/core/end2end/fixtures/h2_sockpair.cc b/test/core/end2end/fixtures/h2_sockpair.cc
index b68279f..75f6402 100644
--- a/test/core/end2end/fixtures/h2_sockpair.cc
+++ b/test/core/end2end/fixtures/h2_sockpair.cc
@@ -23,8 +23,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
+
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/http/client/http_client_filter.h"
 #include "src/core/ext/filters/http/message_compress/message_compress_filter.h"
diff --git a/test/core/end2end/fixtures/h2_sockpair_1byte.cc b/test/core/end2end/fixtures/h2_sockpair_1byte.cc
index 350be13..9296319 100644
--- a/test/core/end2end/fixtures/h2_sockpair_1byte.cc
+++ b/test/core/end2end/fixtures/h2_sockpair_1byte.cc
@@ -23,8 +23,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
+
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/http/client/http_client_filter.h"
 #include "src/core/ext/filters/http/message_compress/message_compress_filter.h"
diff --git a/test/core/end2end/fixtures/h2_ssl.cc b/test/core/end2end/fixtures/h2_ssl.cc
index 8c5c8a2..bbcc88e 100644
--- a/test/core/end2end/fixtures/h2_ssl.cc
+++ b/test/core/end2end/fixtures/h2_ssl.cc
@@ -22,11 +22,11 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gpr/tmpfile.h"
 #include "src/core/lib/security/credentials/credentials.h"
diff --git a/test/core/end2end/fixtures/h2_ssl_proxy.cc b/test/core/end2end/fixtures/h2_ssl_proxy.cc
index 3f0646c..6b0b891 100644
--- a/test/core/end2end/fixtures/h2_ssl_proxy.cc
+++ b/test/core/end2end/fixtures/h2_ssl_proxy.cc
@@ -22,11 +22,11 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gpr/tmpfile.h"
 #include "src/core/lib/security/credentials/credentials.h"
diff --git a/test/core/end2end/fixtures/h2_uds.cc b/test/core/end2end/fixtures/h2_uds.cc
index 1944dd8..1b081f9 100644
--- a/test/core/end2end/fixtures/h2_uds.cc
+++ b/test/core/end2end/fixtures/h2_uds.cc
@@ -23,16 +23,15 @@
 #include <unistd.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
+
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
diff --git a/test/core/end2end/fixtures/http_proxy_fixture.cc b/test/core/end2end/fixtures/http_proxy_fixture.cc
index 8ec97df..f02fa9d 100644
--- a/test/core/end2end/fixtures/http_proxy_fixture.cc
+++ b/test/core/end2end/fixtures/http_proxy_fixture.cc
@@ -26,15 +26,14 @@
 #include <grpc/slice_buffer.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/atm.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/http/parser.h"
 #include "src/core/lib/iomgr/closure.h"
 #include "src/core/lib/iomgr/combiner.h"
@@ -54,7 +53,7 @@
 
 struct grpc_end2end_http_proxy {
   char* proxy_name;
-  gpr_thd_id thd;
+  grpc_core::Thread thd;
   grpc_tcp_server* server;
   grpc_channel_args* channel_args;
   gpr_mu* mu;
@@ -186,7 +185,7 @@
 
 // Callback for writing proxy data to the client.
 static void on_client_write_done(void* arg, grpc_error* error) {
-  proxy_connection* conn = (proxy_connection*)arg;
+  proxy_connection* conn = static_cast<proxy_connection*>(arg);
   conn->client_is_writing = false;
   if (error != GRPC_ERROR_NONE) {
     proxy_connection_failed(conn, CLIENT_WRITE_FAILED,
@@ -211,7 +210,7 @@
 
 // Callback for writing proxy data to the backend server.
 static void on_server_write_done(void* arg, grpc_error* error) {
-  proxy_connection* conn = (proxy_connection*)arg;
+  proxy_connection* conn = static_cast<proxy_connection*>(arg);
   conn->server_is_writing = false;
   if (error != GRPC_ERROR_NONE) {
     proxy_connection_failed(conn, SERVER_WRITE_FAILED,
@@ -237,7 +236,7 @@
 // Callback for reading data from the client, which will be proxied to
 // the backend server.
 static void on_client_read_done(void* arg, grpc_error* error) {
-  proxy_connection* conn = (proxy_connection*)arg;
+  proxy_connection* conn = static_cast<proxy_connection*>(arg);
   if (error != GRPC_ERROR_NONE) {
     proxy_connection_failed(conn, CLIENT_READ_FAILED, "HTTP proxy client read",
                             GRPC_ERROR_REF(error));
@@ -268,7 +267,7 @@
 // Callback for reading data from the backend server, which will be
 // proxied to the client.
 static void on_server_read_done(void* arg, grpc_error* error) {
-  proxy_connection* conn = (proxy_connection*)arg;
+  proxy_connection* conn = static_cast<proxy_connection*>(arg);
   if (error != GRPC_ERROR_NONE) {
     proxy_connection_failed(conn, SERVER_READ_FAILED, "HTTP proxy server read",
                             GRPC_ERROR_REF(error));
@@ -298,7 +297,7 @@
 
 // Callback to write the HTTP response for the CONNECT request.
 static void on_write_response_done(void* arg, grpc_error* error) {
-  proxy_connection* conn = (proxy_connection*)arg;
+  proxy_connection* conn = static_cast<proxy_connection*>(arg);
   conn->client_is_writing = false;
   if (error != GRPC_ERROR_NONE) {
     proxy_connection_failed(conn, SETUP_FAILED, "HTTP proxy write response",
@@ -322,7 +321,7 @@
 // Callback to connect to the backend server specified by the HTTP
 // CONNECT request.
 static void on_server_connect_done(void* arg, grpc_error* error) {
-  proxy_connection* conn = (proxy_connection*)arg;
+  proxy_connection* conn = static_cast<proxy_connection*>(arg);
   if (error != GRPC_ERROR_NONE) {
     // TODO(roth): Technically, in this case, we should handle the error
     // by returning an HTTP response to the client indicating that the
@@ -371,7 +370,7 @@
 // of this test code, it's fine to pretend this is a client-side error,
 // which will cause the client connection to be dropped.
 static void on_read_request_done(void* arg, grpc_error* error) {
-  proxy_connection* conn = (proxy_connection*)arg;
+  proxy_connection* conn = static_cast<proxy_connection*>(arg);
   gpr_log(GPR_DEBUG, "on_read_request_done: %p %s", conn,
           grpc_error_string(error));
   if (error != GRPC_ERROR_NONE) {
@@ -414,12 +413,13 @@
   // If proxy auth is being used, check if the header is present and as expected
   const grpc_arg* proxy_auth_arg = grpc_channel_args_find(
       conn->proxy->channel_args, GRPC_ARG_HTTP_PROXY_AUTH_CREDS);
-  if (proxy_auth_arg != nullptr && proxy_auth_arg->type == GRPC_ARG_STRING) {
+  char* proxy_auth_str = grpc_channel_arg_get_string(proxy_auth_arg);
+  if (proxy_auth_str != nullptr) {
     bool client_authenticated = false;
     for (size_t i = 0; i < conn->http_request.hdr_count; i++) {
       if (strcmp(conn->http_request.hdrs[i].key, "Proxy-Authorization") == 0) {
         client_authenticated = proxy_auth_header_matches(
-            conn->http_request.hdrs[i].value, proxy_auth_arg->value.string);
+            conn->http_request.hdrs[i].value, proxy_auth_str);
         break;
       }
     }
@@ -457,9 +457,10 @@
                       grpc_pollset* accepting_pollset,
                       grpc_tcp_server_acceptor* acceptor) {
   gpr_free(acceptor);
-  grpc_end2end_http_proxy* proxy = (grpc_end2end_http_proxy*)arg;
+  grpc_end2end_http_proxy* proxy = static_cast<grpc_end2end_http_proxy*>(arg);
   // Instantiate proxy_connection.
-  proxy_connection* conn = (proxy_connection*)gpr_zalloc(sizeof(*conn));
+  proxy_connection* conn =
+      static_cast<proxy_connection*>(gpr_zalloc(sizeof(*conn)));
   gpr_ref(&proxy->users);
   conn->client_endpoint = endpoint;
   conn->proxy = proxy;
@@ -500,7 +501,7 @@
 //
 
 static void thread_main(void* arg) {
-  grpc_end2end_http_proxy* proxy = (grpc_end2end_http_proxy*)arg;
+  grpc_end2end_http_proxy* proxy = static_cast<grpc_end2end_http_proxy*>(arg);
   grpc_core::ExecCtx exec_ctx;
   do {
     gpr_ref(&proxy->users);
@@ -519,7 +520,7 @@
     grpc_channel_args* args) {
   grpc_core::ExecCtx exec_ctx;
   grpc_end2end_http_proxy* proxy =
-      (grpc_end2end_http_proxy*)gpr_malloc(sizeof(*proxy));
+      static_cast<grpc_end2end_http_proxy*>(gpr_malloc(sizeof(*proxy)));
   memset(proxy, 0, sizeof(*proxy));
   proxy->combiner = grpc_combiner_create();
   gpr_ref_init(&proxy->users, 1);
@@ -534,29 +535,28 @@
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   // Bind to port.
   grpc_resolved_address resolved_addr;
-  struct sockaddr_in* addr = (struct sockaddr_in*)resolved_addr.addr;
+  grpc_sockaddr_in* addr =
+      reinterpret_cast<grpc_sockaddr_in*>(resolved_addr.addr);
   memset(&resolved_addr, 0, sizeof(resolved_addr));
-  addr->sin_family = AF_INET;
+  addr->sin_family = GRPC_AF_INET;
   grpc_sockaddr_set_port(&resolved_addr, proxy_port);
   int port;
   error = grpc_tcp_server_add_port(proxy->server, &resolved_addr, &port);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   GPR_ASSERT(port == proxy_port);
   // Start server.
-  proxy->pollset = (grpc_pollset*)gpr_zalloc(grpc_pollset_size());
+  proxy->pollset = static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
   grpc_pollset_init(proxy->pollset, &proxy->mu);
   grpc_tcp_server_start(proxy->server, &proxy->pollset, 1, on_accept, proxy);
 
   // Start proxy thread.
-  gpr_thd_options opt = gpr_thd_options_default();
-  gpr_thd_options_set_joinable(&opt);
-  GPR_ASSERT(
-      gpr_thd_new(&proxy->thd, "grpc_http_proxy", thread_main, proxy, &opt));
+  proxy->thd = grpc_core::Thread("grpc_http_proxy", thread_main, proxy);
+  proxy->thd.Start();
   return proxy;
 }
 
 static void destroy_pollset(void* arg, grpc_error* error) {
-  grpc_pollset* pollset = (grpc_pollset*)arg;
+  grpc_pollset* pollset = static_cast<grpc_pollset*>(arg);
   grpc_pollset_destroy(pollset);
   gpr_free(pollset);
 }
@@ -564,7 +564,7 @@
 void grpc_end2end_http_proxy_destroy(grpc_end2end_http_proxy* proxy) {
   gpr_unref(&proxy->users);  // Signal proxy thread to shutdown.
   grpc_core::ExecCtx exec_ctx;
-  gpr_thd_join(proxy->thd);
+  proxy->thd.Join();
   grpc_tcp_server_shutdown_listeners(proxy->server);
   grpc_tcp_server_unref(proxy->server);
   gpr_free(proxy->proxy_name);
diff --git a/test/core/end2end/fixtures/inproc.cc b/test/core/end2end/fixtures/inproc.cc
index b748fbf..d47de42 100644
--- a/test/core/end2end/fixtures/inproc.cc
+++ b/test/core/end2end/fixtures/inproc.cc
@@ -21,15 +21,14 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
+
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/inproc/inproc_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
diff --git a/test/core/end2end/fixtures/proxy.cc b/test/core/end2end/fixtures/proxy.cc
index b1698c8..042c858 100644
--- a/test/core/end2end/fixtures/proxy.cc
+++ b/test/core/end2end/fixtures/proxy.cc
@@ -21,16 +21,16 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
 
+#include "src/core/lib/gpr/host_port.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "test/core/util/port.h"
 
 struct grpc_end2end_proxy {
-  gpr_thd_id thd;
+  grpc_core::Thread thd;
   char* proxy_port;
   char* server_port;
   grpc_completion_queue* cq;
@@ -76,11 +76,11 @@
 grpc_end2end_proxy* grpc_end2end_proxy_create(const grpc_end2end_proxy_def* def,
                                               grpc_channel_args* client_args,
                                               grpc_channel_args* server_args) {
-  gpr_thd_options opt = gpr_thd_options_default();
   int proxy_port = grpc_pick_unused_port_or_die();
   int server_port = grpc_pick_unused_port_or_die();
 
-  grpc_end2end_proxy* proxy = (grpc_end2end_proxy*)gpr_malloc(sizeof(*proxy));
+  grpc_end2end_proxy* proxy =
+      static_cast<grpc_end2end_proxy*>(gpr_malloc(sizeof(*proxy)));
   memset(proxy, 0, sizeof(*proxy));
 
   gpr_join_host_port(&proxy->proxy_port, "localhost", proxy_port);
@@ -97,9 +97,8 @@
   grpc_server_start(proxy->server);
 
   grpc_call_details_init(&proxy->new_call_details);
-  gpr_thd_options_set_joinable(&opt);
-  GPR_ASSERT(
-      gpr_thd_new(&proxy->thd, "grpc_end2end_proxy", thread_main, proxy, &opt));
+  proxy->thd = grpc_core::Thread("grpc_end2end_proxy", thread_main, proxy);
+  proxy->thd.Start();
 
   request_call(proxy);
 
@@ -107,14 +106,14 @@
 }
 
 static closure* new_closure(void (*func)(void* arg, int success), void* arg) {
-  closure* cl = (closure*)gpr_malloc(sizeof(*cl));
+  closure* cl = static_cast<closure*>(gpr_malloc(sizeof(*cl)));
   cl->func = func;
   cl->arg = arg;
   return cl;
 }
 
 static void shutdown_complete(void* arg, int success) {
-  grpc_end2end_proxy* proxy = (grpc_end2end_proxy*)arg;
+  grpc_end2end_proxy* proxy = static_cast<grpc_end2end_proxy*>(arg);
   proxy->shutdown = 1;
   grpc_completion_queue_shutdown(proxy->cq);
 }
@@ -122,7 +121,7 @@
 void grpc_end2end_proxy_destroy(grpc_end2end_proxy* proxy) {
   grpc_server_shutdown_and_notify(proxy->server, proxy->cq,
                                   new_closure(shutdown_complete, proxy));
-  gpr_thd_join(proxy->thd);
+  proxy->thd.Join();
   gpr_free(proxy->proxy_port);
   gpr_free(proxy->server_port);
   grpc_server_destroy(proxy->server);
@@ -147,12 +146,12 @@
 static void refpc(proxy_call* pc, const char* reason) { gpr_ref(&pc->refs); }
 
 static void on_c2p_sent_initial_metadata(void* arg, int success) {
-  proxy_call* pc = (proxy_call*)arg;
+  proxy_call* pc = static_cast<proxy_call*>(arg);
   unrefpc(pc, "on_c2p_sent_initial_metadata");
 }
 
 static void on_p2s_recv_initial_metadata(void* arg, int success) {
-  proxy_call* pc = (proxy_call*)arg;
+  proxy_call* pc = static_cast<proxy_call*>(arg);
   grpc_op op;
   grpc_call_error err;
 
@@ -174,14 +173,14 @@
 }
 
 static void on_p2s_sent_initial_metadata(void* arg, int success) {
-  proxy_call* pc = (proxy_call*)arg;
+  proxy_call* pc = static_cast<proxy_call*>(arg);
   unrefpc(pc, "on_p2s_sent_initial_metadata");
 }
 
 static void on_c2p_recv_msg(void* arg, int success);
 
 static void on_p2s_sent_message(void* arg, int success) {
-  proxy_call* pc = (proxy_call*)arg;
+  proxy_call* pc = static_cast<proxy_call*>(arg);
   grpc_op op;
   grpc_call_error err;
 
@@ -201,12 +200,12 @@
 }
 
 static void on_p2s_sent_close(void* arg, int success) {
-  proxy_call* pc = (proxy_call*)arg;
+  proxy_call* pc = static_cast<proxy_call*>(arg);
   unrefpc(pc, "on_p2s_sent_close");
 }
 
 static void on_c2p_recv_msg(void* arg, int success) {
-  proxy_call* pc = (proxy_call*)arg;
+  proxy_call* pc = static_cast<proxy_call*>(arg);
   grpc_op op;
   grpc_call_error err;
 
@@ -241,7 +240,7 @@
 static void on_p2s_recv_msg(void* arg, int success);
 
 static void on_c2p_sent_message(void* arg, int success) {
-  proxy_call* pc = (proxy_call*)arg;
+  proxy_call* pc = static_cast<proxy_call*>(arg);
   grpc_op op;
   grpc_call_error err;
 
@@ -261,7 +260,7 @@
 }
 
 static void on_p2s_recv_msg(void* arg, int success) {
-  proxy_call* pc = (proxy_call*)arg;
+  proxy_call* pc = static_cast<proxy_call*>(arg);
   grpc_op op;
   grpc_call_error err;
 
@@ -281,12 +280,12 @@
 }
 
 static void on_c2p_sent_status(void* arg, int success) {
-  proxy_call* pc = (proxy_call*)arg;
+  proxy_call* pc = static_cast<proxy_call*>(arg);
   unrefpc(pc, "on_c2p_sent_status");
 }
 
 static void on_p2s_status(void* arg, int success) {
-  proxy_call* pc = (proxy_call*)arg;
+  proxy_call* pc = static_cast<proxy_call*>(arg);
   grpc_op op;
   grpc_call_error err;
 
@@ -311,18 +310,18 @@
 }
 
 static void on_c2p_closed(void* arg, int success) {
-  proxy_call* pc = (proxy_call*)arg;
+  proxy_call* pc = static_cast<proxy_call*>(arg);
   unrefpc(pc, "on_c2p_closed");
 }
 
 static void on_new_call(void* arg, int success) {
-  grpc_end2end_proxy* proxy = (grpc_end2end_proxy*)arg;
+  grpc_end2end_proxy* proxy = static_cast<grpc_end2end_proxy*>(arg);
   grpc_call_error err;
 
   if (success) {
     grpc_op op;
     memset(&op, 0, sizeof(op));
-    proxy_call* pc = (proxy_call*)gpr_malloc(sizeof(*pc));
+    proxy_call* pc = static_cast<proxy_call*>(gpr_malloc(sizeof(*pc)));
     memset(pc, 0, sizeof(*pc));
     pc->proxy = proxy;
     GPR_SWAP(grpc_metadata_array, pc->c2p_initial_metadata,
@@ -412,7 +411,7 @@
 }
 
 static void thread_main(void* arg) {
-  grpc_end2end_proxy* proxy = (grpc_end2end_proxy*)arg;
+  grpc_end2end_proxy* proxy = static_cast<grpc_end2end_proxy*>(arg);
   closure* cl;
   for (;;) {
     grpc_event ev = grpc_completion_queue_next(
@@ -424,7 +423,7 @@
       case GRPC_QUEUE_SHUTDOWN:
         return;
       case GRPC_OP_COMPLETE:
-        cl = (closure*)ev.tag;
+        cl = static_cast<closure*>(ev.tag);
         cl->func(cl->arg, ev.success);
         gpr_free(cl);
         break;
diff --git a/test/core/end2end/fuzzers/BUILD b/test/core/end2end/fuzzers/BUILD
index d33e2b0..c12cfc6 100644
--- a/test/core/end2end/fuzzers/BUILD
+++ b/test/core/end2end/fuzzers/BUILD
@@ -25,6 +25,8 @@
     srcs = ["api_fuzzer.cc"],
     language = "C++",
     corpus = "api_fuzzer_corpus",
+    size = "enormous",
+    timeout = "eternal",
     deps = [
         "//:gpr",
         "//:grpc",
diff --git a/test/core/end2end/fuzzers/api_fuzzer.cc b/test/core/end2end/fuzzers/api_fuzzer.cc
index 14c1555..9ace7d0 100644
--- a/test/core/end2end/fuzzers/api_fuzzer.cc
+++ b/test/core/end2end/fuzzers/api_fuzzer.cc
@@ -93,7 +93,7 @@
       cap = GPR_MAX(3 * cap / 2, cap + 8);
       str = static_cast<char*>(gpr_realloc(str, cap));
     }
-    c = (char)next_byte(inp);
+    c = static_cast<char>(next_byte(inp));
     str[sz++] = c;
   } while (c != 0 && c != 1);
   if (special != nullptr) {
@@ -116,7 +116,7 @@
   }
   *buffer = static_cast<char*>(gpr_malloc(*length));
   for (size_t i = 0; i < *length; i++) {
-    (*buffer)[i] = (char)next_byte(inp);
+    (*buffer)[i] = static_cast<char>(next_byte(inp));
   }
 }
 
@@ -192,7 +192,9 @@
   return out;
 }
 
-static int read_int(input_stream* inp) { return (int)read_uint32(inp); }
+static int read_int(input_stream* inp) {
+  return static_cast<int>(read_uint32(inp));
+}
 
 static grpc_channel_args* read_args(input_stream* inp) {
   size_t n = next_byte(inp);
@@ -424,6 +426,9 @@
       GRPC_CLOSURE_CREATE(finish_resolve, r, grpc_schedule_on_exec_ctx));
 }
 
+static grpc_address_resolver_vtable fuzzer_resolver = {my_resolve_address,
+                                                       nullptr};
+
 grpc_ares_request* my_dns_lookup_ares(const char* dns_server, const char* addr,
                                       const char* default_port,
                                       grpc_pollset_set* interested_parties,
@@ -445,12 +450,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // client connection
 
-// defined in tcp_client_posix.c
-extern void (*grpc_tcp_client_connect_impl)(
-    grpc_closure* closure, grpc_endpoint** ep,
-    grpc_pollset_set* interested_parties, const grpc_channel_args* channel_args,
-    const grpc_resolved_address* addr, grpc_millis deadline);
-
 static void sched_connect(grpc_closure* closure, grpc_endpoint** ep,
                           gpr_timespec deadline);
 
@@ -511,6 +510,8 @@
                 grpc_millis_to_timespec(deadline, GPR_CLOCK_MONOTONIC));
 }
 
+grpc_tcp_client_vtable fuzz_tcp_client_vtable = {my_tcp_client_connect};
+
 ////////////////////////////////////////////////////////////////////////////////
 // test driver
 
@@ -529,10 +530,12 @@
 
 static void assert_success_and_decrement(void* counter, bool success) {
   GPR_ASSERT(success);
-  --*(int*)counter;
+  --*static_cast<int*>(counter);
 }
 
-static void decrement(void* counter, bool success) { --*(int*)counter; }
+static void decrement(void* counter, bool success) {
+  --*static_cast<int*>(counter);
+}
 
 typedef struct connectivity_watch {
   int* counter;
@@ -576,6 +579,7 @@
   grpc_slice recv_status_details;
   int cancelled;
   int pending_ops;
+  bool sent_initial_metadata;
   grpc_call_details call_details;
   grpc_byte_buffer* send_message;
   // starts at 0, individual flags from DONE_FLAG_xxx are set
@@ -748,7 +752,7 @@
   if (squelch && grpc_trace_fuzzer == nullptr) gpr_set_log_function(dont_log);
   gpr_free(grpc_trace_fuzzer);
   input_stream inp = {data, data + size};
-  grpc_tcp_client_connect_impl = my_tcp_client_connect;
+  grpc_set_tcp_client_impl(&fuzz_tcp_client_vtable);
   gpr_now_impl = now_impl;
   grpc_init();
   grpc_timer_manager_set_threading(false);
@@ -756,7 +760,7 @@
     grpc_core::ExecCtx exec_ctx;
     grpc_executor_set_threading(false);
   }
-  grpc_resolve_address = my_resolve_address;
+  grpc_set_resolver_impl(&fuzzer_resolver);
   grpc_dns_lookup_ares = my_dns_lookup_ares;
 
   GPR_ASSERT(g_channel == nullptr);
@@ -1022,11 +1026,16 @@
               ok = false;
               break;
             case GRPC_OP_SEND_INITIAL_METADATA:
-              op->op = GRPC_OP_SEND_INITIAL_METADATA;
-              has_ops |= 1 << GRPC_OP_SEND_INITIAL_METADATA;
-              read_metadata(&inp, &op->data.send_initial_metadata.count,
-                            &op->data.send_initial_metadata.metadata,
-                            g_active_call);
+              if (g_active_call->sent_initial_metadata) {
+                ok = false;
+              } else {
+                g_active_call->sent_initial_metadata = true;
+                op->op = GRPC_OP_SEND_INITIAL_METADATA;
+                has_ops |= 1 << GRPC_OP_SEND_INITIAL_METADATA;
+                read_metadata(&inp, &op->data.send_initial_metadata.count,
+                              &op->data.send_initial_metadata.metadata,
+                              g_active_call);
+              }
               break;
             case GRPC_OP_SEND_MESSAGE:
               op->op = GRPC_OP_SEND_MESSAGE;
@@ -1063,9 +1072,14 @@
                   &g_active_call->recv_initial_metadata;
               break;
             case GRPC_OP_RECV_MESSAGE:
-              op->op = GRPC_OP_RECV_MESSAGE;
-              has_ops |= 1 << GRPC_OP_RECV_MESSAGE;
-              op->data.recv_message.recv_message = &g_active_call->recv_message;
+              if (g_active_call->done_flags & DONE_FLAG_CALL_CLOSED) {
+                ok = false;
+              } else {
+                op->op = GRPC_OP_RECV_MESSAGE;
+                has_ops |= 1 << GRPC_OP_RECV_MESSAGE;
+                op->data.recv_message.recv_message =
+                    &g_active_call->recv_message;
+              }
               break;
             case GRPC_OP_RECV_STATUS_ON_CLIENT:
               op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-minimized-api_fuzzer-4774951120797696 b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-minimized-api_fuzzer-4774951120797696
new file mode 100644
index 0000000..3610316
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-minimized-api_fuzzer-4774951120797696
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-minimized-api_fuzzer-4829913342279680 b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-minimized-api_fuzzer-4829913342279680
new file mode 100644
index 0000000..33bf280
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-minimized-api_fuzzer-4829913342279680
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-minimized-api_fuzzer-5632636438446080 b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-minimized-api_fuzzer-5632636438446080
new file mode 100644
index 0000000..4f995ac
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-minimized-api_fuzzer-5632636438446080
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-minimized-api_fuzzer-6192640044302336 b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-minimized-api_fuzzer-6192640044302336
new file mode 100644
index 0000000..07b4b33
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-minimized-api_fuzzer-6192640044302336
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/poc-2d730ebd78b3052e4367ad0d485208dcb205482cbcd6289f17907989b8de1fba b/test/core/end2end/fuzzers/api_fuzzer_corpus/poc-2d730ebd78b3052e4367ad0d485208dcb205482cbcd6289f17907989b8de1fba
new file mode 100644
index 0000000..89e28bb
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/poc-2d730ebd78b3052e4367ad0d485208dcb205482cbcd6289f17907989b8de1fba
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer.cc b/test/core/end2end/fuzzers/client_fuzzer.cc
index c17d581..16acf8e 100644
--- a/test/core/end2end/fuzzers/client_fuzzer.cc
+++ b/test/core/end2end/fuzzers/client_fuzzer.cc
@@ -33,7 +33,7 @@
 
 static void discard_write(grpc_slice slice) {}
 
-static void* tag(int n) { return (void*)(uintptr_t)n; }
+static void* tag(int n) { return (void*)static_cast<uintptr_t>(n); }
 
 static void dont_log(gpr_log_func_args* args) {}
 
diff --git a/test/core/end2end/fuzzers/hpack.dictionary b/test/core/end2end/fuzzers/hpack.dictionary
index a87e49e..c719d0f 100644
--- a/test/core/end2end/fuzzers/hpack.dictionary
+++ b/test/core/end2end/fuzzers/hpack.dictionary
@@ -21,22 +21,24 @@
 "\x0Auser-agent"
 "\x04host"
 "\x08lb-token"
+"\x1Agrpc-previous-rpc-attempts"
+"\x16grpc-retry-pushback-ms"
 "\x0Cgrpc-timeout"
+"\x011"
+"\x012"
+"\x013"
+"\x014"
 "\x00"
 "\x13grpc.wait_for_ready"
 "\x0Cgrpc.timeout"
 "\x1Egrpc.max_request_message_bytes"
 "\x1Fgrpc.max_response_message_bytes"
 "$/grpc.lb.v1.LoadBalancer/BalanceLoad"
-"\x0Fmessage/deflate"
-"\x0Cmessage/gzip"
+"\x07deflate"
+"\x04gzip"
 "\x0Bstream/gzip"
 "\x010"
-"\x011"
-"\x012"
 "\x08identity"
-"\x04gzip"
-"\x07deflate"
 "\x08trailers"
 "\x10application/grpc"
 "\x04POST"
diff --git a/test/core/end2end/fuzzers/server_fuzzer.cc b/test/core/end2end/fuzzers/server_fuzzer.cc
index 61c55e0..5eb83ed 100644
--- a/test/core/end2end/fuzzers/server_fuzzer.cc
+++ b/test/core/end2end/fuzzers/server_fuzzer.cc
@@ -30,8 +30,8 @@
 
 static void discard_write(grpc_slice slice) {}
 
-static void* tag(int n) { return (void*)(uintptr_t)n; }
-static int detag(void* p) { return (int)(uintptr_t)p; }
+static void* tag(int n) { return (void*)static_cast<uintptr_t>(n); }
+static int detag(void* p) { return static_cast<int>((uintptr_t)p); }
 
 static void dont_log(gpr_log_func_args* args) {}
 
diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py
index e7cf97b..4e20b0b 100755
--- a/test/core/end2end/gen_build_yaml.py
+++ b/test/core/end2end/gen_build_yaml.py
@@ -24,15 +24,24 @@
 
 FixtureOptions = collections.namedtuple(
     'FixtureOptions',
-    'fullstack includes_proxy dns_resolver name_resolution secure platforms ci_mac tracing exclude_configs exclude_iomgrs large_writes enables_compression supports_compression is_inproc is_http2 supports_proxy_auth supports_write_buffering')
+    'fullstack includes_proxy dns_resolver name_resolution secure platforms ci_mac tracing exclude_configs exclude_iomgrs large_writes enables_compression supports_compression is_inproc is_http2 supports_proxy_auth supports_write_buffering client_channel')
 default_unsecure_fixture_options = FixtureOptions(
-    True, False, True, True, False, ['windows', 'linux', 'mac', 'posix'], True, False, [], [], True, False, True, False, True, False, True)
-socketpair_unsecure_fixture_options = default_unsecure_fixture_options._replace(fullstack=False, dns_resolver=False)
-default_secure_fixture_options = default_unsecure_fixture_options._replace(secure=True)
-uds_fixture_options = default_unsecure_fixture_options._replace(dns_resolver=False, platforms=['linux', 'mac', 'posix'], exclude_iomgrs=['uv'])
+    True, False, True, True, False, ['windows', 'linux', 'mac', 'posix'],
+    True, False, [], [], True, False, True, False, True, False, True, True)
+socketpair_unsecure_fixture_options = default_unsecure_fixture_options._replace(
+    fullstack=False, dns_resolver=False, client_channel=False)
+default_secure_fixture_options = default_unsecure_fixture_options._replace(
+    secure=True)
+uds_fixture_options = default_unsecure_fixture_options._replace(
+    dns_resolver=False, platforms=['linux', 'mac', 'posix'],
+    exclude_iomgrs=['uv'])
 fd_unsecure_fixture_options = default_unsecure_fixture_options._replace(
-    dns_resolver=False, fullstack=False, platforms=['linux', 'mac', 'posix'], exclude_iomgrs=['uv'])
-inproc_fixture_options = default_unsecure_fixture_options._replace(dns_resolver=False, fullstack=False, name_resolution=False, supports_compression=False, is_inproc=True, is_http2=False, supports_write_buffering=False)
+    dns_resolver=False, fullstack=False, platforms=['linux', 'mac', 'posix'],
+    exclude_iomgrs=['uv'], client_channel=False)
+inproc_fixture_options = default_unsecure_fixture_options._replace(
+    dns_resolver=False, fullstack=False, name_resolution=False,
+    supports_compression=False, is_inproc=True, is_http2=False,
+    supports_write_buffering=False, client_channel=False)
 
 # maps fixture name to whether it requires the security library
 END2END_FIXTURES = {
@@ -68,9 +77,12 @@
 
 TestOptions = collections.namedtuple(
     'TestOptions',
-    'needs_fullstack needs_dns needs_names proxyable secure traceable cpu_cost exclude_iomgrs large_writes flaky allows_compression needs_compression exclude_inproc needs_http2 needs_proxy_auth needs_write_buffering')
-default_test_options = TestOptions(False, False, False, True, False, True, 1.0, [], False, False, True, False, False, False, False, False)
-connectivity_test_options = default_test_options._replace(needs_fullstack=True)
+    'needs_fullstack needs_dns needs_names proxyable secure traceable cpu_cost exclude_iomgrs large_writes flaky allows_compression needs_compression exclude_inproc needs_http2 needs_proxy_auth needs_write_buffering needs_client_channel')
+default_test_options = TestOptions(
+    False, False, False, True, False, True, 1.0, [], False, False, True,
+    False, False, False, False, False, False)
+connectivity_test_options = default_test_options._replace(
+    needs_fullstack=True)
 
 LOWCPU = 0.1
 
@@ -80,9 +92,8 @@
     'bad_hostname': default_test_options._replace(needs_names=True),
     'bad_ping': connectivity_test_options._replace(proxyable=False),
     'binary_metadata': default_test_options._replace(cpu_cost=LOWCPU),
-    'resource_quota_server': default_test_options._replace(large_writes=True,
-                                                           proxyable=False,
-                                                           allows_compression=False),
+    'resource_quota_server': default_test_options._replace(
+        large_writes=True, proxyable=False, allows_compression=False),
     'call_creds': default_test_options._replace(secure=True),
     'cancel_after_accept': default_test_options._replace(cpu_cost=LOWCPU),
     'cancel_after_client_done': default_test_options._replace(cpu_cost=LOWCPU),
@@ -91,18 +102,21 @@
     'cancel_before_invoke': default_test_options._replace(cpu_cost=LOWCPU),
     'cancel_in_a_vacuum': default_test_options._replace(cpu_cost=LOWCPU),
     'cancel_with_status': default_test_options._replace(cpu_cost=LOWCPU),
-    'compressed_payload': default_test_options._replace(proxyable=False,needs_compression=True),
+    'compressed_payload': default_test_options._replace(proxyable=False,
+                                                        needs_compression=True),
     'connectivity': connectivity_test_options._replace(needs_names=True,
         proxyable=False, cpu_cost=LOWCPU, exclude_iomgrs=['uv']),
-    'default_host': default_test_options._replace(needs_fullstack=True,
-                                                  needs_dns=True,needs_names=True),
-    'disappearing_server': connectivity_test_options._replace(flaky=True,needs_names=True),
+    'default_host': default_test_options._replace(
+        needs_fullstack=True, needs_dns=True, needs_names=True),
+    'disappearing_server': connectivity_test_options._replace(flaky=True,
+                                                              needs_names=True),
     'empty_batch': default_test_options._replace(cpu_cost=LOWCPU),
     'filter_causes_close': default_test_options._replace(cpu_cost=LOWCPU),
     'filter_call_init_fails': default_test_options,
     'filter_latency': default_test_options._replace(cpu_cost=LOWCPU),
     'filter_status_code': default_test_options._replace(cpu_cost=LOWCPU),
-    'graceful_server_shutdown': default_test_options._replace(cpu_cost=LOWCPU,exclude_inproc=True),
+    'graceful_server_shutdown': default_test_options._replace(
+        cpu_cost=LOWCPU, exclude_inproc=True),
     'hpack_size': default_test_options._replace(proxyable=False,
                                                 traceable=False,
                                                 cpu_cost=LOWCPU),
@@ -127,30 +141,75 @@
     'payload': default_test_options,
     'load_reporting_hook': default_test_options,
     'ping_pong_streaming': default_test_options._replace(cpu_cost=LOWCPU),
-    'ping': connectivity_test_options._replace(proxyable=False, cpu_cost=LOWCPU),
+    'ping': connectivity_test_options._replace(proxyable=False,
+                                               cpu_cost=LOWCPU),
     'proxy_auth': default_test_options._replace(needs_proxy_auth=True),
     'registered_call': default_test_options,
     'request_with_flags': default_test_options._replace(
         proxyable=False, cpu_cost=LOWCPU),
     'request_with_payload': default_test_options._replace(cpu_cost=LOWCPU),
+    # TODO(roth): Remove proxyable=False for all retry tests once we
+    # have a way for the proxy to propagate the fact that trailing
+    # metadata is available when initial metadata is returned.
+    # See https://github.com/grpc/grpc/issues/14467 for context.
+    'retry': default_test_options._replace(cpu_cost=LOWCPU,
+                                           needs_client_channel=True,
+                                           proxyable=False),
+    'retry_cancellation': default_test_options._replace(
+        cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
+    'retry_disabled': default_test_options._replace(cpu_cost=LOWCPU,
+                                                    needs_client_channel=True,
+                                                    proxyable=False),
+    'retry_exceeds_buffer_size_in_initial_batch': default_test_options._replace(
+        cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
+    'retry_exceeds_buffer_size_in_subsequent_batch':
+        default_test_options._replace(cpu_cost=LOWCPU,
+                                      needs_client_channel=True,
+                                      proxyable=False),
+    'retry_non_retriable_status': default_test_options._replace(
+        cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
+    'retry_recv_initial_metadata': default_test_options._replace(
+        cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
+    'retry_recv_message': default_test_options._replace(
+        cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
+    'retry_server_pushback_delay': default_test_options._replace(
+        cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
+    'retry_server_pushback_disabled': default_test_options._replace(
+        cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
+    'retry_streaming': default_test_options._replace(cpu_cost=LOWCPU,
+                                                     needs_client_channel=True,
+                                                     proxyable=False),
+    'retry_streaming_after_commit': default_test_options._replace(
+        cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
+    'retry_streaming_succeeds_before_replay_finished':
+        default_test_options._replace(cpu_cost=LOWCPU,
+                                      needs_client_channel=True,
+                                      proxyable=False),
+    'retry_throttled': default_test_options._replace(cpu_cost=LOWCPU,
+                                                     needs_client_channel=True,
+                                                     proxyable=False),
+    'retry_too_many_attempts': default_test_options._replace(
+        cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
     'server_finishes_request': default_test_options._replace(cpu_cost=LOWCPU),
     'shutdown_finishes_calls': default_test_options._replace(cpu_cost=LOWCPU),
     'shutdown_finishes_tags': default_test_options._replace(cpu_cost=LOWCPU),
     'simple_cacheable_request': default_test_options._replace(cpu_cost=LOWCPU),
-    'stream_compression_compressed_payload': default_test_options._replace(proxyable=False,
-                                                               exclude_inproc=True),
-    'stream_compression_payload': default_test_options._replace(exclude_inproc=True),
-    'stream_compression_ping_pong_streaming': default_test_options._replace(exclude_inproc=True),
+    'stream_compression_compressed_payload': default_test_options._replace(
+        proxyable=False, exclude_inproc=True),
+    'stream_compression_payload': default_test_options._replace(
+        exclude_inproc=True),
+    'stream_compression_ping_pong_streaming': default_test_options._replace(
+        exclude_inproc=True),
     'simple_delayed_request': connectivity_test_options,
     'simple_metadata': default_test_options,
     'simple_request': default_test_options,
     'streaming_error_response': default_test_options._replace(cpu_cost=LOWCPU),
     'trailing_metadata': default_test_options,
     'workaround_cronet_compression': default_test_options,
-    'write_buffering': default_test_options._replace(cpu_cost=LOWCPU,
-                                                     needs_write_buffering=True),
-    'write_buffering_at_end': default_test_options._replace(cpu_cost=LOWCPU,
-                                                     needs_write_buffering=True),
+    'write_buffering': default_test_options._replace(
+        cpu_cost=LOWCPU, needs_write_buffering=True),
+    'write_buffering_at_end': default_test_options._replace(
+        cpu_cost=LOWCPU, needs_write_buffering=True),
 }
 
 
@@ -191,6 +250,9 @@
   if END2END_TESTS[t].needs_write_buffering:
     if not END2END_FIXTURES[f].supports_write_buffering:
       return False
+  if END2END_TESTS[t].needs_client_channel:
+    if not END2END_FIXTURES[f].client_channel:
+      return False
   return True
 
 
diff --git a/test/core/end2end/generate_tests.bzl b/test/core/end2end/generate_tests.bzl
index 1d759e1..8e723fd 100755
--- a/test/core/end2end/generate_tests.bzl
+++ b/test/core/end2end/generate_tests.bzl
@@ -13,6 +13,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+POLLERS = ['epollex', 'epollsig', 'epoll1', 'poll', 'poll-cv']
+
 load("//bazel:grpc_build_system.bzl", "grpc_sh_test", "grpc_cc_binary", "grpc_cc_library")
 
 """Generates the appropriate build.json data for all the end2end tests."""
@@ -22,7 +24,7 @@
                     name_resolution=True, secure=True, tracing=False,
                     platforms=['windows', 'linux', 'mac', 'posix'],
                     is_inproc=False, is_http2=True, supports_proxy_auth=False,
-                    supports_write_buffering=True):
+                    supports_write_buffering=True, client_channel=True):
   return struct(
     fullstack=fullstack,
     includes_proxy=includes_proxy,
@@ -33,8 +35,9 @@
     is_inproc=is_inproc,
     is_http2=is_http2,
     supports_proxy_auth=supports_proxy_auth,
-    supports_write_buffering=supports_write_buffering
-    #platforms=platforms
+    supports_write_buffering=supports_write_buffering,
+    client_channel=client_channel,
+    #platforms=platforms,
   )
 
 
@@ -45,6 +48,7 @@
     'h2_load_reporting': fixture_options(),
     'h2_fakesec': fixture_options(),
     'h2_fd': fixture_options(dns_resolver=False, fullstack=False,
+                             client_channel=False,
                              platforms=['linux', 'mac', 'posix']),
     'h2_full': fixture_options(),
     'h2_full+pipe': fixture_options(platforms=['linux']),
@@ -53,24 +57,28 @@
     'h2_http_proxy': fixture_options(supports_proxy_auth=True),
     'h2_oauth2': fixture_options(),
     'h2_proxy': fixture_options(includes_proxy=True),
-    'h2_sockpair_1byte': fixture_options(fullstack=False, dns_resolver=False),
-    'h2_sockpair': fixture_options(fullstack=False, dns_resolver=False),
+    'h2_sockpair_1byte': fixture_options(fullstack=False, dns_resolver=False,
+                                         client_channel=False),
+    'h2_sockpair': fixture_options(fullstack=False, dns_resolver=False,
+                                   client_channel=False),
     'h2_sockpair+trace': fixture_options(fullstack=False, dns_resolver=False,
-                                         tracing=True),
+                                         tracing=True, client_channel=False),
     'h2_ssl': fixture_options(secure=True),
     'h2_ssl_proxy': fixture_options(includes_proxy=True, secure=True),
     'h2_uds': fixture_options(dns_resolver=False,
                               platforms=['linux', 'mac', 'posix']),
     'inproc': fixture_options(fullstack=False, dns_resolver=False,
                               name_resolution=False, is_inproc=True,
-                              is_http2=False, supports_write_buffering=False),
+                              is_http2=False, supports_write_buffering=False,
+                              client_channel=False),
 }
 
 
 def test_options(needs_fullstack=False, needs_dns=False, needs_names=False,
                  proxyable=True, secure=False, traceable=False,
                  exclude_inproc=False, needs_http2=False,
-                 needs_proxy_auth=False, needs_write_buffering=False):
+                 needs_proxy_auth=False, needs_write_buffering=False,
+                 needs_client_channel=False):
   return struct(
     needs_fullstack=needs_fullstack,
     needs_dns=needs_dns,
@@ -81,7 +89,8 @@
     exclude_inproc=exclude_inproc,
     needs_http2=needs_http2,
     needs_proxy_auth=needs_proxy_auth,
-    needs_write_buffering=needs_write_buffering
+    needs_write_buffering=needs_write_buffering,
+    needs_client_channel=needs_client_channel,
   )
 
 
@@ -116,7 +125,8 @@
     'invoke_large_request': test_options(),
     'keepalive_timeout': test_options(proxyable=False, needs_http2=True),
     'large_metadata': test_options(),
-    'max_concurrent_streams': test_options(proxyable=False, exclude_inproc=True),
+    'max_concurrent_streams': test_options(proxyable=False,
+                                           exclude_inproc=True),
     'max_connection_age': test_options(exclude_inproc=True),
     'max_connection_idle': test_options(needs_fullstack=True, proxyable=False),
     'max_message_length': test_options(),
@@ -132,6 +142,37 @@
     'registered_call': test_options(),
     'request_with_flags': test_options(proxyable=False),
     'request_with_payload': test_options(),
+    # TODO(roth): Remove proxyable=False for all retry tests once we
+    # have a way for the proxy to propagate the fact that trailing
+    # metadata is available when initial metadata is returned.
+    # See https://github.com/grpc/grpc/issues/14467 for context.
+    'retry': test_options(needs_client_channel=True, proxyable=False),
+    'retry_cancellation': test_options(needs_client_channel=True,
+                                       proxyable=False),
+    'retry_disabled': test_options(needs_client_channel=True, proxyable=False),
+    'retry_exceeds_buffer_size_in_initial_batch': test_options(
+        needs_client_channel=True, proxyable=False),
+    'retry_exceeds_buffer_size_in_subsequent_batch': test_options(
+        needs_client_channel=True, proxyable=False),
+    'retry_non_retriable_status': test_options(needs_client_channel=True,
+                                               proxyable=False),
+    'retry_recv_initial_metadata': test_options(needs_client_channel=True,
+                                                proxyable=False),
+    'retry_recv_message': test_options(needs_client_channel=True,
+                                       proxyable=False),
+    'retry_server_pushback_delay': test_options(needs_client_channel=True,
+                                                proxyable=False),
+    'retry_server_pushback_disabled': test_options(needs_client_channel=True,
+                                                   proxyable=False),
+    'retry_streaming': test_options(needs_client_channel=True, proxyable=False),
+    'retry_streaming_after_commit': test_options(needs_client_channel=True,
+                                                 proxyable=False),
+    'retry_streaming_succeeds_before_replay_finished': test_options(
+        needs_client_channel=True, proxyable=False),
+    'retry_throttled': test_options(needs_client_channel=True,
+                                    proxyable=False),
+    'retry_too_many_attempts': test_options(needs_client_channel=True,
+                                            proxyable=False),
     'server_finishes_request': test_options(),
     'shutdown_finishes_calls': test_options(),
     'shutdown_finishes_tags': test_options(),
@@ -140,7 +181,8 @@
     'simple_metadata': test_options(),
     'simple_request': test_options(),
     'streaming_error_response': test_options(),
-    'stream_compression_compressed_payload': test_options(proxyable=False, exclude_inproc=True),
+    'stream_compression_compressed_payload': test_options(proxyable=False,
+                                                          exclude_inproc=True),
     'stream_compression_payload': test_options(exclude_inproc=True),
     'stream_compression_ping_pong_streaming': test_options(exclude_inproc=True),
     'trailing_metadata': test_options(),
@@ -181,6 +223,9 @@
   if topt.needs_write_buffering:
     if not fopt.supports_write_buffering:
       return False
+  if topt.needs_client_channel:
+    if not fopt.client_channel:
+      return False
   return True
 
 
@@ -219,9 +264,14 @@
     for t, topt in END2END_TESTS.items():
       #print(compatible(fopt, topt), f, t, fopt, topt)
       if not compatible(fopt, topt): continue
-      grpc_sh_test(
-        name = '%s_test@%s' % (f, t),
-        srcs = ['end2end_test.sh'],
-        args = ['$(location %s_test)' % f, t],
-        data = [':%s_test' % f],
-      )
+      for poller in POLLERS:
+        native.sh_test(
+          name = '%s_test@%s@poller=%s' % (f, t, poller),
+          data = [':%s_test' % f],
+          srcs = ['end2end_test.sh'],
+          args = [
+            '$(location %s_test)' % f, 
+            t,
+            poller,
+          ],
+        )
diff --git a/test/core/end2end/goaway_server_test.cc b/test/core/end2end/goaway_server_test.cc
index f23d87e..0188698 100644
--- a/test/core/end2end/goaway_server_test.cc
+++ b/test/core/end2end/goaway_server_test.cc
@@ -21,6 +21,7 @@
    including windows.h on Windows, uv.h must be included before other system
    headers. Therefore, sockaddr.h must always be included first */
 #include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/iomgr/socket_utils.h"
 
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
@@ -35,14 +36,13 @@
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
+extern grpc_address_resolver_vtable* grpc_resolve_address_impl;
+static grpc_address_resolver_vtable* default_resolver;
+
 static void* tag(intptr_t i) { return (void*)i; }
 
 static gpr_mu g_mu;
 static int g_resolve_port = -1;
-static void (*iomgr_resolve_address)(const char* addr, const char* default_port,
-                                     grpc_pollset_set* interested_parties,
-                                     grpc_closure* on_done,
-                                     grpc_resolved_addresses** addresses);
 
 static grpc_ares_request* (*iomgr_dns_lookup_ares)(
     const char* dns_server, const char* addr, const char* default_port,
@@ -61,8 +61,8 @@
                                grpc_closure* on_done,
                                grpc_resolved_addresses** addrs) {
   if (0 != strcmp(addr, "test")) {
-    iomgr_resolve_address(addr, default_port, interested_parties, on_done,
-                          addrs);
+    default_resolver->resolve_address(addr, default_port, interested_parties,
+                                      on_done, addrs);
     return;
   }
 
@@ -77,16 +77,27 @@
     (*addrs)->addrs = static_cast<grpc_resolved_address*>(
         gpr_malloc(sizeof(*(*addrs)->addrs)));
     memset((*addrs)->addrs, 0, sizeof(*(*addrs)->addrs));
-    struct sockaddr_in* sa = (struct sockaddr_in*)(*addrs)->addrs[0].addr;
-    sa->sin_family = AF_INET;
-    sa->sin_addr.s_addr = htonl(0x7f000001);
-    sa->sin_port = htons((uint16_t)g_resolve_port);
-    (*addrs)->addrs[0].len = sizeof(*sa);
+    grpc_sockaddr_in* sa =
+        reinterpret_cast<grpc_sockaddr_in*>((*addrs)->addrs[0].addr);
+    sa->sin_family = GRPC_AF_INET;
+    sa->sin_addr.s_addr = 0x100007f;
+    sa->sin_port = grpc_htons(static_cast<uint16_t>(g_resolve_port));
+    (*addrs)->addrs[0].len = static_cast<socklen_t>(sizeof(*sa));
     gpr_mu_unlock(&g_mu);
   }
   GRPC_CLOSURE_SCHED(on_done, error);
 }
 
+static grpc_error* my_blocking_resolve_address(
+    const char* name, const char* default_port,
+    grpc_resolved_addresses** addresses) {
+  return default_resolver->blocking_resolve_address(name, default_port,
+                                                    addresses);
+}
+
+static grpc_address_resolver_vtable test_resolver = {
+    my_resolve_address, my_blocking_resolve_address};
+
 static grpc_ares_request* my_dns_lookup_ares(
     const char* dns_server, const char* addr, const char* default_port,
     grpc_pollset_set* interested_parties, grpc_closure* on_done,
@@ -105,11 +116,11 @@
     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Forced Failure");
   } else {
     *lb_addrs = grpc_lb_addresses_create(1, nullptr);
-    struct sockaddr_in* sa = static_cast<struct sockaddr_in*>(
-        gpr_zalloc(sizeof(struct sockaddr_in)));
-    sa->sin_family = AF_INET;
-    sa->sin_addr.s_addr = htonl(0x7f000001);
-    sa->sin_port = htons((uint16_t)g_resolve_port);
+    grpc_sockaddr_in* sa =
+        static_cast<grpc_sockaddr_in*>(gpr_zalloc(sizeof(grpc_sockaddr_in)));
+    sa->sin_family = GRPC_AF_INET;
+    sa->sin_addr.s_addr = 0x100007f;
+    sa->sin_port = grpc_htons(static_cast<uint16_t>(g_resolve_port));
     grpc_lb_addresses_set_address(*lb_addrs, 0, sa, sizeof(*sa), false, nullptr,
                                   nullptr);
     gpr_free(sa);
@@ -129,9 +140,9 @@
 
   gpr_mu_init(&g_mu);
   grpc_init();
-  iomgr_resolve_address = grpc_resolve_address;
+  default_resolver = grpc_resolve_address_impl;
+  grpc_set_resolver_impl(&test_resolver);
   iomgr_dns_lookup_ares = grpc_dns_lookup_ares;
-  grpc_resolve_address = my_resolve_address;
   grpc_dns_lookup_ares = my_dns_lookup_ares;
 
   int was_cancelled1;
diff --git a/test/core/end2end/h2_ssl_cert_test.cc b/test/core/end2end/h2_ssl_cert_test.cc
index 9adb96e..0741e7c 100644
--- a/test/core/end2end/h2_ssl_cert_test.cc
+++ b/test/core/end2end/h2_ssl_cert_test.cc
@@ -22,11 +22,11 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gpr/tmpfile.h"
 #include "src/core/lib/security/credentials/credentials.h"
@@ -57,8 +57,6 @@
 
   f.fixture_data = ffd;
   f.cq = grpc_completion_queue_create_for_next(nullptr);
-  f.shutdown_cq = grpc_completion_queue_create_for_pluck(nullptr);
-
   return f;
 }
 
@@ -270,27 +268,13 @@
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
+// Shuts down the server.
+// Side effect - Also shuts down and drains the completion queue.
 static void shutdown_server(grpc_end2end_test_fixture* f) {
   if (!f->server) return;
-  /* Perform a completion queue next, so that any pending operations can be
-   * finished, and resources can be released. This is so that, shutdown does not
-   * hang. For example, the server might be stuck in the handshaking code, which
-   * keeps a ref to a listener. Unless, it is unref'd, shutdown won't be able
-   * to proceed.
-   *
-   * (If shutdown times out, it is probably because 100ms wasn't enough. In that
-   * case, the deadline can be increased. Or, we could simply have another
-   * thread for the server to poll the completion queue while the shutdown
-   * progresses.)
-   */
-  GPR_ASSERT(grpc_completion_queue_next(
-                 f->cq, grpc_timeout_milliseconds_to_deadline(100), nullptr)
-                 .type == GRPC_QUEUE_TIMEOUT);
-  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
-                                         grpc_timeout_seconds_to_deadline(5),
-                                         nullptr)
-                 .type == GRPC_OP_COMPLETE);
+  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
   grpc_server_destroy(f->server);
   f->server = nullptr;
 }
@@ -304,11 +288,7 @@
 static void end_test(grpc_end2end_test_fixture* f) {
   shutdown_client(f);
   shutdown_server(f);
-
-  grpc_completion_queue_shutdown(f->cq);
-  drain_cq(f->cq);
   grpc_completion_queue_destroy(f->cq);
-  grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
 static void simple_request_body(grpc_end2end_test_fixture f,
@@ -333,7 +313,8 @@
   op->flags = GRPC_INITIAL_METADATA_WAIT_FOR_READY;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(1), expected_result == SUCCESS);
diff --git a/test/core/end2end/h2_ssl_session_reuse_test.cc b/test/core/end2end/h2_ssl_session_reuse_test.cc
new file mode 100644
index 0000000..d5984be
--- /dev/null
+++ b/test/core/end2end/h2_ssl_session_reuse_test.cc
@@ -0,0 +1,280 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/host_port.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/tmpfile.h"
+#include "src/core/lib/security/credentials/credentials.h"
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/end2end/data/ssl_test_data.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+
+#include <gtest/gtest.h>
+
+namespace grpc {
+namespace testing {
+namespace {
+
+void* tag(intptr_t t) { return (void*)t; }
+
+gpr_timespec five_seconds_time() { return grpc_timeout_seconds_to_deadline(5); }
+
+grpc_server* server_create(grpc_completion_queue* cq, char* server_addr) {
+  grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key,
+                                                  test_server1_cert};
+  grpc_server_credentials* server_creds = grpc_ssl_server_credentials_create_ex(
+      test_root_cert, &pem_cert_key_pair, 1,
+      GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY, nullptr);
+
+  grpc_server* server = grpc_server_create(nullptr, nullptr);
+  grpc_server_register_completion_queue(server, cq, nullptr);
+  GPR_ASSERT(
+      grpc_server_add_secure_http2_port(server, server_addr, server_creds));
+  grpc_server_credentials_release(server_creds);
+  grpc_server_start(server);
+
+  return server;
+}
+
+grpc_channel* client_create(char* server_addr, grpc_ssl_session_cache* cache) {
+  grpc_ssl_pem_key_cert_pair signed_client_key_cert_pair = {
+      test_signed_client_key, test_signed_client_cert};
+  grpc_channel_credentials* client_creds = grpc_ssl_credentials_create(
+      test_root_cert, &signed_client_key_cert_pair, nullptr);
+
+  grpc_arg args[] = {
+      grpc_channel_arg_string_create(
+          const_cast<char*>(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG),
+          const_cast<char*>("waterzooi.test.google.be")),
+      grpc_ssl_session_cache_create_channel_arg(cache),
+  };
+
+  grpc_channel_args* client_args =
+      grpc_channel_args_copy_and_add(nullptr, args, GPR_ARRAY_SIZE(args));
+
+  grpc_channel* client = grpc_secure_channel_create(client_creds, server_addr,
+                                                    client_args, nullptr);
+  GPR_ASSERT(client != nullptr);
+  grpc_channel_credentials_release(client_creds);
+
+  {
+    grpc_core::ExecCtx exec_ctx;
+    grpc_channel_args_destroy(client_args);
+  }
+
+  return client;
+}
+
+void do_round_trip(grpc_completion_queue* cq, grpc_server* server,
+                   char* server_addr, grpc_ssl_session_cache* cache,
+                   bool expect_session_reuse) {
+  grpc_channel* client = client_create(server_addr, cache);
+
+  cq_verifier* cqv = cq_verifier_create(cq);
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+
+  gpr_timespec deadline = grpc_timeout_seconds_to_deadline(60);
+  grpc_call* c = grpc_channel_create_call(
+      client, nullptr, GRPC_PROPAGATE_DEFAULTS, cq,
+      grpc_slice_from_static_string("/foo"), nullptr, deadline, nullptr);
+  GPR_ASSERT(c);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  grpc_call* s;
+  error = grpc_server_request_call(server, &s, &call_details,
+                                   &request_metadata_recv, cq, cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
+  cq_verify(cqv);
+
+  grpc_auth_context* auth = grpc_call_auth_context(s);
+  grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(
+      auth, GRPC_SSL_SESSION_REUSED_PROPERTY);
+  const grpc_auth_property* property = grpc_auth_property_iterator_next(&it);
+  GPR_ASSERT(property != nullptr);
+
+  if (expect_session_reuse) {
+    GPR_ASSERT(strcmp(property->value, "true") == 0);
+  } else {
+    GPR_ASSERT(strcmp(property->value, "false") == 0);
+  }
+  grpc_auth_context_release(auth);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_OK;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103),
+                                nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
+  cq_verify(cqv);
+
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+
+  grpc_call_unref(c);
+  grpc_call_unref(s);
+
+  cq_verifier_destroy(cqv);
+
+  grpc_channel_destroy(client);
+}
+
+void drain_cq(grpc_completion_queue* cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), nullptr);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+TEST(H2SessionReuseTest, SingleReuse) {
+  int port = grpc_pick_unused_port_or_die();
+
+  char* server_addr;
+  gpr_join_host_port(&server_addr, "localhost", port);
+
+  grpc_completion_queue* cq = grpc_completion_queue_create_for_next(nullptr);
+  grpc_ssl_session_cache* cache = grpc_ssl_session_cache_create_lru(16);
+
+  grpc_server* server = server_create(cq, server_addr);
+
+  do_round_trip(cq, server, server_addr, cache, false);
+  do_round_trip(cq, server, server_addr, cache, true);
+  do_round_trip(cq, server, server_addr, cache, true);
+
+  gpr_free(server_addr);
+  grpc_ssl_session_cache_destroy(cache);
+
+  GPR_ASSERT(grpc_completion_queue_next(
+                 cq, grpc_timeout_milliseconds_to_deadline(100), nullptr)
+                 .type == GRPC_QUEUE_TIMEOUT);
+
+  grpc_completion_queue* shutdown_cq =
+      grpc_completion_queue_create_for_pluck(nullptr);
+  grpc_server_shutdown_and_notify(server, shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         nullptr)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(server);
+  grpc_completion_queue_destroy(shutdown_cq);
+
+  grpc_completion_queue_shutdown(cq);
+  drain_cq(cq);
+  grpc_completion_queue_destroy(cq);
+}
+
+}  // namespace
+}  // namespace testing
+}  // namespace grpc
+
+int main(int argc, char** argv) {
+  FILE* roots_file;
+  size_t roots_size = strlen(test_root_cert);
+  char* roots_filename;
+
+  grpc_test_init(argc, argv);
+  /* Set the SSL roots env var. */
+  roots_file = gpr_tmpfile("chttp2_ssl_session_reuse_test", &roots_filename);
+  GPR_ASSERT(roots_filename != nullptr);
+  GPR_ASSERT(roots_file != nullptr);
+  GPR_ASSERT(fwrite(test_root_cert, 1, roots_size, roots_file) == roots_size);
+  fclose(roots_file);
+  gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_filename);
+
+  grpc_init();
+  ::testing::InitGoogleTest(&argc, argv);
+  int ret = RUN_ALL_TESTS();
+  grpc_shutdown();
+
+  /* Cleanup. */
+  remove(roots_filename);
+  gpr_free(roots_filename);
+
+  return ret;
+}
diff --git a/test/core/end2end/invalid_call_argument_test.cc b/test/core/end2end/invalid_call_argument_test.cc
index cb6b4c0..6cb2e3e 100644
--- a/test/core/end2end/invalid_call_argument_test.cc
+++ b/test/core/end2end/invalid_call_argument_test.cc
@@ -23,9 +23,9 @@
 
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 
+#include "src/core/lib/gpr/host_port.h"
 #include "test/core/end2end/cq_verifier.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
@@ -209,7 +209,7 @@
 
   op = g_state.ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
-  op->data.send_initial_metadata.count = (size_t)INT_MAX + 1;
+  op->data.send_initial_metadata.count = static_cast<size_t>(INT_MAX) + 1;
   op->flags = 0;
   op->reserved = nullptr;
   op++;
@@ -499,7 +499,7 @@
   op = g_state.ops;
   op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
   op->data.send_status_from_server.trailing_metadata_count =
-      (size_t)INT_MAX + 1;
+      static_cast<size_t>(INT_MAX) + 1;
   op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
   grpc_slice status_details = grpc_slice_from_static_string("xyz");
   op->data.send_status_from_server.status_details = &status_details;
diff --git a/test/core/end2end/no_server_test.cc b/test/core/end2end/no_server_test.cc
index 6113885..e8ce403 100644
--- a/test/core/end2end/no_server_test.cc
+++ b/test/core/end2end/no_server_test.cc
@@ -22,45 +22,47 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
+#include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
 #include "test/core/end2end/cq_verifier.h"
 #include "test/core/util/test_config.h"
 
 static void* tag(intptr_t i) { return (void*)i; }
 
-int main(int argc, char** argv) {
-  grpc_channel* chan;
-  grpc_call* call;
-  gpr_timespec deadline = grpc_timeout_seconds_to_deadline(2);
-  grpc_completion_queue* cq;
-  cq_verifier* cqv;
-  grpc_op ops[6];
-  grpc_op* op;
-  grpc_metadata_array trailing_metadata_recv;
-  grpc_status_code status;
-  grpc_slice details;
+void run_test(bool wait_for_ready) {
+  gpr_log(GPR_INFO, "TEST: wait_for_ready=%d", wait_for_ready);
 
-  grpc_test_init(argc, argv);
   grpc_init();
 
-  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_completion_queue* cq = grpc_completion_queue_create_for_next(nullptr);
+  cq_verifier* cqv = cq_verifier_create(cq);
 
-  cq = grpc_completion_queue_create_for_next(nullptr);
-  cqv = cq_verifier_create(cq);
+  grpc_core::RefCountedPtr<grpc_core::FakeResolverResponseGenerator>
+      response_generator =
+          grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
+  grpc_arg arg = grpc_core::FakeResolverResponseGenerator::MakeChannelArg(
+      response_generator.get());
+  grpc_channel_args args = {1, &arg};
 
   /* create a call, channel to a non existant server */
-  chan = grpc_insecure_channel_create("nonexistant:54321", nullptr, nullptr);
-  grpc_slice host = grpc_slice_from_static_string("nonexistant");
-  call = grpc_channel_create_call(chan, nullptr, GRPC_PROPAGATE_DEFAULTS, cq,
-                                  grpc_slice_from_static_string("/Foo"), &host,
-                                  deadline, nullptr);
+  grpc_channel* chan =
+      grpc_insecure_channel_create("fake:nonexistant", &args, nullptr);
+  gpr_timespec deadline = grpc_timeout_seconds_to_deadline(2);
+  grpc_call* call = grpc_channel_create_call(
+      chan, nullptr, GRPC_PROPAGATE_DEFAULTS, cq,
+      grpc_slice_from_static_string("/Foo"), nullptr, deadline, nullptr);
 
+  grpc_op ops[6];
   memset(ops, 0, sizeof(ops));
-  op = ops;
+  grpc_op* op = ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
   op->data.send_initial_metadata.count = 0;
-  op->flags = 0;
+  op->flags = wait_for_ready ? GRPC_INITIAL_METADATA_WAIT_FOR_READY : 0;
   op->reserved = nullptr;
   op++;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_status_code status;
+  grpc_slice details;
   op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
   op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
   op->data.recv_status_on_client.status = &status;
@@ -71,11 +73,25 @@
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(call, ops,
                                                    (size_t)(op - ops), tag(1),
                                                    nullptr));
+
+  {
+    grpc_core::ExecCtx exec_ctx;
+    response_generator->SetFailure();
+  }
+
   /* verify that all tags get completed */
   CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
-  GPR_ASSERT(status == GRPC_STATUS_DEADLINE_EXCEEDED);
+  gpr_log(GPR_INFO, "call status: %d", status);
+  if (wait_for_ready) {
+    GPR_ASSERT(status == GRPC_STATUS_DEADLINE_EXCEEDED);
+  } else {
+    GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE);
+  }
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
 
   grpc_completion_queue_shutdown(cq);
   while (grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME),
@@ -87,10 +103,12 @@
   grpc_channel_destroy(chan);
   cq_verifier_destroy(cqv);
 
-  grpc_slice_unref(details);
-  grpc_metadata_array_destroy(&trailing_metadata_recv);
-
   grpc_shutdown();
+}
 
+int main(int argc, char** argv) {
+  grpc_test_init(argc, argv);
+  run_test(true /* wait_for_ready */);
+  run_test(false /* wait_for_ready */);
   return 0;
 }
diff --git a/test/core/end2end/tests/authority_not_supported.cc b/test/core/end2end/tests/authority_not_supported.cc
index 9c85450..01a95e4 100644
--- a/test/core/end2end/tests/authority_not_supported.cc
+++ b/test/core/end2end/tests/authority_not_supported.cc
@@ -25,7 +25,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -155,7 +154,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/bad_hostname.cc b/test/core/end2end/tests/bad_hostname.cc
index 85e9ba1..b6f06a2 100644
--- a/test/core/end2end/tests/bad_hostname.cc
+++ b/test/core/end2end/tests/bad_hostname.cc
@@ -26,7 +26,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "src/core/lib/gpr/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
@@ -134,7 +133,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/bad_ping.cc b/test/core/end2end/tests/bad_ping.cc
index 30a1b8d..239c608 100644
--- a/test/core/end2end/tests/bad_ping.cc
+++ b/test/core/end2end/tests/bad_ping.cc
@@ -23,13 +23,12 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
+#include "src/core/lib/gpr/useful.h"
 #include "test/core/end2end/cq_verifier.h"
 
-#define MAX_PING_STRIKES 1
+#define MAX_PING_STRIKES 2
 
 static void* tag(intptr_t t) { return (void*)t; }
 
@@ -63,6 +62,7 @@
   grpc_completion_queue_destroy(f->shutdown_cq);
 }
 
+// Send more pings than server allows to trigger server's GOAWAY.
 static void test_bad_ping(grpc_end2end_test_config config) {
   grpc_end2end_test_fixture f = config.create_fixture(nullptr, nullptr);
   cq_verifier* cqv = cq_verifier_create(f.cq);
@@ -144,7 +144,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -155,14 +156,15 @@
   cq_verify(cqv);
 
   // Send too many pings to the server to trigger the punishment:
-  // Each ping will trigger a ping strike, and we need at least MAX_PING_STRIKES
-  // strikes to trigger the punishment. So (MAX_PING_STRIKES + 1) pings are
+  // The first ping will let server mark its last_recv time. Afterwards, each
+  // ping will trigger a ping strike, and we need at least MAX_PING_STRIKES
+  // strikes to trigger the punishment. So (MAX_PING_STRIKES + 2) pings are
   // needed here.
   int i;
-  for (i = 1; i <= MAX_PING_STRIKES + 1; i++) {
+  for (i = 1; i <= MAX_PING_STRIKES + 2; i++) {
     grpc_channel_ping(f.client, f.cq, tag(200 + i), nullptr);
     CQ_EXPECT_COMPLETION(cqv, tag(200 + i), 1);
-    if (i == MAX_PING_STRIKES + 1) {
+    if (i == MAX_PING_STRIKES + 2) {
       CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
     }
     cq_verify(cqv);
@@ -188,7 +190,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -219,9 +222,170 @@
   config.tear_down_data(&f);
 }
 
+// Try sending more pings than server allows, but server should be fine because
+// max_pings_without_data should limit pings sent out on wire.
+static void test_pings_without_data(grpc_end2end_test_config config) {
+  grpc_end2end_test_fixture f = config.create_fixture(nullptr, nullptr);
+  cq_verifier* cqv = cq_verifier_create(f.cq);
+  grpc_arg client_a[3];
+  client_a[0].type = GRPC_ARG_INTEGER;
+  client_a[0].key =
+      const_cast<char*>(GRPC_ARG_HTTP2_MIN_SENT_PING_INTERVAL_WITHOUT_DATA_MS);
+  client_a[0].value.integer = 10;
+  // Only allow MAX_PING_STRIKES pings without data (DATA/HEADERS/WINDOW_UPDATE)
+  // so that the transport will throttle the excess pings.
+  client_a[1].type = GRPC_ARG_INTEGER;
+  client_a[1].key = const_cast<char*>(GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA);
+  client_a[1].value.integer = MAX_PING_STRIKES;
+  client_a[2].type = GRPC_ARG_INTEGER;
+  client_a[2].key = const_cast<char*>(GRPC_ARG_HTTP2_BDP_PROBE);
+  client_a[2].value.integer = 0;
+  grpc_arg server_a[3];
+  server_a[0].type = GRPC_ARG_INTEGER;
+  server_a[0].key =
+      const_cast<char*>(GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS);
+  server_a[0].value.integer = 300000 /* 5 minutes */;
+  server_a[1].type = GRPC_ARG_INTEGER;
+  server_a[1].key = const_cast<char*>(GRPC_ARG_HTTP2_MAX_PING_STRIKES);
+  server_a[1].value.integer = MAX_PING_STRIKES;
+  server_a[2].type = GRPC_ARG_INTEGER;
+  server_a[2].key = const_cast<char*>(GRPC_ARG_HTTP2_BDP_PROBE);
+  server_a[2].value.integer = 0;
+  grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a};
+  grpc_channel_args server_args = {GPR_ARRAY_SIZE(server_a), server_a};
+
+  config.init_client(&f, &client_args);
+  config.init_server(&f, &server_args);
+
+  grpc_call* c;
+  grpc_call* s;
+  gpr_timespec deadline = grpc_timeout_seconds_to_deadline(10);
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+
+  c = grpc_channel_create_call(
+      f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/foo"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      nullptr);
+  GPR_ASSERT(c);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->data.send_initial_metadata.metadata = nullptr;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
+  cq_verify(cqv);
+
+  // Send too many pings to the server similar to the prevous test case.
+  // However, since we set the MAX_PINGS_WITHOUT_DATA at the client side, only
+  // MAX_PING_STRIKES will actually be sent and the rpc will still succeed.
+  int i;
+  for (i = 1; i <= MAX_PING_STRIKES + 2; i++) {
+    grpc_channel_ping(f.client, f.cq, tag(200 + i), nullptr);
+    if (i <= MAX_PING_STRIKES) {
+      CQ_EXPECT_COMPLETION(cqv, tag(200 + i), 1);
+    }
+    cq_verify(cqv);
+  }
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+  op->data.send_status_from_server.status_details = &status_details;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  // Client call should return.
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
+  cq_verify(cqv);
+
+  grpc_server_shutdown_and_notify(f.server, f.cq, tag(0xdead));
+  CQ_EXPECT_COMPLETION(cqv, tag(0xdead), 1);
+  cq_verify(cqv);
+
+  grpc_call_unref(s);
+
+  // The rpc should be successful.
+  GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_call_unref(c);
+  cq_verifier_destroy(cqv);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
 void bad_ping(grpc_end2end_test_config config) {
   GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION);
   test_bad_ping(config);
+  test_pings_without_data(config);
 }
 
 void bad_ping_pre_init(void) {}
diff --git a/test/core/end2end/tests/binary_metadata.cc b/test/core/end2end/tests/binary_metadata.cc
index 381671e..e66b4da 100644
--- a/test/core/end2end/tests/binary_metadata.cc
+++ b/test/core/end2end/tests/binary_metadata.cc
@@ -25,7 +25,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -183,7 +182,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -206,7 +206,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -247,7 +248,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
diff --git a/test/core/end2end/tests/call_creds.cc b/test/core/end2end/tests/call_creds.cc
index c5ea101..e9cbaa3 100644
--- a/test/core/end2end/tests/call_creds.cc
+++ b/test/core/end2end/tests/call_creds.cc
@@ -26,7 +26,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
+
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/security/credentials/credentials.h"
 #include "test/core/end2end/cq_verifier.h"
@@ -219,7 +219,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -253,7 +254,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -279,7 +281,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
@@ -443,7 +446,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(error == GRPC_CALL_OK);
 
   CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/cancel_after_accept.cc b/test/core/end2end/tests/cancel_after_accept.cc
index f59caf7..e94ea51 100644
--- a/test/core/end2end/tests/cancel_after_accept.cc
+++ b/test/core/end2end/tests/cancel_after_accept.cc
@@ -25,9 +25,9 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/transport/metadata.h"
 #include "src/core/lib/transport/service_config.h"
@@ -187,7 +187,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error = grpc_server_request_call(f.server, &s, &call_details,
@@ -218,7 +219,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(3), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(3),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c, nullptr));
diff --git a/test/core/end2end/tests/cancel_after_client_done.cc b/test/core/end2end/tests/cancel_after_client_done.cc
index 9b832d4..31c3ea6 100644
--- a/test/core/end2end/tests/cancel_after_client_done.cc
+++ b/test/core/end2end/tests/cancel_after_client_done.cc
@@ -25,7 +25,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
 #include "test/core/end2end/cq_verifier.h"
 #include "test/core/end2end/tests/cancel_test_helpers.h"
 
@@ -163,7 +164,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error = grpc_server_request_call(f.server, &s, &call_details,
@@ -194,7 +196,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(3), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(3),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c, nullptr));
diff --git a/test/core/end2end/tests/cancel_after_invoke.cc b/test/core/end2end/tests/cancel_after_invoke.cc
index d3891b1..72f7242 100644
--- a/test/core/end2end/tests/cancel_after_invoke.cc
+++ b/test/core/end2end/tests/cancel_after_invoke.cc
@@ -18,6 +18,7 @@
 
 #include "test/core/end2end/end2end_tests.h"
 
+#include <inttypes.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -25,7 +26,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
 #include "test/core/end2end/cq_verifier.h"
 #include "test/core/end2end/tests/cancel_test_helpers.h"
 
diff --git a/test/core/end2end/tests/cancel_after_round_trip.cc b/test/core/end2end/tests/cancel_after_round_trip.cc
index b10b939..4890b30 100644
--- a/test/core/end2end/tests/cancel_after_round_trip.cc
+++ b/test/core/end2end/tests/cancel_after_round_trip.cc
@@ -25,9 +25,9 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/transport/metadata.h"
 #include "src/core/lib/transport/service_config.h"
@@ -182,7 +182,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -209,7 +210,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -235,7 +237,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(2),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c, nullptr));
@@ -252,7 +255,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(2), 1);
diff --git a/test/core/end2end/tests/cancel_before_invoke.cc b/test/core/end2end/tests/cancel_before_invoke.cc
index 1112375..c7d3ed5 100644
--- a/test/core/end2end/tests/cancel_before_invoke.cc
+++ b/test/core/end2end/tests/cancel_before_invoke.cc
@@ -18,6 +18,7 @@
 
 #include "test/core/end2end/end2end_tests.h"
 
+#include <inttypes.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -25,7 +26,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
diff --git a/test/core/end2end/tests/cancel_in_a_vacuum.cc b/test/core/end2end/tests/cancel_in_a_vacuum.cc
index a6c534e..6be2d69 100644
--- a/test/core/end2end/tests/cancel_in_a_vacuum.cc
+++ b/test/core/end2end/tests/cancel_in_a_vacuum.cc
@@ -25,7 +25,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
 #include "test/core/end2end/cq_verifier.h"
 #include "test/core/end2end/tests/cancel_test_helpers.h"
 
diff --git a/test/core/end2end/tests/cancel_with_status.cc b/test/core/end2end/tests/cancel_with_status.cc
index 7937fd1..887da85 100644
--- a/test/core/end2end/tests/cancel_with_status.cc
+++ b/test/core/end2end/tests/cancel_with_status.cc
@@ -18,6 +18,7 @@
 
 #include "test/core/end2end/end2end_tests.h"
 
+#include <inttypes.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -27,7 +28,6 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "src/core/lib/gpr/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
diff --git a/test/core/end2end/tests/compressed_payload.cc b/test/core/end2end/tests/compressed_payload.cc
index c08653b..85cfe16 100644
--- a/test/core/end2end/tests/compressed_payload.cc
+++ b/test/core/end2end/tests/compressed_payload.cc
@@ -28,7 +28,6 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/surface/call.h"
@@ -188,7 +187,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(101), true);
@@ -206,7 +206,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), false);
@@ -217,7 +218,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(103), true);
@@ -339,7 +341,8 @@
     op->flags = client_send_flags_bitmask;
     op->reserved = nullptr;
     op++;
-    error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
+    error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(2),
+                                  nullptr);
     GPR_ASSERT(GRPC_CALL_OK == error);
     CQ_EXPECT_COMPLETION(cqv, tag(2), true);
   }
@@ -368,7 +371,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -383,9 +387,9 @@
   GPR_ASSERT(GPR_BITGET(grpc_call_test_only_get_encodings_accepted_by_peer(s),
                         GRPC_COMPRESS_NONE) != 0);
   GPR_ASSERT(GPR_BITGET(grpc_call_test_only_get_encodings_accepted_by_peer(s),
-                        GRPC_COMPRESS_MESSAGE_DEFLATE) != 0);
+                        GRPC_COMPRESS_DEFLATE) != 0);
   GPR_ASSERT(GPR_BITGET(grpc_call_test_only_get_encodings_accepted_by_peer(s),
-                        GRPC_COMPRESS_MESSAGE_GZIP) != 0);
+                        GRPC_COMPRESS_GZIP) != 0);
 
   memset(ops, 0, sizeof(ops));
   op = ops;
@@ -404,7 +408,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(101), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(101),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   for (int i = 0; i < 2; i++) {
@@ -419,8 +424,8 @@
       op->flags = client_send_flags_bitmask;
       op->reserved = nullptr;
       op++;
-      error =
-          grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
+      error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops),
+                                    tag(2), nullptr);
       GPR_ASSERT(GRPC_CALL_OK == error);
       CQ_EXPECT_COMPLETION(cqv, tag(2), 1);
     }
@@ -432,8 +437,8 @@
     op->flags = 0;
     op->reserved = nullptr;
     op++;
-    error =
-        grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+    error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops),
+                                  tag(102), nullptr);
     GPR_ASSERT(GRPC_CALL_OK == error);
 
     CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -451,8 +456,8 @@
     op->flags = 0;
     op->reserved = nullptr;
     op++;
-    error =
-        grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+    error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops),
+                                  tag(103), nullptr);
     GPR_ASSERT(GRPC_CALL_OK == error);
 
     memset(ops, 0, sizeof(ops));
@@ -462,7 +467,8 @@
     op->flags = 0;
     op->reserved = nullptr;
     op++;
-    error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), nullptr);
+    error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(3),
+                                  nullptr);
     GPR_ASSERT(GRPC_CALL_OK == error);
 
     CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
@@ -496,7 +502,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(4), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(4),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   memset(ops, 0, sizeof(ops));
@@ -509,7 +516,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(104),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
@@ -550,9 +558,8 @@
     grpc_end2end_test_config config) {
   request_with_payload_template(
       config, "test_invoke_request_with_exceptionally_uncompressed_payload",
-      GRPC_WRITE_NO_COMPRESS, GRPC_COMPRESS_MESSAGE_GZIP,
-      GRPC_COMPRESS_MESSAGE_GZIP, GRPC_COMPRESS_NONE,
-      GRPC_COMPRESS_MESSAGE_GZIP, nullptr, false,
+      GRPC_WRITE_NO_COMPRESS, GRPC_COMPRESS_GZIP, GRPC_COMPRESS_GZIP,
+      GRPC_COMPRESS_NONE, GRPC_COMPRESS_GZIP, nullptr, false,
       /* ignored */ GRPC_COMPRESS_LEVEL_NONE, false);
 }
 
@@ -569,8 +576,8 @@
     grpc_end2end_test_config config) {
   request_with_payload_template(
       config, "test_invoke_request_with_compressed_payload", 0,
-      GRPC_COMPRESS_MESSAGE_GZIP, GRPC_COMPRESS_MESSAGE_GZIP,
-      GRPC_COMPRESS_MESSAGE_GZIP, GRPC_COMPRESS_MESSAGE_GZIP, nullptr, false,
+      GRPC_COMPRESS_GZIP, GRPC_COMPRESS_GZIP, GRPC_COMPRESS_GZIP,
+      GRPC_COMPRESS_GZIP, nullptr, false,
       /* ignored */ GRPC_COMPRESS_LEVEL_NONE, false);
 }
 
@@ -578,8 +585,8 @@
     grpc_end2end_test_config config) {
   request_with_payload_template(
       config, "test_invoke_request_with_compressed_payload", 0,
-      GRPC_COMPRESS_MESSAGE_GZIP, GRPC_COMPRESS_MESSAGE_GZIP,
-      GRPC_COMPRESS_MESSAGE_GZIP, GRPC_COMPRESS_MESSAGE_GZIP, nullptr, false,
+      GRPC_COMPRESS_GZIP, GRPC_COMPRESS_GZIP, GRPC_COMPRESS_GZIP,
+      GRPC_COMPRESS_GZIP, nullptr, false,
       /* ignored */ GRPC_COMPRESS_LEVEL_NONE, true);
 }
 
@@ -597,8 +604,7 @@
   grpc_metadata identity_compression_override;
 
   gzip_compression_override.key = GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST;
-  gzip_compression_override.value =
-      grpc_slice_from_static_string("message/gzip");
+  gzip_compression_override.value = grpc_slice_from_static_string("gzip");
   memset(&gzip_compression_override.internal_data, 0,
          sizeof(gzip_compression_override.internal_data));
 
@@ -611,32 +617,31 @@
   /* Channel default NONE (aka IDENTITY), call override to GZIP */
   request_with_payload_template(
       config, "test_invoke_request_with_compressed_payload_md_override_1", 0,
-      GRPC_COMPRESS_NONE, GRPC_COMPRESS_NONE, GRPC_COMPRESS_MESSAGE_GZIP,
+      GRPC_COMPRESS_NONE, GRPC_COMPRESS_NONE, GRPC_COMPRESS_GZIP,
       GRPC_COMPRESS_NONE, &gzip_compression_override, false,
       /*ignored*/ GRPC_COMPRESS_LEVEL_NONE, false);
 
   /* Channel default DEFLATE, call override to GZIP */
   request_with_payload_template(
       config, "test_invoke_request_with_compressed_payload_md_override_2", 0,
-      GRPC_COMPRESS_MESSAGE_DEFLATE, GRPC_COMPRESS_NONE,
-      GRPC_COMPRESS_MESSAGE_GZIP, GRPC_COMPRESS_NONE,
-      &gzip_compression_override, false,
+      GRPC_COMPRESS_DEFLATE, GRPC_COMPRESS_NONE, GRPC_COMPRESS_GZIP,
+      GRPC_COMPRESS_NONE, &gzip_compression_override, false,
       /*ignored*/ GRPC_COMPRESS_LEVEL_NONE, false);
 
   /* Channel default DEFLATE, call override to NONE (aka IDENTITY) */
   request_with_payload_template(
       config, "test_invoke_request_with_compressed_payload_md_override_3", 0,
-      GRPC_COMPRESS_MESSAGE_DEFLATE, GRPC_COMPRESS_NONE, GRPC_COMPRESS_NONE,
+      GRPC_COMPRESS_DEFLATE, GRPC_COMPRESS_NONE, GRPC_COMPRESS_NONE,
       GRPC_COMPRESS_NONE, &identity_compression_override, false,
       /*ignored*/ GRPC_COMPRESS_LEVEL_NONE, false);
 }
 
 static void test_invoke_request_with_disabled_algorithm(
     grpc_end2end_test_config config) {
-  request_for_disabled_algorithm(
-      config, "test_invoke_request_with_disabled_algorithm", 0,
-      GRPC_COMPRESS_MESSAGE_GZIP, GRPC_COMPRESS_MESSAGE_GZIP,
-      GRPC_STATUS_UNIMPLEMENTED, nullptr);
+  request_for_disabled_algorithm(config,
+                                 "test_invoke_request_with_disabled_algorithm",
+                                 0, GRPC_COMPRESS_GZIP, GRPC_COMPRESS_GZIP,
+                                 GRPC_STATUS_UNIMPLEMENTED, nullptr);
 }
 
 void compressed_payload(grpc_end2end_test_config config) {
diff --git a/test/core/end2end/tests/connectivity.cc b/test/core/end2end/tests/connectivity.cc
index da65080..caa4265 100644
--- a/test/core/end2end/tests/connectivity.cc
+++ b/test/core/end2end/tests/connectivity.cc
@@ -20,9 +20,9 @@
 
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
 
+#include "src/core/lib/gprpp/thd.h"
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -34,7 +34,7 @@
 } child_events;
 
 static void child_thread(void* arg) {
-  child_events* ce = (child_events*)arg;
+  child_events* ce = static_cast<child_events*>(arg);
   grpc_event ev;
   gpr_event_set(&ce->started, (void*)1);
   gpr_log(GPR_DEBUG, "verifying");
@@ -50,8 +50,6 @@
   grpc_connectivity_state state;
   cq_verifier* cqv = cq_verifier_create(f.cq);
   child_events ce;
-  gpr_thd_options thdopt = gpr_thd_options_default();
-  gpr_thd_id thdid;
 
   grpc_channel_args client_args;
   grpc_arg arg_array[1];
@@ -67,9 +65,8 @@
   ce.channel = f.client;
   ce.cq = f.cq;
   gpr_event_init(&ce.started);
-  gpr_thd_options_set_joinable(&thdopt);
-  GPR_ASSERT(
-      gpr_thd_new(&thdid, "grpc_connectivity", child_thread, &ce, &thdopt));
+  grpc_core::Thread thd("grpc_connectivity", child_thread, &ce);
+  thd.Start();
 
   gpr_event_wait(&ce.started, gpr_inf_future(GPR_CLOCK_MONOTONIC));
 
@@ -86,7 +83,7 @@
       f.client, GRPC_CHANNEL_IDLE, gpr_now(GPR_CLOCK_MONOTONIC), f.cq, tag(1));
 
   /* eventually the child thread completion should trigger */
-  gpr_thd_join(thdid);
+  thd.Join();
 
   /* check that we're still in idle, and start connecting */
   GPR_ASSERT(grpc_channel_check_connectivity_state(f.client, 1) ==
diff --git a/test/core/end2end/tests/default_host.cc b/test/core/end2end/tests/default_host.cc
index 7c94420..3191f76 100644
--- a/test/core/end2end/tests/default_host.cc
+++ b/test/core/end2end/tests/default_host.cc
@@ -26,7 +26,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "src/core/lib/gpr/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
@@ -141,7 +140,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(error == GRPC_CALL_OK);
 
   error =
@@ -180,7 +180,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(error == GRPC_CALL_OK);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
diff --git a/test/core/end2end/tests/disappearing_server.cc b/test/core/end2end/tests/disappearing_server.cc
index 29fb194..d5b6f8f 100644
--- a/test/core/end2end/tests/disappearing_server.cc
+++ b/test/core/end2end/tests/disappearing_server.cc
@@ -25,7 +25,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -121,7 +120,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -155,7 +155,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
diff --git a/test/core/end2end/tests/empty_batch.cc b/test/core/end2end/tests/empty_batch.cc
index c41e65d..1de4b8f 100644
--- a/test/core/end2end/tests/empty_batch.cc
+++ b/test/core/end2end/tests/empty_batch.cc
@@ -26,7 +26,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "src/core/lib/gpr/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
diff --git a/test/core/end2end/tests/filter_call_init_fails.cc b/test/core/end2end/tests/filter_call_init_fails.cc
index 8f46f0b..6f72a18 100644
--- a/test/core/end2end/tests/filter_call_init_fails.cc
+++ b/test/core/end2end/tests/filter_call_init_fails.cc
@@ -27,7 +27,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "src/core/lib/channel/channel_stack_builder.h"
 #include "src/core/lib/surface/channel_init.h"
 #include "test/core/end2end/cq_verifier.h"
@@ -159,7 +158,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -254,7 +254,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
@@ -345,7 +346,8 @@
   op->reserved = nullptr;
   op++;
 
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
@@ -369,7 +371,8 @@
       nullptr);
   GPR_ASSERT(c);
 
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(2),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(2), 1);
diff --git a/test/core/end2end/tests/filter_causes_close.cc b/test/core/end2end/tests/filter_causes_close.cc
index ec8f9db..bc4cb86 100644
--- a/test/core/end2end/tests/filter_causes_close.cc
+++ b/test/core/end2end/tests/filter_causes_close.cc
@@ -26,7 +26,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "src/core/lib/channel/channel_stack_builder.h"
 #include "src/core/lib/surface/channel_init.h"
 #include "test/core/end2end/cq_verifier.h"
@@ -153,7 +152,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -198,8 +198,8 @@
 } channel_data;
 
 static void recv_im_ready(void* arg, grpc_error* error) {
-  grpc_call_element* elem = (grpc_call_element*)arg;
-  call_data* calld = (call_data*)elem->call_data;
+  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   GRPC_CLOSURE_RUN(
       calld->recv_im_ready,
       grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
@@ -210,7 +210,7 @@
 
 static void start_transport_stream_op_batch(
     grpc_call_element* elem, grpc_transport_stream_op_batch* op) {
-  call_data* calld = (call_data*)elem->call_data;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
   if (op->recv_initial_metadata) {
     calld->recv_im_ready =
         op->payload->recv_initial_metadata.recv_initial_metadata_ready;
diff --git a/test/core/end2end/tests/filter_latency.cc b/test/core/end2end/tests/filter_latency.cc
index 845cbc0..51f54c9 100644
--- a/test/core/end2end/tests/filter_latency.cc
+++ b/test/core/end2end/tests/filter_latency.cc
@@ -27,7 +27,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/channel/channel_stack_builder.h"
 #include "src/core/lib/surface/channel_init.h"
@@ -166,7 +165,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -197,7 +197,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -306,7 +307,7 @@
  */
 
 static bool maybe_add_filter(grpc_channel_stack_builder* builder, void* arg) {
-  grpc_channel_filter* filter = (grpc_channel_filter*)arg;
+  grpc_channel_filter* filter = static_cast<grpc_channel_filter*>(arg);
   if (g_enable_filter) {
     // Want to add the filter as close to the end as possible, to make
     // sure that all of the filters work well together.  However, we
diff --git a/test/core/end2end/tests/filter_status_code.cc b/test/core/end2end/tests/filter_status_code.cc
index 61c658b..32cd954 100644
--- a/test/core/end2end/tests/filter_status_code.cc
+++ b/test/core/end2end/tests/filter_status_code.cc
@@ -27,7 +27,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/channel/channel_stack_builder.h"
 #include "src/core/lib/surface/call.h"
@@ -165,7 +164,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -200,7 +200,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -251,7 +252,7 @@
 
 static grpc_error* init_call_elem(grpc_call_element* elem,
                                   const grpc_call_element_args* args) {
-  final_status_data* data = (final_status_data*)elem->call_data;
+  final_status_data* data = static_cast<final_status_data*>(elem->call_data);
   data->call = args->call_stack;
   return GRPC_ERROR_NONE;
 }
@@ -259,7 +260,7 @@
 static void client_destroy_call_elem(grpc_call_element* elem,
                                      const grpc_call_final_info* final_info,
                                      grpc_closure* ignored) {
-  final_status_data* data = (final_status_data*)elem->call_data;
+  final_status_data* data = static_cast<final_status_data*>(elem->call_data);
   gpr_mu_lock(&g_mu);
   // Some fixtures, like proxies, will spawn intermidiate calls
   // We only want the results from our explicit calls
@@ -274,7 +275,7 @@
 static void server_destroy_call_elem(grpc_call_element* elem,
                                      const grpc_call_final_info* final_info,
                                      grpc_closure* ignored) {
-  final_status_data* data = (final_status_data*)elem->call_data;
+  final_status_data* data = static_cast<final_status_data*>(elem->call_data);
   gpr_mu_lock(&g_mu);
   // Some fixtures, like proxies, will spawn intermidiate calls
   // We only want the results from our explicit calls
@@ -324,7 +325,7 @@
  */
 
 static bool maybe_add_filter(grpc_channel_stack_builder* builder, void* arg) {
-  grpc_channel_filter* filter = (grpc_channel_filter*)arg;
+  grpc_channel_filter* filter = static_cast<grpc_channel_filter*>(arg);
   if (g_enable_filter) {
     // Want to add the filter as close to the end as possible, to make
     // sure that all of the filters work well together.  However, we
diff --git a/test/core/end2end/tests/graceful_server_shutdown.cc b/test/core/end2end/tests/graceful_server_shutdown.cc
index bf11b49..3ef414f 100644
--- a/test/core/end2end/tests/graceful_server_shutdown.cc
+++ b/test/core/end2end/tests/graceful_server_shutdown.cc
@@ -25,7 +25,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -136,7 +135,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -170,7 +170,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
diff --git a/test/core/end2end/tests/high_initial_seqno.cc b/test/core/end2end/tests/high_initial_seqno.cc
index d4d4f5a..8767437 100644
--- a/test/core/end2end/tests/high_initial_seqno.cc
+++ b/test/core/end2end/tests/high_initial_seqno.cc
@@ -27,7 +27,6 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/gpr/string.h"
 #include "test/core/end2end/cq_verifier.h"
@@ -140,7 +139,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -170,7 +170,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
diff --git a/test/core/end2end/tests/hpack_size.cc b/test/core/end2end/tests/hpack_size.cc
index 0d6ec01..b4973684 100644
--- a/test/core/end2end/tests/hpack_size.cc
+++ b/test/core/end2end/tests/hpack_size.cc
@@ -27,9 +27,9 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -293,7 +293,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -323,7 +324,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
diff --git a/test/core/end2end/tests/idempotent_request.cc b/test/core/end2end/tests/idempotent_request.cc
index 7487e4d..56be2d6 100644
--- a/test/core/end2end/tests/idempotent_request.cc
+++ b/test/core/end2end/tests/idempotent_request.cc
@@ -26,7 +26,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
+
 #include "src/core/lib/gpr/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
@@ -144,7 +144,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -183,7 +184,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
diff --git a/test/core/end2end/tests/invoke_large_request.cc b/test/core/end2end/tests/invoke_large_request.cc
index 8a67e3c..1aab34c 100644
--- a/test/core/end2end/tests/invoke_large_request.cc
+++ b/test/core/end2end/tests/invoke_large_request.cc
@@ -26,7 +26,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -175,7 +176,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -197,7 +199,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -223,7 +226,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
diff --git a/test/core/end2end/tests/keepalive_timeout.cc b/test/core/end2end/tests/keepalive_timeout.cc
index 6482b86..c0771b8 100644
--- a/test/core/end2end/tests/keepalive_timeout.cc
+++ b/test/core/end2end/tests/keepalive_timeout.cc
@@ -25,10 +25,11 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
+
 #include "src/core/ext/transport/chttp2/transport/frame_ping.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "test/core/end2end/cq_verifier.h"
 
@@ -101,7 +102,7 @@
   grpc_arg keepalive_arg_elems[3];
   keepalive_arg_elems[0].type = GRPC_ARG_INTEGER;
   keepalive_arg_elems[0].key = const_cast<char*>(GRPC_ARG_KEEPALIVE_TIME_MS);
-  keepalive_arg_elems[0].value.integer = 1500;
+  keepalive_arg_elems[0].value.integer = 3500;
   keepalive_arg_elems[1].type = GRPC_ARG_INTEGER;
   keepalive_arg_elems[1].key = const_cast<char*>(GRPC_ARG_KEEPALIVE_TIMEOUT_MS);
   keepalive_arg_elems[1].value.integer = 0;
@@ -154,7 +155,8 @@
   op->op = GRPC_OP_RECV_MESSAGE;
   op->data.recv_message.recv_message = &response_payload_recv;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
@@ -171,7 +173,8 @@
   op->op = GRPC_OP_SEND_MESSAGE;
   op->data.send_message.send_message = response_payload;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -185,7 +188,8 @@
   op->data.recv_status_on_client.status = &status;
   op->data.recv_status_on_client.status_details = &details;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(3),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(3), 1);
diff --git a/test/core/end2end/tests/large_metadata.cc b/test/core/end2end/tests/large_metadata.cc
index 8ddf433..da0615b 100644
--- a/test/core/end2end/tests/large_metadata.cc
+++ b/test/core/end2end/tests/large_metadata.cc
@@ -25,7 +25,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -97,7 +96,7 @@
   grpc_arg arg;
   arg.type = GRPC_ARG_INTEGER;
   arg.key = const_cast<char*>(GRPC_ARG_MAX_METADATA_SIZE);
-  arg.value.integer = (int)large_size + 1024;
+  arg.value.integer = static_cast<int>(large_size) + 1024;
   grpc_channel_args args = {1, &arg};
   grpc_end2end_test_fixture f =
       begin_test(config, "test_request_with_large_metadata", &args, &args);
@@ -161,7 +160,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -185,7 +185,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -208,7 +209,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
diff --git a/test/core/end2end/tests/load_reporting_hook.cc b/test/core/end2end/tests/load_reporting_hook.cc
index e056bd5..9e79d02 100644
--- a/test/core/end2end/tests/load_reporting_hook.cc
+++ b/test/core/end2end/tests/load_reporting_hook.cc
@@ -24,7 +24,6 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/ext/filters/load_reporting/server_load_reporting_filter.h"
 #include "src/core/ext/filters/load_reporting/server_load_reporting_plugin.h"
@@ -186,7 +185,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -208,7 +208,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -236,7 +237,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
diff --git a/test/core/end2end/tests/max_concurrent_streams.cc b/test/core/end2end/tests/max_concurrent_streams.cc
index c053973..789b3d4 100644
--- a/test/core/end2end/tests/max_concurrent_streams.cc
+++ b/test/core/end2end/tests/max_concurrent_streams.cc
@@ -25,7 +25,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -136,7 +135,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -166,7 +166,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -275,7 +276,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c1, ops, (size_t)(op - ops), tag(301), nullptr);
+  error = grpc_call_start_batch(c1, ops, static_cast<size_t>(op - ops),
+                                tag(301), nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   memset(ops, 0, sizeof(ops));
@@ -293,7 +295,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c1, ops, (size_t)(op - ops), tag(302), nullptr);
+  error = grpc_call_start_batch(c1, ops, static_cast<size_t>(op - ops),
+                                tag(302), nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   memset(ops, 0, sizeof(ops));
@@ -307,7 +310,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c2, ops, (size_t)(op - ops), tag(401), nullptr);
+  error = grpc_call_start_batch(c2, ops, static_cast<size_t>(op - ops),
+                                tag(401), nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   memset(ops, 0, sizeof(ops));
@@ -325,7 +329,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c2, ops, (size_t)(op - ops), tag(402), nullptr);
+  error = grpc_call_start_batch(c2, ops, static_cast<size_t>(op - ops),
+                                tag(402), nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   got_client_start = 0;
@@ -346,7 +351,7 @@
        * both);
        * check this here */
       /* We'll get tag 303 or 403, we want 300, 400 */
-      live_call = ((int)(intptr_t)ev.tag) - 1;
+      live_call = (static_cast<int>((intptr_t)ev.tag)) - 1;
       got_client_start = 1;
     }
   }
@@ -372,7 +377,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s1, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s1, ops, static_cast<size_t>(op - ops),
+                                tag(102), nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -409,7 +415,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s2, ops, (size_t)(op - ops), tag(202), nullptr);
+  error = grpc_call_start_batch(s2, ops, static_cast<size_t>(op - ops),
+                                tag(202), nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(live_call + 2), 1);
@@ -515,7 +522,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c1, ops, (size_t)(op - ops), tag(301), nullptr);
+  error = grpc_call_start_batch(c1, ops, static_cast<size_t>(op - ops),
+                                tag(301), nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   memset(ops, 0, sizeof(ops));
@@ -533,7 +541,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c1, ops, (size_t)(op - ops), tag(302), nullptr);
+  error = grpc_call_start_batch(c1, ops, static_cast<size_t>(op - ops),
+                                tag(302), nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
@@ -551,7 +560,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c2, ops, (size_t)(op - ops), tag(401), nullptr);
+  error = grpc_call_start_batch(c2, ops, static_cast<size_t>(op - ops),
+                                tag(401), nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   memset(ops, 0, sizeof(ops));
@@ -569,7 +579,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c2, ops, (size_t)(op - ops), tag(402), nullptr);
+  error = grpc_call_start_batch(c2, ops, static_cast<size_t>(op - ops),
+                                tag(402), nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   grpc_call_details_destroy(&call_details);
@@ -604,7 +615,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s2, ops, (size_t)(op - ops), tag(202), nullptr);
+  error = grpc_call_start_batch(s2, ops, static_cast<size_t>(op - ops),
+                                tag(202), nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(402), 1);
@@ -710,7 +722,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c1, ops, (size_t)(op - ops), tag(301), nullptr);
+  error = grpc_call_start_batch(c1, ops, static_cast<size_t>(op - ops),
+                                tag(301), nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   memset(ops, 0, sizeof(ops));
@@ -728,7 +741,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c1, ops, (size_t)(op - ops), tag(302), nullptr);
+  error = grpc_call_start_batch(c1, ops, static_cast<size_t>(op - ops),
+                                tag(302), nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
@@ -746,7 +760,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c2, ops, (size_t)(op - ops), tag(401), nullptr);
+  error = grpc_call_start_batch(c2, ops, static_cast<size_t>(op - ops),
+                                tag(401), nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   memset(ops, 0, sizeof(ops));
@@ -764,7 +779,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c2, ops, (size_t)(op - ops), tag(402), nullptr);
+  error = grpc_call_start_batch(c2, ops, static_cast<size_t>(op - ops),
+                                tag(402), nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   /* the second request is time out*/
@@ -797,7 +813,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s1, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s1, ops, static_cast<size_t>(op - ops),
+                                tag(102), nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(302), 1);
diff --git a/test/core/end2end/tests/max_connection_age.cc b/test/core/end2end/tests/max_connection_age.cc
index ddccfc3..e494dad 100644
--- a/test/core/end2end/tests/max_connection_age.cc
+++ b/test/core/end2end/tests/max_connection_age.cc
@@ -24,8 +24,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
+#include "src/core/lib/gpr/useful.h"
 #include "test/core/end2end/cq_verifier.h"
 
 #define MAX_CONNECTION_AGE_MS 500
@@ -145,7 +145,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -156,7 +157,8 @@
   cq_verify(cqv);
 
   gpr_timespec expect_shutdown_time = grpc_timeout_milliseconds_to_deadline(
-      (int)(MAX_CONNECTION_AGE_MS * MAX_CONNECTION_AGE_JITTER_MULTIPLIER) +
+      static_cast<int>(MAX_CONNECTION_AGE_MS *
+                       MAX_CONNECTION_AGE_JITTER_MULTIPLIER) +
       MAX_CONNECTION_AGE_GRACE_MS + IMMEDIATE_SHUTDOWN_GRACE_TIME_MS);
 
   /* Wait for the channel to reach its max age */
@@ -190,7 +192,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
   CQ_EXPECT_COMPLETION(cqv, tag(102), true);
   cq_verify(cqv);
@@ -288,7 +291,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -325,7 +329,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), true);
diff --git a/test/core/end2end/tests/max_connection_idle.cc b/test/core/end2end/tests/max_connection_idle.cc
index 293ff7d..2f212b9 100644
--- a/test/core/end2end/tests/max_connection_idle.cc
+++ b/test/core/end2end/tests/max_connection_idle.cc
@@ -25,8 +25,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
+#include "src/core/lib/gpr/useful.h"
 #include "test/core/end2end/cq_verifier.h"
 
 #define MAX_CONNECTION_IDLE_MS 500
@@ -100,7 +100,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -139,7 +140,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
diff --git a/test/core/end2end/tests/max_message_length.cc b/test/core/end2end/tests/max_message_length.cc
index e581f1f..fa5b3b6 100644
--- a/test/core/end2end/tests/max_message_length.cc
+++ b/test/core/end2end/tests/max_message_length.cc
@@ -25,9 +25,9 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/transport/metadata.h"
 #include "src/core/lib/transport/service_config.h"
@@ -220,7 +220,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   if (send_limit) {
@@ -248,7 +249,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -409,7 +411,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -444,7 +447,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
diff --git a/test/core/end2end/tests/negative_deadline.cc b/test/core/end2end/tests/negative_deadline.cc
index b752bf9..dce3a02 100644
--- a/test/core/end2end/tests/negative_deadline.cc
+++ b/test/core/end2end/tests/negative_deadline.cc
@@ -18,6 +18,7 @@
 
 #include "test/core/end2end/end2end_tests.h"
 
+#include <inttypes.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -26,7 +27,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "src/core/lib/gpr/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
diff --git a/test/core/end2end/tests/network_status_change.cc b/test/core/end2end/tests/network_status_change.cc
index 7d0318f..83cb172 100644
--- a/test/core/end2end/tests/network_status_change.cc
+++ b/test/core/end2end/tests/network_status_change.cc
@@ -25,7 +25,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
 /* this is a private API but exposed here for testing*/
@@ -151,7 +150,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
@@ -171,7 +171,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -194,7 +195,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
diff --git a/test/core/end2end/tests/no_logging.cc b/test/core/end2end/tests/no_logging.cc
index d89918b..b357e3b 100644
--- a/test/core/end2end/tests/no_logging.cc
+++ b/test/core/end2end/tests/no_logging.cc
@@ -27,7 +27,6 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/error.h"
 #include "test/core/end2end/cq_verifier.h"
@@ -171,7 +170,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -208,7 +208,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
diff --git a/test/core/end2end/tests/no_op.cc b/test/core/end2end/tests/no_op.cc
index 18c2367..020f842 100644
--- a/test/core/end2end/tests/no_op.cc
+++ b/test/core/end2end/tests/no_op.cc
@@ -25,7 +25,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
diff --git a/test/core/end2end/tests/payload.cc b/test/core/end2end/tests/payload.cc
index 2e9513b..340c76e 100644
--- a/test/core/end2end/tests/payload.cc
+++ b/test/core/end2end/tests/payload.cc
@@ -25,7 +25,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -91,9 +90,9 @@
   static const char chars[] = "abcdefghijklmnopqrstuvwxyz1234567890";
   char* output;
   const size_t output_size = 1024 * 1024;
-  output = (char*)gpr_malloc(output_size);
+  output = static_cast<char*>(gpr_malloc(output_size));
   for (i = 0; i < output_size - 1; ++i) {
-    output[i] = chars[rand() % (int)(sizeof(chars) - 1)];
+    output[i] = chars[rand() % static_cast<int>(sizeof(chars) - 1)];
   }
   output[output_size - 1] = '\0';
   grpc_slice out = grpc_slice_from_copied_string(output);
@@ -175,7 +174,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -197,7 +197,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -223,7 +224,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
diff --git a/test/core/end2end/tests/ping.cc b/test/core/end2end/tests/ping.cc
index 725a425..f523cbb 100644
--- a/test/core/end2end/tests/ping.cc
+++ b/test/core/end2end/tests/ping.cc
@@ -20,10 +20,9 @@
 
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
+#include "src/core/lib/gpr/useful.h"
 #include "test/core/end2end/cq_verifier.h"
 
 #define PING_NUM 5
diff --git a/test/core/end2end/tests/ping_pong_streaming.cc b/test/core/end2end/tests/ping_pong_streaming.cc
index ec7981f..9ca8804 100644
--- a/test/core/end2end/tests/ping_pong_streaming.cc
+++ b/test/core/end2end/tests/ping_pong_streaming.cc
@@ -25,7 +25,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -144,7 +143,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -166,7 +166,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(101), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(101),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   for (i = 0; i < messages; i++) {
@@ -185,7 +186,8 @@
     op->flags = 0;
     op->reserved = nullptr;
     op++;
-    error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
+    error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(2),
+                                  nullptr);
     GPR_ASSERT(GRPC_CALL_OK == error);
 
     memset(ops, 0, sizeof(ops));
@@ -195,8 +197,8 @@
     op->flags = 0;
     op->reserved = nullptr;
     op++;
-    error =
-        grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+    error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops),
+                                  tag(102), nullptr);
     GPR_ASSERT(GRPC_CALL_OK == error);
     CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
     cq_verify(cqv);
@@ -208,8 +210,8 @@
     op->flags = 0;
     op->reserved = nullptr;
     op++;
-    error =
-        grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+    error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops),
+                                  tag(103), nullptr);
     GPR_ASSERT(GRPC_CALL_OK == error);
     CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
     CQ_EXPECT_COMPLETION(cqv, tag(2), 1);
@@ -230,7 +232,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(3),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   memset(ops, 0, sizeof(ops));
@@ -243,7 +246,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(104),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/proxy_auth.cc b/test/core/end2end/tests/proxy_auth.cc
index 495151b..5a2e0ef 100644
--- a/test/core/end2end/tests/proxy_auth.cc
+++ b/test/core/end2end/tests/proxy_auth.cc
@@ -31,7 +31,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "src/core/lib/gpr/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
@@ -149,7 +148,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -188,7 +188,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
diff --git a/test/core/end2end/tests/registered_call.cc b/test/core/end2end/tests/registered_call.cc
index cefa89d..d4ca146 100644
--- a/test/core/end2end/tests/registered_call.cc
+++ b/test/core/end2end/tests/registered_call.cc
@@ -26,7 +26,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
+
 #include "src/core/lib/gpr/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
@@ -135,7 +135,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -165,7 +166,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
diff --git a/test/core/end2end/tests/request_with_flags.cc b/test/core/end2end/tests/request_with_flags.cc
index 984d8b1..c524824 100644
--- a/test/core/end2end/tests/request_with_flags.cc
+++ b/test/core/end2end/tests/request_with_flags.cc
@@ -25,7 +25,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/transport/byte_stream.h"
 #include "test/core/end2end/cq_verifier.h"
 
@@ -47,14 +48,12 @@
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_from_now(void) {
-  return n_seconds_from_now(5);
-}
+static gpr_timespec one_second_from_now(void) { return n_seconds_from_now(1); }
 
 static void drain_cq(grpc_completion_queue* cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+    ev = grpc_completion_queue_next(cq, one_second_from_now(), nullptr);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -108,7 +107,7 @@
   grpc_slice details;
   grpc_call_error expectation;
 
-  gpr_timespec deadline = five_seconds_from_now();
+  gpr_timespec deadline = one_second_from_now();
   c = grpc_channel_create_call(
       f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
@@ -150,7 +149,8 @@
   op->reserved = nullptr;
   op++;
   expectation = call_start_batch_expected_result;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(expectation == error);
 
   if (expectation == GRPC_CALL_OK) {
diff --git a/test/core/end2end/tests/request_with_payload.cc b/test/core/end2end/tests/request_with_payload.cc
index b3b9ee5..44398df 100644
--- a/test/core/end2end/tests/request_with_payload.cc
+++ b/test/core/end2end/tests/request_with_payload.cc
@@ -25,7 +25,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -148,7 +147,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
@@ -169,7 +169,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -190,7 +191,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
diff --git a/test/core/end2end/tests/resource_quota_server.cc b/test/core/end2end/tests/resource_quota_server.cc
index 0ee014f..33d6b4e 100644
--- a/test/core/end2end/tests/resource_quota_server.cc
+++ b/test/core/end2end/tests/resource_quota_server.cc
@@ -25,7 +25,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
+
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -91,9 +91,9 @@
   static const char chars[] = "abcdefghijklmnopqrstuvwxyz1234567890";
   char* output;
   const size_t output_size = 1024 * 1024;
-  output = (char*)gpr_malloc(output_size);
+  output = static_cast<char*>(gpr_malloc(output_size));
   for (i = 0; i < output_size - 1; ++i) {
-    output[i] = chars[rand() % (int)(sizeof(chars) - 1)];
+    output[i] = chars[rand() % static_cast<int>(sizeof(chars) - 1)];
   }
   output[output_size - 1] = '\0';
   grpc_slice out = grpc_slice_from_copied_string(output);
@@ -132,25 +132,29 @@
   grpc_slice request_payload_slice = generate_random_slice();
 
   grpc_call** client_calls =
-      (grpc_call**)malloc(sizeof(grpc_call*) * NUM_CALLS);
+      static_cast<grpc_call**>(malloc(sizeof(grpc_call*) * NUM_CALLS));
   grpc_call** server_calls =
-      (grpc_call**)malloc(sizeof(grpc_call*) * NUM_CALLS);
+      static_cast<grpc_call**>(malloc(sizeof(grpc_call*) * NUM_CALLS));
   grpc_metadata_array* initial_metadata_recv =
-      (grpc_metadata_array*)malloc(sizeof(grpc_metadata_array) * NUM_CALLS);
+      static_cast<grpc_metadata_array*>(
+          malloc(sizeof(grpc_metadata_array) * NUM_CALLS));
   grpc_metadata_array* trailing_metadata_recv =
-      (grpc_metadata_array*)malloc(sizeof(grpc_metadata_array) * NUM_CALLS);
+      static_cast<grpc_metadata_array*>(
+          malloc(sizeof(grpc_metadata_array) * NUM_CALLS));
   grpc_metadata_array* request_metadata_recv =
-      (grpc_metadata_array*)malloc(sizeof(grpc_metadata_array) * NUM_CALLS);
-  grpc_call_details* call_details =
-      (grpc_call_details*)malloc(sizeof(grpc_call_details) * NUM_CALLS);
-  grpc_status_code* status =
-      (grpc_status_code*)malloc(sizeof(grpc_status_code) * NUM_CALLS);
-  grpc_slice* details = (grpc_slice*)malloc(sizeof(grpc_slice) * NUM_CALLS);
-  grpc_byte_buffer** request_payload =
-      (grpc_byte_buffer**)malloc(sizeof(grpc_byte_buffer*) * NUM_CALLS);
-  grpc_byte_buffer** request_payload_recv =
-      (grpc_byte_buffer**)malloc(sizeof(grpc_byte_buffer*) * NUM_CALLS);
-  int* was_cancelled = (int*)malloc(sizeof(int) * NUM_CALLS);
+      static_cast<grpc_metadata_array*>(
+          malloc(sizeof(grpc_metadata_array) * NUM_CALLS));
+  grpc_call_details* call_details = static_cast<grpc_call_details*>(
+      malloc(sizeof(grpc_call_details) * NUM_CALLS));
+  grpc_status_code* status = static_cast<grpc_status_code*>(
+      malloc(sizeof(grpc_status_code) * NUM_CALLS));
+  grpc_slice* details =
+      static_cast<grpc_slice*>(malloc(sizeof(grpc_slice) * NUM_CALLS));
+  grpc_byte_buffer** request_payload = static_cast<grpc_byte_buffer**>(
+      malloc(sizeof(grpc_byte_buffer*) * NUM_CALLS));
+  grpc_byte_buffer** request_payload_recv = static_cast<grpc_byte_buffer**>(
+      malloc(sizeof(grpc_byte_buffer*) * NUM_CALLS));
+  int* was_cancelled = static_cast<int*>(malloc(sizeof(int) * NUM_CALLS));
   grpc_call_error error;
   int pending_client_calls = 0;
   int pending_server_start_calls = 0;
@@ -220,7 +224,8 @@
     op->flags = 0;
     op->reserved = nullptr;
     op++;
-    error = grpc_call_start_batch(client_calls[i], ops, (size_t)(op - ops),
+    error = grpc_call_start_batch(client_calls[i], ops,
+                                  static_cast<size_t>(op - ops),
                                   tag(CLIENT_BASE_TAG + i), nullptr);
     GPR_ASSERT(GRPC_CALL_OK == error);
 
@@ -234,7 +239,7 @@
         grpc_completion_queue_next(f.cq, n_seconds_from_now(60), nullptr);
     GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
 
-    int ev_tag = (int)(intptr_t)ev.tag;
+    int ev_tag = static_cast<int>((intptr_t)ev.tag);
     if (ev_tag < CLIENT_BASE_TAG) {
       abort(); /* illegal tag */
     } else if (ev_tag < SERVER_START_BASE_TAG) {
@@ -285,9 +290,9 @@
       op->flags = 0;
       op->reserved = nullptr;
       op++;
-      error =
-          grpc_call_start_batch(server_calls[call_id], ops, (size_t)(op - ops),
-                                tag(SERVER_RECV_BASE_TAG + call_id), nullptr);
+      error = grpc_call_start_batch(
+          server_calls[call_id], ops, static_cast<size_t>(op - ops),
+          tag(SERVER_RECV_BASE_TAG + call_id), nullptr);
       GPR_ASSERT(GRPC_CALL_OK == error);
 
       GPR_ASSERT(pending_server_start_calls > 0);
@@ -326,9 +331,9 @@
       op->flags = 0;
       op->reserved = nullptr;
       op++;
-      error =
-          grpc_call_start_batch(server_calls[call_id], ops, (size_t)(op - ops),
-                                tag(SERVER_END_BASE_TAG + call_id), nullptr);
+      error = grpc_call_start_batch(
+          server_calls[call_id], ops, static_cast<size_t>(op - ops),
+          tag(SERVER_END_BASE_TAG + call_id), nullptr);
       GPR_ASSERT(GRPC_CALL_OK == error);
 
       GPR_ASSERT(pending_server_recv_calls > 0);
diff --git a/test/core/end2end/tests/retry.cc b/test/core/end2end/tests/retry.cc
new file mode 100644
index 0000000..38ecc6f
--- /dev/null
+++ b/test/core/end2end/tests/retry.cc
@@ -0,0 +1,325 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/end2end/tests/cancel_test_helpers.h"
+
+static void* tag(intptr_t t) { return (void*)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char* test_name,
+                                            grpc_channel_args* client_args,
+                                            grpc_channel_args* server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_from_now(int n) {
+  return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue* cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture* f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         nullptr)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = nullptr;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture* f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = nullptr;
+}
+
+static void end_test(grpc_end2end_test_fixture* f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+// Tests a basic retry scenario:
+// - 2 retries allowed for ABORTED status
+// - first attempt returns ABORTED
+// - second attempt returns OK
+static void test_retry(grpc_end2end_test_config config) {
+  grpc_call* c;
+  grpc_call* s;
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
+  grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
+  grpc_byte_buffer* request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer* response_payload =
+      grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+  grpc_byte_buffer* request_payload_recv = nullptr;
+  grpc_byte_buffer* response_payload_recv = nullptr;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+  char* peer;
+
+  grpc_arg arg;
+  arg.type = GRPC_ARG_STRING;
+  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
+  arg.value.string = const_cast<char*>(
+      "{\n"
+      "  \"methodConfig\": [ {\n"
+      "    \"name\": [\n"
+      "      { \"service\": \"service\", \"method\": \"method\" }\n"
+      "    ],\n"
+      "    \"retryPolicy\": {\n"
+      "      \"maxAttempts\": 3,\n"
+      "      \"initialBackoff\": \"1s\",\n"
+      "      \"maxBackoff\": \"120s\",\n"
+      "      \"backoffMultiplier\": 1.6,\n"
+      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+      "    }\n"
+      "  } ]\n"
+      "}");
+  grpc_channel_args client_args = {1, &arg};
+  grpc_end2end_test_fixture f =
+      begin_test(config, "retry", &client_args, nullptr);
+
+  cq_verifier* cqv = cq_verifier_create(f.cq);
+
+  gpr_timespec deadline = five_seconds_from_now();
+  c = grpc_channel_create_call(
+      f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/service/method"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      nullptr);
+  GPR_ASSERT(c);
+
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
+  gpr_free(peer);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &response_payload_recv;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), true);
+  cq_verify(cqv);
+
+  // Make sure the "grpc-previous-rpc-attempts" header was not sent in the
+  // initial attempt.
+  for (size_t i = 0; i < request_metadata_recv.count; ++i) {
+    GPR_ASSERT(!grpc_slice_eq(request_metadata_recv.metadata[i].key,
+                              GRPC_MDSTR_GRPC_PREVIOUS_RPC_ATTEMPTS));
+  }
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(102), true);
+  cq_verify(cqv);
+
+  grpc_call_unref(s);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_call_details_init(&call_details);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(201));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(201), true);
+  cq_verify(cqv);
+
+  // Make sure the "grpc-previous-rpc-attempts" header was sent in the retry.
+  bool found_retry_header = false;
+  for (size_t i = 0; i < request_metadata_recv.count; ++i) {
+    if (grpc_slice_eq(request_metadata_recv.metadata[i].key,
+                      GRPC_MDSTR_GRPC_PREVIOUS_RPC_ATTEMPTS)) {
+      GPR_ASSERT(
+          grpc_slice_eq(request_metadata_recv.metadata[i].value, GRPC_MDSTR_1));
+      found_retry_header = true;
+      break;
+    }
+  }
+  GPR_ASSERT(found_retry_header);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &request_payload_recv;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = response_payload;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_OK;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(202), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(202), true);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), true);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
+  GPR_ASSERT(0 == call_details.flags);
+  GPR_ASSERT(was_cancelled == 0);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(response_payload);
+  grpc_byte_buffer_destroy(request_payload_recv);
+  grpc_byte_buffer_destroy(response_payload_recv);
+
+  grpc_call_unref(c);
+  grpc_call_unref(s);
+
+  cq_verifier_destroy(cqv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void retry(grpc_end2end_test_config config) {
+  GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
+  test_retry(config);
+}
+
+void retry_pre_init(void) {}
diff --git a/test/core/end2end/tests/retry_cancellation.cc b/test/core/end2end/tests/retry_cancellation.cc
new file mode 100644
index 0000000..0504092
--- /dev/null
+++ b/test/core/end2end/tests/retry_cancellation.cc
@@ -0,0 +1,277 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/end2end/tests/cancel_test_helpers.h"
+
+static void* tag(intptr_t t) { return (void*)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char* test_name,
+                                            grpc_channel_args* client_args,
+                                            grpc_channel_args* server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_from_now(int n) {
+  return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue* cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture* f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         nullptr)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = nullptr;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture* f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = nullptr;
+}
+
+static void end_test(grpc_end2end_test_fixture* f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+// Tests retry cancellation.
+static void test_retry_cancellation(grpc_end2end_test_config config,
+                                    cancellation_mode mode) {
+  grpc_call* c;
+  grpc_call* s;
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
+  grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
+  grpc_byte_buffer* request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer* response_payload =
+      grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+  grpc_byte_buffer* request_payload_recv = nullptr;
+  grpc_byte_buffer* response_payload_recv = nullptr;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+  char* peer;
+
+  grpc_arg arg;
+  arg.type = GRPC_ARG_STRING;
+  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
+  arg.value.string = const_cast<char*>(
+      "{\n"
+      "  \"methodConfig\": [ {\n"
+      "    \"name\": [\n"
+      "      { \"service\": \"service\", \"method\": \"method\" }\n"
+      "    ],\n"
+      "    \"retryPolicy\": {\n"
+      "      \"maxAttempts\": 3,\n"
+      "      \"initialBackoff\": \"1s\",\n"
+      "      \"maxBackoff\": \"120s\",\n"
+      "      \"backoffMultiplier\": 1.6,\n"
+      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+      "    },\n"
+      "    \"timeout\": \"5s\"\n"
+      "  } ]\n"
+      "}");
+  grpc_channel_args client_args = {1, &arg};
+  char* name;
+  gpr_asprintf(&name, "retry_cancellation/%s", mode.name);
+  grpc_end2end_test_fixture f = begin_test(config, name, &client_args, nullptr);
+  gpr_free(name);
+
+  cq_verifier* cqv = cq_verifier_create(f.cq);
+
+  gpr_timespec deadline = five_seconds_from_now();
+  c = grpc_channel_create_call(
+      f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/service/method"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      nullptr);
+  GPR_ASSERT(c);
+
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
+  gpr_free(peer);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+
+  // Client starts a batch with all 6 ops.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &response_payload_recv;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  // Server gets a call and fails with retryable status.
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), true);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(102), true);
+  cq_verify(cqv);
+
+  grpc_call_unref(s);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_call_details_init(&call_details);
+
+  // Server gets a second call (the retry).
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(201));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(201), true);
+  cq_verify(cqv);
+
+  // Initiate cancellation.
+  GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c, nullptr));
+
+  CQ_EXPECT_COMPLETION(cqv, tag(1), true);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == mode.expect_status);
+  GPR_ASSERT(was_cancelled == 1);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(response_payload);
+  grpc_byte_buffer_destroy(request_payload_recv);
+  grpc_byte_buffer_destroy(response_payload_recv);
+
+  grpc_call_unref(c);
+  grpc_call_unref(s);
+
+  cq_verifier_destroy(cqv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void retry_cancellation(grpc_end2end_test_config config) {
+  GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(cancellation_modes); ++i) {
+    test_retry_cancellation(config, cancellation_modes[i]);
+  }
+}
+
+void retry_cancellation_pre_init(void) {}
diff --git a/test/core/end2end/tests/retry_disabled.cc b/test/core/end2end/tests/retry_disabled.cc
new file mode 100644
index 0000000..cb30502
--- /dev/null
+++ b/test/core/end2end/tests/retry_disabled.cc
@@ -0,0 +1,262 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/end2end/tests/cancel_test_helpers.h"
+
+static void* tag(intptr_t t) { return (void*)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char* test_name,
+                                            grpc_channel_args* client_args,
+                                            grpc_channel_args* server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_from_now(int n) {
+  return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue* cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture* f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         nullptr)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = nullptr;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture* f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = nullptr;
+}
+
+static void end_test(grpc_end2end_test_fixture* f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+// Tests that we don't retry when retries are disabled via the
+// GRPC_ARG_ENABLE_RETRIES channel arg, even when there is retry
+// configuration in the service config.
+// - 1 retry allowed for ABORTED status
+// - first attempt returns ABORTED but does not retry
+static void test_retry_disabled(grpc_end2end_test_config config) {
+  grpc_call* c;
+  grpc_call* s;
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
+  grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
+  grpc_byte_buffer* request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer* response_payload =
+      grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+  grpc_byte_buffer* request_payload_recv = nullptr;
+  grpc_byte_buffer* response_payload_recv = nullptr;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+  char* peer;
+
+  grpc_arg args[2];
+  args[0].type = GRPC_ARG_STRING;
+  args[0].key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
+  args[0].value.string = const_cast<char*>(
+      "{\n"
+      "  \"methodConfig\": [ {\n"
+      "    \"name\": [\n"
+      "      { \"service\": \"service\", \"method\": \"method\" }\n"
+      "    ],\n"
+      "    \"retryPolicy\": {\n"
+      "      \"maxAttempts\": 2,\n"
+      "      \"initialBackoff\": \"1s\",\n"
+      "      \"maxBackoff\": \"120s\",\n"
+      "      \"backoffMultiplier\": 1.6,\n"
+      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+      "    }\n"
+      "  } ]\n"
+      "}");
+  args[1].type = GRPC_ARG_INTEGER;
+  args[1].key = const_cast<char*>(GRPC_ARG_ENABLE_RETRIES);
+  args[1].value.integer = 0;
+  grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
+  grpc_end2end_test_fixture f =
+      begin_test(config, "retry_disabled", &client_args, nullptr);
+
+  cq_verifier* cqv = cq_verifier_create(f.cq);
+
+  gpr_timespec deadline = five_seconds_from_now();
+  c = grpc_channel_create_call(
+      f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/service/method"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      nullptr);
+  GPR_ASSERT(c);
+
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
+  gpr_free(peer);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &response_payload_recv;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), true);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(102), true);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), true);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_ABORTED);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
+  GPR_ASSERT(0 == call_details.flags);
+  GPR_ASSERT(was_cancelled == 1);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(response_payload);
+  grpc_byte_buffer_destroy(request_payload_recv);
+  grpc_byte_buffer_destroy(response_payload_recv);
+
+  grpc_call_unref(c);
+  grpc_call_unref(s);
+
+  cq_verifier_destroy(cqv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void retry_disabled(grpc_end2end_test_config config) {
+  GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
+  test_retry_disabled(config);
+}
+
+void retry_disabled_pre_init(void) {}
diff --git a/test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc b/test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc
new file mode 100644
index 0000000..3908f29
--- /dev/null
+++ b/test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc
@@ -0,0 +1,266 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/end2end/tests/cancel_test_helpers.h"
+
+static void* tag(intptr_t t) { return (void*)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char* test_name,
+                                            grpc_channel_args* client_args,
+                                            grpc_channel_args* server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_from_now(int n) {
+  return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue* cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture* f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         nullptr)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = nullptr;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture* f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = nullptr;
+}
+
+static void end_test(grpc_end2end_test_fixture* f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+// Tests that we don't make any further attempts after we exceed the
+// max buffer size.
+// - 1 retry allowed for ABORTED status
+// - buffer size set to 2 bytes
+// - client sends a 3-byte message
+// - first attempt gets ABORTED but is not retried
+static void test_retry_exceeds_buffer_size_in_initial_batch(
+    grpc_end2end_test_config config) {
+  grpc_call* c;
+  grpc_call* s;
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
+  grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
+  grpc_byte_buffer* request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer* response_payload =
+      grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+  grpc_byte_buffer* request_payload_recv = nullptr;
+  grpc_byte_buffer* response_payload_recv = nullptr;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+  char* peer;
+
+  grpc_arg args[2];
+  args[0].type = GRPC_ARG_STRING;
+  args[0].key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
+  args[0].value.string = const_cast<char*>(
+      "{\n"
+      "  \"methodConfig\": [ {\n"
+      "    \"name\": [\n"
+      "      { \"service\": \"service\", \"method\": \"method\" }\n"
+      "    ],\n"
+      "    \"retryPolicy\": {\n"
+      "      \"maxAttempts\": 2,\n"
+      "      \"initialBackoff\": \"1s\",\n"
+      "      \"maxBackoff\": \"120s\",\n"
+      "      \"backoffMultiplier\": 1.6,\n"
+      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+      "    }\n"
+      "  } ]\n"
+      "}");
+  args[1].type = GRPC_ARG_INTEGER;
+  args[1].key = const_cast<char*>(GRPC_ARG_PER_RPC_RETRY_BUFFER_SIZE);
+  args[1].value.integer = 2;
+  grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
+  grpc_end2end_test_fixture f =
+      begin_test(config, "retry_exceeds_buffer_size_in_initial_batch",
+                 &client_args, nullptr);
+
+  cq_verifier* cqv = cq_verifier_create(f.cq);
+
+  gpr_timespec deadline = five_seconds_from_now();
+  c = grpc_channel_create_call(
+      f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/service/method"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      nullptr);
+  GPR_ASSERT(c);
+
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
+  gpr_free(peer);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &response_payload_recv;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), true);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(102), true);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), true);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_ABORTED);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
+  GPR_ASSERT(0 == call_details.flags);
+  GPR_ASSERT(was_cancelled == 1);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(response_payload);
+  grpc_byte_buffer_destroy(request_payload_recv);
+  grpc_byte_buffer_destroy(response_payload_recv);
+
+  grpc_call_unref(c);
+  grpc_call_unref(s);
+
+  cq_verifier_destroy(cqv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void retry_exceeds_buffer_size_in_initial_batch(
+    grpc_end2end_test_config config) {
+  GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
+  test_retry_exceeds_buffer_size_in_initial_batch(config);
+}
+
+void retry_exceeds_buffer_size_in_initial_batch_pre_init(void) {}
diff --git a/test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc b/test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc
new file mode 100644
index 0000000..409fac4
--- /dev/null
+++ b/test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc
@@ -0,0 +1,279 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/end2end/tests/cancel_test_helpers.h"
+
+static void* tag(intptr_t t) { return (void*)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char* test_name,
+                                            grpc_channel_args* client_args,
+                                            grpc_channel_args* server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_from_now(int n) {
+  return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue* cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture* f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         nullptr)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = nullptr;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture* f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = nullptr;
+}
+
+static void end_test(grpc_end2end_test_fixture* f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+// Similar to the retry_exceeds_buffer_size_in_initial_batch test, but we
+// don't exceed the buffer size until the second batch.
+// - 1 retry allowed for ABORTED status
+// - buffer size set to 100 KiB (larger than initial metadata)
+// - client sends a 100 KiB message
+// - first attempt gets ABORTED but is not retried
+static void test_retry_exceeds_buffer_size_in_subsequent_batch(
+    grpc_end2end_test_config config) {
+  grpc_call* c;
+  grpc_call* s;
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  const size_t buf_size = 102401;
+  char* buf = static_cast<char*>(gpr_malloc(buf_size * sizeof(*buf)));
+  memset(buf, 'a', buf_size - 1);
+  buf[buf_size - 1] = '\0';
+  // TODO(markdroth): buf is not a static string, so fix the next line
+  grpc_slice request_payload_slice = grpc_slice_from_static_string(buf);
+  grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
+  grpc_byte_buffer* request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer* response_payload =
+      grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+  grpc_byte_buffer* request_payload_recv = nullptr;
+  grpc_byte_buffer* response_payload_recv = nullptr;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+  char* peer;
+
+  grpc_arg args[2];
+  args[0].type = GRPC_ARG_STRING;
+  args[0].key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
+  args[0].value.string = const_cast<char*>(
+      "{\n"
+      "  \"methodConfig\": [ {\n"
+      "    \"name\": [\n"
+      "      { \"service\": \"service\", \"method\": \"method\" }\n"
+      "    ],\n"
+      "    \"retryPolicy\": {\n"
+      "      \"maxAttempts\": 2,\n"
+      "      \"initialBackoff\": \"1s\",\n"
+      "      \"maxBackoff\": \"120s\",\n"
+      "      \"backoffMultiplier\": 1.6,\n"
+      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+      "    }\n"
+      "  } ]\n"
+      "}");
+  args[1].type = GRPC_ARG_INTEGER;
+  args[1].key = const_cast<char*>(GRPC_ARG_PER_RPC_RETRY_BUFFER_SIZE);
+  args[1].value.integer = 102400;
+  grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
+  grpc_end2end_test_fixture f =
+      begin_test(config, "retry_exceeds_buffer_size_in_subsequent_batch",
+                 &client_args, nullptr);
+
+  cq_verifier* cqv = cq_verifier_create(f.cq);
+
+  gpr_timespec deadline = five_seconds_from_now();
+  c = grpc_channel_create_call(
+      f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/service/method"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      nullptr);
+  GPR_ASSERT(c);
+
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
+  gpr_free(peer);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), true);
+  cq_verify(cqv);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &response_payload_recv;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), true);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(102), true);
+  CQ_EXPECT_COMPLETION(cqv, tag(2), true);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_ABORTED);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
+  GPR_ASSERT(0 == call_details.flags);
+  GPR_ASSERT(was_cancelled == 1);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(response_payload);
+  grpc_byte_buffer_destroy(request_payload_recv);
+  grpc_byte_buffer_destroy(response_payload_recv);
+
+  grpc_call_unref(c);
+  grpc_call_unref(s);
+
+  cq_verifier_destroy(cqv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+  gpr_free(buf);
+}
+
+void retry_exceeds_buffer_size_in_subsequent_batch(
+    grpc_end2end_test_config config) {
+  GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
+  test_retry_exceeds_buffer_size_in_subsequent_batch(config);
+}
+
+void retry_exceeds_buffer_size_in_subsequent_batch_pre_init(void) {}
diff --git a/test/core/end2end/tests/retry_non_retriable_status.cc b/test/core/end2end/tests/retry_non_retriable_status.cc
new file mode 100644
index 0000000..6d59db0
--- /dev/null
+++ b/test/core/end2end/tests/retry_non_retriable_status.cc
@@ -0,0 +1,257 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/end2end/tests/cancel_test_helpers.h"
+
+static void* tag(intptr_t t) { return (void*)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char* test_name,
+                                            grpc_channel_args* client_args,
+                                            grpc_channel_args* server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_from_now(int n) {
+  return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue* cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture* f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         nullptr)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = nullptr;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture* f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = nullptr;
+}
+
+static void end_test(grpc_end2end_test_fixture* f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+// Tests that we don't retry for non-retryable status codes.
+// - 1 retry allowed for ABORTED status
+// - first attempt gets INVALID_ARGUMENT, so no retry is done
+static void test_retry_non_retriable_status(grpc_end2end_test_config config) {
+  grpc_call* c;
+  grpc_call* s;
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
+  grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
+  grpc_byte_buffer* request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer* response_payload =
+      grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+  grpc_byte_buffer* request_payload_recv = nullptr;
+  grpc_byte_buffer* response_payload_recv = nullptr;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+  char* peer;
+
+  grpc_arg arg;
+  arg.type = GRPC_ARG_STRING;
+  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
+  arg.value.string = const_cast<char*>(
+      "{\n"
+      "  \"methodConfig\": [ {\n"
+      "    \"name\": [\n"
+      "      { \"service\": \"service\", \"method\": \"method\" }\n"
+      "    ],\n"
+      "    \"retryPolicy\": {\n"
+      "      \"maxAttempts\": 2,\n"
+      "      \"initialBackoff\": \"1s\",\n"
+      "      \"maxBackoff\": \"120s\",\n"
+      "      \"backoffMultiplier\": 1.6,\n"
+      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+      "    }\n"
+      "  } ]\n"
+      "}");
+  grpc_channel_args client_args = {1, &arg};
+  grpc_end2end_test_fixture f =
+      begin_test(config, "retry_non_retriable_status", &client_args, nullptr);
+
+  cq_verifier* cqv = cq_verifier_create(f.cq);
+
+  gpr_timespec deadline = five_seconds_from_now();
+  c = grpc_channel_create_call(
+      f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/service/method"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      nullptr);
+  GPR_ASSERT(c);
+
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
+  gpr_free(peer);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &response_payload_recv;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), true);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_INVALID_ARGUMENT;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(102), true);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), true);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_INVALID_ARGUMENT);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
+  GPR_ASSERT(0 == call_details.flags);
+  GPR_ASSERT(was_cancelled == 1);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(response_payload);
+  grpc_byte_buffer_destroy(request_payload_recv);
+  grpc_byte_buffer_destroy(response_payload_recv);
+
+  grpc_call_unref(c);
+  grpc_call_unref(s);
+
+  cq_verifier_destroy(cqv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void retry_non_retriable_status(grpc_end2end_test_config config) {
+  GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
+  test_retry_non_retriable_status(config);
+}
+
+void retry_non_retriable_status_pre_init(void) {}
diff --git a/test/core/end2end/tests/retry_recv_initial_metadata.cc b/test/core/end2end/tests/retry_recv_initial_metadata.cc
new file mode 100644
index 0000000..14215e4
--- /dev/null
+++ b/test/core/end2end/tests/retry_recv_initial_metadata.cc
@@ -0,0 +1,268 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/end2end/tests/cancel_test_helpers.h"
+
+static void* tag(intptr_t t) { return (void*)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char* test_name,
+                                            grpc_channel_args* client_args,
+                                            grpc_channel_args* server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_from_now(int n) {
+  return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue* cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture* f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         nullptr)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = nullptr;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture* f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = nullptr;
+}
+
+static void end_test(grpc_end2end_test_fixture* f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+// Tests that receiving initial metadata commits the call.
+// - 1 retry allowed for ABORTED status
+// - first attempt receives initial metadata before trailing metadata,
+//   so no retry is done even though status was ABORTED
+static void test_retry_recv_initial_metadata(grpc_end2end_test_config config) {
+  grpc_call* c;
+  grpc_call* s;
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
+  grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
+  grpc_byte_buffer* request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer* response_payload =
+      grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+  grpc_byte_buffer* request_payload_recv = nullptr;
+  grpc_byte_buffer* response_payload_recv = nullptr;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+  char* peer;
+
+  grpc_arg arg;
+  arg.type = GRPC_ARG_STRING;
+  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
+  arg.value.string = const_cast<char*>(
+      "{\n"
+      "  \"methodConfig\": [ {\n"
+      "    \"name\": [\n"
+      "      { \"service\": \"service\", \"method\": \"method\" }\n"
+      "    ],\n"
+      "    \"retryPolicy\": {\n"
+      "      \"maxAttempts\": 2,\n"
+      "      \"initialBackoff\": \"1s\",\n"
+      "      \"maxBackoff\": \"120s\",\n"
+      "      \"backoffMultiplier\": 1.6,\n"
+      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+      "    }\n"
+      "  } ]\n"
+      "}");
+  grpc_channel_args client_args = {1, &arg};
+  grpc_end2end_test_fixture f =
+      begin_test(config, "retry_recv_initial_metadata", &client_args, nullptr);
+
+  cq_verifier* cqv = cq_verifier_create(f.cq);
+
+  gpr_timespec deadline = five_seconds_from_now();
+  c = grpc_channel_create_call(
+      f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/service/method"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      nullptr);
+  GPR_ASSERT(c);
+
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
+  gpr_free(peer);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &response_payload_recv;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), true);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  // Server sends initial metadata in its own batch, before sending
+  // trailing metadata.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(102), true);
+  cq_verify(cqv);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(103), true);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), true);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_ABORTED);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
+  GPR_ASSERT(0 == call_details.flags);
+  GPR_ASSERT(was_cancelled == 1);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(response_payload);
+  grpc_byte_buffer_destroy(request_payload_recv);
+  grpc_byte_buffer_destroy(response_payload_recv);
+
+  grpc_call_unref(c);
+  grpc_call_unref(s);
+
+  cq_verifier_destroy(cqv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void retry_recv_initial_metadata(grpc_end2end_test_config config) {
+  GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
+  test_retry_recv_initial_metadata(config);
+}
+
+void retry_recv_initial_metadata_pre_init(void) {}
diff --git a/test/core/end2end/tests/retry_recv_message.cc b/test/core/end2end/tests/retry_recv_message.cc
new file mode 100644
index 0000000..86171fd
--- /dev/null
+++ b/test/core/end2end/tests/retry_recv_message.cc
@@ -0,0 +1,261 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/end2end/tests/cancel_test_helpers.h"
+
+static void* tag(intptr_t t) { return (void*)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char* test_name,
+                                            grpc_channel_args* client_args,
+                                            grpc_channel_args* server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_from_now(int n) {
+  return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue* cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture* f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         nullptr)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = nullptr;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture* f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = nullptr;
+}
+
+static void end_test(grpc_end2end_test_fixture* f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+// Tests that receiving a message commits the call.
+// - 1 retry allowed for ABORTED status
+// - first attempt receives a message and therefore does not retry even
+//   though the final status is ABORTED
+static void test_retry_recv_message(grpc_end2end_test_config config) {
+  grpc_call* c;
+  grpc_call* s;
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
+  grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
+  grpc_byte_buffer* request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer* response_payload =
+      grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+  grpc_byte_buffer* request_payload_recv = nullptr;
+  grpc_byte_buffer* response_payload_recv = nullptr;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+  char* peer;
+
+  grpc_arg arg;
+  arg.type = GRPC_ARG_STRING;
+  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
+  arg.value.string = const_cast<char*>(
+      "{\n"
+      "  \"methodConfig\": [ {\n"
+      "    \"name\": [\n"
+      "      { \"service\": \"service\", \"method\": \"method\" }\n"
+      "    ],\n"
+      "    \"retryPolicy\": {\n"
+      "      \"maxAttempts\": 2,\n"
+      "      \"initialBackoff\": \"1s\",\n"
+      "      \"maxBackoff\": \"120s\",\n"
+      "      \"backoffMultiplier\": 1.6,\n"
+      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+      "    }\n"
+      "  } ]\n"
+      "}");
+  grpc_channel_args client_args = {1, &arg};
+  grpc_end2end_test_fixture f =
+      begin_test(config, "retry_recv_message", &client_args, nullptr);
+
+  cq_verifier* cqv = cq_verifier_create(f.cq);
+
+  gpr_timespec deadline = five_seconds_from_now();
+  c = grpc_channel_create_call(
+      f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/service/method"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      nullptr);
+  GPR_ASSERT(c);
+
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
+  gpr_free(peer);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &response_payload_recv;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), true);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = response_payload;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(103), true);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), true);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_ABORTED);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
+  GPR_ASSERT(0 == call_details.flags);
+  GPR_ASSERT(was_cancelled == 1);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(response_payload);
+  grpc_byte_buffer_destroy(request_payload_recv);
+  grpc_byte_buffer_destroy(response_payload_recv);
+
+  grpc_call_unref(c);
+  grpc_call_unref(s);
+
+  cq_verifier_destroy(cqv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void retry_recv_message(grpc_end2end_test_config config) {
+  GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
+  test_retry_recv_message(config);
+}
+
+void retry_recv_message_pre_init(void) {}
diff --git a/test/core/end2end/tests/retry_server_pushback_delay.cc b/test/core/end2end/tests/retry_server_pushback_delay.cc
new file mode 100644
index 0000000..1da9860
--- /dev/null
+++ b/test/core/end2end/tests/retry_server_pushback_delay.cc
@@ -0,0 +1,318 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/end2end/tests/cancel_test_helpers.h"
+
+static void* tag(intptr_t t) { return (void*)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char* test_name,
+                                            grpc_channel_args* client_args,
+                                            grpc_channel_args* server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_from_now(int n) {
+  return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue* cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture* f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         nullptr)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = nullptr;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture* f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = nullptr;
+}
+
+static void end_test(grpc_end2end_test_fixture* f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+// Tests that we honor server push-back delay.
+// - 2 retries allowed for ABORTED status
+// - first attempt gets ABORTED with a long delay
+// - second attempt succeeds
+static void test_retry_server_pushback_delay(grpc_end2end_test_config config) {
+  grpc_call* c;
+  grpc_call* s;
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
+  grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
+  grpc_byte_buffer* request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer* response_payload =
+      grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+  grpc_byte_buffer* request_payload_recv = nullptr;
+  grpc_byte_buffer* response_payload_recv = nullptr;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+  char* peer;
+
+  grpc_metadata pushback_md;
+  memset(&pushback_md, 0, sizeof(pushback_md));
+  pushback_md.key = GRPC_MDSTR_GRPC_RETRY_PUSHBACK_MS;
+  pushback_md.value = grpc_slice_from_static_string("2000");
+
+  grpc_arg arg;
+  arg.type = GRPC_ARG_STRING;
+  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
+  arg.value.string = const_cast<char*>(
+      "{\n"
+      "  \"methodConfig\": [ {\n"
+      "    \"name\": [\n"
+      "      { \"service\": \"service\", \"method\": \"method\" }\n"
+      "    ],\n"
+      "    \"retryPolicy\": {\n"
+      "      \"maxAttempts\": 3,\n"
+      "      \"initialBackoff\": \"1s\",\n"
+      "      \"maxBackoff\": \"120s\",\n"
+      "      \"backoffMultiplier\": 1.6,\n"
+      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+      "    }\n"
+      "  } ]\n"
+      "}");
+  grpc_channel_args client_args = {1, &arg};
+  grpc_end2end_test_fixture f =
+      begin_test(config, "retry_server_pushback_delay", &client_args, nullptr);
+
+  cq_verifier* cqv = cq_verifier_create(f.cq);
+
+  gpr_timespec deadline = five_seconds_from_now();
+  c = grpc_channel_create_call(
+      f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/service/method"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      nullptr);
+  GPR_ASSERT(c);
+
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
+  gpr_free(peer);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &response_payload_recv;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), true);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 1;
+  op->data.send_status_from_server.trailing_metadata = &pushback_md;
+  op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(102), true);
+  cq_verify(cqv);
+
+  gpr_timespec before_retry = gpr_now(GPR_CLOCK_MONOTONIC);
+
+  grpc_call_unref(s);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_call_details_init(&call_details);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(201));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(201), true);
+  cq_verify(cqv);
+
+  gpr_timespec after_retry = gpr_now(GPR_CLOCK_MONOTONIC);
+  gpr_timespec retry_delay = gpr_time_sub(after_retry, before_retry);
+  // Configured back-off was 1 second, server push-back said 2 seconds.
+  // To avoid flakiness, we allow some fudge factor here.
+  gpr_log(GPR_INFO, "retry delay was {.tv_sec=%" PRId64 ", .tv_nsec=%d}",
+          retry_delay.tv_sec, retry_delay.tv_nsec);
+  GPR_ASSERT(retry_delay.tv_sec >= 1);
+  if (retry_delay.tv_sec == 1) {
+    GPR_ASSERT(retry_delay.tv_nsec >= 900000000);
+  }
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_OK;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(202), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(202), true);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), true);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
+  GPR_ASSERT(0 == call_details.flags);
+  GPR_ASSERT(was_cancelled == 0);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(response_payload);
+  grpc_byte_buffer_destroy(request_payload_recv);
+  grpc_byte_buffer_destroy(response_payload_recv);
+
+  grpc_call_unref(c);
+  grpc_call_unref(s);
+
+  cq_verifier_destroy(cqv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void retry_server_pushback_delay(grpc_end2end_test_config config) {
+  GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
+  test_retry_server_pushback_delay(config);
+}
+
+void retry_server_pushback_delay_pre_init(void) {}
diff --git a/test/core/end2end/tests/retry_server_pushback_disabled.cc b/test/core/end2end/tests/retry_server_pushback_disabled.cc
new file mode 100644
index 0000000..13d4f01
--- /dev/null
+++ b/test/core/end2end/tests/retry_server_pushback_disabled.cc
@@ -0,0 +1,306 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/end2end/tests/cancel_test_helpers.h"
+
+static void* tag(intptr_t t) { return (void*)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char* test_name,
+                                            grpc_channel_args* client_args,
+                                            grpc_channel_args* server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_from_now(int n) {
+  return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue* cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture* f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         nullptr)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = nullptr;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture* f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = nullptr;
+}
+
+static void end_test(grpc_end2end_test_fixture* f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+// Tests that we don't retry when disabled by server push-back.
+// - 2 retries allowed for ABORTED status
+// - first attempt gets ABORTED
+// - second attempt gets ABORTED but server push back disables retrying
+static void test_retry_server_pushback_disabled(
+    grpc_end2end_test_config config) {
+  grpc_call* c;
+  grpc_call* s;
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
+  grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
+  grpc_byte_buffer* request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer* response_payload =
+      grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+  grpc_byte_buffer* request_payload_recv = nullptr;
+  grpc_byte_buffer* response_payload_recv = nullptr;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+  char* peer;
+
+  grpc_metadata pushback_md;
+  memset(&pushback_md, 0, sizeof(pushback_md));
+  pushback_md.key = GRPC_MDSTR_GRPC_RETRY_PUSHBACK_MS;
+  pushback_md.value = grpc_slice_from_static_string("-1");
+
+  grpc_arg arg;
+  arg.type = GRPC_ARG_STRING;
+  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
+  arg.value.string = const_cast<char*>(
+      "{\n"
+      "  \"methodConfig\": [ {\n"
+      "    \"name\": [\n"
+      "      { \"service\": \"service\", \"method\": \"method\" }\n"
+      "    ],\n"
+      "    \"retryPolicy\": {\n"
+      "      \"maxAttempts\": 3,\n"
+      "      \"initialBackoff\": \"1s\",\n"
+      "      \"maxBackoff\": \"120s\",\n"
+      "      \"backoffMultiplier\": 1.6,\n"
+      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+      "    }\n"
+      "  } ]\n"
+      "}");
+  grpc_channel_args client_args = {1, &arg};
+  grpc_end2end_test_fixture f = begin_test(
+      config, "retry_server_pushback_disabled", &client_args, nullptr);
+
+  cq_verifier* cqv = cq_verifier_create(f.cq);
+
+  gpr_timespec deadline = five_seconds_from_now();
+  c = grpc_channel_create_call(
+      f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/service/method"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      nullptr);
+  GPR_ASSERT(c);
+
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
+  gpr_free(peer);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &response_payload_recv;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), true);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(102), true);
+  cq_verify(cqv);
+
+  grpc_call_unref(s);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_call_details_init(&call_details);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(201));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(201), true);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 1;
+  op->data.send_status_from_server.trailing_metadata = &pushback_md;
+  op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(202), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(202), true);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), true);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_ABORTED);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
+  GPR_ASSERT(0 == call_details.flags);
+  GPR_ASSERT(was_cancelled == 1);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(response_payload);
+  grpc_byte_buffer_destroy(request_payload_recv);
+  grpc_byte_buffer_destroy(response_payload_recv);
+
+  grpc_call_unref(c);
+  grpc_call_unref(s);
+
+  cq_verifier_destroy(cqv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void retry_server_pushback_disabled(grpc_end2end_test_config config) {
+  GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
+  test_retry_server_pushback_disabled(config);
+}
+
+void retry_server_pushback_disabled_pre_init(void) {}
diff --git a/test/core/end2end/tests/retry_streaming.cc b/test/core/end2end/tests/retry_streaming.cc
new file mode 100644
index 0000000..e96e57e
--- /dev/null
+++ b/test/core/end2end/tests/retry_streaming.cc
@@ -0,0 +1,424 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/end2end/tests/cancel_test_helpers.h"
+
+static void* tag(intptr_t t) { return (void*)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char* test_name,
+                                            grpc_channel_args* client_args,
+                                            grpc_channel_args* server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_from_now(int n) {
+  return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue* cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture* f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         nullptr)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = nullptr;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture* f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = nullptr;
+}
+
+static void end_test(grpc_end2end_test_fixture* f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+// Tests retrying a streaming RPC.  This is the same as
+// the basic retry test, except that the client sends two messages on the
+// call before the initial attempt fails.
+// FIXME: We should also test the case where the retry is committed after
+// replaying 1 of 2 previously-completed send_message ops.  However,
+// there's no way to trigger that from an end2end test, because the
+// replayed ops happen under the hood -- they are not surfaced to the
+// C-core API, and therefore we have no way to inject the commit at the
+// right point.
+static void test_retry_streaming(grpc_end2end_test_config config) {
+  grpc_call* c;
+  grpc_call* s;
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
+  grpc_slice request2_payload_slice = grpc_slice_from_static_string("bar");
+  grpc_slice request3_payload_slice = grpc_slice_from_static_string("baz");
+  grpc_slice response_payload_slice = grpc_slice_from_static_string("quux");
+  grpc_byte_buffer* request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer* request2_payload =
+      grpc_raw_byte_buffer_create(&request2_payload_slice, 1);
+  grpc_byte_buffer* request3_payload =
+      grpc_raw_byte_buffer_create(&request3_payload_slice, 1);
+  grpc_byte_buffer* response_payload =
+      grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+  grpc_byte_buffer* request_payload_recv = nullptr;
+  grpc_byte_buffer* request2_payload_recv = nullptr;
+  grpc_byte_buffer* request3_payload_recv = nullptr;
+  grpc_byte_buffer* response_payload_recv = nullptr;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+  char* peer;
+
+  grpc_arg arg;
+  arg.type = GRPC_ARG_STRING;
+  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
+  arg.value.string = const_cast<char*>(
+      "{\n"
+      "  \"methodConfig\": [ {\n"
+      "    \"name\": [\n"
+      "      { \"service\": \"service\", \"method\": \"method\" }\n"
+      "    ],\n"
+      "    \"retryPolicy\": {\n"
+      "      \"maxAttempts\": 3,\n"
+      "      \"initialBackoff\": \"1s\",\n"
+      "      \"maxBackoff\": \"120s\",\n"
+      "      \"backoffMultiplier\": 1.6,\n"
+      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+      "    }\n"
+      "  } ]\n"
+      "}");
+  grpc_channel_args client_args = {1, &arg};
+  grpc_end2end_test_fixture f =
+      begin_test(config, "retry_streaming", &client_args, nullptr);
+
+  cq_verifier* cqv = cq_verifier_create(f.cq);
+
+  gpr_timespec deadline = five_seconds_from_now();
+  c = grpc_channel_create_call(
+      f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/service/method"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      nullptr);
+  GPR_ASSERT(c);
+
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
+  gpr_free(peer);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+
+  // Client starts a batch for receiving initial metadata, a message,
+  // and trailing metadata.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &response_payload_recv;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  // Client sends initial metadata and a message.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(2), true);
+  cq_verify(cqv);
+
+  // Server gets a call with received initial metadata.
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), true);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  // Server receives a message.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &request_payload_recv;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), true);
+  cq_verify(cqv);
+
+  // Client sends a second message.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request2_payload;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(3), true);
+  cq_verify(cqv);
+
+  // Server receives the second message.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &request2_payload_recv;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(103), true);
+  cq_verify(cqv);
+
+  // Server sends both initial and trailing metadata.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(104), true);
+  cq_verify(cqv);
+
+  // Clean up from first attempt.
+  grpc_call_unref(s);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_call_details_init(&call_details);
+  GPR_ASSERT(byte_buffer_eq_slice(request_payload_recv, request_payload_slice));
+  grpc_byte_buffer_destroy(request_payload_recv);
+  request_payload_recv = nullptr;
+  GPR_ASSERT(
+      byte_buffer_eq_slice(request2_payload_recv, request2_payload_slice));
+  grpc_byte_buffer_destroy(request2_payload_recv);
+  request2_payload_recv = nullptr;
+
+  // Server gets a second call (the retry).
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(201));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(201), true);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  // Server receives a message.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &request_payload_recv;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(202), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(202), true);
+  cq_verify(cqv);
+
+  // Server receives a second message.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &request2_payload_recv;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(203), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(203), true);
+  cq_verify(cqv);
+
+  // Client sends a third message and a close.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request3_payload;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(4), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(4), true);
+  cq_verify(cqv);
+
+  // Server receives a third message.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &request3_payload_recv;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(204), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(204), true);
+  cq_verify(cqv);
+
+  // Server receives a close and sends initial metadata, a message, and
+  // trailing metadata.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = response_payload;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  // Returning a retriable code, but because we are also sending a
+  // message, the client will commit instead of retrying again.
+  op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(205), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(205), true);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), true);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_ABORTED);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
+  GPR_ASSERT(0 == call_details.flags);
+  GPR_ASSERT(was_cancelled == 1);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(request2_payload);
+  grpc_byte_buffer_destroy(request3_payload);
+  grpc_byte_buffer_destroy(response_payload);
+  GPR_ASSERT(byte_buffer_eq_slice(request_payload_recv, request_payload_slice));
+  grpc_byte_buffer_destroy(request_payload_recv);
+  GPR_ASSERT(
+      byte_buffer_eq_slice(request2_payload_recv, request2_payload_slice));
+  grpc_byte_buffer_destroy(request2_payload_recv);
+  GPR_ASSERT(
+      byte_buffer_eq_slice(request3_payload_recv, request3_payload_slice));
+  grpc_byte_buffer_destroy(request3_payload_recv);
+  grpc_byte_buffer_destroy(response_payload_recv);
+
+  grpc_call_unref(c);
+  grpc_call_unref(s);
+
+  cq_verifier_destroy(cqv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void retry_streaming(grpc_end2end_test_config config) {
+  GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
+  test_retry_streaming(config);
+}
+
+void retry_streaming_pre_init(void) {}
diff --git a/test/core/end2end/tests/retry_streaming_after_commit.cc b/test/core/end2end/tests/retry_streaming_after_commit.cc
new file mode 100644
index 0000000..43eee86
--- /dev/null
+++ b/test/core/end2end/tests/retry_streaming_after_commit.cc
@@ -0,0 +1,354 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/end2end/tests/cancel_test_helpers.h"
+
+static void* tag(intptr_t t) { return (void*)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char* test_name,
+                                            grpc_channel_args* client_args,
+                                            grpc_channel_args* server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_from_now(int n) {
+  return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue* cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture* f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         nullptr)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = nullptr;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture* f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = nullptr;
+}
+
+static void end_test(grpc_end2end_test_fixture* f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+// Tests that we can continue to send/recv messages on a streaming call
+// after retries are committed.
+static void test_retry_streaming_after_commit(grpc_end2end_test_config config) {
+  grpc_call* c;
+  grpc_call* s;
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
+  grpc_slice request2_payload_slice = grpc_slice_from_static_string("bar");
+  grpc_slice response_payload_slice = grpc_slice_from_static_string("baz");
+  grpc_slice response2_payload_slice = grpc_slice_from_static_string("quux");
+  grpc_byte_buffer* request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer* request2_payload =
+      grpc_raw_byte_buffer_create(&request2_payload_slice, 1);
+  grpc_byte_buffer* response_payload =
+      grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+  grpc_byte_buffer* response2_payload =
+      grpc_raw_byte_buffer_create(&response2_payload_slice, 1);
+  grpc_byte_buffer* request_payload_recv = nullptr;
+  grpc_byte_buffer* request2_payload_recv = nullptr;
+  grpc_byte_buffer* response_payload_recv = nullptr;
+  grpc_byte_buffer* response2_payload_recv = nullptr;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+  char* peer;
+
+  grpc_arg arg;
+  arg.type = GRPC_ARG_STRING;
+  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
+  arg.value.string = const_cast<char*>(
+      "{\n"
+      "  \"methodConfig\": [ {\n"
+      "    \"name\": [\n"
+      "      { \"service\": \"service\", \"method\": \"method\" }\n"
+      "    ],\n"
+      "    \"retryPolicy\": {\n"
+      "      \"maxAttempts\": 3,\n"
+      "      \"initialBackoff\": \"1s\",\n"
+      "      \"maxBackoff\": \"120s\",\n"
+      "      \"backoffMultiplier\": 1.6,\n"
+      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+      "    }\n"
+      "  } ]\n"
+      "}");
+  grpc_channel_args client_args = {1, &arg};
+  grpc_end2end_test_fixture f =
+      begin_test(config, "retry_streaming_after_commit", &client_args, nullptr);
+
+  cq_verifier* cqv = cq_verifier_create(f.cq);
+
+  gpr_timespec deadline = five_seconds_from_now();
+  c = grpc_channel_create_call(
+      f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/service/method"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      nullptr);
+  GPR_ASSERT(c);
+
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
+  gpr_free(peer);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+
+  // Client starts a batch for receiving initial metadata and a message.
+  // This will commit retries.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &response_payload_recv;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  // Client sends initial metadata and a message.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(3), true);
+  cq_verify(cqv);
+
+  // Server gets a call with received initial metadata.
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), true);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  // Server receives a message.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &request_payload_recv;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), true);
+  cq_verify(cqv);
+
+  // Server sends initial metadata and a message.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = response_payload;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(103), true);
+  // Client receives initial metadata and a message.
+  CQ_EXPECT_COMPLETION(cqv, tag(2), true);
+  cq_verify(cqv);
+
+  // Client sends a second message and a close.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request2_payload;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(4), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(4), true);
+  cq_verify(cqv);
+
+  // Server receives a second message.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &request2_payload_recv;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(104), true);
+  cq_verify(cqv);
+
+  // Server receives a close, sends a second message, and sends status.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = response2_payload;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  // Returning a retriable code, but because retries are already
+  // committed, the client will not retry.
+  op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(105), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(105), true);
+  cq_verify(cqv);
+
+  // Client receives a second message.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &response2_payload_recv;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(5), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(5), true);
+  cq_verify(cqv);
+
+  // Client receives status.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), true);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_ABORTED);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
+  GPR_ASSERT(0 == call_details.flags);
+  GPR_ASSERT(was_cancelled == 1);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(request2_payload);
+  grpc_byte_buffer_destroy(response_payload);
+  grpc_byte_buffer_destroy(response2_payload);
+  GPR_ASSERT(byte_buffer_eq_slice(request_payload_recv, request_payload_slice));
+  grpc_byte_buffer_destroy(request_payload_recv);
+  GPR_ASSERT(
+      byte_buffer_eq_slice(request2_payload_recv, request2_payload_slice));
+  grpc_byte_buffer_destroy(request2_payload_recv);
+  GPR_ASSERT(
+      byte_buffer_eq_slice(response_payload_recv, response_payload_slice));
+  grpc_byte_buffer_destroy(response_payload_recv);
+  GPR_ASSERT(
+      byte_buffer_eq_slice(response2_payload_recv, response2_payload_slice));
+  grpc_byte_buffer_destroy(response2_payload_recv);
+  grpc_call_unref(c);
+  grpc_call_unref(s);
+
+  cq_verifier_destroy(cqv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void retry_streaming_after_commit(grpc_end2end_test_config config) {
+  GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
+  test_retry_streaming_after_commit(config);
+}
+
+void retry_streaming_after_commit_pre_init(void) {}
diff --git a/test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc b/test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc
new file mode 100644
index 0000000..5c92f64
--- /dev/null
+++ b/test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc
@@ -0,0 +1,400 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/end2end/tests/cancel_test_helpers.h"
+
+static void* tag(intptr_t t) { return (void*)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char* test_name,
+                                            grpc_channel_args* client_args,
+                                            grpc_channel_args* server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_from_now(int n) {
+  return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue* cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture* f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         nullptr)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = nullptr;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture* f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = nullptr;
+}
+
+static void end_test(grpc_end2end_test_fixture* f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+// Tests that we correctly clean up if the second attempt finishes
+// before we have finished replaying all of the send ops.
+static void test_retry_streaming_succeeds_before_replay_finished(
+    grpc_end2end_test_config config) {
+  grpc_call* c;
+  grpc_call* s;
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
+  grpc_slice request2_payload_slice = grpc_slice_from_static_string("bar");
+  grpc_slice request3_payload_slice = grpc_slice_from_static_string("baz");
+  grpc_slice response_payload_slice = grpc_slice_from_static_string("quux");
+  grpc_byte_buffer* request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer* request2_payload =
+      grpc_raw_byte_buffer_create(&request2_payload_slice, 1);
+  grpc_byte_buffer* request3_payload =
+      grpc_raw_byte_buffer_create(&request3_payload_slice, 1);
+  grpc_byte_buffer* response_payload =
+      grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+  grpc_byte_buffer* request_payload_recv = nullptr;
+  grpc_byte_buffer* request2_payload_recv = nullptr;
+  grpc_byte_buffer* request3_payload_recv = nullptr;
+  grpc_byte_buffer* response_payload_recv = nullptr;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+  char* peer;
+
+  grpc_arg arg;
+  arg.type = GRPC_ARG_STRING;
+  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
+  arg.value.string = const_cast<char*>(
+      "{\n"
+      "  \"methodConfig\": [ {\n"
+      "    \"name\": [\n"
+      "      { \"service\": \"service\", \"method\": \"method\" }\n"
+      "    ],\n"
+      "    \"retryPolicy\": {\n"
+      "      \"maxAttempts\": 3,\n"
+      "      \"initialBackoff\": \"1s\",\n"
+      "      \"maxBackoff\": \"120s\",\n"
+      "      \"backoffMultiplier\": 1.6,\n"
+      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+      "    }\n"
+      "  } ]\n"
+      "}");
+  grpc_channel_args client_args = {1, &arg};
+  grpc_end2end_test_fixture f =
+      begin_test(config, "retry_streaming", &client_args, nullptr);
+
+  cq_verifier* cqv = cq_verifier_create(f.cq);
+
+  gpr_timespec deadline = five_seconds_from_now();
+  c = grpc_channel_create_call(
+      f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/service/method"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      nullptr);
+  GPR_ASSERT(c);
+
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
+  gpr_free(peer);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+
+  // Client starts a batch for receiving initial metadata, a message,
+  // and trailing metadata.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &response_payload_recv;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  // Client sends initial metadata and a message.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(2), true);
+  cq_verify(cqv);
+
+  // Server gets a call with received initial metadata.
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), true);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  // Server receives a message.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &request_payload_recv;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), true);
+  cq_verify(cqv);
+
+  // Client sends a second message.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request2_payload;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(3), true);
+  cq_verify(cqv);
+
+  // Server receives the second message.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &request2_payload_recv;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(103), true);
+  cq_verify(cqv);
+
+  // Client sends a third message.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request3_payload;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(4), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(4), true);
+  cq_verify(cqv);
+
+  // Server receives the third message.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &request3_payload_recv;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(104), true);
+  cq_verify(cqv);
+
+  // Server sends both initial and trailing metadata.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(105), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(105), true);
+  cq_verify(cqv);
+
+  // Clean up from first attempt.
+  grpc_call_unref(s);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_call_details_init(&call_details);
+  GPR_ASSERT(byte_buffer_eq_slice(request_payload_recv, request_payload_slice));
+  grpc_byte_buffer_destroy(request_payload_recv);
+  request_payload_recv = nullptr;
+  GPR_ASSERT(
+      byte_buffer_eq_slice(request2_payload_recv, request2_payload_slice));
+  grpc_byte_buffer_destroy(request2_payload_recv);
+  request2_payload_recv = nullptr;
+  GPR_ASSERT(
+      byte_buffer_eq_slice(request3_payload_recv, request3_payload_slice));
+  grpc_byte_buffer_destroy(request3_payload_recv);
+  request3_payload_recv = nullptr;
+
+  // Server gets a second call (the retry).
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(201));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(201), true);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  // Server receives the first message (and does not receive any others).
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &request_payload_recv;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(202), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(202), true);
+  cq_verify(cqv);
+
+  // Server sends initial metadata, a message, and trailing metadata.
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = response_payload;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  // Returning a retriable code, but because we are also sending a
+  // message, the client will commit instead of retrying again.
+  op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(205), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(205), true);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), true);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_ABORTED);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
+  GPR_ASSERT(0 == call_details.flags);
+  GPR_ASSERT(was_cancelled == 1);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(request2_payload);
+  grpc_byte_buffer_destroy(request3_payload);
+  grpc_byte_buffer_destroy(response_payload);
+  GPR_ASSERT(byte_buffer_eq_slice(request_payload_recv, request_payload_slice));
+  grpc_byte_buffer_destroy(request_payload_recv);
+  grpc_byte_buffer_destroy(response_payload_recv);
+
+  grpc_call_unref(c);
+  grpc_call_unref(s);
+
+  cq_verifier_destroy(cqv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void retry_streaming_succeeds_before_replay_finished(
+    grpc_end2end_test_config config) {
+  GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
+  test_retry_streaming_succeeds_before_replay_finished(config);
+}
+
+void retry_streaming_succeeds_before_replay_finished_pre_init(void) {}
diff --git a/test/core/end2end/tests/retry_throttled.cc b/test/core/end2end/tests/retry_throttled.cc
new file mode 100644
index 0000000..8cd0848
--- /dev/null
+++ b/test/core/end2end/tests/retry_throttled.cc
@@ -0,0 +1,264 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/end2end/tests/cancel_test_helpers.h"
+
+static void* tag(intptr_t t) { return (void*)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char* test_name,
+                                            grpc_channel_args* client_args,
+                                            grpc_channel_args* server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_from_now(int n) {
+  return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue* cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture* f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         nullptr)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = nullptr;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture* f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = nullptr;
+}
+
+static void end_test(grpc_end2end_test_fixture* f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+// Tests that we don't retry when throttled.
+// - 1 retry allowed for ABORTED status
+// - first attempt gets ABORTED but is over limit, so no retry is done
+static void test_retry_throttled(grpc_end2end_test_config config) {
+  grpc_call* c;
+  grpc_call* s;
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
+  grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
+  grpc_byte_buffer* request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer* response_payload =
+      grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+  grpc_byte_buffer* request_payload_recv = nullptr;
+  grpc_byte_buffer* response_payload_recv = nullptr;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+  char* peer;
+
+  grpc_arg arg;
+  arg.type = GRPC_ARG_STRING;
+  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
+  arg.value.string = const_cast<char*>(
+      "{\n"
+      "  \"methodConfig\": [ {\n"
+      "    \"name\": [\n"
+      "      { \"service\": \"service\", \"method\": \"method\" }\n"
+      "    ],\n"
+      "    \"retryPolicy\": {\n"
+      "      \"maxAttempts\": 2,\n"
+      "      \"initialBackoff\": \"1s\",\n"
+      "      \"maxBackoff\": \"120s\",\n"
+      "      \"backoffMultiplier\": 1.6,\n"
+      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+      "    }\n"
+      "  } ],\n"
+      // A single failure will cause us to be throttled.
+      // (This is not a very realistic config, but it works for the
+      // purposes of this test.)
+      "  \"retryThrottling\": {\n"
+      "    \"maxTokens\": 2,\n"
+      "    \"tokenRatio\": 1.0,\n"
+      "  }\n"
+      "}");
+  grpc_channel_args client_args = {1, &arg};
+  grpc_end2end_test_fixture f =
+      begin_test(config, "retry_throttled", &client_args, nullptr);
+
+  cq_verifier* cqv = cq_verifier_create(f.cq);
+
+  gpr_timespec deadline = five_seconds_from_now();
+  c = grpc_channel_create_call(
+      f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/service/method"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      nullptr);
+  GPR_ASSERT(c);
+
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
+  gpr_free(peer);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &response_payload_recv;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), true);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(102), true);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), true);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_ABORTED);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
+  GPR_ASSERT(0 == call_details.flags);
+  GPR_ASSERT(was_cancelled == 1);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(response_payload);
+  grpc_byte_buffer_destroy(request_payload_recv);
+  grpc_byte_buffer_destroy(response_payload_recv);
+
+  grpc_call_unref(c);
+  grpc_call_unref(s);
+
+  cq_verifier_destroy(cqv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void retry_throttled(grpc_end2end_test_config config) {
+  GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
+  test_retry_throttled(config);
+}
+
+void retry_throttled_pre_init(void) {}
diff --git a/test/core/end2end/tests/retry_too_many_attempts.cc b/test/core/end2end/tests/retry_too_many_attempts.cc
new file mode 100644
index 0000000..5225c9b
--- /dev/null
+++ b/test/core/end2end/tests/retry_too_many_attempts.cc
@@ -0,0 +1,299 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/end2end/tests/cancel_test_helpers.h"
+
+static void* tag(intptr_t t) { return (void*)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char* test_name,
+                                            grpc_channel_args* client_args,
+                                            grpc_channel_args* server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_from_now(int n) {
+  return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue* cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture* f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         nullptr)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = nullptr;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture* f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = nullptr;
+}
+
+static void end_test(grpc_end2end_test_fixture* f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+// Tests that we stop retrying after the configured number of attempts.
+// - 1 retry allowed for ABORTED status
+// - first attempt gets ABORTED
+// - second attempt gets ABORTED but does not retry
+static void test_retry_too_many_attempts(grpc_end2end_test_config config) {
+  grpc_call* c;
+  grpc_call* s;
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
+  grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
+  grpc_byte_buffer* request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer* response_payload =
+      grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+  grpc_byte_buffer* request_payload_recv = nullptr;
+  grpc_byte_buffer* response_payload_recv = nullptr;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+  char* peer;
+
+  grpc_arg arg;
+  arg.type = GRPC_ARG_STRING;
+  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
+  arg.value.string = const_cast<char*>(
+      "{\n"
+      "  \"methodConfig\": [ {\n"
+      "    \"name\": [\n"
+      "      { \"service\": \"service\", \"method\": \"method\" }\n"
+      "    ],\n"
+      "    \"retryPolicy\": {\n"
+      "      \"maxAttempts\": 2,\n"
+      "      \"initialBackoff\": \"1s\",\n"
+      "      \"maxBackoff\": \"120s\",\n"
+      "      \"backoffMultiplier\": 1.6,\n"
+      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+      "    }\n"
+      "  } ]\n"
+      "}");
+  grpc_channel_args client_args = {1, &arg};
+  grpc_end2end_test_fixture f =
+      begin_test(config, "retry_too_many_attempts", &client_args, nullptr);
+
+  cq_verifier* cqv = cq_verifier_create(f.cq);
+
+  gpr_timespec deadline = five_seconds_from_now();
+  c = grpc_channel_create_call(
+      f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/service/method"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      nullptr);
+  GPR_ASSERT(c);
+
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
+  gpr_free(peer);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &response_payload_recv;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), true);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(102), true);
+  cq_verify(cqv);
+
+  grpc_call_unref(s);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_call_details_init(&call_details);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(201));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(201), true);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(202), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(202), true);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), true);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_ABORTED);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
+  GPR_ASSERT(0 == call_details.flags);
+  GPR_ASSERT(was_cancelled == 1);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(response_payload);
+  grpc_byte_buffer_destroy(request_payload_recv);
+  grpc_byte_buffer_destroy(response_payload_recv);
+
+  grpc_call_unref(c);
+  grpc_call_unref(s);
+
+  cq_verifier_destroy(cqv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void retry_too_many_attempts(grpc_end2end_test_config config) {
+  GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
+  test_retry_too_many_attempts(config);
+}
+
+void retry_too_many_attempts_pre_init(void) {}
diff --git a/test/core/end2end/tests/server_finishes_request.cc b/test/core/end2end/tests/server_finishes_request.cc
index 743b3ae..6fc06cf 100644
--- a/test/core/end2end/tests/server_finishes_request.cc
+++ b/test/core/end2end/tests/server_finishes_request.cc
@@ -26,7 +26,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "src/core/lib/gpr/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
@@ -134,7 +133,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -164,7 +164,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
diff --git a/test/core/end2end/tests/shutdown_finishes_calls.cc b/test/core/end2end/tests/shutdown_finishes_calls.cc
index fce23f3..28728ef 100644
--- a/test/core/end2end/tests/shutdown_finishes_calls.cc
+++ b/test/core/end2end/tests/shutdown_finishes_calls.cc
@@ -25,7 +25,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -129,7 +128,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -146,9 +146,17 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
+  /* Make sure we don't shutdown the server while HTTP/2 PING frames are still
+   * being exchanged on the newly established connection. It can lead to
+   * failures when testing with HTTP proxy. See
+   * https://github.com/grpc/grpc/issues/14471
+   */
+  gpr_sleep_until(n_seconds_from_now(1));
+
   /* shutdown and destroy the server */
   grpc_server_shutdown_and_notify(f.server, f.cq, tag(1000));
   grpc_server_cancel_all_calls(f.server);
diff --git a/test/core/end2end/tests/shutdown_finishes_tags.cc b/test/core/end2end/tests/shutdown_finishes_tags.cc
index de64eba..55caacb 100644
--- a/test/core/end2end/tests/shutdown_finishes_tags.cc
+++ b/test/core/end2end/tests/shutdown_finishes_tags.cc
@@ -25,7 +25,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -78,7 +77,7 @@
   grpc_end2end_test_fixture f = begin_test(
       config, "test_early_server_shutdown_finishes_tags", nullptr, nullptr);
   cq_verifier* cqv = cq_verifier_create(f.cq);
-  grpc_call* s = (grpc_call*)(uintptr_t)1;
+  grpc_call* s = (grpc_call*)static_cast<uintptr_t>(1);
   grpc_call_details call_details;
   grpc_metadata_array request_metadata_recv;
 
diff --git a/test/core/end2end/tests/simple_cacheable_request.cc b/test/core/end2end/tests/simple_cacheable_request.cc
index d8034dc..4ae8398 100644
--- a/test/core/end2end/tests/simple_cacheable_request.cc
+++ b/test/core/end2end/tests/simple_cacheable_request.cc
@@ -25,7 +25,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
 enum { TIMEOUT = 200000 };
@@ -179,7 +178,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -202,7 +202,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -228,7 +229,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
diff --git a/test/core/end2end/tests/simple_delayed_request.cc b/test/core/end2end/tests/simple_delayed_request.cc
index 0ad224f..f8a1ddf 100644
--- a/test/core/end2end/tests/simple_delayed_request.cc
+++ b/test/core/end2end/tests/simple_delayed_request.cc
@@ -25,7 +25,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -130,7 +129,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -160,7 +160,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
diff --git a/test/core/end2end/tests/simple_metadata.cc b/test/core/end2end/tests/simple_metadata.cc
index 1a74116..1f39f89 100644
--- a/test/core/end2end/tests/simple_metadata.cc
+++ b/test/core/end2end/tests/simple_metadata.cc
@@ -25,7 +25,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -177,7 +176,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -200,7 +200,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -226,7 +227,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
diff --git a/test/core/end2end/tests/simple_request.cc b/test/core/end2end/tests/simple_request.cc
index ae93f79..926e2c7 100644
--- a/test/core/end2end/tests/simple_request.cc
+++ b/test/core/end2end/tests/simple_request.cc
@@ -26,7 +26,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/gpr/string.h"
 #include "test/core/end2end/cq_verifier.h"
@@ -153,7 +152,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -192,7 +192,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
diff --git a/test/core/end2end/tests/stream_compression_compressed_payload.cc b/test/core/end2end/tests/stream_compression_compressed_payload.cc
index 9a38444..e90d54f 100644
--- a/test/core/end2end/tests/stream_compression_compressed_payload.cc
+++ b/test/core/end2end/tests/stream_compression_compressed_payload.cc
@@ -28,7 +28,6 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/surface/call.h"
@@ -188,7 +187,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(101), true);
@@ -206,7 +206,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), false);
@@ -217,7 +218,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(103), true);
@@ -346,7 +348,8 @@
     op->flags = client_send_flags_bitmask;
     op->reserved = nullptr;
     op++;
-    error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
+    error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(2),
+                                  nullptr);
     GPR_ASSERT(GRPC_CALL_OK == error);
     CQ_EXPECT_COMPLETION(cqv, tag(2), true);
   }
@@ -375,7 +378,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -390,9 +394,9 @@
   GPR_ASSERT(GPR_BITGET(grpc_call_test_only_get_encodings_accepted_by_peer(s),
                         GRPC_COMPRESS_NONE) != 0);
   GPR_ASSERT(GPR_BITGET(grpc_call_test_only_get_encodings_accepted_by_peer(s),
-                        GRPC_COMPRESS_MESSAGE_DEFLATE) != 0);
+                        GRPC_COMPRESS_DEFLATE) != 0);
   GPR_ASSERT(GPR_BITGET(grpc_call_test_only_get_encodings_accepted_by_peer(s),
-                        GRPC_COMPRESS_MESSAGE_GZIP) != 0);
+                        GRPC_COMPRESS_GZIP) != 0);
   GPR_ASSERT(GPR_BITGET(grpc_call_test_only_get_encodings_accepted_by_peer(s),
                         GRPC_COMPRESS_STREAM_GZIP) != 0);
   GPR_ASSERT(GPR_BITCOUNT(grpc_call_test_only_get_encodings_accepted_by_peer(
@@ -415,7 +419,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(101), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(101),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   for (int i = 0; i < 2; i++) {
@@ -430,8 +435,8 @@
       op->flags = client_send_flags_bitmask;
       op->reserved = nullptr;
       op++;
-      error =
-          grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
+      error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops),
+                                    tag(2), nullptr);
       GPR_ASSERT(GRPC_CALL_OK == error);
       CQ_EXPECT_COMPLETION(cqv, tag(2), 1);
     }
@@ -443,8 +448,8 @@
     op->flags = 0;
     op->reserved = nullptr;
     op++;
-    error =
-        grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+    error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops),
+                                  tag(102), nullptr);
     GPR_ASSERT(GRPC_CALL_OK == error);
 
     CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -460,8 +465,8 @@
     op->flags = 0;
     op->reserved = nullptr;
     op++;
-    error =
-        grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+    error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops),
+                                  tag(103), nullptr);
     GPR_ASSERT(GRPC_CALL_OK == error);
 
     memset(ops, 0, sizeof(ops));
@@ -471,7 +476,8 @@
     op->flags = 0;
     op->reserved = nullptr;
     op++;
-    error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), nullptr);
+    error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(3),
+                                  nullptr);
     GPR_ASSERT(GRPC_CALL_OK == error);
 
     CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
@@ -496,7 +502,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(4), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(4),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   memset(ops, 0, sizeof(ops));
@@ -509,7 +516,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(104),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/stream_compression_payload.cc b/test/core/end2end/tests/stream_compression_payload.cc
index 9a27957..9eace97 100644
--- a/test/core/end2end/tests/stream_compression_payload.cc
+++ b/test/core/end2end/tests/stream_compression_payload.cc
@@ -26,7 +26,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/surface/call.h"
 #include "test/core/end2end/cq_verifier.h"
@@ -94,9 +93,9 @@
   static const char chars[] = "abcdefghijklmnopqrstuvwxyz1234567890";
   char* output;
   const size_t output_size = 1024 * 1024;
-  output = (char*)gpr_malloc(output_size);
+  output = static_cast<char*>(gpr_malloc(output_size));
   for (i = 0; i < output_size - 1; ++i) {
-    output[i] = chars[rand() % (int)(sizeof(chars) - 1)];
+    output[i] = chars[rand() % static_cast<int>(sizeof(chars) - 1)];
   }
   output[output_size - 1] = '\0';
   grpc_slice out = grpc_slice_from_copied_string(output);
@@ -178,7 +177,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -200,7 +200,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -226,7 +227,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
diff --git a/test/core/end2end/tests/stream_compression_ping_pong_streaming.cc b/test/core/end2end/tests/stream_compression_ping_pong_streaming.cc
index 4dc306b..5b03329 100644
--- a/test/core/end2end/tests/stream_compression_ping_pong_streaming.cc
+++ b/test/core/end2end/tests/stream_compression_ping_pong_streaming.cc
@@ -26,7 +26,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
+
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/surface/call.h"
 #include "test/core/end2end/cq_verifier.h"
@@ -151,7 +151,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -173,7 +174,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(101), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(101),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   for (i = 0; i < messages; i++) {
@@ -192,7 +194,8 @@
     op->flags = 0;
     op->reserved = nullptr;
     op++;
-    error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
+    error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(2),
+                                  nullptr);
     GPR_ASSERT(GRPC_CALL_OK == error);
 
     memset(ops, 0, sizeof(ops));
@@ -202,8 +205,8 @@
     op->flags = 0;
     op->reserved = nullptr;
     op++;
-    error =
-        grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+    error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops),
+                                  tag(102), nullptr);
     GPR_ASSERT(GRPC_CALL_OK == error);
     CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
     cq_verify(cqv);
@@ -215,8 +218,8 @@
     op->flags = 0;
     op->reserved = nullptr;
     op++;
-    error =
-        grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+    error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops),
+                                  tag(103), nullptr);
     GPR_ASSERT(GRPC_CALL_OK == error);
     CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
     CQ_EXPECT_COMPLETION(cqv, tag(2), 1);
@@ -237,7 +240,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(3),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   memset(ops, 0, sizeof(ops));
@@ -250,7 +254,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(104),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
diff --git a/test/core/end2end/tests/streaming_error_response.cc b/test/core/end2end/tests/streaming_error_response.cc
index 6ad1cec..7c7d778 100644
--- a/test/core/end2end/tests/streaming_error_response.cc
+++ b/test/core/end2end/tests/streaming_error_response.cc
@@ -28,7 +28,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -149,7 +148,8 @@
     op->data.recv_status_on_client.status_details = &details;
     op++;
   }
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
@@ -166,7 +166,8 @@
   op->op = GRPC_OP_SEND_MESSAGE;
   op->data.send_message.send_message = response_payload1;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -180,7 +181,8 @@
   op->op = GRPC_OP_SEND_MESSAGE;
   op->data.send_message.send_message = response_payload2;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
@@ -191,7 +193,8 @@
     op->op = GRPC_OP_RECV_MESSAGE;
     op->data.recv_message.recv_message = &response_payload2_recv;
     op++;
-    error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
+    error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(2),
+                                  nullptr);
     GPR_ASSERT(GRPC_CALL_OK == error);
 
     CQ_EXPECT_COMPLETION(cqv, tag(2), 1);
@@ -209,7 +212,8 @@
   grpc_slice status_details = grpc_slice_from_static_string("xyz");
   op->data.send_status_from_server.status_details = &status_details;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(104),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(104), 1);
@@ -226,7 +230,8 @@
     op->data.recv_status_on_client.status = &status;
     op->data.recv_status_on_client.status_details = &details;
     op++;
-    error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), nullptr);
+    error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(3),
+                                  nullptr);
     GPR_ASSERT(GRPC_CALL_OK == error);
 
     CQ_EXPECT_COMPLETION(cqv, tag(3), 1);
diff --git a/test/core/end2end/tests/trailing_metadata.cc b/test/core/end2end/tests/trailing_metadata.cc
index afc56c8..2406985 100644
--- a/test/core/end2end/tests/trailing_metadata.cc
+++ b/test/core/end2end/tests/trailing_metadata.cc
@@ -25,7 +25,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -185,7 +184,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -208,7 +208,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
@@ -235,7 +236,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
diff --git a/test/core/end2end/tests/workaround_cronet_compression.cc b/test/core/end2end/tests/workaround_cronet_compression.cc
index 97ab814..4d4c369 100644
--- a/test/core/end2end/tests/workaround_cronet_compression.cc
+++ b/test/core/end2end/tests/workaround_cronet_compression.cc
@@ -28,7 +28,6 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/surface/call.h"
@@ -192,7 +191,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   error =
@@ -207,9 +207,9 @@
   GPR_ASSERT(GPR_BITGET(grpc_call_test_only_get_encodings_accepted_by_peer(s),
                         GRPC_COMPRESS_NONE) != 0);
   GPR_ASSERT(GPR_BITGET(grpc_call_test_only_get_encodings_accepted_by_peer(s),
-                        GRPC_COMPRESS_MESSAGE_DEFLATE) != 0);
+                        GRPC_COMPRESS_DEFLATE) != 0);
   GPR_ASSERT(GPR_BITGET(grpc_call_test_only_get_encodings_accepted_by_peer(s),
-                        GRPC_COMPRESS_MESSAGE_GZIP) != 0);
+                        GRPC_COMPRESS_GZIP) != 0);
 
   memset(ops, 0, sizeof(ops));
   op = ops;
@@ -228,7 +228,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(101), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(101),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   for (int i = 0; i < 2; i++) {
@@ -247,7 +248,8 @@
     op->flags = 0;
     op->reserved = nullptr;
     op++;
-    error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
+    error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(2),
+                                  nullptr);
     GPR_ASSERT(GRPC_CALL_OK == error);
 
     memset(ops, 0, sizeof(ops));
@@ -257,8 +259,8 @@
     op->flags = 0;
     op->reserved = nullptr;
     op++;
-    error =
-        grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+    error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops),
+                                  tag(102), nullptr);
     GPR_ASSERT(GRPC_CALL_OK == error);
     CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
     cq_verify(cqv);
@@ -275,8 +277,8 @@
     op->flags = 0;
     op->reserved = nullptr;
     op++;
-    error =
-        grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+    error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops),
+                                  tag(103), nullptr);
     GPR_ASSERT(GRPC_CALL_OK == error);
     CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
     CQ_EXPECT_COMPLETION(cqv, tag(2), 1);
@@ -309,7 +311,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(3),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   memset(ops, 0, sizeof(ops));
@@ -322,7 +325,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(104),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
@@ -365,16 +369,16 @@
 } workaround_cronet_compression_config;
 
 static workaround_cronet_compression_config workaround_configs[] = {
-    {nullptr, GRPC_COMPRESS_MESSAGE_GZIP},
+    {nullptr, GRPC_COMPRESS_GZIP},
     {const_cast<char*>(
          "grpc-objc/1.3.0-dev grpc-c/3.0.0-dev (ios; cronet_http; gentle)"),
      GRPC_COMPRESS_NONE},
     {const_cast<char*>(
          "grpc-objc/1.3.0-dev grpc-c/3.0.0-dev (ios; chttp2; gentle)"),
-     GRPC_COMPRESS_MESSAGE_GZIP},
+     GRPC_COMPRESS_GZIP},
     {const_cast<char*>(
          "grpc-objc/1.4.0 grpc-c/3.0.0-dev (ios; cronet_http; gentle)"),
-     GRPC_COMPRESS_MESSAGE_GZIP}};
+     GRPC_COMPRESS_GZIP}};
 static const size_t workaround_configs_num =
     sizeof(workaround_configs) / sizeof(*workaround_configs);
 
@@ -383,8 +387,7 @@
   for (uint32_t i = 0; i < workaround_configs_num; i++) {
     request_with_payload_template(
         config, "test_invoke_request_with_compressed_payload", 0,
-        GRPC_COMPRESS_MESSAGE_GZIP, GRPC_COMPRESS_MESSAGE_GZIP,
-        GRPC_COMPRESS_MESSAGE_GZIP,
+        GRPC_COMPRESS_GZIP, GRPC_COMPRESS_GZIP, GRPC_COMPRESS_GZIP,
         workaround_configs[i].expected_algorithm_from_server, nullptr, false,
         /* ignored */ GRPC_COMPRESS_LEVEL_NONE,
         workaround_configs[i].user_agent_override);
diff --git a/test/core/end2end/tests/write_buffering.cc b/test/core/end2end/tests/write_buffering.cc
index 40821dd..5d76d23 100644
--- a/test/core/end2end/tests/write_buffering.cc
+++ b/test/core/end2end/tests/write_buffering.cc
@@ -25,7 +25,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -129,7 +128,8 @@
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
   op->data.send_initial_metadata.count = 0;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   memset(ops, 0, sizeof(ops));
@@ -139,7 +139,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(2),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
@@ -155,7 +156,8 @@
   op->data.send_message.send_message = request_payload1;
   op->flags = GRPC_WRITE_BUFFER_HINT;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(3),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   memset(ops, 0, sizeof(ops));
@@ -163,7 +165,8 @@
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
   op->data.send_initial_metadata.count = 0;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   /* recv message should not succeed yet - it's buffered at the client still */
@@ -172,7 +175,8 @@
   op->op = GRPC_OP_RECV_MESSAGE;
   op->data.recv_message.recv_message = &request_payload_recv1;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(2), true);
@@ -187,7 +191,8 @@
   op->data.send_message.send_message = request_payload2;
   op->flags = 0;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(4), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(4),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   /* now the first send should match up with the first recv */
@@ -201,7 +206,8 @@
   op->op = GRPC_OP_RECV_MESSAGE;
   op->data.recv_message.recv_message = &request_payload_recv2;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(104),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(104), true);
@@ -220,7 +226,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(4), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(4),
+                                nullptr);
 
   memset(ops, 0, sizeof(ops));
   op = ops;
@@ -237,7 +244,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(105), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(105),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(105), 1);
diff --git a/test/core/end2end/tests/write_buffering_at_end.cc b/test/core/end2end/tests/write_buffering_at_end.cc
index 1b9dc96..bd046ef 100644
--- a/test/core/end2end/tests/write_buffering_at_end.cc
+++ b/test/core/end2end/tests/write_buffering_at_end.cc
@@ -25,7 +25,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -126,7 +125,8 @@
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
   op->data.send_initial_metadata.count = 0;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   memset(ops, 0, sizeof(ops));
@@ -136,7 +136,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(2),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
@@ -152,7 +153,8 @@
   op->data.send_message.send_message = request_payload;
   op->flags = GRPC_WRITE_BUFFER_HINT;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(3),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   memset(ops, 0, sizeof(ops));
@@ -160,7 +162,8 @@
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
   op->data.send_initial_metadata.count = 0;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   /* recv message should not succeed yet - it's buffered at the client still */
@@ -169,7 +172,8 @@
   op->op = GRPC_OP_RECV_MESSAGE;
   op->data.recv_message.recv_message = &request_payload_recv1;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(2), true);
@@ -182,7 +186,8 @@
   op = ops;
   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(4), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(4),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   /* now the first send should match up with the first recv */
@@ -196,7 +201,8 @@
   op->op = GRPC_OP_RECV_MESSAGE;
   op->data.recv_message.recv_message = &request_payload_recv2;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(104),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(104), true);
@@ -211,7 +217,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(4), nullptr);
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(4),
+                                nullptr);
 
   memset(ops, 0, sizeof(ops));
   op = ops;
@@ -228,7 +235,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(105), nullptr);
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(105),
+                                nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   CQ_EXPECT_COMPLETION(cqv, tag(105), 1);
diff --git a/test/core/fling/client.cc b/test/core/fling/client.cc
index c623d37..05dc305 100644
--- a/test/core/fling/client.cc
+++ b/test/core/fling/client.cc
@@ -21,11 +21,12 @@
 #include <stdio.h>
 #include <string.h>
 
-#include <grpc/support/cmdline.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/profiling/timers.h"
+#include "test/core/util/cmdline.h"
 #include "test/core/util/grpc_profiler.h"
 #include "test/core/util/histogram.h"
 #include "test/core/util/test_config.h"
@@ -126,7 +127,7 @@
 
 static double now(void) {
   gpr_timespec tv = gpr_now(GPR_CLOCK_REALTIME);
-  return 1e9 * (double)tv.tv_sec + tv.tv_nsec;
+  return 1e9 * static_cast<double>(tv.tv_sec) + tv.tv_nsec;
 }
 
 typedef struct {
@@ -194,7 +195,8 @@
 
   channel = grpc_insecure_channel_create(target, nullptr, nullptr);
   cq = grpc_completion_queue_create_for_next(nullptr);
-  the_buffer = grpc_raw_byte_buffer_create(&slice, (size_t)payload_size);
+  the_buffer =
+      grpc_raw_byte_buffer_create(&slice, static_cast<size_t>(payload_size));
   histogram = grpc_histogram_create(0.01, 60e9);
 
   sc.init();
diff --git a/test/core/fling/fling_stream_test.cc b/test/core/fling/fling_stream_test.cc
index b5a5ce8..32bc989 100644
--- a/test/core/fling/fling_stream_test.cc
+++ b/test/core/fling/fling_stream_test.cc
@@ -20,11 +20,12 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/subprocess.h>
+
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
 #include "test/core/util/port.h"
+#include "test/core/util/subprocess.h"
 
 int main(int argc, char** argv) {
   char* me = argv[0];
@@ -36,7 +37,7 @@
   gpr_subprocess *svr, *cli;
   /* figure out where we are */
   if (lslash) {
-    memcpy(root, me, (size_t)(lslash - me));
+    memcpy(root, me, static_cast<size_t>(lslash - me));
     root[lslash - me] = 0;
   } else {
     strcpy(root, ".");
diff --git a/test/core/fling/fling_test.cc b/test/core/fling/fling_test.cc
index 3792e45..3587a4a 100644
--- a/test/core/fling/fling_test.cc
+++ b/test/core/fling/fling_test.cc
@@ -20,11 +20,12 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/subprocess.h>
+
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
 #include "test/core/util/port.h"
+#include "test/core/util/subprocess.h"
 
 int main(int argc, const char** argv) {
   const char* me = argv[0];
@@ -36,7 +37,7 @@
   gpr_subprocess *svr, *cli;
   /* figure out where we are */
   if (lslash) {
-    memcpy(root, me, (size_t)(lslash - me));
+    memcpy(root, me, static_cast<size_t>(lslash - me));
     root[lslash - me] = 0;
   } else {
     strcpy(root, ".");
diff --git a/test/core/fling/server.cc b/test/core/fling/server.cc
index f3a8a1c..cf7e246 100644
--- a/test/core/fling/server.cc
+++ b/test/core/fling/server.cc
@@ -30,12 +30,13 @@
 #endif
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/cmdline.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
+
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/profiling/timers.h"
 #include "test/core/end2end/data/ssl_test_data.h"
+#include "test/core/util/cmdline.h"
 #include "test/core/util/grpc_profiler.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
@@ -111,7 +112,8 @@
   op->data.recv_close_on_server.cancelled = &was_cancelled;
   op++;
 
-  error = grpc_call_start_batch(call, unary_ops, (size_t)(op - unary_ops),
+  error = grpc_call_start_batch(call, unary_ops,
+                                static_cast<size_t>(op - unary_ops),
                                 tag(FLING_SERVER_BATCH_OPS_FOR_UNARY), nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 }
@@ -188,7 +190,7 @@
   grpc_test_init(1, fake_argv);
 
   grpc_init();
-  srand((unsigned)clock());
+  srand(static_cast<unsigned>(clock()));
 
   cl = gpr_cmdline_create("fling server");
   gpr_cmdline_add_string(cl, "bind", "Bind host:port", &addr);
diff --git a/test/core/gpr/BUILD b/test/core/gpr/BUILD
index 1be1036..5308ea0 100644
--- a/test/core/gpr/BUILD
+++ b/test/core/gpr/BUILD
@@ -29,18 +29,8 @@
 )
 
 grpc_cc_test(
-    name = "avl_test",
-    srcs = ["avl_test.cc"],
-    language = "C++",
-    deps = [
-        "//:gpr",
-        "//test/core/util:gpr_test_util",
-    ],
-)
-
-grpc_cc_test(
-    name = "cmdline_test",
-    srcs = ["cmdline_test.cc"],
+    name = "arena_test",
+    srcs = ["arena_test.cc"],
     language = "C++",
     deps = [
         "//:gpr",
@@ -139,16 +129,6 @@
 )
 
 grpc_cc_test(
-    name = "thd_test",
-    srcs = ["thd_test.cc"],
-    language = "C++",
-    deps = [
-        "//:gpr",
-        "//test/core/util:gpr_test_util",
-    ],
-)
-
-grpc_cc_test(
     name = "time_test",
     srcs = ["time_test.cc"],
     language = "C++",
diff --git a/test/core/gpr/alloc_test.cc b/test/core/gpr/alloc_test.cc
index bf4471c..36cdc02 100644
--- a/test/core/gpr/alloc_test.cc
+++ b/test/core/gpr/alloc_test.cc
@@ -27,7 +27,9 @@
 
 static void* fake_realloc(void* addr, size_t size) { return (void*)size; }
 
-static void fake_free(void* addr) { *((intptr_t*)addr) = (intptr_t)0xdeadd00d; }
+static void fake_free(void* addr) {
+  *(static_cast<intptr_t*>(addr)) = static_cast<intptr_t>(0xdeadd00d);
+}
 
 static void test_custom_allocs() {
   const gpr_allocation_functions default_fns = gpr_get_allocation_functions();
diff --git a/test/core/gpr/arena_test.cc b/test/core/gpr/arena_test.cc
index 62a3f8b..111414e 100644
--- a/test/core/gpr/arena_test.cc
+++ b/test/core/gpr/arena_test.cc
@@ -18,16 +18,17 @@
 
 #include "src/core/lib/gpr/arena.h"
 
+#include <inttypes.h>
+#include <string.h>
+
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
-#include <inttypes.h>
-#include <string.h>
 
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "test/core/util/test_config.h"
 
 static void test_noop(void) { gpr_arena_destroy(gpr_arena_create(1)); }
@@ -86,7 +87,7 @@
   concurrent_test_args* a = static_cast<concurrent_test_args*>(arg);
   gpr_event_wait(&a->ev_start, gpr_inf_future(GPR_CLOCK_REALTIME));
   for (size_t i = 0; i < concurrent_test_iterations(); i++) {
-    *(char*)gpr_arena_alloc(a->arena, 1) = (char)i;
+    *static_cast<char*>(gpr_arena_alloc(a->arena, 1)) = static_cast<char>(i);
   }
 }
 
@@ -97,19 +98,18 @@
   gpr_event_init(&args.ev_start);
   args.arena = gpr_arena_create(1024);
 
-  gpr_thd_id thds[CONCURRENT_TEST_THREADS];
+  grpc_core::Thread thds[CONCURRENT_TEST_THREADS];
 
   for (int i = 0; i < CONCURRENT_TEST_THREADS; i++) {
-    gpr_thd_options opt = gpr_thd_options_default();
-    gpr_thd_options_set_joinable(&opt);
-    gpr_thd_new(&thds[i], "grpc_concurrent_test", concurrent_test_body, &args,
-                &opt);
+    thds[i] =
+        grpc_core::Thread("grpc_concurrent_test", concurrent_test_body, &args);
+    thds[i].Start();
   }
 
   gpr_event_set(&args.ev_start, (void*)1);
 
-  for (int i = 0; i < CONCURRENT_TEST_THREADS; i++) {
-    gpr_thd_join(thds[i]);
+  for (auto& th : thds) {
+    th.Join();
   }
 
   gpr_arena_destroy(args.arena);
diff --git a/test/core/gpr/avl_test.cc b/test/core/gpr/avl_test.cc
deleted file mode 100644
index 345db55..0000000
--- a/test/core/gpr/avl_test.cc
+++ /dev/null
@@ -1,3659 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <grpc/support/avl.h>
-
-#include <stdio.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/useful.h>
-
-#include "test/core/util/test_config.h"
-
-static int* box(int x) {
-  int* b = static_cast<int*>(gpr_malloc(sizeof(*b)));
-  *b = x;
-  return b;
-}
-
-static long int_compare(void* int1, void* int2, void* unused) {
-  return (*(int*)int1) - (*(int*)int2);
-}
-static void* int_copy(void* p, void* unused) { return box(*(int*)p); }
-
-static void destroy(void* p, void* unused) { gpr_free(p); }
-
-static const gpr_avl_vtable int_int_vtable = {destroy, int_copy, int_compare,
-                                              destroy, int_copy};
-
-static void check_get(gpr_avl avl, int key, int value) {
-  int* k = box(key);
-  GPR_ASSERT(*(int*)gpr_avl_get(avl, k, nullptr) == value);
-  gpr_free(k);
-}
-
-static void check_negget(gpr_avl avl, int key) {
-  int* k = box(key);
-  GPR_ASSERT(gpr_avl_get(avl, k, nullptr) == nullptr);
-  gpr_free(k);
-}
-
-static gpr_avl remove_int(gpr_avl avl, int key) {
-  int* k = box(key);
-  avl = gpr_avl_remove(avl, k, nullptr);
-  gpr_free(k);
-  return avl;
-}
-
-static void test_get(void) {
-  gpr_avl avl;
-  gpr_log(GPR_DEBUG, "test_get");
-  avl = gpr_avl_create(&int_int_vtable);
-  avl = gpr_avl_add(avl, box(1), box(11), nullptr);
-  avl = gpr_avl_add(avl, box(2), box(22), nullptr);
-  avl = gpr_avl_add(avl, box(3), box(33), nullptr);
-  check_get(avl, 1, 11);
-  check_get(avl, 2, 22);
-  check_get(avl, 3, 33);
-  check_negget(avl, 4);
-  gpr_avl_unref(avl, nullptr);
-}
-
-static void test_ll(void) {
-  gpr_avl avl;
-  gpr_log(GPR_DEBUG, "test_ll");
-  avl = gpr_avl_create(&int_int_vtable);
-  avl = gpr_avl_add(avl, box(5), box(1), nullptr);
-  avl = gpr_avl_add(avl, box(4), box(2), nullptr);
-  avl = gpr_avl_add(avl, box(3), box(3), nullptr);
-  GPR_ASSERT(*(int*)avl.root->key == 4);
-  GPR_ASSERT(*(int*)avl.root->left->key == 3);
-  GPR_ASSERT(*(int*)avl.root->right->key == 5);
-  gpr_avl_unref(avl, nullptr);
-}
-
-static void test_lr(void) {
-  gpr_avl avl;
-  gpr_log(GPR_DEBUG, "test_lr");
-  avl = gpr_avl_create(&int_int_vtable);
-  avl = gpr_avl_add(avl, box(5), box(1), nullptr);
-  avl = gpr_avl_add(avl, box(3), box(2), nullptr);
-  avl = gpr_avl_add(avl, box(4), box(3), nullptr);
-  GPR_ASSERT(*(int*)avl.root->key == 4);
-  GPR_ASSERT(*(int*)avl.root->left->key == 3);
-  GPR_ASSERT(*(int*)avl.root->right->key == 5);
-  gpr_avl_unref(avl, nullptr);
-}
-
-static void test_rr(void) {
-  gpr_avl avl;
-  gpr_log(GPR_DEBUG, "test_rr");
-  avl = gpr_avl_create(&int_int_vtable);
-  avl = gpr_avl_add(avl, box(3), box(1), nullptr);
-  avl = gpr_avl_add(avl, box(4), box(2), nullptr);
-  avl = gpr_avl_add(avl, box(5), box(3), nullptr);
-  GPR_ASSERT(*(int*)avl.root->key == 4);
-  GPR_ASSERT(*(int*)avl.root->left->key == 3);
-  GPR_ASSERT(*(int*)avl.root->right->key == 5);
-  gpr_avl_unref(avl, nullptr);
-}
-
-static void test_rl(void) {
-  gpr_avl avl;
-  gpr_log(GPR_DEBUG, "test_rl");
-  avl = gpr_avl_create(&int_int_vtable);
-  avl = gpr_avl_add(avl, box(3), box(1), nullptr);
-  avl = gpr_avl_add(avl, box(5), box(2), nullptr);
-  avl = gpr_avl_add(avl, box(4), box(3), nullptr);
-  GPR_ASSERT(*(int*)avl.root->key == 4);
-  GPR_ASSERT(*(int*)avl.root->left->key == 3);
-  GPR_ASSERT(*(int*)avl.root->right->key == 5);
-  gpr_avl_unref(avl, nullptr);
-}
-
-static void test_unbalanced(void) {
-  gpr_avl avl;
-  gpr_log(GPR_DEBUG, "test_unbalanced");
-  avl = gpr_avl_create(&int_int_vtable);
-  avl = gpr_avl_add(avl, box(5), box(1), nullptr);
-  avl = gpr_avl_add(avl, box(4), box(2), nullptr);
-  avl = gpr_avl_add(avl, box(3), box(3), nullptr);
-  avl = gpr_avl_add(avl, box(2), box(4), nullptr);
-  avl = gpr_avl_add(avl, box(1), box(5), nullptr);
-  GPR_ASSERT(*(int*)avl.root->key == 4);
-  GPR_ASSERT(*(int*)avl.root->left->key == 2);
-  GPR_ASSERT(*(int*)avl.root->left->left->key == 1);
-  GPR_ASSERT(*(int*)avl.root->left->right->key == 3);
-  GPR_ASSERT(*(int*)avl.root->right->key == 5);
-  gpr_avl_unref(avl, nullptr);
-}
-
-static void test_replace(void) {
-  gpr_avl avl;
-  gpr_log(GPR_DEBUG, "test_replace");
-  avl = gpr_avl_create(&int_int_vtable);
-  avl = gpr_avl_add(avl, box(1), box(1), nullptr);
-  avl = gpr_avl_add(avl, box(1), box(2), nullptr);
-  check_get(avl, 1, 2);
-  check_negget(avl, 2);
-  gpr_avl_unref(avl, nullptr);
-}
-
-static void test_remove(void) {
-  gpr_avl avl;
-  gpr_avl avl3, avl4, avl5, avln;
-  gpr_log(GPR_DEBUG, "test_remove");
-  avl = gpr_avl_create(&int_int_vtable);
-  avl = gpr_avl_add(avl, box(3), box(1), nullptr);
-  avl = gpr_avl_add(avl, box(4), box(2), nullptr);
-  avl = gpr_avl_add(avl, box(5), box(3), nullptr);
-
-  avl3 = remove_int(gpr_avl_ref(avl, nullptr), 3);
-  avl4 = remove_int(gpr_avl_ref(avl, nullptr), 4);
-  avl5 = remove_int(gpr_avl_ref(avl, nullptr), 5);
-  avln = remove_int(gpr_avl_ref(avl, nullptr), 1);
-
-  gpr_avl_unref(avl, nullptr);
-
-  check_negget(avl3, 3);
-  check_get(avl3, 4, 2);
-  check_get(avl3, 5, 3);
-  gpr_avl_unref(avl3, nullptr);
-
-  check_get(avl4, 3, 1);
-  check_negget(avl4, 4);
-  check_get(avl4, 5, 3);
-  gpr_avl_unref(avl4, nullptr);
-
-  check_get(avl5, 3, 1);
-  check_get(avl5, 4, 2);
-  check_negget(avl5, 5);
-  gpr_avl_unref(avl5, nullptr);
-
-  check_get(avln, 3, 1);
-  check_get(avln, 4, 2);
-  check_get(avln, 5, 3);
-  gpr_avl_unref(avln, nullptr);
-}
-
-static void test_badcase1(void) {
-  gpr_avl avl;
-
-  gpr_log(GPR_DEBUG, "test_badcase1");
-
-  avl = gpr_avl_create(&int_int_vtable);
-  avl = gpr_avl_add(avl, box(88), box(1), nullptr);
-  avl = remove_int(avl, 643);
-  avl = remove_int(avl, 983);
-  avl = gpr_avl_add(avl, box(985), box(4), nullptr);
-  avl = gpr_avl_add(avl, box(640), box(5), nullptr);
-  avl = gpr_avl_add(avl, box(41), box(6), nullptr);
-  avl = gpr_avl_add(avl, box(112), box(7), nullptr);
-  avl = gpr_avl_add(avl, box(342), box(8), nullptr);
-  avl = remove_int(avl, 1013);
-  avl = gpr_avl_add(avl, box(434), box(10), nullptr);
-  avl = gpr_avl_add(avl, box(520), box(11), nullptr);
-  avl = gpr_avl_add(avl, box(231), box(12), nullptr);
-  avl = gpr_avl_add(avl, box(852), box(13), nullptr);
-  avl = remove_int(avl, 461);
-  avl = gpr_avl_add(avl, box(108), box(15), nullptr);
-  avl = gpr_avl_add(avl, box(806), box(16), nullptr);
-  avl = gpr_avl_add(avl, box(827), box(17), nullptr);
-  avl = remove_int(avl, 796);
-  avl = gpr_avl_add(avl, box(340), box(19), nullptr);
-  avl = gpr_avl_add(avl, box(498), box(20), nullptr);
-  avl = gpr_avl_add(avl, box(203), box(21), nullptr);
-  avl = gpr_avl_add(avl, box(751), box(22), nullptr);
-  avl = gpr_avl_add(avl, box(150), box(23), nullptr);
-  avl = remove_int(avl, 237);
-  avl = gpr_avl_add(avl, box(830), box(25), nullptr);
-  avl = remove_int(avl, 1007);
-  avl = remove_int(avl, 394);
-  avl = gpr_avl_add(avl, box(65), box(28), nullptr);
-  avl = remove_int(avl, 904);
-  avl = remove_int(avl, 123);
-  avl = gpr_avl_add(avl, box(238), box(31), nullptr);
-  avl = gpr_avl_add(avl, box(184), box(32), nullptr);
-  avl = remove_int(avl, 331);
-  avl = gpr_avl_add(avl, box(827), box(34), nullptr);
-
-  check_get(avl, 830, 25);
-
-  gpr_avl_unref(avl, nullptr);
-}
-
-static void test_badcase2(void) {
-  gpr_avl avl;
-
-  gpr_log(GPR_DEBUG, "test_badcase2");
-
-  avl = gpr_avl_create(&int_int_vtable);
-  avl = gpr_avl_add(avl, box(288), box(1), nullptr);
-  avl = remove_int(avl, 415);
-  avl = gpr_avl_add(avl, box(953), box(3), nullptr);
-  avl = gpr_avl_add(avl, box(101), box(4), nullptr);
-  avl = gpr_avl_add(avl, box(516), box(5), nullptr);
-  avl = gpr_avl_add(avl, box(547), box(6), nullptr);
-  avl = gpr_avl_add(avl, box(467), box(7), nullptr);
-  avl = gpr_avl_add(avl, box(793), box(8), nullptr);
-  avl = remove_int(avl, 190);
-  avl = gpr_avl_add(avl, box(687), box(10), nullptr);
-  avl = gpr_avl_add(avl, box(242), box(11), nullptr);
-  avl = gpr_avl_add(avl, box(142), box(12), nullptr);
-  avl = remove_int(avl, 705);
-  avl = remove_int(avl, 578);
-  avl = remove_int(avl, 767);
-  avl = remove_int(avl, 183);
-  avl = gpr_avl_add(avl, box(950), box(17), nullptr);
-  avl = gpr_avl_add(avl, box(622), box(18), nullptr);
-  avl = remove_int(avl, 513);
-  avl = remove_int(avl, 429);
-  avl = gpr_avl_add(avl, box(205), box(21), nullptr);
-  avl = remove_int(avl, 663);
-  avl = remove_int(avl, 953);
-  avl = remove_int(avl, 892);
-  avl = gpr_avl_add(avl, box(236), box(25), nullptr);
-  avl = remove_int(avl, 982);
-  avl = remove_int(avl, 201);
-  avl = remove_int(avl, 684);
-  avl = gpr_avl_add(avl, box(572), box(29), nullptr);
-  avl = remove_int(avl, 817);
-  avl = gpr_avl_add(avl, box(970), box(31), nullptr);
-  avl = remove_int(avl, 347);
-  avl = remove_int(avl, 574);
-  avl = gpr_avl_add(avl, box(752), box(34), nullptr);
-  avl = gpr_avl_add(avl, box(670), box(35), nullptr);
-  avl = gpr_avl_add(avl, box(69), box(36), nullptr);
-  avl = remove_int(avl, 111);
-  avl = remove_int(avl, 523);
-  avl = gpr_avl_add(avl, box(141), box(39), nullptr);
-  avl = remove_int(avl, 159);
-  avl = gpr_avl_add(avl, box(947), box(41), nullptr);
-  avl = gpr_avl_add(avl, box(855), box(42), nullptr);
-  avl = remove_int(avl, 218);
-  avl = remove_int(avl, 6);
-  avl = gpr_avl_add(avl, box(753), box(45), nullptr);
-  avl = remove_int(avl, 82);
-  avl = remove_int(avl, 799);
-  avl = gpr_avl_add(avl, box(572), box(48), nullptr);
-  avl = remove_int(avl, 376);
-  avl = remove_int(avl, 413);
-  avl = gpr_avl_add(avl, box(458), box(51), nullptr);
-  avl = remove_int(avl, 897);
-  avl = gpr_avl_add(avl, box(191), box(53), nullptr);
-  avl = gpr_avl_add(avl, box(609), box(54), nullptr);
-  avl = remove_int(avl, 787);
-  avl = remove_int(avl, 710);
-  avl = remove_int(avl, 886);
-  avl = remove_int(avl, 835);
-  avl = remove_int(avl, 33);
-  avl = gpr_avl_add(avl, box(871), box(60), nullptr);
-  avl = remove_int(avl, 641);
-  avl = gpr_avl_add(avl, box(462), box(62), nullptr);
-  avl = remove_int(avl, 359);
-  avl = remove_int(avl, 767);
-  avl = gpr_avl_add(avl, box(310), box(65), nullptr);
-  avl = remove_int(avl, 757);
-  avl = remove_int(avl, 639);
-  avl = remove_int(avl, 314);
-  avl = gpr_avl_add(avl, box(2), box(69), nullptr);
-  avl = remove_int(avl, 138);
-  avl = gpr_avl_add(avl, box(669), box(71), nullptr);
-  avl = remove_int(avl, 477);
-  avl = gpr_avl_add(avl, box(366), box(73), nullptr);
-  avl = gpr_avl_add(avl, box(612), box(74), nullptr);
-  avl = gpr_avl_add(avl, box(106), box(75), nullptr);
-  avl = remove_int(avl, 161);
-  avl = gpr_avl_add(avl, box(388), box(77), nullptr);
-  avl = gpr_avl_add(avl, box(141), box(78), nullptr);
-  avl = remove_int(avl, 633);
-  avl = remove_int(avl, 459);
-  avl = gpr_avl_add(avl, box(40), box(81), nullptr);
-  avl = remove_int(avl, 689);
-  avl = gpr_avl_add(avl, box(823), box(83), nullptr);
-  avl = remove_int(avl, 485);
-  avl = gpr_avl_add(avl, box(903), box(85), nullptr);
-  avl = gpr_avl_add(avl, box(592), box(86), nullptr);
-  avl = remove_int(avl, 448);
-  avl = gpr_avl_add(avl, box(56), box(88), nullptr);
-  avl = remove_int(avl, 333);
-  avl = gpr_avl_add(avl, box(189), box(90), nullptr);
-  avl = gpr_avl_add(avl, box(103), box(91), nullptr);
-  avl = remove_int(avl, 164);
-  avl = remove_int(avl, 974);
-  avl = gpr_avl_add(avl, box(215), box(94), nullptr);
-  avl = remove_int(avl, 189);
-  avl = remove_int(avl, 504);
-  avl = gpr_avl_add(avl, box(868), box(97), nullptr);
-  avl = remove_int(avl, 909);
-  avl = remove_int(avl, 148);
-  avl = remove_int(avl, 469);
-  avl = gpr_avl_add(avl, box(994), box(101), nullptr);
-  avl = gpr_avl_add(avl, box(576), box(102), nullptr);
-  avl = remove_int(avl, 82);
-  avl = remove_int(avl, 209);
-  avl = gpr_avl_add(avl, box(276), box(105), nullptr);
-  avl = remove_int(avl, 856);
-  avl = gpr_avl_add(avl, box(750), box(107), nullptr);
-  avl = remove_int(avl, 871);
-  avl = gpr_avl_add(avl, box(301), box(109), nullptr);
-  avl = remove_int(avl, 260);
-  avl = remove_int(avl, 737);
-  avl = remove_int(avl, 719);
-  avl = gpr_avl_add(avl, box(933), box(113), nullptr);
-  avl = gpr_avl_add(avl, box(225), box(114), nullptr);
-  avl = gpr_avl_add(avl, box(975), box(115), nullptr);
-  avl = gpr_avl_add(avl, box(86), box(116), nullptr);
-  avl = remove_int(avl, 732);
-  avl = gpr_avl_add(avl, box(340), box(118), nullptr);
-  avl = gpr_avl_add(avl, box(271), box(119), nullptr);
-  avl = remove_int(avl, 206);
-  avl = gpr_avl_add(avl, box(949), box(121), nullptr);
-  avl = gpr_avl_add(avl, box(927), box(122), nullptr);
-  avl = gpr_avl_add(avl, box(34), box(123), nullptr);
-  avl = gpr_avl_add(avl, box(351), box(124), nullptr);
-  avl = remove_int(avl, 836);
-  avl = gpr_avl_add(avl, box(825), box(126), nullptr);
-  avl = gpr_avl_add(avl, box(352), box(127), nullptr);
-  avl = remove_int(avl, 107);
-  avl = remove_int(avl, 101);
-  avl = gpr_avl_add(avl, box(320), box(130), nullptr);
-  avl = gpr_avl_add(avl, box(3), box(131), nullptr);
-  avl = remove_int(avl, 998);
-  avl = remove_int(avl, 44);
-  avl = gpr_avl_add(avl, box(525), box(134), nullptr);
-  avl = gpr_avl_add(avl, box(864), box(135), nullptr);
-  avl = gpr_avl_add(avl, box(863), box(136), nullptr);
-  avl = remove_int(avl, 770);
-  avl = gpr_avl_add(avl, box(440), box(138), nullptr);
-  avl = remove_int(avl, 516);
-  avl = gpr_avl_add(avl, box(116), box(140), nullptr);
-  avl = remove_int(avl, 380);
-  avl = gpr_avl_add(avl, box(878), box(142), nullptr);
-  avl = remove_int(avl, 439);
-  avl = gpr_avl_add(avl, box(994), box(144), nullptr);
-  avl = remove_int(avl, 294);
-  avl = remove_int(avl, 593);
-  avl = gpr_avl_add(avl, box(696), box(147), nullptr);
-  avl = remove_int(avl, 8);
-  avl = gpr_avl_add(avl, box(881), box(149), nullptr);
-  avl = remove_int(avl, 32);
-  avl = remove_int(avl, 242);
-  avl = gpr_avl_add(avl, box(487), box(152), nullptr);
-  avl = gpr_avl_add(avl, box(637), box(153), nullptr);
-  avl = gpr_avl_add(avl, box(793), box(154), nullptr);
-  avl = gpr_avl_add(avl, box(696), box(155), nullptr);
-  avl = remove_int(avl, 458);
-  avl = gpr_avl_add(avl, box(828), box(157), nullptr);
-  avl = remove_int(avl, 784);
-  avl = remove_int(avl, 274);
-  avl = gpr_avl_add(avl, box(783), box(160), nullptr);
-  avl = remove_int(avl, 21);
-  avl = gpr_avl_add(avl, box(866), box(162), nullptr);
-  avl = remove_int(avl, 919);
-  avl = gpr_avl_add(avl, box(435), box(164), nullptr);
-  avl = remove_int(avl, 385);
-  avl = gpr_avl_add(avl, box(475), box(166), nullptr);
-  avl = remove_int(avl, 339);
-  avl = gpr_avl_add(avl, box(615), box(168), nullptr);
-  avl = remove_int(avl, 866);
-  avl = remove_int(avl, 82);
-  avl = remove_int(avl, 271);
-  avl = gpr_avl_add(avl, box(590), box(172), nullptr);
-  avl = gpr_avl_add(avl, box(852), box(173), nullptr);
-  avl = remove_int(avl, 318);
-  avl = remove_int(avl, 82);
-  avl = gpr_avl_add(avl, box(672), box(176), nullptr);
-  avl = remove_int(avl, 430);
-  avl = gpr_avl_add(avl, box(821), box(178), nullptr);
-  avl = gpr_avl_add(avl, box(365), box(179), nullptr);
-  avl = remove_int(avl, 78);
-  avl = gpr_avl_add(avl, box(700), box(181), nullptr);
-  avl = gpr_avl_add(avl, box(353), box(182), nullptr);
-  avl = remove_int(avl, 492);
-  avl = gpr_avl_add(avl, box(991), box(184), nullptr);
-  avl = remove_int(avl, 330);
-  avl = gpr_avl_add(avl, box(873), box(186), nullptr);
-  avl = remove_int(avl, 589);
-  avl = gpr_avl_add(avl, box(676), box(188), nullptr);
-  avl = gpr_avl_add(avl, box(790), box(189), nullptr);
-  avl = remove_int(avl, 521);
-  avl = remove_int(avl, 47);
-  avl = gpr_avl_add(avl, box(976), box(192), nullptr);
-  avl = gpr_avl_add(avl, box(683), box(193), nullptr);
-  avl = remove_int(avl, 803);
-  avl = remove_int(avl, 1006);
-  avl = gpr_avl_add(avl, box(775), box(196), nullptr);
-  avl = gpr_avl_add(avl, box(411), box(197), nullptr);
-  avl = gpr_avl_add(avl, box(697), box(198), nullptr);
-  avl = remove_int(avl, 50);
-  avl = gpr_avl_add(avl, box(213), box(200), nullptr);
-  avl = remove_int(avl, 714);
-  avl = gpr_avl_add(avl, box(981), box(202), nullptr);
-  avl = gpr_avl_add(avl, box(502), box(203), nullptr);
-  avl = gpr_avl_add(avl, box(697), box(204), nullptr);
-  avl = gpr_avl_add(avl, box(603), box(205), nullptr);
-  avl = gpr_avl_add(avl, box(117), box(206), nullptr);
-  avl = remove_int(avl, 363);
-  avl = gpr_avl_add(avl, box(104), box(208), nullptr);
-  avl = remove_int(avl, 842);
-  avl = gpr_avl_add(avl, box(48), box(210), nullptr);
-  avl = remove_int(avl, 764);
-  avl = gpr_avl_add(avl, box(482), box(212), nullptr);
-  avl = gpr_avl_add(avl, box(928), box(213), nullptr);
-  avl = gpr_avl_add(avl, box(30), box(214), nullptr);
-  avl = gpr_avl_add(avl, box(820), box(215), nullptr);
-  avl = gpr_avl_add(avl, box(334), box(216), nullptr);
-  avl = remove_int(avl, 306);
-  avl = gpr_avl_add(avl, box(789), box(218), nullptr);
-  avl = remove_int(avl, 924);
-  avl = gpr_avl_add(avl, box(53), box(220), nullptr);
-  avl = remove_int(avl, 657);
-  avl = gpr_avl_add(avl, box(130), box(222), nullptr);
-  avl = gpr_avl_add(avl, box(239), box(223), nullptr);
-  avl = remove_int(avl, 20);
-  avl = gpr_avl_add(avl, box(117), box(225), nullptr);
-  avl = remove_int(avl, 882);
-  avl = remove_int(avl, 891);
-  avl = gpr_avl_add(avl, box(9), box(228), nullptr);
-  avl = gpr_avl_add(avl, box(496), box(229), nullptr);
-  avl = gpr_avl_add(avl, box(750), box(230), nullptr);
-  avl = gpr_avl_add(avl, box(283), box(231), nullptr);
-  avl = gpr_avl_add(avl, box(802), box(232), nullptr);
-  avl = remove_int(avl, 352);
-  avl = gpr_avl_add(avl, box(374), box(234), nullptr);
-  avl = gpr_avl_add(avl, box(6), box(235), nullptr);
-  avl = gpr_avl_add(avl, box(756), box(236), nullptr);
-  avl = gpr_avl_add(avl, box(597), box(237), nullptr);
-  avl = gpr_avl_add(avl, box(661), box(238), nullptr);
-  avl = remove_int(avl, 96);
-  avl = gpr_avl_add(avl, box(894), box(240), nullptr);
-  avl = remove_int(avl, 749);
-  avl = gpr_avl_add(avl, box(71), box(242), nullptr);
-  avl = remove_int(avl, 68);
-  avl = gpr_avl_add(avl, box(388), box(244), nullptr);
-  avl = remove_int(avl, 119);
-  avl = remove_int(avl, 856);
-  avl = gpr_avl_add(avl, box(176), box(247), nullptr);
-  avl = gpr_avl_add(avl, box(993), box(248), nullptr);
-  avl = remove_int(avl, 178);
-  avl = remove_int(avl, 781);
-  avl = remove_int(avl, 771);
-  avl = remove_int(avl, 848);
-  avl = remove_int(avl, 376);
-  avl = remove_int(avl, 157);
-  avl = remove_int(avl, 142);
-  avl = remove_int(avl, 686);
-  avl = gpr_avl_add(avl, box(779), box(257), nullptr);
-  avl = gpr_avl_add(avl, box(484), box(258), nullptr);
-  avl = remove_int(avl, 837);
-  avl = gpr_avl_add(avl, box(388), box(260), nullptr);
-  avl = remove_int(avl, 987);
-  avl = gpr_avl_add(avl, box(336), box(262), nullptr);
-  avl = remove_int(avl, 855);
-  avl = gpr_avl_add(avl, box(668), box(264), nullptr);
-  avl = remove_int(avl, 648);
-  avl = gpr_avl_add(avl, box(193), box(266), nullptr);
-  avl = remove_int(avl, 939);
-  avl = gpr_avl_add(avl, box(740), box(268), nullptr);
-  avl = gpr_avl_add(avl, box(503), box(269), nullptr);
-  avl = gpr_avl_add(avl, box(765), box(270), nullptr);
-  avl = remove_int(avl, 924);
-  avl = remove_int(avl, 513);
-  avl = gpr_avl_add(avl, box(161), box(273), nullptr);
-  avl = gpr_avl_add(avl, box(502), box(274), nullptr);
-  avl = gpr_avl_add(avl, box(846), box(275), nullptr);
-  avl = remove_int(avl, 931);
-  avl = gpr_avl_add(avl, box(87), box(277), nullptr);
-  avl = gpr_avl_add(avl, box(949), box(278), nullptr);
-  avl = gpr_avl_add(avl, box(548), box(279), nullptr);
-  avl = gpr_avl_add(avl, box(951), box(280), nullptr);
-  avl = remove_int(avl, 1018);
-  avl = remove_int(avl, 568);
-  avl = gpr_avl_add(avl, box(138), box(283), nullptr);
-  avl = gpr_avl_add(avl, box(202), box(284), nullptr);
-  avl = gpr_avl_add(avl, box(157), box(285), nullptr);
-  avl = gpr_avl_add(avl, box(264), box(286), nullptr);
-  avl = gpr_avl_add(avl, box(370), box(287), nullptr);
-  avl = remove_int(avl, 736);
-  avl = remove_int(avl, 751);
-  avl = remove_int(avl, 506);
-  avl = remove_int(avl, 81);
-  avl = remove_int(avl, 358);
-  avl = remove_int(avl, 657);
-  avl = remove_int(avl, 86);
-  avl = gpr_avl_add(avl, box(876), box(295), nullptr);
-  avl = remove_int(avl, 354);
-  avl = gpr_avl_add(avl, box(134), box(297), nullptr);
-  avl = remove_int(avl, 781);
-  avl = remove_int(avl, 183);
-  avl = gpr_avl_add(avl, box(914), box(300), nullptr);
-  avl = remove_int(avl, 926);
-  avl = remove_int(avl, 398);
-  avl = remove_int(avl, 932);
-  avl = remove_int(avl, 804);
-  avl = remove_int(avl, 326);
-  avl = gpr_avl_add(avl, box(208), box(306), nullptr);
-  avl = gpr_avl_add(avl, box(699), box(307), nullptr);
-  avl = remove_int(avl, 576);
-  avl = remove_int(avl, 850);
-  avl = remove_int(avl, 514);
-  avl = remove_int(avl, 676);
-  avl = remove_int(avl, 549);
-  avl = remove_int(avl, 767);
-  avl = gpr_avl_add(avl, box(58), box(314), nullptr);
-  avl = gpr_avl_add(avl, box(265), box(315), nullptr);
-  avl = gpr_avl_add(avl, box(268), box(316), nullptr);
-  avl = gpr_avl_add(avl, box(103), box(317), nullptr);
-  avl = gpr_avl_add(avl, box(440), box(318), nullptr);
-  avl = remove_int(avl, 777);
-  avl = gpr_avl_add(avl, box(670), box(320), nullptr);
-  avl = remove_int(avl, 506);
-  avl = remove_int(avl, 487);
-  avl = gpr_avl_add(avl, box(421), box(323), nullptr);
-  avl = remove_int(avl, 514);
-  avl = gpr_avl_add(avl, box(701), box(325), nullptr);
-  avl = remove_int(avl, 949);
-  avl = remove_int(avl, 872);
-  avl = remove_int(avl, 139);
-  avl = gpr_avl_add(avl, box(781), box(329), nullptr);
-  avl = gpr_avl_add(avl, box(543), box(330), nullptr);
-  avl = gpr_avl_add(avl, box(147), box(331), nullptr);
-  avl = remove_int(avl, 190);
-  avl = gpr_avl_add(avl, box(453), box(333), nullptr);
-  avl = remove_int(avl, 262);
-  avl = remove_int(avl, 850);
-  avl = remove_int(avl, 286);
-  avl = remove_int(avl, 787);
-  avl = gpr_avl_add(avl, box(514), box(338), nullptr);
-  avl = remove_int(avl, 812);
-  avl = gpr_avl_add(avl, box(431), box(340), nullptr);
-  avl = gpr_avl_add(avl, box(8), box(341), nullptr);
-  avl = remove_int(avl, 843);
-  avl = gpr_avl_add(avl, box(831), box(343), nullptr);
-  avl = remove_int(avl, 472);
-  avl = remove_int(avl, 157);
-  avl = gpr_avl_add(avl, box(612), box(346), nullptr);
-  avl = gpr_avl_add(avl, box(802), box(347), nullptr);
-  avl = remove_int(avl, 554);
-  avl = gpr_avl_add(avl, box(409), box(349), nullptr);
-  avl = gpr_avl_add(avl, box(439), box(350), nullptr);
-  avl = gpr_avl_add(avl, box(725), box(351), nullptr);
-  avl = gpr_avl_add(avl, box(568), box(352), nullptr);
-  avl = remove_int(avl, 475);
-  avl = remove_int(avl, 672);
-  avl = remove_int(avl, 62);
-  avl = remove_int(avl, 753);
-  avl = gpr_avl_add(avl, box(435), box(357), nullptr);
-  avl = gpr_avl_add(avl, box(950), box(358), nullptr);
-  avl = gpr_avl_add(avl, box(532), box(359), nullptr);
-  avl = gpr_avl_add(avl, box(832), box(360), nullptr);
-  avl = remove_int(avl, 390);
-  avl = gpr_avl_add(avl, box(993), box(362), nullptr);
-  avl = remove_int(avl, 198);
-  avl = remove_int(avl, 401);
-  avl = gpr_avl_add(avl, box(316), box(365), nullptr);
-  avl = remove_int(avl, 843);
-  avl = gpr_avl_add(avl, box(541), box(367), nullptr);
-  avl = gpr_avl_add(avl, box(505), box(368), nullptr);
-  avl = remove_int(avl, 445);
-  avl = remove_int(avl, 256);
-  avl = gpr_avl_add(avl, box(232), box(371), nullptr);
-  avl = remove_int(avl, 577);
-  avl = remove_int(avl, 558);
-  avl = gpr_avl_add(avl, box(910), box(374), nullptr);
-  avl = remove_int(avl, 902);
-  avl = remove_int(avl, 755);
-  avl = remove_int(avl, 114);
-  avl = remove_int(avl, 438);
-  avl = remove_int(avl, 224);
-  avl = gpr_avl_add(avl, box(920), box(380), nullptr);
-  avl = gpr_avl_add(avl, box(655), box(381), nullptr);
-  avl = remove_int(avl, 557);
-  avl = remove_int(avl, 102);
-  avl = remove_int(avl, 165);
-  avl = gpr_avl_add(avl, box(191), box(385), nullptr);
-  avl = remove_int(avl, 30);
-  avl = gpr_avl_add(avl, box(406), box(387), nullptr);
-  avl = gpr_avl_add(avl, box(66), box(388), nullptr);
-  avl = gpr_avl_add(avl, box(87), box(389), nullptr);
-  avl = remove_int(avl, 7);
-  avl = remove_int(avl, 671);
-  avl = gpr_avl_add(avl, box(234), box(392), nullptr);
-  avl = remove_int(avl, 463);
-  avl = gpr_avl_add(avl, box(75), box(394), nullptr);
-  avl = gpr_avl_add(avl, box(487), box(395), nullptr);
-  avl = remove_int(avl, 203);
-  avl = gpr_avl_add(avl, box(711), box(397), nullptr);
-  avl = remove_int(avl, 291);
-  avl = remove_int(avl, 798);
-  avl = remove_int(avl, 337);
-  avl = gpr_avl_add(avl, box(877), box(401), nullptr);
-  avl = gpr_avl_add(avl, box(388), box(402), nullptr);
-  avl = remove_int(avl, 975);
-  avl = gpr_avl_add(avl, box(200), box(404), nullptr);
-  avl = gpr_avl_add(avl, box(408), box(405), nullptr);
-  avl = gpr_avl_add(avl, box(3), box(406), nullptr);
-  avl = gpr_avl_add(avl, box(971), box(407), nullptr);
-  avl = remove_int(avl, 841);
-  avl = remove_int(avl, 910);
-  avl = remove_int(avl, 74);
-  avl = remove_int(avl, 888);
-  avl = gpr_avl_add(avl, box(492), box(412), nullptr);
-  avl = remove_int(avl, 14);
-  avl = remove_int(avl, 364);
-  avl = gpr_avl_add(avl, box(215), box(415), nullptr);
-  avl = remove_int(avl, 778);
-  avl = remove_int(avl, 45);
-  avl = gpr_avl_add(avl, box(328), box(418), nullptr);
-  avl = gpr_avl_add(avl, box(597), box(419), nullptr);
-  avl = remove_int(avl, 34);
-  avl = gpr_avl_add(avl, box(736), box(421), nullptr);
-  avl = remove_int(avl, 37);
-  avl = gpr_avl_add(avl, box(275), box(423), nullptr);
-  avl = gpr_avl_add(avl, box(70), box(424), nullptr);
-  avl = gpr_avl_add(avl, box(771), box(425), nullptr);
-  avl = remove_int(avl, 536);
-  avl = remove_int(avl, 421);
-  avl = gpr_avl_add(avl, box(186), box(428), nullptr);
-  avl = gpr_avl_add(avl, box(788), box(429), nullptr);
-  avl = gpr_avl_add(avl, box(224), box(430), nullptr);
-  avl = remove_int(avl, 228);
-  avl = gpr_avl_add(avl, box(48), box(432), nullptr);
-  avl = gpr_avl_add(avl, box(120), box(433), nullptr);
-  avl = gpr_avl_add(avl, box(269), box(434), nullptr);
-  avl = gpr_avl_add(avl, box(904), box(435), nullptr);
-  avl = remove_int(avl, 699);
-  avl = gpr_avl_add(avl, box(340), box(437), nullptr);
-  avl = remove_int(avl, 276);
-  avl = gpr_avl_add(avl, box(591), box(439), nullptr);
-  avl = gpr_avl_add(avl, box(778), box(440), nullptr);
-  avl = remove_int(avl, 490);
-  avl = remove_int(avl, 973);
-  avl = gpr_avl_add(avl, box(294), box(443), nullptr);
-  avl = gpr_avl_add(avl, box(323), box(444), nullptr);
-  avl = remove_int(avl, 685);
-  avl = gpr_avl_add(avl, box(38), box(446), nullptr);
-  avl = gpr_avl_add(avl, box(525), box(447), nullptr);
-  avl = remove_int(avl, 162);
-  avl = gpr_avl_add(avl, box(462), box(449), nullptr);
-  avl = gpr_avl_add(avl, box(340), box(450), nullptr);
-  avl = remove_int(avl, 734);
-  avl = remove_int(avl, 959);
-  avl = gpr_avl_add(avl, box(752), box(453), nullptr);
-  avl = gpr_avl_add(avl, box(667), box(454), nullptr);
-  avl = remove_int(avl, 558);
-  avl = remove_int(avl, 657);
-  avl = gpr_avl_add(avl, box(711), box(457), nullptr);
-  avl = remove_int(avl, 937);
-  avl = gpr_avl_add(avl, box(741), box(459), nullptr);
-  avl = gpr_avl_add(avl, box(40), box(460), nullptr);
-  avl = remove_int(avl, 784);
-  avl = gpr_avl_add(avl, box(292), box(462), nullptr);
-  avl = remove_int(avl, 164);
-  avl = remove_int(avl, 931);
-  avl = remove_int(avl, 886);
-  avl = gpr_avl_add(avl, box(968), box(466), nullptr);
-  avl = remove_int(avl, 263);
-  avl = gpr_avl_add(avl, box(647), box(468), nullptr);
-  avl = gpr_avl_add(avl, box(92), box(469), nullptr);
-  avl = remove_int(avl, 310);
-  avl = gpr_avl_add(avl, box(711), box(471), nullptr);
-  avl = gpr_avl_add(avl, box(675), box(472), nullptr);
-  avl = remove_int(avl, 549);
-  avl = gpr_avl_add(avl, box(380), box(474), nullptr);
-  avl = remove_int(avl, 825);
-  avl = gpr_avl_add(avl, box(668), box(476), nullptr);
-  avl = remove_int(avl, 498);
-  avl = gpr_avl_add(avl, box(870), box(478), nullptr);
-  avl = gpr_avl_add(avl, box(391), box(479), nullptr);
-  avl = gpr_avl_add(avl, box(264), box(480), nullptr);
-  avl = remove_int(avl, 1);
-  avl = remove_int(avl, 849);
-  avl = remove_int(avl, 88);
-  avl = remove_int(avl, 255);
-  avl = remove_int(avl, 763);
-  avl = remove_int(avl, 831);
-  avl = gpr_avl_add(avl, box(508), box(487), nullptr);
-  avl = remove_int(avl, 849);
-  avl = remove_int(avl, 47);
-  avl = gpr_avl_add(avl, box(299), box(490), nullptr);
-  avl = remove_int(avl, 625);
-  avl = remove_int(avl, 433);
-  avl = remove_int(avl, 904);
-  avl = remove_int(avl, 761);
-  avl = gpr_avl_add(avl, box(33), box(495), nullptr);
-  avl = gpr_avl_add(avl, box(524), box(496), nullptr);
-  avl = remove_int(avl, 210);
-  avl = remove_int(avl, 299);
-  avl = gpr_avl_add(avl, box(823), box(499), nullptr);
-  avl = remove_int(avl, 479);
-  avl = remove_int(avl, 96);
-  avl = remove_int(avl, 1013);
-  avl = gpr_avl_add(avl, box(768), box(503), nullptr);
-  avl = remove_int(avl, 638);
-  avl = remove_int(avl, 20);
-  avl = gpr_avl_add(avl, box(663), box(506), nullptr);
-  avl = remove_int(avl, 882);
-  avl = gpr_avl_add(avl, box(745), box(508), nullptr);
-  avl = remove_int(avl, 352);
-  avl = gpr_avl_add(avl, box(10), box(510), nullptr);
-  avl = remove_int(avl, 484);
-  avl = gpr_avl_add(avl, box(420), box(512), nullptr);
-  avl = gpr_avl_add(avl, box(884), box(513), nullptr);
-  avl = gpr_avl_add(avl, box(993), box(514), nullptr);
-  avl = gpr_avl_add(avl, box(251), box(515), nullptr);
-  avl = remove_int(avl, 222);
-  avl = gpr_avl_add(avl, box(734), box(517), nullptr);
-  avl = gpr_avl_add(avl, box(952), box(518), nullptr);
-  avl = remove_int(avl, 26);
-  avl = remove_int(avl, 270);
-  avl = remove_int(avl, 481);
-  avl = remove_int(avl, 693);
-  avl = remove_int(avl, 1006);
-  avl = gpr_avl_add(avl, box(77), box(524), nullptr);
-  avl = remove_int(avl, 897);
-  avl = gpr_avl_add(avl, box(719), box(526), nullptr);
-  avl = gpr_avl_add(avl, box(622), box(527), nullptr);
-  avl = remove_int(avl, 28);
-  avl = remove_int(avl, 836);
-  avl = remove_int(avl, 142);
-  avl = gpr_avl_add(avl, box(445), box(531), nullptr);
-  avl = gpr_avl_add(avl, box(410), box(532), nullptr);
-  avl = remove_int(avl, 575);
-  avl = gpr_avl_add(avl, box(634), box(534), nullptr);
-  avl = gpr_avl_add(avl, box(906), box(535), nullptr);
-  avl = remove_int(avl, 649);
-  avl = gpr_avl_add(avl, box(813), box(537), nullptr);
-  avl = remove_int(avl, 702);
-  avl = remove_int(avl, 732);
-  avl = gpr_avl_add(avl, box(105), box(540), nullptr);
-  avl = gpr_avl_add(avl, box(867), box(541), nullptr);
-  avl = remove_int(avl, 964);
-  avl = remove_int(avl, 941);
-  avl = gpr_avl_add(avl, box(947), box(544), nullptr);
-  avl = remove_int(avl, 990);
-  avl = gpr_avl_add(avl, box(816), box(546), nullptr);
-  avl = remove_int(avl, 429);
-  avl = remove_int(avl, 567);
-  avl = remove_int(avl, 541);
-  avl = remove_int(avl, 583);
-  avl = gpr_avl_add(avl, box(57), box(551), nullptr);
-  avl = gpr_avl_add(avl, box(786), box(552), nullptr);
-  avl = gpr_avl_add(avl, box(526), box(553), nullptr);
-  avl = remove_int(avl, 642);
-  avl = remove_int(avl, 220);
-  avl = remove_int(avl, 840);
-  avl = remove_int(avl, 548);
-  avl = gpr_avl_add(avl, box(528), box(558), nullptr);
-  avl = gpr_avl_add(avl, box(749), box(559), nullptr);
-  avl = gpr_avl_add(avl, box(194), box(560), nullptr);
-  avl = remove_int(avl, 517);
-  avl = gpr_avl_add(avl, box(102), box(562), nullptr);
-  avl = remove_int(avl, 189);
-  avl = gpr_avl_add(avl, box(927), box(564), nullptr);
-  avl = remove_int(avl, 846);
-  avl = remove_int(avl, 130);
-  avl = gpr_avl_add(avl, box(694), box(567), nullptr);
-  avl = remove_int(avl, 750);
-  avl = gpr_avl_add(avl, box(357), box(569), nullptr);
-  avl = remove_int(avl, 431);
-  avl = remove_int(avl, 91);
-  avl = gpr_avl_add(avl, box(640), box(572), nullptr);
-  avl = remove_int(avl, 4);
-  avl = gpr_avl_add(avl, box(81), box(574), nullptr);
-  avl = gpr_avl_add(avl, box(595), box(575), nullptr);
-  avl = remove_int(avl, 444);
-  avl = remove_int(avl, 262);
-  avl = remove_int(avl, 11);
-  avl = gpr_avl_add(avl, box(192), box(579), nullptr);
-  avl = gpr_avl_add(avl, box(158), box(580), nullptr);
-  avl = remove_int(avl, 401);
-  avl = remove_int(avl, 918);
-  avl = gpr_avl_add(avl, box(180), box(583), nullptr);
-  avl = remove_int(avl, 268);
-  avl = gpr_avl_add(avl, box(1012), box(585), nullptr);
-  avl = gpr_avl_add(avl, box(90), box(586), nullptr);
-  avl = gpr_avl_add(avl, box(946), box(587), nullptr);
-  avl = remove_int(avl, 719);
-  avl = gpr_avl_add(avl, box(874), box(589), nullptr);
-  avl = gpr_avl_add(avl, box(679), box(590), nullptr);
-  avl = remove_int(avl, 53);
-  avl = remove_int(avl, 534);
-  avl = gpr_avl_add(avl, box(646), box(593), nullptr);
-  avl = gpr_avl_add(avl, box(767), box(594), nullptr);
-  avl = gpr_avl_add(avl, box(460), box(595), nullptr);
-  avl = gpr_avl_add(avl, box(852), box(596), nullptr);
-  avl = gpr_avl_add(avl, box(189), box(597), nullptr);
-  avl = remove_int(avl, 932);
-  avl = remove_int(avl, 366);
-  avl = remove_int(avl, 907);
-  avl = gpr_avl_add(avl, box(875), box(601), nullptr);
-  avl = gpr_avl_add(avl, box(434), box(602), nullptr);
-  avl = gpr_avl_add(avl, box(704), box(603), nullptr);
-  avl = gpr_avl_add(avl, box(724), box(604), nullptr);
-  avl = gpr_avl_add(avl, box(930), box(605), nullptr);
-  avl = gpr_avl_add(avl, box(1000), box(606), nullptr);
-  avl = remove_int(avl, 479);
-  avl = gpr_avl_add(avl, box(275), box(608), nullptr);
-  avl = remove_int(avl, 32);
-  avl = gpr_avl_add(avl, box(939), box(610), nullptr);
-  avl = remove_int(avl, 943);
-  avl = remove_int(avl, 329);
-  avl = gpr_avl_add(avl, box(490), box(613), nullptr);
-  avl = remove_int(avl, 477);
-  avl = remove_int(avl, 414);
-  avl = remove_int(avl, 187);
-  avl = remove_int(avl, 334);
-  avl = gpr_avl_add(avl, box(40), box(618), nullptr);
-  avl = remove_int(avl, 751);
-  avl = gpr_avl_add(avl, box(568), box(620), nullptr);
-  avl = gpr_avl_add(avl, box(120), box(621), nullptr);
-  avl = gpr_avl_add(avl, box(617), box(622), nullptr);
-  avl = gpr_avl_add(avl, box(32), box(623), nullptr);
-  avl = remove_int(avl, 701);
-  avl = gpr_avl_add(avl, box(910), box(625), nullptr);
-  avl = remove_int(avl, 557);
-  avl = remove_int(avl, 361);
-  avl = remove_int(avl, 937);
-  avl = remove_int(avl, 100);
-  avl = remove_int(avl, 684);
-  avl = gpr_avl_add(avl, box(751), box(631), nullptr);
-  avl = remove_int(avl, 781);
-  avl = remove_int(avl, 469);
-  avl = remove_int(avl, 75);
-  avl = remove_int(avl, 561);
-  avl = gpr_avl_add(avl, box(854), box(636), nullptr);
-  avl = remove_int(avl, 164);
-  avl = remove_int(avl, 258);
-  avl = remove_int(avl, 315);
-  avl = remove_int(avl, 261);
-  avl = gpr_avl_add(avl, box(552), box(641), nullptr);
-  avl = gpr_avl_add(avl, box(6), box(642), nullptr);
-  avl = gpr_avl_add(avl, box(680), box(643), nullptr);
-  avl = remove_int(avl, 741);
-  avl = remove_int(avl, 309);
-  avl = remove_int(avl, 272);
-  avl = gpr_avl_add(avl, box(249), box(647), nullptr);
-  avl = remove_int(avl, 97);
-  avl = remove_int(avl, 850);
-  avl = gpr_avl_add(avl, box(915), box(650), nullptr);
-  avl = gpr_avl_add(avl, box(816), box(651), nullptr);
-  avl = gpr_avl_add(avl, box(45), box(652), nullptr);
-  avl = gpr_avl_add(avl, box(168), box(653), nullptr);
-  avl = remove_int(avl, 153);
-  avl = remove_int(avl, 239);
-  avl = gpr_avl_add(avl, box(684), box(656), nullptr);
-  avl = gpr_avl_add(avl, box(208), box(657), nullptr);
-  avl = gpr_avl_add(avl, box(681), box(658), nullptr);
-  avl = gpr_avl_add(avl, box(609), box(659), nullptr);
-  avl = gpr_avl_add(avl, box(645), box(660), nullptr);
-  avl = remove_int(avl, 799);
-  avl = gpr_avl_add(avl, box(955), box(662), nullptr);
-  avl = gpr_avl_add(avl, box(946), box(663), nullptr);
-  avl = gpr_avl_add(avl, box(744), box(664), nullptr);
-  avl = gpr_avl_add(avl, box(201), box(665), nullptr);
-  avl = gpr_avl_add(avl, box(136), box(666), nullptr);
-  avl = remove_int(avl, 357);
-  avl = gpr_avl_add(avl, box(974), box(668), nullptr);
-  avl = remove_int(avl, 485);
-  avl = gpr_avl_add(avl, box(1009), box(670), nullptr);
-  avl = gpr_avl_add(avl, box(517), box(671), nullptr);
-  avl = remove_int(avl, 491);
-  avl = gpr_avl_add(avl, box(336), box(673), nullptr);
-  avl = gpr_avl_add(avl, box(589), box(674), nullptr);
-  avl = remove_int(avl, 546);
-  avl = remove_int(avl, 840);
-  avl = remove_int(avl, 104);
-  avl = remove_int(avl, 347);
-  avl = gpr_avl_add(avl, box(801), box(679), nullptr);
-  avl = remove_int(avl, 799);
-  avl = remove_int(avl, 702);
-  avl = remove_int(avl, 996);
-  avl = remove_int(avl, 93);
-  avl = gpr_avl_add(avl, box(561), box(684), nullptr);
-  avl = gpr_avl_add(avl, box(25), box(685), nullptr);
-  avl = remove_int(avl, 278);
-  avl = gpr_avl_add(avl, box(191), box(687), nullptr);
-  avl = remove_int(avl, 243);
-  avl = remove_int(avl, 918);
-  avl = remove_int(avl, 449);
-  avl = gpr_avl_add(avl, box(19), box(691), nullptr);
-  avl = gpr_avl_add(avl, box(762), box(692), nullptr);
-  avl = gpr_avl_add(avl, box(13), box(693), nullptr);
-  avl = gpr_avl_add(avl, box(151), box(694), nullptr);
-  avl = gpr_avl_add(avl, box(152), box(695), nullptr);
-  avl = gpr_avl_add(avl, box(793), box(696), nullptr);
-  avl = remove_int(avl, 862);
-  avl = remove_int(avl, 890);
-  avl = gpr_avl_add(avl, box(687), box(699), nullptr);
-  avl = gpr_avl_add(avl, box(509), box(700), nullptr);
-  avl = gpr_avl_add(avl, box(973), box(701), nullptr);
-  avl = remove_int(avl, 230);
-  avl = gpr_avl_add(avl, box(532), box(703), nullptr);
-  avl = remove_int(avl, 668);
-  avl = gpr_avl_add(avl, box(281), box(705), nullptr);
-  avl = gpr_avl_add(avl, box(867), box(706), nullptr);
-  avl = gpr_avl_add(avl, box(359), box(707), nullptr);
-  avl = remove_int(avl, 425);
-  avl = gpr_avl_add(avl, box(691), box(709), nullptr);
-  avl = gpr_avl_add(avl, box(163), box(710), nullptr);
-  avl = gpr_avl_add(avl, box(502), box(711), nullptr);
-  avl = remove_int(avl, 674);
-  avl = gpr_avl_add(avl, box(697), box(713), nullptr);
-  avl = remove_int(avl, 271);
-  avl = gpr_avl_add(avl, box(968), box(715), nullptr);
-  avl = gpr_avl_add(avl, box(48), box(716), nullptr);
-  avl = remove_int(avl, 543);
-  avl = gpr_avl_add(avl, box(35), box(718), nullptr);
-  avl = gpr_avl_add(avl, box(751), box(719), nullptr);
-  avl = gpr_avl_add(avl, box(478), box(720), nullptr);
-  avl = remove_int(avl, 797);
-  avl = remove_int(avl, 309);
-  avl = gpr_avl_add(avl, box(927), box(723), nullptr);
-  avl = remove_int(avl, 504);
-  avl = gpr_avl_add(avl, box(286), box(725), nullptr);
-  avl = gpr_avl_add(avl, box(413), box(726), nullptr);
-  avl = gpr_avl_add(avl, box(599), box(727), nullptr);
-  avl = remove_int(avl, 105);
-  avl = remove_int(avl, 605);
-  avl = gpr_avl_add(avl, box(632), box(730), nullptr);
-  avl = gpr_avl_add(avl, box(133), box(731), nullptr);
-  avl = remove_int(avl, 443);
-  avl = gpr_avl_add(avl, box(958), box(733), nullptr);
-  avl = gpr_avl_add(avl, box(729), box(734), nullptr);
-  avl = remove_int(avl, 158);
-  avl = gpr_avl_add(avl, box(694), box(736), nullptr);
-  avl = gpr_avl_add(avl, box(505), box(737), nullptr);
-  avl = remove_int(avl, 63);
-  avl = remove_int(avl, 714);
-  avl = gpr_avl_add(avl, box(1002), box(740), nullptr);
-  avl = remove_int(avl, 211);
-  avl = gpr_avl_add(avl, box(765), box(742), nullptr);
-  avl = gpr_avl_add(avl, box(455), box(743), nullptr);
-  avl = remove_int(avl, 59);
-  avl = remove_int(avl, 224);
-  avl = gpr_avl_add(avl, box(586), box(746), nullptr);
-  avl = gpr_avl_add(avl, box(348), box(747), nullptr);
-  avl = remove_int(avl, 10);
-  avl = remove_int(avl, 484);
-  avl = gpr_avl_add(avl, box(968), box(750), nullptr);
-  avl = gpr_avl_add(avl, box(923), box(751), nullptr);
-  avl = remove_int(avl, 573);
-  avl = remove_int(avl, 617);
-  avl = gpr_avl_add(avl, box(812), box(754), nullptr);
-  avl = gpr_avl_add(avl, box(179), box(755), nullptr);
-  avl = remove_int(avl, 284);
-  avl = remove_int(avl, 157);
-  avl = remove_int(avl, 177);
-  avl = remove_int(avl, 896);
-  avl = gpr_avl_add(avl, box(649), box(760), nullptr);
-  avl = gpr_avl_add(avl, box(927), box(761), nullptr);
-  avl = gpr_avl_add(avl, box(454), box(762), nullptr);
-  avl = gpr_avl_add(avl, box(217), box(763), nullptr);
-  avl = remove_int(avl, 534);
-  avl = gpr_avl_add(avl, box(180), box(765), nullptr);
-  avl = gpr_avl_add(avl, box(319), box(766), nullptr);
-  avl = remove_int(avl, 92);
-  avl = gpr_avl_add(avl, box(483), box(768), nullptr);
-  avl = remove_int(avl, 504);
-  avl = remove_int(avl, 1017);
-  avl = remove_int(avl, 37);
-  avl = remove_int(avl, 50);
-  avl = gpr_avl_add(avl, box(302), box(773), nullptr);
-  avl = remove_int(avl, 807);
-  avl = gpr_avl_add(avl, box(463), box(775), nullptr);
-  avl = gpr_avl_add(avl, box(271), box(776), nullptr);
-  avl = gpr_avl_add(avl, box(644), box(777), nullptr);
-  avl = remove_int(avl, 618);
-  avl = gpr_avl_add(avl, box(166), box(779), nullptr);
-  avl = gpr_avl_add(avl, box(538), box(780), nullptr);
-  avl = remove_int(avl, 606);
-  avl = gpr_avl_add(avl, box(425), box(782), nullptr);
-  avl = remove_int(avl, 725);
-  avl = remove_int(avl, 383);
-  avl = gpr_avl_add(avl, box(155), box(785), nullptr);
-  avl = remove_int(avl, 889);
-  avl = gpr_avl_add(avl, box(653), box(787), nullptr);
-  avl = remove_int(avl, 386);
-  avl = gpr_avl_add(avl, box(142), box(789), nullptr);
-  avl = remove_int(avl, 107);
-  avl = remove_int(avl, 603);
-  avl = remove_int(avl, 971);
-  avl = gpr_avl_add(avl, box(80), box(793), nullptr);
-  avl = gpr_avl_add(avl, box(61), box(794), nullptr);
-  avl = gpr_avl_add(avl, box(693), box(795), nullptr);
-  avl = gpr_avl_add(avl, box(592), box(796), nullptr);
-  avl = gpr_avl_add(avl, box(433), box(797), nullptr);
-  avl = gpr_avl_add(avl, box(973), box(798), nullptr);
-  avl = remove_int(avl, 901);
-  avl = remove_int(avl, 340);
-  avl = remove_int(avl, 709);
-  avl = gpr_avl_add(avl, box(224), box(802), nullptr);
-  avl = remove_int(avl, 120);
-  avl = remove_int(avl, 271);
-  avl = gpr_avl_add(avl, box(780), box(805), nullptr);
-  avl = gpr_avl_add(avl, box(867), box(806), nullptr);
-  avl = gpr_avl_add(avl, box(756), box(807), nullptr);
-  avl = gpr_avl_add(avl, box(583), box(808), nullptr);
-  avl = gpr_avl_add(avl, box(356), box(809), nullptr);
-  avl = gpr_avl_add(avl, box(58), box(810), nullptr);
-  avl = remove_int(avl, 219);
-  avl = gpr_avl_add(avl, box(301), box(812), nullptr);
-  avl = remove_int(avl, 643);
-  avl = remove_int(avl, 787);
-  avl = remove_int(avl, 583);
-  avl = remove_int(avl, 552);
-  avl = remove_int(avl, 308);
-  avl = remove_int(avl, 608);
-  avl = remove_int(avl, 363);
-  avl = remove_int(avl, 690);
-  avl = gpr_avl_add(avl, box(233), box(821), nullptr);
-  avl = gpr_avl_add(avl, box(479), box(822), nullptr);
-  avl = gpr_avl_add(avl, box(323), box(823), nullptr);
-  avl = gpr_avl_add(avl, box(802), box(824), nullptr);
-  avl = remove_int(avl, 682);
-  avl = remove_int(avl, 705);
-  avl = remove_int(avl, 487);
-  avl = gpr_avl_add(avl, box(530), box(828), nullptr);
-  avl = gpr_avl_add(avl, box(232), box(829), nullptr);
-  avl = remove_int(avl, 627);
-  avl = gpr_avl_add(avl, box(396), box(831), nullptr);
-  avl = gpr_avl_add(avl, box(61), box(832), nullptr);
-  avl = gpr_avl_add(avl, box(932), box(833), nullptr);
-  avl = gpr_avl_add(avl, box(108), box(834), nullptr);
-  avl = gpr_avl_add(avl, box(524), box(835), nullptr);
-  avl = remove_int(avl, 390);
-  avl = remove_int(avl, 307);
-  avl = gpr_avl_add(avl, box(722), box(838), nullptr);
-  avl = gpr_avl_add(avl, box(907), box(839), nullptr);
-  avl = remove_int(avl, 286);
-  avl = remove_int(avl, 337);
-  avl = remove_int(avl, 443);
-  avl = gpr_avl_add(avl, box(973), box(843), nullptr);
-  avl = remove_int(avl, 930);
-  avl = remove_int(avl, 242);
-  avl = gpr_avl_add(avl, box(997), box(846), nullptr);
-  avl = gpr_avl_add(avl, box(689), box(847), nullptr);
-  avl = remove_int(avl, 318);
-  avl = gpr_avl_add(avl, box(703), box(849), nullptr);
-  avl = gpr_avl_add(avl, box(868), box(850), nullptr);
-  avl = gpr_avl_add(avl, box(200), box(851), nullptr);
-  avl = gpr_avl_add(avl, box(960), box(852), nullptr);
-  avl = gpr_avl_add(avl, box(80), box(853), nullptr);
-  avl = remove_int(avl, 113);
-  avl = gpr_avl_add(avl, box(135), box(855), nullptr);
-  avl = remove_int(avl, 529);
-  avl = gpr_avl_add(avl, box(366), box(857), nullptr);
-  avl = remove_int(avl, 272);
-  avl = gpr_avl_add(avl, box(921), box(859), nullptr);
-  avl = remove_int(avl, 497);
-  avl = gpr_avl_add(avl, box(712), box(861), nullptr);
-  avl = remove_int(avl, 777);
-  avl = remove_int(avl, 505);
-  avl = remove_int(avl, 974);
-  avl = remove_int(avl, 497);
-  avl = gpr_avl_add(avl, box(388), box(866), nullptr);
-  avl = gpr_avl_add(avl, box(29), box(867), nullptr);
-  avl = gpr_avl_add(avl, box(180), box(868), nullptr);
-  avl = gpr_avl_add(avl, box(983), box(869), nullptr);
-  avl = gpr_avl_add(avl, box(72), box(870), nullptr);
-  avl = gpr_avl_add(avl, box(693), box(871), nullptr);
-  avl = gpr_avl_add(avl, box(567), box(872), nullptr);
-  avl = remove_int(avl, 549);
-  avl = remove_int(avl, 351);
-  avl = gpr_avl_add(avl, box(1019), box(875), nullptr);
-  avl = remove_int(avl, 585);
-  avl = remove_int(avl, 294);
-  avl = remove_int(avl, 61);
-  avl = gpr_avl_add(avl, box(409), box(879), nullptr);
-  avl = gpr_avl_add(avl, box(984), box(880), nullptr);
-  avl = gpr_avl_add(avl, box(830), box(881), nullptr);
-  avl = remove_int(avl, 579);
-  avl = gpr_avl_add(avl, box(672), box(883), nullptr);
-  avl = remove_int(avl, 968);
-
-  gpr_avl_unref(avl, nullptr);
-}
-
-static void test_badcase3(void) {
-  gpr_avl avl;
-
-  gpr_log(GPR_DEBUG, "test_badcase3");
-
-  avl = gpr_avl_create(&int_int_vtable);
-  avl = remove_int(avl, 624);
-  avl = gpr_avl_add(avl, box(59), box(2), nullptr);
-  avl = gpr_avl_add(avl, box(494), box(3), nullptr);
-  avl = gpr_avl_add(avl, box(226), box(4), nullptr);
-  avl = remove_int(avl, 524);
-  avl = gpr_avl_add(avl, box(540), box(6), nullptr);
-  avl = remove_int(avl, 1008);
-  avl = gpr_avl_add(avl, box(502), box(8), nullptr);
-  avl = remove_int(avl, 267);
-  avl = remove_int(avl, 764);
-  avl = remove_int(avl, 443);
-  avl = gpr_avl_add(avl, box(8), box(12), nullptr);
-  avl = remove_int(avl, 291);
-  avl = remove_int(avl, 796);
-  avl = remove_int(avl, 1002);
-  avl = gpr_avl_add(avl, box(778), box(16), nullptr);
-  avl = remove_int(avl, 621);
-  avl = remove_int(avl, 891);
-  avl = remove_int(avl, 880);
-  avl = gpr_avl_add(avl, box(197), box(20), nullptr);
-  avl = gpr_avl_add(avl, box(441), box(21), nullptr);
-  avl = gpr_avl_add(avl, box(719), box(22), nullptr);
-  avl = remove_int(avl, 109);
-  avl = gpr_avl_add(avl, box(458), box(24), nullptr);
-  avl = remove_int(avl, 86);
-  avl = gpr_avl_add(avl, box(897), box(26), nullptr);
-  avl = gpr_avl_add(avl, box(997), box(27), nullptr);
-  avl = remove_int(avl, 235);
-  avl = remove_int(avl, 425);
-  avl = remove_int(avl, 186);
-  avl = gpr_avl_add(avl, box(887), box(31), nullptr);
-  avl = gpr_avl_add(avl, box(1005), box(32), nullptr);
-  avl = gpr_avl_add(avl, box(778), box(33), nullptr);
-  avl = gpr_avl_add(avl, box(575), box(34), nullptr);
-  avl = remove_int(avl, 966);
-  avl = remove_int(avl, 1015);
-  avl = gpr_avl_add(avl, box(486), box(37), nullptr);
-  avl = gpr_avl_add(avl, box(809), box(38), nullptr);
-  avl = gpr_avl_add(avl, box(907), box(39), nullptr);
-  avl = gpr_avl_add(avl, box(971), box(40), nullptr);
-  avl = remove_int(avl, 441);
-  avl = remove_int(avl, 498);
-  avl = gpr_avl_add(avl, box(727), box(43), nullptr);
-  avl = remove_int(avl, 679);
-  avl = remove_int(avl, 740);
-  avl = remove_int(avl, 532);
-  avl = gpr_avl_add(avl, box(805), box(47), nullptr);
-  avl = remove_int(avl, 64);
-  avl = gpr_avl_add(avl, box(362), box(49), nullptr);
-  avl = gpr_avl_add(avl, box(170), box(50), nullptr);
-  avl = gpr_avl_add(avl, box(389), box(51), nullptr);
-  avl = gpr_avl_add(avl, box(689), box(52), nullptr);
-  avl = remove_int(avl, 871);
-  avl = gpr_avl_add(avl, box(447), box(54), nullptr);
-  avl = remove_int(avl, 718);
-  avl = gpr_avl_add(avl, box(724), box(56), nullptr);
-  avl = remove_int(avl, 215);
-  avl = gpr_avl_add(avl, box(550), box(58), nullptr);
-  avl = remove_int(avl, 932);
-  avl = gpr_avl_add(avl, box(47), box(60), nullptr);
-  avl = remove_int(avl, 46);
-  avl = remove_int(avl, 229);
-  avl = gpr_avl_add(avl, box(68), box(63), nullptr);
-  avl = gpr_avl_add(avl, box(387), box(64), nullptr);
-  avl = remove_int(avl, 933);
-  avl = remove_int(avl, 736);
-  avl = remove_int(avl, 719);
-  avl = gpr_avl_add(avl, box(150), box(68), nullptr);
-  avl = remove_int(avl, 875);
-  avl = remove_int(avl, 298);
-  avl = gpr_avl_add(avl, box(991), box(71), nullptr);
-  avl = remove_int(avl, 705);
-  avl = gpr_avl_add(avl, box(197), box(73), nullptr);
-  avl = gpr_avl_add(avl, box(101), box(74), nullptr);
-  avl = remove_int(avl, 436);
-  avl = gpr_avl_add(avl, box(755), box(76), nullptr);
-  avl = gpr_avl_add(avl, box(727), box(77), nullptr);
-  avl = remove_int(avl, 309);
-  avl = remove_int(avl, 253);
-  avl = gpr_avl_add(avl, box(203), box(80), nullptr);
-  avl = remove_int(avl, 231);
-  avl = gpr_avl_add(avl, box(461), box(82), nullptr);
-  avl = remove_int(avl, 316);
-  avl = remove_int(avl, 493);
-  avl = gpr_avl_add(avl, box(184), box(85), nullptr);
-  avl = remove_int(avl, 737);
-  avl = gpr_avl_add(avl, box(790), box(87), nullptr);
-  avl = gpr_avl_add(avl, box(335), box(88), nullptr);
-  avl = remove_int(avl, 649);
-  avl = gpr_avl_add(avl, box(69), box(90), nullptr);
-  avl = remove_int(avl, 585);
-  avl = remove_int(avl, 543);
-  avl = gpr_avl_add(avl, box(784), box(93), nullptr);
-  avl = gpr_avl_add(avl, box(60), box(94), nullptr);
-  avl = gpr_avl_add(avl, box(525), box(95), nullptr);
-  avl = gpr_avl_add(avl, box(177), box(96), nullptr);
-  avl = gpr_avl_add(avl, box(178), box(97), nullptr);
-  avl = gpr_avl_add(avl, box(683), box(98), nullptr);
-  avl = gpr_avl_add(avl, box(226), box(99), nullptr);
-  avl = gpr_avl_add(avl, box(662), box(100), nullptr);
-  avl = remove_int(avl, 944);
-  avl = gpr_avl_add(avl, box(562), box(102), nullptr);
-  avl = gpr_avl_add(avl, box(793), box(103), nullptr);
-  avl = remove_int(avl, 673);
-  avl = gpr_avl_add(avl, box(310), box(105), nullptr);
-  avl = remove_int(avl, 479);
-  avl = remove_int(avl, 543);
-  avl = remove_int(avl, 159);
-  avl = remove_int(avl, 850);
-  avl = gpr_avl_add(avl, box(318), box(110), nullptr);
-  avl = gpr_avl_add(avl, box(483), box(111), nullptr);
-  avl = gpr_avl_add(avl, box(84), box(112), nullptr);
-  avl = remove_int(avl, 109);
-  avl = gpr_avl_add(avl, box(132), box(114), nullptr);
-  avl = gpr_avl_add(avl, box(920), box(115), nullptr);
-  avl = remove_int(avl, 746);
-  avl = gpr_avl_add(avl, box(145), box(117), nullptr);
-  avl = gpr_avl_add(avl, box(526), box(118), nullptr);
-  avl = remove_int(avl, 158);
-  avl = gpr_avl_add(avl, box(332), box(120), nullptr);
-  avl = gpr_avl_add(avl, box(918), box(121), nullptr);
-  avl = remove_int(avl, 339);
-  avl = gpr_avl_add(avl, box(809), box(123), nullptr);
-  avl = gpr_avl_add(avl, box(742), box(124), nullptr);
-  avl = gpr_avl_add(avl, box(718), box(125), nullptr);
-  avl = remove_int(avl, 988);
-  avl = remove_int(avl, 531);
-  avl = remove_int(avl, 840);
-  avl = gpr_avl_add(avl, box(816), box(129), nullptr);
-  avl = gpr_avl_add(avl, box(976), box(130), nullptr);
-  avl = remove_int(avl, 743);
-  avl = remove_int(avl, 528);
-  avl = remove_int(avl, 982);
-  avl = gpr_avl_add(avl, box(803), box(134), nullptr);
-  avl = gpr_avl_add(avl, box(205), box(135), nullptr);
-  avl = gpr_avl_add(avl, box(584), box(136), nullptr);
-  avl = remove_int(avl, 923);
-  avl = remove_int(avl, 538);
-  avl = remove_int(avl, 398);
-  avl = remove_int(avl, 320);
-  avl = remove_int(avl, 292);
-  avl = gpr_avl_add(avl, box(270), box(142), nullptr);
-  avl = gpr_avl_add(avl, box(333), box(143), nullptr);
-  avl = remove_int(avl, 439);
-  avl = gpr_avl_add(avl, box(35), box(145), nullptr);
-  avl = gpr_avl_add(avl, box(837), box(146), nullptr);
-  avl = remove_int(avl, 65);
-  avl = remove_int(avl, 642);
-  avl = remove_int(avl, 371);
-  avl = remove_int(avl, 140);
-  avl = remove_int(avl, 533);
-  avl = remove_int(avl, 676);
-  avl = gpr_avl_add(avl, box(624), box(153), nullptr);
-  avl = gpr_avl_add(avl, box(116), box(154), nullptr);
-  avl = gpr_avl_add(avl, box(446), box(155), nullptr);
-  avl = remove_int(avl, 91);
-  avl = remove_int(avl, 721);
-  avl = remove_int(avl, 537);
-  avl = gpr_avl_add(avl, box(448), box(159), nullptr);
-  avl = remove_int(avl, 155);
-  avl = remove_int(avl, 344);
-  avl = remove_int(avl, 237);
-  avl = gpr_avl_add(avl, box(309), box(163), nullptr);
-  avl = gpr_avl_add(avl, box(434), box(164), nullptr);
-  avl = gpr_avl_add(avl, box(277), box(165), nullptr);
-  avl = remove_int(avl, 233);
-  avl = gpr_avl_add(avl, box(275), box(167), nullptr);
-  avl = gpr_avl_add(avl, box(218), box(168), nullptr);
-  avl = gpr_avl_add(avl, box(76), box(169), nullptr);
-  avl = gpr_avl_add(avl, box(898), box(170), nullptr);
-  avl = remove_int(avl, 771);
-  avl = gpr_avl_add(avl, box(237), box(172), nullptr);
-  avl = remove_int(avl, 327);
-  avl = gpr_avl_add(avl, box(499), box(174), nullptr);
-  avl = remove_int(avl, 727);
-  avl = remove_int(avl, 234);
-  avl = remove_int(avl, 623);
-  avl = remove_int(avl, 458);
-  avl = remove_int(avl, 326);
-  avl = remove_int(avl, 589);
-  avl = gpr_avl_add(avl, box(442), box(181), nullptr);
-  avl = remove_int(avl, 389);
-  avl = gpr_avl_add(avl, box(708), box(183), nullptr);
-  avl = gpr_avl_add(avl, box(594), box(184), nullptr);
-  avl = gpr_avl_add(avl, box(942), box(185), nullptr);
-  avl = gpr_avl_add(avl, box(282), box(186), nullptr);
-  avl = remove_int(avl, 434);
-  avl = remove_int(avl, 134);
-  avl = remove_int(avl, 270);
-  avl = remove_int(avl, 512);
-  avl = remove_int(avl, 265);
-  avl = remove_int(avl, 21);
-  avl = remove_int(avl, 193);
-  avl = remove_int(avl, 797);
-  avl = remove_int(avl, 347);
-  avl = gpr_avl_add(avl, box(99), box(196), nullptr);
-  avl = gpr_avl_add(avl, box(161), box(197), nullptr);
-  avl = remove_int(avl, 484);
-  avl = gpr_avl_add(avl, box(72), box(199), nullptr);
-  avl = remove_int(avl, 629);
-  avl = gpr_avl_add(avl, box(522), box(201), nullptr);
-  avl = remove_int(avl, 679);
-  avl = gpr_avl_add(avl, box(407), box(203), nullptr);
-  avl = remove_int(avl, 693);
-  avl = gpr_avl_add(avl, box(424), box(205), nullptr);
-  avl = gpr_avl_add(avl, box(651), box(206), nullptr);
-  avl = gpr_avl_add(avl, box(927), box(207), nullptr);
-  avl = remove_int(avl, 553);
-  avl = gpr_avl_add(avl, box(128), box(209), nullptr);
-  avl = gpr_avl_add(avl, box(616), box(210), nullptr);
-  avl = gpr_avl_add(avl, box(690), box(211), nullptr);
-  avl = remove_int(avl, 241);
-  avl = remove_int(avl, 179);
-  avl = gpr_avl_add(avl, box(697), box(214), nullptr);
-  avl = remove_int(avl, 779);
-  avl = gpr_avl_add(avl, box(241), box(216), nullptr);
-  avl = remove_int(avl, 190);
-  avl = remove_int(avl, 210);
-  avl = gpr_avl_add(avl, box(711), box(219), nullptr);
-  avl = remove_int(avl, 251);
-  avl = remove_int(avl, 61);
-  avl = gpr_avl_add(avl, box(800), box(222), nullptr);
-  avl = remove_int(avl, 551);
-  avl = gpr_avl_add(avl, box(61), box(224), nullptr);
-  avl = gpr_avl_add(avl, box(656), box(225), nullptr);
-  avl = remove_int(avl, 130);
-  avl = remove_int(avl, 368);
-  avl = remove_int(avl, 150);
-  avl = remove_int(avl, 73);
-  avl = gpr_avl_add(avl, box(799), box(230), nullptr);
-  avl = gpr_avl_add(avl, box(125), box(231), nullptr);
-  avl = remove_int(avl, 107);
-  avl = gpr_avl_add(avl, box(938), box(233), nullptr);
-  avl = gpr_avl_add(avl, box(914), box(234), nullptr);
-  avl = gpr_avl_add(avl, box(197), box(235), nullptr);
-  avl = remove_int(avl, 736);
-  avl = gpr_avl_add(avl, box(20), box(237), nullptr);
-  avl = remove_int(avl, 224);
-  avl = remove_int(avl, 841);
-  avl = gpr_avl_add(avl, box(226), box(240), nullptr);
-  avl = remove_int(avl, 963);
-  avl = remove_int(avl, 796);
-  avl = remove_int(avl, 728);
-  avl = gpr_avl_add(avl, box(855), box(244), nullptr);
-  avl = gpr_avl_add(avl, box(769), box(245), nullptr);
-  avl = gpr_avl_add(avl, box(631), box(246), nullptr);
-  avl = remove_int(avl, 648);
-  avl = gpr_avl_add(avl, box(187), box(248), nullptr);
-  avl = gpr_avl_add(avl, box(31), box(249), nullptr);
-  avl = remove_int(avl, 163);
-  avl = gpr_avl_add(avl, box(218), box(251), nullptr);
-  avl = gpr_avl_add(avl, box(488), box(252), nullptr);
-  avl = gpr_avl_add(avl, box(387), box(253), nullptr);
-  avl = gpr_avl_add(avl, box(809), box(254), nullptr);
-  avl = gpr_avl_add(avl, box(997), box(255), nullptr);
-  avl = remove_int(avl, 678);
-  avl = gpr_avl_add(avl, box(368), box(257), nullptr);
-  avl = gpr_avl_add(avl, box(220), box(258), nullptr);
-  avl = gpr_avl_add(avl, box(373), box(259), nullptr);
-  avl = remove_int(avl, 874);
-  avl = remove_int(avl, 682);
-  avl = remove_int(avl, 1014);
-  avl = remove_int(avl, 195);
-  avl = gpr_avl_add(avl, box(868), box(264), nullptr);
-  avl = remove_int(avl, 254);
-  avl = remove_int(avl, 456);
-  avl = gpr_avl_add(avl, box(906), box(267), nullptr);
-  avl = remove_int(avl, 711);
-  avl = gpr_avl_add(avl, box(632), box(269), nullptr);
-  avl = remove_int(avl, 474);
-  avl = gpr_avl_add(avl, box(508), box(271), nullptr);
-  avl = gpr_avl_add(avl, box(518), box(272), nullptr);
-  avl = remove_int(avl, 579);
-  avl = remove_int(avl, 948);
-  avl = gpr_avl_add(avl, box(789), box(275), nullptr);
-  avl = gpr_avl_add(avl, box(48), box(276), nullptr);
-  avl = gpr_avl_add(avl, box(256), box(277), nullptr);
-  avl = gpr_avl_add(avl, box(754), box(278), nullptr);
-  avl = remove_int(avl, 215);
-  avl = gpr_avl_add(avl, box(679), box(280), nullptr);
-  avl = gpr_avl_add(avl, box(606), box(281), nullptr);
-  avl = remove_int(avl, 941);
-  avl = remove_int(avl, 31);
-  avl = gpr_avl_add(avl, box(758), box(284), nullptr);
-  avl = remove_int(avl, 101);
-  avl = gpr_avl_add(avl, box(244), box(286), nullptr);
-  avl = gpr_avl_add(avl, box(337), box(287), nullptr);
-  avl = gpr_avl_add(avl, box(461), box(288), nullptr);
-  avl = remove_int(avl, 476);
-  avl = gpr_avl_add(avl, box(845), box(290), nullptr);
-  avl = remove_int(avl, 160);
-  avl = gpr_avl_add(avl, box(690), box(292), nullptr);
-  avl = remove_int(avl, 931);
-  avl = gpr_avl_add(avl, box(869), box(294), nullptr);
-  avl = gpr_avl_add(avl, box(1019), box(295), nullptr);
-  avl = remove_int(avl, 591);
-  avl = remove_int(avl, 635);
-  avl = remove_int(avl, 67);
-  avl = gpr_avl_add(avl, box(113), box(299), nullptr);
-  avl = remove_int(avl, 305);
-  avl = gpr_avl_add(avl, box(10), box(301), nullptr);
-  avl = remove_int(avl, 823);
-  avl = remove_int(avl, 288);
-  avl = remove_int(avl, 239);
-  avl = gpr_avl_add(avl, box(646), box(305), nullptr);
-  avl = gpr_avl_add(avl, box(1006), box(306), nullptr);
-  avl = gpr_avl_add(avl, box(954), box(307), nullptr);
-  avl = gpr_avl_add(avl, box(199), box(308), nullptr);
-  avl = gpr_avl_add(avl, box(69), box(309), nullptr);
-  avl = gpr_avl_add(avl, box(984), box(310), nullptr);
-  avl = remove_int(avl, 568);
-  avl = remove_int(avl, 666);
-  avl = remove_int(avl, 37);
-  avl = gpr_avl_add(avl, box(845), box(314), nullptr);
-  avl = remove_int(avl, 535);
-  avl = remove_int(avl, 365);
-  avl = remove_int(avl, 676);
-  avl = remove_int(avl, 892);
-  avl = remove_int(avl, 425);
-  avl = remove_int(avl, 704);
-  avl = remove_int(avl, 168);
-  avl = gpr_avl_add(avl, box(853), box(322), nullptr);
-  avl = gpr_avl_add(avl, box(335), box(323), nullptr);
-  avl = gpr_avl_add(avl, box(961), box(324), nullptr);
-  avl = gpr_avl_add(avl, box(73), box(325), nullptr);
-  avl = remove_int(avl, 469);
-  avl = gpr_avl_add(avl, box(449), box(327), nullptr);
-  avl = remove_int(avl, 821);
-  avl = gpr_avl_add(avl, box(845), box(329), nullptr);
-  avl = remove_int(avl, 637);
-  avl = gpr_avl_add(avl, box(769), box(331), nullptr);
-  avl = gpr_avl_add(avl, box(901), box(332), nullptr);
-  avl = remove_int(avl, 142);
-  avl = remove_int(avl, 361);
-  avl = remove_int(avl, 876);
-  avl = gpr_avl_add(avl, box(614), box(336), nullptr);
-  avl = gpr_avl_add(avl, box(729), box(337), nullptr);
-  avl = remove_int(avl, 120);
-  avl = remove_int(avl, 473);
-  avl = remove_int(avl, 445);
-  avl = gpr_avl_add(avl, box(978), box(341), nullptr);
-  avl = gpr_avl_add(avl, box(164), box(342), nullptr);
-  avl = gpr_avl_add(avl, box(1), box(343), nullptr);
-  avl = remove_int(avl, 890);
-  avl = gpr_avl_add(avl, box(605), box(345), nullptr);
-  avl = gpr_avl_add(avl, box(178), box(346), nullptr);
-  avl = gpr_avl_add(avl, box(481), box(347), nullptr);
-  avl = gpr_avl_add(avl, box(772), box(348), nullptr);
-  avl = remove_int(avl, 824);
-  avl = remove_int(avl, 167);
-  avl = remove_int(avl, 151);
-  avl = gpr_avl_add(avl, box(698), box(352), nullptr);
-  avl = gpr_avl_add(avl, box(202), box(353), nullptr);
-  avl = gpr_avl_add(avl, box(921), box(354), nullptr);
-  avl = gpr_avl_add(avl, box(875), box(355), nullptr);
-  avl = remove_int(avl, 197);
-  avl = remove_int(avl, 232);
-  avl = gpr_avl_add(avl, box(209), box(358), nullptr);
-  avl = remove_int(avl, 324);
-  avl = remove_int(avl, 56);
-  avl = remove_int(avl, 579);
-  avl = remove_int(avl, 255);
-  avl = remove_int(avl, 290);
-  avl = gpr_avl_add(avl, box(661), box(364), nullptr);
-  avl = gpr_avl_add(avl, box(113), box(365), nullptr);
-  avl = remove_int(avl, 767);
-  avl = gpr_avl_add(avl, box(586), box(367), nullptr);
-  avl = gpr_avl_add(avl, box(121), box(368), nullptr);
-  avl = remove_int(avl, 235);
-  avl = remove_int(avl, 439);
-  avl = remove_int(avl, 360);
-  avl = gpr_avl_add(avl, box(916), box(372), nullptr);
-  avl = remove_int(avl, 999);
-  avl = gpr_avl_add(avl, box(825), box(374), nullptr);
-  avl = gpr_avl_add(avl, box(177), box(375), nullptr);
-  avl = remove_int(avl, 204);
-  avl = remove_int(avl, 92);
-  avl = gpr_avl_add(avl, box(794), box(378), nullptr);
-  avl = gpr_avl_add(avl, box(463), box(379), nullptr);
-  avl = gpr_avl_add(avl, box(472), box(380), nullptr);
-  avl = remove_int(avl, 235);
-  avl = gpr_avl_add(avl, box(840), box(382), nullptr);
-  avl = remove_int(avl, 657);
-  avl = gpr_avl_add(avl, box(586), box(384), nullptr);
-  avl = gpr_avl_add(avl, box(979), box(385), nullptr);
-  avl = remove_int(avl, 979);
-  avl = gpr_avl_add(avl, box(639), box(387), nullptr);
-  avl = remove_int(avl, 907);
-  avl = remove_int(avl, 973);
-  avl = gpr_avl_add(avl, box(913), box(390), nullptr);
-  avl = gpr_avl_add(avl, box(566), box(391), nullptr);
-  avl = gpr_avl_add(avl, box(883), box(392), nullptr);
-  avl = gpr_avl_add(avl, box(552), box(393), nullptr);
-  avl = gpr_avl_add(avl, box(16), box(394), nullptr);
-  avl = remove_int(avl, 60);
-  avl = gpr_avl_add(avl, box(567), box(396), nullptr);
-  avl = gpr_avl_add(avl, box(705), box(397), nullptr);
-  avl = gpr_avl_add(avl, box(94), box(398), nullptr);
-  avl = remove_int(avl, 321);
-  avl = gpr_avl_add(avl, box(207), box(400), nullptr);
-  avl = gpr_avl_add(avl, box(682), box(401), nullptr);
-  avl = gpr_avl_add(avl, box(592), box(402), nullptr);
-  avl = gpr_avl_add(avl, box(10), box(403), nullptr);
-  avl = remove_int(avl, 911);
-  avl = remove_int(avl, 161);
-  avl = gpr_avl_add(avl, box(86), box(406), nullptr);
-  avl = remove_int(avl, 893);
-  avl = remove_int(avl, 362);
-  avl = gpr_avl_add(avl, box(599), box(409), nullptr);
-  avl = remove_int(avl, 413);
-  avl = gpr_avl_add(avl, box(867), box(411), nullptr);
-  avl = remove_int(avl, 955);
-  avl = gpr_avl_add(avl, box(341), box(413), nullptr);
-  avl = gpr_avl_add(avl, box(887), box(414), nullptr);
-  avl = remove_int(avl, 706);
-  avl = gpr_avl_add(avl, box(939), box(416), nullptr);
-  avl = remove_int(avl, 233);
-  avl = remove_int(avl, 662);
-  avl = remove_int(avl, 984);
-  avl = remove_int(avl, 203);
-  avl = gpr_avl_add(avl, box(326), box(421), nullptr);
-  avl = remove_int(avl, 848);
-  avl = gpr_avl_add(avl, box(235), box(423), nullptr);
-  avl = remove_int(avl, 617);
-  avl = gpr_avl_add(avl, box(565), box(425), nullptr);
-  avl = remove_int(avl, 469);
-  avl = gpr_avl_add(avl, box(988), box(427), nullptr);
-  avl = remove_int(avl, 957);
-  avl = gpr_avl_add(avl, box(426), box(429), nullptr);
-  avl = remove_int(avl, 967);
-  avl = gpr_avl_add(avl, box(890), box(431), nullptr);
-  avl = gpr_avl_add(avl, box(473), box(432), nullptr);
-  avl = remove_int(avl, 367);
-  avl = remove_int(avl, 344);
-  avl = remove_int(avl, 660);
-  avl = remove_int(avl, 448);
-  avl = remove_int(avl, 837);
-  avl = remove_int(avl, 158);
-  avl = gpr_avl_add(avl, box(459), box(439), nullptr);
-  avl = remove_int(avl, 882);
-  avl = remove_int(avl, 782);
-  avl = gpr_avl_add(avl, box(408), box(442), nullptr);
-  avl = gpr_avl_add(avl, box(728), box(443), nullptr);
-  avl = remove_int(avl, 27);
-  avl = gpr_avl_add(avl, box(137), box(445), nullptr);
-  avl = gpr_avl_add(avl, box(239), box(446), nullptr);
-  avl = remove_int(avl, 854);
-  avl = gpr_avl_add(avl, box(104), box(448), nullptr);
-  avl = gpr_avl_add(avl, box(823), box(449), nullptr);
-  avl = gpr_avl_add(avl, box(524), box(450), nullptr);
-  avl = gpr_avl_add(avl, box(995), box(451), nullptr);
-  avl = remove_int(avl, 422);
-  avl = remove_int(avl, 220);
-  avl = gpr_avl_add(avl, box(856), box(454), nullptr);
-  avl = remove_int(avl, 332);
-  avl = gpr_avl_add(avl, box(679), box(456), nullptr);
-  avl = remove_int(avl, 18);
-  avl = gpr_avl_add(avl, box(837), box(458), nullptr);
-  avl = remove_int(avl, 405);
-  avl = remove_int(avl, 877);
-  avl = remove_int(avl, 835);
-  avl = gpr_avl_add(avl, box(547), box(462), nullptr);
-  avl = remove_int(avl, 805);
-  avl = remove_int(avl, 862);
-  avl = gpr_avl_add(avl, box(75), box(465), nullptr);
-  avl = remove_int(avl, 41);
-  avl = gpr_avl_add(avl, box(310), box(467), nullptr);
-  avl = remove_int(avl, 855);
-  avl = gpr_avl_add(avl, box(20), box(469), nullptr);
-  avl = remove_int(avl, 186);
-  avl = remove_int(avl, 378);
-  avl = remove_int(avl, 442);
-  avl = remove_int(avl, 930);
-  avl = gpr_avl_add(avl, box(118), box(474), nullptr);
-  avl = gpr_avl_add(avl, box(96), box(475), nullptr);
-  avl = remove_int(avl, 854);
-  avl = gpr_avl_add(avl, box(65), box(477), nullptr);
-  avl = gpr_avl_add(avl, box(573), box(478), nullptr);
-  avl = gpr_avl_add(avl, box(4), box(479), nullptr);
-  avl = gpr_avl_add(avl, box(451), box(480), nullptr);
-  avl = gpr_avl_add(avl, box(774), box(481), nullptr);
-  avl = gpr_avl_add(avl, box(126), box(482), nullptr);
-  avl = remove_int(avl, 956);
-  avl = remove_int(avl, 591);
-  avl = remove_int(avl, 644);
-  avl = gpr_avl_add(avl, box(304), box(486), nullptr);
-  avl = remove_int(avl, 620);
-  avl = remove_int(avl, 394);
-  avl = gpr_avl_add(avl, box(1002), box(489), nullptr);
-  avl = gpr_avl_add(avl, box(837), box(490), nullptr);
-  avl = remove_int(avl, 485);
-  avl = gpr_avl_add(avl, box(1005), box(492), nullptr);
-  avl = remove_int(avl, 21);
-  avl = gpr_avl_add(avl, box(396), box(494), nullptr);
-  avl = remove_int(avl, 966);
-  avl = gpr_avl_add(avl, box(105), box(496), nullptr);
-  avl = gpr_avl_add(avl, box(316), box(497), nullptr);
-  avl = remove_int(avl, 776);
-  avl = gpr_avl_add(avl, box(188), box(499), nullptr);
-  avl = remove_int(avl, 200);
-  avl = gpr_avl_add(avl, box(98), box(501), nullptr);
-  avl = gpr_avl_add(avl, box(831), box(502), nullptr);
-  avl = gpr_avl_add(avl, box(227), box(503), nullptr);
-  avl = gpr_avl_add(avl, box(220), box(504), nullptr);
-  avl = remove_int(avl, 715);
-  avl = remove_int(avl, 279);
-  avl = gpr_avl_add(avl, box(701), box(507), nullptr);
-  avl = gpr_avl_add(avl, box(726), box(508), nullptr);
-  avl = gpr_avl_add(avl, box(815), box(509), nullptr);
-  avl = gpr_avl_add(avl, box(749), box(510), nullptr);
-  avl = remove_int(avl, 946);
-  avl = remove_int(avl, 449);
-  avl = remove_int(avl, 62);
-  avl = remove_int(avl, 487);
-  avl = gpr_avl_add(avl, box(545), box(515), nullptr);
-  avl = remove_int(avl, 59);
-  avl = gpr_avl_add(avl, box(168), box(517), nullptr);
-  avl = remove_int(avl, 337);
-  avl = gpr_avl_add(avl, box(69), box(519), nullptr);
-  avl = remove_int(avl, 600);
-  avl = gpr_avl_add(avl, box(591), box(521), nullptr);
-  avl = gpr_avl_add(avl, box(960), box(522), nullptr);
-  avl = gpr_avl_add(avl, box(116), box(523), nullptr);
-  avl = remove_int(avl, 991);
-  avl = gpr_avl_add(avl, box(760), box(525), nullptr);
-  avl = gpr_avl_add(avl, box(664), box(526), nullptr);
-  avl = gpr_avl_add(avl, box(547), box(527), nullptr);
-  avl = remove_int(avl, 922);
-  avl = gpr_avl_add(avl, box(290), box(529), nullptr);
-  avl = gpr_avl_add(avl, box(859), box(530), nullptr);
-  avl = gpr_avl_add(avl, box(49), box(531), nullptr);
-  avl = remove_int(avl, 455);
-  avl = remove_int(avl, 786);
-  avl = gpr_avl_add(avl, box(613), box(534), nullptr);
-  avl = gpr_avl_add(avl, box(326), box(535), nullptr);
-  avl = remove_int(avl, 615);
-  avl = gpr_avl_add(avl, box(45), box(537), nullptr);
-  avl = gpr_avl_add(avl, box(162), box(538), nullptr);
-  avl = gpr_avl_add(avl, box(189), box(539), nullptr);
-  avl = remove_int(avl, 68);
-  avl = remove_int(avl, 846);
-  avl = gpr_avl_add(avl, box(608), box(542), nullptr);
-  avl = remove_int(avl, 821);
-  avl = gpr_avl_add(avl, box(978), box(544), nullptr);
-  avl = gpr_avl_add(avl, box(892), box(545), nullptr);
-  avl = remove_int(avl, 924);
-  avl = gpr_avl_add(avl, box(708), box(547), nullptr);
-  avl = remove_int(avl, 135);
-  avl = remove_int(avl, 124);
-  avl = gpr_avl_add(avl, box(301), box(550), nullptr);
-  avl = gpr_avl_add(avl, box(939), box(551), nullptr);
-  avl = gpr_avl_add(avl, box(344), box(552), nullptr);
-  avl = remove_int(avl, 443);
-  avl = remove_int(avl, 122);
-  avl = gpr_avl_add(avl, box(636), box(555), nullptr);
-  avl = remove_int(avl, 558);
-  avl = gpr_avl_add(avl, box(923), box(557), nullptr);
-  avl = remove_int(avl, 827);
-  avl = gpr_avl_add(avl, box(649), box(559), nullptr);
-  avl = gpr_avl_add(avl, box(808), box(560), nullptr);
-  avl = remove_int(avl, 570);
-  avl = remove_int(avl, 434);
-  avl = gpr_avl_add(avl, box(40), box(563), nullptr);
-  avl = gpr_avl_add(avl, box(725), box(564), nullptr);
-  avl = remove_int(avl, 295);
-  avl = remove_int(avl, 615);
-  avl = remove_int(avl, 919);
-  avl = remove_int(avl, 170);
-  avl = remove_int(avl, 442);
-  avl = remove_int(avl, 971);
-  avl = gpr_avl_add(avl, box(483), box(571), nullptr);
-  avl = gpr_avl_add(avl, box(512), box(572), nullptr);
-  avl = remove_int(avl, 648);
-  avl = remove_int(avl, 78);
-  avl = remove_int(avl, 72);
-  avl = remove_int(avl, 790);
-  avl = remove_int(avl, 571);
-  avl = gpr_avl_add(avl, box(898), box(578), nullptr);
-  avl = remove_int(avl, 770);
-  avl = remove_int(avl, 776);
-  avl = gpr_avl_add(avl, box(602), box(581), nullptr);
-  avl = remove_int(avl, 251);
-  avl = gpr_avl_add(avl, box(303), box(583), nullptr);
-  avl = remove_int(avl, 837);
-  avl = gpr_avl_add(avl, box(714), box(585), nullptr);
-  avl = remove_int(avl, 800);
-  avl = gpr_avl_add(avl, box(266), box(587), nullptr);
-  avl = gpr_avl_add(avl, box(555), box(588), nullptr);
-  avl = remove_int(avl, 604);
-  avl = remove_int(avl, 163);
-  avl = remove_int(avl, 497);
-  avl = gpr_avl_add(avl, box(296), box(592), nullptr);
-  avl = remove_int(avl, 129);
-  avl = gpr_avl_add(avl, box(656), box(594), nullptr);
-  avl = remove_int(avl, 769);
-  avl = remove_int(avl, 941);
-  avl = gpr_avl_add(avl, box(775), box(597), nullptr);
-  avl = gpr_avl_add(avl, box(846), box(598), nullptr);
-  avl = remove_int(avl, 591);
-  avl = remove_int(avl, 801);
-  avl = remove_int(avl, 419);
-  avl = remove_int(avl, 455);
-  avl = gpr_avl_add(avl, box(866), box(603), nullptr);
-  avl = gpr_avl_add(avl, box(575), box(604), nullptr);
-  avl = gpr_avl_add(avl, box(620), box(605), nullptr);
-  avl = remove_int(avl, 100);
-  avl = remove_int(avl, 667);
-  avl = gpr_avl_add(avl, box(138), box(608), nullptr);
-  avl = gpr_avl_add(avl, box(566), box(609), nullptr);
-  avl = gpr_avl_add(avl, box(673), box(610), nullptr);
-  avl = gpr_avl_add(avl, box(178), box(611), nullptr);
-  avl = remove_int(avl, 659);
-  avl = gpr_avl_add(avl, box(759), box(613), nullptr);
-  avl = gpr_avl_add(avl, box(1008), box(614), nullptr);
-  avl = remove_int(avl, 116);
-  avl = gpr_avl_add(avl, box(608), box(616), nullptr);
-  avl = gpr_avl_add(avl, box(339), box(617), nullptr);
-  avl = gpr_avl_add(avl, box(197), box(618), nullptr);
-  avl = remove_int(avl, 25);
-  avl = remove_int(avl, 628);
-  avl = gpr_avl_add(avl, box(487), box(621), nullptr);
-  avl = remove_int(avl, 739);
-  avl = remove_int(avl, 100);
-  avl = remove_int(avl, 928);
-  avl = gpr_avl_add(avl, box(647), box(625), nullptr);
-  avl = remove_int(avl, 978);
-  avl = remove_int(avl, 143);
-  avl = remove_int(avl, 755);
-  avl = gpr_avl_add(avl, box(71), box(629), nullptr);
-  avl = remove_int(avl, 205);
-  avl = gpr_avl_add(avl, box(501), box(631), nullptr);
-  avl = remove_int(avl, 723);
-  avl = remove_int(avl, 852);
-  avl = remove_int(avl, 1021);
-  avl = remove_int(avl, 670);
-  avl = remove_int(avl, 500);
-  avl = gpr_avl_add(avl, box(330), box(637), nullptr);
-  avl = remove_int(avl, 264);
-  avl = gpr_avl_add(avl, box(69), box(639), nullptr);
-  avl = remove_int(avl, 73);
-  avl = gpr_avl_add(avl, box(745), box(641), nullptr);
-  avl = remove_int(avl, 518);
-  avl = remove_int(avl, 641);
-  avl = remove_int(avl, 768);
-  avl = gpr_avl_add(avl, box(988), box(645), nullptr);
-  avl = gpr_avl_add(avl, box(899), box(646), nullptr);
-  avl = remove_int(avl, 763);
-  avl = remove_int(avl, 281);
-  avl = remove_int(avl, 496);
-  avl = gpr_avl_add(avl, box(445), box(650), nullptr);
-  avl = remove_int(avl, 905);
-  avl = gpr_avl_add(avl, box(275), box(652), nullptr);
-  avl = gpr_avl_add(avl, box(137), box(653), nullptr);
-  avl = remove_int(avl, 642);
-  avl = gpr_avl_add(avl, box(708), box(655), nullptr);
-  avl = remove_int(avl, 922);
-  avl = gpr_avl_add(avl, box(743), box(657), nullptr);
-  avl = remove_int(avl, 295);
-  avl = remove_int(avl, 665);
-  avl = remove_int(avl, 48);
-  avl = gpr_avl_add(avl, box(1012), box(661), nullptr);
-  avl = remove_int(avl, 71);
-  avl = remove_int(avl, 523);
-  avl = gpr_avl_add(avl, box(319), box(664), nullptr);
-  avl = remove_int(avl, 632);
-  avl = gpr_avl_add(avl, box(137), box(666), nullptr);
-  avl = gpr_avl_add(avl, box(686), box(667), nullptr);
-  avl = gpr_avl_add(avl, box(724), box(668), nullptr);
-  avl = gpr_avl_add(avl, box(952), box(669), nullptr);
-  avl = gpr_avl_add(avl, box(5), box(670), nullptr);
-  avl = remove_int(avl, 35);
-  avl = gpr_avl_add(avl, box(43), box(672), nullptr);
-  avl = gpr_avl_add(avl, box(320), box(673), nullptr);
-  avl = gpr_avl_add(avl, box(115), box(674), nullptr);
-  avl = remove_int(avl, 377);
-  avl = remove_int(avl, 591);
-  avl = remove_int(avl, 87);
-  avl = remove_int(avl, 93);
-  avl = gpr_avl_add(avl, box(1016), box(679), nullptr);
-  avl = gpr_avl_add(avl, box(605), box(680), nullptr);
-  avl = gpr_avl_add(avl, box(152), box(681), nullptr);
-  avl = gpr_avl_add(avl, box(113), box(682), nullptr);
-  avl = remove_int(avl, 131);
-  avl = remove_int(avl, 637);
-  avl = gpr_avl_add(avl, box(156), box(685), nullptr);
-  avl = remove_int(avl, 696);
-  avl = gpr_avl_add(avl, box(546), box(687), nullptr);
-  avl = remove_int(avl, 970);
-  avl = remove_int(avl, 53);
-  avl = remove_int(avl, 827);
-  avl = remove_int(avl, 224);
-  avl = remove_int(avl, 796);
-  avl = remove_int(avl, 34);
-  avl = remove_int(avl, 922);
-  avl = remove_int(avl, 277);
-  avl = remove_int(avl, 650);
-  avl = remove_int(avl, 222);
-  avl = remove_int(avl, 244);
-  avl = remove_int(avl, 576);
-  avl = remove_int(avl, 413);
-  avl = gpr_avl_add(avl, box(500), box(701), nullptr);
-  avl = remove_int(avl, 924);
-  avl = gpr_avl_add(avl, box(825), box(703), nullptr);
-  avl = remove_int(avl, 888);
-  avl = remove_int(avl, 931);
-  avl = gpr_avl_add(avl, box(285), box(706), nullptr);
-  avl = remove_int(avl, 62);
-  avl = remove_int(avl, 444);
-  avl = remove_int(avl, 946);
-  avl = gpr_avl_add(avl, box(122), box(710), nullptr);
-  avl = gpr_avl_add(avl, box(846), box(711), nullptr);
-  avl = remove_int(avl, 628);
-  avl = gpr_avl_add(avl, box(511), box(713), nullptr);
-  avl = gpr_avl_add(avl, box(398), box(714), nullptr);
-  avl = remove_int(avl, 730);
-  avl = gpr_avl_add(avl, box(797), box(716), nullptr);
-  avl = remove_int(avl, 897);
-  avl = remove_int(avl, 228);
-  avl = remove_int(avl, 544);
-  avl = remove_int(avl, 552);
-  avl = remove_int(avl, 783);
-  avl = remove_int(avl, 583);
-  avl = remove_int(avl, 894);
-  avl = remove_int(avl, 942);
-  avl = gpr_avl_add(avl, box(346), box(725), nullptr);
-  avl = gpr_avl_add(avl, box(1015), box(726), nullptr);
-  avl = remove_int(avl, 813);
-  avl = gpr_avl_add(avl, box(213), box(728), nullptr);
-  avl = remove_int(avl, 468);
-  avl = remove_int(avl, 365);
-  avl = remove_int(avl, 399);
-  avl = gpr_avl_add(avl, box(380), box(732), nullptr);
-  avl = remove_int(avl, 835);
-  avl = remove_int(avl, 970);
-  avl = gpr_avl_add(avl, box(700), box(735), nullptr);
-  avl = gpr_avl_add(avl, box(807), box(736), nullptr);
-  avl = remove_int(avl, 312);
-  avl = remove_int(avl, 282);
-  avl = remove_int(avl, 370);
-  avl = remove_int(avl, 999);
-  avl = remove_int(avl, 241);
-  avl = remove_int(avl, 884);
-  avl = gpr_avl_add(avl, box(587), box(743), nullptr);
-  avl = gpr_avl_add(avl, box(332), box(744), nullptr);
-  avl = remove_int(avl, 686);
-  avl = remove_int(avl, 206);
-  avl = remove_int(avl, 835);
-  avl = gpr_avl_add(avl, box(334), box(748), nullptr);
-  avl = remove_int(avl, 171);
-  avl = gpr_avl_add(avl, box(1002), box(750), nullptr);
-  avl = gpr_avl_add(avl, box(779), box(751), nullptr);
-  avl = gpr_avl_add(avl, box(307), box(752), nullptr);
-  avl = gpr_avl_add(avl, box(127), box(753), nullptr);
-  avl = gpr_avl_add(avl, box(251), box(754), nullptr);
-  avl = remove_int(avl, 790);
-  avl = remove_int(avl, 189);
-  avl = remove_int(avl, 193);
-  avl = remove_int(avl, 38);
-  avl = remove_int(avl, 124);
-  avl = gpr_avl_add(avl, box(812), box(760), nullptr);
-  avl = remove_int(avl, 43);
-  avl = gpr_avl_add(avl, box(871), box(762), nullptr);
-  avl = gpr_avl_add(avl, box(580), box(763), nullptr);
-  avl = remove_int(avl, 501);
-  avl = remove_int(avl, 462);
-  avl = remove_int(avl, 599);
-  avl = gpr_avl_add(avl, box(240), box(767), nullptr);
-  avl = gpr_avl_add(avl, box(285), box(768), nullptr);
-  avl = gpr_avl_add(avl, box(472), box(769), nullptr);
-  avl = remove_int(avl, 865);
-  avl = remove_int(avl, 763);
-  avl = remove_int(avl, 245);
-  avl = remove_int(avl, 80);
-  avl = remove_int(avl, 713);
-  avl = remove_int(avl, 654);
-  avl = remove_int(avl, 1014);
-  avl = gpr_avl_add(avl, box(495), box(777), nullptr);
-  avl = gpr_avl_add(avl, box(552), box(778), nullptr);
-  avl = remove_int(avl, 19);
-  avl = remove_int(avl, 803);
-  avl = gpr_avl_add(avl, box(508), box(781), nullptr);
-  avl = remove_int(avl, 699);
-  avl = remove_int(avl, 260);
-  avl = remove_int(avl, 92);
-  avl = remove_int(avl, 497);
-  avl = gpr_avl_add(avl, box(970), box(786), nullptr);
-  avl = remove_int(avl, 987);
-  avl = remove_int(avl, 168);
-  avl = remove_int(avl, 476);
-  avl = remove_int(avl, 248);
-  avl = gpr_avl_add(avl, box(358), box(791), nullptr);
-  avl = remove_int(avl, 804);
-  avl = remove_int(avl, 77);
-  avl = remove_int(avl, 905);
-  avl = remove_int(avl, 362);
-  avl = gpr_avl_add(avl, box(578), box(796), nullptr);
-  avl = remove_int(avl, 38);
-  avl = remove_int(avl, 595);
-  avl = gpr_avl_add(avl, box(213), box(799), nullptr);
-  avl = remove_int(avl, 7);
-  avl = remove_int(avl, 620);
-  avl = gpr_avl_add(avl, box(946), box(802), nullptr);
-  avl = remove_int(avl, 145);
-  avl = gpr_avl_add(avl, box(628), box(804), nullptr);
-  avl = remove_int(avl, 972);
-  avl = gpr_avl_add(avl, box(728), box(806), nullptr);
-  avl = remove_int(avl, 91);
-  avl = gpr_avl_add(avl, box(136), box(808), nullptr);
-  avl = gpr_avl_add(avl, box(841), box(809), nullptr);
-  avl = gpr_avl_add(avl, box(265), box(810), nullptr);
-  avl = gpr_avl_add(avl, box(701), box(811), nullptr);
-  avl = gpr_avl_add(avl, box(27), box(812), nullptr);
-  avl = remove_int(avl, 72);
-  avl = remove_int(avl, 14);
-  avl = gpr_avl_add(avl, box(286), box(815), nullptr);
-  avl = remove_int(avl, 996);
-  avl = remove_int(avl, 998);
-  avl = gpr_avl_add(avl, box(466), box(818), nullptr);
-  avl = remove_int(avl, 1009);
-  avl = remove_int(avl, 741);
-  avl = remove_int(avl, 947);
-  avl = remove_int(avl, 241);
-  avl = remove_int(avl, 954);
-  avl = remove_int(avl, 183);
-  avl = remove_int(avl, 395);
-  avl = remove_int(avl, 951);
-  avl = gpr_avl_add(avl, box(267), box(827), nullptr);
-  avl = remove_int(avl, 812);
-  avl = gpr_avl_add(avl, box(577), box(829), nullptr);
-  avl = remove_int(avl, 624);
-  avl = remove_int(avl, 847);
-  avl = remove_int(avl, 745);
-  avl = gpr_avl_add(avl, box(491), box(833), nullptr);
-  avl = gpr_avl_add(avl, box(941), box(834), nullptr);
-  avl = remove_int(avl, 258);
-  avl = gpr_avl_add(avl, box(410), box(836), nullptr);
-  avl = gpr_avl_add(avl, box(80), box(837), nullptr);
-  avl = gpr_avl_add(avl, box(196), box(838), nullptr);
-  avl = gpr_avl_add(avl, box(5), box(839), nullptr);
-  avl = remove_int(avl, 782);
-  avl = gpr_avl_add(avl, box(827), box(841), nullptr);
-  avl = remove_int(avl, 472);
-  avl = remove_int(avl, 664);
-  avl = gpr_avl_add(avl, box(409), box(844), nullptr);
-  avl = gpr_avl_add(avl, box(62), box(845), nullptr);
-  avl = remove_int(avl, 56);
-  avl = remove_int(avl, 606);
-  avl = remove_int(avl, 707);
-  avl = remove_int(avl, 989);
-  avl = remove_int(avl, 549);
-  avl = remove_int(avl, 259);
-  avl = gpr_avl_add(avl, box(405), box(852), nullptr);
-  avl = remove_int(avl, 587);
-  avl = remove_int(avl, 350);
-  avl = gpr_avl_add(avl, box(980), box(855), nullptr);
-  avl = gpr_avl_add(avl, box(992), box(856), nullptr);
-  avl = gpr_avl_add(avl, box(818), box(857), nullptr);
-  avl = remove_int(avl, 853);
-  avl = remove_int(avl, 701);
-  avl = gpr_avl_add(avl, box(675), box(860), nullptr);
-  avl = remove_int(avl, 248);
-  avl = remove_int(avl, 649);
-  avl = gpr_avl_add(avl, box(508), box(863), nullptr);
-  avl = remove_int(avl, 927);
-  avl = gpr_avl_add(avl, box(957), box(865), nullptr);
-  avl = gpr_avl_add(avl, box(698), box(866), nullptr);
-  avl = gpr_avl_add(avl, box(388), box(867), nullptr);
-  avl = gpr_avl_add(avl, box(532), box(868), nullptr);
-  avl = gpr_avl_add(avl, box(681), box(869), nullptr);
-  avl = remove_int(avl, 544);
-  avl = remove_int(avl, 991);
-  avl = remove_int(avl, 397);
-  avl = gpr_avl_add(avl, box(954), box(873), nullptr);
-  avl = gpr_avl_add(avl, box(219), box(874), nullptr);
-  avl = gpr_avl_add(avl, box(465), box(875), nullptr);
-  avl = remove_int(avl, 371);
-  avl = gpr_avl_add(avl, box(601), box(877), nullptr);
-  avl = gpr_avl_add(avl, box(543), box(878), nullptr);
-  avl = remove_int(avl, 329);
-  avl = gpr_avl_add(avl, box(560), box(880), nullptr);
-  avl = remove_int(avl, 898);
-  avl = gpr_avl_add(avl, box(455), box(882), nullptr);
-  avl = remove_int(avl, 313);
-  avl = gpr_avl_add(avl, box(215), box(884), nullptr);
-  avl = remove_int(avl, 846);
-  avl = gpr_avl_add(avl, box(608), box(886), nullptr);
-  avl = remove_int(avl, 248);
-  avl = gpr_avl_add(avl, box(575), box(888), nullptr);
-  avl = remove_int(avl, 207);
-  avl = remove_int(avl, 810);
-  avl = remove_int(avl, 665);
-  avl = remove_int(avl, 361);
-  avl = gpr_avl_add(avl, box(154), box(893), nullptr);
-  avl = gpr_avl_add(avl, box(329), box(894), nullptr);
-  avl = gpr_avl_add(avl, box(326), box(895), nullptr);
-  avl = remove_int(avl, 746);
-  avl = remove_int(avl, 99);
-  avl = gpr_avl_add(avl, box(464), box(898), nullptr);
-  avl = gpr_avl_add(avl, box(141), box(899), nullptr);
-  avl = remove_int(avl, 383);
-  avl = gpr_avl_add(avl, box(414), box(901), nullptr);
-  avl = gpr_avl_add(avl, box(777), box(902), nullptr);
-  avl = remove_int(avl, 972);
-  avl = remove_int(avl, 841);
-  avl = remove_int(avl, 100);
-  avl = gpr_avl_add(avl, box(828), box(906), nullptr);
-  avl = remove_int(avl, 785);
-  avl = gpr_avl_add(avl, box(1008), box(908), nullptr);
-  avl = gpr_avl_add(avl, box(46), box(909), nullptr);
-  avl = remove_int(avl, 399);
-  avl = gpr_avl_add(avl, box(178), box(911), nullptr);
-  avl = gpr_avl_add(avl, box(573), box(912), nullptr);
-  avl = remove_int(avl, 299);
-  avl = gpr_avl_add(avl, box(690), box(914), nullptr);
-  avl = gpr_avl_add(avl, box(692), box(915), nullptr);
-  avl = remove_int(avl, 404);
-  avl = remove_int(avl, 16);
-  avl = remove_int(avl, 746);
-  avl = remove_int(avl, 486);
-  avl = remove_int(avl, 119);
-  avl = gpr_avl_add(avl, box(167), box(921), nullptr);
-  avl = remove_int(avl, 328);
-  avl = gpr_avl_add(avl, box(89), box(923), nullptr);
-  avl = remove_int(avl, 867);
-  avl = remove_int(avl, 626);
-  avl = remove_int(avl, 507);
-  avl = gpr_avl_add(avl, box(365), box(927), nullptr);
-  avl = gpr_avl_add(avl, box(58), box(928), nullptr);
-  avl = gpr_avl_add(avl, box(70), box(929), nullptr);
-  avl = remove_int(avl, 81);
-  avl = remove_int(avl, 797);
-  avl = gpr_avl_add(avl, box(846), box(932), nullptr);
-  avl = remove_int(avl, 642);
-  avl = gpr_avl_add(avl, box(777), box(934), nullptr);
-  avl = remove_int(avl, 107);
-  avl = gpr_avl_add(avl, box(691), box(936), nullptr);
-  avl = gpr_avl_add(avl, box(820), box(937), nullptr);
-  avl = gpr_avl_add(avl, box(202), box(938), nullptr);
-  avl = gpr_avl_add(avl, box(308), box(939), nullptr);
-  avl = gpr_avl_add(avl, box(20), box(940), nullptr);
-  avl = remove_int(avl, 289);
-  avl = gpr_avl_add(avl, box(714), box(942), nullptr);
-  avl = gpr_avl_add(avl, box(584), box(943), nullptr);
-  avl = remove_int(avl, 294);
-  avl = gpr_avl_add(avl, box(496), box(945), nullptr);
-  avl = gpr_avl_add(avl, box(394), box(946), nullptr);
-  avl = gpr_avl_add(avl, box(860), box(947), nullptr);
-  avl = gpr_avl_add(avl, box(58), box(948), nullptr);
-  avl = remove_int(avl, 784);
-  avl = remove_int(avl, 584);
-  avl = remove_int(avl, 708);
-  avl = gpr_avl_add(avl, box(142), box(952), nullptr);
-  avl = gpr_avl_add(avl, box(247), box(953), nullptr);
-  avl = gpr_avl_add(avl, box(389), box(954), nullptr);
-  avl = remove_int(avl, 390);
-  avl = gpr_avl_add(avl, box(465), box(956), nullptr);
-  avl = gpr_avl_add(avl, box(936), box(957), nullptr);
-  avl = gpr_avl_add(avl, box(309), box(958), nullptr);
-  avl = remove_int(avl, 928);
-  avl = remove_int(avl, 128);
-  avl = remove_int(avl, 979);
-  avl = remove_int(avl, 670);
-  avl = remove_int(avl, 738);
-  avl = remove_int(avl, 271);
-  avl = remove_int(avl, 540);
-  avl = gpr_avl_add(avl, box(365), box(966), nullptr);
-  avl = remove_int(avl, 82);
-  avl = gpr_avl_add(avl, box(728), box(968), nullptr);
-  avl = remove_int(avl, 852);
-  avl = gpr_avl_add(avl, box(884), box(970), nullptr);
-  avl = gpr_avl_add(avl, box(502), box(971), nullptr);
-  avl = remove_int(avl, 898);
-  avl = remove_int(avl, 481);
-  avl = gpr_avl_add(avl, box(911), box(974), nullptr);
-  avl = remove_int(avl, 787);
-  avl = remove_int(avl, 785);
-  avl = remove_int(avl, 537);
-  avl = remove_int(avl, 535);
-  avl = remove_int(avl, 136);
-  avl = remove_int(avl, 749);
-  avl = remove_int(avl, 637);
-  avl = remove_int(avl, 900);
-  avl = gpr_avl_add(avl, box(598), box(983), nullptr);
-  avl = remove_int(avl, 25);
-  avl = remove_int(avl, 697);
-  avl = gpr_avl_add(avl, box(645), box(986), nullptr);
-  avl = gpr_avl_add(avl, box(211), box(987), nullptr);
-  avl = gpr_avl_add(avl, box(589), box(988), nullptr);
-  avl = remove_int(avl, 702);
-  avl = gpr_avl_add(avl, box(53), box(990), nullptr);
-  avl = remove_int(avl, 492);
-  avl = remove_int(avl, 185);
-  avl = remove_int(avl, 246);
-  avl = remove_int(avl, 257);
-  avl = remove_int(avl, 502);
-  avl = remove_int(avl, 34);
-  avl = gpr_avl_add(avl, box(74), box(997), nullptr);
-  avl = gpr_avl_add(avl, box(834), box(998), nullptr);
-  avl = gpr_avl_add(avl, box(514), box(999), nullptr);
-  avl = gpr_avl_add(avl, box(75), box(1000), nullptr);
-  avl = remove_int(avl, 745);
-  avl = gpr_avl_add(avl, box(362), box(1002), nullptr);
-  avl = remove_int(avl, 215);
-  avl = gpr_avl_add(avl, box(624), box(1004), nullptr);
-  avl = remove_int(avl, 404);
-  avl = remove_int(avl, 359);
-  avl = remove_int(avl, 491);
-  avl = gpr_avl_add(avl, box(903), box(1008), nullptr);
-  avl = gpr_avl_add(avl, box(240), box(1009), nullptr);
-  avl = remove_int(avl, 95);
-  avl = gpr_avl_add(avl, box(119), box(1011), nullptr);
-  avl = gpr_avl_add(avl, box(857), box(1012), nullptr);
-  avl = remove_int(avl, 39);
-  avl = remove_int(avl, 866);
-  avl = gpr_avl_add(avl, box(503), box(1015), nullptr);
-  avl = gpr_avl_add(avl, box(740), box(1016), nullptr);
-  avl = remove_int(avl, 637);
-  avl = remove_int(avl, 156);
-  avl = remove_int(avl, 6);
-  avl = remove_int(avl, 745);
-  avl = remove_int(avl, 433);
-  avl = remove_int(avl, 283);
-  avl = gpr_avl_add(avl, box(625), box(1023), nullptr);
-  avl = remove_int(avl, 638);
-  avl = gpr_avl_add(avl, box(299), box(1025), nullptr);
-  avl = gpr_avl_add(avl, box(584), box(1026), nullptr);
-  avl = remove_int(avl, 863);
-  avl = gpr_avl_add(avl, box(612), box(1028), nullptr);
-  avl = gpr_avl_add(avl, box(62), box(1029), nullptr);
-  avl = gpr_avl_add(avl, box(432), box(1030), nullptr);
-  avl = remove_int(avl, 371);
-  avl = remove_int(avl, 790);
-  avl = remove_int(avl, 227);
-  avl = remove_int(avl, 836);
-  avl = gpr_avl_add(avl, box(703), box(1035), nullptr);
-  avl = gpr_avl_add(avl, box(644), box(1036), nullptr);
-  avl = remove_int(avl, 638);
-  avl = gpr_avl_add(avl, box(13), box(1038), nullptr);
-  avl = remove_int(avl, 66);
-  avl = remove_int(avl, 82);
-  avl = gpr_avl_add(avl, box(362), box(1041), nullptr);
-  avl = gpr_avl_add(avl, box(783), box(1042), nullptr);
-  avl = remove_int(avl, 60);
-  avl = gpr_avl_add(avl, box(80), box(1044), nullptr);
-  avl = gpr_avl_add(avl, box(825), box(1045), nullptr);
-  avl = gpr_avl_add(avl, box(688), box(1046), nullptr);
-  avl = gpr_avl_add(avl, box(662), box(1047), nullptr);
-  avl = remove_int(avl, 156);
-  avl = remove_int(avl, 376);
-  avl = remove_int(avl, 99);
-  avl = gpr_avl_add(avl, box(526), box(1051), nullptr);
-  avl = gpr_avl_add(avl, box(168), box(1052), nullptr);
-  avl = remove_int(avl, 646);
-  avl = remove_int(avl, 380);
-  avl = remove_int(avl, 833);
-  avl = gpr_avl_add(avl, box(53), box(1056), nullptr);
-  avl = remove_int(avl, 105);
-  avl = gpr_avl_add(avl, box(373), box(1058), nullptr);
-  avl = gpr_avl_add(avl, box(184), box(1059), nullptr);
-  avl = remove_int(avl, 288);
-  avl = gpr_avl_add(avl, box(966), box(1061), nullptr);
-  avl = remove_int(avl, 158);
-  avl = gpr_avl_add(avl, box(406), box(1063), nullptr);
-  avl = remove_int(avl, 470);
-  avl = gpr_avl_add(avl, box(283), box(1065), nullptr);
-  avl = gpr_avl_add(avl, box(838), box(1066), nullptr);
-  avl = gpr_avl_add(avl, box(288), box(1067), nullptr);
-  avl = gpr_avl_add(avl, box(950), box(1068), nullptr);
-  avl = gpr_avl_add(avl, box(163), box(1069), nullptr);
-  avl = remove_int(avl, 623);
-  avl = remove_int(avl, 769);
-  avl = gpr_avl_add(avl, box(144), box(1072), nullptr);
-  avl = gpr_avl_add(avl, box(489), box(1073), nullptr);
-  avl = remove_int(avl, 15);
-  avl = gpr_avl_add(avl, box(971), box(1075), nullptr);
-  avl = remove_int(avl, 660);
-  avl = gpr_avl_add(avl, box(255), box(1077), nullptr);
-  avl = remove_int(avl, 494);
-  avl = gpr_avl_add(avl, box(109), box(1079), nullptr);
-  avl = gpr_avl_add(avl, box(420), box(1080), nullptr);
-  avl = gpr_avl_add(avl, box(509), box(1081), nullptr);
-  avl = remove_int(avl, 178);
-  avl = gpr_avl_add(avl, box(216), box(1083), nullptr);
-  avl = gpr_avl_add(avl, box(707), box(1084), nullptr);
-  avl = gpr_avl_add(avl, box(411), box(1085), nullptr);
-  avl = gpr_avl_add(avl, box(352), box(1086), nullptr);
-  avl = remove_int(avl, 983);
-  avl = gpr_avl_add(avl, box(6), box(1088), nullptr);
-  avl = gpr_avl_add(avl, box(1014), box(1089), nullptr);
-  avl = remove_int(avl, 98);
-  avl = remove_int(avl, 325);
-  avl = gpr_avl_add(avl, box(851), box(1092), nullptr);
-  avl = remove_int(avl, 553);
-  avl = gpr_avl_add(avl, box(218), box(1094), nullptr);
-  avl = gpr_avl_add(avl, box(261), box(1095), nullptr);
-  avl = remove_int(avl, 31);
-  avl = gpr_avl_add(avl, box(872), box(1097), nullptr);
-  avl = remove_int(avl, 543);
-  avl = remove_int(avl, 314);
-  avl = remove_int(avl, 443);
-  avl = gpr_avl_add(avl, box(533), box(1101), nullptr);
-  avl = remove_int(avl, 881);
-  avl = remove_int(avl, 269);
-  avl = remove_int(avl, 940);
-  avl = remove_int(avl, 909);
-  avl = remove_int(avl, 197);
-  avl = remove_int(avl, 773);
-  avl = remove_int(avl, 790);
-  avl = remove_int(avl, 345);
-  avl = gpr_avl_add(avl, box(965), box(1110), nullptr);
-  avl = remove_int(avl, 622);
-  avl = gpr_avl_add(avl, box(352), box(1112), nullptr);
-  avl = remove_int(avl, 182);
-  avl = gpr_avl_add(avl, box(534), box(1114), nullptr);
-  avl = gpr_avl_add(avl, box(97), box(1115), nullptr);
-  avl = gpr_avl_add(avl, box(198), box(1116), nullptr);
-  avl = remove_int(avl, 750);
-  avl = gpr_avl_add(avl, box(98), box(1118), nullptr);
-  avl = remove_int(avl, 943);
-  avl = gpr_avl_add(avl, box(254), box(1120), nullptr);
-  avl = gpr_avl_add(avl, box(30), box(1121), nullptr);
-  avl = remove_int(avl, 14);
-  avl = remove_int(avl, 475);
-  avl = remove_int(avl, 82);
-  avl = gpr_avl_add(avl, box(789), box(1125), nullptr);
-  avl = gpr_avl_add(avl, box(402), box(1126), nullptr);
-  avl = remove_int(avl, 1019);
-  avl = gpr_avl_add(avl, box(858), box(1128), nullptr);
-  avl = gpr_avl_add(avl, box(625), box(1129), nullptr);
-  avl = remove_int(avl, 675);
-  avl = remove_int(avl, 323);
-  avl = gpr_avl_add(avl, box(329), box(1132), nullptr);
-  avl = remove_int(avl, 929);
-  avl = remove_int(avl, 44);
-  avl = gpr_avl_add(avl, box(443), box(1135), nullptr);
-  avl = gpr_avl_add(avl, box(653), box(1136), nullptr);
-  avl = gpr_avl_add(avl, box(750), box(1137), nullptr);
-  avl = gpr_avl_add(avl, box(252), box(1138), nullptr);
-  avl = gpr_avl_add(avl, box(449), box(1139), nullptr);
-  avl = remove_int(avl, 1022);
-  avl = remove_int(avl, 357);
-  avl = remove_int(avl, 602);
-  avl = remove_int(avl, 131);
-  avl = gpr_avl_add(avl, box(531), box(1144), nullptr);
-  avl = remove_int(avl, 806);
-  avl = gpr_avl_add(avl, box(455), box(1146), nullptr);
-  avl = remove_int(avl, 31);
-  avl = gpr_avl_add(avl, box(154), box(1148), nullptr);
-  avl = gpr_avl_add(avl, box(189), box(1149), nullptr);
-  avl = remove_int(avl, 786);
-  avl = gpr_avl_add(avl, box(496), box(1151), nullptr);
-  avl = gpr_avl_add(avl, box(81), box(1152), nullptr);
-  avl = gpr_avl_add(avl, box(59), box(1153), nullptr);
-  avl = remove_int(avl, 424);
-  avl = remove_int(avl, 668);
-  avl = gpr_avl_add(avl, box(723), box(1156), nullptr);
-  avl = gpr_avl_add(avl, box(822), box(1157), nullptr);
-  avl = gpr_avl_add(avl, box(354), box(1158), nullptr);
-  avl = remove_int(avl, 738);
-  avl = gpr_avl_add(avl, box(686), box(1160), nullptr);
-  avl = gpr_avl_add(avl, box(43), box(1161), nullptr);
-  avl = gpr_avl_add(avl, box(625), box(1162), nullptr);
-  avl = gpr_avl_add(avl, box(902), box(1163), nullptr);
-  avl = gpr_avl_add(avl, box(12), box(1164), nullptr);
-  avl = gpr_avl_add(avl, box(977), box(1165), nullptr);
-  avl = gpr_avl_add(avl, box(699), box(1166), nullptr);
-  avl = gpr_avl_add(avl, box(189), box(1167), nullptr);
-  avl = remove_int(avl, 672);
-  avl = remove_int(avl, 90);
-  avl = remove_int(avl, 757);
-  avl = remove_int(avl, 494);
-  avl = gpr_avl_add(avl, box(759), box(1172), nullptr);
-  avl = remove_int(avl, 758);
-  avl = remove_int(avl, 222);
-  avl = gpr_avl_add(avl, box(975), box(1175), nullptr);
-  avl = remove_int(avl, 993);
-  avl = gpr_avl_add(avl, box(2), box(1177), nullptr);
-  avl = gpr_avl_add(avl, box(70), box(1178), nullptr);
-  avl = remove_int(avl, 350);
-  avl = remove_int(avl, 972);
-  avl = remove_int(avl, 880);
-  avl = gpr_avl_add(avl, box(753), box(1182), nullptr);
-  avl = remove_int(avl, 404);
-  avl = gpr_avl_add(avl, box(294), box(1184), nullptr);
-  avl = remove_int(avl, 474);
-  avl = gpr_avl_add(avl, box(228), box(1186), nullptr);
-  avl = gpr_avl_add(avl, box(484), box(1187), nullptr);
-  avl = remove_int(avl, 238);
-  avl = remove_int(avl, 53);
-  avl = remove_int(avl, 691);
-  avl = gpr_avl_add(avl, box(345), box(1191), nullptr);
-  avl = remove_int(avl, 0);
-  avl = gpr_avl_add(avl, box(230), box(1193), nullptr);
-  avl = remove_int(avl, 227);
-  avl = remove_int(avl, 152);
-  avl = gpr_avl_add(avl, box(884), box(1196), nullptr);
-  avl = remove_int(avl, 823);
-  avl = remove_int(avl, 53);
-  avl = gpr_avl_add(avl, box(1015), box(1199), nullptr);
-  avl = gpr_avl_add(avl, box(697), box(1200), nullptr);
-  avl = gpr_avl_add(avl, box(376), box(1201), nullptr);
-  avl = remove_int(avl, 411);
-  avl = gpr_avl_add(avl, box(888), box(1203), nullptr);
-  avl = remove_int(avl, 55);
-  avl = gpr_avl_add(avl, box(85), box(1205), nullptr);
-  avl = remove_int(avl, 947);
-  avl = remove_int(avl, 382);
-  avl = remove_int(avl, 777);
-  avl = gpr_avl_add(avl, box(1017), box(1209), nullptr);
-  avl = gpr_avl_add(avl, box(169), box(1210), nullptr);
-  avl = gpr_avl_add(avl, box(156), box(1211), nullptr);
-  avl = remove_int(avl, 153);
-  avl = remove_int(avl, 642);
-  avl = remove_int(avl, 158);
-  avl = gpr_avl_add(avl, box(554), box(1215), nullptr);
-  avl = gpr_avl_add(avl, box(76), box(1216), nullptr);
-  avl = gpr_avl_add(avl, box(756), box(1217), nullptr);
-  avl = remove_int(avl, 767);
-  avl = remove_int(avl, 112);
-  avl = remove_int(avl, 539);
-  avl = remove_int(avl, 544);
-  avl = remove_int(avl, 628);
-  avl = remove_int(avl, 385);
-  avl = remove_int(avl, 514);
-  avl = remove_int(avl, 362);
-  avl = gpr_avl_add(avl, box(523), box(1226), nullptr);
-  avl = gpr_avl_add(avl, box(712), box(1227), nullptr);
-  avl = gpr_avl_add(avl, box(474), box(1228), nullptr);
-  avl = gpr_avl_add(avl, box(882), box(1229), nullptr);
-  avl = gpr_avl_add(avl, box(965), box(1230), nullptr);
-  avl = remove_int(avl, 464);
-  avl = gpr_avl_add(avl, box(319), box(1232), nullptr);
-  avl = gpr_avl_add(avl, box(504), box(1233), nullptr);
-  avl = remove_int(avl, 818);
-  avl = gpr_avl_add(avl, box(884), box(1235), nullptr);
-  avl = gpr_avl_add(avl, box(813), box(1236), nullptr);
-  avl = gpr_avl_add(avl, box(795), box(1237), nullptr);
-  avl = remove_int(avl, 306);
-  avl = gpr_avl_add(avl, box(799), box(1239), nullptr);
-  avl = remove_int(avl, 534);
-  avl = gpr_avl_add(avl, box(480), box(1241), nullptr);
-  avl = gpr_avl_add(avl, box(656), box(1242), nullptr);
-  avl = gpr_avl_add(avl, box(709), box(1243), nullptr);
-  avl = gpr_avl_add(avl, box(500), box(1244), nullptr);
-  avl = remove_int(avl, 740);
-  avl = gpr_avl_add(avl, box(980), box(1246), nullptr);
-  avl = gpr_avl_add(avl, box(458), box(1247), nullptr);
-  avl = remove_int(avl, 377);
-  avl = remove_int(avl, 338);
-  avl = gpr_avl_add(avl, box(554), box(1250), nullptr);
-  avl = gpr_avl_add(avl, box(504), box(1251), nullptr);
-  avl = gpr_avl_add(avl, box(603), box(1252), nullptr);
-  avl = gpr_avl_add(avl, box(761), box(1253), nullptr);
-  avl = remove_int(avl, 431);
-  avl = gpr_avl_add(avl, box(707), box(1255), nullptr);
-  avl = gpr_avl_add(avl, box(673), box(1256), nullptr);
-  avl = remove_int(avl, 998);
-  avl = remove_int(avl, 332);
-  avl = remove_int(avl, 413);
-  avl = remove_int(avl, 227);
-  avl = remove_int(avl, 249);
-  avl = remove_int(avl, 309);
-  avl = remove_int(avl, 459);
-  avl = gpr_avl_add(avl, box(645), box(1264), nullptr);
-  avl = remove_int(avl, 858);
-  avl = remove_int(avl, 997);
-  avl = gpr_avl_add(avl, box(519), box(1267), nullptr);
-  avl = remove_int(avl, 614);
-  avl = remove_int(avl, 462);
-  avl = remove_int(avl, 792);
-  avl = gpr_avl_add(avl, box(987), box(1271), nullptr);
-  avl = gpr_avl_add(avl, box(309), box(1272), nullptr);
-  avl = remove_int(avl, 747);
-  avl = gpr_avl_add(avl, box(621), box(1274), nullptr);
-  avl = gpr_avl_add(avl, box(450), box(1275), nullptr);
-  avl = remove_int(avl, 265);
-  avl = remove_int(avl, 8);
-  avl = remove_int(avl, 383);
-  avl = gpr_avl_add(avl, box(238), box(1279), nullptr);
-  avl = remove_int(avl, 241);
-  avl = gpr_avl_add(avl, box(180), box(1281), nullptr);
-  avl = gpr_avl_add(avl, box(411), box(1282), nullptr);
-  avl = gpr_avl_add(avl, box(791), box(1283), nullptr);
-  avl = gpr_avl_add(avl, box(955), box(1284), nullptr);
-  avl = remove_int(avl, 24);
-  avl = remove_int(avl, 375);
-  avl = gpr_avl_add(avl, box(140), box(1287), nullptr);
-  avl = remove_int(avl, 949);
-  avl = gpr_avl_add(avl, box(301), box(1289), nullptr);
-  avl = gpr_avl_add(avl, box(0), box(1290), nullptr);
-  avl = remove_int(avl, 371);
-  avl = remove_int(avl, 427);
-  avl = remove_int(avl, 841);
-  avl = remove_int(avl, 847);
-  avl = gpr_avl_add(avl, box(814), box(1295), nullptr);
-  avl = gpr_avl_add(avl, box(127), box(1296), nullptr);
-  avl = gpr_avl_add(avl, box(279), box(1297), nullptr);
-  avl = remove_int(avl, 669);
-  avl = remove_int(avl, 541);
-  avl = remove_int(avl, 275);
-  avl = remove_int(avl, 299);
-  avl = remove_int(avl, 552);
-  avl = gpr_avl_add(avl, box(310), box(1303), nullptr);
-  avl = gpr_avl_add(avl, box(304), box(1304), nullptr);
-  avl = gpr_avl_add(avl, box(1), box(1305), nullptr);
-  avl = gpr_avl_add(avl, box(339), box(1306), nullptr);
-  avl = remove_int(avl, 570);
-  avl = remove_int(avl, 752);
-  avl = remove_int(avl, 552);
-  avl = remove_int(avl, 442);
-  avl = remove_int(avl, 639);
-  avl = gpr_avl_add(avl, box(313), box(1312), nullptr);
-  avl = remove_int(avl, 85);
-  avl = gpr_avl_add(avl, box(964), box(1314), nullptr);
-  avl = gpr_avl_add(avl, box(559), box(1315), nullptr);
-  avl = remove_int(avl, 167);
-  avl = gpr_avl_add(avl, box(866), box(1317), nullptr);
-  avl = remove_int(avl, 275);
-  avl = gpr_avl_add(avl, box(173), box(1319), nullptr);
-  avl = gpr_avl_add(avl, box(765), box(1320), nullptr);
-  avl = remove_int(avl, 883);
-  avl = gpr_avl_add(avl, box(547), box(1322), nullptr);
-  avl = gpr_avl_add(avl, box(847), box(1323), nullptr);
-  avl = remove_int(avl, 817);
-  avl = remove_int(avl, 850);
-  avl = remove_int(avl, 718);
-  avl = gpr_avl_add(avl, box(806), box(1327), nullptr);
-  avl = gpr_avl_add(avl, box(360), box(1328), nullptr);
-  avl = remove_int(avl, 991);
-  avl = gpr_avl_add(avl, box(493), box(1330), nullptr);
-  avl = remove_int(avl, 516);
-  avl = gpr_avl_add(avl, box(361), box(1332), nullptr);
-  avl = remove_int(avl, 355);
-  avl = gpr_avl_add(avl, box(512), box(1334), nullptr);
-  avl = gpr_avl_add(avl, box(191), box(1335), nullptr);
-  avl = remove_int(avl, 703);
-  avl = gpr_avl_add(avl, box(333), box(1337), nullptr);
-  avl = remove_int(avl, 481);
-  avl = gpr_avl_add(avl, box(501), box(1339), nullptr);
-  avl = remove_int(avl, 532);
-  avl = remove_int(avl, 510);
-  avl = gpr_avl_add(avl, box(793), box(1342), nullptr);
-  avl = gpr_avl_add(avl, box(234), box(1343), nullptr);
-  avl = remove_int(avl, 159);
-  avl = remove_int(avl, 429);
-  avl = remove_int(avl, 728);
-  avl = remove_int(avl, 288);
-  avl = gpr_avl_add(avl, box(281), box(1348), nullptr);
-  avl = gpr_avl_add(avl, box(702), box(1349), nullptr);
-  avl = gpr_avl_add(avl, box(149), box(1350), nullptr);
-  avl = remove_int(avl, 22);
-  avl = remove_int(avl, 944);
-  avl = remove_int(avl, 55);
-  avl = remove_int(avl, 512);
-  avl = remove_int(avl, 676);
-  avl = remove_int(avl, 884);
-  avl = gpr_avl_add(avl, box(246), box(1357), nullptr);
-  avl = gpr_avl_add(avl, box(455), box(1358), nullptr);
-  avl = remove_int(avl, 782);
-  avl = remove_int(avl, 682);
-  avl = gpr_avl_add(avl, box(243), box(1361), nullptr);
-  avl = gpr_avl_add(avl, box(109), box(1362), nullptr);
-  avl = gpr_avl_add(avl, box(452), box(1363), nullptr);
-  avl = remove_int(avl, 151);
-  avl = gpr_avl_add(avl, box(159), box(1365), nullptr);
-  avl = remove_int(avl, 1023);
-  avl = gpr_avl_add(avl, box(129), box(1367), nullptr);
-  avl = gpr_avl_add(avl, box(537), box(1368), nullptr);
-  avl = remove_int(avl, 321);
-  avl = gpr_avl_add(avl, box(740), box(1370), nullptr);
-  avl = remove_int(avl, 45);
-  avl = remove_int(avl, 136);
-  avl = gpr_avl_add(avl, box(229), box(1373), nullptr);
-  avl = remove_int(avl, 772);
-  avl = gpr_avl_add(avl, box(181), box(1375), nullptr);
-  avl = remove_int(avl, 175);
-  avl = gpr_avl_add(avl, box(817), box(1377), nullptr);
-  avl = remove_int(avl, 956);
-  avl = gpr_avl_add(avl, box(675), box(1379), nullptr);
-  avl = gpr_avl_add(avl, box(375), box(1380), nullptr);
-  avl = remove_int(avl, 384);
-  avl = gpr_avl_add(avl, box(1016), box(1382), nullptr);
-  avl = remove_int(avl, 295);
-  avl = remove_int(avl, 697);
-  avl = remove_int(avl, 554);
-  avl = remove_int(avl, 590);
-  avl = remove_int(avl, 1014);
-  avl = gpr_avl_add(avl, box(890), box(1388), nullptr);
-  avl = gpr_avl_add(avl, box(293), box(1389), nullptr);
-  avl = remove_int(avl, 207);
-  avl = remove_int(avl, 46);
-  avl = gpr_avl_add(avl, box(899), box(1392), nullptr);
-  avl = gpr_avl_add(avl, box(666), box(1393), nullptr);
-  avl = gpr_avl_add(avl, box(85), box(1394), nullptr);
-  avl = gpr_avl_add(avl, box(914), box(1395), nullptr);
-  avl = gpr_avl_add(avl, box(128), box(1396), nullptr);
-  avl = gpr_avl_add(avl, box(835), box(1397), nullptr);
-  avl = gpr_avl_add(avl, box(787), box(1398), nullptr);
-  avl = gpr_avl_add(avl, box(649), box(1399), nullptr);
-  avl = gpr_avl_add(avl, box(723), box(1400), nullptr);
-  avl = remove_int(avl, 874);
-  avl = gpr_avl_add(avl, box(778), box(1402), nullptr);
-  avl = gpr_avl_add(avl, box(1015), box(1403), nullptr);
-  avl = gpr_avl_add(avl, box(59), box(1404), nullptr);
-  avl = gpr_avl_add(avl, box(259), box(1405), nullptr);
-  avl = gpr_avl_add(avl, box(758), box(1406), nullptr);
-  avl = remove_int(avl, 648);
-  avl = gpr_avl_add(avl, box(145), box(1408), nullptr);
-  avl = gpr_avl_add(avl, box(440), box(1409), nullptr);
-  avl = remove_int(avl, 608);
-  avl = remove_int(avl, 690);
-  avl = gpr_avl_add(avl, box(605), box(1412), nullptr);
-  avl = remove_int(avl, 856);
-  avl = remove_int(avl, 608);
-  avl = gpr_avl_add(avl, box(829), box(1415), nullptr);
-  avl = gpr_avl_add(avl, box(660), box(1416), nullptr);
-  avl = remove_int(avl, 596);
-  avl = gpr_avl_add(avl, box(519), box(1418), nullptr);
-  avl = gpr_avl_add(avl, box(35), box(1419), nullptr);
-  avl = gpr_avl_add(avl, box(871), box(1420), nullptr);
-  avl = remove_int(avl, 845);
-  avl = gpr_avl_add(avl, box(600), box(1422), nullptr);
-  avl = gpr_avl_add(avl, box(215), box(1423), nullptr);
-  avl = remove_int(avl, 761);
-  avl = gpr_avl_add(avl, box(975), box(1425), nullptr);
-  avl = remove_int(avl, 987);
-  avl = gpr_avl_add(avl, box(58), box(1427), nullptr);
-  avl = remove_int(avl, 119);
-  avl = gpr_avl_add(avl, box(937), box(1429), nullptr);
-  avl = gpr_avl_add(avl, box(372), box(1430), nullptr);
-  avl = gpr_avl_add(avl, box(11), box(1431), nullptr);
-  avl = gpr_avl_add(avl, box(398), box(1432), nullptr);
-  avl = gpr_avl_add(avl, box(423), box(1433), nullptr);
-  avl = remove_int(avl, 171);
-  avl = gpr_avl_add(avl, box(473), box(1435), nullptr);
-  avl = remove_int(avl, 752);
-  avl = remove_int(avl, 625);
-  avl = remove_int(avl, 764);
-  avl = remove_int(avl, 49);
-  avl = gpr_avl_add(avl, box(472), box(1440), nullptr);
-  avl = remove_int(avl, 847);
-  avl = remove_int(avl, 642);
-  avl = remove_int(avl, 1004);
-  avl = remove_int(avl, 795);
-  avl = remove_int(avl, 465);
-  avl = gpr_avl_add(avl, box(636), box(1446), nullptr);
-  avl = remove_int(avl, 152);
-  avl = gpr_avl_add(avl, box(61), box(1448), nullptr);
-  avl = remove_int(avl, 929);
-  avl = remove_int(avl, 9);
-  avl = gpr_avl_add(avl, box(251), box(1451), nullptr);
-  avl = gpr_avl_add(avl, box(672), box(1452), nullptr);
-  avl = gpr_avl_add(avl, box(66), box(1453), nullptr);
-  avl = remove_int(avl, 693);
-  avl = remove_int(avl, 914);
-  avl = remove_int(avl, 116);
-  avl = remove_int(avl, 577);
-  avl = gpr_avl_add(avl, box(618), box(1458), nullptr);
-  avl = gpr_avl_add(avl, box(495), box(1459), nullptr);
-  avl = remove_int(avl, 450);
-  avl = gpr_avl_add(avl, box(533), box(1461), nullptr);
-  avl = gpr_avl_add(avl, box(414), box(1462), nullptr);
-  avl = remove_int(avl, 74);
-  avl = remove_int(avl, 236);
-  avl = gpr_avl_add(avl, box(707), box(1465), nullptr);
-  avl = gpr_avl_add(avl, box(357), box(1466), nullptr);
-  avl = gpr_avl_add(avl, box(1007), box(1467), nullptr);
-  avl = gpr_avl_add(avl, box(811), box(1468), nullptr);
-  avl = gpr_avl_add(avl, box(418), box(1469), nullptr);
-  avl = gpr_avl_add(avl, box(164), box(1470), nullptr);
-  avl = gpr_avl_add(avl, box(622), box(1471), nullptr);
-  avl = remove_int(avl, 22);
-  avl = remove_int(avl, 14);
-  avl = remove_int(avl, 732);
-  avl = remove_int(avl, 7);
-  avl = remove_int(avl, 447);
-  avl = gpr_avl_add(avl, box(221), box(1477), nullptr);
-  avl = gpr_avl_add(avl, box(202), box(1478), nullptr);
-  avl = gpr_avl_add(avl, box(312), box(1479), nullptr);
-  avl = remove_int(avl, 274);
-  avl = gpr_avl_add(avl, box(684), box(1481), nullptr);
-  avl = gpr_avl_add(avl, box(954), box(1482), nullptr);
-  avl = gpr_avl_add(avl, box(637), box(1483), nullptr);
-  avl = remove_int(avl, 716);
-  avl = gpr_avl_add(avl, box(198), box(1485), nullptr);
-  avl = remove_int(avl, 340);
-  avl = remove_int(avl, 137);
-  avl = remove_int(avl, 995);
-  avl = remove_int(avl, 1004);
-  avl = gpr_avl_add(avl, box(661), box(1490), nullptr);
-  avl = gpr_avl_add(avl, box(862), box(1491), nullptr);
-  avl = remove_int(avl, 527);
-  avl = gpr_avl_add(avl, box(945), box(1493), nullptr);
-  avl = remove_int(avl, 355);
-  avl = remove_int(avl, 144);
-  avl = gpr_avl_add(avl, box(229), box(1496), nullptr);
-  avl = gpr_avl_add(avl, box(237), box(1497), nullptr);
-  avl = remove_int(avl, 471);
-  avl = remove_int(avl, 901);
-  avl = gpr_avl_add(avl, box(905), box(1500), nullptr);
-  avl = remove_int(avl, 19);
-  avl = remove_int(avl, 896);
-  avl = remove_int(avl, 585);
-  avl = remove_int(avl, 308);
-  avl = gpr_avl_add(avl, box(547), box(1505), nullptr);
-  avl = gpr_avl_add(avl, box(552), box(1506), nullptr);
-  avl = gpr_avl_add(avl, box(30), box(1507), nullptr);
-  avl = gpr_avl_add(avl, box(445), box(1508), nullptr);
-  avl = remove_int(avl, 785);
-  avl = remove_int(avl, 185);
-  avl = gpr_avl_add(avl, box(405), box(1511), nullptr);
-  avl = gpr_avl_add(avl, box(733), box(1512), nullptr);
-  avl = gpr_avl_add(avl, box(573), box(1513), nullptr);
-  avl = gpr_avl_add(avl, box(492), box(1514), nullptr);
-  avl = gpr_avl_add(avl, box(343), box(1515), nullptr);
-  avl = gpr_avl_add(avl, box(527), box(1516), nullptr);
-  avl = gpr_avl_add(avl, box(596), box(1517), nullptr);
-  avl = gpr_avl_add(avl, box(519), box(1518), nullptr);
-  avl = remove_int(avl, 243);
-  avl = remove_int(avl, 722);
-  avl = gpr_avl_add(avl, box(772), box(1521), nullptr);
-  avl = remove_int(avl, 152);
-  avl = remove_int(avl, 305);
-  avl = gpr_avl_add(avl, box(754), box(1524), nullptr);
-  avl = gpr_avl_add(avl, box(373), box(1525), nullptr);
-  avl = remove_int(avl, 995);
-  avl = gpr_avl_add(avl, box(329), box(1527), nullptr);
-  avl = remove_int(avl, 397);
-  avl = gpr_avl_add(avl, box(884), box(1529), nullptr);
-  avl = remove_int(avl, 329);
-  avl = remove_int(avl, 240);
-  avl = gpr_avl_add(avl, box(566), box(1532), nullptr);
-  avl = gpr_avl_add(avl, box(232), box(1533), nullptr);
-  avl = remove_int(avl, 993);
-  avl = gpr_avl_add(avl, box(888), box(1535), nullptr);
-  avl = remove_int(avl, 242);
-  avl = gpr_avl_add(avl, box(941), box(1537), nullptr);
-  avl = remove_int(avl, 415);
-  avl = gpr_avl_add(avl, box(992), box(1539), nullptr);
-  avl = remove_int(avl, 289);
-  avl = gpr_avl_add(avl, box(60), box(1541), nullptr);
-  avl = gpr_avl_add(avl, box(97), box(1542), nullptr);
-  avl = remove_int(avl, 965);
-  avl = remove_int(avl, 267);
-  avl = remove_int(avl, 360);
-  avl = gpr_avl_add(avl, box(5), box(1546), nullptr);
-  avl = remove_int(avl, 429);
-  avl = gpr_avl_add(avl, box(412), box(1548), nullptr);
-  avl = remove_int(avl, 632);
-  avl = remove_int(avl, 113);
-  avl = gpr_avl_add(avl, box(48), box(1551), nullptr);
-  avl = gpr_avl_add(avl, box(108), box(1552), nullptr);
-  avl = gpr_avl_add(avl, box(750), box(1553), nullptr);
-  avl = remove_int(avl, 188);
-  avl = gpr_avl_add(avl, box(668), box(1555), nullptr);
-  avl = remove_int(avl, 37);
-  avl = remove_int(avl, 737);
-  avl = gpr_avl_add(avl, box(93), box(1558), nullptr);
-  avl = gpr_avl_add(avl, box(628), box(1559), nullptr);
-  avl = gpr_avl_add(avl, box(480), box(1560), nullptr);
-  avl = remove_int(avl, 958);
-  avl = remove_int(avl, 565);
-  avl = remove_int(avl, 32);
-  avl = remove_int(avl, 1);
-  avl = remove_int(avl, 335);
-  avl = gpr_avl_add(avl, box(136), box(1566), nullptr);
-  avl = gpr_avl_add(avl, box(469), box(1567), nullptr);
-  avl = remove_int(avl, 349);
-  avl = gpr_avl_add(avl, box(768), box(1569), nullptr);
-  avl = gpr_avl_add(avl, box(915), box(1570), nullptr);
-  avl = remove_int(avl, 1014);
-  avl = gpr_avl_add(avl, box(117), box(1572), nullptr);
-  avl = remove_int(avl, 62);
-  avl = gpr_avl_add(avl, box(382), box(1574), nullptr);
-  avl = remove_int(avl, 571);
-  avl = gpr_avl_add(avl, box(655), box(1576), nullptr);
-  avl = gpr_avl_add(avl, box(323), box(1577), nullptr);
-  avl = remove_int(avl, 869);
-  avl = remove_int(avl, 151);
-  avl = gpr_avl_add(avl, box(1019), box(1580), nullptr);
-  avl = gpr_avl_add(avl, box(984), box(1581), nullptr);
-  avl = gpr_avl_add(avl, box(870), box(1582), nullptr);
-  avl = gpr_avl_add(avl, box(376), box(1583), nullptr);
-  avl = remove_int(avl, 625);
-  avl = gpr_avl_add(avl, box(733), box(1585), nullptr);
-  avl = remove_int(avl, 532);
-  avl = remove_int(avl, 444);
-  avl = gpr_avl_add(avl, box(428), box(1588), nullptr);
-  avl = gpr_avl_add(avl, box(860), box(1589), nullptr);
-  avl = gpr_avl_add(avl, box(173), box(1590), nullptr);
-  avl = remove_int(avl, 649);
-  avl = remove_int(avl, 913);
-  avl = remove_int(avl, 1);
-  avl = remove_int(avl, 304);
-  avl = gpr_avl_add(avl, box(604), box(1595), nullptr);
-  avl = gpr_avl_add(avl, box(639), box(1596), nullptr);
-  avl = remove_int(avl, 431);
-  avl = gpr_avl_add(avl, box(993), box(1598), nullptr);
-  avl = remove_int(avl, 681);
-  avl = remove_int(avl, 927);
-  avl = gpr_avl_add(avl, box(87), box(1601), nullptr);
-  avl = gpr_avl_add(avl, box(91), box(1602), nullptr);
-  avl = remove_int(avl, 61);
-  avl = remove_int(avl, 14);
-  avl = remove_int(avl, 305);
-  avl = remove_int(avl, 304);
-  avl = remove_int(avl, 1016);
-  avl = gpr_avl_add(avl, box(903), box(1608), nullptr);
-  avl = gpr_avl_add(avl, box(951), box(1609), nullptr);
-  avl = gpr_avl_add(avl, box(146), box(1610), nullptr);
-  avl = gpr_avl_add(avl, box(482), box(1611), nullptr);
-  avl = gpr_avl_add(avl, box(71), box(1612), nullptr);
-  avl = remove_int(avl, 246);
-  avl = remove_int(avl, 696);
-  avl = gpr_avl_add(avl, box(636), box(1615), nullptr);
-  avl = gpr_avl_add(avl, box(295), box(1616), nullptr);
-  avl = remove_int(avl, 11);
-  avl = remove_int(avl, 231);
-  avl = gpr_avl_add(avl, box(905), box(1619), nullptr);
-  avl = gpr_avl_add(avl, box(993), box(1620), nullptr);
-  avl = gpr_avl_add(avl, box(433), box(1621), nullptr);
-  avl = gpr_avl_add(avl, box(117), box(1622), nullptr);
-  avl = gpr_avl_add(avl, box(467), box(1623), nullptr);
-  avl = remove_int(avl, 419);
-  avl = gpr_avl_add(avl, box(179), box(1625), nullptr);
-  avl = remove_int(avl, 926);
-  avl = remove_int(avl, 326);
-  avl = gpr_avl_add(avl, box(551), box(1628), nullptr);
-  avl = remove_int(avl, 14);
-  avl = remove_int(avl, 476);
-  avl = remove_int(avl, 823);
-  avl = gpr_avl_add(avl, box(350), box(1632), nullptr);
-  avl = gpr_avl_add(avl, box(133), box(1633), nullptr);
-  avl = remove_int(avl, 906);
-  avl = gpr_avl_add(avl, box(827), box(1635), nullptr);
-  avl = gpr_avl_add(avl, box(201), box(1636), nullptr);
-  avl = remove_int(avl, 124);
-  avl = remove_int(avl, 662);
-  avl = gpr_avl_add(avl, box(314), box(1639), nullptr);
-  avl = gpr_avl_add(avl, box(986), box(1640), nullptr);
-  avl = gpr_avl_add(avl, box(622), box(1641), nullptr);
-  avl = remove_int(avl, 130);
-  avl = gpr_avl_add(avl, box(861), box(1643), nullptr);
-  avl = remove_int(avl, 497);
-  avl = remove_int(avl, 905);
-  avl = gpr_avl_add(avl, box(502), box(1646), nullptr);
-  avl = remove_int(avl, 721);
-  avl = gpr_avl_add(avl, box(514), box(1648), nullptr);
-  avl = gpr_avl_add(avl, box(410), box(1649), nullptr);
-  avl = remove_int(avl, 869);
-  avl = remove_int(avl, 247);
-  avl = gpr_avl_add(avl, box(450), box(1652), nullptr);
-  avl = remove_int(avl, 364);
-  avl = gpr_avl_add(avl, box(963), box(1654), nullptr);
-  avl = gpr_avl_add(avl, box(146), box(1655), nullptr);
-  avl = remove_int(avl, 147);
-  avl = remove_int(avl, 789);
-  avl = gpr_avl_add(avl, box(693), box(1658), nullptr);
-  avl = gpr_avl_add(avl, box(959), box(1659), nullptr);
-  avl = remove_int(avl, 478);
-  avl = gpr_avl_add(avl, box(116), box(1661), nullptr);
-  avl = gpr_avl_add(avl, box(520), box(1662), nullptr);
-  avl = gpr_avl_add(avl, box(809), box(1663), nullptr);
-  avl = gpr_avl_add(avl, box(667), box(1664), nullptr);
-  avl = gpr_avl_add(avl, box(406), box(1665), nullptr);
-  avl = remove_int(avl, 409);
-  avl = gpr_avl_add(avl, box(558), box(1667), nullptr);
-  avl = gpr_avl_add(avl, box(0), box(1668), nullptr);
-  avl = gpr_avl_add(avl, box(948), box(1669), nullptr);
-  avl = gpr_avl_add(avl, box(576), box(1670), nullptr);
-  avl = remove_int(avl, 864);
-  avl = remove_int(avl, 840);
-  avl = remove_int(avl, 1001);
-  avl = gpr_avl_add(avl, box(232), box(1674), nullptr);
-  avl = remove_int(avl, 676);
-  avl = remove_int(avl, 752);
-  avl = remove_int(avl, 667);
-  avl = remove_int(avl, 605);
-  avl = gpr_avl_add(avl, box(258), box(1679), nullptr);
-  avl = gpr_avl_add(avl, box(648), box(1680), nullptr);
-  avl = gpr_avl_add(avl, box(761), box(1681), nullptr);
-  avl = remove_int(avl, 293);
-  avl = remove_int(avl, 893);
-  avl = gpr_avl_add(avl, box(194), box(1684), nullptr);
-  avl = remove_int(avl, 233);
-  avl = gpr_avl_add(avl, box(888), box(1686), nullptr);
-  avl = remove_int(avl, 470);
-  avl = remove_int(avl, 703);
-  avl = remove_int(avl, 190);
-  avl = remove_int(avl, 359);
-  avl = gpr_avl_add(avl, box(621), box(1691), nullptr);
-  avl = remove_int(avl, 634);
-  avl = remove_int(avl, 335);
-  avl = gpr_avl_add(avl, box(718), box(1694), nullptr);
-  avl = gpr_avl_add(avl, box(463), box(1695), nullptr);
-  avl = gpr_avl_add(avl, box(233), box(1696), nullptr);
-  avl = remove_int(avl, 376);
-  avl = remove_int(avl, 496);
-  avl = remove_int(avl, 819);
-  avl = remove_int(avl, 38);
-  avl = remove_int(avl, 436);
-  avl = remove_int(avl, 102);
-  avl = gpr_avl_add(avl, box(607), box(1703), nullptr);
-  avl = remove_int(avl, 329);
-  avl = gpr_avl_add(avl, box(716), box(1705), nullptr);
-  avl = remove_int(avl, 639);
-  avl = remove_int(avl, 775);
-  avl = remove_int(avl, 578);
-  avl = remove_int(avl, 464);
-  avl = remove_int(avl, 679);
-  avl = remove_int(avl, 615);
-  avl = remove_int(avl, 104);
-  avl = gpr_avl_add(avl, box(414), box(1713), nullptr);
-  avl = gpr_avl_add(avl, box(212), box(1714), nullptr);
-  avl = gpr_avl_add(avl, box(266), box(1715), nullptr);
-  avl = gpr_avl_add(avl, box(238), box(1716), nullptr);
-  avl = remove_int(avl, 153);
-  avl = gpr_avl_add(avl, box(585), box(1718), nullptr);
-  avl = remove_int(avl, 121);
-  avl = gpr_avl_add(avl, box(534), box(1720), nullptr);
-  avl = remove_int(avl, 579);
-  avl = gpr_avl_add(avl, box(127), box(1722), nullptr);
-  avl = gpr_avl_add(avl, box(399), box(1723), nullptr);
-  avl = remove_int(avl, 417);
-  avl = gpr_avl_add(avl, box(978), box(1725), nullptr);
-  avl = gpr_avl_add(avl, box(768), box(1726), nullptr);
-  avl = remove_int(avl, 985);
-  avl = gpr_avl_add(avl, box(536), box(1728), nullptr);
-  avl = gpr_avl_add(avl, box(449), box(1729), nullptr);
-  avl = gpr_avl_add(avl, box(586), box(1730), nullptr);
-  avl = remove_int(avl, 998);
-  avl = remove_int(avl, 394);
-  avl = remove_int(avl, 141);
-  avl = gpr_avl_add(avl, box(889), box(1734), nullptr);
-  avl = gpr_avl_add(avl, box(871), box(1735), nullptr);
-  avl = gpr_avl_add(avl, box(76), box(1736), nullptr);
-  avl = gpr_avl_add(avl, box(549), box(1737), nullptr);
-  avl = gpr_avl_add(avl, box(757), box(1738), nullptr);
-  avl = remove_int(avl, 908);
-  avl = gpr_avl_add(avl, box(789), box(1740), nullptr);
-  avl = remove_int(avl, 224);
-  avl = gpr_avl_add(avl, box(407), box(1742), nullptr);
-  avl = gpr_avl_add(avl, box(381), box(1743), nullptr);
-  avl = gpr_avl_add(avl, box(561), box(1744), nullptr);
-  avl = gpr_avl_add(avl, box(667), box(1745), nullptr);
-  avl = gpr_avl_add(avl, box(522), box(1746), nullptr);
-  avl = gpr_avl_add(avl, box(948), box(1747), nullptr);
-  avl = remove_int(avl, 770);
-  avl = gpr_avl_add(avl, box(872), box(1749), nullptr);
-  avl = gpr_avl_add(avl, box(327), box(1750), nullptr);
-  avl = remove_int(avl, 10);
-  avl = gpr_avl_add(avl, box(122), box(1752), nullptr);
-  avl = remove_int(avl, 606);
-  avl = gpr_avl_add(avl, box(485), box(1754), nullptr);
-  avl = remove_int(avl, 6);
-  avl = gpr_avl_add(avl, box(329), box(1756), nullptr);
-  avl = gpr_avl_add(avl, box(783), box(1757), nullptr);
-  avl = remove_int(avl, 416);
-  avl = gpr_avl_add(avl, box(656), box(1759), nullptr);
-  avl = gpr_avl_add(avl, box(971), box(1760), nullptr);
-  avl = gpr_avl_add(avl, box(77), box(1761), nullptr);
-  avl = gpr_avl_add(avl, box(942), box(1762), nullptr);
-  avl = remove_int(avl, 361);
-  avl = gpr_avl_add(avl, box(66), box(1764), nullptr);
-  avl = gpr_avl_add(avl, box(299), box(1765), nullptr);
-  avl = gpr_avl_add(avl, box(929), box(1766), nullptr);
-  avl = gpr_avl_add(avl, box(797), box(1767), nullptr);
-  avl = remove_int(avl, 869);
-  avl = remove_int(avl, 907);
-  avl = gpr_avl_add(avl, box(870), box(1770), nullptr);
-  avl = remove_int(avl, 580);
-  avl = remove_int(avl, 120);
-  avl = gpr_avl_add(avl, box(913), box(1773), nullptr);
-  avl = remove_int(avl, 480);
-  avl = gpr_avl_add(avl, box(489), box(1775), nullptr);
-  avl = remove_int(avl, 845);
-  avl = gpr_avl_add(avl, box(896), box(1777), nullptr);
-  avl = remove_int(avl, 567);
-  avl = remove_int(avl, 427);
-  avl = gpr_avl_add(avl, box(443), box(1780), nullptr);
-  avl = gpr_avl_add(avl, box(3), box(1781), nullptr);
-  avl = remove_int(avl, 12);
-  avl = gpr_avl_add(avl, box(376), box(1783), nullptr);
-  avl = gpr_avl_add(avl, box(155), box(1784), nullptr);
-  avl = gpr_avl_add(avl, box(188), box(1785), nullptr);
-  avl = gpr_avl_add(avl, box(149), box(1786), nullptr);
-  avl = gpr_avl_add(avl, box(178), box(1787), nullptr);
-  avl = remove_int(avl, 84);
-  avl = gpr_avl_add(avl, box(805), box(1789), nullptr);
-  avl = gpr_avl_add(avl, box(612), box(1790), nullptr);
-  avl = remove_int(avl, 991);
-  avl = gpr_avl_add(avl, box(837), box(1792), nullptr);
-  avl = remove_int(avl, 173);
-  avl = remove_int(avl, 72);
-  avl = gpr_avl_add(avl, box(1014), box(1795), nullptr);
-  avl = remove_int(avl, 303);
-  avl = gpr_avl_add(avl, box(865), box(1797), nullptr);
-  avl = gpr_avl_add(avl, box(793), box(1798), nullptr);
-  avl = remove_int(avl, 173);
-  avl = remove_int(avl, 477);
-  avl = gpr_avl_add(avl, box(950), box(1801), nullptr);
-  avl = gpr_avl_add(avl, box(105), box(1802), nullptr);
-  avl = gpr_avl_add(avl, box(895), box(1803), nullptr);
-  avl = gpr_avl_add(avl, box(171), box(1804), nullptr);
-  avl = gpr_avl_add(avl, box(753), box(1805), nullptr);
-  avl = gpr_avl_add(avl, box(946), box(1806), nullptr);
-  avl = remove_int(avl, 194);
-  avl = remove_int(avl, 559);
-  avl = remove_int(avl, 116);
-  avl = gpr_avl_add(avl, box(968), box(1810), nullptr);
-  avl = remove_int(avl, 124);
-  avl = remove_int(avl, 99);
-  avl = gpr_avl_add(avl, box(563), box(1813), nullptr);
-  avl = remove_int(avl, 182);
-  avl = gpr_avl_add(avl, box(816), box(1815), nullptr);
-  avl = remove_int(avl, 73);
-  avl = remove_int(avl, 261);
-  avl = gpr_avl_add(avl, box(847), box(1818), nullptr);
-  avl = gpr_avl_add(avl, box(368), box(1819), nullptr);
-  avl = gpr_avl_add(avl, box(808), box(1820), nullptr);
-  avl = gpr_avl_add(avl, box(779), box(1821), nullptr);
-  avl = remove_int(avl, 818);
-  avl = gpr_avl_add(avl, box(466), box(1823), nullptr);
-  avl = remove_int(avl, 316);
-  avl = gpr_avl_add(avl, box(986), box(1825), nullptr);
-  avl = gpr_avl_add(avl, box(688), box(1826), nullptr);
-  avl = gpr_avl_add(avl, box(509), box(1827), nullptr);
-  avl = gpr_avl_add(avl, box(51), box(1828), nullptr);
-  avl = remove_int(avl, 655);
-  avl = remove_int(avl, 785);
-  avl = remove_int(avl, 893);
-  avl = gpr_avl_add(avl, box(167), box(1832), nullptr);
-  avl = remove_int(avl, 13);
-  avl = remove_int(avl, 263);
-  avl = gpr_avl_add(avl, box(1009), box(1835), nullptr);
-  avl = remove_int(avl, 480);
-  avl = remove_int(avl, 778);
-  avl = remove_int(avl, 713);
-  avl = remove_int(avl, 628);
-  avl = gpr_avl_add(avl, box(803), box(1840), nullptr);
-  avl = remove_int(avl, 267);
-  avl = gpr_avl_add(avl, box(676), box(1842), nullptr);
-  avl = gpr_avl_add(avl, box(231), box(1843), nullptr);
-  avl = gpr_avl_add(avl, box(824), box(1844), nullptr);
-  avl = remove_int(avl, 961);
-  avl = gpr_avl_add(avl, box(311), box(1846), nullptr);
-  avl = gpr_avl_add(avl, box(420), box(1847), nullptr);
-  avl = gpr_avl_add(avl, box(960), box(1848), nullptr);
-  avl = gpr_avl_add(avl, box(468), box(1849), nullptr);
-  avl = gpr_avl_add(avl, box(815), box(1850), nullptr);
-  avl = remove_int(avl, 247);
-  avl = remove_int(avl, 194);
-  avl = gpr_avl_add(avl, box(546), box(1853), nullptr);
-  avl = remove_int(avl, 222);
-  avl = remove_int(avl, 914);
-  avl = remove_int(avl, 741);
-  avl = gpr_avl_add(avl, box(470), box(1857), nullptr);
-  avl = gpr_avl_add(avl, box(933), box(1858), nullptr);
-  avl = gpr_avl_add(avl, box(97), box(1859), nullptr);
-  avl = remove_int(avl, 564);
-  avl = remove_int(avl, 295);
-  avl = gpr_avl_add(avl, box(864), box(1862), nullptr);
-  avl = remove_int(avl, 329);
-  avl = gpr_avl_add(avl, box(124), box(1864), nullptr);
-  avl = gpr_avl_add(avl, box(1000), box(1865), nullptr);
-  avl = gpr_avl_add(avl, box(228), box(1866), nullptr);
-  avl = gpr_avl_add(avl, box(187), box(1867), nullptr);
-  avl = remove_int(avl, 224);
-  avl = remove_int(avl, 306);
-  avl = remove_int(avl, 884);
-  avl = gpr_avl_add(avl, box(449), box(1871), nullptr);
-  avl = gpr_avl_add(avl, box(353), box(1872), nullptr);
-  avl = gpr_avl_add(avl, box(994), box(1873), nullptr);
-  avl = gpr_avl_add(avl, box(596), box(1874), nullptr);
-  avl = gpr_avl_add(avl, box(996), box(1875), nullptr);
-  avl = gpr_avl_add(avl, box(101), box(1876), nullptr);
-  avl = gpr_avl_add(avl, box(1012), box(1877), nullptr);
-  avl = gpr_avl_add(avl, box(982), box(1878), nullptr);
-  avl = gpr_avl_add(avl, box(742), box(1879), nullptr);
-  avl = remove_int(avl, 92);
-  avl = remove_int(avl, 1022);
-  avl = gpr_avl_add(avl, box(941), box(1882), nullptr);
-  avl = remove_int(avl, 742);
-  avl = remove_int(avl, 919);
-  avl = gpr_avl_add(avl, box(588), box(1885), nullptr);
-  avl = remove_int(avl, 221);
-  avl = gpr_avl_add(avl, box(356), box(1887), nullptr);
-  avl = gpr_avl_add(avl, box(932), box(1888), nullptr);
-  avl = remove_int(avl, 837);
-  avl = gpr_avl_add(avl, box(394), box(1890), nullptr);
-  avl = gpr_avl_add(avl, box(642), box(1891), nullptr);
-  avl = gpr_avl_add(avl, box(52), box(1892), nullptr);
-  avl = gpr_avl_add(avl, box(437), box(1893), nullptr);
-  avl = gpr_avl_add(avl, box(948), box(1894), nullptr);
-  avl = gpr_avl_add(avl, box(93), box(1895), nullptr);
-  avl = remove_int(avl, 873);
-  avl = remove_int(avl, 336);
-  avl = remove_int(avl, 277);
-  avl = remove_int(avl, 932);
-  avl = gpr_avl_add(avl, box(80), box(1900), nullptr);
-  avl = gpr_avl_add(avl, box(952), box(1901), nullptr);
-  avl = gpr_avl_add(avl, box(510), box(1902), nullptr);
-  avl = remove_int(avl, 876);
-  avl = remove_int(avl, 612);
-  avl = gpr_avl_add(avl, box(923), box(1905), nullptr);
-  avl = gpr_avl_add(avl, box(475), box(1906), nullptr);
-  avl = remove_int(avl, 478);
-  avl = remove_int(avl, 148);
-  avl = gpr_avl_add(avl, box(538), box(1909), nullptr);
-  avl = remove_int(avl, 47);
-  avl = gpr_avl_add(avl, box(89), box(1911), nullptr);
-  avl = remove_int(avl, 723);
-  avl = gpr_avl_add(avl, box(687), box(1913), nullptr);
-  avl = gpr_avl_add(avl, box(480), box(1914), nullptr);
-  avl = gpr_avl_add(avl, box(149), box(1915), nullptr);
-  avl = remove_int(avl, 68);
-  avl = remove_int(avl, 862);
-  avl = remove_int(avl, 363);
-  avl = gpr_avl_add(avl, box(996), box(1919), nullptr);
-  avl = remove_int(avl, 380);
-  avl = gpr_avl_add(avl, box(957), box(1921), nullptr);
-  avl = remove_int(avl, 413);
-  avl = gpr_avl_add(avl, box(360), box(1923), nullptr);
-  avl = gpr_avl_add(avl, box(304), box(1924), nullptr);
-  avl = gpr_avl_add(avl, box(634), box(1925), nullptr);
-  avl = gpr_avl_add(avl, box(506), box(1926), nullptr);
-  avl = remove_int(avl, 248);
-  avl = gpr_avl_add(avl, box(124), box(1928), nullptr);
-  avl = gpr_avl_add(avl, box(181), box(1929), nullptr);
-  avl = remove_int(avl, 507);
-  avl = gpr_avl_add(avl, box(141), box(1931), nullptr);
-  avl = remove_int(avl, 409);
-  avl = remove_int(avl, 129);
-  avl = remove_int(avl, 694);
-  avl = remove_int(avl, 723);
-  avl = gpr_avl_add(avl, box(998), box(1936), nullptr);
-  avl = gpr_avl_add(avl, box(906), box(1937), nullptr);
-  avl = gpr_avl_add(avl, box(44), box(1938), nullptr);
-  avl = remove_int(avl, 949);
-  avl = remove_int(avl, 117);
-  avl = gpr_avl_add(avl, box(700), box(1941), nullptr);
-  avl = gpr_avl_add(avl, box(258), box(1942), nullptr);
-  avl = remove_int(avl, 828);
-  avl = gpr_avl_add(avl, box(860), box(1944), nullptr);
-  avl = gpr_avl_add(avl, box(987), box(1945), nullptr);
-  avl = gpr_avl_add(avl, box(316), box(1946), nullptr);
-  avl = gpr_avl_add(avl, box(919), box(1947), nullptr);
-  avl = remove_int(avl, 84);
-  avl = gpr_avl_add(avl, box(473), box(1949), nullptr);
-  avl = remove_int(avl, 127);
-  avl = remove_int(avl, 829);
-  avl = remove_int(avl, 829);
-  avl = gpr_avl_add(avl, box(488), box(1953), nullptr);
-  avl = gpr_avl_add(avl, box(954), box(1954), nullptr);
-  avl = remove_int(avl, 198);
-  avl = remove_int(avl, 972);
-  avl = remove_int(avl, 670);
-  avl = gpr_avl_add(avl, box(822), box(1958), nullptr);
-  avl = remove_int(avl, 589);
-  avl = remove_int(avl, 459);
-  avl = gpr_avl_add(avl, box(1003), box(1961), nullptr);
-  avl = gpr_avl_add(avl, box(657), box(1962), nullptr);
-  avl = gpr_avl_add(avl, box(477), box(1963), nullptr);
-  avl = gpr_avl_add(avl, box(923), box(1964), nullptr);
-  avl = remove_int(avl, 496);
-  avl = remove_int(avl, 99);
-  avl = gpr_avl_add(avl, box(127), box(1967), nullptr);
-  avl = gpr_avl_add(avl, box(1013), box(1968), nullptr);
-  avl = gpr_avl_add(avl, box(778), box(1969), nullptr);
-  avl = remove_int(avl, 5);
-  avl = remove_int(avl, 990);
-  avl = remove_int(avl, 850);
-  avl = remove_int(avl, 160);
-  avl = remove_int(avl, 86);
-  avl = gpr_avl_add(avl, box(283), box(1975), nullptr);
-  avl = remove_int(avl, 278);
-  avl = remove_int(avl, 297);
-  avl = remove_int(avl, 137);
-  avl = remove_int(avl, 653);
-  avl = gpr_avl_add(avl, box(702), box(1980), nullptr);
-  avl = remove_int(avl, 63);
-  avl = remove_int(avl, 427);
-  avl = remove_int(avl, 706);
-  avl = remove_int(avl, 806);
-  avl = gpr_avl_add(avl, box(335), box(1985), nullptr);
-  avl = gpr_avl_add(avl, box(412), box(1986), nullptr);
-  avl = remove_int(avl, 766);
-  avl = remove_int(avl, 937);
-  avl = remove_int(avl, 886);
-  avl = remove_int(avl, 652);
-  avl = gpr_avl_add(avl, box(545), box(1991), nullptr);
-  avl = gpr_avl_add(avl, box(408), box(1992), nullptr);
-  avl = gpr_avl_add(avl, box(841), box(1993), nullptr);
-  avl = remove_int(avl, 593);
-  avl = gpr_avl_add(avl, box(582), box(1995), nullptr);
-  avl = gpr_avl_add(avl, box(597), box(1996), nullptr);
-  avl = remove_int(avl, 49);
-  avl = remove_int(avl, 835);
-  avl = gpr_avl_add(avl, box(417), box(1999), nullptr);
-  avl = gpr_avl_add(avl, box(191), box(2000), nullptr);
-  avl = remove_int(avl, 406);
-  avl = gpr_avl_add(avl, box(30), box(2002), nullptr);
-  avl = remove_int(avl, 841);
-  avl = remove_int(avl, 50);
-  avl = gpr_avl_add(avl, box(967), box(2005), nullptr);
-  avl = gpr_avl_add(avl, box(849), box(2006), nullptr);
-  avl = remove_int(avl, 608);
-  avl = gpr_avl_add(avl, box(306), box(2008), nullptr);
-  avl = remove_int(avl, 779);
-  avl = gpr_avl_add(avl, box(897), box(2010), nullptr);
-  avl = gpr_avl_add(avl, box(147), box(2011), nullptr);
-  avl = remove_int(avl, 982);
-  avl = gpr_avl_add(avl, box(470), box(2013), nullptr);
-  avl = remove_int(avl, 951);
-  avl = gpr_avl_add(avl, box(388), box(2015), nullptr);
-  avl = remove_int(avl, 616);
-  avl = remove_int(avl, 721);
-  avl = remove_int(avl, 942);
-  avl = remove_int(avl, 589);
-  avl = gpr_avl_add(avl, box(218), box(2020), nullptr);
-  avl = remove_int(avl, 671);
-  avl = gpr_avl_add(avl, box(1020), box(2022), nullptr);
-  avl = remove_int(avl, 277);
-  avl = gpr_avl_add(avl, box(681), box(2024), nullptr);
-  avl = gpr_avl_add(avl, box(179), box(2025), nullptr);
-  avl = gpr_avl_add(avl, box(370), box(2026), nullptr);
-  avl = gpr_avl_add(avl, box(0), box(2027), nullptr);
-  avl = remove_int(avl, 523);
-  avl = gpr_avl_add(avl, box(99), box(2029), nullptr);
-  avl = gpr_avl_add(avl, box(334), box(2030), nullptr);
-  avl = gpr_avl_add(avl, box(569), box(2031), nullptr);
-  avl = gpr_avl_add(avl, box(257), box(2032), nullptr);
-  avl = remove_int(avl, 572);
-  avl = gpr_avl_add(avl, box(805), box(2034), nullptr);
-  avl = gpr_avl_add(avl, box(143), box(2035), nullptr);
-  avl = gpr_avl_add(avl, box(670), box(2036), nullptr);
-  avl = remove_int(avl, 42);
-  avl = gpr_avl_add(avl, box(46), box(2038), nullptr);
-  avl = remove_int(avl, 970);
-  avl = gpr_avl_add(avl, box(353), box(2040), nullptr);
-  avl = remove_int(avl, 258);
-  avl = gpr_avl_add(avl, box(451), box(2042), nullptr);
-  avl = gpr_avl_add(avl, box(28), box(2043), nullptr);
-  avl = gpr_avl_add(avl, box(729), box(2044), nullptr);
-  avl = gpr_avl_add(avl, box(401), box(2045), nullptr);
-  avl = gpr_avl_add(avl, box(614), box(2046), nullptr);
-  avl = remove_int(avl, 990);
-  avl = remove_int(avl, 212);
-  avl = remove_int(avl, 22);
-  avl = remove_int(avl, 677);
-  avl = gpr_avl_add(avl, box(1016), box(2051), nullptr);
-  avl = gpr_avl_add(avl, box(980), box(2052), nullptr);
-  avl = gpr_avl_add(avl, box(990), box(2053), nullptr);
-  avl = gpr_avl_add(avl, box(355), box(2054), nullptr);
-  avl = remove_int(avl, 730);
-  avl = remove_int(avl, 37);
-  avl = gpr_avl_add(avl, box(407), box(2057), nullptr);
-  avl = gpr_avl_add(avl, box(222), box(2058), nullptr);
-  avl = gpr_avl_add(avl, box(439), box(2059), nullptr);
-  avl = gpr_avl_add(avl, box(563), box(2060), nullptr);
-  avl = remove_int(avl, 992);
-  avl = remove_int(avl, 786);
-  avl = gpr_avl_add(avl, box(1), box(2063), nullptr);
-  avl = gpr_avl_add(avl, box(473), box(2064), nullptr);
-  avl = gpr_avl_add(avl, box(992), box(2065), nullptr);
-  avl = remove_int(avl, 190);
-  avl = remove_int(avl, 450);
-  avl = remove_int(avl, 1020);
-  avl = remove_int(avl, 149);
-  avl = gpr_avl_add(avl, box(329), box(2070), nullptr);
-  avl = gpr_avl_add(avl, box(35), box(2071), nullptr);
-  avl = remove_int(avl, 843);
-  avl = gpr_avl_add(avl, box(855), box(2073), nullptr);
-  avl = remove_int(avl, 878);
-  avl = gpr_avl_add(avl, box(993), box(2075), nullptr);
-  avl = gpr_avl_add(avl, box(87), box(2076), nullptr);
-  avl = gpr_avl_add(avl, box(572), box(2077), nullptr);
-  avl = remove_int(avl, 896);
-  avl = gpr_avl_add(avl, box(849), box(2079), nullptr);
-  avl = remove_int(avl, 597);
-  avl = gpr_avl_add(avl, box(472), box(2081), nullptr);
-  avl = remove_int(avl, 778);
-  avl = remove_int(avl, 934);
-  avl = remove_int(avl, 314);
-  avl = gpr_avl_add(avl, box(101), box(2085), nullptr);
-  avl = remove_int(avl, 938);
-  avl = remove_int(avl, 1010);
-  avl = gpr_avl_add(avl, box(579), box(2088), nullptr);
-  avl = remove_int(avl, 798);
-  avl = remove_int(avl, 88);
-  avl = gpr_avl_add(avl, box(851), box(2091), nullptr);
-  avl = remove_int(avl, 705);
-  avl = gpr_avl_add(avl, box(26), box(2093), nullptr);
-  avl = remove_int(avl, 973);
-  avl = gpr_avl_add(avl, box(923), box(2095), nullptr);
-  avl = remove_int(avl, 668);
-  avl = gpr_avl_add(avl, box(310), box(2097), nullptr);
-  avl = gpr_avl_add(avl, box(269), box(2098), nullptr);
-  avl = remove_int(avl, 173);
-  avl = gpr_avl_add(avl, box(279), box(2100), nullptr);
-  avl = remove_int(avl, 203);
-  avl = gpr_avl_add(avl, box(411), box(2102), nullptr);
-  avl = remove_int(avl, 950);
-  avl = gpr_avl_add(avl, box(6), box(2104), nullptr);
-  avl = remove_int(avl, 400);
-  avl = remove_int(avl, 468);
-  avl = remove_int(avl, 271);
-  avl = gpr_avl_add(avl, box(627), box(2108), nullptr);
-  avl = remove_int(avl, 727);
-  avl = remove_int(avl, 148);
-  avl = remove_int(avl, 98);
-  avl = remove_int(avl, 997);
-  avl = remove_int(avl, 215);
-  avl = remove_int(avl, 628);
-  avl = remove_int(avl, 826);
-  avl = remove_int(avl, 664);
-  avl = gpr_avl_add(avl, box(76), box(2117), nullptr);
-  avl = remove_int(avl, 194);
-  avl = remove_int(avl, 18);
-  avl = gpr_avl_add(avl, box(727), box(2120), nullptr);
-  avl = remove_int(avl, 295);
-  avl = gpr_avl_add(avl, box(645), box(2122), nullptr);
-  avl = remove_int(avl, 321);
-  avl = remove_int(avl, 863);
-  avl = gpr_avl_add(avl, box(824), box(2125), nullptr);
-  avl = gpr_avl_add(avl, box(651), box(2126), nullptr);
-  avl = gpr_avl_add(avl, box(804), box(2127), nullptr);
-  avl = remove_int(avl, 307);
-  avl = gpr_avl_add(avl, box(867), box(2129), nullptr);
-  avl = remove_int(avl, 384);
-  avl = gpr_avl_add(avl, box(819), box(2131), nullptr);
-  avl = remove_int(avl, 674);
-  avl = gpr_avl_add(avl, box(76), box(2133), nullptr);
-  avl = remove_int(avl, 898);
-  avl = gpr_avl_add(avl, box(45), box(2135), nullptr);
-  avl = gpr_avl_add(avl, box(512), box(2136), nullptr);
-  avl = remove_int(avl, 773);
-  avl = remove_int(avl, 907);
-  avl = remove_int(avl, 382);
-  avl = remove_int(avl, 95);
-  avl = remove_int(avl, 734);
-  avl = remove_int(avl, 81);
-  avl = gpr_avl_add(avl, box(348), box(2143), nullptr);
-  avl = remove_int(avl, 509);
-  avl = remove_int(avl, 301);
-  avl = gpr_avl_add(avl, box(861), box(2146), nullptr);
-  avl = gpr_avl_add(avl, box(918), box(2147), nullptr);
-  avl = remove_int(avl, 992);
-  avl = gpr_avl_add(avl, box(356), box(2149), nullptr);
-  avl = remove_int(avl, 64);
-  avl = remove_int(avl, 444);
-  avl = remove_int(avl, 741);
-  avl = gpr_avl_add(avl, box(710), box(2153), nullptr);
-  avl = gpr_avl_add(avl, box(264), box(2154), nullptr);
-  avl = remove_int(avl, 347);
-  avl = remove_int(avl, 250);
-  avl = gpr_avl_add(avl, box(82), box(2157), nullptr);
-  avl = gpr_avl_add(avl, box(571), box(2158), nullptr);
-  avl = remove_int(avl, 721);
-  avl = remove_int(avl, 622);
-  avl = gpr_avl_add(avl, box(950), box(2161), nullptr);
-  avl = gpr_avl_add(avl, box(94), box(2162), nullptr);
-  avl = remove_int(avl, 970);
-  avl = gpr_avl_add(avl, box(815), box(2164), nullptr);
-  avl = remove_int(avl, 930);
-  avl = remove_int(avl, 703);
-  avl = gpr_avl_add(avl, box(432), box(2167), nullptr);
-  avl = remove_int(avl, 544);
-  avl = gpr_avl_add(avl, box(21), box(2169), nullptr);
-  avl = gpr_avl_add(avl, box(186), box(2170), nullptr);
-  avl = remove_int(avl, 143);
-  avl = gpr_avl_add(avl, box(425), box(2172), nullptr);
-  avl = remove_int(avl, 769);
-  avl = gpr_avl_add(avl, box(656), box(2174), nullptr);
-  avl = remove_int(avl, 29);
-  avl = gpr_avl_add(avl, box(464), box(2176), nullptr);
-  avl = remove_int(avl, 713);
-  avl = gpr_avl_add(avl, box(800), box(2178), nullptr);
-  avl = remove_int(avl, 621);
-  avl = gpr_avl_add(avl, box(962), box(2180), nullptr);
-  avl = remove_int(avl, 448);
-  avl = gpr_avl_add(avl, box(878), box(2182), nullptr);
-  avl = remove_int(avl, 39);
-  avl = remove_int(avl, 999);
-  avl = gpr_avl_add(avl, box(182), box(2185), nullptr);
-  avl = gpr_avl_add(avl, box(429), box(2186), nullptr);
-  avl = gpr_avl_add(avl, box(598), box(2187), nullptr);
-  avl = remove_int(avl, 551);
-  avl = gpr_avl_add(avl, box(827), box(2189), nullptr);
-  avl = gpr_avl_add(avl, box(809), box(2190), nullptr);
-  avl = remove_int(avl, 438);
-  avl = remove_int(avl, 811);
-  avl = gpr_avl_add(avl, box(808), box(2193), nullptr);
-  avl = gpr_avl_add(avl, box(788), box(2194), nullptr);
-  avl = remove_int(avl, 156);
-  avl = gpr_avl_add(avl, box(933), box(2196), nullptr);
-  avl = gpr_avl_add(avl, box(344), box(2197), nullptr);
-  avl = remove_int(avl, 460);
-  avl = gpr_avl_add(avl, box(161), box(2199), nullptr);
-  avl = gpr_avl_add(avl, box(444), box(2200), nullptr);
-  avl = remove_int(avl, 597);
-  avl = remove_int(avl, 668);
-  avl = gpr_avl_add(avl, box(703), box(2203), nullptr);
-  avl = remove_int(avl, 515);
-  avl = gpr_avl_add(avl, box(380), box(2205), nullptr);
-  avl = gpr_avl_add(avl, box(338), box(2206), nullptr);
-  avl = remove_int(avl, 550);
-  avl = remove_int(avl, 946);
-  avl = remove_int(avl, 714);
-  avl = remove_int(avl, 739);
-  avl = gpr_avl_add(avl, box(413), box(2211), nullptr);
-  avl = remove_int(avl, 450);
-  avl = gpr_avl_add(avl, box(411), box(2213), nullptr);
-  avl = gpr_avl_add(avl, box(117), box(2214), nullptr);
-  avl = gpr_avl_add(avl, box(322), box(2215), nullptr);
-  avl = gpr_avl_add(avl, box(915), box(2216), nullptr);
-  avl = gpr_avl_add(avl, box(410), box(2217), nullptr);
-  avl = gpr_avl_add(avl, box(66), box(2218), nullptr);
-  avl = remove_int(avl, 756);
-  avl = remove_int(avl, 596);
-  avl = gpr_avl_add(avl, box(882), box(2221), nullptr);
-  avl = gpr_avl_add(avl, box(930), box(2222), nullptr);
-  avl = gpr_avl_add(avl, box(36), box(2223), nullptr);
-  avl = remove_int(avl, 742);
-  avl = gpr_avl_add(avl, box(539), box(2225), nullptr);
-  avl = gpr_avl_add(avl, box(596), box(2226), nullptr);
-  avl = remove_int(avl, 82);
-  avl = remove_int(avl, 686);
-  avl = remove_int(avl, 933);
-  avl = remove_int(avl, 42);
-  avl = remove_int(avl, 340);
-  avl = gpr_avl_add(avl, box(126), box(2232), nullptr);
-  avl = gpr_avl_add(avl, box(493), box(2233), nullptr);
-  avl = gpr_avl_add(avl, box(839), box(2234), nullptr);
-  avl = remove_int(avl, 774);
-  avl = gpr_avl_add(avl, box(337), box(2236), nullptr);
-  avl = remove_int(avl, 322);
-  avl = gpr_avl_add(avl, box(16), box(2238), nullptr);
-  avl = remove_int(avl, 73);
-  avl = remove_int(avl, 85);
-  avl = remove_int(avl, 191);
-  avl = remove_int(avl, 541);
-  avl = gpr_avl_add(avl, box(704), box(2243), nullptr);
-  avl = remove_int(avl, 767);
-  avl = remove_int(avl, 1006);
-  avl = remove_int(avl, 844);
-  avl = remove_int(avl, 742);
-  avl = gpr_avl_add(avl, box(48), box(2248), nullptr);
-  avl = gpr_avl_add(avl, box(138), box(2249), nullptr);
-  avl = gpr_avl_add(avl, box(437), box(2250), nullptr);
-  avl = gpr_avl_add(avl, box(275), box(2251), nullptr);
-  avl = remove_int(avl, 520);
-  avl = gpr_avl_add(avl, box(1019), box(2253), nullptr);
-  avl = remove_int(avl, 955);
-  avl = gpr_avl_add(avl, box(270), box(2255), nullptr);
-  avl = remove_int(avl, 680);
-  avl = remove_int(avl, 698);
-  avl = gpr_avl_add(avl, box(735), box(2258), nullptr);
-  avl = gpr_avl_add(avl, box(400), box(2259), nullptr);
-  avl = remove_int(avl, 991);
-  avl = gpr_avl_add(avl, box(263), box(2261), nullptr);
-  avl = remove_int(avl, 704);
-  avl = gpr_avl_add(avl, box(757), box(2263), nullptr);
-  avl = remove_int(avl, 194);
-  avl = remove_int(avl, 616);
-  avl = remove_int(avl, 784);
-  avl = gpr_avl_add(avl, box(382), box(2267), nullptr);
-  avl = gpr_avl_add(avl, box(464), box(2268), nullptr);
-  avl = gpr_avl_add(avl, box(817), box(2269), nullptr);
-  avl = remove_int(avl, 445);
-  avl = gpr_avl_add(avl, box(412), box(2271), nullptr);
-  avl = remove_int(avl, 525);
-  avl = gpr_avl_add(avl, box(299), box(2273), nullptr);
-  avl = gpr_avl_add(avl, box(464), box(2274), nullptr);
-  avl = gpr_avl_add(avl, box(715), box(2275), nullptr);
-  avl = remove_int(avl, 58);
-  avl = remove_int(avl, 218);
-  avl = gpr_avl_add(avl, box(961), box(2278), nullptr);
-  avl = gpr_avl_add(avl, box(491), box(2279), nullptr);
-  avl = remove_int(avl, 846);
-  avl = gpr_avl_add(avl, box(762), box(2281), nullptr);
-  avl = remove_int(avl, 974);
-  avl = remove_int(avl, 887);
-  avl = gpr_avl_add(avl, box(498), box(2284), nullptr);
-  avl = remove_int(avl, 810);
-  avl = remove_int(avl, 743);
-  avl = remove_int(avl, 22);
-  avl = remove_int(avl, 284);
-  avl = gpr_avl_add(avl, box(482), box(2289), nullptr);
-  avl = gpr_avl_add(avl, box(1021), box(2290), nullptr);
-  avl = remove_int(avl, 155);
-  avl = remove_int(avl, 128);
-  avl = gpr_avl_add(avl, box(819), box(2293), nullptr);
-  avl = gpr_avl_add(avl, box(324), box(2294), nullptr);
-  avl = remove_int(avl, 196);
-  avl = remove_int(avl, 370);
-  avl = remove_int(avl, 753);
-  avl = remove_int(avl, 56);
-  avl = remove_int(avl, 735);
-  avl = gpr_avl_add(avl, box(272), box(2300), nullptr);
-  avl = gpr_avl_add(avl, box(474), box(2301), nullptr);
-  avl = gpr_avl_add(avl, box(719), box(2302), nullptr);
-  avl = gpr_avl_add(avl, box(236), box(2303), nullptr);
-  avl = remove_int(avl, 818);
-  avl = gpr_avl_add(avl, box(727), box(2305), nullptr);
-  avl = remove_int(avl, 892);
-  avl = remove_int(avl, 871);
-  avl = remove_int(avl, 231);
-  avl = gpr_avl_add(avl, box(62), box(2309), nullptr);
-  avl = gpr_avl_add(avl, box(953), box(2310), nullptr);
-  avl = remove_int(avl, 701);
-  avl = gpr_avl_add(avl, box(193), box(2312), nullptr);
-  avl = remove_int(avl, 619);
-  avl = remove_int(avl, 22);
-  avl = remove_int(avl, 804);
-  avl = remove_int(avl, 851);
-  avl = gpr_avl_add(avl, box(286), box(2317), nullptr);
-  avl = gpr_avl_add(avl, box(751), box(2318), nullptr);
-  avl = remove_int(avl, 525);
-  avl = gpr_avl_add(avl, box(217), box(2320), nullptr);
-  avl = remove_int(avl, 336);
-  avl = gpr_avl_add(avl, box(86), box(2322), nullptr);
-  avl = gpr_avl_add(avl, box(81), box(2323), nullptr);
-  avl = gpr_avl_add(avl, box(850), box(2324), nullptr);
-  avl = remove_int(avl, 872);
-  avl = gpr_avl_add(avl, box(402), box(2326), nullptr);
-  avl = gpr_avl_add(avl, box(54), box(2327), nullptr);
-  avl = gpr_avl_add(avl, box(980), box(2328), nullptr);
-  avl = gpr_avl_add(avl, box(845), box(2329), nullptr);
-  avl = remove_int(avl, 1004);
-  avl = remove_int(avl, 273);
-  avl = remove_int(avl, 879);
-  avl = gpr_avl_add(avl, box(354), box(2333), nullptr);
-  avl = gpr_avl_add(avl, box(58), box(2334), nullptr);
-  avl = gpr_avl_add(avl, box(127), box(2335), nullptr);
-  avl = remove_int(avl, 84);
-  avl = gpr_avl_add(avl, box(360), box(2337), nullptr);
-  avl = remove_int(avl, 648);
-  avl = remove_int(avl, 488);
-  avl = remove_int(avl, 585);
-  avl = remove_int(avl, 230);
-  avl = gpr_avl_add(avl, box(887), box(2342), nullptr);
-  avl = remove_int(avl, 558);
-  avl = remove_int(avl, 958);
-  avl = gpr_avl_add(avl, box(822), box(2345), nullptr);
-  avl = remove_int(avl, 1004);
-  avl = remove_int(avl, 747);
-  avl = gpr_avl_add(avl, box(631), box(2348), nullptr);
-  avl = gpr_avl_add(avl, box(442), box(2349), nullptr);
-  avl = remove_int(avl, 957);
-  avl = remove_int(avl, 964);
-  avl = gpr_avl_add(avl, box(10), box(2352), nullptr);
-  avl = remove_int(avl, 189);
-  avl = gpr_avl_add(avl, box(742), box(2354), nullptr);
-  avl = remove_int(avl, 108);
-  avl = gpr_avl_add(avl, box(1014), box(2356), nullptr);
-  avl = remove_int(avl, 266);
-  avl = remove_int(avl, 623);
-  avl = remove_int(avl, 697);
-  avl = gpr_avl_add(avl, box(180), box(2360), nullptr);
-  avl = remove_int(avl, 472);
-  avl = gpr_avl_add(avl, box(567), box(2362), nullptr);
-  avl = remove_int(avl, 1020);
-  avl = remove_int(avl, 273);
-  avl = gpr_avl_add(avl, box(864), box(2365), nullptr);
-  avl = gpr_avl_add(avl, box(1009), box(2366), nullptr);
-  avl = remove_int(avl, 224);
-  avl = remove_int(avl, 81);
-  avl = gpr_avl_add(avl, box(653), box(2369), nullptr);
-  avl = remove_int(avl, 67);
-  avl = remove_int(avl, 102);
-  avl = remove_int(avl, 76);
-  avl = remove_int(avl, 935);
-  avl = remove_int(avl, 169);
-  avl = remove_int(avl, 232);
-  avl = remove_int(avl, 79);
-  avl = gpr_avl_add(avl, box(509), box(2377), nullptr);
-  avl = remove_int(avl, 900);
-  avl = remove_int(avl, 822);
-  avl = remove_int(avl, 945);
-  avl = remove_int(avl, 356);
-  avl = gpr_avl_add(avl, box(443), box(2382), nullptr);
-  avl = gpr_avl_add(avl, box(925), box(2383), nullptr);
-  avl = remove_int(avl, 994);
-  avl = remove_int(avl, 324);
-  avl = gpr_avl_add(avl, box(291), box(2386), nullptr);
-  avl = remove_int(avl, 94);
-  avl = remove_int(avl, 795);
-  avl = remove_int(avl, 42);
-  avl = gpr_avl_add(avl, box(613), box(2390), nullptr);
-  avl = remove_int(avl, 289);
-  avl = gpr_avl_add(avl, box(980), box(2392), nullptr);
-  avl = remove_int(avl, 316);
-  avl = gpr_avl_add(avl, box(281), box(2394), nullptr);
-  avl = gpr_avl_add(avl, box(1006), box(2395), nullptr);
-  avl = remove_int(avl, 776);
-  avl = gpr_avl_add(avl, box(108), box(2397), nullptr);
-  avl = gpr_avl_add(avl, box(918), box(2398), nullptr);
-  avl = remove_int(avl, 721);
-  avl = remove_int(avl, 563);
-  avl = gpr_avl_add(avl, box(925), box(2401), nullptr);
-  avl = remove_int(avl, 448);
-  avl = remove_int(avl, 198);
-  avl = remove_int(avl, 1);
-  avl = gpr_avl_add(avl, box(160), box(2405), nullptr);
-  avl = remove_int(avl, 515);
-  avl = gpr_avl_add(avl, box(284), box(2407), nullptr);
-  avl = gpr_avl_add(avl, box(225), box(2408), nullptr);
-  avl = remove_int(avl, 304);
-  avl = gpr_avl_add(avl, box(714), box(2410), nullptr);
-  avl = gpr_avl_add(avl, box(708), box(2411), nullptr);
-  avl = gpr_avl_add(avl, box(624), box(2412), nullptr);
-  avl = remove_int(avl, 662);
-  avl = remove_int(avl, 825);
-  avl = remove_int(avl, 383);
-  avl = remove_int(avl, 381);
-  avl = gpr_avl_add(avl, box(194), box(2417), nullptr);
-  avl = remove_int(avl, 280);
-  avl = remove_int(avl, 25);
-  avl = remove_int(avl, 633);
-  avl = gpr_avl_add(avl, box(897), box(2421), nullptr);
-  avl = remove_int(avl, 636);
-  avl = remove_int(avl, 596);
-  avl = remove_int(avl, 757);
-  avl = remove_int(avl, 343);
-  avl = remove_int(avl, 162);
-  avl = remove_int(avl, 913);
-  avl = remove_int(avl, 843);
-  avl = remove_int(avl, 280);
-  avl = remove_int(avl, 911);
-  avl = gpr_avl_add(avl, box(1008), box(2431), nullptr);
-  avl = remove_int(avl, 948);
-  avl = remove_int(avl, 74);
-  avl = remove_int(avl, 571);
-  avl = gpr_avl_add(avl, box(486), box(2435), nullptr);
-  avl = gpr_avl_add(avl, box(285), box(2436), nullptr);
-  avl = remove_int(avl, 304);
-  avl = remove_int(avl, 516);
-  avl = gpr_avl_add(avl, box(758), box(2439), nullptr);
-  avl = gpr_avl_add(avl, box(776), box(2440), nullptr);
-  avl = remove_int(avl, 696);
-  avl = gpr_avl_add(avl, box(104), box(2442), nullptr);
-  avl = gpr_avl_add(avl, box(700), box(2443), nullptr);
-  avl = gpr_avl_add(avl, box(114), box(2444), nullptr);
-  avl = gpr_avl_add(avl, box(567), box(2445), nullptr);
-  avl = remove_int(avl, 620);
-  avl = gpr_avl_add(avl, box(270), box(2447), nullptr);
-  avl = remove_int(avl, 730);
-  avl = gpr_avl_add(avl, box(749), box(2449), nullptr);
-  avl = gpr_avl_add(avl, box(443), box(2450), nullptr);
-  avl = remove_int(avl, 457);
-  avl = gpr_avl_add(avl, box(571), box(2452), nullptr);
-  avl = gpr_avl_add(avl, box(626), box(2453), nullptr);
-  avl = remove_int(avl, 638);
-  avl = remove_int(avl, 313);
-
-  gpr_avl_unref(avl, nullptr);
-}
-
-static void test_stress(int amount_of_stress) {
-  int added[1024];
-  int i, j;
-  int deletions = 0;
-  gpr_avl avl;
-
-  unsigned seed = (unsigned)time(nullptr);
-
-  gpr_log(GPR_DEBUG, "test_stress amount=%d seed=%u", amount_of_stress, seed);
-
-  srand((unsigned)time(nullptr));
-  avl = gpr_avl_create(&int_int_vtable);
-
-  memset(added, 0, sizeof(added));
-
-  for (i = 1; deletions < amount_of_stress; i++) {
-    int idx = rand() % (int)GPR_ARRAY_SIZE(added);
-    GPR_ASSERT(i);
-    if (rand() < RAND_MAX / 2) {
-      added[idx] = i;
-      printf("avl = gpr_avl_add(avl, box(%d), box(%d), NULL); /* d=%d */\n",
-             idx, i, deletions);
-      avl = gpr_avl_add(avl, box(idx), box(i), nullptr);
-    } else {
-      deletions += (added[idx] != 0);
-      added[idx] = 0;
-      printf("avl = remove_int(avl, %d); /* d=%d */\n", idx, deletions);
-      avl = remove_int(avl, idx);
-    }
-    for (j = 0; j < (int)GPR_ARRAY_SIZE(added); j++) {
-      if (added[j] != 0) {
-        check_get(avl, j, added[j]);
-      } else {
-        check_negget(avl, j);
-      }
-    }
-  }
-
-  gpr_avl_unref(avl, nullptr);
-}
-
-int main(int argc, char* argv[]) {
-  grpc_test_init(argc, argv);
-
-  test_get();
-  test_ll();
-  test_lr();
-  test_rr();
-  test_rl();
-  test_unbalanced();
-  test_replace();
-  test_remove();
-  test_badcase1();
-  test_badcase2();
-  test_badcase3();
-  test_stress(10);
-
-  return 0;
-}
diff --git a/test/core/gpr/cpu_test.cc b/test/core/gpr/cpu_test.cc
index 87cdc0f..1052d40 100644
--- a/test/core/gpr/cpu_test.cc
+++ b/test/core/gpr/cpu_test.cc
@@ -21,14 +21,17 @@
    gpr_cpu_current_cpu()
 */
 
-#include <grpc/support/alloc.h>
 #include <grpc/support/cpu.h>
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/time.h>
+
 #include <stdio.h>
 #include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/gprpp/thd.h"
 #include "test/core/util/test_config.h"
 
 /* Test structure is essentially:
@@ -62,7 +65,7 @@
 };
 
 static void worker_thread(void* arg) {
-  struct cpu_test* ct = (struct cpu_test*)arg;
+  struct cpu_test* ct = static_cast<struct cpu_test*>(arg);
   uint32_t cpu;
   unsigned r = 12345678;
   unsigned i, j;
@@ -100,24 +103,32 @@
   uint32_t i;
   int cores_seen = 0;
   struct cpu_test ct;
-  gpr_thd_id thd;
   ct.ncores = gpr_cpu_num_cores();
   GPR_ASSERT(ct.ncores > 0);
-  ct.nthreads = (int)ct.ncores * 3;
+  ct.nthreads = static_cast<int>(ct.ncores) * 3;
   ct.used = static_cast<int*>(gpr_malloc(ct.ncores * sizeof(int)));
   memset(ct.used, 0, ct.ncores * sizeof(int));
   gpr_mu_init(&ct.mu);
   gpr_cv_init(&ct.done_cv);
   ct.is_done = 0;
-  for (i = 0; i < ct.ncores * 3; i++) {
-    GPR_ASSERT(
-        gpr_thd_new(&thd, "grpc_cpu_test", &worker_thread, &ct, nullptr));
+
+  uint32_t nthreads = ct.ncores * 3;
+  grpc_core::Thread* thd =
+      static_cast<grpc_core::Thread*>(gpr_malloc(sizeof(*thd) * nthreads));
+
+  for (i = 0; i < nthreads; i++) {
+    thd[i] = grpc_core::Thread("grpc_cpu_test", &worker_thread, &ct);
+    thd[i].Start();
   }
   gpr_mu_lock(&ct.mu);
   while (!ct.is_done) {
     gpr_cv_wait(&ct.done_cv, &ct.mu, gpr_inf_future(GPR_CLOCK_MONOTONIC));
   }
   gpr_mu_unlock(&ct.mu);
+  for (i = 0; i < nthreads; i++) {
+    thd[i].Join();
+  }
+  gpr_free(thd);
   fprintf(stderr, "Saw cores [");
   fflush(stderr);
   for (i = 0; i < ct.ncores; i++) {
diff --git a/test/core/gpr/host_port_test.cc b/test/core/gpr/host_port_test.cc
index 42dd565..b5d88b2 100644
--- a/test/core/gpr/host_port_test.cc
+++ b/test/core/gpr/host_port_test.cc
@@ -19,8 +19,9 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
+
+#include "src/core/lib/gpr/host_port.h"
 #include "test/core/util/test_config.h"
 
 static void join_host_port_expect(const char* host, int port,
diff --git a/test/core/gpr/mpscq_test.cc b/test/core/gpr/mpscq_test.cc
index 5a81775..f51bdf8 100644
--- a/test/core/gpr/mpscq_test.cc
+++ b/test/core/gpr/mpscq_test.cc
@@ -18,13 +18,15 @@
 
 #include "src/core/lib/gpr/mpscq.h"
 
+#include <inttypes.h>
 #include <stdlib.h>
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "test/core/util/test_config.h"
 
 typedef struct test_node {
@@ -48,7 +50,7 @@
     gpr_mpscq_push(&q, &new_node(i, nullptr)->node);
   }
   for (size_t i = 0; i < 10000000; i++) {
-    test_node* n = (test_node*)gpr_mpscq_pop(&q);
+    test_node* n = reinterpret_cast<test_node*>(gpr_mpscq_pop(&q));
     GPR_ASSERT(n);
     GPR_ASSERT(n->i == i);
     gpr_free(n);
@@ -75,18 +77,16 @@
   gpr_log(GPR_DEBUG, "test_mt");
   gpr_event start;
   gpr_event_init(&start);
-  gpr_thd_id thds[100];
+  grpc_core::Thread thds[100];
   thd_args ta[GPR_ARRAY_SIZE(thds)];
   gpr_mpscq q;
   gpr_mpscq_init(&q);
   for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) {
-    gpr_thd_options options = gpr_thd_options_default();
-    gpr_thd_options_set_joinable(&options);
     ta[i].ctr = 0;
     ta[i].q = &q;
     ta[i].start = &start;
-    GPR_ASSERT(
-        gpr_thd_new(&thds[i], "grpc_mt_test", test_thread, &ta[i], &options));
+    thds[i] = grpc_core::Thread("grpc_mt_test", test_thread, &ta[i]);
+    thds[i].Start();
   }
   size_t num_done = 0;
   size_t spins = 0;
@@ -96,15 +96,15 @@
     while ((n = gpr_mpscq_pop(&q)) == nullptr) {
       spins++;
     }
-    test_node* tn = (test_node*)n;
+    test_node* tn = reinterpret_cast<test_node*>(n);
     GPR_ASSERT(*tn->ctr == tn->i - 1);
     *tn->ctr = tn->i;
     if (tn->i == THREAD_ITERATIONS) num_done++;
     gpr_free(tn);
   }
   gpr_log(GPR_DEBUG, "spins: %" PRIdPTR, spins);
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) {
-    gpr_thd_join(thds[i]);
+  for (auto& th : thds) {
+    th.Join();
   }
   gpr_mpscq_destroy(&q);
 }
@@ -133,7 +133,7 @@
     while ((n = gpr_mpscq_pop(pa->q)) == nullptr) {
       pa->spins++;
     }
-    test_node* tn = (test_node*)n;
+    test_node* tn = reinterpret_cast<test_node*>(n);
     GPR_ASSERT(*tn->ctr == tn->i - 1);
     *tn->ctr = tn->i;
     if (tn->i == THREAD_ITERATIONS) pa->num_done++;
@@ -146,19 +146,17 @@
   gpr_log(GPR_DEBUG, "test_mt_multipop");
   gpr_event start;
   gpr_event_init(&start);
-  gpr_thd_id thds[100];
-  gpr_thd_id pull_thds[100];
+  grpc_core::Thread thds[50];
+  grpc_core::Thread pull_thds[50];
   thd_args ta[GPR_ARRAY_SIZE(thds)];
   gpr_mpscq q;
   gpr_mpscq_init(&q);
   for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) {
-    gpr_thd_options options = gpr_thd_options_default();
-    gpr_thd_options_set_joinable(&options);
     ta[i].ctr = 0;
     ta[i].q = &q;
     ta[i].start = &start;
-    GPR_ASSERT(gpr_thd_new(&thds[i], "grpc_multipop_test", test_thread, &ta[i],
-                           &options));
+    thds[i] = grpc_core::Thread("grpc_multipop_test", test_thread, &ta[i]);
+    thds[i].Start();
   }
   pull_args pa;
   pa.ta = ta;
@@ -169,18 +167,16 @@
   pa.start = &start;
   gpr_mu_init(&pa.mu);
   for (size_t i = 0; i < GPR_ARRAY_SIZE(pull_thds); i++) {
-    gpr_thd_options options = gpr_thd_options_default();
-    gpr_thd_options_set_joinable(&options);
-    GPR_ASSERT(gpr_thd_new(&pull_thds[i], "grpc_multipop_pull", pull_thread,
-                           &pa, &options));
+    pull_thds[i] = grpc_core::Thread("grpc_multipop_pull", pull_thread, &pa);
+    pull_thds[i].Start();
   }
   gpr_event_set(&start, (void*)1);
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(pull_thds); i++) {
-    gpr_thd_join(pull_thds[i]);
+  for (auto& pth : pull_thds) {
+    pth.Join();
   }
   gpr_log(GPR_DEBUG, "spins: %" PRIdPTR, pa.spins);
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) {
-    gpr_thd_join(thds[i]);
+  for (auto& th : thds) {
+    th.Join();
   }
   gpr_mpscq_destroy(&q);
 }
diff --git a/test/core/gpr/murmur_hash_test.cc b/test/core/gpr/murmur_hash_test.cc
index d920dd3..2d2fa72 100644
--- a/test/core/gpr/murmur_hash_test.cc
+++ b/test/core/gpr/murmur_hash_test.cc
@@ -42,8 +42,8 @@
      the seed */
 
   for (i = 0; i < 256; i++) {
-    key[i] = (uint8_t)i;
-    hashes[i] = hash(key, i, (uint32_t)(256u - i));
+    key[i] = static_cast<uint8_t>(i);
+    hashes[i] = hash(key, i, static_cast<uint32_t>(256u - i));
   }
 
   /* Then hash the result array */
diff --git a/test/core/gpr/spinlock_test.cc b/test/core/gpr/spinlock_test.cc
index 77e3dfb..0ee72ed 100644
--- a/test/core/gpr/spinlock_test.cc
+++ b/test/core/gpr/spinlock_test.cc
@@ -16,23 +16,26 @@
  *
  */
 
-/* Test of gpr synchronization support. */
+/* Test of gpr spin-lock support. */
 
 #include "src/core/lib/gpr/spinlock.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
-#include <stdio.h>
-#include <stdlib.h>
+
+#include "src/core/lib/gprpp/thd.h"
 #include "test/core/util/test_config.h"
 
 /* ------------------------------------------------- */
 /* Tests for gpr_spinlock. */
 struct test {
   int thread_count; /* number of threads */
-  gpr_thd_id* threads;
+  grpc_core::Thread* threads;
 
   int64_t iterations; /* number of iterations per thread */
   int64_t counter;
@@ -45,8 +48,8 @@
 static struct test* test_new(int threads, int64_t iterations, int incr_step) {
   struct test* m = static_cast<struct test*>(gpr_malloc(sizeof(*m)));
   m->thread_count = threads;
-  m->threads = static_cast<gpr_thd_id*>(
-      gpr_malloc(sizeof(*m->threads) * (size_t)threads));
+  m->threads = static_cast<grpc_core::Thread*>(
+      gpr_malloc(sizeof(*m->threads) * static_cast<size_t>(threads)));
   m->iterations = iterations;
   m->counter = 0;
   m->thread_count = 0;
@@ -65,10 +68,8 @@
 static void test_create_threads(struct test* m, void (*body)(void* arg)) {
   int i;
   for (i = 0; i != m->thread_count; i++) {
-    gpr_thd_options opt = gpr_thd_options_default();
-    gpr_thd_options_set_joinable(&opt);
-    GPR_ASSERT(
-        gpr_thd_new(&m->threads[i], "grpc_create_threads", body, m, &opt));
+    m->threads[i] = grpc_core::Thread("grpc_create_threads", body, m);
+    m->threads[i].Start();
   }
 }
 
@@ -76,7 +77,7 @@
 static void test_wait(struct test* m) {
   int i;
   for (i = 0; i != m->thread_count; i++) {
-    gpr_thd_join(m->threads[i]);
+    m->threads[i].Join();
   }
 }
 
@@ -93,27 +94,30 @@
   gpr_timespec start = gpr_now(GPR_CLOCK_REALTIME);
   gpr_timespec time_taken;
   gpr_timespec deadline = gpr_time_add(
-      start, gpr_time_from_micros((int64_t)timeout_s * 1000000, GPR_TIMESPAN));
+      start, gpr_time_from_micros(static_cast<int64_t>(timeout_s) * 1000000,
+                                  GPR_TIMESPAN));
   fprintf(stderr, "%s:", name);
   fflush(stderr);
   while (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0) {
     if (iterations < INT64_MAX / 2) iterations <<= 1;
-    fprintf(stderr, " %ld", (long)iterations);
+    fprintf(stderr, " %ld", static_cast<long>(iterations));
     fflush(stderr);
     m = test_new(10, iterations, incr_step);
     test_create_threads(m, body);
     test_wait(m);
     if (m->counter != m->thread_count * m->iterations * m->incr_step) {
       fprintf(stderr, "counter %ld  threads %d  iterations %ld\n",
-              (long)m->counter, m->thread_count, (long)m->iterations);
+              static_cast<long>(m->counter), m->thread_count,
+              static_cast<long>(m->iterations));
       fflush(stderr);
       GPR_ASSERT(0);
     }
     test_destroy(m);
   }
   time_taken = gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), start);
-  fprintf(stderr, " done %lld.%09d s\n", (long long)time_taken.tv_sec,
-          (int)time_taken.tv_nsec);
+  fprintf(stderr, " done %lld.%09d s\n",
+          static_cast<long long>(time_taken.tv_sec),
+          static_cast<int>(time_taken.tv_nsec));
   fflush(stderr);
 }
 
diff --git a/test/core/gpr/string_test.cc b/test/core/gpr/string_test.cc
index 57068eb..9f3b312 100644
--- a/test/core/gpr/string_test.cc
+++ b/test/core/gpr/string_test.cc
@@ -26,7 +26,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
+
 #include "test/core/util/test_config.h"
 
 #define LOG_TEST_NAME(x) gpr_log(GPR_INFO, "%s", x)
diff --git a/test/core/gpr/sync_test.cc b/test/core/gpr/sync_test.cc
index 768f96d..24b4562 100644
--- a/test/core/gpr/sync_test.cc
+++ b/test/core/gpr/sync_test.cc
@@ -18,13 +18,16 @@
 
 /* Test of gpr synchronization support. */
 
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/time.h>
+
 #include <stdio.h>
 #include <stdlib.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/gprpp/thd.h"
 #include "test/core/util/test_config.h"
 
 /* ==================Example use of interface===================
@@ -132,7 +135,8 @@
 /* ------------------------------------------------- */
 /* Tests for gpr_mu and gpr_cv, and the queue example. */
 struct test {
-  int threads; /* number of threads */
+  int nthreads; /* number of threads */
+  grpc_core::Thread* threads;
 
   int64_t iterations; /* number of iterations per thread */
   int64_t counter;
@@ -156,13 +160,15 @@
 };
 
 /* Return pointer to a new struct test. */
-static struct test* test_new(int threads, int64_t iterations, int incr_step) {
+static struct test* test_new(int nthreads, int64_t iterations, int incr_step) {
   struct test* m = static_cast<struct test*>(gpr_malloc(sizeof(*m)));
-  m->threads = threads;
+  m->nthreads = nthreads;
+  m->threads = static_cast<grpc_core::Thread*>(
+      gpr_malloc(sizeof(*m->threads) * nthreads));
   m->iterations = iterations;
   m->counter = 0;
   m->thread_count = 0;
-  m->done = threads;
+  m->done = nthreads;
   m->incr_step = incr_step;
   gpr_mu_init(&m->mu);
   gpr_cv_init(&m->cv);
@@ -170,7 +176,7 @@
   queue_init(&m->q);
   gpr_stats_init(&m->stats_counter, 0);
   gpr_ref_init(&m->refcount, 0);
-  gpr_ref_init(&m->thread_refcount, threads);
+  gpr_ref_init(&m->thread_refcount, nthreads);
   gpr_event_init(&m->event);
   return m;
 }
@@ -181,15 +187,16 @@
   gpr_cv_destroy(&m->cv);
   gpr_cv_destroy(&m->done_cv);
   queue_destroy(&m->q);
+  gpr_free(m->threads);
   gpr_free(m);
 }
 
-/* Create m->threads threads, each running (*body)(m) */
+/* Create m->nthreads threads, each running (*body)(m) */
 static void test_create_threads(struct test* m, void (*body)(void* arg)) {
-  gpr_thd_id id;
   int i;
-  for (i = 0; i != m->threads; i++) {
-    GPR_ASSERT(gpr_thd_new(&id, "grpc_create_threads", body, m, nullptr));
+  for (i = 0; i != m->nthreads; i++) {
+    m->threads[i] = grpc_core::Thread("grpc_create_threads", body, m);
+    m->threads[i].Start();
   }
 }
 
@@ -200,9 +207,12 @@
     gpr_cv_wait(&m->done_cv, &m->mu, gpr_inf_future(GPR_CLOCK_MONOTONIC));
   }
   gpr_mu_unlock(&m->mu);
+  for (int i = 0; i != m->nthreads; i++) {
+    m->threads[i].Join();
+  }
 }
 
-/* Get an integer thread id in the raneg 0..threads-1 */
+/* Get an integer thread id in the raneg 0..nthreads-1 */
 static int thread_id(struct test* m) {
   int id;
   gpr_mu_lock(&m->mu);
@@ -236,23 +246,29 @@
   gpr_timespec start = gpr_now(GPR_CLOCK_REALTIME);
   gpr_timespec time_taken;
   gpr_timespec deadline = gpr_time_add(
-      start, gpr_time_from_micros((int64_t)timeout_s * 1000000, GPR_TIMESPAN));
+      start, gpr_time_from_micros(static_cast<int64_t>(timeout_s) * 1000000,
+                                  GPR_TIMESPAN));
   fprintf(stderr, "%s:", name);
   fflush(stderr);
   while (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0) {
-    fprintf(stderr, " %ld", (long)iterations);
+    fprintf(stderr, " %ld", static_cast<long>(iterations));
     fflush(stderr);
     m = test_new(10, iterations, incr_step);
+    grpc_core::Thread extra_thd;
     if (extra != nullptr) {
-      gpr_thd_id id;
-      GPR_ASSERT(gpr_thd_new(&id, name, extra, m, nullptr));
+      extra_thd = grpc_core::Thread(name, extra, m);
+      extra_thd.Start();
       m->done++; /* one more thread to wait for */
     }
     test_create_threads(m, body);
     test_wait(m);
-    if (m->counter != m->threads * m->iterations * m->incr_step) {
+    if (extra != nullptr) {
+      extra_thd.Join();
+    }
+    if (m->counter != m->nthreads * m->iterations * m->incr_step) {
       fprintf(stderr, "counter %ld  threads %d  iterations %ld\n",
-              (long)m->counter, m->threads, (long)m->iterations);
+              static_cast<long>(m->counter), m->nthreads,
+              static_cast<long>(m->iterations));
       fflush(stderr);
       GPR_ASSERT(0);
     }
@@ -260,8 +276,9 @@
     iterations <<= 1;
   }
   time_taken = gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), start);
-  fprintf(stderr, " done %lld.%09d s\n", (long long)time_taken.tv_sec,
-          (int)time_taken.tv_nsec);
+  fprintf(stderr, " done %lld.%09d s\n",
+          static_cast<long long>(time_taken.tv_sec),
+          static_cast<int>(time_taken.tv_nsec));
   fflush(stderr);
 }
 
@@ -292,7 +309,7 @@
   mark_thread_done(m);
 }
 
-/* Increment counter only when (m->counter%m->threads)==m->thread_id; then mark
+/* Increment counter only when (m->counter%m->nthreads)==m->thread_id; then mark
    thread as done.  */
 static void inc_by_turns(void* v /*=m*/) {
   struct test* m = static_cast<struct test*>(v);
@@ -300,7 +317,7 @@
   int id = thread_id(m);
   for (i = 0; i != m->iterations; i++) {
     gpr_mu_lock(&m->mu);
-    while ((m->counter % m->threads) != id) {
+    while ((m->counter % m->nthreads) != id) {
       gpr_cv_wait(&m->cv, &m->mu, gpr_inf_future(GPR_CLOCK_MONOTONIC));
     }
     m->counter++;
@@ -365,12 +382,12 @@
   mark_thread_done(m);
 }
 
-/* Consume elements from m->q until m->threads*m->iterations are seen,
+/* Consume elements from m->q until m->nthreads*m->iterations are seen,
    wait an extra second to confirm that no more elements are arriving,
    then mark thread as done. */
 static void consumer(void* v /*=m*/) {
   struct test* m = static_cast<struct test*>(v);
-  int64_t n = m->iterations * m->threads;
+  int64_t n = m->iterations * m->nthreads;
   int64_t i;
   int value;
   for (i = 0; i != n; i++) {
@@ -420,11 +437,11 @@
 }
 
 /* Wait until m->event is set to (void *)1, then decrement m->refcount by 1
-   (m->threads * m->iterations * m->incr_step) times, and ensure that the last
+   (m->nthreads * m->iterations * m->incr_step) times, and ensure that the last
    decrement caused the counter to reach zero, then mark thread as done.  */
 static void refcheck(void* v /*=m*/) {
   struct test* m = static_cast<struct test*>(v);
-  int64_t n = m->iterations * m->threads * m->incr_step;
+  int64_t n = m->iterations * m->nthreads * m->incr_step;
   int64_t i;
   GPR_ASSERT(gpr_event_wait(&m->event, gpr_inf_future(GPR_CLOCK_REALTIME)) ==
              (void*)1);
diff --git a/test/core/gpr/thd_test.cc b/test/core/gpr/thd_test.cc
deleted file mode 100644
index b755bf1..0000000
--- a/test/core/gpr/thd_test.cc
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-/* Test of gpr thread support. */
-
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/time.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "test/core/util/test_config.h"
-
-#define NUM_THREADS 300
-
-struct test {
-  gpr_mu mu;
-  int n;
-  int is_done;
-  gpr_cv done_cv;
-};
-
-/* A Thread body.   Decrement t->n, and if is becomes zero, set t->done. */
-static void thd_body(void* v) {
-  struct test* t = static_cast<struct test*>(v);
-  gpr_mu_lock(&t->mu);
-  t->n--;
-  if (t->n == 0) {
-    t->is_done = 1;
-    gpr_cv_signal(&t->done_cv);
-  }
-  gpr_mu_unlock(&t->mu);
-}
-
-static void thd_body_joinable(void* v) {}
-
-/* Test thread options work as expected */
-static void test_options(void) {
-  gpr_thd_options options = gpr_thd_options_default();
-  GPR_ASSERT(!gpr_thd_options_is_joinable(&options));
-  GPR_ASSERT(gpr_thd_options_is_detached(&options));
-  gpr_thd_options_set_joinable(&options);
-  GPR_ASSERT(gpr_thd_options_is_joinable(&options));
-  GPR_ASSERT(!gpr_thd_options_is_detached(&options));
-  gpr_thd_options_set_detached(&options);
-  GPR_ASSERT(!gpr_thd_options_is_joinable(&options));
-  GPR_ASSERT(gpr_thd_options_is_detached(&options));
-}
-
-/* Test that we can create a number of threads and wait for them. */
-static void test(void) {
-  int i;
-  gpr_thd_id thd;
-  gpr_thd_id thds[NUM_THREADS];
-  struct test t;
-  gpr_thd_options options = gpr_thd_options_default();
-  gpr_mu_init(&t.mu);
-  gpr_cv_init(&t.done_cv);
-  t.n = NUM_THREADS;
-  t.is_done = 0;
-  for (i = 0; i < NUM_THREADS; i++) {
-    GPR_ASSERT(gpr_thd_new(&thd, "grpc_thread_test", &thd_body, &t, nullptr));
-  }
-  gpr_mu_lock(&t.mu);
-  while (!t.is_done) {
-    gpr_cv_wait(&t.done_cv, &t.mu, gpr_inf_future(GPR_CLOCK_REALTIME));
-  }
-  gpr_mu_unlock(&t.mu);
-  GPR_ASSERT(t.n == 0);
-  gpr_thd_options_set_joinable(&options);
-  for (i = 0; i < NUM_THREADS; i++) {
-    GPR_ASSERT(gpr_thd_new(&thds[i], "grpc_joinable_thread_test",
-                           &thd_body_joinable, nullptr, &options));
-  }
-  for (i = 0; i < NUM_THREADS; i++) {
-    gpr_thd_join(thds[i]);
-  }
-}
-
-/* ------------------------------------------------- */
-
-int main(int argc, char* argv[]) {
-  grpc_test_init(argc, argv);
-  test_options();
-  test();
-  return 0;
-}
diff --git a/test/core/gpr/time_test.cc b/test/core/gpr/time_test.cc
index b2b4dce..6f070f5 100644
--- a/test/core/gpr/time_test.cc
+++ b/test/core/gpr/time_test.cc
@@ -20,16 +20,17 @@
 
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
+#include <inttypes.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+
 #include "test/core/util/test_config.h"
 
 static void to_fp(void* arg, const char* buf, size_t len) {
-  fwrite(buf, 1, len, (FILE*)arg);
+  fwrite(buf, 1, len, static_cast<FILE*>(arg));
 }
 
 /* Convert gpr_intmax x to ascii base b (2..16), and write with
diff --git a/test/core/gpr/tls_test.cc b/test/core/gpr/tls_test.cc
index 743b10f..0502fc7 100644
--- a/test/core/gpr/tls_test.cc
+++ b/test/core/gpr/tls_test.cc
@@ -18,12 +18,15 @@
 
 /* Test of gpr thread local storage support. */
 
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/tls.h>
+#include "src/core/lib/gpr/tls.h"
+
 #include <stdio.h>
 #include <stdlib.h>
+
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+
+#include "src/core/lib/gprpp/thd.h"
 #include "test/core/util/test_config.h"
 
 #define NUM_THREADS 100
@@ -45,21 +48,18 @@
 /* ------------------------------------------------- */
 
 int main(int argc, char* argv[]) {
-  gpr_thd_options opt = gpr_thd_options_default();
-  int i;
-  gpr_thd_id threads[NUM_THREADS];
+  grpc_core::Thread threads[NUM_THREADS];
 
   grpc_test_init(argc, argv);
 
   gpr_tls_init(&test_var);
 
-  gpr_thd_options_set_joinable(&opt);
-
-  for (i = 0; i < NUM_THREADS; i++) {
-    gpr_thd_new(&threads[i], "grpc_tls_test", thd_body, nullptr, &opt);
+  for (auto& th : threads) {
+    th = grpc_core::Thread("grpc_tls_test", thd_body, nullptr);
+    th.Start();
   }
-  for (i = 0; i < NUM_THREADS; i++) {
-    gpr_thd_join(threads[i]);
+  for (auto& th : threads) {
+    th.Join();
   }
 
   gpr_tls_destroy(&test_var);
diff --git a/test/core/gpr/useful_test.cc b/test/core/gpr/useful_test.cc
index 2f86010..619c800 100644
--- a/test/core/gpr/useful_test.cc
+++ b/test/core/gpr/useful_test.cc
@@ -18,7 +18,8 @@
 
 #include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
 #include "test/core/util/test_config.h"
 
 int main(int argc, char** argv) {
diff --git a/test/core/gprpp/BUILD b/test/core/gprpp/BUILD
index 1c11e0b..a8a5739 100644
--- a/test/core/gprpp/BUILD
+++ b/test/core/gprpp/BUILD
@@ -24,7 +24,6 @@
     language = "C++",
     deps = [
         "//:gpr",
-        "//:gpr++_base",
         "//test/core/util:gpr_test_util",
     ],
 )
@@ -37,7 +36,7 @@
     ],
     language = "C++",
     deps = [
-        "//:gpr++_base",
+        "//:gpr_base",
         "//test/core/util:gpr_test_util",
     ],
 )
@@ -58,39 +57,49 @@
 grpc_cc_test(
     name = "orphanable_test",
     srcs = ["orphanable_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
     language = "C++",
     deps = [
         "//:orphanable",
         "//test/core/util:gpr_test_util",
     ],
-    external_deps = [
-        "gtest",
-    ],
 )
 
 grpc_cc_test(
     name = "ref_counted_test",
     srcs = ["ref_counted_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
     language = "C++",
     deps = [
         "//:ref_counted",
         "//test/core/util:gpr_test_util",
     ],
-    external_deps = [
-        "gtest",
-    ],
 )
 
 grpc_cc_test(
     name = "ref_counted_ptr_test",
     srcs = ["ref_counted_ptr_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
     language = "C++",
     deps = [
         "//:ref_counted",
         "//:ref_counted_ptr",
         "//test/core/util:gpr_test_util",
     ],
-    external_deps = [
-        "gtest",
+)
+
+grpc_cc_test(
+    name = "thd_test",
+    srcs = ["thd_test.cc"],
+    language = "C++",
+    deps = [
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
     ],
 )
diff --git a/test/core/gprpp/inlined_vector_test.cc b/test/core/gprpp/inlined_vector_test.cc
index b900afa..2a35742 100644
--- a/test/core/gprpp/inlined_vector_test.cc
+++ b/test/core/gprpp/inlined_vector_test.cc
@@ -87,14 +87,17 @@
 }
 
 TEST(InlinedVectorTest, ConstIndexOperator) {
-  const int kNumElements = 10;
+  constexpr int kNumElements = 10;
   InlinedVector<int, 5> v;
   EXPECT_EQ(0UL, v.size());
   for (int i = 0; i < kNumElements; ++i) {
     v.push_back(i);
     EXPECT_EQ(i + 1UL, v.size());
   }
-  auto const_func = [kNumElements](const InlinedVector<int, 5>& v) {
+  // The following lambda function is exceptionally allowed to use an anonymous
+  // capture due to the erroneous behavior of the MSVC compiler, that refuses to
+  // capture the kNumElements constexpr, something allowed by the standard.
+  auto const_func = [&](const InlinedVector<int, 5>& v) {
     for (int i = 0; i < kNumElements; ++i) {
       EXPECT_EQ(i, v[i]);
     }
diff --git a/test/core/gprpp/manual_constructor_test.cc b/test/core/gprpp/manual_constructor_test.cc
index f06c3ca..af162ae 100644
--- a/test/core/gprpp/manual_constructor_test.cc
+++ b/test/core/gprpp/manual_constructor_test.cc
@@ -22,10 +22,10 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <cstring>
+
 #include "src/core/lib/gprpp/abstract.h"
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/gprpp/orphanable_test.cc b/test/core/gprpp/orphanable_test.cc
index ff2f6d8..ad6b9ac 100644
--- a/test/core/gprpp/orphanable_test.cc
+++ b/test/core/gprpp/orphanable_test.cc
@@ -58,18 +58,19 @@
   EXPECT_EQ(5, foo->value());
 }
 
-class Bar : public InternallyRefCounted {
+class Bar : public InternallyRefCounted<Bar> {
  public:
   Bar() : Bar(0) {}
   explicit Bar(int value) : value_(value) {}
   void Orphan() override { Unref(); }
   int value() const { return value_; }
 
-  void StartWork() { Ref(); }
-  void FinishWork() { Unref(); }
+  void StartWork() { self_ref_ = Ref(); }
+  void FinishWork() { self_ref_.reset(); }
 
  private:
   int value_;
+  RefCountedPtr<Bar> self_ref_;
 };
 
 TEST(OrphanablePtr, InternallyRefCounted) {
@@ -82,19 +83,24 @@
 // things build properly in both debug and non-debug cases.
 DebugOnlyTraceFlag baz_tracer(true, "baz");
 
-class Baz : public InternallyRefCountedWithTracing {
+class Baz : public InternallyRefCountedWithTracing<Baz> {
  public:
   Baz() : Baz(0) {}
   explicit Baz(int value)
-      : InternallyRefCountedWithTracing(&baz_tracer), value_(value) {}
+      : InternallyRefCountedWithTracing<Baz>(&baz_tracer), value_(value) {}
   void Orphan() override { Unref(); }
   int value() const { return value_; }
 
-  void StartWork() { Ref(DEBUG_LOCATION, "work"); }
-  void FinishWork() { Unref(DEBUG_LOCATION, "work"); }
+  void StartWork() { self_ref_ = Ref(DEBUG_LOCATION, "work"); }
+  void FinishWork() {
+    // This is a little ugly, but it makes the logged ref and unref match up.
+    self_ref_.release();
+    Unref(DEBUG_LOCATION, "work");
+  }
 
  private:
   int value_;
+  RefCountedPtr<Baz> self_ref_;
 };
 
 TEST(OrphanablePtr, InternallyRefCountedWithTracing) {
diff --git a/test/core/gprpp/ref_counted_ptr_test.cc b/test/core/gprpp/ref_counted_ptr_test.cc
index f1f13f3..2e398a7 100644
--- a/test/core/gprpp/ref_counted_ptr_test.cc
+++ b/test/core/gprpp/ref_counted_ptr_test.cc
@@ -30,7 +30,7 @@
 namespace testing {
 namespace {
 
-class Foo : public RefCounted {
+class Foo : public RefCounted<Foo> {
  public:
   Foo() : value_(0) {}
 
@@ -163,14 +163,15 @@
 
 TraceFlag foo_tracer(true, "foo");
 
-class FooWithTracing : public RefCountedWithTracing {
+class FooWithTracing : public RefCountedWithTracing<FooWithTracing> {
  public:
   FooWithTracing() : RefCountedWithTracing(&foo_tracer) {}
 };
 
 TEST(RefCountedPtr, RefCountedWithTracing) {
   RefCountedPtr<FooWithTracing> foo(New<FooWithTracing>());
-  foo->Ref(DEBUG_LOCATION, "foo");
+  RefCountedPtr<FooWithTracing> foo2 = foo->Ref(DEBUG_LOCATION, "foo");
+  foo2.release();
   foo->Unref(DEBUG_LOCATION, "foo");
 }
 
diff --git a/test/core/gprpp/ref_counted_test.cc b/test/core/gprpp/ref_counted_test.cc
index b1b0fee..f85a2e4 100644
--- a/test/core/gprpp/ref_counted_test.cc
+++ b/test/core/gprpp/ref_counted_test.cc
@@ -27,7 +27,7 @@
 namespace testing {
 namespace {
 
-class Foo : public RefCounted {
+class Foo : public RefCounted<Foo> {
  public:
   Foo() {}
 };
@@ -39,7 +39,8 @@
 
 TEST(RefCounted, ExtraRef) {
   Foo* foo = New<Foo>();
-  foo->Ref();
+  RefCountedPtr<Foo> foop = foo->Ref();
+  foop.release();
   foo->Unref();
   foo->Unref();
 }
@@ -48,17 +49,19 @@
 // things build properly in both debug and non-debug cases.
 DebugOnlyTraceFlag foo_tracer(true, "foo");
 
-class FooWithTracing : public RefCountedWithTracing {
+class FooWithTracing : public RefCountedWithTracing<FooWithTracing> {
  public:
   FooWithTracing() : RefCountedWithTracing(&foo_tracer) {}
 };
 
 TEST(RefCountedWithTracing, Basic) {
   FooWithTracing* foo = New<FooWithTracing>();
-  foo->Ref(DEBUG_LOCATION, "extra_ref");
+  RefCountedPtr<FooWithTracing> foop = foo->Ref(DEBUG_LOCATION, "extra_ref");
+  foop.release();
   foo->Unref(DEBUG_LOCATION, "extra_ref");
   // Can use the no-argument methods, too.
-  foo->Ref();
+  foop = foo->Ref();
+  foop.release();
   foo->Unref();
   foo->Unref(DEBUG_LOCATION, "original_ref");
 }
diff --git a/test/core/gprpp/thd_test.cc b/test/core/gprpp/thd_test.cc
new file mode 100644
index 0000000..82dd681
--- /dev/null
+++ b/test/core/gprpp/thd_test.cc
@@ -0,0 +1,99 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/* Test of gpr thread support. */
+
+#include "src/core/lib/gprpp/thd.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.h>
+
+#include "test/core/util/test_config.h"
+
+#define NUM_THREADS 100
+
+struct test {
+  gpr_mu mu;
+  int n;
+  int is_done;
+  gpr_cv done_cv;
+};
+
+/* A Thread body.   Decrement t->n, and if is becomes zero, set t->done. */
+static void thd_body1(void* v) {
+  struct test* t = static_cast<struct test*>(v);
+  gpr_mu_lock(&t->mu);
+  t->n--;
+  if (t->n == 0) {
+    t->is_done = 1;
+    gpr_cv_signal(&t->done_cv);
+  }
+  gpr_mu_unlock(&t->mu);
+}
+
+/* Test that we can create a number of threads, wait for them, and join them. */
+static void test1(void) {
+  grpc_core::Thread thds[NUM_THREADS];
+  struct test t;
+  gpr_mu_init(&t.mu);
+  gpr_cv_init(&t.done_cv);
+  t.n = NUM_THREADS;
+  t.is_done = 0;
+  for (auto& th : thds) {
+    th = grpc_core::Thread("grpc_thread_body1_test", &thd_body1, &t);
+    th.Start();
+  }
+  gpr_mu_lock(&t.mu);
+  while (!t.is_done) {
+    gpr_cv_wait(&t.done_cv, &t.mu, gpr_inf_future(GPR_CLOCK_REALTIME));
+  }
+  gpr_mu_unlock(&t.mu);
+  for (auto& th : thds) {
+    th.Join();
+  }
+  GPR_ASSERT(t.n == 0);
+}
+
+static void thd_body2(void* v) {}
+
+/* Test that we can create a number of threads and join them. */
+static void test2(void) {
+  grpc_core::Thread thds[NUM_THREADS];
+  for (auto& th : thds) {
+    bool ok;
+    th = grpc_core::Thread("grpc_thread_body2_test", &thd_body2, nullptr, &ok);
+    GPR_ASSERT(ok);
+    th.Start();
+  }
+  for (auto& th : thds) {
+    th.Join();
+  }
+}
+
+/* ------------------------------------------------- */
+
+int main(int argc, char* argv[]) {
+  grpc_test_init(argc, argv);
+  test1();
+  test2();
+  return 0;
+}
diff --git a/test/core/handshake/client_ssl.cc b/test/core/handshake/client_ssl.cc
index 2302e3d..8ac763a 100644
--- a/test/core/handshake/client_ssl.cc
+++ b/test/core/handshake/client_ssl.cc
@@ -34,7 +34,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/thd.h>
+
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/load_file.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
@@ -68,7 +69,7 @@
     return -1;
   }
 
-  if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+  if (bind(s, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) < 0) {
     perror("Unable to bind");
     gpr_log(GPR_ERROR, "%s", "Unable to bind to any port");
     close(s);
@@ -82,7 +83,8 @@
   }
 
   addr_len = sizeof(addr);
-  if (getsockname(s, (struct sockaddr*)&addr, &addr_len) != 0 ||
+  if (getsockname(s, reinterpret_cast<struct sockaddr*>(&addr), &addr_len) !=
+          0 ||
       addr_len > sizeof(addr)) {
     perror("getsockname");
     gpr_log(GPR_ERROR, "%s", "Unable to get socket local address");
@@ -98,19 +100,19 @@
 // SSL_CTX_set_alpn_select_cb.
 static int alpn_select_cb(SSL* ssl, const uint8_t** out, uint8_t* out_len,
                           const uint8_t* in, unsigned in_len, void* arg) {
-  const uint8_t* alpn_preferred = (const uint8_t*)arg;
+  const uint8_t* alpn_preferred = static_cast<const uint8_t*>(arg);
 
   *out = alpn_preferred;
-  *out_len = (uint8_t)strlen((char*)alpn_preferred);
+  *out_len = static_cast<uint8_t>(strlen((char*)alpn_preferred));
 
   // Validate that the ALPN list includes "h2" and "grpc-exp", that "grpc-exp"
   // precedes "h2".
   bool grpc_exp_seen = false;
   bool h2_seen = false;
-  const char* inp = (const char*)in;
+  const char* inp = reinterpret_cast<const char*>(in);
   const char* in_end = inp + in_len;
   while (inp < in_end) {
-    const size_t length = (size_t)*inp++;
+    const size_t length = static_cast<size_t>(*inp++);
     if (length == strlen("grpc-exp") && strncmp(inp, "grpc-exp", length) == 0) {
       grpc_exp_seen = true;
       GPR_ASSERT(!h2_seen);
@@ -133,7 +135,7 @@
 // https://wiki.openssl.org/index.php/Simple_TLS_Server and the gRPC core
 // internals in src/core/tsi/ssl_transport_security.c.
 static void server_thread(void* arg) {
-  const server_args* args = (server_args*)arg;
+  const server_args* args = static_cast<server_args*>(arg);
 
   SSL_load_error_strings();
   OpenSSL_add_ssl_algorithms();
@@ -175,7 +177,8 @@
   gpr_log(GPR_INFO, "Server listening");
   struct sockaddr_in addr;
   socklen_t len = sizeof(addr);
-  const int client = accept(sock, (struct sockaddr*)&addr, &len);
+  const int client =
+      accept(sock, reinterpret_cast<struct sockaddr*>(&addr), &len);
   if (client < 0) {
     perror("Unable to accept");
     abort();
@@ -227,12 +230,11 @@
   GPR_ASSERT(server_socket > 0 && port > 0);
 
   // Launch the TLS server thread.
-  gpr_thd_options thdopt = gpr_thd_options_default();
-  gpr_thd_id thdid;
-  gpr_thd_options_set_joinable(&thdopt);
   server_args args = {server_socket, server_alpn_preferred};
-  GPR_ASSERT(gpr_thd_new(&thdid, "grpc_client_ssl_test", server_thread, &args,
-                         &thdopt));
+  bool ok;
+  grpc_core::Thread thd("grpc_client_ssl_test", server_thread, &args, &ok);
+  GPR_ASSERT(ok);
+  thd.Start();
 
   // Load key pair and establish client SSL credentials.
   grpc_ssl_pem_key_cert_pair pem_key_cert_pair;
@@ -243,9 +245,12 @@
                                grpc_load_file(SSL_CERT_PATH, 1, &cert_slice)));
   GPR_ASSERT(GRPC_LOG_IF_ERROR("load_file",
                                grpc_load_file(SSL_KEY_PATH, 1, &key_slice)));
-  const char* ca_cert = (const char*)GRPC_SLICE_START_PTR(ca_slice);
-  pem_key_cert_pair.private_key = (const char*)GRPC_SLICE_START_PTR(key_slice);
-  pem_key_cert_pair.cert_chain = (const char*)GRPC_SLICE_START_PTR(cert_slice);
+  const char* ca_cert =
+      reinterpret_cast<const char*> GRPC_SLICE_START_PTR(ca_slice);
+  pem_key_cert_pair.private_key =
+      reinterpret_cast<const char*> GRPC_SLICE_START_PTR(key_slice);
+  pem_key_cert_pair.cert_chain =
+      reinterpret_cast<const char*> GRPC_SLICE_START_PTR(cert_slice);
   grpc_channel_credentials* ssl_creds =
       grpc_ssl_credentials_create(ca_cert, &pem_key_cert_pair, nullptr);
 
@@ -297,7 +302,7 @@
   grpc_slice_unref(key_slice);
   grpc_slice_unref(ca_slice);
 
-  gpr_thd_join(thdid);
+  thd.Join();
 
   grpc_shutdown();
 
diff --git a/test/core/handshake/readahead_handshaker_server_ssl.cc b/test/core/handshake/readahead_handshaker_server_ssl.cc
index 599e0e1..9788320 100644
--- a/test/core/handshake/readahead_handshaker_server_ssl.cc
+++ b/test/core/handshake/readahead_handshaker_server_ssl.cc
@@ -29,7 +29,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
+
 #include "src/core/lib/iomgr/load_file.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
@@ -67,7 +67,8 @@
     readahead_handshaker_do_handshake};
 
 static grpc_handshaker* readahead_handshaker_create() {
-  grpc_handshaker* h = (grpc_handshaker*)gpr_zalloc(sizeof(grpc_handshaker));
+  grpc_handshaker* h =
+      static_cast<grpc_handshaker*>(gpr_zalloc(sizeof(grpc_handshaker)));
   grpc_handshaker_init(&readahead_handshaker_vtable, h);
   return h;
 }
diff --git a/test/core/handshake/server_ssl.cc b/test/core/handshake/server_ssl.cc
index 736d3e5..8fa5f7f 100644
--- a/test/core/handshake/server_ssl.cc
+++ b/test/core/handshake/server_ssl.cc
@@ -29,7 +29,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
+
 #include "src/core/lib/iomgr/load_file.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
diff --git a/test/core/handshake/server_ssl_common.cc b/test/core/handshake/server_ssl_common.cc
index 0bf453a..41b2829 100644
--- a/test/core/handshake/server_ssl_common.cc
+++ b/test/core/handshake/server_ssl_common.cc
@@ -31,7 +31,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
+
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/load_file.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
@@ -48,7 +49,7 @@
   struct sockaddr_in addr;
 
   addr.sin_family = AF_INET;
-  addr.sin_port = htons((uint16_t)port);
+  addr.sin_port = htons(static_cast<uint16_t>(port));
   addr.sin_addr.s_addr = htonl(INADDR_ANY);
 
   s = socket(AF_INET, SOCK_STREAM, 0);
@@ -57,7 +58,7 @@
     return -1;
   }
 
-  if (connect(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+  if (connect(s, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) < 0) {
     perror("Unable to connect");
     return -1;
   }
@@ -67,7 +68,7 @@
 
 // Simple gRPC server. This listens until client_handshake_complete occurs.
 static void server_thread(void* arg) {
-  const int port = *(int*)arg;
+  const int port = *static_cast<int*>(arg);
 
   // Load key pair and establish server SSL credentials.
   grpc_ssl_pem_key_cert_pair pem_key_cert_pair;
@@ -78,9 +79,12 @@
                                grpc_load_file(SSL_CERT_PATH, 1, &cert_slice)));
   GPR_ASSERT(GRPC_LOG_IF_ERROR("load_file",
                                grpc_load_file(SSL_KEY_PATH, 1, &key_slice)));
-  const char* ca_cert = (const char*)GRPC_SLICE_START_PTR(ca_slice);
-  pem_key_cert_pair.private_key = (const char*)GRPC_SLICE_START_PTR(key_slice);
-  pem_key_cert_pair.cert_chain = (const char*)GRPC_SLICE_START_PTR(cert_slice);
+  const char* ca_cert =
+      reinterpret_cast<const char*> GRPC_SLICE_START_PTR(ca_slice);
+  pem_key_cert_pair.private_key =
+      reinterpret_cast<const char*> GRPC_SLICE_START_PTR(key_slice);
+  pem_key_cert_pair.cert_chain =
+      reinterpret_cast<const char*> GRPC_SLICE_START_PTR(cert_slice);
   grpc_server_credentials* ssl_creds = grpc_ssl_server_credentials_create(
       ca_cert, &pem_key_cert_pair, 1, 0, nullptr);
 
@@ -134,11 +138,10 @@
   gpr_event_init(&client_handshake_complete);
 
   // Launch the gRPC server thread.
-  gpr_thd_options thdopt = gpr_thd_options_default();
-  gpr_thd_id thdid;
-  gpr_thd_options_set_joinable(&thdopt);
-  GPR_ASSERT(
-      gpr_thd_new(&thdid, "grpc_ssl_test", server_thread, &port, &thdopt));
+  bool ok;
+  grpc_core::Thread thd("grpc_ssl_test", server_thread, &port, &ok);
+  GPR_ASSERT(ok);
+  thd.Start();
 
   SSL_load_error_strings();
   OpenSSL_add_ssl_algorithms();
@@ -176,13 +179,13 @@
   // wire format, see documentation for SSL_CTX_set_alpn_protos.
   unsigned int alpn_protos_len = alpn_list_len;
   for (unsigned int i = 0; i < alpn_list_len; ++i) {
-    alpn_protos_len += (unsigned int)strlen(alpn_list[i]);
+    alpn_protos_len += static_cast<unsigned int>(strlen(alpn_list[i]));
   }
   unsigned char* alpn_protos =
       static_cast<unsigned char*>(gpr_malloc(alpn_protos_len));
   unsigned char* p = alpn_protos;
   for (unsigned int i = 0; i < alpn_list_len; ++i) {
-    const uint8_t len = (uint8_t)strlen(alpn_list[i]);
+    const uint8_t len = static_cast<uint8_t>(strlen(alpn_list[i]));
     *p++ = len;
     memcpy(p, alpn_list[i], len);
     p += len;
@@ -217,8 +220,8 @@
     unsigned int alpn_selected_len;
     SSL_get0_alpn_selected(ssl, &alpn_selected, &alpn_selected_len);
     if (strlen(alpn_expected) != alpn_selected_len ||
-        strncmp((const char*)alpn_selected, alpn_expected, alpn_selected_len) !=
-            0) {
+        strncmp(reinterpret_cast<const char*>(alpn_selected), alpn_expected,
+                alpn_selected_len) != 0) {
       gpr_log(GPR_ERROR, "Unexpected ALPN protocol preference");
       success = false;
     }
@@ -231,7 +234,7 @@
   EVP_cleanup();
   close(sock);
 
-  gpr_thd_join(thdid);
+  thd.Join();
 
   grpc_shutdown();
 
diff --git a/test/core/handshake/server_ssl_common.h b/test/core/handshake/server_ssl_common.h
index 77865a4..32bc6f9 100644
--- a/test/core/handshake/server_ssl_common.h
+++ b/test/core/handshake/server_ssl_common.h
@@ -25,7 +25,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
+
 #include "src/core/lib/iomgr/load_file.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
diff --git a/test/core/http/BUILD b/test/core/http/BUILD
index 03b8f4e..be51ea0 100644
--- a/test/core/http/BUILD
+++ b/test/core/http/BUILD
@@ -113,3 +113,16 @@
         "//test/core/util:grpc_test_util",
     ],
 )
+
+grpc_cc_test(
+    name = "format_request_test",
+    srcs = ["format_request_test.cc"],
+    language = "C++",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/end2end:ssl_test_data",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
+)
diff --git a/test/core/http/httpcli_test.cc b/test/core/http/httpcli_test.cc
index 6ad0753..16448d9 100644
--- a/test/core/http/httpcli_test.cc
+++ b/test/core/http/httpcli_test.cc
@@ -24,10 +24,11 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/subprocess.h>
 #include <grpc/support/sync.h>
+
 #include "src/core/lib/iomgr/iomgr.h"
 #include "test/core/util/port.h"
+#include "test/core/util/subprocess.h"
 #include "test/core/util/test_config.h"
 
 static int g_done = 0;
@@ -46,6 +47,7 @@
       "<body><p>This is a test</p></body></html>";
   grpc_http_response* response = static_cast<grpc_http_response*>(arg);
   GPR_ASSERT(response);
+  gpr_log(GPR_INFO, "response status %d", response->status);
   GPR_ASSERT(response->status == 200);
   GPR_ASSERT(response->body_length == strlen(expect));
   GPR_ASSERT(0 == memcmp(expect, response->body, response->body_length));
@@ -156,14 +158,14 @@
     char* root;
     if (lslash != nullptr) {
       /* Hack for bazel target */
-      if ((unsigned)(lslash - me) >= (sizeof("http") - 1) &&
+      if (static_cast<unsigned>(lslash - me) >= (sizeof("http") - 1) &&
           strncmp(me + (lslash - me) - sizeof("http") + 1, "http",
                   sizeof("http") - 1) == 0) {
         lslash = me + (lslash - me) - sizeof("http");
       }
       root = static_cast<char*>(
-          gpr_malloc((size_t)(lslash - me + sizeof("/../.."))));
-      memcpy(root, me, (size_t)(lslash - me));
+          gpr_malloc(static_cast<size_t>(lslash - me + sizeof("/../.."))));
+      memcpy(root, me, static_cast<size_t>(lslash - me));
       memcpy(root + (lslash - me), "/../..", sizeof("/../.."));
     } else {
       root = gpr_strdup(".");
diff --git a/test/core/http/httpscli_test.cc b/test/core/http/httpscli_test.cc
index 92193bb..b8f2e43 100644
--- a/test/core/http/httpscli_test.cc
+++ b/test/core/http/httpscli_test.cc
@@ -25,11 +25,12 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/subprocess.h>
 #include <grpc/support/sync.h>
+
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "test/core/util/port.h"
+#include "test/core/util/subprocess.h"
 #include "test/core/util/test_config.h"
 
 static int g_done = 0;
@@ -48,6 +49,7 @@
       "<body><p>This is a test</p></body></html>";
   grpc_http_response* response = static_cast<grpc_http_response*>(arg);
   GPR_ASSERT(response);
+  gpr_log(GPR_INFO, "response status %d", response->status);
   GPR_ASSERT(response->status == 200);
   GPR_ASSERT(response->body_length == strlen(expect));
   GPR_ASSERT(0 == memcmp(expect, response->body, response->body_length));
@@ -156,14 +158,14 @@
   char* root;
   if (lslash != nullptr) {
     /* Hack for bazel target */
-    if ((unsigned)(lslash - me) >= (sizeof("http") - 1) &&
+    if (static_cast<unsigned>(lslash - me) >= (sizeof("http") - 1) &&
         strncmp(me + (lslash - me) - sizeof("http") + 1, "http",
                 sizeof("http") - 1) == 0) {
       lslash = me + (lslash - me) - sizeof("http");
     }
     root = static_cast<char*>(
-        gpr_malloc((size_t)(lslash - me + sizeof("/../.."))));
-    memcpy(root, me, (size_t)(lslash - me));
+        gpr_malloc(static_cast<size_t>(lslash - me + sizeof("/../.."))));
+    memcpy(root, me, static_cast<size_t>(lslash - me));
     memcpy(root + (lslash - me), "/../..", sizeof("/../.."));
   } else {
     root = gpr_strdup(".");
diff --git a/test/core/http/parser_test.cc b/test/core/http/parser_test.cc
index 18f1985..fe824f5 100644
--- a/test/core/http/parser_test.cc
+++ b/test/core/http/parser_test.cc
@@ -25,7 +25,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
 #include "test/core/util/slice_splitter.h"
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/iomgr/BUILD b/test/core/iomgr/BUILD
index 41e2607..349a06d 100644
--- a/test/core/iomgr/BUILD
+++ b/test/core/iomgr/BUILD
@@ -60,6 +60,19 @@
 )
 
 grpc_cc_test(
+    name = "error_test",
+    srcs = ["error_test.cc"],
+    language = "C++",
+    deps = [
+        ":endpoint_tests",
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+grpc_cc_test(
     name = "ev_epollsig_linux_test",
     srcs = ["ev_epollsig_linux_test.cc"],
     deps = [
diff --git a/test/core/iomgr/combiner_test.cc b/test/core/iomgr/combiner_test.cc
index 891008c..cf2c7db 100644
--- a/test/core/iomgr/combiner_test.cc
+++ b/test/core/iomgr/combiner_test.cc
@@ -21,9 +21,9 @@
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
 
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "test/core/util/test_config.h"
 
 static void test_no_op(void) {
@@ -97,21 +97,19 @@
   gpr_log(GPR_DEBUG, "test_execute_many");
 
   grpc_combiner* lock = grpc_combiner_create();
-  gpr_thd_id thds[100];
+  grpc_core::Thread thds[100];
   thd_args ta[GPR_ARRAY_SIZE(thds)];
   for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) {
-    gpr_thd_options options = gpr_thd_options_default();
-    gpr_thd_options_set_joinable(&options);
     ta[i].ctr = 0;
     ta[i].lock = lock;
     gpr_event_init(&ta[i].done);
-    GPR_ASSERT(gpr_thd_new(&thds[i], "grpc_execute_many", execute_many_loop,
-                           &ta[i], &options));
+    thds[i] = grpc_core::Thread("grpc_execute_many", execute_many_loop, &ta[i]);
+    thds[i].Start();
   }
   for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) {
     GPR_ASSERT(gpr_event_wait(&ta[i].done,
                               gpr_inf_future(GPR_CLOCK_REALTIME)) != nullptr);
-    gpr_thd_join(thds[i]);
+    thds[i].Join();
   }
   grpc_core::ExecCtx exec_ctx;
   GRPC_COMBINER_UNREF(lock, "test_execute_many");
diff --git a/test/core/iomgr/endpoint_pair_test.cc b/test/core/iomgr/endpoint_pair_test.cc
index 90dd40d..ad38076 100644
--- a/test/core/iomgr/endpoint_pair_test.cc
+++ b/test/core/iomgr/endpoint_pair_test.cc
@@ -21,7 +21,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
 #include "test/core/iomgr/endpoint_tests.h"
 #include "test/core/util/test_config.h"
 
@@ -37,7 +38,7 @@
   grpc_arg a[1];
   a[0].key = const_cast<char*>(GRPC_ARG_TCP_READ_CHUNK_SIZE);
   a[0].type = GRPC_ARG_INTEGER;
-  a[0].value.integer = (int)slice_size;
+  a[0].value.integer = static_cast<int>(slice_size);
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
   grpc_endpoint_pair p = grpc_iomgr_create_endpoint_pair("test", &args);
 
diff --git a/test/core/iomgr/endpoint_tests.cc b/test/core/iomgr/endpoint_tests.cc
index 8ccae52..8db8ac5 100644
--- a/test/core/iomgr/endpoint_tests.cc
+++ b/test/core/iomgr/endpoint_tests.cc
@@ -25,8 +25,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "test/core/util/test_config.h"
 
@@ -77,7 +77,8 @@
 static grpc_slice* allocate_blocks(size_t num_bytes, size_t slice_size,
                                    size_t* num_blocks, uint8_t* current_data) {
   size_t nslices = num_bytes / slice_size + (num_bytes % slice_size ? 1 : 0);
-  grpc_slice* slices = (grpc_slice*)gpr_malloc(sizeof(grpc_slice) * nslices);
+  grpc_slice* slices =
+      static_cast<grpc_slice*>(gpr_malloc(sizeof(grpc_slice) * nslices));
   size_t num_bytes_left = num_bytes;
   size_t i;
   size_t j;
@@ -117,7 +118,7 @@
 
 static void read_and_write_test_read_handler(void* data, grpc_error* error) {
   struct read_and_write_test_state* state =
-      (struct read_and_write_test_state*)data;
+      static_cast<struct read_and_write_test_state*>(data);
 
   state->bytes_read += count_slices(
       state->incoming.slices, state->incoming.count, &state->current_read_data);
@@ -134,7 +135,7 @@
 
 static void read_and_write_test_write_handler(void* data, grpc_error* error) {
   struct read_and_write_test_state* state =
-      (struct read_and_write_test_state*)data;
+      static_cast<struct read_and_write_test_state*>(data);
   grpc_slice* slices = nullptr;
   size_t nslices;
 
@@ -246,7 +247,7 @@
 
 static void inc_on_failure(void* arg, grpc_error* error) {
   gpr_mu_lock(g_mu);
-  *(int*)arg += (error != GRPC_ERROR_NONE);
+  *static_cast<int*>(arg) += (error != GRPC_ERROR_NONE);
   GPR_ASSERT(GRPC_LOG_IF_ERROR("kick", grpc_pollset_kick(g_pollset, nullptr)));
   gpr_mu_unlock(g_mu);
 }
diff --git a/test/core/iomgr/error_test.cc b/test/core/iomgr/error_test.cc
index 51f8af1..a1628a1 100644
--- a/test/core/iomgr/error_test.cc
+++ b/test/core/iomgr/error_test.cc
@@ -21,8 +21,6 @@
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
 
 #include <string.h>
 
diff --git a/test/core/iomgr/ev_epollsig_linux_test.cc b/test/core/iomgr/ev_epollsig_linux_test.cc
index 2624703..c3ba6d7 100644
--- a/test/core/iomgr/ev_epollsig_linux_test.cc
+++ b/test/core/iomgr/ev_epollsig_linux_test.cc
@@ -29,9 +29,9 @@
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
 
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "test/core/util/test_config.h"
 
@@ -98,7 +98,7 @@
 }
 
 static void destroy_pollset(void* p, grpc_error* error) {
-  grpc_pollset_destroy((grpc_pollset*)p);
+  grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
 }
 
 static void test_pollset_cleanup(test_pollset* pollsets, int num_pollsets) {
@@ -259,11 +259,10 @@
   shared.pollset = static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
   grpc_pollset_init(shared.pollset, &shared.mu);
 
-  gpr_thd_id thds[10];
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) {
-    gpr_thd_options opt = gpr_thd_options_default();
-    gpr_thd_options_set_joinable(&opt);
-    gpr_thd_new(&thds[i], "test_thread", test_threading_loop, &shared, &opt);
+  grpc_core::Thread thds[10];
+  for (auto& th : thds) {
+    th = grpc_core::Thread("test_thread", test_threading_loop, &shared);
+    th.Start();
   }
   grpc_wakeup_fd fd;
   GPR_ASSERT(GRPC_LOG_IF_ERROR("wakeup_fd_init", grpc_wakeup_fd_init(&fd)));
@@ -280,8 +279,8 @@
   }
   GPR_ASSERT(GRPC_LOG_IF_ERROR("wakeup_first",
                                grpc_wakeup_fd_wakeup(shared.wakeup_fd)));
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) {
-    gpr_thd_join(thds[i]);
+  for (auto& th : thds) {
+    th.Join();
   }
   fd.read_fd = 0;
   grpc_wakeup_fd_destroy(&fd);
diff --git a/test/core/iomgr/fd_posix_test.cc b/test/core/iomgr/fd_posix_test.cc
index cf75517..b81c73b 100644
--- a/test/core/iomgr/fd_posix_test.cc
+++ b/test/core/iomgr/fd_posix_test.cc
@@ -78,7 +78,7 @@
   sin->sin_family = AF_INET;
   sin->sin_addr.s_addr = htonl(0x7f000001);
   GPR_ASSERT(port >= 0 && port < 65536);
-  sin->sin_port = htons((uint16_t)port);
+  sin->sin_port = htons(static_cast<uint16_t>(port));
 }
 
 /* Dummy gRPC callback */
@@ -196,7 +196,8 @@
     return;
   }
 
-  fd = accept(grpc_fd_wrapped_fd(listen_em_fd), (struct sockaddr*)&ss, &slen);
+  fd = accept(grpc_fd_wrapped_fd(listen_em_fd),
+              reinterpret_cast<struct sockaddr*>(&ss), &slen);
   GPR_ASSERT(fd >= 0);
   GPR_ASSERT(fd < FD_SETSIZE);
   flags = fcntl(fd, F_GETFL, 0);
@@ -335,7 +336,8 @@
   int fd;
   struct sockaddr_in sin;
   create_test_socket(port, &fd, &sin);
-  if (connect(fd, (struct sockaddr*)&sin, sizeof(sin)) == -1) {
+  if (connect(fd, reinterpret_cast<struct sockaddr*>(&sin), sizeof(sin)) ==
+      -1) {
     if (errno == EINPROGRESS) {
       struct pollfd pfd;
       pfd.fd = fd;
diff --git a/test/core/iomgr/pollset_set_test.cc b/test/core/iomgr/pollset_set_test.cc
index 7d2f59b..0dc75a5 100644
--- a/test/core/iomgr/pollset_set_test.cc
+++ b/test/core/iomgr/pollset_set_test.cc
@@ -27,8 +27,8 @@
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
 
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "test/core/util/test_config.h"
@@ -103,7 +103,7 @@
 } test_fd;
 
 void on_readable(void* tfd, grpc_error* error) {
-  ((test_fd*)tfd)->is_on_readable_called = true;
+  (static_cast<test_fd*>(tfd))->is_on_readable_called = true;
 }
 
 static void reset_test_fd(test_fd* tfd) {
diff --git a/test/core/iomgr/resolve_address_posix_test.cc b/test/core/iomgr/resolve_address_posix_test.cc
index e363153..79b2b50 100644
--- a/test/core/iomgr/resolve_address_posix_test.cc
+++ b/test/core/iomgr/resolve_address_posix_test.cc
@@ -25,10 +25,10 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "test/core/util/test_config.h"
@@ -38,6 +38,7 @@
 }
 
 typedef struct args_struct {
+  grpc_core::Thread thd;
   gpr_event ev;
   grpc_resolved_addresses* addrs;
   gpr_atm done_atm;
@@ -59,6 +60,9 @@
 
 void args_finish(args_struct* args) {
   GPR_ASSERT(gpr_event_wait(&args->ev, test_deadline()));
+  args->thd.Join();
+  // Don't need to explicitly destruct args->thd since
+  // args is actually going to be destructed, not just freed
   grpc_resolved_addresses_destroy(args->addrs);
   grpc_pollset_set_del_pollset(args->pollset_set, args->pollset);
   grpc_pollset_set_destroy(args->pollset_set);
@@ -101,8 +105,8 @@
 
 static void poll_pollset_until_request_done(args_struct* args) {
   gpr_atm_rel_store(&args->done_atm, 0);
-  gpr_thd_id id;
-  gpr_thd_new(&id, "grpc_poll_pollset", actually_poll, args, nullptr);
+  args->thd = grpc_core::Thread("grpc_poll_pollset", actually_poll, args);
+  args->thd.Start();
 }
 
 static void must_succeed(void* argsp, grpc_error* err) {
diff --git a/test/core/iomgr/resource_quota_test.cc b/test/core/iomgr/resource_quota_test.cc
index 07682d2..059ff7b 100644
--- a/test/core/iomgr/resource_quota_test.cc
+++ b/test/core/iomgr/resource_quota_test.cc
@@ -21,6 +21,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "test/core/util/test_config.h"
 
@@ -29,7 +30,7 @@
 
 static void inc_int_cb(void* a, grpc_error* error) {
   gpr_mu_lock(&g_mu);
-  ++*(int*)a;
+  ++*static_cast<int*>(a);
   gpr_cv_signal(&g_cv);
   gpr_mu_unlock(&g_mu);
 }
@@ -44,7 +45,7 @@
 }
 
 static void set_event_cb(void* a, grpc_error* error) {
-  gpr_event_set((gpr_event*)a, (void*)1);
+  gpr_event_set(static_cast<gpr_event*>(a), (void*)1);
 }
 grpc_closure* set_event(gpr_event* ev) {
   return GRPC_CLOSURE_CREATE(set_event_cb, ev, grpc_schedule_on_exec_ctx);
diff --git a/test/core/iomgr/sockaddr_utils_test.cc b/test/core/iomgr/sockaddr_utils_test.cc
index a445714..3783f96 100644
--- a/test/core/iomgr/sockaddr_utils_test.cc
+++ b/test/core/iomgr/sockaddr_utils_test.cc
@@ -22,6 +22,7 @@
    headers. Therefore, sockaddr.h must always be included first */
 #include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/iomgr/socket_utils.h"
 
 #include <errno.h>
 #include <string.h>
@@ -33,31 +34,33 @@
 
 static grpc_resolved_address make_addr4(const uint8_t* data, size_t data_len) {
   grpc_resolved_address resolved_addr4;
-  struct sockaddr_in* addr4 = (struct sockaddr_in*)resolved_addr4.addr;
+  grpc_sockaddr_in* addr4 =
+      reinterpret_cast<grpc_sockaddr_in*>(resolved_addr4.addr);
   memset(&resolved_addr4, 0, sizeof(resolved_addr4));
-  addr4->sin_family = AF_INET;
+  addr4->sin_family = GRPC_AF_INET;
   GPR_ASSERT(data_len == sizeof(addr4->sin_addr.s_addr));
   memcpy(&addr4->sin_addr.s_addr, data, data_len);
-  addr4->sin_port = htons(12345);
-  resolved_addr4.len = sizeof(struct sockaddr_in);
+  addr4->sin_port = grpc_htons(12345);
+  resolved_addr4.len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in));
   return resolved_addr4;
 }
 
 static grpc_resolved_address make_addr6(const uint8_t* data, size_t data_len) {
   grpc_resolved_address resolved_addr6;
-  struct sockaddr_in6* addr6 = (struct sockaddr_in6*)resolved_addr6.addr;
+  grpc_sockaddr_in6* addr6 =
+      reinterpret_cast<grpc_sockaddr_in6*>(resolved_addr6.addr);
   memset(&resolved_addr6, 0, sizeof(resolved_addr6));
-  addr6->sin6_family = AF_INET6;
+  addr6->sin6_family = GRPC_AF_INET6;
   GPR_ASSERT(data_len == sizeof(addr6->sin6_addr.s6_addr));
   memcpy(&addr6->sin6_addr.s6_addr, data, data_len);
-  addr6->sin6_port = htons(12345);
-  resolved_addr6.len = sizeof(struct sockaddr_in6);
+  addr6->sin6_port = grpc_htons(12345);
+  resolved_addr6.len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in6));
   return resolved_addr6;
 }
 
 static void set_addr6_scope_id(grpc_resolved_address* addr, uint32_t scope_id) {
-  struct sockaddr_in6* addr6 = (struct sockaddr_in6*)addr->addr;
-  GPR_ASSERT(addr6->sin6_family == AF_INET6);
+  grpc_sockaddr_in6* addr6 = reinterpret_cast<grpc_sockaddr_in6*>(addr->addr);
+  GPR_ASSERT(addr6->sin6_family == GRPC_AF_INET6);
   addr6->sin6_scope_id = scope_id;
 }
 
@@ -128,9 +131,9 @@
   grpc_resolved_address wild6;
   grpc_resolved_address wild_mapped;
   grpc_resolved_address dummy;
-  struct sockaddr_in* wild4_addr;
-  struct sockaddr_in6* wild6_addr;
-  struct sockaddr_in6* wild_mapped_addr;
+  grpc_sockaddr_in* wild4_addr;
+  grpc_sockaddr_in6* wild6_addr;
+  grpc_sockaddr_in6* wild_mapped_addr;
   int port;
 
   gpr_log(GPR_INFO, "%s", "test_sockaddr_is_wildcard");
@@ -143,7 +146,7 @@
   port = -1;
   GPR_ASSERT(grpc_sockaddr_is_wildcard(&wild4, &port));
   GPR_ASSERT(port == 555);
-  wild4_addr = (struct sockaddr_in*)&wild4.addr;
+  wild4_addr = reinterpret_cast<grpc_sockaddr_in*>(&wild4.addr);
   memset(&wild4_addr->sin_addr.s_addr, 0xbd, 1);
   GPR_ASSERT(!grpc_sockaddr_is_wildcard(&wild4, &port));
 
@@ -151,7 +154,7 @@
   port = -1;
   GPR_ASSERT(grpc_sockaddr_is_wildcard(&wild6, &port));
   GPR_ASSERT(port == 555);
-  wild6_addr = (struct sockaddr_in6*)&wild6.addr;
+  wild6_addr = reinterpret_cast<grpc_sockaddr_in6*>(&wild6.addr);
   memset(&wild6_addr->sin6_addr.s6_addr, 0xbd, 1);
   GPR_ASSERT(!grpc_sockaddr_is_wildcard(&wild6, &port));
 
@@ -159,7 +162,7 @@
   port = -1;
   GPR_ASSERT(grpc_sockaddr_is_wildcard(&wild_mapped, &port));
   GPR_ASSERT(port == 555);
-  wild_mapped_addr = (struct sockaddr_in6*)&wild_mapped.addr;
+  wild_mapped_addr = reinterpret_cast<grpc_sockaddr_in6*>(&wild_mapped.addr);
   memset(&wild_mapped_addr->sin6_addr.s6_addr, 0xbd, 1);
   GPR_ASSERT(!grpc_sockaddr_is_wildcard(&wild_mapped, &port));
 
@@ -197,7 +200,7 @@
   grpc_resolved_address input4;
   grpc_resolved_address input6;
   grpc_resolved_address dummy;
-  struct sockaddr* dummy_addr;
+  grpc_sockaddr* dummy_addr;
 
   gpr_log(GPR_INFO, "%s", "test_sockaddr_to_string");
 
@@ -234,7 +237,7 @@
   expect_sockaddr_uri("ipv6:[::fffe:c000:263]:12345", &input6);
 
   memset(&dummy, 0, sizeof(dummy));
-  dummy_addr = (struct sockaddr*)dummy.addr;
+  dummy_addr = reinterpret_cast<grpc_sockaddr*>(dummy.addr);
   dummy_addr->sa_family = 123;
   expect_sockaddr_str("(sockaddr family=123)", &dummy, 0);
   expect_sockaddr_str("(sockaddr family=123)", &dummy, 1);
@@ -245,7 +248,7 @@
   grpc_resolved_address input4;
   grpc_resolved_address input6;
   grpc_resolved_address dummy;
-  struct sockaddr* dummy_addr;
+  grpc_sockaddr* dummy_addr;
 
   gpr_log(GPR_DEBUG, "test_sockaddr_set_get_port");
 
@@ -260,7 +263,7 @@
   GPR_ASSERT(grpc_sockaddr_get_port(&input6) == 54321);
 
   memset(&dummy, 0, sizeof(dummy));
-  dummy_addr = (struct sockaddr*)dummy.addr;
+  dummy_addr = reinterpret_cast<grpc_sockaddr*>(dummy.addr);
   dummy_addr->sa_family = 123;
   GPR_ASSERT(grpc_sockaddr_get_port(&dummy) == 0);
   GPR_ASSERT(grpc_sockaddr_set_port(&dummy, 1234) == 0);
diff --git a/test/core/iomgr/socket_utils_test.cc b/test/core/iomgr/socket_utils_test.cc
index 49c6f79..a21f3fa 100644
--- a/test/core/iomgr/socket_utils_test.cc
+++ b/test/core/iomgr/socket_utils_test.cc
@@ -30,7 +30,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/socket_mutator.h"
 #include "test/core/util/test_config.h"
 
@@ -42,7 +43,8 @@
 static bool mutate_fd(int fd, grpc_socket_mutator* mutator) {
   int newval;
   socklen_t intlen = sizeof(newval);
-  struct test_socket_mutator* m = (struct test_socket_mutator*)mutator;
+  struct test_socket_mutator* m =
+      reinterpret_cast<struct test_socket_mutator*>(mutator);
 
   if (0 != setsockopt(fd, IPPROTO_IP, IP_TOS, &m->option_value,
                       sizeof(m->option_value))) {
@@ -58,14 +60,17 @@
 }
 
 static void destroy_test_mutator(grpc_socket_mutator* mutator) {
-  struct test_socket_mutator* m = (struct test_socket_mutator*)mutator;
+  struct test_socket_mutator* m =
+      reinterpret_cast<struct test_socket_mutator*>(mutator);
   gpr_free(m);
 }
 
 static int compare_test_mutator(grpc_socket_mutator* a,
                                 grpc_socket_mutator* b) {
-  struct test_socket_mutator* ma = (struct test_socket_mutator*)a;
-  struct test_socket_mutator* mb = (struct test_socket_mutator*)b;
+  struct test_socket_mutator* ma =
+      reinterpret_cast<struct test_socket_mutator*>(a);
+  struct test_socket_mutator* mb =
+      reinterpret_cast<struct test_socket_mutator*>(b);
   return GPR_ICMP(ma->option_value, mb->option_value);
 }
 
@@ -116,7 +121,8 @@
       grpc_set_socket_with_mutator(sock, (grpc_socket_mutator*)&mutator)));
 
   mutator.option_value = -1;
-  err = grpc_set_socket_with_mutator(sock, (grpc_socket_mutator*)&mutator);
+  err = grpc_set_socket_with_mutator(
+      sock, reinterpret_cast<grpc_socket_mutator*>(&mutator));
   GPR_ASSERT(err != GRPC_ERROR_NONE);
   GRPC_ERROR_UNREF(err);
 
diff --git a/test/core/iomgr/tcp_client_posix_test.cc b/test/core/iomgr/tcp_client_posix_test.cc
index 40a050e..a4c38af 100644
--- a/test/core/iomgr/tcp_client_posix_test.cc
+++ b/test/core/iomgr/tcp_client_posix_test.cc
@@ -78,7 +78,8 @@
 
 void test_succeeds(void) {
   grpc_resolved_address resolved_addr;
-  struct sockaddr_in* addr = (struct sockaddr_in*)resolved_addr.addr;
+  struct sockaddr_in* addr =
+      reinterpret_cast<struct sockaddr_in*>(resolved_addr.addr);
   int svr_fd;
   int r;
   int connections_complete_before;
@@ -88,7 +89,7 @@
   gpr_log(GPR_DEBUG, "test_succeeds");
 
   memset(&resolved_addr, 0, sizeof(resolved_addr));
-  resolved_addr.len = sizeof(struct sockaddr_in);
+  resolved_addr.len = static_cast<socklen_t>(sizeof(struct sockaddr_in));
   addr->sin_family = AF_INET;
 
   /* create a dummy server */
@@ -111,8 +112,9 @@
 
   /* await the connection */
   do {
-    resolved_addr.len = sizeof(addr);
-    r = accept(svr_fd, (struct sockaddr*)addr, (socklen_t*)&resolved_addr.len);
+    resolved_addr.len = static_cast<socklen_t>(sizeof(addr));
+    r = accept(svr_fd, reinterpret_cast<struct sockaddr*>(addr),
+               reinterpret_cast<socklen_t*>(&resolved_addr.len));
   } while (r == -1 && errno == EINTR);
   GPR_ASSERT(r >= 0);
   close(r);
@@ -136,7 +138,8 @@
 
 void test_fails(void) {
   grpc_resolved_address resolved_addr;
-  struct sockaddr_in* addr = (struct sockaddr_in*)resolved_addr.addr;
+  struct sockaddr_in* addr =
+      reinterpret_cast<struct sockaddr_in*>(resolved_addr.addr);
   int connections_complete_before;
   grpc_closure done;
   grpc_core::ExecCtx exec_ctx;
@@ -144,7 +147,7 @@
   gpr_log(GPR_DEBUG, "test_fails");
 
   memset(&resolved_addr, 0, sizeof(resolved_addr));
-  resolved_addr.len = sizeof(struct sockaddr_in);
+  resolved_addr.len = static_cast<socklen_t>(sizeof(struct sockaddr_in));
   addr->sin_family = AF_INET;
 
   gpr_mu_lock(g_mu);
diff --git a/test/core/iomgr/tcp_posix_test.cc b/test/core/iomgr/tcp_posix_test.cc
index f4acba8..f4df6fc 100644
--- a/test/core/iomgr/tcp_posix_test.cc
+++ b/test/core/iomgr/tcp_posix_test.cc
@@ -34,8 +34,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "test/core/iomgr/endpoint_tests.h"
 #include "test/core/util/test_config.h"
@@ -74,7 +74,7 @@
   int i;
   unsigned char buf[256];
   for (i = 0; i < 256; ++i) {
-    buf[i] = (uint8_t)i;
+    buf[i] = static_cast<uint8_t>(i);
   }
   do {
     write_bytes = write(fd, buf, 256);
@@ -89,16 +89,16 @@
 static size_t fill_socket_partial(int fd, size_t bytes) {
   ssize_t write_bytes;
   size_t total_bytes = 0;
-  unsigned char* buf = (unsigned char*)gpr_malloc(bytes);
+  unsigned char* buf = static_cast<unsigned char*>(gpr_malloc(bytes));
   unsigned i;
   for (i = 0; i < bytes; ++i) {
-    buf[i] = (uint8_t)(i % 256);
+    buf[i] = static_cast<uint8_t>(i % 256);
   }
 
   do {
     write_bytes = write(fd, buf, bytes - total_bytes);
     if (write_bytes > 0) {
-      total_bytes += (size_t)write_bytes;
+      total_bytes += static_cast<size_t>(write_bytes);
     }
   } while ((write_bytes >= 0 || errno == EINTR) && bytes > total_bytes);
 
@@ -132,7 +132,8 @@
 }
 
 static void read_cb(void* user_data, grpc_error* error) {
-  struct read_socket_state* state = (struct read_socket_state*)user_data;
+  struct read_socket_state* state =
+      static_cast<struct read_socket_state*>(user_data);
   size_t read_bytes;
   int current_data;
 
@@ -172,7 +173,8 @@
 
   grpc_arg a[1];
   a[0].key = const_cast<char*>(GRPC_ARG_TCP_READ_CHUNK_SIZE);
-  a[0].type = GRPC_ARG_INTEGER, a[0].value.integer = (int)slice_size;
+  a[0].type = GRPC_ARG_INTEGER,
+  a[0].value.integer = static_cast<int>(slice_size);
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
   ep = grpc_tcp_create(grpc_fd_create(sv[1], "read_test"), &args, "test");
   grpc_endpoint_add_to_pollset(ep, g_pollset);
@@ -222,7 +224,7 @@
   grpc_arg a[1];
   a[0].key = const_cast<char*>(GRPC_ARG_TCP_READ_CHUNK_SIZE);
   a[0].type = GRPC_ARG_INTEGER;
-  a[0].value.integer = (int)slice_size;
+  a[0].value.integer = static_cast<int>(slice_size);
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
   ep = grpc_tcp_create(grpc_fd_create(sv[1], "large_read_test"), &args, "test");
   grpc_endpoint_add_to_pollset(ep, g_pollset);
@@ -232,7 +234,7 @@
 
   state.ep = ep;
   state.read_bytes = 0;
-  state.target_read_bytes = (size_t)written_bytes;
+  state.target_read_bytes = static_cast<size_t>(written_bytes);
   grpc_slice_buffer_init(&state.incoming);
   GRPC_CLOSURE_INIT(&state.read_cb, read_cb, &state, grpc_schedule_on_exec_ctx);
 
@@ -262,7 +264,8 @@
 static grpc_slice* allocate_blocks(size_t num_bytes, size_t slice_size,
                                    size_t* num_blocks, uint8_t* current_data) {
   size_t nslices = num_bytes / slice_size + (num_bytes % slice_size ? 1u : 0u);
-  grpc_slice* slices = (grpc_slice*)gpr_malloc(sizeof(grpc_slice) * nslices);
+  grpc_slice* slices =
+      static_cast<grpc_slice*>(gpr_malloc(sizeof(grpc_slice) * nslices));
   size_t num_bytes_left = num_bytes;
   unsigned i, j;
   unsigned char* buf;
@@ -284,7 +287,8 @@
 
 static void write_done(void* user_data /* write_socket_state */,
                        grpc_error* error) {
-  struct write_socket_state* state = (struct write_socket_state*)user_data;
+  struct write_socket_state* state =
+      static_cast<struct write_socket_state*>(user_data);
   gpr_log(GPR_INFO, "Write done callback called");
   gpr_mu_lock(g_mu);
   gpr_log(GPR_INFO, "Signalling write done");
@@ -295,7 +299,7 @@
 }
 
 void drain_socket_blocking(int fd, size_t num_bytes, size_t read_size) {
-  unsigned char* buf = (unsigned char*)gpr_malloc(read_size);
+  unsigned char* buf = static_cast<unsigned char*>(gpr_malloc(read_size));
   ssize_t bytes_read;
   size_t bytes_left = num_bytes;
   int flags;
@@ -325,7 +329,7 @@
       GPR_ASSERT(buf[i] == current);
       current = (current + 1) % 256;
     }
-    bytes_left -= (size_t)bytes_read;
+    bytes_left -= static_cast<size_t>(bytes_read);
     if (bytes_left == 0) break;
   }
   flags = fcntl(fd, F_GETFL, 0);
@@ -358,7 +362,8 @@
 
   grpc_arg a[1];
   a[0].key = const_cast<char*>(GRPC_ARG_TCP_READ_CHUNK_SIZE);
-  a[0].type = GRPC_ARG_INTEGER, a[0].value.integer = (int)slice_size;
+  a[0].type = GRPC_ARG_INTEGER,
+  a[0].value.integer = static_cast<int>(slice_size);
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
   ep = grpc_tcp_create(grpc_fd_create(sv[1], "write_test"), &args, "test");
   grpc_endpoint_add_to_pollset(ep, g_pollset);
@@ -395,7 +400,7 @@
 }
 
 void on_fd_released(void* arg, grpc_error* errors) {
-  int* done = (int*)arg;
+  int* done = static_cast<int*>(arg);
   *done = 1;
   GPR_ASSERT(
       GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(g_pollset, nullptr)));
@@ -426,7 +431,7 @@
   grpc_arg a[1];
   a[0].key = const_cast<char*>(GRPC_ARG_TCP_READ_CHUNK_SIZE);
   a[0].type = GRPC_ARG_INTEGER;
-  a[0].value.integer = (int)slice_size;
+  a[0].value.integer = static_cast<int>(slice_size);
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
   ep = grpc_tcp_create(grpc_fd_create(sv[1], "read_test"), &args, "test");
   GPR_ASSERT(grpc_tcp_fd(ep) == sv[1] && sv[1] >= 0);
@@ -515,7 +520,7 @@
   grpc_arg a[1];
   a[0].key = const_cast<char*>(GRPC_ARG_TCP_READ_CHUNK_SIZE);
   a[0].type = GRPC_ARG_INTEGER;
-  a[0].value.integer = (int)slice_size;
+  a[0].value.integer = static_cast<int>(slice_size);
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
   f.client_ep =
       grpc_tcp_create(grpc_fd_create(sv[0], "fixture:client"), &args, "test");
@@ -533,7 +538,7 @@
 };
 
 static void destroy_pollset(void* p, grpc_error* error) {
-  grpc_pollset_destroy((grpc_pollset*)p);
+  grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
 }
 
 int main(int argc, char** argv) {
@@ -542,7 +547,7 @@
   grpc_init();
   {
     grpc_core::ExecCtx exec_ctx;
-    g_pollset = (grpc_pollset*)gpr_zalloc(grpc_pollset_size());
+    g_pollset = static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
     grpc_pollset_init(g_pollset, &g_mu);
     grpc_endpoint_tests(configs[0], g_pollset, g_mu);
     run_tests();
diff --git a/test/core/iomgr/tcp_server_posix_test.cc b/test/core/iomgr/tcp_server_posix_test.cc
index 3c9ca21..d646df1 100644
--- a/test/core/iomgr/tcp_server_posix_test.cc
+++ b/test/core/iomgr/tcp_server_posix_test.cc
@@ -181,13 +181,14 @@
 static void test_no_op_with_port(void) {
   grpc_core::ExecCtx exec_ctx;
   grpc_resolved_address resolved_addr;
-  struct sockaddr_in* addr = (struct sockaddr_in*)resolved_addr.addr;
+  struct sockaddr_in* addr =
+      reinterpret_cast<struct sockaddr_in*>(resolved_addr.addr);
   grpc_tcp_server* s;
   GPR_ASSERT(GRPC_ERROR_NONE == grpc_tcp_server_create(nullptr, nullptr, &s));
   LOG_TEST("test_no_op_with_port");
 
   memset(&resolved_addr, 0, sizeof(resolved_addr));
-  resolved_addr.len = sizeof(struct sockaddr_in);
+  resolved_addr.len = static_cast<socklen_t>(sizeof(struct sockaddr_in));
   addr->sin_family = AF_INET;
   int port = -1;
   GPR_ASSERT(grpc_tcp_server_add_port(s, &resolved_addr, &port) ==
@@ -200,14 +201,15 @@
 static void test_no_op_with_port_and_start(void) {
   grpc_core::ExecCtx exec_ctx;
   grpc_resolved_address resolved_addr;
-  struct sockaddr_in* addr = (struct sockaddr_in*)resolved_addr.addr;
+  struct sockaddr_in* addr =
+      reinterpret_cast<struct sockaddr_in*>(resolved_addr.addr);
   grpc_tcp_server* s;
   GPR_ASSERT(GRPC_ERROR_NONE == grpc_tcp_server_create(nullptr, nullptr, &s));
   LOG_TEST("test_no_op_with_port_and_start");
   int port = -1;
 
   memset(&resolved_addr, 0, sizeof(resolved_addr));
-  resolved_addr.len = sizeof(struct sockaddr_in);
+  resolved_addr.len = static_cast<socklen_t>(sizeof(struct sockaddr_in));
   addr->sin_family = AF_INET;
   GPR_ASSERT(grpc_tcp_server_add_port(s, &resolved_addr, &port) ==
                  GRPC_ERROR_NONE &&
@@ -225,7 +227,7 @@
   int clifd;
   int nconnects_before;
   const struct sockaddr* remote_addr =
-      (const struct sockaddr*)remote->addr.addr;
+      reinterpret_cast<const struct sockaddr*>(remote->addr.addr);
 
   gpr_log(GPR_INFO, "Connecting to %s", remote->str);
   gpr_mu_lock(g_mu);
@@ -237,7 +239,8 @@
     return GRPC_OS_ERROR(errno, "Failed to create socket");
   }
   gpr_log(GPR_DEBUG, "start connect to %s", remote->str);
-  if (connect(clifd, remote_addr, (socklen_t)remote->addr.len) != 0) {
+  if (connect(clifd, remote_addr, static_cast<socklen_t>(remote->addr.len)) !=
+      0) {
     gpr_mu_unlock(g_mu);
     close(clifd);
     return GRPC_OS_ERROR(errno, "connect");
@@ -286,9 +289,9 @@
   grpc_resolved_address resolved_addr;
   grpc_resolved_address resolved_addr1;
   struct sockaddr_storage* const addr =
-      (struct sockaddr_storage*)resolved_addr.addr;
+      reinterpret_cast<struct sockaddr_storage*>(resolved_addr.addr);
   struct sockaddr_storage* const addr1 =
-      (struct sockaddr_storage*)resolved_addr1.addr;
+      reinterpret_cast<struct sockaddr_storage*>(resolved_addr1.addr);
   unsigned svr_fd_count;
   int port;
   int svr_port;
@@ -305,13 +308,14 @@
   LOG_TEST("test_connect");
   gpr_log(GPR_INFO,
           "clients=%lu, num chan args=%lu, remote IP=%s, test_dst_addrs=%d",
-          (unsigned long)num_connects,
-          (unsigned long)(channel_args != nullptr ? channel_args->num_args : 0),
+          static_cast<unsigned long>(num_connects),
+          static_cast<unsigned long>(
+              channel_args != nullptr ? channel_args->num_args : 0),
           dst_addrs != nullptr ? "<specific>" : "::", test_dst_addrs);
   memset(&resolved_addr, 0, sizeof(resolved_addr));
   memset(&resolved_addr1, 0, sizeof(resolved_addr1));
-  resolved_addr.len = sizeof(struct sockaddr_storage);
-  resolved_addr1.len = sizeof(struct sockaddr_storage);
+  resolved_addr.len = static_cast<socklen_t>(sizeof(struct sockaddr_storage));
+  resolved_addr1.len = static_cast<socklen_t>(sizeof(struct sockaddr_storage));
   addr->ss_family = addr1->ss_family = AF_INET;
   GPR_ASSERT(GRPC_LOG_IF_ERROR(
       "grpc_tcp_server_add_port",
@@ -383,7 +387,7 @@
         size_t connect_num;
         test_addr dst;
         GPR_ASSERT(fd >= 0);
-        dst.addr.len = sizeof(dst.addr.addr);
+        dst.addr.len = static_cast<socklen_t>(sizeof(dst.addr.addr));
         GPR_ASSERT(getsockname(fd, (struct sockaddr*)dst.addr.addr,
                                (socklen_t*)&dst.addr.len) == 0);
         GPR_ASSERT(dst.addr.len <= sizeof(dst.addr.addr));
@@ -456,10 +460,10 @@
         continue;
       } else if (ifa_it->ifa_addr->sa_family == AF_INET) {
         dst_addrs->addrs[dst_addrs->naddrs].addr.len =
-            sizeof(struct sockaddr_in);
+            static_cast<socklen_t>(sizeof(struct sockaddr_in));
       } else if (ifa_it->ifa_addr->sa_family == AF_INET6) {
         dst_addrs->addrs[dst_addrs->naddrs].addr.len =
-            sizeof(struct sockaddr_in6);
+            static_cast<socklen_t>(sizeof(struct sockaddr_in6));
       } else {
         continue;
       }
diff --git a/test/core/iomgr/timer_heap_test.cc b/test/core/iomgr/timer_heap_test.cc
index f0ab434..ebe5e32 100644
--- a/test/core/iomgr/timer_heap_test.cc
+++ b/test/core/iomgr/timer_heap_test.cc
@@ -18,9 +18,6 @@
 
 #include "src/core/lib/iomgr/port.h"
 
-// This test only works with the generic timer implementation
-#ifdef GRPC_TIMER_USE_GENERIC
-
 #include "src/core/lib/iomgr/timer_heap.h"
 
 #include <stdlib.h>
@@ -28,8 +25,8 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
 
+#include "src/core/lib/gpr/useful.h"
 #include "test/core/util/test_config.h"
 
 static gpr_atm random_deadline(void) { return rand(); }
@@ -102,7 +99,7 @@
   check_valid(&pq);
 
   for (i = 0; i < num_test_operations; ++i) {
-    size_t elem_num = (size_t)rand() % num_test_elements;
+    size_t elem_num = static_cast<size_t>(rand()) % num_test_elements;
     grpc_timer* el = &test_elements[elem_num];
     if (!inpq[elem_num]) { /* not in pq */
       GPR_ASSERT(!contains(&pq, el));
@@ -142,8 +139,8 @@
     search_order[i] = i;
   }
   for (size_t i = 0; i < count * 2; i++) {
-    size_t a = (size_t)rand() % count;
-    size_t b = (size_t)rand() % count;
+    size_t a = static_cast<size_t>(rand()) % count;
+    size_t b = static_cast<size_t>(rand()) % count;
     GPR_SWAP(size_t, search_order[a], search_order[b]);
   }
   elem_struct* out = nullptr;
@@ -235,7 +232,7 @@
   size_t expected_size;
 
   /* A large random number to allow for multiple shrinkages, at least 512. */
-  const size_t num_elements = (size_t)rand() % 2000 + 512;
+  const size_t num_elements = static_cast<size_t>(rand()) % 2000 + 512;
 
   grpc_timer_heap_init(&pq);
 
@@ -265,7 +262,7 @@
      4 times the Size and not less than 2 times, but never goes below 16. */
   expected_size = pq.timer_count;
   while (pq.timer_count > 0) {
-    const size_t which = (size_t)rand() % pq.timer_count;
+    const size_t which = static_cast<size_t>(rand()) % pq.timer_count;
     grpc_timer* te = pq.timers[which];
     grpc_timer_heap_remove(&pq, te);
     gpr_free(te);
@@ -299,9 +296,3 @@
 
   return 0;
 }
-
-#else /* GRPC_TIMER_USE_GENERIC */
-
-int main(int argc, char** argv) { return 1; }
-
-#endif /* GRPC_TIMER_USE_GENERIC */
diff --git a/test/core/iomgr/timer_list_test.cc b/test/core/iomgr/timer_list_test.cc
index deb8c4d..b1d919b 100644
--- a/test/core/iomgr/timer_list_test.cc
+++ b/test/core/iomgr/timer_list_test.cc
@@ -19,8 +19,9 @@
 #include "src/core/lib/iomgr/port.h"
 
 // This test only works with the generic timer implementation
-#ifdef GRPC_TIMER_USE_GENERIC
+#ifndef GRPC_CUSTOM_SOCKET
 
+#include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/timer.h"
 
 #include <string.h>
@@ -153,15 +154,19 @@
 int main(int argc, char** argv) {
   grpc_test_init(argc, argv);
   grpc_core::ExecCtx::GlobalInit();
+  grpc_core::ExecCtx exec_ctx;
+  grpc_determine_iomgr_platform();
+  grpc_iomgr_platform_init();
   gpr_set_log_verbosity(GPR_LOG_SEVERITY_DEBUG);
   add_test();
   destruction_test();
+  grpc_iomgr_platform_shutdown();
   grpc_core::ExecCtx::GlobalShutdown();
   return 0;
 }
 
-#else /* GRPC_TIMER_USE_GENERIC */
+#else /* GRPC_CUSTOM_SOCKET */
 
 int main(int argc, char** argv) { return 1; }
 
-#endif /* GRPC_TIMER_USE_GENERIC */
+#endif /* GRPC_CUSTOM_SOCKET */
diff --git a/test/core/iomgr/udp_server_test.cc b/test/core/iomgr/udp_server_test.cc
index 09f0283..3058e87 100644
--- a/test/core/iomgr/udp_server_test.cc
+++ b/test/core/iomgr/udp_server_test.cc
@@ -33,9 +33,10 @@
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/iomgr/socket_factory_posix.h"
@@ -54,42 +55,70 @@
 int rcv_buf_size = 1024;
 int snd_buf_size = 1024;
 
-static void on_start(grpc_fd* emfd, void* user_data) { g_number_of_starts++; }
+class TestGrpcUdpHandler : public GrpcUdpHandler {
+ public:
+  TestGrpcUdpHandler(grpc_fd* emfd, void* user_data)
+      : GrpcUdpHandler(emfd, user_data), emfd_(emfd) {
+    g_number_of_starts++;
+  }
+  ~TestGrpcUdpHandler() override {}
 
-static bool on_read(grpc_fd* emfd) {
-  char read_buffer[512];
-  ssize_t byte_count;
+ protected:
+  bool Read() override {
+    char read_buffer[512];
+    ssize_t byte_count;
 
-  gpr_mu_lock(g_mu);
-  byte_count =
-      recv(grpc_fd_wrapped_fd(emfd), read_buffer, sizeof(read_buffer), 0);
+    gpr_mu_lock(g_mu);
+    byte_count =
+        recv(grpc_fd_wrapped_fd(emfd()), read_buffer, sizeof(read_buffer), 0);
 
-  g_number_of_reads++;
-  g_number_of_bytes_read += (int)byte_count;
+    g_number_of_reads++;
+    g_number_of_bytes_read += static_cast<int>(byte_count);
 
-  GPR_ASSERT(
-      GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(g_pollset, nullptr)));
-  gpr_mu_unlock(g_mu);
-  return false;
-}
+    GPR_ASSERT(GRPC_LOG_IF_ERROR("pollset_kick",
+                                 grpc_pollset_kick(g_pollset, nullptr)));
+    gpr_mu_unlock(g_mu);
+    return false;
+  }
 
-static void on_write(grpc_fd* emfd, void* user_data,
-                     grpc_closure* notify_on_write_closure) {
-  gpr_mu_lock(g_mu);
-  g_number_of_writes++;
+  void OnCanWrite(void* user_data,
+                  grpc_closure* notify_on_write_closure) override {
+    gpr_mu_lock(g_mu);
+    g_number_of_writes++;
 
-  GPR_ASSERT(
-      GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(g_pollset, nullptr)));
-  gpr_mu_unlock(g_mu);
-}
+    GPR_ASSERT(GRPC_LOG_IF_ERROR("pollset_kick",
+                                 grpc_pollset_kick(g_pollset, nullptr)));
+    gpr_mu_unlock(g_mu);
+  }
 
-static void on_fd_orphaned(grpc_fd* emfd, grpc_closure* closure,
-                           void* user_data) {
-  gpr_log(GPR_INFO, "gRPC FD about to be orphaned: %d",
-          grpc_fd_wrapped_fd(emfd));
-  GRPC_CLOSURE_SCHED(closure, GRPC_ERROR_NONE);
-  g_number_of_orphan_calls++;
-}
+  void OnFdAboutToOrphan(grpc_closure* orphan_fd_closure,
+                         void* user_data) override {
+    gpr_log(GPR_INFO, "gRPC FD about to be orphaned: %d",
+            grpc_fd_wrapped_fd(emfd()));
+    GRPC_CLOSURE_SCHED(orphan_fd_closure, GRPC_ERROR_NONE);
+    g_number_of_orphan_calls++;
+  }
+
+  grpc_fd* emfd() { return emfd_; }
+
+ private:
+  grpc_fd* emfd_;
+};
+
+class TestGrpcUdpHandlerFactory : public GrpcUdpHandlerFactory {
+ public:
+  GrpcUdpHandler* CreateUdpHandler(grpc_fd* emfd, void* user_data) override {
+    gpr_log(GPR_INFO, "create udp handler for fd %d", grpc_fd_wrapped_fd(emfd));
+    return grpc_core::New<TestGrpcUdpHandler>(emfd, user_data);
+  }
+
+  void DestroyUdpHandler(GrpcUdpHandler* handler) override {
+    gpr_log(GPR_INFO, "Destroy handler");
+    grpc_core::Delete(reinterpret_cast<TestGrpcUdpHandler*>(handler));
+  }
+};
+
+TestGrpcUdpHandlerFactory handler_factory;
 
 struct test_socket_factory {
   grpc_socket_factory base;
@@ -100,16 +129,18 @@
 
 static int test_socket_factory_socket(grpc_socket_factory* factory, int domain,
                                       int type, int protocol) {
-  test_socket_factory* f = (test_socket_factory*)factory;
+  test_socket_factory* f = reinterpret_cast<test_socket_factory*>(factory);
   f->number_of_socket_calls++;
   return socket(domain, type, protocol);
 }
 
 static int test_socket_factory_bind(grpc_socket_factory* factory, int sockfd,
                                     const grpc_resolved_address* addr) {
-  test_socket_factory* f = (test_socket_factory*)factory;
+  test_socket_factory* f = reinterpret_cast<test_socket_factory*>(factory);
   f->number_of_bind_calls++;
-  return bind(sockfd, (struct sockaddr*)addr->addr, (socklen_t)addr->len);
+  return bind(sockfd,
+              reinterpret_cast<struct sockaddr*>(const_cast<char*>(addr->addr)),
+              static_cast<socklen_t>(addr->len));
 }
 
 static int test_socket_factory_compare(grpc_socket_factory* a,
@@ -118,7 +149,7 @@
 }
 
 static void test_socket_factory_destroy(grpc_socket_factory* factory) {
-  test_socket_factory* f = (test_socket_factory*)factory;
+  test_socket_factory* f = reinterpret_cast<test_socket_factory*>(factory);
   gpr_free(f);
 }
 
@@ -173,21 +204,21 @@
   g_number_of_orphan_calls = 0;
   grpc_core::ExecCtx exec_ctx;
   grpc_resolved_address resolved_addr;
-  struct sockaddr_in* addr = (struct sockaddr_in*)resolved_addr.addr;
+  struct sockaddr_in* addr =
+      reinterpret_cast<struct sockaddr_in*>(resolved_addr.addr);
   grpc_udp_server* s = grpc_udp_server_create(nullptr);
   LOG_TEST("test_no_op_with_port");
 
   memset(&resolved_addr, 0, sizeof(resolved_addr));
-  resolved_addr.len = sizeof(struct sockaddr_in);
+  resolved_addr.len = static_cast<socklen_t>(sizeof(struct sockaddr_in));
   addr->sin_family = AF_INET;
   GPR_ASSERT(grpc_udp_server_add_port(s, &resolved_addr, rcv_buf_size,
-                                      snd_buf_size, on_start, on_read, on_write,
-                                      on_fd_orphaned));
+                                      snd_buf_size, &handler_factory));
 
   grpc_udp_server_destroy(s, nullptr);
 
-  /* The server had a single FD, which should have been orphaned. */
-  GPR_ASSERT(g_number_of_orphan_calls == 1);
+  /* The server haven't start listening, so no udp handler to be notified. */
+  GPR_ASSERT(g_number_of_orphan_calls == 0);
   shutdown_and_destroy_pollset();
 }
 
@@ -196,7 +227,8 @@
   g_number_of_orphan_calls = 0;
   grpc_core::ExecCtx exec_ctx;
   grpc_resolved_address resolved_addr;
-  struct sockaddr_in* addr = (struct sockaddr_in*)resolved_addr.addr;
+  struct sockaddr_in* addr =
+      reinterpret_cast<struct sockaddr_in*>(resolved_addr.addr);
 
   test_socket_factory* socket_factory = test_socket_factory_create();
   grpc_arg socket_factory_arg =
@@ -209,11 +241,10 @@
   LOG_TEST("test_no_op_with_port_and_socket_factory");
 
   memset(&resolved_addr, 0, sizeof(resolved_addr));
-  resolved_addr.len = sizeof(struct sockaddr_in);
+  resolved_addr.len = static_cast<socklen_t>(sizeof(struct sockaddr_in));
   addr->sin_family = AF_INET;
   GPR_ASSERT(grpc_udp_server_add_port(s, &resolved_addr, rcv_buf_size,
-                                      snd_buf_size, on_start, on_read, on_write,
-                                      on_fd_orphaned));
+                                      snd_buf_size, &handler_factory));
   GPR_ASSERT(socket_factory->number_of_socket_calls == 1);
   GPR_ASSERT(socket_factory->number_of_bind_calls == 1);
 
@@ -221,8 +252,8 @@
 
   grpc_socket_factory_unref(&socket_factory->base);
 
-  /* The server had a single FD, which should have been orphaned. */
-  GPR_ASSERT(g_number_of_orphan_calls == 1);
+  /* The server haven't start listening, so no udp handler to be notified. */
+  GPR_ASSERT(g_number_of_orphan_calls == 0);
   shutdown_and_destroy_pollset();
 }
 
@@ -231,16 +262,16 @@
   g_number_of_orphan_calls = 0;
   grpc_core::ExecCtx exec_ctx;
   grpc_resolved_address resolved_addr;
-  struct sockaddr_in* addr = (struct sockaddr_in*)resolved_addr.addr;
+  struct sockaddr_in* addr =
+      reinterpret_cast<struct sockaddr_in*>(resolved_addr.addr);
   grpc_udp_server* s = grpc_udp_server_create(nullptr);
   LOG_TEST("test_no_op_with_port_and_start");
 
   memset(&resolved_addr, 0, sizeof(resolved_addr));
-  resolved_addr.len = sizeof(struct sockaddr_in);
+  resolved_addr.len = static_cast<socklen_t>(sizeof(struct sockaddr_in));
   addr->sin_family = AF_INET;
   GPR_ASSERT(grpc_udp_server_add_port(s, &resolved_addr, rcv_buf_size,
-                                      snd_buf_size, on_start, on_read, on_write,
-                                      on_fd_orphaned));
+                                      snd_buf_size, &handler_factory));
 
   grpc_udp_server_start(s, nullptr, 0, nullptr);
   GPR_ASSERT(g_number_of_starts == 1);
@@ -256,7 +287,8 @@
   grpc_pollset_init(g_pollset, &g_mu);
   grpc_core::ExecCtx exec_ctx;
   grpc_resolved_address resolved_addr;
-  struct sockaddr_storage* addr = (struct sockaddr_storage*)resolved_addr.addr;
+  struct sockaddr_storage* addr =
+      reinterpret_cast<struct sockaddr_storage*>(resolved_addr.addr);
   int clifd, svrfd;
   grpc_udp_server* s = grpc_udp_server_create(nullptr);
   int i;
@@ -269,11 +301,10 @@
   g_number_of_orphan_calls = 0;
 
   memset(&resolved_addr, 0, sizeof(resolved_addr));
-  resolved_addr.len = sizeof(struct sockaddr_storage);
+  resolved_addr.len = static_cast<socklen_t>(sizeof(struct sockaddr_storage));
   addr->ss_family = AF_INET;
   GPR_ASSERT(grpc_udp_server_add_port(s, &resolved_addr, rcv_buf_size,
-                                      snd_buf_size, on_start, on_read, on_write,
-                                      on_fd_orphaned));
+                                      snd_buf_size, &handler_factory));
 
   svrfd = grpc_udp_server_get_fd(s, 0);
   GPR_ASSERT(svrfd >= 0);
diff --git a/test/core/iomgr/wakeup_fd_cv_test.cc b/test/core/iomgr/wakeup_fd_cv_test.cc
index c092a8f..f297a56 100644
--- a/test/core/iomgr/wakeup_fd_cv_test.cc
+++ b/test/core/iomgr/wakeup_fd_cv_test.cc
@@ -23,11 +23,10 @@
 #include <pthread.h>
 
 #include <grpc/support/log.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/iomgr_posix.h"
 
@@ -85,7 +84,7 @@
 }
 
 void background_poll(void* args) {
-  poll_args* pargs = (poll_args*)args;
+  poll_args* pargs = static_cast<poll_args*>(args);
   pargs->result = grpc_poll_function(pargs->fds, pargs->nfds, pargs->timeout);
 }
 
@@ -104,8 +103,6 @@
   grpc_wakeup_fd cvfd1, cvfd2, cvfd3;
   struct pollfd pfds[6];
   poll_args pargs;
-  gpr_thd_id t_id;
-  gpr_thd_options opt;
 
   GPR_ASSERT(grpc_wakeup_fd_init(&cvfd1) == GRPC_ERROR_NONE);
   GPR_ASSERT(grpc_wakeup_fd_init(&cvfd2) == GRPC_ERROR_NONE);
@@ -136,79 +133,91 @@
   pargs.timeout = 1000;
   pargs.result = -2;
 
-  opt = gpr_thd_options_default();
-  gpr_thd_options_set_joinable(&opt);
-  gpr_thd_new(&t_id, "grpc_background_poll", &background_poll, &pargs, &opt);
+  {
+    grpc_core::Thread thd("grpc_background_poll", &background_poll, &pargs);
+    thd.Start();
+    // Wakeup wakeup_fd not listening for events
+    GPR_ASSERT(grpc_wakeup_fd_wakeup(&cvfd1) == GRPC_ERROR_NONE);
+    thd.Join();
+    GPR_ASSERT(pargs.result == 0);
+    GPR_ASSERT(pfds[0].revents == 0);
+    GPR_ASSERT(pfds[1].revents == 0);
+    GPR_ASSERT(pfds[2].revents == 0);
+    GPR_ASSERT(pfds[3].revents == 0);
+    GPR_ASSERT(pfds[4].revents == 0);
+    GPR_ASSERT(pfds[5].revents == 0);
+  }
 
-  // Wakeup wakeup_fd not listening for events
-  GPR_ASSERT(grpc_wakeup_fd_wakeup(&cvfd1) == GRPC_ERROR_NONE);
-  gpr_thd_join(t_id);
-  GPR_ASSERT(pargs.result == 0);
-  GPR_ASSERT(pfds[0].revents == 0);
-  GPR_ASSERT(pfds[1].revents == 0);
-  GPR_ASSERT(pfds[2].revents == 0);
-  GPR_ASSERT(pfds[3].revents == 0);
-  GPR_ASSERT(pfds[4].revents == 0);
-  GPR_ASSERT(pfds[5].revents == 0);
+  {
+    // Pollin on socket fd
+    pargs.timeout = -1;
+    pargs.result = -2;
+    grpc_core::Thread thd("grpc_background_poll", &background_poll, &pargs);
+    thd.Start();
+    trigger_socket_event();
+    thd.Join();
+    GPR_ASSERT(pargs.result == 1);
+    GPR_ASSERT(pfds[0].revents == 0);
+    GPR_ASSERT(pfds[1].revents == 0);
+    GPR_ASSERT(pfds[2].revents == POLLIN);
+    GPR_ASSERT(pfds[3].revents == 0);
+    GPR_ASSERT(pfds[4].revents == 0);
+    GPR_ASSERT(pfds[5].revents == 0);
+  }
 
-  // Pollin on socket fd
-  pargs.timeout = -1;
-  pargs.result = -2;
-  gpr_thd_new(&t_id, "grpc_background_poll", &background_poll, &pargs, &opt);
-  trigger_socket_event();
-  gpr_thd_join(t_id);
-  GPR_ASSERT(pargs.result == 1);
-  GPR_ASSERT(pfds[0].revents == 0);
-  GPR_ASSERT(pfds[1].revents == 0);
-  GPR_ASSERT(pfds[2].revents == POLLIN);
-  GPR_ASSERT(pfds[3].revents == 0);
-  GPR_ASSERT(pfds[4].revents == 0);
-  GPR_ASSERT(pfds[5].revents == 0);
+  {
+    // Pollin on wakeup fd
+    reset_socket_event();
+    pargs.result = -2;
+    grpc_core::Thread thd("grpc_background_poll", &background_poll, &pargs);
+    thd.Start();
+    GPR_ASSERT(grpc_wakeup_fd_wakeup(&cvfd2) == GRPC_ERROR_NONE);
+    thd.Join();
 
-  // Pollin on wakeup fd
-  reset_socket_event();
-  pargs.result = -2;
-  gpr_thd_new(&t_id, "grpc_background_poll", &background_poll, &pargs, &opt);
-  GPR_ASSERT(grpc_wakeup_fd_wakeup(&cvfd2) == GRPC_ERROR_NONE);
-  gpr_thd_join(t_id);
+    GPR_ASSERT(pargs.result == 1);
+    GPR_ASSERT(pfds[0].revents == 0);
+    GPR_ASSERT(pfds[1].revents == POLLIN);
+    GPR_ASSERT(pfds[2].revents == 0);
+    GPR_ASSERT(pfds[3].revents == 0);
+    GPR_ASSERT(pfds[4].revents == 0);
+    GPR_ASSERT(pfds[5].revents == 0);
+  }
 
-  GPR_ASSERT(pargs.result == 1);
-  GPR_ASSERT(pfds[0].revents == 0);
-  GPR_ASSERT(pfds[1].revents == POLLIN);
-  GPR_ASSERT(pfds[2].revents == 0);
-  GPR_ASSERT(pfds[3].revents == 0);
-  GPR_ASSERT(pfds[4].revents == 0);
-  GPR_ASSERT(pfds[5].revents == 0);
+  {
+    // Pollin on wakeupfd before poll()
+    pargs.result = -2;
+    grpc_core::Thread thd("grpc_background_poll", &background_poll, &pargs);
+    thd.Start();
+    thd.Join();
 
-  // Pollin on wakeupfd before poll()
-  pargs.result = -2;
-  gpr_thd_new(&t_id, "grpc_background_poll", &background_poll, &pargs, &opt);
-  gpr_thd_join(t_id);
+    GPR_ASSERT(pargs.result == 1);
+    GPR_ASSERT(pfds[0].revents == 0);
+    GPR_ASSERT(pfds[1].revents == POLLIN);
+    GPR_ASSERT(pfds[2].revents == 0);
+    GPR_ASSERT(pfds[3].revents == 0);
+    GPR_ASSERT(pfds[4].revents == 0);
+    GPR_ASSERT(pfds[5].revents == 0);
+  }
 
-  GPR_ASSERT(pargs.result == 1);
-  GPR_ASSERT(pfds[0].revents == 0);
-  GPR_ASSERT(pfds[1].revents == POLLIN);
-  GPR_ASSERT(pfds[2].revents == 0);
-  GPR_ASSERT(pfds[3].revents == 0);
-  GPR_ASSERT(pfds[4].revents == 0);
-  GPR_ASSERT(pfds[5].revents == 0);
+  {
+    // No Events
+    pargs.result = -2;
+    pargs.timeout = 1000;
+    reset_socket_event();
+    GPR_ASSERT(grpc_wakeup_fd_consume_wakeup(&cvfd1) == GRPC_ERROR_NONE);
+    GPR_ASSERT(grpc_wakeup_fd_consume_wakeup(&cvfd2) == GRPC_ERROR_NONE);
+    grpc_core::Thread thd("grpc_background_poll", &background_poll, &pargs);
+    thd.Start();
+    thd.Join();
 
-  // No Events
-  pargs.result = -2;
-  pargs.timeout = 1000;
-  reset_socket_event();
-  GPR_ASSERT(grpc_wakeup_fd_consume_wakeup(&cvfd1) == GRPC_ERROR_NONE);
-  GPR_ASSERT(grpc_wakeup_fd_consume_wakeup(&cvfd2) == GRPC_ERROR_NONE);
-  gpr_thd_new(&t_id, "grpc_background_poll", &background_poll, &pargs, &opt);
-  gpr_thd_join(t_id);
-
-  GPR_ASSERT(pargs.result == 0);
-  GPR_ASSERT(pfds[0].revents == 0);
-  GPR_ASSERT(pfds[1].revents == 0);
-  GPR_ASSERT(pfds[2].revents == 0);
-  GPR_ASSERT(pfds[3].revents == 0);
-  GPR_ASSERT(pfds[4].revents == 0);
-  GPR_ASSERT(pfds[5].revents == 0);
+    GPR_ASSERT(pargs.result == 0);
+    GPR_ASSERT(pfds[0].revents == 0);
+    GPR_ASSERT(pfds[1].revents == 0);
+    GPR_ASSERT(pfds[2].revents == 0);
+    GPR_ASSERT(pfds[3].revents == 0);
+    GPR_ASSERT(pfds[4].revents == 0);
+    GPR_ASSERT(pfds[5].revents == 0);
+  }
 }
 
 int main(int argc, char** argv) {
@@ -216,7 +225,7 @@
   grpc_poll_function = &mock_poll;
   gpr_mu_init(&poll_mu);
   gpr_cv_init(&poll_cv);
-
+  grpc_determine_iomgr_platform();
   grpc_iomgr_platform_init();
   test_many_fds();
   grpc_iomgr_platform_shutdown();
diff --git a/test/core/json/json_rewrite.cc b/test/core/json/json_rewrite.cc
index 6891a57..da2f50e 100644
--- a/test/core/json/json_rewrite.cc
+++ b/test/core/json/json_rewrite.cc
@@ -20,11 +20,11 @@
 #include <stdlib.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/cmdline.h>
 #include <grpc/support/log.h>
 
 #include "src/core/lib/json/json_reader.h"
 #include "src/core/lib/json/json_writer.h"
+#include "test/core/util/cmdline.h"
 
 typedef struct json_writer_userdata {
   FILE* out;
@@ -86,7 +86,7 @@
   json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
   check_string(state, 1);
   GPR_ASSERT(c < 256);
-  state->scratchpad[state->string_len++] = (char)c;
+  state->scratchpad[state->string_len++] = static_cast<char>(c);
 }
 
 static void json_reader_string_add_utf32(void* userdata, uint32_t c) {
@@ -122,7 +122,7 @@
 
   r = fgetc(state->in);
   if (r == EOF) r = GRPC_JSON_READ_CHAR_EOF;
-  return (uint32_t)r;
+  return static_cast<uint32_t>(r);
 }
 
 static void json_reader_container_begins(void* userdata, grpc_json_type type) {
diff --git a/test/core/json/json_rewrite_test.cc b/test/core/json/json_rewrite_test.cc
index 3104afc..2fade12 100644
--- a/test/core/json/json_rewrite_test.cc
+++ b/test/core/json/json_rewrite_test.cc
@@ -21,9 +21,9 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
 #include "test/core/util/test_config.h"
 
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/json/json_reader.h"
 #include "src/core/lib/json/json_writer.h"
 
@@ -97,7 +97,7 @@
   json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
   check_string(state, 1);
   GPR_ASSERT(c <= 256);
-  state->scratchpad[state->string_len++] = (char)c;
+  state->scratchpad[state->string_len++] = static_cast<char>(c);
 }
 
 static void json_reader_string_add_utf32(void* userdata, uint32_t c) {
@@ -140,7 +140,7 @@
 
   r = fgetc(state->in);
   if (r == EOF) r = GRPC_JSON_READ_CHAR_EOF;
-  return (uint32_t)r;
+  return static_cast<uint32_t>(r);
 }
 
 static void json_reader_container_begins(void* userdata, grpc_json_type type) {
diff --git a/test/core/json/json_stream_error_test.cc b/test/core/json/json_stream_error_test.cc
index b367d3f..00288d6 100644
--- a/test/core/json/json_stream_error_test.cc
+++ b/test/core/json/json_stream_error_test.cc
@@ -21,7 +21,6 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
 #include "test/core/util/test_config.h"
 
 #include "src/core/lib/json/json_reader.h"
diff --git a/test/core/json/json_test.cc b/test/core/json/json_test.cc
index 902f1cd..7f1dbb7 100644
--- a/test/core/json/json_test.cc
+++ b/test/core/json/json_test.cc
@@ -21,8 +21,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/json/json.h"
 
 #include "test/core/util/test_config.h"
diff --git a/test/core/memory_usage/client.cc b/test/core/memory_usage/client.cc
index ca84143..3c3fa53 100644
--- a/test/core/memory_usage/client.cc
+++ b/test/core/memory_usage/client.cc
@@ -24,12 +24,13 @@
 #include <grpc/byte_buffer.h>
 #include <grpc/byte_buffer_reader.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/cmdline.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+
+#include "test/core/util/cmdline.h"
 #include "test/core/util/memory_counters.h"
 #include "test/core/util/test_config.h"
 
@@ -154,16 +155,20 @@
 
   struct grpc_memory_counters snapshot;
   snapshot.total_size_absolute =
-      ((struct grpc_memory_counters*)GRPC_SLICE_START_PTR(response))
+      (reinterpret_cast<struct grpc_memory_counters*> GRPC_SLICE_START_PTR(
+           response))
           ->total_size_absolute;
   snapshot.total_allocs_absolute =
-      ((struct grpc_memory_counters*)GRPC_SLICE_START_PTR(response))
+      (reinterpret_cast<struct grpc_memory_counters*> GRPC_SLICE_START_PTR(
+           response))
           ->total_allocs_absolute;
   snapshot.total_size_relative =
-      ((struct grpc_memory_counters*)GRPC_SLICE_START_PTR(response))
+      (reinterpret_cast<struct grpc_memory_counters*> GRPC_SLICE_START_PTR(
+           response))
           ->total_size_relative;
   snapshot.total_allocs_relative =
-      ((struct grpc_memory_counters*)GRPC_SLICE_START_PTR(response))
+      (reinterpret_cast<struct grpc_memory_counters*> GRPC_SLICE_START_PTR(
+           response))
           ->total_allocs_relative;
 
   grpc_metadata_array_destroy(&calls[call_idx].initial_metadata_recv);
@@ -283,10 +288,11 @@
   grpc_shutdown();
 
   gpr_log(GPR_INFO, "---------client stats--------");
-  gpr_log(GPR_INFO, "client call memory usage: %f bytes per call",
-          (double)(client_calls_inflight.total_size_relative -
-                   client_benchmark_calls_start.total_size_relative) /
-              benchmark_iterations);
+  gpr_log(
+      GPR_INFO, "client call memory usage: %f bytes per call",
+      static_cast<double>(client_calls_inflight.total_size_relative -
+                          client_benchmark_calls_start.total_size_relative) /
+          benchmark_iterations);
   gpr_log(GPR_INFO, "client channel memory usage %zi bytes",
           client_channel_end.total_size_relative -
               client_channel_start.total_size_relative);
@@ -295,10 +301,11 @@
   gpr_log(GPR_INFO, "server create: %zi bytes",
           after_server_create.total_size_relative -
               before_server_create.total_size_relative);
-  gpr_log(GPR_INFO, "server call memory usage: %f bytes per call",
-          (double)(server_calls_inflight.total_size_relative -
-                   server_benchmark_calls_start.total_size_relative) /
-              benchmark_iterations);
+  gpr_log(
+      GPR_INFO, "server call memory usage: %f bytes per call",
+      static_cast<double>(server_calls_inflight.total_size_relative -
+                          server_benchmark_calls_start.total_size_relative) /
+          benchmark_iterations);
   gpr_log(GPR_INFO, "server channel memory usage %zi bytes",
           server_calls_end.total_size_relative -
               after_server_create.total_size_relative);
@@ -308,21 +315,22 @@
   if (csv) {
     char* env_build = gpr_getenv("BUILD_NUMBER");
     char* env_job = gpr_getenv("JOB_NAME");
-    fprintf(csv, "%f,%zi,%zi,%f,%zi,%s,%s\n",
-            (double)(client_calls_inflight.total_size_relative -
-                     client_benchmark_calls_start.total_size_relative) /
-                benchmark_iterations,
-            client_channel_end.total_size_relative -
-                client_channel_start.total_size_relative,
-            after_server_create.total_size_relative -
-                before_server_create.total_size_relative,
-            (double)(server_calls_inflight.total_size_relative -
-                     server_benchmark_calls_start.total_size_relative) /
-                benchmark_iterations,
-            server_calls_end.total_size_relative -
-                after_server_create.total_size_relative,
-            env_build == nullptr ? "" : env_build,
-            env_job == nullptr ? "" : env_job);
+    fprintf(
+        csv, "%f,%zi,%zi,%f,%zi,%s,%s\n",
+        static_cast<double>(client_calls_inflight.total_size_relative -
+                            client_benchmark_calls_start.total_size_relative) /
+            benchmark_iterations,
+        client_channel_end.total_size_relative -
+            client_channel_start.total_size_relative,
+        after_server_create.total_size_relative -
+            before_server_create.total_size_relative,
+        static_cast<double>(server_calls_inflight.total_size_relative -
+                            server_benchmark_calls_start.total_size_relative) /
+            benchmark_iterations,
+        server_calls_end.total_size_relative -
+            after_server_create.total_size_relative,
+        env_build == nullptr ? "" : env_build,
+        env_job == nullptr ? "" : env_job);
     fclose(csv);
     gpr_log(GPR_INFO, "Summary written to %s", csv_file);
   }
diff --git a/test/core/memory_usage/memory_usage_test.cc b/test/core/memory_usage/memory_usage_test.cc
index fb6d290..c170f5a 100644
--- a/test/core/memory_usage/memory_usage_test.cc
+++ b/test/core/memory_usage/memory_usage_test.cc
@@ -20,11 +20,12 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/subprocess.h>
+
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
 #include "test/core/util/port.h"
+#include "test/core/util/subprocess.h"
 
 int main(int argc, char** argv) {
   char* me = argv[0];
@@ -36,7 +37,7 @@
   gpr_subprocess *svr, *cli;
   /* figure out where we are */
   if (lslash) {
-    memcpy(root, me, (size_t)(lslash - me));
+    memcpy(root, me, static_cast<size_t>(lslash - me));
     root[lslash - me] = 0;
   } else {
     strcpy(root, ".");
diff --git a/test/core/memory_usage/server.cc b/test/core/memory_usage/server.cc
index 45aeaea..3e7bb7e 100644
--- a/test/core/memory_usage/server.cc
+++ b/test/core/memory_usage/server.cc
@@ -30,11 +30,12 @@
 #endif
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/cmdline.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
+
+#include "src/core/lib/gpr/host_port.h"
 #include "test/core/end2end/data/ssl_test_data.h"
+#include "test/core/util/cmdline.h"
 #include "test/core/util/memory_counters.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
@@ -72,7 +73,7 @@
 static fling_call calls[100006];
 
 static void request_call_unary(int call_idx) {
-  if (call_idx == (int)(sizeof(calls) / sizeof(fling_call))) {
+  if (call_idx == static_cast<int>(sizeof(calls) / sizeof(fling_call))) {
     gpr_log(GPR_INFO, "Used all call slots (10000) on server. Server exit.");
     _exit(0);
   }
@@ -83,7 +84,8 @@
 }
 
 static void send_initial_metadata_unary(void* tag) {
-  grpc_metadata_array_init(&(*(fling_call*)tag).initial_metadata_send);
+  grpc_metadata_array_init(
+      &(*static_cast<fling_call*>(tag)).initial_metadata_send);
   metadata_ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
   metadata_ops[0].data.send_initial_metadata.count = 0;
 
@@ -110,7 +112,8 @@
   grpc_slice snapshot_slice =
       grpc_slice_new(snapshot, sizeof(*snapshot), gpr_free);
   payload_buffer = grpc_raw_byte_buffer_create(&snapshot_slice, 1);
-  grpc_metadata_array_init(&(*(fling_call*)tag).initial_metadata_send);
+  grpc_metadata_array_init(
+      &(*static_cast<fling_call*>(tag)).initial_metadata_send);
 
   op = snapshot_ops;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
@@ -162,7 +165,7 @@
   grpc_test_init(1, fake_argv);
 
   grpc_init();
-  srand((unsigned)clock());
+  srand(static_cast<unsigned>(clock()));
 
   cl = gpr_cmdline_create("fling server");
   gpr_cmdline_add_string(cl, "bind", "Bind host:port", &addr);
@@ -203,7 +206,8 @@
   addr = addr_buf = nullptr;
 
   // initialize call instances
-  for (int i = 0; i < (int)(sizeof(calls) / sizeof(fling_call)); i++) {
+  for (int i = 0; i < static_cast<int>(sizeof(calls) / sizeof(fling_call));
+       i++) {
     grpc_call_details_init(&calls[i].call_details);
     calls[i].state = FLING_SERVER_NEW_REQUEST;
   }
@@ -280,7 +284,8 @@
             grpc_metadata_array_destroy(&s->request_metadata_recv);
             break;
           case FLING_SERVER_BATCH_SEND_STATUS_FLING_CALL:
-            for (int k = 0; k < (int)(sizeof(calls) / sizeof(fling_call));
+            for (int k = 0;
+                 k < static_cast<int>(sizeof(calls) / sizeof(fling_call));
                  ++k) {
               if (calls[k].state == FLING_SERVER_WAIT_FOR_DESTROY) {
                 calls[k].state = FLING_SERVER_SEND_STATUS_FLING_CALL;
diff --git a/test/core/network_benchmarks/low_level_ping_pong.cc b/test/core/network_benchmarks/low_level_ping_pong.cc
index fb982a1..a983b18 100644
--- a/test/core/network_benchmarks/low_level_ping_pong.cc
+++ b/test/core/network_benchmarks/low_level_ping_pong.cc
@@ -35,13 +35,14 @@
 #include <sys/socket.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/cmdline.h>
 #include <grpc/support/log.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/socket_utils_posix.h"
+#include "test/core/util/cmdline.h"
 #include "test/core/util/histogram.h"
 
 typedef struct fd_pair {
@@ -83,7 +84,7 @@
         return -1;
       }
     } else {
-      bytes_read += (size_t)err;
+      bytes_read += static_cast<size_t>(err);
     }
   } while (bytes_read < read_size);
   return 0;
@@ -126,7 +127,7 @@
       gpr_log(GPR_ERROR, "Read failed: %s", strerror(errno));
       return -1;
     }
-    bytes_read += (size_t)err2;
+    bytes_read += static_cast<size_t>(err2);
   } while (bytes_read < read_size);
   return 0;
 }
@@ -165,7 +166,7 @@
             read(args->fds.read_fd, buf + bytes_read, read_size - bytes_read);
       } while (err2 < 0 && errno == EINTR);
       if (errno == EAGAIN) break;
-      bytes_read += (size_t)err2;
+      bytes_read += static_cast<size_t>(err2);
       /* TODO(klempner): This should really be doing an extra call after we are
          done to ensure we see an EAGAIN */
     } while (bytes_read < read_size);
@@ -202,7 +203,7 @@
         return -1;
       }
     } else {
-      bytes_written += (size_t)err;
+      bytes_written += static_cast<size_t>(err);
     }
   } while (bytes_written < write_size);
   return 0;
@@ -287,7 +288,7 @@
 
 static double now(void) {
   gpr_timespec tv = gpr_now(GPR_CLOCK_REALTIME);
-  return 1e9 * (double)tv.tv_sec + (double)tv.tv_nsec;
+  return 1e9 * static_cast<double>(tv.tv_sec) + static_cast<double>(tv.tv_nsec);
 }
 
 static void client_thread(thread_args* args) {
@@ -419,7 +420,7 @@
   int server_fd = -1;
 
   struct sockaddr_in port;
-  struct sockaddr* sa_port = (struct sockaddr*)&port;
+  struct sockaddr* sa_port = reinterpret_cast<struct sockaddr*>(&port);
 
   port.sin_family = AF_INET;
   port.sin_port = 0;
@@ -574,7 +575,6 @@
 
 static int run_benchmark(const char* socket_type, thread_args* client_args,
                          thread_args* server_args) {
-  gpr_thd_id tid;
   int rv = 0;
 
   rv = create_socket(socket_type, &client_args->fds, &server_args->fds);
@@ -585,8 +585,11 @@
   gpr_log(GPR_INFO, "Starting test %s %s %zu", client_args->strategy_name,
           socket_type, client_args->msg_size);
 
-  gpr_thd_new(&tid, "server_thread", server_thread_wrap, server_args, nullptr);
+  grpc_core::Thread server("server_thread", server_thread_wrap, server_args);
+  server.Start();
   client_thread(client_args);
+  server.Join();
+
   return 0;
 }
 
@@ -651,7 +654,7 @@
 
   if (read_strategy == nullptr) {
     gpr_log(GPR_INFO, "No strategy specified, running all benchmarks");
-    return run_all_benchmarks((size_t)msg_size);
+    return run_all_benchmarks(static_cast<size_t>(msg_size));
   }
 
   if (socket_type == nullptr) {
@@ -678,12 +681,12 @@
   client_args->read_bytes = strategy->read_strategy;
   client_args->write_bytes = blocking_write_bytes;
   client_args->setup = strategy->setup;
-  client_args->msg_size = (size_t)msg_size;
+  client_args->msg_size = static_cast<size_t>(msg_size);
   client_args->strategy_name = read_strategy;
   server_args->read_bytes = strategy->read_strategy;
   server_args->write_bytes = blocking_write_bytes;
   server_args->setup = strategy->setup;
-  server_args->msg_size = (size_t)msg_size;
+  server_args->msg_size = static_cast<size_t>(msg_size);
   server_args->strategy_name = read_strategy;
 
   error = run_benchmark(socket_type, client_args, server_args);
diff --git a/test/core/security/BUILD b/test/core/security/BUILD
index 7cd3ae5..9db73b9 100644
--- a/test/core/security/BUILD
+++ b/test/core/security/BUILD
@@ -24,7 +24,7 @@
     name = "ssl_server_fuzzer",
     srcs = ["ssl_server_fuzzer.cc"],
     language = "C++",
-    corpus = "corpus",
+    corpus = "corpus/ssl_server_corpus",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -67,6 +67,31 @@
 )
 
 grpc_cc_test(
+    name = "json_token_test",
+    srcs = ["json_token_test.cc"],
+    language = "C++",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+grpc_cc_test(
+    name = "jwt_verifier_test",
+    srcs = ["jwt_verifier_test.cc"],
+    language = "C++",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+
+grpc_cc_test(
     name = "secure_endpoint_test",
     srcs = ["secure_endpoint_test.cc"],
     language = "C++",
@@ -110,6 +135,7 @@
     deps = [
         "//:gpr",
         "//:grpc",
+        "//test/core/util:grpc_test_util",
     ],
 )
 
@@ -121,6 +147,7 @@
         ":oauth2_utils",
         "//:gpr",
         "//:grpc",
+        "//test/core/util:grpc_test_util",
     ],
 )
 
@@ -131,5 +158,55 @@
     deps = [
         "//:gpr",
         "//:grpc",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+grpc_cc_test(
+    name = "check_gcp_environment_linux_test",
+    srcs = ["check_gcp_environment_linux_test.cc"],
+    language = "C++",
+    deps = [
+        "//:alts_util",
+        "//:gpr",
+        "//:gpr_base",
+        "//:grpc",
+    ],
+)
+
+grpc_cc_test(
+    name = "check_gcp_environment_windows_test",
+    srcs = ["check_gcp_environment_windows_test.cc"],
+    language = "C++",
+    deps = [
+        "//:alts_util",
+        "//:gpr",
+        "//:gpr_base",
+        "//:grpc",
+    ],
+)
+
+grpc_cc_test(
+    name = "grpc_alts_credentials_options_test",
+    srcs = ["grpc_alts_credentials_options_test.cc"],
+    language = "C++",
+    deps = [
+        "//:alts_util",
+        "//:gpr",
+        "//:grpc",
+    ],
+)
+
+grpc_cc_test(
+    name = "alts_security_connector_test",
+    srcs = ["alts_security_connector_test.cc"],
+    language = "C++",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//:grpc_base_c", 
+        "//:grpc_secure",
+        "//:tsi", 
+        "//:tsi_interface",
     ],
 )
diff --git a/test/core/security/alts_security_connector_test.cc b/test/core/security/alts_security_connector_test.cc
new file mode 100644
index 0000000..103a493
--- /dev/null
+++ b/test/core/security/alts_security_connector_test.cc
@@ -0,0 +1,166 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/security/security_connector/alts_security_connector.h"
+#include "src/core/lib/transport/transport.h"
+#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h"
+#include "src/core/tsi/transport_security.h"
+
+using grpc_core::internal::grpc_alts_auth_context_from_tsi_peer;
+
+/* This file contains unit tests of grpc_alts_auth_context_from_tsi_peer(). */
+static void test_invalid_input_failure() {
+  tsi_peer peer;
+  grpc_auth_context* ctx;
+  GPR_ASSERT(grpc_alts_auth_context_from_tsi_peer(nullptr, &ctx) ==
+             GRPC_SECURITY_ERROR);
+  GPR_ASSERT(grpc_alts_auth_context_from_tsi_peer(&peer, nullptr) ==
+             GRPC_SECURITY_ERROR);
+}
+
+static void test_empty_certificate_type_failure() {
+  tsi_peer peer;
+  grpc_auth_context* ctx = nullptr;
+  GPR_ASSERT(tsi_construct_peer(0, &peer) == TSI_OK);
+  GPR_ASSERT(grpc_alts_auth_context_from_tsi_peer(&peer, &ctx) ==
+             GRPC_SECURITY_ERROR);
+  GPR_ASSERT(ctx == nullptr);
+  tsi_peer_destruct(&peer);
+}
+
+static void test_empty_peer_property_failure() {
+  tsi_peer peer;
+  grpc_auth_context* ctx;
+  GPR_ASSERT(tsi_construct_peer(1, &peer) == TSI_OK);
+  GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_ALTS_CERTIFICATE_TYPE,
+                 &peer.properties[0]) == TSI_OK);
+  GPR_ASSERT(grpc_alts_auth_context_from_tsi_peer(&peer, &ctx) ==
+             GRPC_SECURITY_ERROR);
+  GPR_ASSERT(ctx == nullptr);
+  tsi_peer_destruct(&peer);
+}
+
+static void test_missing_rpc_protocol_versions_property_failure() {
+  tsi_peer peer;
+  grpc_auth_context* ctx;
+  GPR_ASSERT(tsi_construct_peer(kTsiAltsNumOfPeerProperties, &peer) == TSI_OK);
+  GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_ALTS_CERTIFICATE_TYPE,
+                 &peer.properties[0]) == TSI_OK);
+  GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                 TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY, "alice",
+                 &peer.properties[1]) == TSI_OK);
+  GPR_ASSERT(grpc_alts_auth_context_from_tsi_peer(&peer, &ctx) ==
+             GRPC_SECURITY_ERROR);
+  GPR_ASSERT(ctx == nullptr);
+  tsi_peer_destruct(&peer);
+}
+
+static void test_unknown_peer_property_failure() {
+  tsi_peer peer;
+  grpc_auth_context* ctx;
+  GPR_ASSERT(tsi_construct_peer(kTsiAltsNumOfPeerProperties, &peer) == TSI_OK);
+  GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_ALTS_CERTIFICATE_TYPE,
+                 &peer.properties[0]) == TSI_OK);
+  GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                 "unknown", "alice", &peer.properties[1]) == TSI_OK);
+  GPR_ASSERT(grpc_alts_auth_context_from_tsi_peer(&peer, &ctx) ==
+             GRPC_SECURITY_ERROR);
+  GPR_ASSERT(ctx == nullptr);
+  tsi_peer_destruct(&peer);
+}
+
+static bool test_identity(const grpc_auth_context* ctx,
+                          const char* expected_property_name,
+                          const char* expected_identity) {
+  grpc_auth_property_iterator it;
+  const grpc_auth_property* prop;
+  GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx));
+  it = grpc_auth_context_peer_identity(ctx);
+  prop = grpc_auth_property_iterator_next(&it);
+  GPR_ASSERT(prop != nullptr);
+  if (strcmp(prop->name, expected_property_name) != 0) {
+    gpr_log(GPR_ERROR, "Expected peer identity property name %s and got %s.",
+            expected_property_name, prop->name);
+    return false;
+  }
+  if (strncmp(prop->value, expected_identity, prop->value_length) != 0) {
+    gpr_log(GPR_ERROR, "Expected peer identity %s and got got %s.",
+            expected_identity, prop->value);
+    return false;
+  }
+  return true;
+}
+
+static void test_alts_peer_to_auth_context_success() {
+  tsi_peer peer;
+  grpc_auth_context* ctx;
+  GPR_ASSERT(tsi_construct_peer(kTsiAltsNumOfPeerProperties, &peer) == TSI_OK);
+  GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_ALTS_CERTIFICATE_TYPE,
+                 &peer.properties[0]) == TSI_OK);
+  GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                 TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY, "alice",
+                 &peer.properties[1]) == TSI_OK);
+  grpc_gcp_rpc_protocol_versions peer_versions;
+  grpc_gcp_rpc_protocol_versions_set_max(&peer_versions,
+                                         GRPC_PROTOCOL_VERSION_MAX_MAJOR,
+                                         GRPC_PROTOCOL_VERSION_MAX_MINOR);
+  grpc_gcp_rpc_protocol_versions_set_min(&peer_versions,
+                                         GRPC_PROTOCOL_VERSION_MIN_MAJOR,
+                                         GRPC_PROTOCOL_VERSION_MIN_MINOR);
+  grpc_slice serialized_peer_versions;
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_encode(&peer_versions,
+                                                   &serialized_peer_versions));
+
+  GPR_ASSERT(tsi_construct_string_peer_property(
+                 TSI_ALTS_RPC_VERSIONS,
+                 reinterpret_cast<char*>(
+                     GRPC_SLICE_START_PTR(serialized_peer_versions)),
+                 GRPC_SLICE_LENGTH(serialized_peer_versions),
+                 &peer.properties[2]) == TSI_OK);
+  GPR_ASSERT(grpc_alts_auth_context_from_tsi_peer(&peer, &ctx) ==
+             GRPC_SECURITY_OK);
+  GPR_ASSERT(
+      test_identity(ctx, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY, "alice"));
+  GRPC_AUTH_CONTEXT_UNREF(ctx, "test");
+  grpc_slice_unref(serialized_peer_versions);
+  tsi_peer_destruct(&peer);
+}
+
+int main(int argc, char** argv) {
+  /* Test. */
+  test_invalid_input_failure();
+  test_empty_certificate_type_failure();
+  test_empty_peer_property_failure();
+  test_unknown_peer_property_failure();
+  test_missing_rpc_protocol_versions_property_failure();
+  test_alts_peer_to_auth_context_success();
+
+  return 0;
+}
diff --git a/test/core/security/check_gcp_environment_linux_test.cc b/test/core/security/check_gcp_environment_linux_test.cc
new file mode 100644
index 0000000..6c436a3
--- /dev/null
+++ b/test/core/security/check_gcp_environment_linux_test.cc
@@ -0,0 +1,83 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/core/lib/security/credentials/alts/check_gcp_environment.h"
+
+#if GPR_LINUX
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/gpr/tmpfile.h"
+
+static bool check_bios_data_linux_test(const char* data) {
+  /* Create a file with contents data. */
+  char* filename = nullptr;
+  FILE* fp = gpr_tmpfile("check_gcp_environment_test", &filename);
+  GPR_ASSERT(filename != nullptr);
+  GPR_ASSERT(fp != nullptr);
+  GPR_ASSERT(fwrite(data, 1, strlen(data), fp) == strlen(data));
+  fclose(fp);
+  bool result = grpc_core::internal::check_bios_data(
+      reinterpret_cast<const char*>(filename));
+  /* Cleanup. */
+  remove(filename);
+  gpr_free(filename);
+  return result;
+}
+
+static void test_gcp_environment_check_success() {
+  /* Exact match. */
+  GPR_ASSERT(check_bios_data_linux_test("Google"));
+  GPR_ASSERT(check_bios_data_linux_test("Google Compute Engine"));
+  /* With leading and trailing whitespaces. */
+  GPR_ASSERT(check_bios_data_linux_test(" Google  "));
+  GPR_ASSERT(check_bios_data_linux_test("Google  "));
+  GPR_ASSERT(check_bios_data_linux_test("   Google"));
+  GPR_ASSERT(check_bios_data_linux_test("  Google Compute Engine  "));
+  GPR_ASSERT(check_bios_data_linux_test("Google Compute Engine  "));
+  GPR_ASSERT(check_bios_data_linux_test("  Google Compute Engine"));
+  /* With leading and trailing \t and \n. */
+  GPR_ASSERT(check_bios_data_linux_test("\t\tGoogle Compute Engine\t"));
+  GPR_ASSERT(check_bios_data_linux_test("Google Compute Engine\n"));
+  GPR_ASSERT(check_bios_data_linux_test("\n\n\tGoogle Compute Engine \n\t\t"));
+}
+
+static void test_gcp_environment_check_failure() {
+  GPR_ASSERT(!check_bios_data_linux_test("non_existing-file"));
+  GPR_ASSERT(!check_bios_data_linux_test("Google-Chrome"));
+  GPR_ASSERT(!check_bios_data_linux_test("Amazon"));
+  GPR_ASSERT(!check_bios_data_linux_test("Google-Chrome\t\t"));
+  GPR_ASSERT(!check_bios_data_linux_test("Amazon"));
+}
+
+int main(int argc, char** argv) {
+  /* Tests. */
+  test_gcp_environment_check_success();
+  test_gcp_environment_check_failure();
+  return 0;
+}
+
+#else  // GPR_LINUX
+
+int main(int argc, char** argv) { return 0; }
+
+#endif  // GPR_LINUX
diff --git a/test/core/security/check_gcp_environment_windows_test.cc b/test/core/security/check_gcp_environment_windows_test.cc
new file mode 100644
index 0000000..46179b7
--- /dev/null
+++ b/test/core/security/check_gcp_environment_windows_test.cc
@@ -0,0 +1,71 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/core/lib/security/credentials/alts/check_gcp_environment.h"
+
+#ifdef GPR_WINDOWS
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include "src/core/lib/gpr/tmpfile.h"
+
+static bool check_bios_data_windows_test(const char* data) {
+  /* Create a file with contents data. */
+  char* filename = nullptr;
+  FILE* fp = gpr_tmpfile("check_gcp_environment_test", &filename);
+  GPR_ASSERT(filename != nullptr);
+  GPR_ASSERT(fp != nullptr);
+  GPR_ASSERT(fwrite(data, 1, strlen(data), fp) == strlen(data));
+  fclose(fp);
+  bool result = grpc_core::internal::check_bios_data(
+      reinterpret_cast<const char*>(filename));
+  /* Cleanup. */
+  remove(filename);
+  gpr_free(filename);
+  return result;
+}
+
+static void test_gcp_environment_check_success() {
+  GPR_ASSERT(check_bios_data_windows_test("Google"));
+  GPR_ASSERT(check_bios_data_windows_test("Google\n"));
+  GPR_ASSERT(check_bios_data_windows_test("Google\r"));
+  GPR_ASSERT(check_bios_data_windows_test("Google\r\n"));
+  GPR_ASSERT(check_bios_data_windows_test("   Google   \r\n"));
+  GPR_ASSERT(check_bios_data_windows_test(" \t\t Google\r\n"));
+  GPR_ASSERT(check_bios_data_windows_test(" \t\t Google\t\t  \r\n"));
+}
+
+static void test_gcp_environment_check_failure() {
+  GPR_ASSERT(!check_bios_data_windows_test("\t\tAmazon\n"));
+  GPR_ASSERT(!check_bios_data_windows_test("  Amazon\r\n"));
+}
+
+int main(int argc, char** argv) {
+  /* Tests. */
+  test_gcp_environment_check_success();
+  test_gcp_environment_check_failure();
+  return 0;
+}
+#else  // GPR_WINDOWS
+
+int main(int argc, char** argv) { return 0; }
+
+#endif  // GPR_WINDOWS
diff --git a/test/core/security/create_jwt.cc b/test/core/security/create_jwt.cc
index 56ae9c8..2ea640b 100644
--- a/test/core/security/create_jwt.cc
+++ b/test/core/security/create_jwt.cc
@@ -24,9 +24,10 @@
 
 #include <grpc/slice.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/cmdline.h>
 #include <grpc/support/log.h>
 
+#include "test/core/util/cmdline.h"
+
 void create_jwt(const char* json_key_file_path, const char* service_url,
                 const char* scope) {
   grpc_auth_json_key key;
@@ -35,7 +36,7 @@
   GPR_ASSERT(GRPC_LOG_IF_ERROR(
       "load_file", grpc_load_file(json_key_file_path, 1, &json_key_data)));
   key = grpc_auth_json_key_create_from_string(
-      (const char*)GRPC_SLICE_START_PTR(json_key_data));
+      reinterpret_cast<const char*> GRPC_SLICE_START_PTR(json_key_data));
   grpc_slice_unref(json_key_data);
   if (!grpc_auth_json_key_is_valid(&key)) {
     fprintf(stderr, "Could not parse json key.\n");
diff --git a/test/core/security/credentials_test.cc b/test/core/security/credentials_test.cc
index 9031046..ce92e21 100644
--- a/test/core/security/credentials_test.cc
+++ b/test/core/security/credentials_test.cc
@@ -140,7 +140,7 @@
   grpc_httpcli_response response;
   memset(&response, 0, sizeof(grpc_httpcli_response));
   response.status = status;
-  response.body = gpr_strdup((char*)body);
+  response.body = gpr_strdup(const_cast<char*>(body));
   response.body_length = strlen(body);
   return response;
 }
@@ -324,7 +324,7 @@
 }
 
 static void check_request_metadata(void* arg, grpc_error* error) {
-  request_metadata_state* state = (request_metadata_state*)arg;
+  request_metadata_state* state = static_cast<request_metadata_state*>(arg);
   gpr_log(GPR_INFO, "expected_error: %s",
           grpc_error_string(state->expected_error));
   gpr_log(GPR_INFO, "actual_error: %s", grpc_error_string(error));
@@ -754,7 +754,7 @@
     grpc_call_credentials* creds) {
   GPR_ASSERT(creds != nullptr);
   GPR_ASSERT(strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_JWT) == 0);
-  return (grpc_service_account_jwt_access_credentials*)creds;
+  return reinterpret_cast<grpc_service_account_jwt_access_credentials*>(creds);
 }
 
 static void test_jwt_creds_lifetime(void) {
@@ -873,10 +873,11 @@
   set_google_default_creds_env_var_with_file_contents(
       "json_key_google_default_creds", json_key);
   gpr_free(json_key);
-  creds = (grpc_composite_channel_credentials*)
-      grpc_google_default_credentials_create();
+  creds = reinterpret_cast<grpc_composite_channel_credentials*>(
+      grpc_google_default_credentials_create());
   GPR_ASSERT(creds != nullptr);
-  jwt = (grpc_service_account_jwt_access_credentials*)creds->call_creds;
+  jwt = reinterpret_cast<grpc_service_account_jwt_access_credentials*>(
+      creds->call_creds);
   GPR_ASSERT(
       strcmp(jwt->key.client_id,
              "777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent.com") ==
@@ -892,10 +893,11 @@
   grpc_flush_cached_google_default_credentials();
   set_google_default_creds_env_var_with_file_contents(
       "refresh_token_google_default_creds", test_refresh_token_str);
-  creds = (grpc_composite_channel_credentials*)
-      grpc_google_default_credentials_create();
+  creds = reinterpret_cast<grpc_composite_channel_credentials*>(
+      grpc_google_default_credentials_create());
   GPR_ASSERT(creds != nullptr);
-  refresh = (grpc_google_refresh_token_credentials*)creds->call_creds;
+  refresh = reinterpret_cast<grpc_google_refresh_token_credentials*>(
+      creds->call_creds);
   GPR_ASSERT(strcmp(refresh->refresh_token.client_id,
                     "32555999999.apps.googleusercontent.com") == 0);
   grpc_channel_credentials_unref(&creds->base);
@@ -938,8 +940,8 @@
       default_creds_gce_detection_httpcli_get_success_override,
       httpcli_post_should_not_be_called);
   grpc_composite_channel_credentials* creds =
-      (grpc_composite_channel_credentials*)
-          grpc_google_default_credentials_create();
+      reinterpret_cast<grpc_composite_channel_credentials*>(
+          grpc_google_default_credentials_create());
 
   /* Verify that the default creds actually embeds a GCE creds. */
   GPR_ASSERT(creds != nullptr);
@@ -1018,7 +1020,7 @@
   GPR_ASSERT(context.reserved == nullptr);
   GPR_ASSERT(GPR_ARRAY_SIZE(plugin_md) <
              GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX);
-  plugin_state* s = (plugin_state*)state;
+  plugin_state* s = static_cast<plugin_state*>(state);
   *s = PLUGIN_GET_METADATA_CALLED_STATE;
   for (size_t i = 0; i < GPR_ARRAY_SIZE(plugin_md); ++i) {
     memset(&creds_md[i], 0, sizeof(grpc_metadata));
@@ -1041,7 +1043,7 @@
   GPR_ASSERT(strcmp(context.method_name, test_method) == 0);
   GPR_ASSERT(context.channel_auth_context == nullptr);
   GPR_ASSERT(context.reserved == nullptr);
-  plugin_state* s = (plugin_state*)state;
+  plugin_state* s = static_cast<plugin_state*>(state);
   *s = PLUGIN_GET_METADATA_CALLED_STATE;
   *status = GRPC_STATUS_UNAUTHENTICATED;
   *error_details = gpr_strdup(plugin_error_details);
@@ -1049,7 +1051,7 @@
 }
 
 static void plugin_destroy(void* state) {
-  plugin_state* s = (plugin_state*)state;
+  plugin_state* s = static_cast<plugin_state*>(state);
   *s = PLUGIN_DESTROY_CALLED_STATE;
 }
 
diff --git a/test/core/security/fetch_oauth2.cc b/test/core/security/fetch_oauth2.cc
index cb28a04..82efe68 100644
--- a/test/core/security/fetch_oauth2.cc
+++ b/test/core/security/fetch_oauth2.cc
@@ -23,13 +23,13 @@
 #include <grpc/grpc_security.h>
 #include <grpc/slice.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/cmdline.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 
 #include "src/core/lib/iomgr/load_file.h"
 #include "src/core/lib/security/credentials/credentials.h"
 #include "test/core/security/oauth2_utils.h"
+#include "test/core/util/cmdline.h"
 
 static grpc_call_credentials* create_refresh_token_creds(
     const char* json_refresh_token_file_path) {
@@ -38,7 +38,8 @@
       "load_file",
       grpc_load_file(json_refresh_token_file_path, 1, &refresh_token)));
   return grpc_google_refresh_token_credentials_create(
-      (const char*)GRPC_SLICE_START_PTR(refresh_token), nullptr);
+      reinterpret_cast<const char*> GRPC_SLICE_START_PTR(refresh_token),
+      nullptr);
 }
 
 int main(int argc, char** argv) {
diff --git a/test/core/security/grpc_alts_credentials_options_test.cc b/test/core/security/grpc_alts_credentials_options_test.cc
new file mode 100644
index 0000000..1217065
--- /dev/null
+++ b/test/core/security/grpc_alts_credentials_options_test.cc
@@ -0,0 +1,118 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h"
+
+#define ALTS_CLIENT_OPTIONS_TEST_TARGET_SERVICE_ACCOUNT_1 "abc@google.com"
+#define ALTS_CLIENT_OPTIONS_TEST_TARGET_SERVICE_ACCOUNT_2 "def@google.com"
+
+const size_t kTargetServiceAccountNum = 2;
+
+static void test_add_target_service_account_failure() {
+  /* Initialization. */
+  grpc_alts_credentials_options* options =
+      grpc_alts_credentials_client_options_create();
+  auto client_options =
+      reinterpret_cast<grpc_alts_credentials_client_options*>(options);
+
+  /* Test. */
+  GPR_ASSERT(!grpc_alts_credentials_client_options_add_target_service_account(
+      client_options, nullptr));
+  GPR_ASSERT(!grpc_alts_credentials_client_options_add_target_service_account(
+      nullptr, ALTS_CLIENT_OPTIONS_TEST_TARGET_SERVICE_ACCOUNT_1));
+
+  /* Cleanup. */
+  grpc_alts_credentials_options_destroy(options);
+}
+
+static void test_copy_client_options_failure() {
+  /* Initialization. */
+  grpc_alts_credentials_options* options =
+      grpc_alts_credentials_client_options_create();
+
+  /* Test. */
+  GPR_ASSERT(grpc_alts_credentials_options_copy(nullptr) == nullptr);
+
+  /* Cleanup. */
+  grpc_alts_credentials_options_destroy(options);
+}
+
+static size_t get_target_service_account_num(
+    grpc_alts_credentials_client_options* options) {
+  size_t num = 0;
+  target_service_account* node = options->target_account_list_head;
+  while (node != nullptr) {
+    num++;
+    node = node->next;
+  }
+  return num;
+}
+
+static void test_client_options_api_success() {
+  /* Initialization. */
+  grpc_alts_credentials_options* options =
+      grpc_alts_credentials_client_options_create();
+  auto client_options =
+      reinterpret_cast<grpc_alts_credentials_client_options*>(options);
+
+  /* Set client options fields. */
+  grpc_alts_credentials_client_options_add_target_service_account(
+      client_options, ALTS_CLIENT_OPTIONS_TEST_TARGET_SERVICE_ACCOUNT_1);
+  grpc_alts_credentials_client_options_add_target_service_account(
+      client_options, ALTS_CLIENT_OPTIONS_TEST_TARGET_SERVICE_ACCOUNT_2);
+
+  /* Validate client option fields. */
+  GPR_ASSERT(get_target_service_account_num(client_options) ==
+             kTargetServiceAccountNum);
+  GPR_ASSERT(strcmp(client_options->target_account_list_head->data,
+                    ALTS_CLIENT_OPTIONS_TEST_TARGET_SERVICE_ACCOUNT_2) == 0);
+  GPR_ASSERT(strcmp(client_options->target_account_list_head->next->data,
+                    ALTS_CLIENT_OPTIONS_TEST_TARGET_SERVICE_ACCOUNT_1) == 0);
+
+  /* Perform a copy operation and validate its correctness. */
+  grpc_alts_credentials_options* new_options =
+      grpc_alts_credentials_options_copy(options);
+  auto new_client_options =
+      reinterpret_cast<grpc_alts_credentials_client_options*>(new_options);
+
+  GPR_ASSERT(get_target_service_account_num(new_client_options) ==
+             kTargetServiceAccountNum);
+  GPR_ASSERT(strcmp(new_client_options->target_account_list_head->data,
+                    ALTS_CLIENT_OPTIONS_TEST_TARGET_SERVICE_ACCOUNT_2) == 0);
+  GPR_ASSERT(strcmp(new_client_options->target_account_list_head->next->data,
+                    ALTS_CLIENT_OPTIONS_TEST_TARGET_SERVICE_ACCOUNT_1) == 0);
+
+  /* Cleanup.*/
+  grpc_alts_credentials_options_destroy(options);
+  grpc_alts_credentials_options_destroy(new_options);
+}
+
+int main(int argc, char** argv) {
+  /* Test. */
+  test_add_target_service_account_failure();
+  test_copy_client_options_failure();
+  test_client_options_api_success();
+  return 0;
+}
diff --git a/test/core/security/json_token_test.cc b/test/core/security/json_token_test.cc
index aac9cc0..7a5b335 100644
--- a/test/core/security/json_token_test.cc
+++ b/test/core/security/json_token_test.cc
@@ -218,7 +218,7 @@
   slice = grpc_base64_decode(b64, 1);
   GPR_ASSERT(!GRPC_SLICE_IS_EMPTY(slice));
   decoded = static_cast<char*>(gpr_malloc(GRPC_SLICE_LENGTH(slice) + 1));
-  strncpy(decoded, (const char*)GRPC_SLICE_START_PTR(slice),
+  strncpy(decoded, reinterpret_cast<const char*> GRPC_SLICE_START_PTR(slice),
           GRPC_SLICE_LENGTH(slice));
   decoded[GRPC_SLICE_LENGTH(slice)] = '\0';
   json = grpc_json_parse_string(decoded);
@@ -385,21 +385,21 @@
   char* jwt = jwt_encode_and_sign_func(&json_key);
   const char* dot = strchr(jwt, '.');
   GPR_ASSERT(dot != nullptr);
-  parsed_header =
-      parse_json_part_from_jwt(jwt, (size_t)(dot - jwt), &scratchpad);
+  parsed_header = parse_json_part_from_jwt(jwt, static_cast<size_t>(dot - jwt),
+                                           &scratchpad);
   GPR_ASSERT(parsed_header != nullptr);
   check_jwt_header(parsed_header);
-  offset = (size_t)(dot - jwt) + 1;
+  offset = static_cast<size_t>(dot - jwt) + 1;
   grpc_json_destroy(parsed_header);
   gpr_free(scratchpad);
 
   dot = strchr(jwt + offset, '.');
   GPR_ASSERT(dot != nullptr);
   parsed_claim = parse_json_part_from_jwt(
-      jwt + offset, (size_t)(dot - (jwt + offset)), &scratchpad);
+      jwt + offset, static_cast<size_t>(dot - (jwt + offset)), &scratchpad);
   GPR_ASSERT(parsed_claim != nullptr);
   check_jwt_claim_func(parsed_claim);
-  offset = (size_t)(dot - jwt) + 1;
+  offset = static_cast<size_t>(dot - jwt) + 1;
   grpc_json_destroy(parsed_claim);
   gpr_free(scratchpad);
 
diff --git a/test/core/security/jwt_verifier_test.cc b/test/core/security/jwt_verifier_test.cc
index e219260..9718580 100644
--- a/test/core/security/jwt_verifier_test.cc
+++ b/test/core/security/jwt_verifier_test.cc
@@ -207,7 +207,7 @@
   grpc_jwt_claims* claims;
   grpc_slice s = grpc_slice_from_copied_string(claims_without_time_constraint);
   grpc_json* json = grpc_json_parse_string_with_len(
-      (char*)GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s));
+      reinterpret_cast<char*> GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s));
   GPR_ASSERT(json != nullptr);
   grpc_core::ExecCtx exec_ctx;
   claims = grpc_jwt_claims_from_json(json, s);
@@ -226,7 +226,7 @@
   grpc_jwt_claims* claims;
   grpc_slice s = grpc_slice_from_copied_string(expired_claims);
   grpc_json* json = grpc_json_parse_string_with_len(
-      (char*)GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s));
+      reinterpret_cast<char*> GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s));
   gpr_timespec exp_iat = {100, 0, GPR_CLOCK_REALTIME};
   gpr_timespec exp_exp = {120, 0, GPR_CLOCK_REALTIME};
   gpr_timespec exp_nbf = {60, 0, GPR_CLOCK_REALTIME};
@@ -251,7 +251,7 @@
 static void test_invalid_claims_failure(void) {
   grpc_slice s = grpc_slice_from_copied_string(invalid_claims);
   grpc_json* json = grpc_json_parse_string_with_len(
-      (char*)GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s));
+      reinterpret_cast<char*> GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s));
   grpc_core::ExecCtx exec_ctx;
   GPR_ASSERT(grpc_jwt_claims_from_json(json, s) == nullptr);
 }
@@ -260,7 +260,7 @@
   grpc_jwt_claims* claims;
   grpc_slice s = grpc_slice_from_copied_string(claims_without_time_constraint);
   grpc_json* json = grpc_json_parse_string_with_len(
-      (char*)GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s));
+      reinterpret_cast<char*> GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s));
   GPR_ASSERT(json != nullptr);
   grpc_core::ExecCtx exec_ctx;
   claims = grpc_jwt_claims_from_json(json, s);
@@ -274,7 +274,7 @@
   grpc_jwt_claims* claims;
   grpc_slice s = grpc_slice_from_copied_string(claims_with_bad_subject);
   grpc_json* json = grpc_json_parse_string_with_len(
-      (char*)GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s));
+      reinterpret_cast<char*> GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s));
   GPR_ASSERT(json != nullptr);
   grpc_core::ExecCtx exec_ctx;
   claims = grpc_jwt_claims_from_json(json, s);
diff --git a/test/core/security/oauth2_utils.cc b/test/core/security/oauth2_utils.cc
index 0d3a127..469129a 100644
--- a/test/core/security/oauth2_utils.cc
+++ b/test/core/security/oauth2_utils.cc
@@ -40,7 +40,7 @@
 } oauth2_request;
 
 static void on_oauth2_response(void* arg, grpc_error* error) {
-  oauth2_request* request = (oauth2_request*)arg;
+  oauth2_request* request = static_cast<oauth2_request*>(arg);
   char* token = nullptr;
   grpc_slice token_slice;
   if (error != GRPC_ERROR_NONE) {
@@ -48,7 +48,7 @@
   } else {
     GPR_ASSERT(request->md_array.size == 1);
     token_slice = GRPC_MDVALUE(request->md_array.md[0]);
-    token = (char*)gpr_malloc(GRPC_SLICE_LENGTH(token_slice) + 1);
+    token = static_cast<char*>(gpr_malloc(GRPC_SLICE_LENGTH(token_slice) + 1));
     memcpy(token, GRPC_SLICE_START_PTR(token_slice),
            GRPC_SLICE_LENGTH(token_slice));
     token[GRPC_SLICE_LENGTH(token_slice)] = '\0';
@@ -73,7 +73,8 @@
   grpc_closure do_nothing_closure;
   grpc_auth_metadata_context null_ctx = {"", "", nullptr, nullptr};
 
-  grpc_pollset* pollset = (grpc_pollset*)gpr_zalloc(grpc_pollset_size());
+  grpc_pollset* pollset =
+      static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
   grpc_pollset_init(pollset, &request.mu);
   request.pops = grpc_polling_entity_create_from_pollset(pollset);
   request.is_done = false;
diff --git a/test/core/security/print_google_default_creds_token.cc b/test/core/security/print_google_default_creds_token.cc
index a90f997..4d25139 100644
--- a/test/core/security/print_google_default_creds_token.cc
+++ b/test/core/security/print_google_default_creds_token.cc
@@ -23,7 +23,6 @@
 #include <grpc/grpc_security.h>
 #include <grpc/slice.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/cmdline.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 
@@ -31,6 +30,7 @@
 #include "src/core/lib/security/credentials/composite/composite_credentials.h"
 #include "src/core/lib/security/credentials/credentials.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
+#include "test/core/util/cmdline.h"
 
 typedef struct {
   gpr_mu* mu;
@@ -88,7 +88,7 @@
   }
 
   memset(&sync, 0, sizeof(sync));
-  pollset = (grpc_pollset*)gpr_zalloc(grpc_pollset_size());
+  pollset = static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
   grpc_pollset_init(pollset, &sync.mu);
   sync.pops = grpc_polling_entity_create_from_pollset(pollset);
   sync.is_done = false;
@@ -97,8 +97,10 @@
 
   error = GRPC_ERROR_NONE;
   if (grpc_call_credentials_get_request_metadata(
-          ((grpc_composite_channel_credentials*)creds)->call_creds, &sync.pops,
-          context, &sync.md_array, &sync.on_request_metadata, &error)) {
+          (reinterpret_cast<grpc_composite_channel_credentials*>(creds))
+              ->call_creds,
+          &sync.pops, context, &sync.md_array, &sync.on_request_metadata,
+          &error)) {
     // Synchronous response.  Invoke callback directly.
     on_metadata_response(&sync, error);
     GRPC_ERROR_UNREF(error);
diff --git a/test/core/security/secure_endpoint_test.cc b/test/core/security/secure_endpoint_test.cc
index 38c78fe..23cef99 100644
--- a/test/core/security/secure_endpoint_test.cc
+++ b/test/core/security/secure_endpoint_test.cc
@@ -24,7 +24,7 @@
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/endpoint_pair.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/security/transport/secure_endpoint.h"
@@ -57,7 +57,7 @@
   grpc_arg a[1];
   a[0].key = const_cast<char*>(GRPC_ARG_TCP_READ_CHUNK_SIZE);
   a[0].type = GRPC_ARG_INTEGER;
-  a[0].value.integer = (int)slice_size;
+  a[0].value.integer = static_cast<int>(slice_size);
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
   tcp = grpc_iomgr_create_endpoint_pair("fixture", &args);
   grpc_endpoint_add_to_pollset(tcp.client, g_pollset);
@@ -73,7 +73,7 @@
     size_t still_pending_size;
     size_t total_buffer_size = 8192;
     size_t buffer_size = total_buffer_size;
-    uint8_t* encrypted_buffer = (uint8_t*)gpr_malloc(buffer_size);
+    uint8_t* encrypted_buffer = static_cast<uint8_t*>(gpr_malloc(buffer_size));
     uint8_t* cur = encrypted_buffer;
     grpc_slice encrypted_leftover;
     for (i = 0; i < leftover_nslices; i++) {
@@ -106,7 +106,8 @@
       buffer_size -= protected_buffer_size_to_send;
     } while (still_pending_size > 0);
     encrypted_leftover = grpc_slice_from_copied_buffer(
-        (const char*)encrypted_buffer, total_buffer_size - buffer_size);
+        reinterpret_cast<const char*>(encrypted_buffer),
+        total_buffer_size - buffer_size);
     f.client_ep = grpc_secure_endpoint_create(
         fake_read_protector, fake_read_zero_copy_protector, tcp.client,
         &encrypted_leftover, 1);
@@ -165,7 +166,9 @@
      clean_up},
 };
 
-static void inc_call_ctr(void* arg, grpc_error* error) { ++*(int*)arg; }
+static void inc_call_ctr(void* arg, grpc_error* error) {
+  ++*static_cast<int*>(arg);
+}
 
 static void test_leftover(grpc_endpoint_test_config config, size_t slice_size) {
   grpc_endpoint_test_fixture f = config.create_fixture(slice_size);
@@ -200,7 +203,7 @@
 }
 
 static void destroy_pollset(void* p, grpc_error* error) {
-  grpc_pollset_destroy((grpc_pollset*)p);
+  grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
 }
 
 int main(int argc, char** argv) {
@@ -210,7 +213,7 @@
 
   {
     grpc_core::ExecCtx exec_ctx;
-    g_pollset = (grpc_pollset*)gpr_zalloc(grpc_pollset_size());
+    g_pollset = static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
     grpc_pollset_init(g_pollset, &g_mu);
     grpc_endpoint_tests(configs[0], g_pollset, g_mu);
     grpc_endpoint_tests(configs[1], g_pollset, g_mu);
diff --git a/test/core/security/security_connector_test.cc b/test/core/security/security_connector_test.cc
index 6eaef2b..f03f4cc 100644
--- a/test/core/security/security_connector_test.cc
+++ b/test/core/security/security_connector_test.cc
@@ -23,13 +23,12 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gpr/tmpfile.h"
 #include "src/core/lib/security/context/security_context.h"
-#include "src/core/lib/security/transport/security_connector.h"
+#include "src/core/lib/security/security_connector/security_connector.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/tsi/ssl_transport_security.h"
 #include "src/core/tsi/transport_security.h"
@@ -341,6 +340,21 @@
   return GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY;
 }
 
+namespace grpc_core {
+namespace {
+
+class TestDefafaultSllRootStore : public DefaultSslRootStore {
+ public:
+  static grpc_slice ComputePemRootCertsForTesting() {
+    return ComputePemRootCerts();
+  }
+};
+
+}  // namespace
+}  // namespace grpc_core
+
+// TODO: Convert this test to C++ test when security_connector implementation
+// is converted to C++.
 static void test_default_ssl_roots(void) {
   const char* roots_for_env_var = "roots for env var";
 
@@ -354,7 +368,8 @@
      value. */
   gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, "");
   grpc_set_ssl_roots_override_callback(override_roots_success);
-  grpc_slice roots = grpc_get_default_ssl_roots_for_testing();
+  grpc_slice roots =
+      grpc_core::TestDefafaultSllRootStore::ComputePemRootCertsForTesting();
   char* roots_contents = grpc_slice_to_c_string(roots);
   grpc_slice_unref(roots);
   GPR_ASSERT(strcmp(roots_contents, roots_for_override_api) == 0);
@@ -363,7 +378,7 @@
   /* Now let's set the env var: We should get the contents pointed value
      instead. */
   gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_env_var_file_path);
-  roots = grpc_get_default_ssl_roots_for_testing();
+  roots = grpc_core::TestDefafaultSllRootStore::ComputePemRootCertsForTesting();
   roots_contents = grpc_slice_to_c_string(roots);
   grpc_slice_unref(roots);
   GPR_ASSERT(strcmp(roots_contents, roots_for_env_var) == 0);
@@ -372,7 +387,7 @@
   /* Now reset the env var. We should fall back to the value overridden using
      the api. */
   gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, "");
-  roots = grpc_get_default_ssl_roots_for_testing();
+  roots = grpc_core::TestDefafaultSllRootStore::ComputePemRootCertsForTesting();
   roots_contents = grpc_slice_to_c_string(roots);
   grpc_slice_unref(roots);
   GPR_ASSERT(strcmp(roots_contents, roots_for_override_api) == 0);
@@ -381,8 +396,11 @@
   /* Now setup a permanent failure for the overridden roots and we should get
      an empty slice. */
   grpc_set_ssl_roots_override_callback(override_roots_permanent_failure);
-  roots = grpc_get_default_ssl_roots_for_testing();
+  roots = grpc_core::TestDefafaultSllRootStore::ComputePemRootCertsForTesting();
   GPR_ASSERT(GRPC_SLICE_IS_EMPTY(roots));
+  const tsi_ssl_root_certs_store* root_store =
+      grpc_core::TestDefafaultSllRootStore::GetRootStore();
+  GPR_ASSERT(root_store == nullptr);
 
   /* Cleanup. */
   remove(roots_env_var_file_path);
diff --git a/test/core/security/ssl_server_fuzzer.cc b/test/core/security/ssl_server_fuzzer.cc
index 6e30698..cb74e3b 100644
--- a/test/core/security/ssl_server_fuzzer.cc
+++ b/test/core/security/ssl_server_fuzzer.cc
@@ -22,7 +22,7 @@
 
 #include "src/core/lib/iomgr/load_file.h"
 #include "src/core/lib/security/credentials/credentials.h"
-#include "src/core/lib/security/transport/security_connector.h"
+#include "src/core/lib/security/security_connector/security_connector.h"
 #include "test/core/end2end/data/ssl_test_data.h"
 #include "test/core/util/memory_counters.h"
 #include "test/core/util/mock_endpoint.h"
diff --git a/test/core/security/verify_jwt.cc b/test/core/security/verify_jwt.cc
index 5d32ce0..61dde0e 100644
--- a/test/core/security/verify_jwt.cc
+++ b/test/core/security/verify_jwt.cc
@@ -23,11 +23,11 @@
 #include <grpc/grpc_security.h>
 #include <grpc/slice.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/cmdline.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 
 #include "src/core/lib/security/credentials/jwt/jwt_verifier.h"
+#include "test/core/util/cmdline.h"
 
 typedef struct {
   grpc_pollset* pollset;
@@ -54,8 +54,8 @@
   if (sync->success) {
     char* claims_str;
     GPR_ASSERT(claims != nullptr);
-    claims_str =
-        grpc_json_dump_to_string((grpc_json*)grpc_jwt_claims_json(claims), 2);
+    claims_str = grpc_json_dump_to_string(
+        const_cast<grpc_json*>(grpc_jwt_claims_json(claims)), 2);
     printf("Claims: \n\n%s\n", claims_str);
     gpr_free(claims_str);
     grpc_jwt_claims_destroy(claims);
diff --git a/test/core/slice/BUILD b/test/core/slice/BUILD
index ba2b553..9a1a506 100644
--- a/test/core/slice/BUILD
+++ b/test/core/slice/BUILD
@@ -23,8 +23,8 @@
 grpc_fuzzer(
     name = "percent_encode_fuzzer",
     srcs = ["percent_encode_fuzzer.cc"],
-    language = "C++",
     corpus = "percent_encode_corpus",
+    language = "C++",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -35,8 +35,8 @@
 grpc_fuzzer(
     name = "percent_decode_fuzzer",
     srcs = ["percent_decode_fuzzer.cc"],
-    language = "C++",
     corpus = "percent_decode_corpus",
+    language = "C++",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -59,8 +59,13 @@
 grpc_cc_test(
     name = "slice_test",
     srcs = ["slice_test.cc"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
     language = "C++",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
 grpc_cc_test(
@@ -78,15 +83,43 @@
 grpc_cc_test(
     name = "slice_buffer_test",
     srcs = ["slice_buffer_test.cc"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
     language = "C++",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
 grpc_cc_test(
     name = "slice_hash_table_test",
     srcs = ["slice_hash_table_test.cc"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+    external_deps = [
+        "gtest",
+    ],
     language = "C++",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+grpc_cc_test(
+    name = "slice_weak_hash_table_test",
+    srcs = ["slice_weak_hash_table_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
+    language = "C++",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
 grpc_cc_test(
diff --git a/test/core/slice/b64_test.cc b/test/core/slice/b64_test.cc
index 94785fd..6b29443 100644
--- a/test/core/slice/b64_test.cc
+++ b/test/core/slice/b64_test.cc
@@ -34,7 +34,7 @@
   for (i = 0; i < size; i++) {
     if (buf1[i] != buf2[i]) {
       gpr_log(GPR_ERROR, "buf1 and buf2 differ: buf1[%d] = %x vs buf2[%d] = %x",
-              (int)i, buf1[i], (int)i, buf2[i]);
+              static_cast<int>(i), buf1[i], static_cast<int>(i), buf2[i]);
       return 0;
     }
   }
@@ -61,7 +61,7 @@
   size_t i;
   char* b64;
   grpc_slice orig_decoded;
-  for (i = 0; i < sizeof(orig); i++) orig[i] = (uint8_t)i;
+  for (i = 0; i < sizeof(orig); i++) orig[i] = static_cast<uint8_t>(i);
 
   /* Try all the different paddings. */
   for (i = 0; i < 3; i++) {
@@ -114,7 +114,7 @@
   char* b64;
   grpc_slice orig_decoded;
   int url_safe = 1;
-  for (i = 0; i < sizeof(orig); i++) orig[i] = (uint8_t)i;
+  for (i = 0; i < sizeof(orig); i++) orig[i] = static_cast<uint8_t>(i);
 
   grpc_core::ExecCtx exec_ctx;
   b64 = grpc_base64_encode(orig, sizeof(orig), url_safe, 0);
diff --git a/test/core/slice/percent_encode_fuzzer.cc b/test/core/slice/percent_encode_fuzzer.cc
index 201ae27..1fd197e 100644
--- a/test/core/slice/percent_encode_fuzzer.cc
+++ b/test/core/slice/percent_encode_fuzzer.cc
@@ -34,7 +34,8 @@
   struct grpc_memory_counters counters;
   grpc_init();
   grpc_memory_counters_init();
-  grpc_slice input = grpc_slice_from_copied_buffer((const char*)data, size);
+  grpc_slice input =
+      grpc_slice_from_copied_buffer(reinterpret_cast<const char*>(data), size);
   grpc_slice output = grpc_percent_encode_slice(input, dict);
   grpc_slice decoded_output;
   // encoder must always produce decodable output
diff --git a/test/core/slice/slice_hash_table_test.cc b/test/core/slice/slice_hash_table_test.cc
index 9fad9a6..43ddfe9 100644
--- a/test/core/slice/slice_hash_table_test.cc
+++ b/test/core/slice/slice_hash_table_test.cc
@@ -20,63 +20,67 @@
 
 #include <string.h>
 
+#include <vector>
+
+#include <gtest/gtest.h>
+
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "test/core/util/test_config.h"
 
-typedef struct {
+namespace grpc_core {
+namespace {
+
+typedef SliceHashTable<UniquePtr<char>> TestHashTable;
+
+struct TestEntry {
   const char* key;
   const char* value;
-} test_entry;
+};
 
-static void populate_entries(const test_entry* input, size_t num_entries,
-                             grpc_slice_hash_table_entry* output) {
-  for (size_t i = 0; i < num_entries; ++i) {
-    output[i].key = grpc_slice_from_copied_string(input[i].key);
-    output[i].value = gpr_strdup(input[i].value);
-  }
-}
-
-static void check_values(const test_entry* input, size_t num_entries,
-                         grpc_slice_hash_table* table) {
-  for (size_t i = 0; i < num_entries; ++i) {
-    grpc_slice key = grpc_slice_from_static_string(input[i].key);
-    const char* actual =
-        static_cast<const char*>(grpc_slice_hash_table_get(table, key));
-    GPR_ASSERT(actual != nullptr);
-    GPR_ASSERT(strcmp(actual, input[i].value) == 0);
+void CheckValues(const std::vector<TestEntry>& input,
+                 const TestHashTable& table) {
+  for (const TestEntry& expected : input) {
+    grpc_slice key = grpc_slice_from_static_string(expected.key);
+    const UniquePtr<char>* actual = table.Get(key);
+    ASSERT_NE(actual, nullptr);
+    EXPECT_STREQ(expected.value, actual->get());
     grpc_slice_unref(key);
   }
 }
 
-static void check_non_existent_value(const char* key_string,
-                                     grpc_slice_hash_table* table) {
+void CheckNonExistentValue(const char* key_string, const TestHashTable& table) {
   grpc_slice key = grpc_slice_from_static_string(key_string);
-  GPR_ASSERT(grpc_slice_hash_table_get(table, key) == nullptr);
+  ASSERT_EQ(nullptr, table.Get(key));
   grpc_slice_unref(key);
 }
 
-static void destroy_string(void* value) { gpr_free(value); }
+void PopulateEntries(const std::vector<TestEntry>& input,
+                     TestHashTable::Entry* output) {
+  for (size_t i = 0; i < input.size(); ++i) {
+    output[i].key = grpc_slice_from_copied_string(input[i].key);
+    output[i].value = UniquePtr<char>(gpr_strdup(input[i].value));
+  }
+}
 
-static grpc_slice_hash_table* create_table_from_entries(
-    const test_entry* test_entries, size_t num_test_entries,
-    int (*value_cmp_fn)(void*, void*)) {
-  // Construct table.
-  grpc_slice_hash_table_entry* entries =
-      static_cast<grpc_slice_hash_table_entry*>(
-          gpr_zalloc(sizeof(*entries) * num_test_entries));
-  populate_entries(test_entries, num_test_entries, entries);
-  grpc_slice_hash_table* table = grpc_slice_hash_table_create(
-      num_test_entries, entries, destroy_string, value_cmp_fn);
+RefCountedPtr<TestHashTable> CreateTableFromEntries(
+    const std::vector<TestEntry>& test_entries,
+    TestHashTable::ValueCmp value_cmp) {
+  TestHashTable::Entry* entries = static_cast<TestHashTable::Entry*>(
+      gpr_zalloc(sizeof(*entries) * test_entries.size()));
+  PopulateEntries(test_entries, entries);
+  RefCountedPtr<TestHashTable> table =
+      TestHashTable::Create(test_entries.size(), entries, value_cmp);
   gpr_free(entries);
   return table;
 }
 
-static void test_slice_hash_table() {
-  const test_entry test_entries[] = {
+TEST(SliceHashTable, Basic) {
+  const std::vector<TestEntry> test_entries = {
       {"key_0", "value_0"},   {"key_1", "value_1"},   {"key_2", "value_2"},
       {"key_3", "value_3"},   {"key_4", "value_4"},   {"key_5", "value_5"},
       {"key_6", "value_6"},   {"key_7", "value_7"},   {"key_8", "value_8"},
@@ -112,129 +116,110 @@
       {"key_96", "value_96"}, {"key_97", "value_97"}, {"key_98", "value_98"},
       {"key_99", "value_99"},
   };
-  const size_t num_entries = GPR_ARRAY_SIZE(test_entries);
-  grpc_slice_hash_table* table =
-      create_table_from_entries(test_entries, num_entries, nullptr);
+  RefCountedPtr<TestHashTable> table =
+      CreateTableFromEntries(test_entries, nullptr);
   // Check contents of table.
-  check_values(test_entries, num_entries, table);
-  check_non_existent_value("XX", table);
-  // Clean up.
-  grpc_core::ExecCtx exec_ctx;
-  grpc_slice_hash_table_unref(table);
+  CheckValues(test_entries, *table);
+  CheckNonExistentValue("XX", *table);
 }
 
-static int value_cmp_fn(void* a, void* b) {
-  const char* a_str = static_cast<const char*>(a);
-  const char* b_str = static_cast<const char*>(b);
-  return strcmp(a_str, b_str);
+int StringCmp(const UniquePtr<char>& a, const UniquePtr<char>& b) {
+  return strcmp(a.get(), b.get());
 }
 
-static int pointer_cmp_fn(void* a, void* b) { return GPR_ICMP(a, b); }
-
-static void test_slice_hash_table_eq() {
-  const test_entry test_entries_a[] = {
-      {"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
-  const size_t num_entries_a = GPR_ARRAY_SIZE(test_entries_a);
-  grpc_slice_hash_table* table_a =
-      create_table_from_entries(test_entries_a, num_entries_a, value_cmp_fn);
-  GPR_ASSERT(grpc_slice_hash_table_cmp(table_a, table_a) == 0);
-
-  const test_entry test_entries_b[] = {
-      {"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
-  const size_t num_entries_b = GPR_ARRAY_SIZE(test_entries_b);
-  grpc_slice_hash_table* table_b =
-      create_table_from_entries(test_entries_b, num_entries_b, value_cmp_fn);
-
-  GPR_ASSERT(grpc_slice_hash_table_cmp(table_a, table_b) == 0);
-  grpc_core::ExecCtx exec_ctx;
-  grpc_slice_hash_table_unref(table_a);
-  grpc_slice_hash_table_unref(table_b);
+int PointerCmp(const UniquePtr<char>& a, const UniquePtr<char>& b) {
+  return GPR_ICMP(a.get(), b.get());
 }
 
-static void test_slice_hash_table_not_eq() {
-  const test_entry test_entries_a[] = {
+TEST(SliceHashTable, CmpEqual) {
+  const std::vector<TestEntry> test_entries_a = {
       {"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
-  const size_t num_entries_a = GPR_ARRAY_SIZE(test_entries_a);
-  grpc_slice_hash_table* table_a =
-      create_table_from_entries(test_entries_a, num_entries_a, value_cmp_fn);
+  RefCountedPtr<TestHashTable> table_a =
+      CreateTableFromEntries(test_entries_a, StringCmp);
+  const std::vector<TestEntry> test_entries_b = {
+      {"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
+  RefCountedPtr<TestHashTable> table_b =
+      CreateTableFromEntries(test_entries_b, StringCmp);
+  // table_a equals itself.
+  EXPECT_EQ(0, TestHashTable::Cmp(*table_a, *table_a));
+  // table_a equals table_b.
+  EXPECT_EQ(0, TestHashTable::Cmp(*table_a, *table_b));
+}
 
-  // Different sizes.
-  const test_entry test_entries_b_smaller[] = {{"key_0", "value_0"},
-                                               {"key_1", "value_1"}};
-  const size_t num_entries_b_smaller = GPR_ARRAY_SIZE(test_entries_b_smaller);
-  grpc_slice_hash_table* table_b_smaller = create_table_from_entries(
-      test_entries_b_smaller, num_entries_b_smaller, value_cmp_fn);
-  GPR_ASSERT(grpc_slice_hash_table_cmp(table_a, table_b_smaller) > 0);
+TEST(SliceHashTable, CmpDifferentSizes) {
+  // table_a has 3 entries, table_b has only 2.
+  const std::vector<TestEntry> test_entries_a = {
+      {"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
+  RefCountedPtr<TestHashTable> table_a =
+      CreateTableFromEntries(test_entries_a, StringCmp);
+  const std::vector<TestEntry> test_entries_b = {{"key_0", "value_0"},
+                                                 {"key_1", "value_1"}};
+  RefCountedPtr<TestHashTable> table_b =
+      CreateTableFromEntries(test_entries_b, StringCmp);
+  EXPECT_GT(TestHashTable::Cmp(*table_a, *table_b), 0);
+  EXPECT_LT(TestHashTable::Cmp(*table_b, *table_a), 0);
+}
 
-  const test_entry test_entries_b_larger[] = {{"key_0", "value_0"},
-                                              {"key_1", "value_1"},
-                                              {"key_2", "value_2"},
-                                              {"key_3", "value_3"}};
-  const size_t num_entries_b_larger = GPR_ARRAY_SIZE(test_entries_b_larger);
-  grpc_slice_hash_table* table_b_larger = create_table_from_entries(
-      test_entries_b_larger, num_entries_b_larger, value_cmp_fn);
-  GPR_ASSERT(grpc_slice_hash_table_cmp(table_a, table_b_larger) < 0);
-
+TEST(SliceHashTable, CmpDifferentKey) {
   // One key doesn't match and is lexicographically "smaller".
-  const test_entry test_entries_c[] = {
+  const std::vector<TestEntry> test_entries_a = {
+      {"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
+  RefCountedPtr<TestHashTable> table_a =
+      CreateTableFromEntries(test_entries_a, StringCmp);
+  const std::vector<TestEntry> test_entries_b = {
       {"key_zz", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
-  const size_t num_entries_c = GPR_ARRAY_SIZE(test_entries_c);
-  grpc_slice_hash_table* table_c =
-      create_table_from_entries(test_entries_c, num_entries_c, value_cmp_fn);
-  GPR_ASSERT(grpc_slice_hash_table_cmp(table_a, table_c) > 0);
-  GPR_ASSERT(grpc_slice_hash_table_cmp(table_c, table_a) < 0);
-
-  // One value doesn't match.
-  const test_entry test_entries_d[] = {
-      {"key_0", "value_z"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
-  const size_t num_entries_d = GPR_ARRAY_SIZE(test_entries_d);
-  grpc_slice_hash_table* table_d =
-      create_table_from_entries(test_entries_d, num_entries_d, value_cmp_fn);
-  GPR_ASSERT(grpc_slice_hash_table_cmp(table_a, table_d) < 0);
-  GPR_ASSERT(grpc_slice_hash_table_cmp(table_d, table_a) > 0);
-
-  // Same values but different "equals" functions.
-  const test_entry test_entries_e[] = {
-      {"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
-  const size_t num_entries_e = GPR_ARRAY_SIZE(test_entries_e);
-  grpc_slice_hash_table* table_e =
-      create_table_from_entries(test_entries_e, num_entries_e, value_cmp_fn);
-  const test_entry test_entries_f[] = {
-      {"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
-  const size_t num_entries_f = GPR_ARRAY_SIZE(test_entries_f);
-  grpc_slice_hash_table* table_f =
-      create_table_from_entries(test_entries_f, num_entries_f, pointer_cmp_fn);
-  GPR_ASSERT(grpc_slice_hash_table_cmp(table_e, table_f) != 0);
-
-  // Same (empty) key, different values.
-  const test_entry test_entries_g[] = {{"", "value_0"}};
-  const size_t num_entries_g = GPR_ARRAY_SIZE(test_entries_g);
-  grpc_slice_hash_table* table_g =
-      create_table_from_entries(test_entries_g, num_entries_g, value_cmp_fn);
-  const test_entry test_entries_h[] = {{"", "value_1"}};
-  const size_t num_entries_h = GPR_ARRAY_SIZE(test_entries_h);
-  grpc_slice_hash_table* table_h =
-      create_table_from_entries(test_entries_h, num_entries_h, pointer_cmp_fn);
-  GPR_ASSERT(grpc_slice_hash_table_cmp(table_g, table_h) != 0);
-
-  grpc_core::ExecCtx exec_ctx;
-  grpc_slice_hash_table_unref(table_a);
-  grpc_slice_hash_table_unref(table_b_larger);
-  grpc_slice_hash_table_unref(table_b_smaller);
-  grpc_slice_hash_table_unref(table_c);
-  grpc_slice_hash_table_unref(table_d);
-  grpc_slice_hash_table_unref(table_e);
-  grpc_slice_hash_table_unref(table_f);
-  grpc_slice_hash_table_unref(table_g);
-  grpc_slice_hash_table_unref(table_h);
+  RefCountedPtr<TestHashTable> table_b =
+      CreateTableFromEntries(test_entries_b, StringCmp);
+  EXPECT_GT(TestHashTable::Cmp(*table_a, *table_b), 0);
+  EXPECT_LT(TestHashTable::Cmp(*table_b, *table_a), 0);
 }
 
+TEST(SliceHashTable, CmpDifferentValue) {
+  // One value doesn't match.
+  const std::vector<TestEntry> test_entries_a = {
+      {"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
+  RefCountedPtr<TestHashTable> table_a =
+      CreateTableFromEntries(test_entries_a, StringCmp);
+  const std::vector<TestEntry> test_entries_b = {
+      {"key_0", "value_z"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
+  RefCountedPtr<TestHashTable> table_b =
+      CreateTableFromEntries(test_entries_b, StringCmp);
+  EXPECT_LT(TestHashTable::Cmp(*table_a, *table_b), 0);
+  EXPECT_GT(TestHashTable::Cmp(*table_b, *table_a), 0);
+}
+
+TEST(SliceHashTable, CmpDifferentCmpFunctions) {
+  // Same values but different "equals" functions.
+  const std::vector<TestEntry> test_entries_a = {
+      {"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
+  RefCountedPtr<TestHashTable> table_a =
+      CreateTableFromEntries(test_entries_a, StringCmp);
+  const std::vector<TestEntry> test_entries_b = {
+      {"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
+  RefCountedPtr<TestHashTable> table_b =
+      CreateTableFromEntries(test_entries_b, PointerCmp);
+  EXPECT_NE(TestHashTable::Cmp(*table_a, *table_b), 0);
+}
+
+TEST(SliceHashTable, CmpEmptyKeysDifferentValue) {
+  // Same (empty) key, different values.
+  const std::vector<TestEntry> test_entries_a = {{"", "value_0"}};
+  RefCountedPtr<TestHashTable> table_a =
+      CreateTableFromEntries(test_entries_a, StringCmp);
+  const std::vector<TestEntry> test_entries_b = {{"", "value_1"}};
+  RefCountedPtr<TestHashTable> table_b =
+      CreateTableFromEntries(test_entries_b, PointerCmp);
+  EXPECT_NE(TestHashTable::Cmp(*table_a, *table_b), 0);
+}
+
+}  // namespace
+}  // namespace grpc_core
+
 int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
   grpc_test_init(argc, argv);
   grpc_core::ExecCtx::GlobalInit();
-  test_slice_hash_table();
-  test_slice_hash_table_eq();
-  test_slice_hash_table_not_eq();
+  int result = RUN_ALL_TESTS();
   grpc_core::ExecCtx::GlobalShutdown();
-  return 0;
+  return result;
 }
diff --git a/test/core/slice/slice_string_helpers_test.cc b/test/core/slice/slice_string_helpers_test.cc
index 1e38f8d..860a1bf 100644
--- a/test/core/slice/slice_string_helpers_test.cc
+++ b/test/core/slice/slice_string_helpers_test.cc
@@ -26,7 +26,6 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 
 #include "src/core/lib/gpr/string.h"
 #include "test/core/util/test_config.h"
diff --git a/test/core/slice/slice_test.cc b/test/core/slice/slice_test.cc
index e40154d..e683c41 100644
--- a/test/core/slice/slice_test.cc
+++ b/test/core/slice/slice_test.cc
@@ -16,8 +16,11 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <grpc/slice.h>
 
+#include <inttypes.h>
 #include <string.h>
 
 #include <grpc/grpc.h>
@@ -57,7 +60,7 @@
     }
     /* We must be able to write to every byte of the data */
     for (i = 0; i < length; i++) {
-      GRPC_SLICE_START_PTR(slice)[i] = (uint8_t)i;
+      GRPC_SLICE_START_PTR(slice)[i] = static_cast<uint8_t>(i);
     }
     /* And finally we must succeed in destroying the slice */
     grpc_slice_unref(slice);
@@ -77,7 +80,7 @@
 }
 
 /* destroy function that sets a mark to indicate it was called. */
-static void set_mark(void* p) { *((int*)p) = 1; }
+static void set_mark(void* p) { *(static_cast<int*>(p)) = 1; }
 
 static void test_slice_new_with_user_data(void) {
   int marker = 0;
@@ -143,7 +146,7 @@
      beginning of the slice. */
   slice = grpc_slice_malloc(length);
   for (i = 0; i < length; i++) {
-    GRPC_SLICE_START_PTR(slice)[i] = (uint8_t)i;
+    GRPC_SLICE_START_PTR(slice)[i] = static_cast<uint8_t>(i);
   }
 
   /* Ensure that for all subsets length is correct and that we start on the
@@ -183,7 +186,7 @@
      beginning of the slice. */
   slice = grpc_slice_malloc(length);
   for (i = 0; i < length; i++) {
-    GRPC_SLICE_START_PTR(slice)[i] = (uint8_t)i;
+    GRPC_SLICE_START_PTR(slice)[i] = static_cast<uint8_t>(i);
   }
 
   /* Ensure that for all subsets length is correct and that we start on the
@@ -211,7 +214,7 @@
      beginning of the slice. */
   slice = grpc_slice_malloc(length);
   for (i = 0; i < length; i++) {
-    GRPC_SLICE_START_PTR(slice)[i] = (uint8_t)i;
+    GRPC_SLICE_START_PTR(slice)[i] = static_cast<uint8_t>(i);
   }
 
   /* Ensure that for all subsets length is correct and that we start on the
diff --git a/test/core/slice/slice_weak_hash_table_test.cc b/test/core/slice/slice_weak_hash_table_test.cc
new file mode 100644
index 0000000..b0a243d
--- /dev/null
+++ b/test/core/slice/slice_weak_hash_table_test.cc
@@ -0,0 +1,106 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/core/lib/slice/slice_weak_hash_table.h"
+
+#include <cstring>
+#include <sstream>
+
+#include <gtest/gtest.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "test/core/util/test_config.h"
+
+namespace grpc_core {
+namespace {
+
+grpc_slice BuildRefCountedKey(const char* key_str) {
+  const size_t key_length = strlen(key_str);
+  grpc_slice key = grpc_slice_malloc_large(key_length);
+  memcpy(GRPC_SLICE_START_PTR(key), key_str, key_length);
+  return key;
+}
+
+TEST(SliceWeakHashTable, Basic) {
+  auto table = SliceWeakHashTable<UniquePtr<char>, 10>::Create();
+  // Single key-value insertion.
+  grpc_slice key = BuildRefCountedKey("key");
+  grpc_slice_ref(key);  // Get doesn't own.
+  table->Add(key, UniquePtr<char>(gpr_strdup("value")));
+  ASSERT_NE(table->Get(key), nullptr);
+  ASSERT_STREQ(table->Get(key)->get(), "value");
+  grpc_slice_unref(key);
+  // Unknown key.
+  ASSERT_EQ(table->Get(grpc_slice_from_static_string("unknown_key")), nullptr);
+}
+
+TEST(SliceWeakHashTable, ValueTypeConstructor) {
+  struct Value {
+    Value() : a(123) {}
+    int a;
+  };
+  auto table = SliceWeakHashTable<Value, 1>::Create();
+  grpc_slice key = BuildRefCountedKey("key");
+  grpc_slice_ref(key);  // Get doesn't own.
+  table->Add(key, Value());
+  ASSERT_EQ(table->Get(key)->a, 123);
+  grpc_slice_unref(key);
+}
+
+TEST(SliceWeakHashTable, ForceOverload) {
+  constexpr int kTableSize = 10;
+  auto table = SliceWeakHashTable<UniquePtr<char>, kTableSize>::Create();
+  // Insert a multiple of the maximum size table.
+  for (int i = 0; i < kTableSize * 2; ++i) {
+    std::ostringstream oss;
+    oss << "key-" << i;
+    grpc_slice key = BuildRefCountedKey(oss.str().c_str());
+    oss.clear();
+    oss << "value-" << i;
+    table->Add(key, UniquePtr<char>(gpr_strdup(oss.str().c_str())));
+  }
+  // Verify that some will have been replaced.
+  int num_missing = 0;
+  for (int i = 0; i < kTableSize * 2; ++i) {
+    std::ostringstream oss;
+    oss << "key-" << i;
+    grpc_slice key = BuildRefCountedKey(oss.str().c_str());
+    if (table->Get(key) == nullptr) num_missing++;
+    grpc_slice_unref(key);
+  }
+  // At least kTableSize elements will be missing.
+  ASSERT_GE(num_missing, kTableSize);
+}
+
+}  // namespace
+}  // namespace grpc_core
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  grpc_test_init(argc, argv);
+  grpc_core::ExecCtx::GlobalInit();
+  int result = RUN_ALL_TESTS();
+  grpc_core::ExecCtx::GlobalShutdown();
+  return result;
+}
diff --git a/test/core/statistics/rpc_stats_test.cc b/test/core/statistics/rpc_stats_test.cc
index aead5cf..a2a648e 100644
--- a/test/core/statistics/rpc_stats_test.cc
+++ b/test/core/statistics/rpc_stats_test.cc
@@ -22,8 +22,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
 #include <grpc/support/string.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
+
 #include "src/core/ext/census/census_interface.h"
 #include "src/core/ext/census/census_rpc_stats.h"
 #include "src/core/ext/census/census_tracing.h"
diff --git a/test/core/surface/BUILD b/test/core/surface/BUILD
index d27123d..e848dde 100644
--- a/test/core/surface/BUILD
+++ b/test/core/surface/BUILD
@@ -55,6 +55,18 @@
 )
 
 grpc_cc_test(
+    name = "completion_queue_threading_test",
+    srcs = ["completion_queue_threading_test.cc"],
+    language = "C++",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+grpc_cc_test(
     name = "concurrent_connectivity_test",
     srcs = ["concurrent_connectivity_test.cc"],
     language = "C++",
@@ -104,6 +116,19 @@
 )
 
 grpc_cc_test(
+    name = "num_external_connectivity_watchers_test",
+    srcs = ["num_external_connectivity_watchers_test.cc"],
+    language = "C++",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/end2end:ssl_test_data",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+grpc_cc_test(
     name = "public_headers_must_be_c89",
     srcs = ["public_headers_must_be_c89.c"],
     language = "C",
diff --git a/test/core/surface/byte_buffer_reader_test.cc b/test/core/surface/byte_buffer_reader_test.cc
index 91662b0..cff05ca 100644
--- a/test/core/surface/byte_buffer_reader_test.cc
+++ b/test/core/surface/byte_buffer_reader_test.cc
@@ -23,10 +23,10 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
 
 #include "src/core/lib/compression/message_compress.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "test/core/util/test_config.h"
 
@@ -109,7 +109,7 @@
   LOG_TEST("test_read_corrupted_slice");
   slice = grpc_slice_from_copied_string("test");
   buffer = grpc_raw_byte_buffer_create(&slice, 1);
-  buffer->data.raw.compression = GRPC_COMPRESS_MESSAGE_GZIP; /* lies! */
+  buffer->data.raw.compression = GRPC_COMPRESS_GZIP; /* lies! */
   grpc_slice_unref(slice);
   GPR_ASSERT(!grpc_byte_buffer_reader_init(&reader, buffer));
   grpc_byte_buffer_destroy(buffer);
@@ -161,13 +161,13 @@
 static void test_read_gzip_compressed_slice(void) {
   const size_t INPUT_SIZE = 2048;
   LOG_TEST("test_read_gzip_compressed_slice");
-  read_compressed_slice(GRPC_COMPRESS_MESSAGE_GZIP, INPUT_SIZE);
+  read_compressed_slice(GRPC_COMPRESS_GZIP, INPUT_SIZE);
 }
 
 static void test_read_deflate_compressed_slice(void) {
   const size_t INPUT_SIZE = 2048;
   LOG_TEST("test_read_deflate_compressed_slice");
-  read_compressed_slice(GRPC_COMPRESS_MESSAGE_DEFLATE, INPUT_SIZE);
+  read_compressed_slice(GRPC_COMPRESS_DEFLATE, INPUT_SIZE);
 }
 
 static void test_byte_buffer_from_reader(void) {
diff --git a/test/core/surface/channel_create_test.cc b/test/core/surface/channel_create_test.cc
index 37247f8..56f4f60 100644
--- a/test/core/surface/channel_create_test.cc
+++ b/test/core/surface/channel_create_test.cc
@@ -29,8 +29,8 @@
 void test_unknown_scheme_target(void) {
   grpc_channel* chan;
   /* avoid default prefix */
-  grpc_resolver_registry_shutdown();
-  grpc_resolver_registry_init();
+  grpc_core::ResolverRegistry::Builder::ShutdownRegistry();
+  grpc_core::ResolverRegistry::Builder::InitRegistry();
 
   chan = grpc_insecure_channel_create("blah://blah", nullptr, nullptr);
   GPR_ASSERT(chan != nullptr);
diff --git a/test/core/surface/completion_queue_test.cc b/test/core/surface/completion_queue_test.cc
index fefbb3c..6812914 100644
--- a/test/core/surface/completion_queue_test.cc
+++ b/test/core/surface/completion_queue_test.cc
@@ -21,7 +21,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/surface/completion_queue_threading_test.cc b/test/core/surface/completion_queue_threading_test.cc
index 4a9e818..0b82803 100644
--- a/test/core/surface/completion_queue_threading_test.cc
+++ b/test/core/surface/completion_queue_threading_test.cc
@@ -20,9 +20,10 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "test/core/util/test_config.h"
 
@@ -77,16 +78,14 @@
   grpc_completion_queue* cc;
   void* tags[GRPC_MAX_COMPLETION_QUEUE_PLUCKERS];
   grpc_cq_completion completions[GPR_ARRAY_SIZE(tags)];
-  gpr_thd_id thread_ids[GPR_ARRAY_SIZE(tags)];
+  grpc_core::Thread threads[GPR_ARRAY_SIZE(tags)];
   struct thread_state thread_states[GPR_ARRAY_SIZE(tags)];
-  gpr_thd_options thread_options = gpr_thd_options_default();
   grpc_core::ExecCtx exec_ctx;
   unsigned i, j;
 
   LOG_TEST("test_too_many_plucks");
 
   cc = grpc_completion_queue_create_for_pluck(nullptr);
-  gpr_thd_options_set_joinable(&thread_options);
 
   for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
     tags[i] = create_test_tag();
@@ -95,8 +94,9 @@
     }
     thread_states[i].cc = cc;
     thread_states[i].tag = tags[i];
-    gpr_thd_new(thread_ids + i, "grpc_pluck_test", pluck_one, thread_states + i,
-                &thread_options);
+    threads[i] =
+        grpc_core::Thread("grpc_pluck_test", pluck_one, thread_states + i);
+    threads[i].Start();
   }
 
   /* wait until all other threads are plucking */
@@ -112,8 +112,8 @@
                    nullptr, &completions[i]);
   }
 
-  for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
-    gpr_thd_join(thread_ids[i]);
+  for (auto& th : threads) {
+    th.Join();
   }
 
   shutdown_and_destroy(cc);
@@ -145,7 +145,7 @@
   int i;
 
   gpr_log(GPR_INFO, "producer %d started", opt->id);
-  gpr_event_set(&opt->on_started, (void*)(intptr_t)1);
+  gpr_event_set(&opt->on_started, (void*)static_cast<intptr_t>(1));
   GPR_ASSERT(gpr_event_wait(opt->phase1, ten_seconds_time()));
 
   gpr_log(GPR_INFO, "producer %d phase 1", opt->id);
@@ -154,13 +154,13 @@
   }
 
   gpr_log(GPR_INFO, "producer %d phase 1 done", opt->id);
-  gpr_event_set(&opt->on_phase1_done, (void*)(intptr_t)1);
+  gpr_event_set(&opt->on_phase1_done, (void*)static_cast<intptr_t>(1));
   GPR_ASSERT(gpr_event_wait(opt->phase2, ten_seconds_time()));
 
   gpr_log(GPR_INFO, "producer %d phase 2", opt->id);
   for (i = 0; i < TEST_THREAD_EVENTS; i++) {
     grpc_core::ExecCtx exec_ctx;
-    grpc_cq_end_op(opt->cc, (void*)(intptr_t)1, GRPC_ERROR_NONE,
+    grpc_cq_end_op(opt->cc, (void*)static_cast<intptr_t>(1), GRPC_ERROR_NONE,
                    free_completion, nullptr,
                    static_cast<grpc_cq_completion*>(
                        gpr_malloc(sizeof(grpc_cq_completion))));
@@ -168,7 +168,7 @@
   }
 
   gpr_log(GPR_INFO, "producer %d phase 2 done", opt->id);
-  gpr_event_set(&opt->on_finished, (void*)(intptr_t)1);
+  gpr_event_set(&opt->on_finished, (void*)static_cast<intptr_t>(1));
 }
 
 static void consumer_thread(void* arg) {
@@ -176,13 +176,13 @@
   grpc_event ev;
 
   gpr_log(GPR_INFO, "consumer %d started", opt->id);
-  gpr_event_set(&opt->on_started, (void*)(intptr_t)1);
+  gpr_event_set(&opt->on_started, (void*)static_cast<intptr_t>(1));
   GPR_ASSERT(gpr_event_wait(opt->phase1, ten_seconds_time()));
 
   gpr_log(GPR_INFO, "consumer %d phase 1", opt->id);
 
   gpr_log(GPR_INFO, "consumer %d phase 1 done", opt->id);
-  gpr_event_set(&opt->on_phase1_done, (void*)(intptr_t)1);
+  gpr_event_set(&opt->on_phase1_done, (void*)static_cast<intptr_t>(1));
   GPR_ASSERT(gpr_event_wait(opt->phase2, ten_seconds_time()));
 
   gpr_log(GPR_INFO, "consumer %d phase 2", opt->id);
@@ -196,7 +196,7 @@
         break;
       case GRPC_QUEUE_SHUTDOWN:
         gpr_log(GPR_INFO, "consumer %d phase 2 done", opt->id);
-        gpr_event_set(&opt->on_finished, (void*)(intptr_t)1);
+        gpr_event_set(&opt->on_finished, (void*)static_cast<intptr_t>(1));
         return;
       case GRPC_QUEUE_TIMEOUT:
         gpr_log(GPR_ERROR, "Invalid timeout received");
@@ -219,8 +219,9 @@
           "test_threading", producers, consumers);
 
   /* start all threads: they will wait for phase1 */
+  grpc_core::Thread* threads = static_cast<grpc_core::Thread*>(
+      gpr_malloc(sizeof(*threads) * (producers + consumers)));
   for (i = 0; i < producers + consumers; i++) {
-    gpr_thd_id id;
     gpr_event_init(&options[i].on_started);
     gpr_event_init(&options[i].on_phase1_done);
     gpr_event_init(&options[i].on_finished);
@@ -229,17 +230,20 @@
     options[i].events_triggered = 0;
     options[i].cc = cc;
     options[i].id = optid++;
-    GPR_ASSERT(gpr_thd_new(&id,
-                           i < producers ? "grpc_producer" : "grpc_consumer",
-                           i < producers ? producer_thread : consumer_thread,
-                           options + i, nullptr));
+
+    bool ok;
+    threads[i] = grpc_core::Thread(
+        i < producers ? "grpc_producer" : "grpc_consumer",
+        i < producers ? producer_thread : consumer_thread, options + i, &ok);
+    GPR_ASSERT(ok);
+    threads[i].Start();
     gpr_event_wait(&options[i].on_started, ten_seconds_time());
   }
 
   /* start phase1: producers will pre-declare all operations they will
      complete */
   gpr_log(GPR_INFO, "start phase 1");
-  gpr_event_set(&phase1, (void*)(intptr_t)1);
+  gpr_event_set(&phase1, (void*)static_cast<intptr_t>(1));
 
   gpr_log(GPR_INFO, "wait phase 1");
   for (i = 0; i < producers + consumers; i++) {
@@ -249,7 +253,7 @@
 
   /* start phase2: operations will complete, and consumers will consume them */
   gpr_log(GPR_INFO, "start phase 2");
-  gpr_event_set(&phase2, (void*)(intptr_t)1);
+  gpr_event_set(&phase2, (void*)static_cast<intptr_t>(1));
 
   /* in parallel, we shutdown the completion channel - all events should still
      be consumed */
@@ -265,6 +269,11 @@
   /* destroy the completion channel */
   grpc_completion_queue_destroy(cc);
 
+  for (i = 0; i < producers + consumers; i++) {
+    threads[i].Join();
+  }
+  gpr_free(threads);
+
   /* verify that everything was produced and consumed */
   for (i = 0; i < producers + consumers; i++) {
     if (i < producers) {
diff --git a/test/core/surface/concurrent_connectivity_test.cc b/test/core/surface/concurrent_connectivity_test.cc
index 235d136..fbc5ec4 100644
--- a/test/core/surface/concurrent_connectivity_test.cc
+++ b/test/core/surface/concurrent_connectivity_test.cc
@@ -29,8 +29,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/thd.h>
 
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/iomgr/resolve_address.h"
@@ -55,14 +55,14 @@
 // it should never take longer that this to shutdown the server
 #define SERVER_SHUTDOWN_TIMEOUT 30000
 
-static void* tag(int n) { return (void*)(uintptr_t)n; }
-static int detag(void* p) { return (int)(uintptr_t)p; }
+static void* tag(int n) { return (void*)static_cast<uintptr_t>(n); }
+static int detag(void* p) { return static_cast<int>((uintptr_t)p); }
 
 void create_loop_destroy(void* addr) {
   for (int i = 0; i < NUM_OUTER_LOOPS; ++i) {
     grpc_completion_queue* cq = grpc_completion_queue_create_for_next(nullptr);
-    grpc_channel* chan =
-        grpc_insecure_channel_create((char*)addr, nullptr, nullptr);
+    grpc_channel* chan = grpc_insecure_channel_create(static_cast<char*>(addr),
+                                                      nullptr, nullptr);
 
     for (int j = 0; j < NUM_INNER_LOOPS; ++j) {
       gpr_timespec later_time =
@@ -94,7 +94,8 @@
 };
 
 void server_thread(void* vargs) {
-  struct server_thread_args* args = (struct server_thread_args*)vargs;
+  struct server_thread_args* args =
+      static_cast<struct server_thread_args*>(vargs);
   grpc_event ev;
   gpr_timespec deadline =
       grpc_timeout_milliseconds_to_deadline(SERVER_SHUTDOWN_TIMEOUT);
@@ -107,7 +108,8 @@
                        grpc_pollset* accepting_pollset,
                        grpc_tcp_server_acceptor* acceptor) {
   gpr_free(acceptor);
-  struct server_thread_args* args = (struct server_thread_args*)vargs;
+  struct server_thread_args* args =
+      static_cast<struct server_thread_args*>(vargs);
   grpc_endpoint_shutdown(tcp,
                          GRPC_ERROR_CREATE_FROM_STATIC_STRING("Connected"));
   grpc_endpoint_destroy(tcp);
@@ -117,17 +119,18 @@
 }
 
 void bad_server_thread(void* vargs) {
-  struct server_thread_args* args = (struct server_thread_args*)vargs;
+  struct server_thread_args* args =
+      static_cast<struct server_thread_args*>(vargs);
 
   grpc_core::ExecCtx exec_ctx;
   grpc_resolved_address resolved_addr;
-  struct sockaddr_storage* addr = (struct sockaddr_storage*)resolved_addr.addr;
+  grpc_sockaddr* addr = reinterpret_cast<grpc_sockaddr*>(resolved_addr.addr);
   int port;
   grpc_tcp_server* s;
   grpc_error* error = grpc_tcp_server_create(nullptr, nullptr, &s);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
   memset(&resolved_addr, 0, sizeof(resolved_addr));
-  addr->ss_family = AF_INET;
+  addr->sa_family = GRPC_AF_INET;
   error = grpc_tcp_server_add_port(s, &resolved_addr, &port);
   GPR_ASSERT(GRPC_LOG_IF_ERROR("grpc_tcp_server_add_port", error));
   GPR_ASSERT(port > 0);
@@ -168,73 +171,77 @@
 
   grpc_init();
 
-  gpr_thd_id threads[NUM_THREADS];
-  gpr_thd_id server;
-
-  char* localhost = gpr_strdup("localhost:54321");
-  gpr_thd_options options = gpr_thd_options_default();
-  gpr_thd_options_set_joinable(&options);
-
   /* First round, no server */
-  gpr_log(GPR_DEBUG, "Wave 1");
-  for (size_t i = 0; i < NUM_THREADS; ++i) {
-    gpr_thd_new(&threads[i], "grpc_wave_1", create_loop_destroy, localhost,
-                &options);
-  }
-  for (size_t i = 0; i < NUM_THREADS; ++i) {
-    gpr_thd_join(threads[i]);
-  }
-  gpr_free(localhost);
-
-  /* Second round, actual grpc server */
-  gpr_log(GPR_DEBUG, "Wave 2");
-  int port = grpc_pick_unused_port_or_die();
-  gpr_asprintf(&args.addr, "localhost:%d", port);
-  args.server = grpc_server_create(nullptr, nullptr);
-  grpc_server_add_insecure_http2_port(args.server, args.addr);
-  args.cq = grpc_completion_queue_create_for_next(nullptr);
-  grpc_server_register_completion_queue(args.server, args.cq, nullptr);
-  grpc_server_start(args.server);
-  gpr_thd_new(&server, "grpc_wave_2_server", server_thread, &args, &options);
-
-  for (size_t i = 0; i < NUM_THREADS; ++i) {
-    gpr_thd_new(&threads[i], "grpc_wave_2", create_loop_destroy, args.addr,
-                &options);
-  }
-  for (size_t i = 0; i < NUM_THREADS; ++i) {
-    gpr_thd_join(threads[i]);
-  }
-  grpc_server_shutdown_and_notify(args.server, args.cq, tag(0xd1e));
-
-  gpr_thd_join(server);
-  grpc_server_destroy(args.server);
-  grpc_completion_queue_destroy(args.cq);
-  gpr_free(args.addr);
-
-  /* Third round, bogus tcp server */
-  gpr_log(GPR_DEBUG, "Wave 3");
-  args.pollset = static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
-  grpc_pollset_init(args.pollset, &args.mu);
-  gpr_event_init(&args.ready);
-  gpr_thd_new(&server, "grpc_wave_3_server", bad_server_thread, &args,
-              &options);
-  gpr_event_wait(&args.ready, gpr_inf_future(GPR_CLOCK_MONOTONIC));
-
-  for (size_t i = 0; i < NUM_THREADS; ++i) {
-    gpr_thd_new(&threads[i], "grpc_wave_3", create_loop_destroy, args.addr,
-                &options);
-  }
-  for (size_t i = 0; i < NUM_THREADS; ++i) {
-    gpr_thd_join(threads[i]);
-  }
-
-  gpr_atm_rel_store(&args.stop, 1);
-  gpr_thd_join(server);
   {
-    grpc_core::ExecCtx exec_ctx;
-    grpc_pollset_shutdown(
-        args.pollset, GRPC_CLOSURE_CREATE(done_pollset_shutdown, args.pollset,
-                                          grpc_schedule_on_exec_ctx));
+    gpr_log(GPR_DEBUG, "Wave 1");
+    char* localhost = gpr_strdup("localhost:54321");
+    grpc_core::Thread threads[NUM_THREADS];
+    for (auto& th : threads) {
+      th = grpc_core::Thread("grpc_wave_1", create_loop_destroy, localhost);
+      th.Start();
+    }
+    for (auto& th : threads) {
+      th.Join();
+    }
+    gpr_free(localhost);
+  }
+
+  {
+    /* Second round, actual grpc server */
+    gpr_log(GPR_DEBUG, "Wave 2");
+    int port = grpc_pick_unused_port_or_die();
+    gpr_asprintf(&args.addr, "localhost:%d", port);
+    args.server = grpc_server_create(nullptr, nullptr);
+    grpc_server_add_insecure_http2_port(args.server, args.addr);
+    args.cq = grpc_completion_queue_create_for_next(nullptr);
+    grpc_server_register_completion_queue(args.server, args.cq, nullptr);
+    grpc_server_start(args.server);
+    grpc_core::Thread server2("grpc_wave_2_server", server_thread, &args);
+    server2.Start();
+
+    grpc_core::Thread threads[NUM_THREADS];
+    for (auto& th : threads) {
+      th = grpc_core::Thread("grpc_wave_2", create_loop_destroy, args.addr);
+      th.Start();
+    }
+    for (auto& th : threads) {
+      th.Join();
+    }
+    grpc_server_shutdown_and_notify(args.server, args.cq, tag(0xd1e));
+
+    server2.Join();
+    grpc_server_destroy(args.server);
+    grpc_completion_queue_destroy(args.cq);
+    gpr_free(args.addr);
+  }
+
+  {
+    /* Third round, bogus tcp server */
+    gpr_log(GPR_DEBUG, "Wave 3");
+    args.pollset = static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
+    grpc_pollset_init(args.pollset, &args.mu);
+    gpr_event_init(&args.ready);
+    grpc_core::Thread server3("grpc_wave_3_server", bad_server_thread, &args);
+    server3.Start();
+    gpr_event_wait(&args.ready, gpr_inf_future(GPR_CLOCK_MONOTONIC));
+
+    grpc_core::Thread threads[NUM_THREADS];
+    for (auto& th : threads) {
+      th = grpc_core::Thread("grpc_wave_3", create_loop_destroy, args.addr);
+      th.Start();
+    }
+    for (auto& th : threads) {
+      th.Join();
+    }
+
+    gpr_atm_rel_store(&args.stop, 1);
+    server3.Join();
+    {
+      grpc_core::ExecCtx exec_ctx;
+      grpc_pollset_shutdown(
+          args.pollset, GRPC_CLOSURE_CREATE(done_pollset_shutdown, args.pollset,
+                                            grpc_schedule_on_exec_ctx));
+    }
   }
 
   grpc_shutdown();
@@ -244,8 +251,8 @@
 void watches_with_short_timeouts(void* addr) {
   for (int i = 0; i < NUM_OUTER_LOOPS_SHORT_TIMEOUTS; ++i) {
     grpc_completion_queue* cq = grpc_completion_queue_create_for_next(nullptr);
-    grpc_channel* chan =
-        grpc_insecure_channel_create((char*)addr, nullptr, nullptr);
+    grpc_channel* chan = grpc_insecure_channel_create(static_cast<char*>(addr),
+                                                      nullptr, nullptr);
 
     for (int j = 0; j < NUM_INNER_LOOPS_SHORT_TIMEOUTS; ++j) {
       gpr_timespec later_time =
@@ -274,18 +281,17 @@
 int run_concurrent_watches_with_short_timeouts_test() {
   grpc_init();
 
-  gpr_thd_id threads[NUM_THREADS];
+  grpc_core::Thread threads[NUM_THREADS];
 
   char* localhost = gpr_strdup("localhost:54321");
-  gpr_thd_options options = gpr_thd_options_default();
-  gpr_thd_options_set_joinable(&options);
 
-  for (size_t i = 0; i < NUM_THREADS; ++i) {
-    gpr_thd_new(&threads[i], "grpc_short_watches", watches_with_short_timeouts,
-                localhost, &options);
+  for (auto& th : threads) {
+    th = grpc_core::Thread("grpc_short_watches", watches_with_short_timeouts,
+                           localhost);
+    th.Start();
   }
-  for (size_t i = 0; i < NUM_THREADS; ++i) {
-    gpr_thd_join(threads[i]);
+  for (auto& th : threads) {
+    th.Join();
   }
   gpr_free(localhost);
 
diff --git a/test/core/surface/lame_client_test.cc b/test/core/surface/lame_client_test.cc
index 4bf4056..fac5ca8 100644
--- a/test/core/surface/lame_client_test.cc
+++ b/test/core/surface/lame_client_test.cc
@@ -112,7 +112,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(call, ops, (size_t)(op - ops), tag(1), nullptr);
+  error = grpc_call_start_batch(call, ops, static_cast<size_t>(op - ops),
+                                tag(1), nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   /* the call should immediately fail */
@@ -128,7 +129,8 @@
   op->flags = 0;
   op->reserved = nullptr;
   op++;
-  error = grpc_call_start_batch(call, ops, (size_t)(op - ops), tag(2), nullptr);
+  error = grpc_call_start_batch(call, ops, static_cast<size_t>(op - ops),
+                                tag(2), nullptr);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   /* the call should immediately fail */
diff --git a/test/core/surface/num_external_connectivity_watchers_test.cc b/test/core/surface/num_external_connectivity_watchers_test.cc
index 9cdd299..467deee 100644
--- a/test/core/surface/num_external_connectivity_watchers_test.cc
+++ b/test/core/surface/num_external_connectivity_watchers_test.cc
@@ -19,11 +19,11 @@
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
-#include <grpc/support/thd.h>
 
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/host_port.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "test/core/end2end/data/ssl_test_data.h"
 #include "test/core/util/port.h"
diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c
index 36d5ad6..866bee5 100644
--- a/test/core/surface/public_headers_must_be_c89.c
+++ b/test/core/surface/public_headers_must_be_c89.c
@@ -20,7 +20,6 @@
 #include <grpc/byte_buffer_reader.h>
 #include <grpc/census.h>
 #include <grpc/compression.h>
-#include <grpc/compression_ruby.h>
 #include <grpc/fork.h>
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
@@ -47,21 +46,15 @@
 #include <grpc/status.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/atm.h>
-#include <grpc/support/avl.h>
-#include <grpc/support/cmdline.h>
 #include <grpc/support/cpu.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/subprocess.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/sync_custom.h>
 #include <grpc/support/sync_generic.h>
-#include <grpc/support/thd.h>
+#include <grpc/support/thd_id.h>
 #include <grpc/support/time.h>
-#include <grpc/support/tls.h>
-#include <grpc/support/useful.h>
 #include <grpc/support/workaround_list.h>
 
 #include <stdio.h>
@@ -76,8 +69,6 @@
   printf("%lx", (unsigned long) grpc_compression_options_enable_algorithm);
   printf("%lx", (unsigned long) grpc_compression_options_disable_algorithm);
   printf("%lx", (unsigned long) grpc_compression_options_is_algorithm_enabled);
-  printf("%lx", (unsigned long) grpc_compression_algorithm_parse_ruby);
-  printf("%lx", (unsigned long) grpc_compression_algorithm_name_ruby);
   printf("%lx", (unsigned long) grpc_metadata_array_init);
   printf("%lx", (unsigned long) grpc_metadata_array_destroy);
   printf("%lx", (unsigned long) grpc_call_details_init);
@@ -115,6 +106,8 @@
   printf("%lx", (unsigned long) grpc_insecure_channel_create);
   printf("%lx", (unsigned long) grpc_lame_client_channel_create);
   printf("%lx", (unsigned long) grpc_channel_destroy);
+  printf("%lx", (unsigned long) grpc_channel_get_trace);
+  printf("%lx", (unsigned long) grpc_channel_get_uuid);
   printf("%lx", (unsigned long) grpc_call_cancel);
   printf("%lx", (unsigned long) grpc_call_cancel_with_status);
   printf("%lx", (unsigned long) grpc_call_ref);
@@ -150,6 +143,9 @@
   printf("%lx", (unsigned long) grpc_auth_context_add_property);
   printf("%lx", (unsigned long) grpc_auth_context_add_cstring_property);
   printf("%lx", (unsigned long) grpc_auth_context_set_peer_identity_property_name);
+  printf("%lx", (unsigned long) grpc_ssl_session_cache_create_lru);
+  printf("%lx", (unsigned long) grpc_ssl_session_cache_destroy);
+  printf("%lx", (unsigned long) grpc_ssl_session_cache_create_channel_arg);
   printf("%lx", (unsigned long) grpc_channel_credentials_release);
   printf("%lx", (unsigned long) grpc_google_default_credentials_create);
   printf("%lx", (unsigned long) grpc_set_ssl_roots_override_callback);
@@ -243,27 +239,8 @@
   printf("%lx", (unsigned long) gpr_free_aligned);
   printf("%lx", (unsigned long) gpr_set_allocation_functions);
   printf("%lx", (unsigned long) gpr_get_allocation_functions);
-  printf("%lx", (unsigned long) gpr_avl_create);
-  printf("%lx", (unsigned long) gpr_avl_ref);
-  printf("%lx", (unsigned long) gpr_avl_unref);
-  printf("%lx", (unsigned long) gpr_avl_add);
-  printf("%lx", (unsigned long) gpr_avl_remove);
-  printf("%lx", (unsigned long) gpr_avl_get);
-  printf("%lx", (unsigned long) gpr_avl_maybe_get);
-  printf("%lx", (unsigned long) gpr_avl_is_empty);
-  printf("%lx", (unsigned long) gpr_cmdline_create);
-  printf("%lx", (unsigned long) gpr_cmdline_add_int);
-  printf("%lx", (unsigned long) gpr_cmdline_add_flag);
-  printf("%lx", (unsigned long) gpr_cmdline_add_string);
-  printf("%lx", (unsigned long) gpr_cmdline_on_extra_arg);
-  printf("%lx", (unsigned long) gpr_cmdline_set_survive_failure);
-  printf("%lx", (unsigned long) gpr_cmdline_parse);
-  printf("%lx", (unsigned long) gpr_cmdline_destroy);
-  printf("%lx", (unsigned long) gpr_cmdline_usage_string);
   printf("%lx", (unsigned long) gpr_cpu_num_cores);
   printf("%lx", (unsigned long) gpr_cpu_current_cpu);
-  printf("%lx", (unsigned long) gpr_join_host_port);
-  printf("%lx", (unsigned long) gpr_split_host_port);
   printf("%lx", (unsigned long) gpr_log_severity_string);
   printf("%lx", (unsigned long) gpr_log);
   printf("%lx", (unsigned long) gpr_log_message);
@@ -272,11 +249,6 @@
   printf("%lx", (unsigned long) gpr_set_log_function);
   printf("%lx", (unsigned long) gpr_strdup);
   printf("%lx", (unsigned long) gpr_asprintf);
-  printf("%lx", (unsigned long) gpr_subprocess_binary_extension);
-  printf("%lx", (unsigned long) gpr_subprocess_create);
-  printf("%lx", (unsigned long) gpr_subprocess_destroy);
-  printf("%lx", (unsigned long) gpr_subprocess_join);
-  printf("%lx", (unsigned long) gpr_subprocess_interrupt);
   printf("%lx", (unsigned long) gpr_mu_init);
   printf("%lx", (unsigned long) gpr_mu_destroy);
   printf("%lx", (unsigned long) gpr_mu_lock);
@@ -301,14 +273,7 @@
   printf("%lx", (unsigned long) gpr_stats_init);
   printf("%lx", (unsigned long) gpr_stats_inc);
   printf("%lx", (unsigned long) gpr_stats_read);
-  printf("%lx", (unsigned long) gpr_thd_new);
-  printf("%lx", (unsigned long) gpr_thd_options_default);
-  printf("%lx", (unsigned long) gpr_thd_options_set_detached);
-  printf("%lx", (unsigned long) gpr_thd_options_set_joinable);
-  printf("%lx", (unsigned long) gpr_thd_options_is_detached);
-  printf("%lx", (unsigned long) gpr_thd_options_is_joinable);
   printf("%lx", (unsigned long) gpr_thd_currentid);
-  printf("%lx", (unsigned long) gpr_thd_join);
   printf("%lx", (unsigned long) gpr_time_0);
   printf("%lx", (unsigned long) gpr_inf_future);
   printf("%lx", (unsigned long) gpr_inf_past);
diff --git a/test/core/surface/secure_channel_create_test.cc b/test/core/surface/secure_channel_create_test.cc
index fa22cd6..0696217 100644
--- a/test/core/surface/secure_channel_create_test.cc
+++ b/test/core/surface/secure_channel_create_test.cc
@@ -23,13 +23,13 @@
 #include <grpc/support/log.h>
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/lib/security/credentials/fake/fake_credentials.h"
-#include "src/core/lib/security/transport/security_connector.h"
+#include "src/core/lib/security/security_connector/security_connector.h"
 #include "src/core/lib/surface/channel.h"
 #include "test/core/util/test_config.h"
 
 void test_unknown_scheme_target(void) {
-  grpc_resolver_registry_shutdown();
-  grpc_resolver_registry_init();
+  grpc_core::ResolverRegistry::Builder::ShutdownRegistry();
+  grpc_core::ResolverRegistry::Builder::InitRegistry();
   grpc_channel_credentials* creds =
       grpc_fake_transport_security_credentials_create();
   grpc_channel* chan =
diff --git a/test/core/surface/sequential_connectivity_test.cc b/test/core/surface/sequential_connectivity_test.cc
index ac49bd9..9aba4c4 100644
--- a/test/core/surface/sequential_connectivity_test.cc
+++ b/test/core/surface/sequential_connectivity_test.cc
@@ -19,11 +19,11 @@
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
-#include <grpc/support/thd.h>
 
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/host_port.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "test/core/end2end/data/ssl_test_data.h"
 #include "test/core/util/port.h"
@@ -67,10 +67,8 @@
   grpc_server_start(server);
 
   server_thread_args sta = {server, server_cq};
-  gpr_thd_id server_thread;
-  gpr_thd_options thdopt = gpr_thd_options_default();
-  gpr_thd_options_set_joinable(&thdopt);
-  gpr_thd_new(&server_thread, "grpc_server", server_thread_func, &sta, &thdopt);
+  grpc_core::Thread server_thread("grpc_server", server_thread_func, &sta);
+  server_thread.Start();
 
   grpc_completion_queue* cq = grpc_completion_queue_create_for_next(nullptr);
   grpc_channel* channels[NUM_CONNECTIONS];
@@ -95,7 +93,7 @@
   }
 
   grpc_server_shutdown_and_notify(server, server_cq, nullptr);
-  gpr_thd_join(server_thread);
+  server_thread.Join();
 
   grpc_completion_queue_shutdown(server_cq);
   grpc_completion_queue_shutdown(cq);
diff --git a/test/core/surface/server_chttp2_test.cc b/test/core/surface/server_chttp2_test.cc
index 96eaa6a..f0412d0 100644
--- a/test/core/surface/server_chttp2_test.cc
+++ b/test/core/surface/server_chttp2_test.cc
@@ -19,9 +19,10 @@
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
+
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/security/credentials/credentials.h"
 #include "src/core/lib/security/credentials/fake/fake_credentials.h"
 #include "src/core/tsi/fake_transport_security.h"
diff --git a/test/core/surface/server_test.cc b/test/core/surface/server_test.cc
index 969b8cb..3b08efb 100644
--- a/test/core/surface/server_test.cc
+++ b/test/core/surface/server_test.cc
@@ -19,9 +19,10 @@
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
+
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/security/credentials/fake/fake_credentials.h"
 #include "test/core/util/port.h"
diff --git a/test/core/transport/BUILD b/test/core/transport/BUILD
index b31d4ff..84fb3a1 100644
--- a/test/core/transport/BUILD
+++ b/test/core/transport/BUILD
@@ -43,6 +43,9 @@
         "//test/core/util:gpr_test_util",
         "//test/core/util:grpc_test_util",
     ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
 grpc_cc_test(
@@ -119,3 +122,15 @@
         "//test/core/util:grpc_test_util",
     ],
 )
+
+grpc_cc_test(
+    name = "status_metadata_test",
+    srcs = ["status_metadata_test.cc"],
+    language = "C++",
+    deps = [
+        "//:grpc",
+    ],
+    external_deps = [
+        "gtest",
+    ],
+)
diff --git a/test/core/transport/bdp_estimator_test.cc b/test/core/transport/bdp_estimator_test.cc
index 3afcad7..c7e6b2b 100644
--- a/test/core/transport/bdp_estimator_test.cc
+++ b/test/core/transport/bdp_estimator_test.cc
@@ -22,10 +22,12 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
+
 #include <gtest/gtest.h>
 #include <limits.h>
+
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/timer_manager.h"
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/transport/byte_stream_test.cc b/test/core/transport/byte_stream_test.cc
index 2aab6e9..df09637 100644
--- a/test/core/transport/byte_stream_test.cc
+++ b/test/core/transport/byte_stream_test.cc
@@ -21,22 +21,25 @@
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
 
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/slice/slice_internal.h"
 
 #include "test/core/util/test_config.h"
 
+#include <gtest/gtest.h>
+
+namespace grpc_core {
+namespace {
+
 //
-// grpc_slice_buffer_stream tests
+// SliceBufferByteStream tests
 //
 
-static void not_called_closure(void* arg, grpc_error* error) {
-  GPR_ASSERT(false);
-}
+void NotCalledClosure(void* arg, grpc_error* error) { GPR_ASSERT(false); }
 
-static void test_slice_buffer_stream_basic(void) {
-  gpr_log(GPR_DEBUG, "test_slice_buffer_stream_basic");
+TEST(SliceBufferByteStream, Basic) {
   grpc_core::ExecCtx exec_ctx;
   // Create and populate slice buffer.
   grpc_slice_buffer buffer;
@@ -49,28 +52,26 @@
     grpc_slice_buffer_add(&buffer, input[i]);
   }
   // Create byte stream.
-  grpc_slice_buffer_stream stream;
-  grpc_slice_buffer_stream_init(&stream, &buffer, 0);
-  GPR_ASSERT(stream.base.length == 6);
+  SliceBufferByteStream stream(&buffer, 0);
+  grpc_slice_buffer_destroy_internal(&buffer);
+  EXPECT_EQ(6U, stream.length());
   grpc_closure closure;
-  GRPC_CLOSURE_INIT(&closure, not_called_closure, nullptr,
+  GRPC_CLOSURE_INIT(&closure, NotCalledClosure, nullptr,
                     grpc_schedule_on_exec_ctx);
-  // Read each slice.  Note that next() always returns synchronously.
+  // Read each slice.  Note that Next() always returns synchronously.
   for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) {
-    GPR_ASSERT(grpc_byte_stream_next(&stream.base, ~(size_t)0, &closure));
+    ASSERT_TRUE(stream.Next(~(size_t)0, &closure));
     grpc_slice output;
-    grpc_error* error = grpc_byte_stream_pull(&stream.base, &output);
-    GPR_ASSERT(error == GRPC_ERROR_NONE);
-    GPR_ASSERT(grpc_slice_eq(input[i], output));
+    grpc_error* error = stream.Pull(&output);
+    EXPECT_TRUE(error == GRPC_ERROR_NONE);
+    EXPECT_TRUE(grpc_slice_eq(input[i], output));
     grpc_slice_unref_internal(output);
   }
   // Clean up.
-  grpc_byte_stream_destroy(&stream.base);
-  grpc_slice_buffer_destroy_internal(&buffer);
+  stream.Orphan();
 }
 
-static void test_slice_buffer_stream_shutdown(void) {
-  gpr_log(GPR_DEBUG, "test_slice_buffer_stream_shutdown");
+TEST(SliceBufferByteStream, Shutdown) {
   grpc_core::ExecCtx exec_ctx;
   // Create and populate slice buffer.
   grpc_slice_buffer buffer;
@@ -83,40 +84,38 @@
     grpc_slice_buffer_add(&buffer, input[i]);
   }
   // Create byte stream.
-  grpc_slice_buffer_stream stream;
-  grpc_slice_buffer_stream_init(&stream, &buffer, 0);
-  GPR_ASSERT(stream.base.length == 6);
+  SliceBufferByteStream stream(&buffer, 0);
+  grpc_slice_buffer_destroy_internal(&buffer);
+  EXPECT_EQ(6U, stream.length());
   grpc_closure closure;
-  GRPC_CLOSURE_INIT(&closure, not_called_closure, nullptr,
+  GRPC_CLOSURE_INIT(&closure, NotCalledClosure, nullptr,
                     grpc_schedule_on_exec_ctx);
   // Read the first slice.
-  GPR_ASSERT(grpc_byte_stream_next(&stream.base, ~(size_t)0, &closure));
+  ASSERT_TRUE(stream.Next(~(size_t)0, &closure));
   grpc_slice output;
-  grpc_error* error = grpc_byte_stream_pull(&stream.base, &output);
-  GPR_ASSERT(error == GRPC_ERROR_NONE);
-  GPR_ASSERT(grpc_slice_eq(input[0], output));
+  grpc_error* error = stream.Pull(&output);
+  EXPECT_TRUE(error == GRPC_ERROR_NONE);
+  EXPECT_TRUE(grpc_slice_eq(input[0], output));
   grpc_slice_unref_internal(output);
   // Now shutdown.
   grpc_error* shutdown_error =
       GRPC_ERROR_CREATE_FROM_STATIC_STRING("shutdown error");
-  grpc_byte_stream_shutdown(&stream.base, GRPC_ERROR_REF(shutdown_error));
+  stream.Shutdown(GRPC_ERROR_REF(shutdown_error));
   // After shutdown, the next pull() should return the error.
-  GPR_ASSERT(grpc_byte_stream_next(&stream.base, ~(size_t)0, &closure));
-  error = grpc_byte_stream_pull(&stream.base, &output);
-  GPR_ASSERT(error == shutdown_error);
+  ASSERT_TRUE(stream.Next(~(size_t)0, &closure));
+  error = stream.Pull(&output);
+  EXPECT_TRUE(error == shutdown_error);
   GRPC_ERROR_UNREF(error);
   GRPC_ERROR_UNREF(shutdown_error);
   // Clean up.
-  grpc_byte_stream_destroy(&stream.base);
-  grpc_slice_buffer_destroy_internal(&buffer);
+  stream.Orphan();
 }
 
 //
-// grpc_caching_byte_stream tests
+// CachingByteStream tests
 //
 
-static void test_caching_byte_stream_basic(void) {
-  gpr_log(GPR_DEBUG, "test_caching_byte_stream_basic");
+TEST(CachingByteStream, Basic) {
   grpc_core::ExecCtx exec_ctx;
   // Create and populate slice buffer byte stream.
   grpc_slice_buffer buffer;
@@ -128,34 +127,30 @@
   for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) {
     grpc_slice_buffer_add(&buffer, input[i]);
   }
-  grpc_slice_buffer_stream underlying_stream;
-  grpc_slice_buffer_stream_init(&underlying_stream, &buffer, 0);
+  SliceBufferByteStream underlying_stream(&buffer, 0);
+  grpc_slice_buffer_destroy_internal(&buffer);
   // Create cache and caching stream.
-  grpc_byte_stream_cache cache;
-  grpc_byte_stream_cache_init(&cache, &underlying_stream.base);
-  grpc_caching_byte_stream stream;
-  grpc_caching_byte_stream_init(&stream, &cache);
+  ByteStreamCache cache((OrphanablePtr<ByteStream>(&underlying_stream)));
+  ByteStreamCache::CachingByteStream stream(&cache);
   grpc_closure closure;
-  GRPC_CLOSURE_INIT(&closure, not_called_closure, nullptr,
+  GRPC_CLOSURE_INIT(&closure, NotCalledClosure, nullptr,
                     grpc_schedule_on_exec_ctx);
   // Read each slice.  Note that next() always returns synchronously,
   // because the underlying byte stream always does.
   for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) {
-    GPR_ASSERT(grpc_byte_stream_next(&stream.base, ~(size_t)0, &closure));
+    ASSERT_TRUE(stream.Next(~(size_t)0, &closure));
     grpc_slice output;
-    grpc_error* error = grpc_byte_stream_pull(&stream.base, &output);
-    GPR_ASSERT(error == GRPC_ERROR_NONE);
-    GPR_ASSERT(grpc_slice_eq(input[i], output));
+    grpc_error* error = stream.Pull(&output);
+    EXPECT_TRUE(error == GRPC_ERROR_NONE);
+    EXPECT_TRUE(grpc_slice_eq(input[i], output));
     grpc_slice_unref_internal(output);
   }
   // Clean up.
-  grpc_byte_stream_destroy(&stream.base);
-  grpc_byte_stream_cache_destroy(&cache);
-  grpc_slice_buffer_destroy_internal(&buffer);
+  stream.Orphan();
+  cache.Destroy();
 }
 
-static void test_caching_byte_stream_reset(void) {
-  gpr_log(GPR_DEBUG, "test_caching_byte_stream_reset");
+TEST(CachingByteStream, Reset) {
   grpc_core::ExecCtx exec_ctx;
   // Create and populate slice buffer byte stream.
   grpc_slice_buffer buffer;
@@ -167,41 +162,37 @@
   for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) {
     grpc_slice_buffer_add(&buffer, input[i]);
   }
-  grpc_slice_buffer_stream underlying_stream;
-  grpc_slice_buffer_stream_init(&underlying_stream, &buffer, 0);
+  SliceBufferByteStream underlying_stream(&buffer, 0);
+  grpc_slice_buffer_destroy_internal(&buffer);
   // Create cache and caching stream.
-  grpc_byte_stream_cache cache;
-  grpc_byte_stream_cache_init(&cache, &underlying_stream.base);
-  grpc_caching_byte_stream stream;
-  grpc_caching_byte_stream_init(&stream, &cache);
+  ByteStreamCache cache((OrphanablePtr<ByteStream>(&underlying_stream)));
+  ByteStreamCache::CachingByteStream stream(&cache);
   grpc_closure closure;
-  GRPC_CLOSURE_INIT(&closure, not_called_closure, nullptr,
+  GRPC_CLOSURE_INIT(&closure, NotCalledClosure, nullptr,
                     grpc_schedule_on_exec_ctx);
   // Read one slice.
-  GPR_ASSERT(grpc_byte_stream_next(&stream.base, ~(size_t)0, &closure));
+  ASSERT_TRUE(stream.Next(~(size_t)0, &closure));
   grpc_slice output;
-  grpc_error* error = grpc_byte_stream_pull(&stream.base, &output);
-  GPR_ASSERT(error == GRPC_ERROR_NONE);
-  GPR_ASSERT(grpc_slice_eq(input[0], output));
+  grpc_error* error = stream.Pull(&output);
+  EXPECT_TRUE(error == GRPC_ERROR_NONE);
+  EXPECT_TRUE(grpc_slice_eq(input[0], output));
   grpc_slice_unref_internal(output);
   // Reset the caching stream.  The reads should start over from the
   // first slice.
-  grpc_caching_byte_stream_reset(&stream);
+  stream.Reset();
   for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) {
-    GPR_ASSERT(grpc_byte_stream_next(&stream.base, ~(size_t)0, &closure));
-    error = grpc_byte_stream_pull(&stream.base, &output);
-    GPR_ASSERT(error == GRPC_ERROR_NONE);
-    GPR_ASSERT(grpc_slice_eq(input[i], output));
+    ASSERT_TRUE(stream.Next(~(size_t)0, &closure));
+    error = stream.Pull(&output);
+    EXPECT_TRUE(error == GRPC_ERROR_NONE);
+    EXPECT_TRUE(grpc_slice_eq(input[i], output));
     grpc_slice_unref_internal(output);
   }
   // Clean up.
-  grpc_byte_stream_destroy(&stream.base);
-  grpc_byte_stream_cache_destroy(&cache);
-  grpc_slice_buffer_destroy_internal(&buffer);
+  stream.Orphan();
+  cache.Destroy();
 }
 
-static void test_caching_byte_stream_shared_cache(void) {
-  gpr_log(GPR_DEBUG, "test_caching_byte_stream_shared_cache");
+TEST(CachingByteStream, SharedCache) {
   grpc_core::ExecCtx exec_ctx;
   // Create and populate slice buffer byte stream.
   grpc_slice_buffer buffer;
@@ -213,54 +204,50 @@
   for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) {
     grpc_slice_buffer_add(&buffer, input[i]);
   }
-  grpc_slice_buffer_stream underlying_stream;
-  grpc_slice_buffer_stream_init(&underlying_stream, &buffer, 0);
+  SliceBufferByteStream underlying_stream(&buffer, 0);
+  grpc_slice_buffer_destroy_internal(&buffer);
   // Create cache and two caching streams.
-  grpc_byte_stream_cache cache;
-  grpc_byte_stream_cache_init(&cache, &underlying_stream.base);
-  grpc_caching_byte_stream stream1;
-  grpc_caching_byte_stream_init(&stream1, &cache);
-  grpc_caching_byte_stream stream2;
-  grpc_caching_byte_stream_init(&stream2, &cache);
+  ByteStreamCache cache((OrphanablePtr<ByteStream>(&underlying_stream)));
+  ByteStreamCache::CachingByteStream stream1(&cache);
+  ByteStreamCache::CachingByteStream stream2(&cache);
   grpc_closure closure;
-  GRPC_CLOSURE_INIT(&closure, not_called_closure, nullptr,
+  GRPC_CLOSURE_INIT(&closure, NotCalledClosure, nullptr,
                     grpc_schedule_on_exec_ctx);
   // Read one slice from stream1.
-  GPR_ASSERT(grpc_byte_stream_next(&stream1.base, ~(size_t)0, &closure));
+  EXPECT_TRUE(stream1.Next(~(size_t)0, &closure));
   grpc_slice output;
-  grpc_error* error = grpc_byte_stream_pull(&stream1.base, &output);
-  GPR_ASSERT(error == GRPC_ERROR_NONE);
-  GPR_ASSERT(grpc_slice_eq(input[0], output));
+  grpc_error* error = stream1.Pull(&output);
+  EXPECT_TRUE(error == GRPC_ERROR_NONE);
+  EXPECT_TRUE(grpc_slice_eq(input[0], output));
   grpc_slice_unref_internal(output);
   // Read all slices from stream2.
   for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) {
-    GPR_ASSERT(grpc_byte_stream_next(&stream2.base, ~(size_t)0, &closure));
-    error = grpc_byte_stream_pull(&stream2.base, &output);
-    GPR_ASSERT(error == GRPC_ERROR_NONE);
-    GPR_ASSERT(grpc_slice_eq(input[i], output));
+    EXPECT_TRUE(stream2.Next(~(size_t)0, &closure));
+    error = stream2.Pull(&output);
+    EXPECT_TRUE(error == GRPC_ERROR_NONE);
+    EXPECT_TRUE(grpc_slice_eq(input[i], output));
     grpc_slice_unref_internal(output);
   }
   // Now read the second slice from stream1.
-  GPR_ASSERT(grpc_byte_stream_next(&stream1.base, ~(size_t)0, &closure));
-  error = grpc_byte_stream_pull(&stream1.base, &output);
-  GPR_ASSERT(error == GRPC_ERROR_NONE);
-  GPR_ASSERT(grpc_slice_eq(input[1], output));
+  EXPECT_TRUE(stream1.Next(~(size_t)0, &closure));
+  error = stream1.Pull(&output);
+  EXPECT_TRUE(error == GRPC_ERROR_NONE);
+  EXPECT_TRUE(grpc_slice_eq(input[1], output));
   grpc_slice_unref_internal(output);
   // Clean up.
-  grpc_byte_stream_destroy(&stream1.base);
-  grpc_byte_stream_destroy(&stream2.base);
-  grpc_byte_stream_cache_destroy(&cache);
-  grpc_slice_buffer_destroy_internal(&buffer);
+  stream1.Orphan();
+  stream2.Orphan();
+  cache.Destroy();
 }
 
+}  // namespace
+}  // namespace grpc_core
+
 int main(int argc, char** argv) {
   grpc_init();
   grpc_test_init(argc, argv);
-  test_slice_buffer_stream_basic();
-  test_slice_buffer_stream_shutdown();
-  test_caching_byte_stream_basic();
-  test_caching_byte_stream_reset();
-  test_caching_byte_stream_shared_cache();
+  ::testing::InitGoogleTest(&argc, argv);
+  int retval = RUN_ALL_TESTS();
   grpc_shutdown();
-  return 0;
+  return retval;
 }
diff --git a/test/core/transport/chttp2/bin_decoder_test.cc b/test/core/transport/chttp2/bin_decoder_test.cc
index 283eebb..b4b0798 100644
--- a/test/core/transport/chttp2/bin_decoder_test.cc
+++ b/test/core/transport/chttp2/bin_decoder_test.cc
@@ -25,6 +25,7 @@
 #include <grpc/support/log.h>
 #include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 
@@ -67,6 +68,16 @@
   return out;
 }
 
+static size_t base64_infer_length(const char* s) {
+  grpc_slice ss = grpc_slice_from_copied_string(s);
+  size_t out = grpc_chttp2_base64_infer_length_after_decode(ss);
+  grpc_slice_unref_internal(ss);
+  return out;
+}
+
+#define EXPECT_DECODED_LENGTH(s, expected) \
+  GPR_ASSERT((expected) == base64_infer_length((s)));
+
 #define EXPECT_SLICE_EQ(expected, slice)                                    \
   expect_slice_eq(                                                          \
       grpc_slice_from_copied_buffer(expected, sizeof(expected) - 1), slice, \
@@ -131,6 +142,26 @@
     // Test illegal charactors in grpc_chttp2_base64_decode_with_length
     EXPECT_SLICE_EQ("", base64_decode_with_length("Zm:v", 3));
     EXPECT_SLICE_EQ("", base64_decode_with_length("Zm=v", 3));
+
+    EXPECT_DECODED_LENGTH("", 0);
+    EXPECT_DECODED_LENGTH("ab", 1);
+    EXPECT_DECODED_LENGTH("abc", 2);
+    EXPECT_DECODED_LENGTH("abcd", 3);
+    EXPECT_DECODED_LENGTH("abcdef", 4);
+    EXPECT_DECODED_LENGTH("abcdefg", 5);
+    EXPECT_DECODED_LENGTH("abcdefgh", 6);
+
+    EXPECT_DECODED_LENGTH("ab==", 1);
+    EXPECT_DECODED_LENGTH("abc=", 2);
+    EXPECT_DECODED_LENGTH("abcd", 3);
+    EXPECT_DECODED_LENGTH("abcdef==", 4);
+    EXPECT_DECODED_LENGTH("abcdefg=", 5);
+    EXPECT_DECODED_LENGTH("abcdefgh", 6);
+
+    EXPECT_DECODED_LENGTH("a", 0);
+    EXPECT_DECODED_LENGTH("a===", 0);
+    EXPECT_DECODED_LENGTH("abcde", 0);
+    EXPECT_DECODED_LENGTH("abcde===", 0);
   }
   grpc_shutdown();
   return all_ok ? 0 : 1;
diff --git a/test/core/transport/chttp2/hpack_encoder_test.cc b/test/core/transport/chttp2/hpack_encoder_test.cc
index a40bd64..d3ba50a 100644
--- a/test/core/transport/chttp2/hpack_encoder_test.cc
+++ b/test/core/transport/chttp2/hpack_encoder_test.cc
@@ -152,10 +152,10 @@
 }
 
 static void encode_int_to_str(int i, char* p) {
-  p[0] = (char)('a' + i % 26);
+  p[0] = static_cast<char>('a' + i % 26);
   i /= 26;
   GPR_ASSERT(i < 26);
-  p[1] = (char)('a' + i);
+  p[1] = static_cast<char>('a' + i);
   p[2] = 0;
 }
 
diff --git a/test/core/transport/chttp2/hpack_parser_fuzzer_test.cc b/test/core/transport/chttp2/hpack_parser_fuzzer_test.cc
index 9a195da..a8eec1e 100644
--- a/test/core/transport/chttp2/hpack_parser_fuzzer_test.cc
+++ b/test/core/transport/chttp2/hpack_parser_fuzzer_test.cc
@@ -24,6 +24,7 @@
 #include <grpc/support/log.h>
 
 #include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/slice/slice_internal.h"
 
 bool squelch = true;
diff --git a/test/core/transport/chttp2/hpack_parser_test.cc b/test/core/transport/chttp2/hpack_parser_test.cc
index 9d3456a..43b6c79 100644
--- a/test/core/transport/chttp2/hpack_parser_test.cc
+++ b/test/core/transport/chttp2/hpack_parser_test.cc
@@ -24,6 +24,8 @@
 #include <grpc/slice.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "test/core/util/parse_hexstring.h"
 #include "test/core/util/slice_splitter.h"
 #include "test/core/util/test_config.h"
diff --git a/test/core/transport/chttp2/hpack_table_test.cc b/test/core/transport/chttp2/hpack_table_test.cc
index e316cf6..3ab463b 100644
--- a/test/core/transport/chttp2/hpack_table_test.cc
+++ b/test/core/transport/chttp2/hpack_table_test.cc
@@ -27,6 +27,7 @@
 #include <grpc/support/string_util.h>
 
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "test/core/util/test_config.h"
 
 #define LOG_TEST(x) gpr_log(GPR_INFO, "%s", x)
diff --git a/test/core/transport/chttp2/settings_timeout_test.cc b/test/core/transport/chttp2/settings_timeout_test.cc
index 7fb395d..39ae587 100644
--- a/test/core/transport/chttp2/settings_timeout_test.cc
+++ b/test/core/transport/chttp2/settings_timeout_test.cc
@@ -104,7 +104,7 @@
         grpc_blocking_resolve_address(server_address_, "80", &server_addresses);
     ASSERT_EQ(GRPC_ERROR_NONE, error) << grpc_error_string(error);
     ASSERT_GE(server_addresses->naddrs, 1UL);
-    pollset_ = (grpc_pollset*)gpr_zalloc(grpc_pollset_size());
+    pollset_ = static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
     grpc_pollset_init(pollset_, &mu_);
     grpc_pollset_set* pollset_set = grpc_pollset_set_create();
     grpc_pollset_set_add_pollset(pollset_set, pollset_);
@@ -177,7 +177,7 @@
    private:
     static void OnEventDone(void* arg, grpc_error* error) {
       gpr_log(GPR_INFO, "OnEventDone(): %s", grpc_error_string(error));
-      EventState* state = (EventState*)arg;
+      EventState* state = static_cast<EventState*>(arg);
       state->error_ = GRPC_ERROR_REF(error);
       gpr_atm_rel_store(&state->done_atm_, 1);
     }
@@ -203,7 +203,7 @@
   }
 
   static void PollsetDestroy(void* arg, grpc_error* error) {
-    grpc_pollset* pollset = (grpc_pollset*)arg;
+    grpc_pollset* pollset = static_cast<grpc_pollset*>(arg);
     grpc_pollset_destroy(pollset);
     gpr_free(pollset);
   }
diff --git a/test/core/transport/chttp2/stream_map_test.cc b/test/core/transport/chttp2/stream_map_test.cc
index 9b21cb2..773eb3a 100644
--- a/test/core/transport/chttp2/stream_map_test.cc
+++ b/test/core/transport/chttp2/stream_map_test.cc
@@ -78,7 +78,7 @@
   grpc_chttp2_stream_map_init(&map, 8);
   GPR_ASSERT(0 == grpc_chttp2_stream_map_size(&map));
   for (i = 1; i <= n; i++) {
-    grpc_chttp2_stream_map_add(&map, i, (void*)(uintptr_t)i);
+    grpc_chttp2_stream_map_add(&map, i, (void*)static_cast<uintptr_t>(i));
   }
   GPR_ASSERT(n == grpc_chttp2_stream_map_size(&map));
   GPR_ASSERT(nullptr == grpc_chttp2_stream_map_find(&map, 0));
@@ -133,7 +133,7 @@
 
   grpc_chttp2_stream_map_init(&map, 8);
   for (i = 1; i <= n; i++) {
-    grpc_chttp2_stream_map_add(&map, i, (void*)(uintptr_t)i);
+    grpc_chttp2_stream_map_add(&map, i, (void*)static_cast<uintptr_t>(i));
   }
   for (i = 1; i <= n; i++) {
     if ((i & 1) == 0) {
@@ -155,7 +155,7 @@
 
   grpc_chttp2_stream_map_init(&map, 8);
   for (i = 1; i <= n; i++) {
-    grpc_chttp2_stream_map_add(&map, i, (void*)(uintptr_t)i);
+    grpc_chttp2_stream_map_add(&map, i, (void*)static_cast<uintptr_t>(i));
     if ((i & 1) == 0) {
       grpc_chttp2_stream_map_delete(&map, i);
     }
@@ -177,7 +177,7 @@
   grpc_chttp2_stream_map_init(&map, 16);
   GPR_ASSERT(map.capacity == 16);
   for (i = 1; i <= n; i++) {
-    grpc_chttp2_stream_map_add(&map, i, (void*)(uintptr_t)i);
+    grpc_chttp2_stream_map_add(&map, i, (void*)static_cast<uintptr_t>(i));
     if (i > 8) {
       del = i - 8;
       GPR_ASSERT((void*)(uintptr_t)del ==
diff --git a/test/core/transport/connectivity_state_test.cc b/test/core/transport/connectivity_state_test.cc
index f589459..cbd6318 100644
--- a/test/core/transport/connectivity_state_test.cc
+++ b/test/core/transport/connectivity_state_test.cc
@@ -22,6 +22,7 @@
 
 #include <grpc/support/log.h>
 
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "test/core/util/test_config.h"
 #include "test/core/util/tracer_util.h"
 
diff --git a/test/core/transport/metadata_test.cc b/test/core/transport/metadata_test.cc
index 7d943fd..4be34f7 100644
--- a/test/core/transport/metadata_test.cc
+++ b/test/core/transport/metadata_test.cc
@@ -28,6 +28,7 @@
 
 #include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/transport/static_metadata.h"
 #include "test/core/util/test_config.h"
@@ -240,8 +241,8 @@
   }
 
   for (i = 0; i < nstrs; i++) {
-    size_t p = (size_t)rand() % nstrs;
-    size_t q = (size_t)rand() % nstrs;
+    size_t p = static_cast<size_t>(rand()) % nstrs;
+    size_t q = static_cast<size_t>(rand()) % nstrs;
     size_t temp = shuf[p];
     shuf[p] = shuf[q];
     shuf[q] = temp;
@@ -307,8 +308,8 @@
                    intern_value));
   GPR_ASSERT(grpc_is_binary_header(GRPC_MDKEY(elem)));
   size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem, false);
-  grpc_slice value_slice =
-      grpc_slice_from_copied_buffer((const char*)value, value_len);
+  grpc_slice value_slice = grpc_slice_from_copied_buffer(
+      reinterpret_cast<const char*>(value), value_len);
   grpc_slice base64_encoded = grpc_chttp2_base64_encode(value_slice);
   size_t expected_size = 32 + strlen(key) + GRPC_SLICE_LENGTH(base64_encoded);
   GPR_ASSERT(expected_size == elem_size);
diff --git a/test/core/transport/pid_controller_test.cc b/test/core/transport/pid_controller_test.cc
index 1a499c2..8d2cec4 100644
--- a/test/core/transport/pid_controller_test.cc
+++ b/test/core/transport/pid_controller_test.cc
@@ -24,7 +24,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
+
 #include <gtest/gtest.h>
 #include "src/core/lib/gpr/string.h"
 #include "test/core/util/test_config.h"
diff --git a/test/core/transport/status_metadata_test.cc b/test/core/transport/status_metadata_test.cc
new file mode 100644
index 0000000..a96f11c
--- /dev/null
+++ b/test/core/transport/status_metadata_test.cc
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/core/lib/transport/status_metadata.h"
+
+#include <gtest/gtest.h>
+
+#include "src/core/lib/transport/static_metadata.h"
+
+namespace {
+
+TEST(GetStatusCodeFromMetadata, OK) {
+  EXPECT_EQ(GRPC_STATUS_OK,
+            grpc_get_status_code_from_metadata(GRPC_MDELEM_GRPC_STATUS_0));
+}
+
+TEST(GetStatusCodeFromMetadata, CANCELLED) {
+  EXPECT_EQ(GRPC_STATUS_CANCELLED,
+            grpc_get_status_code_from_metadata(GRPC_MDELEM_GRPC_STATUS_1));
+}
+
+TEST(GetStatusCodeFromMetadata, UNKNOWN) {
+  EXPECT_EQ(GRPC_STATUS_UNKNOWN,
+            grpc_get_status_code_from_metadata(GRPC_MDELEM_GRPC_STATUS_2));
+}
+
+TEST(GetStatusCodeFromMetadata, Other) {
+  grpc_mdelem status_md = grpc_mdelem_from_slices(
+      GRPC_MDSTR_GRPC_STATUS, grpc_slice_from_static_string("10"));
+  EXPECT_EQ(GRPC_STATUS_ABORTED, grpc_get_status_code_from_metadata(status_md));
+  GRPC_MDELEM_UNREF(status_md);
+}
+
+TEST(GetStatusCodeFromMetadata, Unparseable) {
+  grpc_mdelem status_md = grpc_mdelem_from_slices(
+      GRPC_MDSTR_GRPC_STATUS, grpc_slice_from_static_string("NaN"));
+  EXPECT_EQ(GRPC_STATUS_UNKNOWN, grpc_get_status_code_from_metadata(status_md));
+  GRPC_MDELEM_UNREF(status_md);
+}
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/test/core/transport/timeout_encoding_test.cc b/test/core/transport/timeout_encoding_test.cc
index e94be13..2367acc 100644
--- a/test/core/transport/timeout_encoding_test.cc
+++ b/test/core/transport/timeout_encoding_test.cc
@@ -24,9 +24,10 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
+
 #include "src/core/lib/gpr/murmur_hash.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
 #include "test/core/util/test_config.h"
 
 #define LOG_TEST(x) gpr_log(GPR_INFO, "%s", x)
@@ -102,20 +103,22 @@
 }
 
 static grpc_millis millis_from_nanos(int64_t x) {
-  return (grpc_millis)(x / GPR_NS_PER_MS + (x % GPR_NS_PER_MS != 0));
+  return static_cast<grpc_millis>(x / GPR_NS_PER_MS + (x % GPR_NS_PER_MS != 0));
 }
 static grpc_millis millis_from_micros(int64_t x) {
-  return (grpc_millis)(x / GPR_US_PER_MS + (x % GPR_US_PER_MS != 0));
+  return static_cast<grpc_millis>(x / GPR_US_PER_MS + (x % GPR_US_PER_MS != 0));
 }
-static grpc_millis millis_from_millis(int64_t x) { return (grpc_millis)x; }
+static grpc_millis millis_from_millis(int64_t x) {
+  return static_cast<grpc_millis>(x);
+}
 static grpc_millis millis_from_seconds(int64_t x) {
-  return (grpc_millis)(x * GPR_MS_PER_SEC);
+  return static_cast<grpc_millis>(x * GPR_MS_PER_SEC);
 }
 static grpc_millis millis_from_minutes(int64_t x) {
-  return (grpc_millis)(x * 60 * GPR_MS_PER_SEC);
+  return static_cast<grpc_millis>(x * 60 * GPR_MS_PER_SEC);
 }
 static grpc_millis millis_from_hours(int64_t x) {
-  return (grpc_millis)(x * 3600 * GPR_MS_PER_SEC);
+  return static_cast<grpc_millis>(x * 3600 * GPR_MS_PER_SEC);
 }
 
 void test_decoding(void) {
diff --git a/test/core/tsi/BUILD b/test/core/tsi/BUILD
index e28c0b5..ae6e8fd 100644
--- a/test/core/tsi/BUILD
+++ b/test/core/tsi/BUILD
@@ -16,7 +16,7 @@
 
 licenses(["notice"])  # Apache v2
 
-grpc_package(name = "test/core/tsi")
+grpc_package(name = "test/core/tsi", visibility = "public")
 
 grpc_cc_library(
     name = "transport_security_test_lib",
@@ -41,6 +41,20 @@
     ],
 )
 
+grpc_cc_test(
+    name = "ssl_session_cache_test",
+    srcs = ["ssl_session_cache_test.cc"],
+    language = "C++",
+    external_deps = [
+        "gtest",
+    ],
+    deps = [
+        "//:grpc",
+        "//:gpr",
+        "//:tsi",
+        "//test/core/util:gpr_test_util",
+    ],
+)
 
 grpc_cc_test(
     name = "ssl_transport_security_test",
diff --git a/test/core/tsi/alts/crypt/BUILD b/test/core/tsi/alts/crypt/BUILD
new file mode 100644
index 0000000..b2fcb65
--- /dev/null
+++ b/test/core/tsi/alts/crypt/BUILD
@@ -0,0 +1,42 @@
+# Copyright 2018 gRPC authors.
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_package")
+
+licenses(["notice"])  # Apache v2
+
+grpc_package(name = "crypt", visibility = "public")
+
+grpc_cc_test(
+    name = "alts_crypt_test",
+    srcs = ["aes_gcm_test.cc"],
+    language = "C++",
+    deps = [
+        ":alts_crypt_test_util",
+        "//:alts_frame_protector",
+        "//:gpr",
+        "//:grpc",
+    ],
+)
+
+grpc_cc_library(
+    name = "alts_crypt_test_util",
+    srcs = ["gsec_test_util.cc"],
+    hdrs = ["gsec_test_util.h"],
+    deps = [
+        "//:gpr",
+        "//:grpc",
+    ],
+)
+
diff --git a/test/core/tsi/alts/crypt/aes_gcm_test.cc b/test/core/tsi/alts/crypt/aes_gcm_test.cc
new file mode 100644
index 0000000..576dd8f
--- /dev/null
+++ b/test/core/tsi/alts/crypt/aes_gcm_test.cc
@@ -0,0 +1,2105 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/core/tsi/alts/crypt/gsec.h"
+#include "test/core/tsi/alts/crypt/gsec_test_util.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+const size_t kTestMinTagLengthForCorruption = 8;
+const size_t kTestNumCrypters = 3;
+const size_t kTestMaxSlices = 5;
+const size_t kTestMaxLength = 1024;
+const size_t kTestNumEncryptions = 100;
+
+/* Struct for pre-generated test vector */
+typedef struct gsec_aead_test_vector {
+  uint8_t* nonce;
+  uint8_t* aad;
+  uint8_t* key;
+  uint8_t* plaintext;
+  uint8_t* ciphertext_and_tag;
+  size_t nonce_length;
+  size_t aad_length;
+  size_t key_length;
+  size_t plaintext_length;
+  size_t ciphertext_and_tag_length;
+} gsec_aead_test_vector;
+
+static void gsec_randomly_slice(uint8_t* input, size_t input_length,
+                                struct iovec** output, size_t* output_length) {
+  if (input_length == 0) {
+    *output = nullptr;
+    *output_length = 0;
+    return;
+  }
+  *output_length = gsec_test_bias_random_uint32(kTestMaxSlices) + 1;
+  *output =
+      static_cast<struct iovec*>(malloc(*output_length * sizeof(**output)));
+  size_t i;
+  for (i = 0; i < *output_length - 1; i++) {
+    size_t slice_length =
+        gsec_test_bias_random_uint32(static_cast<uint32_t>(input_length));
+    struct iovec slice = {input, slice_length};
+    (*output)[i] = slice;
+    input += slice_length;
+    input_length -= slice_length;
+  }
+  struct iovec slice = {input, input_length};
+  (*output)[*output_length - 1] = slice;
+}
+
+static void gsec_assert_ok(grpc_status_code status, const char* error_detail) {
+  char empty_string[] = "";
+  if (error_detail == nullptr) {
+    error_detail = empty_string;
+  }
+  if (status != GRPC_STATUS_OK) {
+    fprintf(stderr, "Status is not ok: %s\n", error_detail);
+  }
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+}
+
+static void gsec_test_random_encrypt_decrypt(gsec_aead_crypter* crypter,
+                                             size_t aad_length,
+                                             size_t message_length) {
+  GPR_ASSERT(crypter != nullptr);
+  size_t nonce_length, tag_length;
+  uint8_t *nonce, *aad, *message;
+  gsec_aead_crypter_nonce_length(crypter, &nonce_length, nullptr);
+  gsec_aead_crypter_tag_length(crypter, &tag_length, nullptr);
+
+  gsec_test_random_array(&nonce, nonce_length);
+  gsec_test_random_array(&aad, aad_length);
+  gsec_test_random_array(&message, message_length);
+
+  /* Test encryption  */
+  size_t ciphertext_and_tag_length, ciphertext_bytes_written = 0;
+  gsec_aead_crypter_max_ciphertext_and_tag_length(
+      crypter, message_length, &ciphertext_and_tag_length, nullptr);
+
+  uint8_t* ciphertext_and_tag =
+      static_cast<uint8_t*>(gpr_malloc(ciphertext_and_tag_length));
+
+  char* error_buffer = nullptr;
+  gsec_assert_ok(
+      gsec_aead_crypter_encrypt(crypter, nonce, nonce_length, aad, aad_length,
+                                message, message_length, ciphertext_and_tag,
+                                ciphertext_and_tag_length,
+                                &ciphertext_bytes_written, &error_buffer),
+      error_buffer);
+  GPR_ASSERT(message_length + tag_length == ciphertext_and_tag_length);
+  GPR_ASSERT(ciphertext_bytes_written == ciphertext_and_tag_length);
+
+  /* Test decryption */
+  size_t plaintext_length, plaintext_bytes_written = 0;
+  gsec_aead_crypter_max_plaintext_length(crypter, ciphertext_bytes_written,
+                                         &plaintext_length, nullptr);
+  uint8_t* plaintext = static_cast<uint8_t*>(gpr_malloc(plaintext_length));
+  grpc_status_code status = gsec_aead_crypter_decrypt(
+      crypter, nonce, nonce_length, aad, aad_length, ciphertext_and_tag,
+      ciphertext_bytes_written, plaintext, plaintext_length,
+      &plaintext_bytes_written, nullptr);
+
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(message_length == plaintext_bytes_written);
+  GPR_ASSERT(memcmp(message, plaintext, message_length) == 0);
+
+  /**
+   * The returned plaintext will be zeroed if there was an authentication error.
+   */
+  uint8_t* zero_message = static_cast<uint8_t*>(gpr_zalloc(plaintext_length));
+  if (tag_length >= kTestMinTagLengthForCorruption) {
+    char* error_message;
+    /* Corrupt nonce */
+    if (nonce_length > 0) {
+      plaintext_bytes_written = 0;
+      uint8_t* corrupt_nonce;
+      gsec_test_copy_and_alter_random_byte(nonce, &corrupt_nonce, nonce_length);
+      status = gsec_aead_crypter_decrypt(
+          crypter, corrupt_nonce, nonce_length, aad, aad_length,
+          ciphertext_and_tag, ciphertext_bytes_written, plaintext,
+          plaintext_length, &plaintext_bytes_written, &error_message);
+
+      GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+          status, GRPC_STATUS_FAILED_PRECONDITION, "Checking tag failed.",
+          error_message));
+      GPR_ASSERT(plaintext_bytes_written == 0);
+      GPR_ASSERT(memcmp(zero_message, plaintext, plaintext_length) == 0);
+      gpr_free(corrupt_nonce);
+      gpr_free(error_message);
+    }
+
+    /* Corrupt ciphertext_and_tag */
+    plaintext_bytes_written = 0;
+    uint8_t* corrupt_ciphertext_and_tag;
+    gsec_test_copy_and_alter_random_byte(ciphertext_and_tag,
+                                         &corrupt_ciphertext_and_tag,
+                                         ciphertext_and_tag_length);
+    status = gsec_aead_crypter_decrypt(
+        crypter, nonce, nonce_length, aad, aad_length,
+        corrupt_ciphertext_and_tag, ciphertext_bytes_written, plaintext,
+        plaintext_length, &plaintext_bytes_written, &error_message);
+
+    GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+        status, GRPC_STATUS_FAILED_PRECONDITION, error_message,
+        "Checking tag failed"));
+    GPR_ASSERT(plaintext_bytes_written == 0);
+    GPR_ASSERT(memcmp(zero_message, plaintext, plaintext_length) == 0);
+    gpr_free(error_message);
+    gpr_free(corrupt_ciphertext_and_tag);
+
+    /* Corrupt start of ciphertext_and_tag */
+    plaintext_bytes_written = 0;
+    gsec_test_copy(ciphertext_and_tag, &corrupt_ciphertext_and_tag,
+                   ciphertext_and_tag_length);
+    (*corrupt_ciphertext_and_tag)++;
+    status = gsec_aead_crypter_decrypt(
+        crypter, nonce, nonce_length, aad, aad_length,
+        corrupt_ciphertext_and_tag, ciphertext_bytes_written, plaintext,
+        plaintext_length, &plaintext_bytes_written, &error_message);
+    GPR_ASSERT(plaintext_bytes_written == 0);
+    GPR_ASSERT(memcmp(zero_message, plaintext, plaintext_length) == 0);
+    GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+        status, GRPC_STATUS_FAILED_PRECONDITION, error_message,
+        "Checking tag failed"));
+    gpr_free(error_message);
+    gpr_free(corrupt_ciphertext_and_tag);
+
+    /* Corrupt end of ciphertext_and_tag */
+    plaintext_bytes_written = 0;
+    gsec_test_copy(ciphertext_and_tag, &corrupt_ciphertext_and_tag,
+                   ciphertext_and_tag_length);
+    (*(corrupt_ciphertext_and_tag + ciphertext_and_tag_length - 1))++;
+
+    status = gsec_aead_crypter_decrypt(
+        crypter, nonce, nonce_length, aad, aad_length,
+        corrupt_ciphertext_and_tag, ciphertext_bytes_written, plaintext,
+        plaintext_length, &plaintext_bytes_written, &error_message);
+
+    GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+        status, GRPC_STATUS_FAILED_PRECONDITION, error_message,
+        "Checking tag failed"));
+    GPR_ASSERT(plaintext_bytes_written == 0);
+    GPR_ASSERT(memcmp(zero_message, plaintext, plaintext_length) == 0);
+    gpr_free(error_message);
+    gpr_free(corrupt_ciphertext_and_tag);
+  }
+
+  gpr_free(zero_message);
+  gpr_free(nonce);
+  gpr_free(aad);
+  gpr_free(message);
+  gpr_free(plaintext);
+  gpr_free(ciphertext_and_tag);
+}
+
+static void gsec_test_encrypt_decrypt(gsec_aead_crypter* crypter) {
+  GPR_ASSERT(crypter != nullptr);
+  size_t aad_length, message_length;
+  aad_length = gsec_test_bias_random_uint32(kTestMaxLength);
+  message_length = gsec_test_bias_random_uint32(kTestMaxLength);
+  gsec_test_random_encrypt_decrypt(crypter, aad_length, message_length);
+  gsec_test_random_encrypt_decrypt(crypter, 0, message_length);
+  gsec_test_random_encrypt_decrypt(crypter, aad_length, 0);
+}
+
+static void gsec_test_multiple_random_encrypt_decrypt(
+    gsec_aead_crypter* crypter, size_t* aad_lengths, size_t* message_lengths,
+    size_t count) {
+  GPR_ASSERT(crypter != nullptr);
+  size_t nonce_length, tag_length;
+  uint8_t **nonces, **aads, **messages;
+  nonces = static_cast<uint8_t**>(gpr_malloc(sizeof(uint8_t*) * count));
+  aads = static_cast<uint8_t**>(gpr_malloc(sizeof(uint8_t*) * count));
+  messages = static_cast<uint8_t**>(gpr_malloc(sizeof(uint8_t*) * count));
+
+  gsec_aead_crypter_nonce_length(crypter, &nonce_length, nullptr);
+  gsec_aead_crypter_tag_length(crypter, &tag_length, nullptr);
+
+  size_t ind;
+  for (ind = 0; ind < count; ind++) {
+    size_t aad_length = (aad_lengths == nullptr) ? 0 : aad_lengths[ind];
+    size_t message_length =
+        (message_lengths == nullptr) ? 0 : message_lengths[ind];
+    gsec_test_random_array(&(nonces[ind]), nonce_length);
+    gsec_test_random_array(&(aads[ind]), aad_length);
+    gsec_test_random_array(&(messages[ind]), message_length);
+  }
+
+  size_t* ciphertext_and_tag_lengths =
+      static_cast<size_t*>(gpr_malloc(sizeof(size_t) * count));
+  size_t* ciphertext_bytes_writtens =
+      static_cast<size_t*>(gpr_malloc(sizeof(size_t) * count));
+  size_t* plaintext_lengths =
+      static_cast<size_t*>(gpr_malloc(sizeof(size_t) * count));
+  size_t* plaintext_bytes_writtens =
+      static_cast<size_t*>(gpr_malloc(sizeof(size_t) * count));
+  uint8_t** ciphertext_and_tags =
+      static_cast<uint8_t**>(gpr_malloc(sizeof(uint8_t*) * count));
+  uint8_t** plaintexts =
+      static_cast<uint8_t**>(gpr_malloc(sizeof(uint8_t*) * count));
+
+  /* Do encryption */
+  for (ind = 0; ind < count; ind++) {
+    size_t aad_length = (aad_lengths == nullptr) ? 0 : aad_lengths[ind];
+    size_t message_length =
+        (message_lengths == nullptr) ? 0 : message_lengths[ind];
+    gsec_aead_crypter_max_ciphertext_and_tag_length(
+        crypter, message_length, &(ciphertext_and_tag_lengths[ind]), nullptr);
+    ciphertext_and_tags[ind] =
+        static_cast<uint8_t*>(gpr_malloc(ciphertext_and_tag_lengths[ind]));
+    grpc_status_code status = gsec_aead_crypter_encrypt(
+        crypter, nonces[ind], nonce_length, aads[ind], aad_length,
+        messages[ind], message_length, ciphertext_and_tags[ind],
+        ciphertext_and_tag_lengths[ind], &(ciphertext_bytes_writtens[ind]),
+        nullptr);
+    GPR_ASSERT(status == GRPC_STATUS_OK);
+    GPR_ASSERT(message_length + tag_length == ciphertext_and_tag_lengths[ind]);
+    GPR_ASSERT(ciphertext_bytes_writtens[ind] ==
+               ciphertext_and_tag_lengths[ind]);
+  }
+  /* Do Decryption */
+  for (ind = 0; ind < count; ind++) {
+    size_t aad_length = (aad_lengths == nullptr) ? 0 : aad_lengths[ind];
+    size_t message_length =
+        (message_lengths == nullptr) ? 0 : message_lengths[ind];
+    gsec_aead_crypter_max_plaintext_length(crypter,
+                                           ciphertext_bytes_writtens[ind],
+                                           &(plaintext_lengths[ind]), nullptr);
+    plaintexts[ind] = static_cast<uint8_t*>(gpr_malloc(plaintext_lengths[ind]));
+    grpc_status_code status = gsec_aead_crypter_decrypt(
+        crypter, nonces[ind], nonce_length, aads[ind], aad_length,
+        ciphertext_and_tags[ind], ciphertext_bytes_writtens[ind],
+        plaintexts[ind], plaintext_lengths[ind],
+        &(plaintext_bytes_writtens[ind]), nullptr);
+    GPR_ASSERT(status == GRPC_STATUS_OK);
+    GPR_ASSERT(message_length == plaintext_bytes_writtens[ind]);
+    GPR_ASSERT(memcmp(messages[ind], plaintexts[ind], message_length) == 0);
+  }
+
+  /* Slice the plaintext and encrypt with iovecs */
+  for (ind = 0; ind < count; ind++) {
+    size_t aad_length = (aad_lengths == nullptr) ? 0 : aad_lengths[ind];
+    struct iovec* aad_vecs = nullptr;
+    size_t aad_vecs_length = 0;
+    gsec_randomly_slice(aads[ind], aad_length, &aad_vecs, &aad_vecs_length);
+    size_t message_length =
+        (message_lengths == nullptr) ? 0 : message_lengths[ind];
+    struct iovec* message_vecs = nullptr;
+    size_t message_vecs_length = 0;
+    gsec_randomly_slice(messages[ind], message_length, &message_vecs,
+                        &message_vecs_length);
+
+    size_t ciphertext_length = ciphertext_and_tag_lengths[ind];
+    uint8_t* another_ciphertext =
+        static_cast<uint8_t*>(malloc(ciphertext_length));
+    struct iovec another_ciphertext_vec = {another_ciphertext,
+                                           ciphertext_length};
+
+    char* error_details = nullptr;
+    size_t ciphertext_bytes_written = 0;
+    gsec_assert_ok(
+        gsec_aead_crypter_encrypt_iovec(
+            crypter, nonces[ind], nonce_length, aad_vecs, aad_vecs_length,
+            message_vecs, message_vecs_length, another_ciphertext_vec,
+            &ciphertext_bytes_written, &error_details),
+        error_details);
+    GPR_ASSERT(memcmp(ciphertext_and_tags[ind], another_ciphertext_vec.iov_base,
+                      ciphertext_length) == 0);
+    free(another_ciphertext);
+    free(aad_vecs);
+    free(message_vecs);
+  }
+
+  /* Slice the ciphertext and decrypt with iovecs */
+  for (ind = 0; ind < count; ind++) {
+    size_t message_length =
+        (message_lengths == nullptr) ? 0 : message_lengths[ind];
+    message_length = message_length + 0;
+
+    size_t aad_length = (aad_lengths == nullptr) ? 0 : aad_lengths[ind];
+
+    struct iovec* aad_vecs = nullptr;
+    size_t aad_vecs_length = 0;
+    gsec_randomly_slice(aads[ind], aad_length, &aad_vecs, &aad_vecs_length);
+
+    struct iovec* ciphertext_vecs = nullptr;
+    size_t ciphertext_vecs_length = 0;
+    gsec_randomly_slice(ciphertext_and_tags[ind],
+                        ciphertext_bytes_writtens[ind], &ciphertext_vecs,
+                        &ciphertext_vecs_length);
+
+    size_t decrypted_length = plaintext_lengths[ind];
+    uint8_t* decrypted = static_cast<uint8_t*>(malloc(decrypted_length));
+    struct iovec decrypted_vec = {decrypted, decrypted_length};
+
+    char* error_details = nullptr;
+    gsec_assert_ok(gsec_aead_crypter_decrypt_iovec(
+                       crypter, nonces[ind], nonce_length, aad_vecs,
+                       aad_vecs_length, ciphertext_vecs, ciphertext_vecs_length,
+                       decrypted_vec, &decrypted_length, &error_details),
+                   error_details);
+    GPR_ASSERT(decrypted_vec.iov_len == message_length);
+    GPR_ASSERT(memcmp(decrypted_vec.iov_base, messages[ind], message_length) ==
+               0);
+    free(decrypted);
+    free(aad_vecs);
+    free(ciphertext_vecs);
+  }
+
+  for (ind = 0; ind < count; ind++) {
+    gpr_free(nonces[ind]);
+    gpr_free(aads[ind]);
+    gpr_free(messages[ind]);
+    gpr_free(ciphertext_and_tags[ind]);
+    gpr_free(plaintexts[ind]);
+  }
+  gpr_free(nonces);
+  gpr_free(aads);
+  gpr_free(messages);
+  gpr_free(ciphertext_and_tag_lengths);
+  gpr_free(ciphertext_bytes_writtens);
+  gpr_free(plaintext_lengths);
+  gpr_free(plaintext_bytes_writtens);
+  gpr_free(ciphertext_and_tags);
+  gpr_free(plaintexts);
+}
+
+static void gsec_test_multiple_encrypt_decrypt(gsec_aead_crypter* crypter) {
+  GPR_ASSERT(crypter != nullptr);
+  size_t count = kTestNumEncryptions;
+  size_t* aad_lengths =
+      static_cast<size_t*>(gpr_malloc(sizeof(size_t) * count));
+  size_t* message_lengths =
+      static_cast<size_t*>(gpr_malloc(sizeof(size_t) * count));
+  size_t ind;
+  for (ind = 0; ind < count; ind++) {
+    aad_lengths[ind] = gsec_test_bias_random_uint32(kTestMaxLength);
+    message_lengths[ind] = gsec_test_bias_random_uint32(kTestMaxLength);
+  }
+  gsec_test_multiple_random_encrypt_decrypt(crypter, aad_lengths,
+                                            message_lengths, count);
+  gsec_test_multiple_random_encrypt_decrypt(crypter, aad_lengths, nullptr,
+                                            count);
+  gsec_test_multiple_random_encrypt_decrypt(crypter, nullptr, message_lengths,
+                                            count);
+  gpr_free(aad_lengths);
+  gpr_free(message_lengths);
+}
+
+static void gsec_test_encryption_failure(gsec_aead_crypter* crypter) {
+  GPR_ASSERT(crypter != nullptr);
+  size_t aad_length = kTestMaxLength;
+  size_t message_length = kTestMaxLength;
+  size_t nonce_length;
+
+  char* error_message;
+  uint8_t *nonce, *aad, *message;
+
+  gsec_aead_crypter_nonce_length(crypter, &nonce_length, nullptr);
+  gsec_test_random_array(&nonce, nonce_length);
+  gsec_test_random_array(&aad, aad_length);
+  gsec_test_random_array(&message, message_length);
+
+  size_t ciphertext_and_tag_length, ciphertext_bytes_written = 0;
+  gsec_aead_crypter_max_ciphertext_and_tag_length(
+      crypter, message_length, &ciphertext_and_tag_length, nullptr);
+  uint8_t* ciphertext_and_tag =
+      static_cast<uint8_t*>(gpr_malloc(ciphertext_and_tag_length));
+
+  /* nullptr nonce */
+  grpc_status_code status = gsec_aead_crypter_encrypt(
+      crypter, nullptr, nonce_length, aad, aad_length, message, message_length,
+      ciphertext_and_tag, ciphertext_and_tag_length, &ciphertext_bytes_written,
+      &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "Nonce buffer is nullptr."));
+  gpr_free(error_message);
+
+  /* Big nonce */
+  status = gsec_aead_crypter_encrypt(
+      crypter, nonce, nonce_length + 1, aad, aad_length, message,
+      message_length, ciphertext_and_tag, ciphertext_and_tag_length,
+      &ciphertext_bytes_written, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "Nonce buffer has the wrong length."));
+  gpr_free(error_message);
+
+  /* Small nonce */
+  status = gsec_aead_crypter_encrypt(
+      crypter, nonce, nonce_length - 1, aad, aad_length, message,
+      message_length, ciphertext_and_tag, ciphertext_and_tag_length,
+      &ciphertext_bytes_written, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "Nonce buffer has the wrong length."));
+  gpr_free(error_message);
+
+  /* nullptr aad */
+  status = gsec_aead_crypter_encrypt(
+      crypter, nonce, nonce_length, nullptr, aad_length, message,
+      message_length, ciphertext_and_tag, ciphertext_and_tag_length,
+      &ciphertext_bytes_written, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message, "aad is nullptr."));
+  gpr_free(error_message);
+
+  /* nullptr aad with zero length */
+  gsec_assert_ok(
+      gsec_aead_crypter_encrypt(crypter, nonce, nonce_length, nullptr, 0,
+                                message, message_length, ciphertext_and_tag,
+                                ciphertext_and_tag_length,
+                                &ciphertext_bytes_written, &error_message),
+      error_message);
+
+  /* nullptr plaintext */
+  status = gsec_aead_crypter_encrypt(
+      crypter, nonce, nonce_length, aad, aad_length, nullptr, message_length,
+      ciphertext_and_tag, ciphertext_and_tag_length, &ciphertext_bytes_written,
+      &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "plaintext is nullptr."));
+  gpr_free(error_message);
+
+  /* nullptr ciphertext */
+  status = gsec_aead_crypter_encrypt(crypter, nonce, nonce_length, aad,
+                                     aad_length, message, message_length,
+                                     nullptr, ciphertext_and_tag_length,
+                                     &ciphertext_bytes_written, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "ciphertext is nullptr."));
+  gpr_free(error_message);
+
+  /* Short ciphertext */
+  status = gsec_aead_crypter_encrypt(
+      crypter, nonce, nonce_length, aad, aad_length, message, message_length,
+      ciphertext_and_tag, ciphertext_and_tag_length - 1,
+      &ciphertext_bytes_written, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "ciphertext is too small to hold a tag."));
+  gpr_free(error_message);
+
+  /* nullptr ciphertext_bytes_written */
+  status = gsec_aead_crypter_encrypt(
+      crypter, nonce, nonce_length, aad, aad_length, message, message_length,
+      ciphertext_and_tag, ciphertext_and_tag_length, nullptr, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "bytes_written is nullptr."));
+  gpr_free(error_message);
+
+  /* nullptr plaintext/ciphertext encrypt with zero length */
+  gsec_assert_ok(gsec_aead_crypter_encrypt(
+                     crypter, nonce, nonce_length, aad, aad_length, nullptr, 0,
+                     ciphertext_and_tag, ciphertext_and_tag_length,
+                     &ciphertext_bytes_written, &error_message),
+                 error_message);
+
+  /* Success */
+  status = gsec_aead_crypter_encrypt(
+      crypter, nonce, nonce_length, aad, aad_length, message, message_length,
+      ciphertext_and_tag, ciphertext_and_tag_length, &ciphertext_bytes_written,
+      &error_message);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+
+  gpr_free(message);
+  gpr_free(aad);
+  gpr_free(nonce);
+  gpr_free(ciphertext_and_tag);
+}
+
+static void gsec_test_decryption_failure(gsec_aead_crypter* crypter) {
+  GPR_ASSERT(crypter != nullptr);
+  size_t aad_length = kTestMaxLength;
+  size_t message_length = kTestMaxLength;
+  size_t nonce_length, tag_length;
+  uint8_t *nonce, *aad, *message;
+
+  gsec_aead_crypter_nonce_length(crypter, &nonce_length, nullptr);
+  gsec_aead_crypter_tag_length(crypter, &tag_length, nullptr);
+  gsec_test_random_array(&nonce, nonce_length);
+  gsec_test_random_array(&aad, aad_length);
+  gsec_test_random_array(&message, message_length);
+
+  /* Test encryption */
+  size_t ciphertext_and_tag_length, ciphertext_bytes_written = 0;
+  gsec_aead_crypter_max_ciphertext_and_tag_length(
+      crypter, message_length, &ciphertext_and_tag_length, nullptr);
+  uint8_t* ciphertext_and_tag =
+      static_cast<uint8_t*>(gpr_malloc(ciphertext_and_tag_length));
+
+  grpc_status_code status = gsec_aead_crypter_encrypt(
+      crypter, nonce, nonce_length, aad, aad_length, message, message_length,
+      ciphertext_and_tag, ciphertext_and_tag_length, &ciphertext_bytes_written,
+      nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(ciphertext_bytes_written == ciphertext_and_tag_length);
+
+  size_t plaintext_length, plaintext_bytes_written = 0;
+  gsec_aead_crypter_max_plaintext_length(crypter, ciphertext_bytes_written,
+                                         &plaintext_length, nullptr);
+  uint8_t* plaintext = static_cast<uint8_t*>(gpr_malloc(plaintext_length));
+
+  char* error_message;
+  /* nullptr nonce */
+  status = gsec_aead_crypter_decrypt(
+      crypter, nullptr, nonce_length, aad, aad_length, ciphertext_and_tag,
+      ciphertext_and_tag_length, plaintext, plaintext_length,
+      &plaintext_bytes_written, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "Nonce buffer is nullptr."));
+  gpr_free(error_message);
+
+  /* Big nonce */
+  status = gsec_aead_crypter_decrypt(
+      crypter, nonce, nonce_length + 1, aad, aad_length, ciphertext_and_tag,
+      ciphertext_and_tag_length, plaintext, plaintext_length,
+      &plaintext_bytes_written, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "Nonce buffer has the wrong length."));
+  gpr_free(error_message);
+
+  /* Small nonce */
+  status = gsec_aead_crypter_decrypt(
+      crypter, nonce, nonce_length - 1, aad, aad_length, ciphertext_and_tag,
+      ciphertext_and_tag_length, plaintext, plaintext_length,
+      &plaintext_bytes_written, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "Nonce buffer has the wrong length."));
+  gpr_free(error_message);
+
+  /* nullptr aad */
+  status = gsec_aead_crypter_decrypt(
+      crypter, nonce, nonce_length, nullptr, aad_length, ciphertext_and_tag,
+      ciphertext_and_tag_length, plaintext, plaintext_length,
+      &plaintext_bytes_written, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message, "aad is nullptr."));
+  gpr_free(error_message);
+
+  /* nullptr aad with zero length */
+  status = gsec_aead_crypter_encrypt(
+      crypter, nonce, nonce_length, nullptr, 0, message, message_length,
+      ciphertext_and_tag, ciphertext_and_tag_length, &ciphertext_bytes_written,
+      &error_message);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+
+  status = gsec_aead_crypter_decrypt(
+      crypter, nonce, nonce_length, nullptr, 0, ciphertext_and_tag,
+      ciphertext_and_tag_length, plaintext, plaintext_length,
+      &plaintext_bytes_written, &error_message);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+
+  /* Small ciphertext */
+  if (tag_length > 0) {
+    status = gsec_aead_crypter_decrypt(
+        crypter, nonce, nonce_length, aad, aad_length, ciphertext_and_tag,
+        tag_length - 1, plaintext, plaintext_length, &plaintext_bytes_written,
+        &error_message);
+
+    GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+        status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+        "ciphertext is too small to hold a tag."));
+    gpr_free(error_message);
+  }
+
+  /* nullptr ciphertext */
+  status = gsec_aead_crypter_decrypt(
+      crypter, nonce, nonce_length, aad, aad_length, nullptr,
+      ciphertext_and_tag_length, plaintext, plaintext_length,
+      &plaintext_bytes_written, &error_message);
+
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "ciphertext is nullptr."));
+  gpr_free(error_message);
+
+  /* nullptr plaintext */
+  status = gsec_aead_crypter_decrypt(
+      crypter, nonce, nonce_length, aad, aad_length, ciphertext_and_tag,
+      ciphertext_and_tag_length, nullptr, plaintext_length,
+      &plaintext_bytes_written, &error_message);
+
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "plaintext is nullptr, but plaintext_length is positive."));
+  gpr_free(error_message);
+
+  /* Short plaintext */
+  status = gsec_aead_crypter_decrypt(
+      crypter, nonce, nonce_length, aad, aad_length, ciphertext_and_tag,
+      ciphertext_and_tag_length, plaintext, plaintext_length - 1,
+      &plaintext_bytes_written, &error_message);
+
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "Not enough plaintext buffer to hold encrypted ciphertext."));
+  gpr_free(error_message);
+
+  /* nullptr plaintext_bytes_written */
+  status = gsec_aead_crypter_decrypt(crypter, nonce, nonce_length, aad,
+                                     aad_length, ciphertext_and_tag,
+                                     ciphertext_and_tag_length, plaintext,
+                                     plaintext_length, nullptr, &error_message);
+
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "bytes_written is nullptr."));
+  gpr_free(error_message);
+
+  gpr_free(message);
+  gpr_free(plaintext);
+  gpr_free(ciphertext_and_tag);
+  gpr_free(aad);
+  gpr_free(nonce);
+}
+
+static void gsec_test_encrypt_decrypt_test_vector(
+    gsec_aead_crypter* crypter, gsec_aead_test_vector* test_vector) {
+  GPR_ASSERT(crypter != nullptr);
+  /* Test byte-based encryption interface. */
+  size_t ciphertext_and_tag_length, ciphertext_bytes_written = 0;
+  gsec_aead_crypter_max_ciphertext_and_tag_length(
+      crypter, test_vector->plaintext_length, &ciphertext_and_tag_length,
+      nullptr);
+  uint8_t* ciphertext_and_tag_bytes =
+      static_cast<uint8_t*>(gpr_malloc(ciphertext_and_tag_length));
+  grpc_status_code status = gsec_aead_crypter_encrypt(
+      crypter, test_vector->nonce, test_vector->nonce_length, test_vector->aad,
+      test_vector->aad_length, test_vector->plaintext,
+      test_vector->plaintext_length, ciphertext_and_tag_bytes,
+      ciphertext_and_tag_length, &ciphertext_bytes_written, nullptr);
+
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(ciphertext_bytes_written == ciphertext_and_tag_length);
+  GPR_ASSERT(memcmp(test_vector->ciphertext_and_tag, ciphertext_and_tag_bytes,
+                    ciphertext_and_tag_length) == 0);
+
+  /* Test byte-based decryption interface */
+  size_t plaintext_length, plaintext_bytes_written = 0;
+  gsec_aead_crypter_max_plaintext_length(crypter, ciphertext_and_tag_length,
+                                         &plaintext_length, nullptr);
+  uint8_t* plaintext_bytes =
+      static_cast<uint8_t*>(gpr_malloc(plaintext_length));
+  status = gsec_aead_crypter_decrypt(
+      crypter, test_vector->nonce, test_vector->nonce_length, test_vector->aad,
+      test_vector->aad_length, test_vector->ciphertext_and_tag,
+      test_vector->ciphertext_and_tag_length, plaintext_bytes, plaintext_length,
+      &plaintext_bytes_written, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(memcmp(test_vector->plaintext, plaintext_bytes,
+                    plaintext_bytes_written) == 0);
+
+  gpr_free(ciphertext_and_tag_bytes);
+  gpr_free(plaintext_bytes);
+}
+
+static void gsec_test_get_crypter_from_test_vector(
+    gsec_aead_crypter** crypter, gsec_aead_test_vector* test_vector,
+    bool rekey = false) {
+  size_t key_length = test_vector->key_length;
+  GPR_ASSERT(key_length == kAes128GcmKeyLength ||
+             key_length == kAes256GcmKeyLength ||
+             key_length == kAes128GcmRekeyKeyLength);
+  size_t nonce_length = test_vector->nonce_length;
+  GPR_ASSERT(nonce_length == kAesGcmNonceLength);
+  size_t plaintext_length = test_vector->plaintext_length;
+  size_t ciphertext_and_tag_length = test_vector->ciphertext_and_tag_length;
+  GPR_ASSERT(ciphertext_and_tag_length == plaintext_length + kAesGcmTagLength);
+  size_t tag_length = ciphertext_and_tag_length - plaintext_length;
+  gsec_aes_gcm_aead_crypter_create(test_vector->key, key_length, nonce_length,
+                                   tag_length, rekey, crypter, nullptr);
+}
+
+static void gsec_test_verify_crypter_on_test_vector(
+    gsec_aead_test_vector* test_vector, bool rekey = false) {
+  gsec_aead_crypter* crypter;
+  gsec_test_get_crypter_from_test_vector(&crypter, test_vector, rekey);
+  gsec_test_encrypt_decrypt_test_vector(crypter, test_vector);
+  gsec_aead_crypter_destroy(crypter);
+}
+
+static void gsec_aead_malloc_test_vector(
+    gsec_aead_test_vector** test_vector, const uint8_t* key, size_t key_length,
+    const uint8_t* nonce, size_t nonce_length, const uint8_t* aad,
+    size_t aad_length, const uint8_t* plaintext, size_t plaintext_length,
+    const uint8_t* ciphertext_and_tag, size_t ciphertext_and_tag_length) {
+  *test_vector = static_cast<gsec_aead_test_vector*>(
+      gpr_malloc(sizeof(gsec_aead_test_vector)));
+  (*test_vector)->key_length = key_length;
+  (*test_vector)->nonce_length = nonce_length;
+  (*test_vector)->aad_length = aad_length;
+  (*test_vector)->plaintext_length = plaintext_length;
+  (*test_vector)->ciphertext_and_tag_length = ciphertext_and_tag_length;
+  gsec_test_copy(key, &((*test_vector)->key), key_length);
+  gsec_test_copy(nonce, &((*test_vector)->nonce), nonce_length);
+  gsec_test_copy(aad, &((*test_vector)->aad), aad_length);
+  gsec_test_copy(plaintext, &((*test_vector)->plaintext), plaintext_length);
+  gsec_test_copy(ciphertext_and_tag, &((*test_vector)->ciphertext_and_tag),
+                 ciphertext_and_tag_length);
+}
+
+static void gsec_aead_free_test_vector(gsec_aead_test_vector* test_vector) {
+  gpr_free(test_vector->key);
+  gpr_free(test_vector->nonce);
+  gpr_free(test_vector->aad);
+  gpr_free(test_vector->plaintext);
+  gpr_free(test_vector->ciphertext_and_tag);
+  gpr_free(test_vector);
+}
+
+static void gsec_test_create_random_aes_gcm_crypter(gsec_aead_crypter** crypter,
+                                                    size_t key_length,
+                                                    size_t nonce_length,
+                                                    size_t tag_length,
+                                                    bool rekey) {
+  uint8_t* key;
+  gsec_test_random_array(&key, key_length);
+  gsec_aes_gcm_aead_crypter_create(key, key_length, nonce_length, tag_length,
+                                   rekey, crypter, nullptr);
+  gpr_free(key);
+}
+
+static void gsec_test_get_random_aes_gcm_crypters(
+    gsec_aead_crypter*** crypters) {
+  *crypters = static_cast<gsec_aead_crypter**>(
+      gpr_malloc(sizeof(gsec_aead_crypter*) * kTestNumCrypters));
+  gsec_test_create_random_aes_gcm_crypter(
+      &((*crypters)[0]), kAes128GcmKeyLength, kAesGcmNonceLength,
+      kAesGcmTagLength, /*rekey=*/false);
+  gsec_test_create_random_aes_gcm_crypter(
+      &((*crypters)[1]), kAes256GcmKeyLength, kAesGcmNonceLength,
+      kAesGcmTagLength, /*rekey=*/false);
+  gsec_test_create_random_aes_gcm_crypter(
+      &((*crypters)[2]), kAes128GcmRekeyKeyLength, kAesGcmNonceLength,
+      kAesGcmTagLength, /*rekey=*/true);
+}
+
+static void gsec_test_do_generic_crypter_tests() {
+  gsec_aead_crypter** crypters;
+  gsec_test_get_random_aes_gcm_crypters(&crypters);
+  size_t ind;
+  for (ind = 0; ind < kTestNumCrypters; ind++) {
+    gsec_test_encrypt_decrypt(crypters[ind]);
+    gsec_test_multiple_encrypt_decrypt(crypters[ind]);
+    gsec_test_encryption_failure(crypters[ind]);
+    gsec_test_decryption_failure(crypters[ind]);
+  }
+  for (ind = 0; ind < kTestNumCrypters; ind++) {
+    gsec_aead_crypter_destroy(crypters[ind]);
+  }
+  gpr_free(crypters);
+}
+
+static void gsec_test_do_vector_tests_rekey_nist() {
+  // NIST vectors from:
+  // http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf
+  //
+  // IEEE vectors from:
+  // http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
+  //
+  // Key expanded by setting expandedKey = (key||(key ^ {0x01, .., 0x01})||key ^
+  // {0x02,..,0x02}))[0:44].
+
+  gsec_aead_test_vector vec;
+
+  // Derived from NIST test vector 1
+  uint8_t nonce_0[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+                       0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+  uint8_t aad_0[1] = {};
+  uint8_t key_0[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+                     0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
+                     0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2,
+                     0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2};
+  uint8_t plaintext_0[1] = {};
+  uint8_t ciphertext_0[] = {0x85, 0xE8, 0x73, 0xE0, 0x2,  0xF6, 0xEB, 0xDC,
+                            0x40, 0x60, 0x95, 0x4E, 0xB8, 0x67, 0x55, 0x8};
+  vec = {nonce_0, aad_0, key_0, plaintext_0, ciphertext_0, 12, 0, 44, 0, 16};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from NIST test vector 2
+  uint8_t nonce_1[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+                       0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+  uint8_t aad_1[1] = {};
+  uint8_t key_1[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+                     0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
+                     0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2,
+                     0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2};
+  uint8_t plaintext_1[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+                           0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+  uint8_t ciphertext_1[] = {0x51, 0xE9, 0xA8, 0xCB, 0x23, 0xCA, 0x25, 0x12,
+                            0xC8, 0x25, 0x6A, 0xFF, 0xF8, 0xE7, 0x2D, 0x68,
+                            0x1A, 0xCA, 0x19, 0xA1, 0x14, 0x8A, 0xC1, 0x15,
+                            0xE8, 0x3D, 0xF4, 0x88, 0x8C, 0xC0, 0xD,  0x11};
+  vec = {nonce_1, aad_1, key_1, plaintext_1, ciphertext_1, 12, 0, 44, 16, 32};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from NIST test vector 3
+  uint8_t nonce_2[] = {0xCA, 0xFE, 0xBA, 0xBE, 0xFA, 0xCE,
+                       0xDB, 0xAD, 0xDE, 0xCA, 0xF8, 0x88};
+  uint8_t aad_2[1] = {};
+  uint8_t key_2[] = {0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D,
+                     0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x8,  0xFF, 0xFE,
+                     0xE8, 0x93, 0x87, 0x64, 0x72, 0x1D, 0x6C, 0x6B, 0x8E,
+                     0x95, 0x66, 0x31, 0x82, 0x9,  0xFC, 0xFD, 0xEB, 0x90,
+                     0x84, 0x67, 0x71, 0x1E, 0x6F, 0x68, 0x8D, 0x96};
+  uint8_t plaintext_2[] = {
+      0xD9, 0x31, 0x32, 0x25, 0xF8, 0x84, 0x6,  0xE5, 0xA5, 0x59, 0x9,
+      0xC5, 0xAF, 0xF5, 0x26, 0x9A, 0x86, 0xA7, 0xA9, 0x53, 0x15, 0x34,
+      0xF7, 0xDA, 0x2E, 0x4C, 0x30, 0x3D, 0x8A, 0x31, 0x8A, 0x72, 0x1C,
+      0x3C, 0xC,  0x95, 0x95, 0x68, 0x9,  0x53, 0x2F, 0xCF, 0xE,  0x24,
+      0x49, 0xA6, 0xB5, 0x25, 0xB1, 0x6A, 0xED, 0xF5, 0xAA, 0xD,  0xE6,
+      0x57, 0xBA, 0x63, 0x7B, 0x39, 0x1A, 0xAF, 0xD2, 0x55};
+  uint8_t ciphertext_2[] = {
+      0x10, 0x18, 0xED, 0x5A, 0x14, 0x2,  0xA8, 0x65, 0x16, 0xD6, 0x57, 0x6D,
+      0x70, 0xB2, 0xFF, 0xCC, 0xCA, 0x26, 0x1B, 0x94, 0xDF, 0x88, 0xB5, 0x8F,
+      0x53, 0xB6, 0x4D, 0xFB, 0xA4, 0x35, 0xD1, 0x8B, 0x2F, 0x6E, 0x3B, 0x78,
+      0x69, 0xF9, 0x35, 0x3D, 0x4A, 0xC8, 0xCF, 0x9,  0xAF, 0xB1, 0x66, 0x3D,
+      0xAA, 0x7B, 0x40, 0x17, 0xE6, 0xFC, 0x2C, 0x17, 0x7C, 0xC,  0x8,  0x7C,
+      0xD,  0xF1, 0x16, 0x21, 0x29, 0x95, 0x22, 0x13, 0xCE, 0xE1, 0xBC, 0x6E,
+      0x9C, 0x84, 0x95, 0xDD, 0x70, 0x5E, 0x1F, 0x3D};
+  vec = {nonce_2, aad_2, key_2, plaintext_2, ciphertext_2, 12, 0, 44, 64, 80};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from NIST test vector 4
+  uint8_t nonce_3[] = {0xCA, 0xFE, 0xBA, 0xBE, 0xFA, 0xCE,
+                       0xDB, 0xAD, 0xDE, 0xCA, 0xF8, 0x88};
+  uint8_t aad_3[] = {0xFE, 0xED, 0xFA, 0xCE, 0xDE, 0xAD, 0xBE,
+                     0xEF, 0xFE, 0xED, 0xFA, 0xCE, 0xDE, 0xAD,
+                     0xBE, 0xEF, 0xAB, 0xAD, 0xDA, 0xD2};
+  uint8_t key_3[] = {0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D,
+                     0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x8,  0xFF, 0xFE,
+                     0xE8, 0x93, 0x87, 0x64, 0x72, 0x1D, 0x6C, 0x6B, 0x8E,
+                     0x95, 0x66, 0x31, 0x82, 0x9,  0xFC, 0xFD, 0xEB, 0x90,
+                     0x84, 0x67, 0x71, 0x1E, 0x6F, 0x68, 0x8D, 0x96};
+  uint8_t plaintext_3[] = {
+      0xD9, 0x31, 0x32, 0x25, 0xF8, 0x84, 0x6,  0xE5, 0xA5, 0x59, 0x9,  0xC5,
+      0xAF, 0xF5, 0x26, 0x9A, 0x86, 0xA7, 0xA9, 0x53, 0x15, 0x34, 0xF7, 0xDA,
+      0x2E, 0x4C, 0x30, 0x3D, 0x8A, 0x31, 0x8A, 0x72, 0x1C, 0x3C, 0xC,  0x95,
+      0x95, 0x68, 0x9,  0x53, 0x2F, 0xCF, 0xE,  0x24, 0x49, 0xA6, 0xB5, 0x25,
+      0xB1, 0x6A, 0xED, 0xF5, 0xAA, 0xD,  0xE6, 0x57, 0xBA, 0x63, 0x7B, 0x39};
+  uint8_t ciphertext_3[] = {
+      0x10, 0x18, 0xED, 0x5A, 0x14, 0x2,  0xA8, 0x65, 0x16, 0xD6, 0x57,
+      0x6D, 0x70, 0xB2, 0xFF, 0xCC, 0xCA, 0x26, 0x1B, 0x94, 0xDF, 0x88,
+      0xB5, 0x8F, 0x53, 0xB6, 0x4D, 0xFB, 0xA4, 0x35, 0xD1, 0x8B, 0x2F,
+      0x6E, 0x3B, 0x78, 0x69, 0xF9, 0x35, 0x3D, 0x4A, 0xC8, 0xCF, 0x9,
+      0xAF, 0xB1, 0x66, 0x3D, 0xAA, 0x7B, 0x40, 0x17, 0xE6, 0xFC, 0x2C,
+      0x17, 0x7C, 0xC,  0x8,  0x7C, 0x47, 0x64, 0x56, 0x5D, 0x7,  0x7E,
+      0x91, 0x24, 0x0,  0x1D, 0xDB, 0x27, 0xFC, 0x8,  0x48, 0xC5};
+  vec = {nonce_3, aad_3, key_3, plaintext_3, ciphertext_3, 12, 20, 44, 60, 76};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from adapted NIST test vector 4 for KDF counter boundary (flip
+  // nonce bit 15)
+  uint8_t nonce_4[] = {0xCA, 0x7E, 0xBA, 0xBE, 0xFA, 0xCE,
+                       0xDB, 0xAD, 0xDE, 0xCA, 0xF8, 0x88};
+  uint8_t aad_4[] = {0xFE, 0xED, 0xFA, 0xCE, 0xDE, 0xAD, 0xBE,
+                     0xEF, 0xFE, 0xED, 0xFA, 0xCE, 0xDE, 0xAD,
+                     0xBE, 0xEF, 0xAB, 0xAD, 0xDA, 0xD2};
+  uint8_t key_4[] = {0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D,
+                     0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x8,  0xFF, 0xFE,
+                     0xE8, 0x93, 0x87, 0x64, 0x72, 0x1D, 0x6C, 0x6B, 0x8E,
+                     0x95, 0x66, 0x31, 0x82, 0x9,  0xFC, 0xFD, 0xEB, 0x90,
+                     0x84, 0x67, 0x71, 0x1E, 0x6F, 0x68, 0x8D, 0x96};
+  uint8_t plaintext_4[] = {
+      0xD9, 0x31, 0x32, 0x25, 0xF8, 0x84, 0x6,  0xE5, 0xA5, 0x59, 0x9,  0xC5,
+      0xAF, 0xF5, 0x26, 0x9A, 0x86, 0xA7, 0xA9, 0x53, 0x15, 0x34, 0xF7, 0xDA,
+      0x2E, 0x4C, 0x30, 0x3D, 0x8A, 0x31, 0x8A, 0x72, 0x1C, 0x3C, 0xC,  0x95,
+      0x95, 0x68, 0x9,  0x53, 0x2F, 0xCF, 0xE,  0x24, 0x49, 0xA6, 0xB5, 0x25,
+      0xB1, 0x6A, 0xED, 0xF5, 0xAA, 0xD,  0xE6, 0x57, 0xBA, 0x63, 0x7B, 0x39};
+  uint8_t ciphertext_4[] = {
+      0xE6, 0x50, 0xD3, 0xC0, 0xFB, 0x87, 0x93, 0x27, 0xF2, 0xD0, 0x32,
+      0x87, 0xFA, 0x93, 0xCD, 0x7,  0x34, 0x2B, 0x13, 0x62, 0x15, 0xAD,
+      0xBC, 0xA0, 0xC,  0x3B, 0xD5, 0x9,  0x9E, 0xC4, 0x18, 0x32, 0xB1,
+      0xD1, 0x8E, 0x4,  0x23, 0xED, 0x26, 0xBB, 0x12, 0xC6, 0xCD, 0x9,
+      0xDE, 0xBB, 0x29, 0x23, 0xA,  0x94, 0xC0, 0xCE, 0xE1, 0x59, 0x3,
+      0x65, 0x6F, 0x85, 0xED, 0xB6, 0xFC, 0x50, 0x9B, 0x1B, 0x28, 0x21,
+      0x63, 0x82, 0x17, 0x2E, 0xCB, 0xCC, 0x31, 0xE1, 0xE9, 0xB1};
+  vec = {nonce_4, aad_4, key_4, plaintext_4, ciphertext_4, 12, 20, 44, 60, 76};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from adapted NIST test vector 4 for KDF counter boundary (flip
+  // nonce bit 16)
+  uint8_t nonce_5[] = {0xCA, 0xFE, 0xBB, 0xBE, 0xFA, 0xCE,
+                       0xDB, 0xAD, 0xDE, 0xCA, 0xF8, 0x88};
+  uint8_t aad_5[] = {0xFE, 0xED, 0xFA, 0xCE, 0xDE, 0xAD, 0xBE,
+                     0xEF, 0xFE, 0xED, 0xFA, 0xCE, 0xDE, 0xAD,
+                     0xBE, 0xEF, 0xAB, 0xAD, 0xDA, 0xD2};
+  uint8_t key_5[] = {0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D,
+                     0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x8,  0xFF, 0xFE,
+                     0xE8, 0x93, 0x87, 0x64, 0x72, 0x1D, 0x6C, 0x6B, 0x8E,
+                     0x95, 0x66, 0x31, 0x82, 0x9,  0xFC, 0xFD, 0xEB, 0x90,
+                     0x84, 0x67, 0x71, 0x1E, 0x6F, 0x68, 0x8D, 0x96};
+  uint8_t plaintext_5[] = {
+      0xD9, 0x31, 0x32, 0x25, 0xF8, 0x84, 0x6,  0xE5, 0xA5, 0x59, 0x9,  0xC5,
+      0xAF, 0xF5, 0x26, 0x9A, 0x86, 0xA7, 0xA9, 0x53, 0x15, 0x34, 0xF7, 0xDA,
+      0x2E, 0x4C, 0x30, 0x3D, 0x8A, 0x31, 0x8A, 0x72, 0x1C, 0x3C, 0xC,  0x95,
+      0x95, 0x68, 0x9,  0x53, 0x2F, 0xCF, 0xE,  0x24, 0x49, 0xA6, 0xB5, 0x25,
+      0xB1, 0x6A, 0xED, 0xF5, 0xAA, 0xD,  0xE6, 0x57, 0xBA, 0x63, 0x7B, 0x39};
+  uint8_t ciphertext_5[] = {
+      0xC0, 0x12, 0x1E, 0x6C, 0x95, 0x4D, 0x7,  0x67, 0xF9, 0x66, 0x30,
+      0xC3, 0x34, 0x50, 0x99, 0x97, 0x91, 0xB2, 0xDA, 0x2A, 0xD0, 0x5C,
+      0x41, 0x90, 0x16, 0x9C, 0xCA, 0xD9, 0xAC, 0x86, 0xFF, 0x1C, 0x72,
+      0x1E, 0x3D, 0x82, 0xF2, 0xAD, 0x22, 0xAB, 0x46, 0x3B, 0xAB, 0x4A,
+      0x7,  0x54, 0xB7, 0xDD, 0x68, 0xCA, 0x4D, 0xE7, 0xEA, 0x25, 0x31,
+      0xB6, 0x25, 0xED, 0xA0, 0x1F, 0x89, 0x31, 0x2B, 0x2A, 0xB9, 0x57,
+      0xD5, 0xC7, 0xF8, 0x56, 0x8D, 0xD9, 0x5F, 0xCD, 0xCD, 0x1F};
+  vec = {nonce_5, aad_5, key_5, plaintext_5, ciphertext_5, 12, 20, 44, 60, 76};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from adapted NIST test vector 4 for KDF counter boundary (flip
+  // nonce bit 63)
+  uint8_t nonce_6[] = {0xCA, 0xFE, 0xBA, 0xBE, 0xFA, 0xCE,
+                       0xDB, 0x2D, 0xDE, 0xCA, 0xF8, 0x88};
+  uint8_t aad_6[] = {0xFE, 0xED, 0xFA, 0xCE, 0xDE, 0xAD, 0xBE,
+                     0xEF, 0xFE, 0xED, 0xFA, 0xCE, 0xDE, 0xAD,
+                     0xBE, 0xEF, 0xAB, 0xAD, 0xDA, 0xD2};
+  uint8_t key_6[] = {0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D,
+                     0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x8,  0xFF, 0xFE,
+                     0xE8, 0x93, 0x87, 0x64, 0x72, 0x1D, 0x6C, 0x6B, 0x8E,
+                     0x95, 0x66, 0x31, 0x82, 0x9,  0xFC, 0xFD, 0xEB, 0x90,
+                     0x84, 0x67, 0x71, 0x1E, 0x6F, 0x68, 0x8D, 0x96};
+  uint8_t plaintext_6[] = {
+      0xD9, 0x31, 0x32, 0x25, 0xF8, 0x84, 0x6,  0xE5, 0xA5, 0x59, 0x9,  0xC5,
+      0xAF, 0xF5, 0x26, 0x9A, 0x86, 0xA7, 0xA9, 0x53, 0x15, 0x34, 0xF7, 0xDA,
+      0x2E, 0x4C, 0x30, 0x3D, 0x8A, 0x31, 0x8A, 0x72, 0x1C, 0x3C, 0xC,  0x95,
+      0x95, 0x68, 0x9,  0x53, 0x2F, 0xCF, 0xE,  0x24, 0x49, 0xA6, 0xB5, 0x25,
+      0xB1, 0x6A, 0xED, 0xF5, 0xAA, 0xD,  0xE6, 0x57, 0xBA, 0x63, 0x7B, 0x39};
+  uint8_t ciphertext_6[] = {
+      0x8A, 0xF3, 0x7E, 0xA5, 0x68, 0x4A, 0x4D, 0x81, 0xD4, 0xFD, 0x81,
+      0x72, 0x61, 0xFD, 0x97, 0x43, 0x9,  0x9E, 0x7E, 0x6A, 0x2,  0x5E,
+      0xAA, 0xCF, 0x8E, 0x54, 0xB1, 0x24, 0xFB, 0x57, 0x43, 0x14, 0x9E,
+      0x5,  0xCB, 0x89, 0xF4, 0xA4, 0x94, 0x67, 0xFE, 0x2E, 0x5E, 0x59,
+      0x65, 0xF2, 0x9A, 0x19, 0xF9, 0x94, 0x16, 0xB0, 0x1,  0x6B, 0x54,
+      0x58, 0x5D, 0x12, 0x55, 0x37, 0x83, 0xBA, 0x59, 0xE9, 0xF7, 0x82,
+      0xE8, 0x2E, 0x9,  0x7C, 0x33, 0x6B, 0xF7, 0x98, 0x9F, 0x8};
+  vec = {nonce_6, aad_6, key_6, plaintext_6, ciphertext_6, 12, 20, 44, 60, 76};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from adapted NIST test vector 4 for KDF counter boundary (flip
+  // nonce bit 64)
+  uint8_t nonce_7[] = {0xCA, 0xFE, 0xBA, 0xBE, 0xFA, 0xCE,
+                       0xDB, 0xAD, 0xDF, 0xCA, 0xF8, 0x88};
+  uint8_t aad_7[] = {0xFE, 0xED, 0xFA, 0xCE, 0xDE, 0xAD, 0xBE,
+                     0xEF, 0xFE, 0xED, 0xFA, 0xCE, 0xDE, 0xAD,
+                     0xBE, 0xEF, 0xAB, 0xAD, 0xDA, 0xD2};
+  uint8_t key_7[] = {0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D,
+                     0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x8,  0xFF, 0xFE,
+                     0xE8, 0x93, 0x87, 0x64, 0x72, 0x1D, 0x6C, 0x6B, 0x8E,
+                     0x95, 0x66, 0x31, 0x82, 0x9,  0xFC, 0xFD, 0xEB, 0x90,
+                     0x84, 0x67, 0x71, 0x1E, 0x6F, 0x68, 0x8D, 0x96};
+  uint8_t plaintext_7[] = {
+      0xD9, 0x31, 0x32, 0x25, 0xF8, 0x84, 0x6,  0xE5, 0xA5, 0x59, 0x9,  0xC5,
+      0xAF, 0xF5, 0x26, 0x9A, 0x86, 0xA7, 0xA9, 0x53, 0x15, 0x34, 0xF7, 0xDA,
+      0x2E, 0x4C, 0x30, 0x3D, 0x8A, 0x31, 0x8A, 0x72, 0x1C, 0x3C, 0xC,  0x95,
+      0x95, 0x68, 0x9,  0x53, 0x2F, 0xCF, 0xE,  0x24, 0x49, 0xA6, 0xB5, 0x25,
+      0xB1, 0x6A, 0xED, 0xF5, 0xAA, 0xD,  0xE6, 0x57, 0xBA, 0x63, 0x7B, 0x39};
+  uint8_t ciphertext_7[] = {
+      0xFB, 0xD5, 0x28, 0x44, 0x8D, 0x3,  0x46, 0xBF, 0xA8, 0x78, 0x63,
+      0x48, 0x64, 0xD4, 0x7,  0xA3, 0x5A, 0x3,  0x9D, 0xE9, 0xDB, 0x2F,
+      0x1F, 0xEB, 0x8E, 0x96, 0x5B, 0x3A, 0xE9, 0x35, 0x6C, 0xE6, 0x28,
+      0x94, 0x41, 0xD7, 0x7F, 0x8F, 0xD,  0xF2, 0x94, 0x89, 0x1F, 0x37,
+      0xEA, 0x43, 0x8B, 0x22, 0x3E, 0x3B, 0xF2, 0xBD, 0xC5, 0x3D, 0x4C,
+      0x5A, 0x74, 0xFB, 0x68, 0xB,  0xB3, 0x12, 0xA8, 0xDE, 0xC6, 0xF7,
+      0x25, 0x2C, 0xBC, 0xD7, 0xF5, 0x79, 0x97, 0x50, 0xAD, 0x78};
+  vec = {nonce_7, aad_7, key_7, plaintext_7, ciphertext_7, 12, 20, 44, 60, 76};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+}
+
+static void gsec_test_do_vector_tests_rekey_ieee() {
+  // IEEE vectors from:
+  // http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
+  //
+  // Key expanded by setting expandedKey = (key||(key ^ {0x01, .., 0x01})||key ^
+  // {0x02,..,0x02}))[0:44].
+
+  gsec_aead_test_vector vec;
+
+  // Derived from IEEE 2.1.1 54-byte auth
+  uint8_t nonce_8[] = {0x12, 0x15, 0x35, 0x24, 0xC0, 0x89,
+                       0x5E, 0x81, 0xB2, 0xC2, 0x84, 0x65};
+  uint8_t aad_8[] = {0xD6, 0x9,  0xB1, 0xF0, 0x56, 0x63, 0x7A, 0xD,  0x46, 0xDF,
+                     0x99, 0x8D, 0x88, 0xE5, 0x22, 0x2A, 0xB2, 0xC2, 0x84, 0x65,
+                     0x12, 0x15, 0x35, 0x24, 0xC0, 0x89, 0x5E, 0x81, 0x8,  0x0,
+                     0xF,  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+                     0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22,
+                     0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C,
+                     0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x0,  0x1};
+  uint8_t key_8[] = {0xAD, 0x7A, 0x2B, 0xD0, 0x3E, 0xAC, 0x83, 0x5A, 0x6F,
+                     0x62, 0xF,  0xDC, 0xB5, 0x6,  0xB3, 0x45, 0xAC, 0x7B,
+                     0x2A, 0xD1, 0x3F, 0xAD, 0x82, 0x5B, 0x6E, 0x63, 0xE,
+                     0xDD, 0xB4, 0x7,  0xB2, 0x44, 0xAF, 0x78, 0x29, 0xD2,
+                     0x3C, 0xAE, 0x81, 0x58, 0x6D, 0x60, 0xD,  0xDE};
+  uint8_t plaintext_8[1] = {};
+  uint8_t ciphertext_8[] = {0x3E, 0xA0, 0xB5, 0x84, 0xF3, 0xC8, 0x5E, 0x93,
+                            0xF9, 0x32, 0xE,  0xA5, 0x91, 0x69, 0x9E, 0xFB};
+  vec = {nonce_8, aad_8, key_8, plaintext_8, ciphertext_8, 12, 70, 44, 0, 16};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from IEEE 2.1.2 54-byte auth
+  uint8_t nonce_9[] = {0x12, 0x15, 0x35, 0x24, 0xC0, 0x89,
+                       0x5E, 0x81, 0xB2, 0xC2, 0x84, 0x65};
+  uint8_t aad_9[] = {0xD6, 0x9,  0xB1, 0xF0, 0x56, 0x63, 0x7A, 0xD,  0x46, 0xDF,
+                     0x99, 0x8D, 0x88, 0xE5, 0x22, 0x2A, 0xB2, 0xC2, 0x84, 0x65,
+                     0x12, 0x15, 0x35, 0x24, 0xC0, 0x89, 0x5E, 0x81, 0x8,  0x0,
+                     0xF,  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+                     0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22,
+                     0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C,
+                     0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x0,  0x1};
+  uint8_t key_9[] = {0xE3, 0xC0, 0x8A, 0x8F, 0x6,  0xC6, 0xE3, 0xAD, 0x95,
+                     0xA7, 0x5,  0x57, 0xB2, 0x3F, 0x75, 0x48, 0x3C, 0xE3,
+                     0x30, 0x21, 0xA9, 0xC7, 0x2B, 0x70, 0x25, 0x66, 0x62,
+                     0x4,  0xC6, 0x9C, 0xB,  0x72, 0xE1, 0xC2, 0x88, 0x8D,
+                     0x4,  0xC4, 0xE1, 0xAF, 0x97, 0xA5, 0x7,  0x55};
+  uint8_t plaintext_9[1] = {};
+  uint8_t ciphertext_9[] = {0x29, 0x4E, 0x2,  0x8B, 0xF1, 0xFE, 0x6F, 0x14,
+                            0xC4, 0xE8, 0xF7, 0x30, 0x5C, 0x93, 0x3E, 0xB5};
+  vec = {nonce_9, aad_9, key_9, plaintext_9, ciphertext_9, 12, 70, 44, 0, 16};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from IEEE 2.2.1 60-byte crypt
+  uint8_t nonce_10[] = {0x12, 0x15, 0x35, 0x24, 0xC0, 0x89,
+                        0x5E, 0x81, 0xB2, 0xC2, 0x84, 0x65};
+  uint8_t aad_10[] = {0xD6, 0x9,  0xB1, 0xF0, 0x56, 0x63, 0x7A,
+                      0xD,  0x46, 0xDF, 0x99, 0x8D, 0x88, 0xE5,
+                      0x2E, 0x0,  0xB2, 0xC2, 0x84, 0x65, 0x12,
+                      0x15, 0x35, 0x24, 0xC0, 0x89, 0x5E, 0x81};
+  uint8_t key_10[] = {0xAD, 0x7A, 0x2B, 0xD0, 0x3E, 0xAC, 0x83, 0x5A, 0x6F,
+                      0x62, 0xF,  0xDC, 0xB5, 0x6,  0xB3, 0x45, 0xAC, 0x7B,
+                      0x2A, 0xD1, 0x3F, 0xAD, 0x82, 0x5B, 0x6E, 0x63, 0xE,
+                      0xDD, 0xB4, 0x7,  0xB2, 0x44, 0xAF, 0x78, 0x29, 0xD2,
+                      0x3C, 0xAE, 0x81, 0x58, 0x6D, 0x60, 0xD,  0xDE};
+  uint8_t plaintext_10[] = {
+      0x8,  0x0,  0xF,  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+      0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
+      0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
+      0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x0,  0x2};
+  uint8_t ciphertext_10[] = {
+      0xDB, 0x3D, 0x25, 0x71, 0x9C, 0x6B, 0xA,  0x3C, 0xA6, 0x14, 0x5C,
+      0x15, 0x9D, 0x5C, 0x6E, 0xD9, 0xAF, 0xF9, 0xC6, 0xE0, 0xB7, 0x9F,
+      0x17, 0x1,  0x9E, 0xA9, 0x23, 0xB8, 0x66, 0x5D, 0xDF, 0x52, 0x13,
+      0x7A, 0xD6, 0x11, 0xF0, 0xD1, 0xBF, 0x41, 0x7A, 0x7C, 0xA8, 0x5E,
+      0x45, 0xAF, 0xE1, 0x6,  0xFF, 0x9C, 0x75, 0x69, 0xD3, 0x35, 0xD0,
+      0x86, 0xAE, 0x6C, 0x3,  0xF0, 0x9,  0x87, 0xCC, 0xD6};
+  vec = {nonce_10, aad_10, key_10, plaintext_10, ciphertext_10,
+         12,       28,     44,     48,           64};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from IEEE 2.2.2 60-byte crypt
+  uint8_t nonce_11[] = {0x12, 0x15, 0x35, 0x24, 0xC0, 0x89,
+                        0x5E, 0x81, 0xB2, 0xC2, 0x84, 0x65};
+  uint8_t aad_11[] = {0xD6, 0x9,  0xB1, 0xF0, 0x56, 0x63, 0x7A,
+                      0xD,  0x46, 0xDF, 0x99, 0x8D, 0x88, 0xE5,
+                      0x2E, 0x0,  0xB2, 0xC2, 0x84, 0x65, 0x12,
+                      0x15, 0x35, 0x24, 0xC0, 0x89, 0x5E, 0x81};
+  uint8_t key_11[] = {0xE3, 0xC0, 0x8A, 0x8F, 0x6,  0xC6, 0xE3, 0xAD, 0x95,
+                      0xA7, 0x5,  0x57, 0xB2, 0x3F, 0x75, 0x48, 0x3C, 0xE3,
+                      0x30, 0x21, 0xA9, 0xC7, 0x2B, 0x70, 0x25, 0x66, 0x62,
+                      0x4,  0xC6, 0x9C, 0xB,  0x72, 0xE1, 0xC2, 0x88, 0x8D,
+                      0x4,  0xC4, 0xE1, 0xAF, 0x97, 0xA5, 0x7,  0x55};
+  uint8_t plaintext_11[] = {
+      0x8,  0x0,  0xF,  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+      0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
+      0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
+      0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x0,  0x2};
+  uint8_t ciphertext_11[] = {
+      0x16, 0x41, 0xF2, 0x8E, 0xC1, 0x3A, 0xFC, 0xC8, 0xF7, 0x90, 0x33,
+      0x89, 0x78, 0x72, 0x1,  0x5,  0x16, 0x44, 0x91, 0x49, 0x33, 0xE9,
+      0x20, 0x2B, 0xB9, 0xD0, 0x6A, 0xA0, 0x20, 0xC2, 0xA6, 0x7E, 0xF5,
+      0x1D, 0xFE, 0x7B, 0xC0, 0xA,  0x85, 0x6C, 0x55, 0xB8, 0xF8, 0x13,
+      0x3E, 0x77, 0xF6, 0x59, 0x13, 0x25, 0x2,  0xBA, 0xD6, 0x3F, 0x57,
+      0x13, 0xD5, 0x7D, 0xC,  0x11, 0xE0, 0xF8, 0x71, 0xED};
+  vec = {nonce_11, aad_11, key_11, plaintext_11, ciphertext_11,
+         12,       28,     44,     48,           64};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from IEEE 2.3.1 60-byte auth
+  uint8_t nonce_12[] = {0xF0, 0x76, 0x1E, 0x8D, 0xCD, 0x3D,
+                        0x0,  0x1,  0x76, 0xD4, 0x57, 0xED};
+  uint8_t aad_12[] = {
+      0xE2, 0x1,  0x6,  0xD7, 0xCD, 0xD,  0xF0, 0x76, 0x1E, 0x8D, 0xCD, 0x3D,
+      0x88, 0xE5, 0x40, 0x0,  0x76, 0xD4, 0x57, 0xED, 0x8,  0x0,  0xF,  0x10,
+      0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
+      0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+      0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34,
+      0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x0,  0x3};
+  uint8_t key_12[] = {0x7,  0x1B, 0x11, 0x3B, 0xC,  0xA7, 0x43, 0xFE, 0xCC,
+                      0xCF, 0x3D, 0x5,  0x1F, 0x73, 0x73, 0x82, 0x6,  0x1A,
+                      0x10, 0x3A, 0xD,  0xA6, 0x42, 0xFF, 0xCD, 0xCE, 0x3C,
+                      0x4,  0x1E, 0x72, 0x72, 0x83, 0x5,  0x19, 0x13, 0x39,
+                      0xE,  0xA5, 0x41, 0xFC, 0xCE, 0xCD, 0x3F, 0x7};
+  uint8_t plaintext_12[1] = {};
+  uint8_t ciphertext_12[] = {0x58, 0x83, 0x7A, 0x10, 0x56, 0x2B, 0xF,  0x1F,
+                             0x8E, 0xDB, 0xE5, 0x8C, 0xA5, 0x58, 0x11, 0xD3};
+  vec = {nonce_12, aad_12, key_12, plaintext_12, ciphertext_12, 12, 68,
+         44,       0,      16};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from IEEE 2.3.2 60-byte auth
+  uint8_t nonce_13[] = {0xF0, 0x76, 0x1E, 0x8D, 0xCD, 0x3D,
+                        0x0,  0x1,  0x76, 0xD4, 0x57, 0xED};
+  uint8_t aad_13[] = {
+      0xE2, 0x1,  0x6,  0xD7, 0xCD, 0xD,  0xF0, 0x76, 0x1E, 0x8D, 0xCD, 0x3D,
+      0x88, 0xE5, 0x40, 0x0,  0x76, 0xD4, 0x57, 0xED, 0x8,  0x0,  0xF,  0x10,
+      0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
+      0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+      0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34,
+      0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x0,  0x3};
+  uint8_t key_13[] = {0x69, 0x1D, 0x3E, 0xE9, 0x9,  0xD7, 0xF5, 0x41, 0x67,
+                      0xFD, 0x1C, 0xA0, 0xB5, 0xD7, 0x69, 0x8,  0x1F, 0x2B,
+                      0xDE, 0x1A, 0xEE, 0x65, 0x5F, 0xDB, 0xAB, 0x80, 0xBD,
+                      0x52, 0x95, 0xAE, 0x6B, 0xE7, 0x6B, 0x1F, 0x3C, 0xEB,
+                      0xB,  0xD5, 0xF7, 0x43, 0x65, 0xFF, 0x1E, 0xA2};
+  uint8_t plaintext_13[1] = {};
+  uint8_t ciphertext_13[] = {0xC2, 0x72, 0x2F, 0xF6, 0xCA, 0x29, 0xA2, 0x57,
+                             0x71, 0x8A, 0x52, 0x9D, 0x1F, 0xC,  0x6A, 0x3B};
+  vec = {nonce_13, aad_13, key_13, plaintext_13, ciphertext_13, 12, 68,
+         44,       0,      16};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from IEEE 2.4.1 54-byte crypt
+  uint8_t nonce_14[] = {0xF0, 0x76, 0x1E, 0x8D, 0xCD, 0x3D,
+                        0x0,  0x1,  0x76, 0xD4, 0x57, 0xED};
+  uint8_t aad_14[] = {0xE2, 0x1,  0x6,  0xD7, 0xCD, 0xD,  0xF0,
+                      0x76, 0x1E, 0x8D, 0xCD, 0x3D, 0x88, 0xE5,
+                      0x4C, 0x2A, 0x76, 0xD4, 0x57, 0xED};
+  uint8_t key_14[] = {0x7,  0x1B, 0x11, 0x3B, 0xC,  0xA7, 0x43, 0xFE, 0xCC,
+                      0xCF, 0x3D, 0x5,  0x1F, 0x73, 0x73, 0x82, 0x6,  0x1A,
+                      0x10, 0x3A, 0xD,  0xA6, 0x42, 0xFF, 0xCD, 0xCE, 0x3C,
+                      0x4,  0x1E, 0x72, 0x72, 0x83, 0x5,  0x19, 0x13, 0x39,
+                      0xE,  0xA5, 0x41, 0xFC, 0xCE, 0xCD, 0x3F, 0x7};
+  uint8_t plaintext_14[] = {
+      0x8,  0x0,  0xF,  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+      0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22,
+      0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D,
+      0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x0,  0x4};
+  uint8_t ciphertext_14[] = {
+      0xFD, 0x96, 0xB7, 0x15, 0xB9, 0x3A, 0x13, 0x34, 0x6A, 0xF5, 0x1E, 0x8A,
+      0xCD, 0xF7, 0x92, 0xCD, 0xC7, 0xB2, 0x68, 0x6F, 0x85, 0x74, 0xC7, 0xE,
+      0x6B, 0xC,  0xBF, 0x16, 0x29, 0x1D, 0xED, 0x42, 0x7A, 0xD7, 0x3F, 0xEC,
+      0x48, 0xCD, 0x29, 0x8E, 0x5,  0x28, 0xA1, 0xF4, 0xC6, 0x44, 0xA9, 0x49,
+      0xFC, 0x31, 0xDC, 0x92, 0x79, 0x70, 0x6D, 0xDB, 0xA3, 0x3F};
+  vec = {nonce_14, aad_14, key_14, plaintext_14, ciphertext_14,
+         12,       20,     44,     42,           58};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from IEEE 2.4.2 54-byte crypt
+  uint8_t nonce_15[] = {0xF0, 0x76, 0x1E, 0x8D, 0xCD, 0x3D,
+                        0x0,  0x1,  0x76, 0xD4, 0x57, 0xED};
+  uint8_t aad_15[] = {0xE2, 0x1,  0x6,  0xD7, 0xCD, 0xD,  0xF0,
+                      0x76, 0x1E, 0x8D, 0xCD, 0x3D, 0x88, 0xE5,
+                      0x4C, 0x2A, 0x76, 0xD4, 0x57, 0xED};
+  uint8_t key_15[] = {0x69, 0x1D, 0x3E, 0xE9, 0x9,  0xD7, 0xF5, 0x41, 0x67,
+                      0xFD, 0x1C, 0xA0, 0xB5, 0xD7, 0x69, 0x8,  0x1F, 0x2B,
+                      0xDE, 0x1A, 0xEE, 0x65, 0x5F, 0xDB, 0xAB, 0x80, 0xBD,
+                      0x52, 0x95, 0xAE, 0x6B, 0xE7, 0x6B, 0x1F, 0x3C, 0xEB,
+                      0xB,  0xD5, 0xF7, 0x43, 0x65, 0xFF, 0x1E, 0xA2};
+  uint8_t plaintext_15[] = {
+      0x8,  0x0,  0xF,  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+      0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22,
+      0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D,
+      0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x0,  0x4};
+  uint8_t ciphertext_15[] = {
+      0xB6, 0x8F, 0x63, 0x0,  0xC2, 0xE9, 0xAE, 0x83, 0x3B, 0xDC, 0x7,  0xE,
+      0x24, 0x2,  0x1A, 0x34, 0x77, 0x11, 0x8E, 0x78, 0xCC, 0xF8, 0x4E, 0x11,
+      0xA4, 0x85, 0xD8, 0x61, 0x47, 0x6C, 0x30, 0xF,  0x17, 0x53, 0x53, 0xD5,
+      0xCD, 0xF9, 0x20, 0x8,  0xA4, 0xF8, 0x78, 0xE6, 0xCC, 0x35, 0x77, 0x76,
+      0x80, 0x85, 0xC5, 0xA,  0xE,  0x98, 0xFD, 0xA6, 0xCB, 0xB8};
+  vec = {nonce_15, aad_15, key_15, plaintext_15, ciphertext_15,
+         12,       20,     44,     42,           58};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from IEEE 2.5.1 65-byte auth
+  uint8_t nonce_16[] = {0x7C, 0xFD, 0xE9, 0xF9, 0xE3, 0x37,
+                        0x24, 0xC6, 0x89, 0x32, 0xD6, 0x12};
+  uint8_t aad_16[] = {
+      0x84, 0xC5, 0xD5, 0x13, 0xD2, 0xAA, 0xF6, 0xE5, 0xBB, 0xD2, 0x72, 0x77,
+      0x88, 0xE5, 0x23, 0x0,  0x89, 0x32, 0xD6, 0x12, 0x7C, 0xFD, 0xE9, 0xF9,
+      0xE3, 0x37, 0x24, 0xC6, 0x8,  0x0,  0xF,  0x10, 0x11, 0x12, 0x13, 0x14,
+      0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
+      0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C,
+      0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+      0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x0,  0x5};
+  uint8_t key_16[] = {0x1,  0x3F, 0xE0, 0xB,  0x5F, 0x11, 0xBE, 0x7F, 0x86,
+                      0x6D, 0xC,  0xBB, 0xC5, 0x5A, 0x7A, 0x90, 0x0,  0x3E,
+                      0xE1, 0xA,  0x5E, 0x10, 0xBF, 0x7E, 0x87, 0x6C, 0xD,
+                      0xBA, 0xC4, 0x5B, 0x7B, 0x91, 0x3,  0x3D, 0xE2, 0x9,
+                      0x5D, 0x13, 0xBC, 0x7D, 0x84, 0x6F, 0xE,  0xB9};
+  uint8_t plaintext_16[1] = {};
+  uint8_t ciphertext_16[] = {0xCC, 0xA2, 0xE,  0xEC, 0xDA, 0x62, 0x83, 0xF0,
+                             0x9B, 0xB3, 0x54, 0x3D, 0xD9, 0x9E, 0xDB, 0x9B};
+  vec = {nonce_16, aad_16, key_16, plaintext_16, ciphertext_16, 12, 81,
+         44,       0,      16};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from IEEE 2.5.2 65-byte auth
+  uint8_t nonce_17[] = {0x7C, 0xFD, 0xE9, 0xF9, 0xE3, 0x37,
+                        0x24, 0xC6, 0x89, 0x32, 0xD6, 0x12};
+  uint8_t aad_17[] = {
+      0x84, 0xC5, 0xD5, 0x13, 0xD2, 0xAA, 0xF6, 0xE5, 0xBB, 0xD2, 0x72, 0x77,
+      0x88, 0xE5, 0x23, 0x0,  0x89, 0x32, 0xD6, 0x12, 0x7C, 0xFD, 0xE9, 0xF9,
+      0xE3, 0x37, 0x24, 0xC6, 0x8,  0x0,  0xF,  0x10, 0x11, 0x12, 0x13, 0x14,
+      0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
+      0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C,
+      0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+      0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x0,  0x5};
+  uint8_t key_17[] = {0x83, 0xC0, 0x93, 0xB5, 0x8D, 0xE7, 0xFF, 0xE1, 0xC0,
+                      0xDA, 0x92, 0x6A, 0xC4, 0x3F, 0xB3, 0x60, 0x9A, 0xC1,
+                      0xC8, 0xF,  0xEE, 0x1B, 0x62, 0x44, 0x97, 0xEF, 0x94,
+                      0x2E, 0x2F, 0x79, 0xA8, 0x23, 0x81, 0xC2, 0x91, 0xB7,
+                      0x8F, 0xE5, 0xFD, 0xE3, 0xC2, 0xD8, 0x90, 0x68};
+  uint8_t plaintext_17[1] = {};
+  uint8_t ciphertext_17[] = {0xB2, 0x32, 0xCC, 0x1D, 0xA5, 0x11, 0x7B, 0xF1,
+                             0x50, 0x3,  0x73, 0x4F, 0xA5, 0x99, 0xD2, 0x71};
+  vec = {nonce_17, aad_17, key_17, plaintext_17, ciphertext_17, 12, 81,
+         44,       0,      16};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from IEEE  2.6.1 61-byte crypt
+  uint8_t nonce_18[] = {0x7C, 0xFD, 0xE9, 0xF9, 0xE3, 0x37,
+                        0x24, 0xC6, 0x89, 0x32, 0xD6, 0x12};
+  uint8_t aad_18[] = {0x84, 0xC5, 0xD5, 0x13, 0xD2, 0xAA, 0xF6,
+                      0xE5, 0xBB, 0xD2, 0x72, 0x77, 0x88, 0xE5,
+                      0x2F, 0x0,  0x89, 0x32, 0xD6, 0x12, 0x7C,
+                      0xFD, 0xE9, 0xF9, 0xE3, 0x37, 0x24, 0xC6};
+  uint8_t key_18[] = {0x1,  0x3F, 0xE0, 0xB,  0x5F, 0x11, 0xBE, 0x7F, 0x86,
+                      0x6D, 0xC,  0xBB, 0xC5, 0x5A, 0x7A, 0x90, 0x0,  0x3E,
+                      0xE1, 0xA,  0x5E, 0x10, 0xBF, 0x7E, 0x87, 0x6C, 0xD,
+                      0xBA, 0xC4, 0x5B, 0x7B, 0x91, 0x3,  0x3D, 0xE2, 0x9,
+                      0x5D, 0x13, 0xBC, 0x7D, 0x84, 0x6F, 0xE,  0xB9};
+  uint8_t plaintext_18[] = {
+      0x8,  0x0,  0xF,  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+      0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
+      0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A,
+      0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34,
+      0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x0,  0x6};
+  uint8_t ciphertext_18[] = {
+      0xFF, 0x19, 0x10, 0xD3, 0x5A, 0xD7, 0xE5, 0x65, 0x78, 0x90, 0xC7,
+      0xC5, 0x60, 0x14, 0x6F, 0xD0, 0x38, 0x70, 0x7F, 0x20, 0x4B, 0x66,
+      0xED, 0xBC, 0x3D, 0x16, 0x1F, 0x8A, 0xCE, 0x24, 0x4B, 0x98, 0x59,
+      0x21, 0x2,  0x3C, 0x43, 0x6E, 0x3A, 0x1C, 0x35, 0x32, 0xEC, 0xD5,
+      0xD0, 0x9A, 0x5,  0x6D, 0x70, 0xBE, 0x58, 0x3F, 0xD,  0x10, 0x82,
+      0x9D, 0x93, 0x87, 0xD0, 0x7D, 0x33, 0xD8, 0x72, 0xE4, 0x90};
+  vec = {nonce_18, aad_18, key_18, plaintext_18, ciphertext_18,
+         12,       28,     44,     49,           65};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from IEEE 2.6.2 61-byte crypt
+  uint8_t nonce_19[] = {0x7C, 0xFD, 0xE9, 0xF9, 0xE3, 0x37,
+                        0x24, 0xC6, 0x89, 0x32, 0xD6, 0x12};
+  uint8_t aad_19[] = {0x84, 0xC5, 0xD5, 0x13, 0xD2, 0xAA, 0xF6,
+                      0xE5, 0xBB, 0xD2, 0x72, 0x77, 0x88, 0xE5,
+                      0x2F, 0x0,  0x89, 0x32, 0xD6, 0x12, 0x7C,
+                      0xFD, 0xE9, 0xF9, 0xE3, 0x37, 0x24, 0xC6};
+  uint8_t key_19[] = {0x83, 0xC0, 0x93, 0xB5, 0x8D, 0xE7, 0xFF, 0xE1, 0xC0,
+                      0xDA, 0x92, 0x6A, 0xC4, 0x3F, 0xB3, 0x60, 0x9A, 0xC1,
+                      0xC8, 0xF,  0xEE, 0x1B, 0x62, 0x44, 0x97, 0xEF, 0x94,
+                      0x2E, 0x2F, 0x79, 0xA8, 0x23, 0x81, 0xC2, 0x91, 0xB7,
+                      0x8F, 0xE5, 0xFD, 0xE3, 0xC2, 0xD8, 0x90, 0x68};
+  uint8_t plaintext_19[] = {
+      0x8,  0x0,  0xF,  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+      0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
+      0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A,
+      0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34,
+      0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x0,  0x6};
+  uint8_t ciphertext_19[] = {
+      0xD,  0xB4, 0xCF, 0x95, 0x6B, 0x5F, 0x97, 0xEC, 0xA4, 0xEA, 0xB8,
+      0x2A, 0x69, 0x55, 0x30, 0x7F, 0x9A, 0xE0, 0x2A, 0x32, 0xDD, 0x7D,
+      0x93, 0xF8, 0x3D, 0x66, 0xAD, 0x4,  0xE1, 0xCF, 0xDC, 0x51, 0x82,
+      0xAD, 0x12, 0xAB, 0xDE, 0xA5, 0xBB, 0xB6, 0x19, 0xA1, 0xBD, 0x5F,
+      0xB9, 0xA5, 0x73, 0x59, 0xF,  0xBA, 0x90, 0x8E, 0x9C, 0x7A, 0x46,
+      0xC1, 0xF7, 0xBA, 0x9,  0x5,  0xD1, 0xB5, 0x5F, 0xFD, 0xA4};
+  vec = {nonce_19, aad_19, key_19, plaintext_19, ciphertext_19,
+         12,       28,     44,     49,           65};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from IEEE 2.7.1 79-byte crypt
+  uint8_t nonce_20[] = {0x7A, 0xE8, 0xE2, 0xCA, 0x4E, 0xC5,
+                        0x0,  0x1,  0x2E, 0x58, 0x49, 0x5C};
+  uint8_t aad_20[] = {
+      0x68, 0xF2, 0xE7, 0x76, 0x96, 0xCE, 0x7A, 0xE8, 0xE2, 0xCA, 0x4E,
+      0xC5, 0x88, 0xE5, 0x41, 0x0,  0x2E, 0x58, 0x49, 0x5C, 0x8,  0x0,
+      0xF,  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+      0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
+      0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+      0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
+      0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
+      0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x0,  0x7};
+  uint8_t key_20[] = {0x88, 0xEE, 0x8,  0x7F, 0xD9, 0x5D, 0xA9, 0xFB, 0xF6,
+                      0x72, 0x5A, 0xA9, 0xD7, 0x57, 0xB0, 0xCD, 0x89, 0xEF,
+                      0x9,  0x7E, 0xD8, 0x5C, 0xA8, 0xFA, 0xF7, 0x73, 0x5B,
+                      0xA8, 0xD6, 0x56, 0xB1, 0xCC, 0x8A, 0xEC, 0xA,  0x7D,
+                      0xDB, 0x5F, 0xAB, 0xF9, 0xF4, 0x70, 0x58, 0xAB};
+  uint8_t plaintext_20[1] = {};
+  uint8_t ciphertext_20[] = {0x81, 0x3F, 0xE,  0x63, 0xF,  0x96, 0xFB, 0x2D,
+                             0x3,  0xF,  0x58, 0xD8, 0x3F, 0x5C, 0xDF, 0xD0};
+  vec = {nonce_20, aad_20, key_20, plaintext_20, ciphertext_20, 12, 87,
+         44,       0,      16};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from IEEE 2.7.2 79-byte crypt
+  uint8_t nonce_21[] = {0x7A, 0xE8, 0xE2, 0xCA, 0x4E, 0xC5,
+                        0x0,  0x1,  0x2E, 0x58, 0x49, 0x5C};
+  uint8_t aad_21[] = {
+      0x68, 0xF2, 0xE7, 0x76, 0x96, 0xCE, 0x7A, 0xE8, 0xE2, 0xCA, 0x4E,
+      0xC5, 0x88, 0xE5, 0x41, 0x0,  0x2E, 0x58, 0x49, 0x5C, 0x8,  0x0,
+      0xF,  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+      0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
+      0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+      0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
+      0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
+      0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x0,  0x7};
+  uint8_t key_21[] = {0x4C, 0x97, 0x3D, 0xBC, 0x73, 0x64, 0x62, 0x16, 0x74,
+                      0xF8, 0xB5, 0xB8, 0x9E, 0x5C, 0x15, 0x51, 0x1F, 0xCE,
+                      0xD9, 0x21, 0x64, 0x90, 0xFB, 0x1C, 0x1A, 0x2C, 0xAA,
+                      0xF,  0xFE, 0x4,  0x7,  0xE5, 0x4E, 0x95, 0x3F, 0xBE,
+                      0x71, 0x66, 0x60, 0x14, 0x76, 0xFA, 0xB7, 0xBA};
+  uint8_t plaintext_21[1] = {};
+  uint8_t ciphertext_21[] = {0x77, 0xE5, 0xA4, 0x4C, 0x21, 0xEB, 0x7, 0x18,
+                             0x8A, 0xAC, 0xBD, 0x74, 0xD1, 0x98, 0xE, 0x97};
+  vec = {nonce_21, aad_21, key_21, plaintext_21, ciphertext_21, 12, 87,
+         44,       0,      16};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from IEEE 2.8.1 61-byte crypt
+  uint8_t nonce_22[] = {0x7A, 0xE8, 0xE2, 0xCA, 0x4E, 0xC5,
+                        0x0,  0x1,  0x2E, 0x58, 0x49, 0x5C};
+  uint8_t aad_22[] = {0x68, 0xF2, 0xE7, 0x76, 0x96, 0xCE, 0x7A,
+                      0xE8, 0xE2, 0xCA, 0x4E, 0xC5, 0x88, 0xE5,
+                      0x4D, 0x0,  0x2E, 0x58, 0x49, 0x5C};
+  uint8_t key_22[] = {0x88, 0xEE, 0x8,  0x7F, 0xD9, 0x5D, 0xA9, 0xFB, 0xF6,
+                      0x72, 0x5A, 0xA9, 0xD7, 0x57, 0xB0, 0xCD, 0x89, 0xEF,
+                      0x9,  0x7E, 0xD8, 0x5C, 0xA8, 0xFA, 0xF7, 0x73, 0x5B,
+                      0xA8, 0xD6, 0x56, 0xB1, 0xCC, 0x8A, 0xEC, 0xA,  0x7D,
+                      0xDB, 0x5F, 0xAB, 0xF9, 0xF4, 0x70, 0x58, 0xAB};
+  uint8_t plaintext_22[] = {
+      0x8,  0x0,  0xF,  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+      0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22,
+      0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D,
+      0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+      0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43,
+      0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x0,  0x8};
+  uint8_t ciphertext_22[] = {
+      0x95, 0x8E, 0xC3, 0xF6, 0xD6, 0xA,  0xFE, 0xDA, 0x99, 0xEF, 0xD8, 0x88,
+      0xF1, 0x75, 0xE5, 0xFC, 0xD4, 0xC8, 0x7B, 0x9B, 0xCC, 0x5C, 0x2F, 0x54,
+      0x26, 0x25, 0x3A, 0x8B, 0x50, 0x62, 0x96, 0xC8, 0xC4, 0x33, 0x9,  0xAB,
+      0x2A, 0xDB, 0x59, 0x39, 0x46, 0x25, 0x41, 0xD9, 0x5E, 0x80, 0x81, 0x1E,
+      0x4,  0xE7, 0x6,  0xB1, 0x49, 0x8F, 0x2C, 0x40, 0x7C, 0x7F, 0xB2, 0x34,
+      0xF8, 0xCC, 0x1,  0xA6, 0x47, 0x55, 0xE,  0xE6, 0xB5, 0x57, 0xB3, 0x5A,
+      0x7E, 0x39, 0x45, 0x38, 0x18, 0x21, 0xF4};
+  vec = {nonce_22, aad_22, key_22, plaintext_22, ciphertext_22,
+         12,       20,     44,     63,           79};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+
+  // Derived from IEEE 2.8.2 61-byte crypt
+  uint8_t nonce_23[] = {0x7A, 0xE8, 0xE2, 0xCA, 0x4E, 0xC5,
+                        0x0,  0x1,  0x2E, 0x58, 0x49, 0x5C};
+  uint8_t aad_23[] = {0x68, 0xF2, 0xE7, 0x76, 0x96, 0xCE, 0x7A,
+                      0xE8, 0xE2, 0xCA, 0x4E, 0xC5, 0x88, 0xE5,
+                      0x4D, 0x0,  0x2E, 0x58, 0x49, 0x5C};
+  uint8_t key_23[] = {0x4C, 0x97, 0x3D, 0xBC, 0x73, 0x64, 0x62, 0x16, 0x74,
+                      0xF8, 0xB5, 0xB8, 0x9E, 0x5C, 0x15, 0x51, 0x1F, 0xCE,
+                      0xD9, 0x21, 0x64, 0x90, 0xFB, 0x1C, 0x1A, 0x2C, 0xAA,
+                      0xF,  0xFE, 0x4,  0x7,  0xE5, 0x4E, 0x95, 0x3F, 0xBE,
+                      0x71, 0x66, 0x60, 0x14, 0x76, 0xFA, 0xB7, 0xBA};
+  uint8_t plaintext_23[] = {
+      0x8,  0x0,  0xF,  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+      0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22,
+      0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D,
+      0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+      0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43,
+      0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x0,  0x8};
+  uint8_t ciphertext_23[] = {
+      0xB4, 0x4D, 0x7,  0x20, 0x11, 0xCD, 0x36, 0xD2, 0x72, 0xA9, 0xB7, 0xA9,
+      0x8D, 0xB9, 0xAA, 0x90, 0xCB, 0xC5, 0xC6, 0x7B, 0x93, 0xDD, 0xCE, 0x67,
+      0xC8, 0x54, 0x50, 0x32, 0x14, 0xE2, 0xE8, 0x96, 0xEC, 0x7E, 0x9D, 0xB6,
+      0x49, 0xED, 0x4B, 0xCF, 0x6F, 0x85, 0xA,  0xAC, 0x2,  0x23, 0xD0, 0xCF,
+      0x92, 0xC8, 0x3D, 0xB8, 0x7,  0x95, 0xC3, 0xA1, 0x7E, 0xCC, 0x12, 0x48,
+      0xBB, 0x0,  0x59, 0x17, 0x12, 0xB1, 0xAE, 0x71, 0xE2, 0x68, 0x16, 0x41,
+      0x96, 0x25, 0x21, 0x62, 0x81, 0xB,  0x0};
+  vec = {nonce_23, aad_23, key_23, plaintext_23, ciphertext_23,
+         12,       20,     44,     63,           79};
+  gsec_test_verify_crypter_on_test_vector(&vec, /*rekey=*/true);
+}
+
+static void gsec_test_do_vector_tests_nist() {
+  /**
+   * From:
+   * http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/
+   * gcm-revised-spec.pdf
+   */
+
+  /* Test vector 1 */
+  gsec_aead_test_vector* test_vector_1;
+  const uint8_t test_vector_1_key[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                       0x00, 0x00, 0x00, 0x00};
+  const uint8_t test_vector_1_nonce[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+  const uint8_t test_vector_1_aad[1] = {};
+  const uint8_t test_vector_1_plaintext[1] = {};
+  const uint8_t test_vector_1_ciphertext_and_tag[] = {
+      0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61,
+      0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7, 0x45, 0x5a};
+  gsec_aead_malloc_test_vector(
+      &test_vector_1, test_vector_1_key,
+      sizeof(test_vector_1_key) / sizeof(uint8_t), test_vector_1_nonce,
+      sizeof(test_vector_1_nonce) / sizeof(uint8_t), test_vector_1_aad, 0,
+      test_vector_1_plaintext, 0, test_vector_1_ciphertext_and_tag,
+      sizeof(test_vector_1_ciphertext_and_tag) / sizeof(uint8_t));
+  gsec_test_verify_crypter_on_test_vector(test_vector_1);
+  gsec_aead_free_test_vector(test_vector_1);
+
+  /* Test vector 2 */
+  gsec_aead_test_vector* test_vector_2;
+  const uint8_t test_vector_2_key[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                       0x00, 0x00, 0x00, 0x00};
+  const uint8_t test_vector_2_nonce[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+  const uint8_t test_vector_2_aad[1] = {};
+  const uint8_t test_vector_2_plaintext[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                             0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                             0x00, 0x00, 0x00, 0x00};
+  const uint8_t test_vector_2_ciphertext_and_tag[] = {
+      0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92, 0xf3, 0x28, 0xc2,
+      0xb9, 0x71, 0xb2, 0xfe, 0x78, 0xab, 0x6e, 0x47, 0xd4, 0x2c, 0xec,
+      0x13, 0xbd, 0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57, 0xbd, 0xdf};
+  gsec_aead_malloc_test_vector(
+      &test_vector_2, test_vector_2_key,
+      sizeof(test_vector_2_key) / sizeof(uint8_t), test_vector_2_nonce,
+      sizeof(test_vector_2_nonce) / sizeof(uint8_t), test_vector_2_aad, 0,
+      test_vector_2_plaintext,
+      sizeof(test_vector_2_plaintext) / sizeof(uint8_t),
+      test_vector_2_ciphertext_and_tag,
+      sizeof(test_vector_2_ciphertext_and_tag) / sizeof(uint8_t));
+  gsec_test_verify_crypter_on_test_vector(test_vector_2);
+  gsec_aead_free_test_vector(test_vector_2);
+
+  /* Test vector 3 */
+  gsec_aead_test_vector* test_vector_3;
+  const uint8_t test_vector_3_key[] = {0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65,
+                                       0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94,
+                                       0x67, 0x30, 0x83, 0x08};
+  const uint8_t test_vector_3_nonce[] = {0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
+                                         0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88};
+  const uint8_t test_vector_3_aad[1] = {};
+  const uint8_t test_vector_3_plaintext[] = {
+      0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09,
+      0xc5, 0xaf, 0xf5, 0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34,
+      0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, 0x1c,
+      0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24,
+      0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6,
+      0x57, 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55};
+  const uint8_t test_vector_3_ciphertext_and_tag[] = {
+      0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, 0x4b, 0x72, 0x21, 0xb7,
+      0x84, 0xd0, 0xd4, 0x9c, 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
+      0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, 0x21, 0xd5, 0x14, 0xb2,
+      0x54, 0x66, 0x93, 0x1c, 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
+      0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, 0x3d, 0x58, 0xe0, 0x91,
+      0x47, 0x3f, 0x59, 0x85, 0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6,
+      0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4};
+  gsec_aead_malloc_test_vector(
+      &test_vector_3, test_vector_3_key,
+      sizeof(test_vector_3_key) / sizeof(uint8_t), test_vector_3_nonce,
+      sizeof(test_vector_3_nonce) / sizeof(uint8_t), test_vector_3_aad, 0,
+      test_vector_3_plaintext,
+      sizeof(test_vector_3_plaintext) / sizeof(uint8_t),
+      test_vector_3_ciphertext_and_tag,
+      sizeof(test_vector_3_ciphertext_and_tag) / sizeof(uint8_t));
+  gsec_test_verify_crypter_on_test_vector(test_vector_3);
+  gsec_aead_free_test_vector(test_vector_3);
+
+  /* Test vector 4 */
+  gsec_aead_test_vector* test_vector_4;
+  const uint8_t test_vector_4_key[] = {0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65,
+                                       0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94,
+                                       0x67, 0x30, 0x83, 0x08};
+  const uint8_t test_vector_4_nonce[] = {0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
+                                         0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88};
+  const uint8_t test_vector_4_aad[] = {0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe,
+                                       0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad,
+                                       0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2};
+  const uint8_t test_vector_4_plaintext[] = {
+      0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5,
+      0xaf, 0xf5, 0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+      0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95,
+      0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+      0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39};
+  const uint8_t test_vector_4_ciphertext_and_tag[] = {
+      0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, 0x4b, 0x72, 0x21,
+      0xb7, 0x84, 0xd0, 0xd4, 0x9c, 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02,
+      0xa4, 0xe0, 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, 0x21,
+      0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, 0x7d, 0x8f, 0x6a, 0x5a,
+      0xac, 0x84, 0xaa, 0x05, 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac,
+      0x97, 0x3d, 0x58, 0xe0, 0x91, 0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21,
+      0xa5, 0xdb, 0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12, 0x1a, 0x47};
+  gsec_aead_malloc_test_vector(
+      &test_vector_4, test_vector_4_key,
+      sizeof(test_vector_4_key) / sizeof(uint8_t), test_vector_4_nonce,
+      sizeof(test_vector_4_nonce) / sizeof(uint8_t), test_vector_4_aad,
+      sizeof(test_vector_4_aad) / sizeof(uint8_t), test_vector_4_plaintext,
+      sizeof(test_vector_4_plaintext) / sizeof(uint8_t),
+      test_vector_4_ciphertext_and_tag,
+      sizeof(test_vector_4_ciphertext_and_tag) / sizeof(uint8_t));
+  gsec_test_verify_crypter_on_test_vector(test_vector_4);
+  gsec_aead_free_test_vector(test_vector_4);
+}
+
+static void gsec_test_do_vector_tests_ieee() {
+  /**
+   * From:
+   * http://www.ieee802.org/1/files/public/docs2011/
+   * bn-randall-test-vectors-0511-v1.pdf
+   */
+
+  /* 2.1.1 54-byte auth */
+  gsec_aead_test_vector* test_vector_5;
+  const uint8_t test_vector_5_key[] = {0xad, 0x7a, 0x2b, 0xd0, 0x3e, 0xac,
+                                       0x83, 0x5a, 0x6f, 0x62, 0x0f, 0xdc,
+                                       0xb5, 0x06, 0xb3, 0x45};
+  const uint8_t test_vector_5_nonce[] = {0x12, 0x15, 0x35, 0x24, 0xc0, 0x89,
+                                         0x5e, 0x81, 0xb2, 0xc2, 0x84, 0x65};
+  const uint8_t test_vector_5_aad[] = {
+      0xd6, 0x09, 0xb1, 0xf0, 0x56, 0x63, 0x7a, 0x0d, 0x46, 0xdf, 0x99, 0x8d,
+      0x88, 0xe5, 0x22, 0x2a, 0xb2, 0xc2, 0x84, 0x65, 0x12, 0x15, 0x35, 0x24,
+      0xc0, 0x89, 0x5e, 0x81, 0x08, 0x00, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+      0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+      0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
+      0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x00, 0x01};
+  const uint8_t test_vector_5_plaintext[1] = {};
+  const uint8_t test_vector_5_ciphertext_and_tag[] = {
+      0xf0, 0x94, 0x78, 0xa9, 0xb0, 0x90, 0x07, 0xd0,
+      0x6f, 0x46, 0xe9, 0xb6, 0xa1, 0xda, 0x25, 0xdd};
+  gsec_aead_malloc_test_vector(
+      &test_vector_5, test_vector_5_key,
+      sizeof(test_vector_5_key) / sizeof(uint8_t), test_vector_5_nonce,
+      sizeof(test_vector_5_nonce) / sizeof(uint8_t), test_vector_5_aad,
+      sizeof(test_vector_5_aad) / sizeof(uint8_t), test_vector_5_plaintext, 0,
+      test_vector_5_ciphertext_and_tag,
+      sizeof(test_vector_5_ciphertext_and_tag) / sizeof(uint8_t));
+  gsec_test_verify_crypter_on_test_vector(test_vector_5);
+  gsec_aead_free_test_vector(test_vector_5);
+
+  /* 2.1.2 54-byte auth */
+  gsec_aead_test_vector* test_vector_6;
+  const uint8_t test_vector_6_key[] = {
+      0xe3, 0xc0, 0x8a, 0x8f, 0x06, 0xc6, 0xe3, 0xad, 0x95, 0xa7, 0x05,
+      0x57, 0xb2, 0x3f, 0x75, 0x48, 0x3c, 0xe3, 0x30, 0x21, 0xa9, 0xc7,
+      0x2b, 0x70, 0x25, 0x66, 0x62, 0x04, 0xc6, 0x9c, 0x0b, 0x72};
+
+  const uint8_t test_vector_6_nonce[] = {0x12, 0x15, 0x35, 0x24, 0xc0, 0x89,
+                                         0x5e, 0x81, 0xb2, 0xc2, 0x84, 0x65};
+  const uint8_t test_vector_6_aad[] = {
+      0xd6, 0x09, 0xb1, 0xf0, 0x56, 0x63, 0x7a, 0x0d, 0x46, 0xdf, 0x99, 0x8d,
+      0x88, 0xe5, 0x22, 0x2a, 0xb2, 0xc2, 0x84, 0x65, 0x12, 0x15, 0x35, 0x24,
+      0xc0, 0x89, 0x5e, 0x81, 0x08, 0x00, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+      0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+      0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
+      0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x00, 0x01};
+  const uint8_t test_vector_6_plaintext[1] = {};
+  const uint8_t test_vector_6_ciphertext_and_tag[] = {
+      0x2f, 0x0b, 0xc5, 0xaf, 0x40, 0x9e, 0x06, 0xd6,
+      0x09, 0xea, 0x8b, 0x7d, 0x0f, 0xa5, 0xea, 0x50};
+  gsec_aead_malloc_test_vector(
+      &test_vector_6, test_vector_6_key,
+      sizeof(test_vector_6_key) / sizeof(uint8_t), test_vector_6_nonce,
+      sizeof(test_vector_6_nonce) / sizeof(uint8_t), test_vector_6_aad,
+      sizeof(test_vector_6_aad) / sizeof(uint8_t), test_vector_6_plaintext, 0,
+      test_vector_6_ciphertext_and_tag,
+      sizeof(test_vector_6_ciphertext_and_tag) / sizeof(uint8_t));
+  gsec_test_verify_crypter_on_test_vector(test_vector_6);
+  gsec_aead_free_test_vector(test_vector_6);
+
+  /* 2.2.1 60-byte crypt */
+  gsec_aead_test_vector* test_vector_7;
+  const uint8_t test_vector_7_key[] = {0xad, 0x7a, 0x2b, 0xd0, 0x3e, 0xac,
+                                       0x83, 0x5a, 0x6f, 0x62, 0x0f, 0xdc,
+                                       0xb5, 0x06, 0xb3, 0x45};
+
+  const uint8_t test_vector_7_nonce[] = {0x12, 0x15, 0x35, 0x24, 0xc0, 0x89,
+                                         0x5e, 0x81, 0xb2, 0xc2, 0x84, 0x65};
+  const uint8_t test_vector_7_aad[] = {
+      0xd6, 0x09, 0xb1, 0xf0, 0x56, 0x63, 0x7a, 0x0d, 0x46, 0xdf,
+      0x99, 0x8d, 0x88, 0xe5, 0x2e, 0x00, 0xb2, 0xc2, 0x84, 0x65,
+      0x12, 0x15, 0x35, 0x24, 0xc0, 0x89, 0x5e, 0x81};
+  const uint8_t test_vector_7_plaintext[] = {
+      0x08, 0x00, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+      0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
+      0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+      0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x00, 0x02};
+  const uint8_t test_vector_7_ciphertext_and_tag[] = {
+      0x70, 0x1a, 0xfa, 0x1c, 0xc0, 0x39, 0xc0, 0xd7, 0x65, 0x12, 0x8a,
+      0x66, 0x5d, 0xab, 0x69, 0x24, 0x38, 0x99, 0xbf, 0x73, 0x18, 0xcc,
+      0xdc, 0x81, 0xc9, 0x93, 0x1d, 0xa1, 0x7f, 0xbe, 0x8e, 0xdd, 0x7d,
+      0x17, 0xcb, 0x8b, 0x4c, 0x26, 0xfc, 0x81, 0xe3, 0x28, 0x4f, 0x2b,
+      0x7f, 0xba, 0x71, 0x3d, 0x4f, 0x8d, 0x55, 0xe7, 0xd3, 0xf0, 0x6f,
+      0xd5, 0xa1, 0x3c, 0x0c, 0x29, 0xb9, 0xd5, 0xb8, 0x80};
+  gsec_aead_malloc_test_vector(
+      &test_vector_7, test_vector_7_key,
+      sizeof(test_vector_7_key) / sizeof(uint8_t), test_vector_7_nonce,
+      sizeof(test_vector_7_nonce) / sizeof(uint8_t), test_vector_7_aad,
+      sizeof(test_vector_7_aad) / sizeof(uint8_t), test_vector_7_plaintext,
+      sizeof(test_vector_7_plaintext) / sizeof(uint8_t),
+      test_vector_7_ciphertext_and_tag,
+      sizeof(test_vector_7_ciphertext_and_tag) / sizeof(uint8_t));
+  gsec_test_verify_crypter_on_test_vector(test_vector_7);
+  gsec_aead_free_test_vector(test_vector_7);
+
+  /* 2.2.2 60-byte crypt */
+  gsec_aead_test_vector* test_vector_8;
+  const uint8_t test_vector_8_key[] = {
+      0xe3, 0xc0, 0x8a, 0x8f, 0x06, 0xc6, 0xe3, 0xad, 0x95, 0xa7, 0x05,
+      0x57, 0xb2, 0x3f, 0x75, 0x48, 0x3c, 0xe3, 0x30, 0x21, 0xa9, 0xc7,
+      0x2b, 0x70, 0x25, 0x66, 0x62, 0x04, 0xc6, 0x9c, 0x0b, 0x72};
+  const uint8_t test_vector_8_nonce[] = {0x12, 0x15, 0x35, 0x24, 0xc0, 0x89,
+                                         0x5e, 0x81, 0xb2, 0xc2, 0x84, 0x65};
+  const uint8_t test_vector_8_aad[] = {
+      0xd6, 0x09, 0xb1, 0xf0, 0x56, 0x63, 0x7a, 0x0d, 0x46, 0xdf,
+      0x99, 0x8d, 0x88, 0xe5, 0x2e, 0x00, 0xb2, 0xc2, 0x84, 0x65,
+      0x12, 0x15, 0x35, 0x24, 0xc0, 0x89, 0x5e, 0x81};
+  const uint8_t test_vector_8_plaintext[] = {
+      0x08, 0x00, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+      0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
+      0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+      0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x00, 0x02};
+  const uint8_t test_vector_8_ciphertext_and_tag[] = {
+      0xe2, 0x00, 0x6e, 0xb4, 0x2f, 0x52, 0x77, 0x02, 0x2d, 0x9b, 0x19,
+      0x92, 0x5b, 0xc4, 0x19, 0xd7, 0xa5, 0x92, 0x66, 0x6c, 0x92, 0x5f,
+      0xe2, 0xef, 0x71, 0x8e, 0xb4, 0xe3, 0x08, 0xef, 0xea, 0xa7, 0xc5,
+      0x27, 0x3b, 0x39, 0x41, 0x18, 0x86, 0x0a, 0x5b, 0xe2, 0xa9, 0x7f,
+      0x56, 0xab, 0x78, 0x36, 0x5c, 0xa5, 0x97, 0xcd, 0xbb, 0x3e, 0xdb,
+      0x8d, 0x1a, 0x11, 0x51, 0xea, 0x0a, 0xf7, 0xb4, 0x36};
+  gsec_aead_malloc_test_vector(
+      &test_vector_8, test_vector_8_key,
+      sizeof(test_vector_8_key) / sizeof(uint8_t), test_vector_8_nonce,
+      sizeof(test_vector_8_nonce) / sizeof(uint8_t), test_vector_8_aad,
+      sizeof(test_vector_8_aad) / sizeof(uint8_t), test_vector_8_plaintext,
+      sizeof(test_vector_8_plaintext) / sizeof(uint8_t),
+      test_vector_8_ciphertext_and_tag,
+      sizeof(test_vector_8_ciphertext_and_tag) / sizeof(uint8_t));
+  gsec_test_verify_crypter_on_test_vector(test_vector_8);
+  gsec_aead_free_test_vector(test_vector_8);
+
+  /* 2.3.1 60-byte auth */
+  gsec_aead_test_vector* test_vector_9;
+  const uint8_t test_vector_9_key[] = {0x07, 0x1b, 0x11, 0x3b, 0x0c, 0xa7,
+                                       0x43, 0xfe, 0xcc, 0xcf, 0x3d, 0x05,
+                                       0x1f, 0x73, 0x73, 0x82};
+  const uint8_t test_vector_9_nonce[] = {0xf0, 0x76, 0x1e, 0x8d, 0xcd, 0x3d,
+                                         0x00, 0x01, 0x76, 0xd4, 0x57, 0xed};
+  const uint8_t test_vector_9_aad[] = {
+      0xe2, 0x01, 0x06, 0xd7, 0xcd, 0x0d, 0xf0, 0x76, 0x1e, 0x8d, 0xcd, 0x3d,
+      0x88, 0xe5, 0x40, 0x00, 0x76, 0xd4, 0x57, 0xed, 0x08, 0x00, 0x0f, 0x10,
+      0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c,
+      0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+      0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34,
+      0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x00, 0x03};
+  const uint8_t test_vector_9_plaintext[1] = {};
+  const uint8_t test_vector_9_ciphertext_and_tag[] = {
+      0x0c, 0x01, 0x7b, 0xc7, 0x3b, 0x22, 0x7d, 0xfc,
+      0xc9, 0xba, 0xfa, 0x1c, 0x41, 0xac, 0xc3, 0x53};
+  gsec_aead_malloc_test_vector(
+      &test_vector_9, test_vector_9_key,
+      sizeof(test_vector_9_key) / sizeof(uint8_t), test_vector_9_nonce,
+      sizeof(test_vector_9_nonce) / sizeof(uint8_t), test_vector_9_aad,
+      sizeof(test_vector_9_aad) / sizeof(uint8_t), test_vector_9_plaintext, 0,
+      test_vector_9_ciphertext_and_tag,
+      sizeof(test_vector_9_ciphertext_and_tag) / sizeof(uint8_t));
+  gsec_test_verify_crypter_on_test_vector(test_vector_9);
+  gsec_aead_free_test_vector(test_vector_9);
+
+  /* 2.3.2 60-byte auth */
+  gsec_aead_test_vector* test_vector_10;
+  const uint8_t test_vector_10_key[] = {
+      0x69, 0x1d, 0x3e, 0xe9, 0x09, 0xd7, 0xf5, 0x41, 0x67, 0xfd, 0x1c,
+      0xa0, 0xb5, 0xd7, 0x69, 0x08, 0x1f, 0x2b, 0xde, 0x1a, 0xee, 0x65,
+      0x5f, 0xdb, 0xab, 0x80, 0xbd, 0x52, 0x95, 0xae, 0x6b, 0xe7};
+  const uint8_t test_vector_10_nonce[] = {0xf0, 0x76, 0x1e, 0x8d, 0xcd, 0x3d,
+                                          0x00, 0x01, 0x76, 0xd4, 0x57, 0xed};
+  const uint8_t test_vector_10_aad[] = {
+      0xe2, 0x01, 0x06, 0xd7, 0xcd, 0x0d, 0xf0, 0x76, 0x1e, 0x8d, 0xcd, 0x3d,
+      0x88, 0xe5, 0x40, 0x00, 0x76, 0xd4, 0x57, 0xed, 0x08, 0x00, 0x0f, 0x10,
+      0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c,
+      0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+      0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34,
+      0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x00, 0x03};
+  const uint8_t test_vector_10_plaintext[1] = {};
+  const uint8_t test_vector_10_ciphertext_and_tag[] = {
+      0x35, 0x21, 0x7c, 0x77, 0x4b, 0xbc, 0x31, 0xb6,
+      0x31, 0x66, 0xbc, 0xf9, 0xd4, 0xab, 0xed, 0x07};
+  gsec_aead_malloc_test_vector(
+      &test_vector_10, test_vector_10_key,
+      sizeof(test_vector_10_key) / sizeof(uint8_t), test_vector_10_nonce,
+      sizeof(test_vector_10_nonce) / sizeof(uint8_t), test_vector_10_aad,
+      sizeof(test_vector_10_aad) / sizeof(uint8_t), test_vector_10_plaintext, 0,
+      test_vector_10_ciphertext_and_tag,
+      sizeof(test_vector_10_ciphertext_and_tag) / sizeof(uint8_t));
+  gsec_test_verify_crypter_on_test_vector(test_vector_10);
+  gsec_aead_free_test_vector(test_vector_10);
+
+  /* 2.4.1 54-byte crypt */
+  gsec_aead_test_vector* test_vector_11;
+  const uint8_t test_vector_11_key[] = {0x07, 0x1b, 0x11, 0x3b, 0x0c, 0xa7,
+                                        0x43, 0xfe, 0xcc, 0xcf, 0x3d, 0x05,
+                                        0x1f, 0x73, 0x73, 0x82};
+  const uint8_t test_vector_11_nonce[] = {0xf0, 0x76, 0x1e, 0x8d, 0xcd, 0x3d,
+                                          0x00, 0x01, 0x76, 0xd4, 0x57, 0xed};
+  const uint8_t test_vector_11_aad[] = {
+      0xe2, 0x01, 0x06, 0xd7, 0xcd, 0x0d, 0xf0, 0x76, 0x1e, 0x8d,
+      0xcd, 0x3d, 0x88, 0xe5, 0x4c, 0x2a, 0x76, 0xd4, 0x57, 0xed};
+  const uint8_t test_vector_11_plaintext[] = {
+      0x08, 0x00, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+      0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22,
+      0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
+      0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x00, 0x04};
+  const uint8_t test_vector_11_ciphertext_and_tag[] = {
+      0x13, 0xb4, 0xc7, 0x2b, 0x38, 0x9d, 0xc5, 0x01, 0x8e, 0x72, 0xa1, 0x71,
+      0xdd, 0x85, 0xa5, 0xd3, 0x75, 0x22, 0x74, 0xd3, 0xa0, 0x19, 0xfb, 0xca,
+      0xed, 0x09, 0xa4, 0x25, 0xcd, 0x9b, 0x2e, 0x1c, 0x9b, 0x72, 0xee, 0xe7,
+      0xc9, 0xde, 0x7d, 0x52, 0xb3, 0xf3, 0xd6, 0xa5, 0x28, 0x4f, 0x4a, 0x6d,
+      0x3f, 0xe2, 0x2a, 0x5d, 0x6c, 0x2b, 0x96, 0x04, 0x94, 0xc3};
+  gsec_aead_malloc_test_vector(
+      &test_vector_11, test_vector_11_key,
+      sizeof(test_vector_11_key) / sizeof(uint8_t), test_vector_11_nonce,
+      sizeof(test_vector_11_nonce) / sizeof(uint8_t), test_vector_11_aad,
+      sizeof(test_vector_11_aad) / sizeof(uint8_t), test_vector_11_plaintext,
+      sizeof(test_vector_11_plaintext) / sizeof(uint8_t),
+      test_vector_11_ciphertext_and_tag,
+      sizeof(test_vector_11_ciphertext_and_tag) / sizeof(uint8_t));
+  gsec_test_verify_crypter_on_test_vector(test_vector_11);
+  gsec_aead_free_test_vector(test_vector_11);
+
+  /* 2.4.2 54-byte crypt */
+  gsec_aead_test_vector* test_vector_12;
+  const uint8_t test_vector_12_key[] = {
+      0x69, 0x1d, 0x3e, 0xe9, 0x09, 0xd7, 0xf5, 0x41, 0x67, 0xfd, 0x1c,
+      0xa0, 0xb5, 0xd7, 0x69, 0x08, 0x1f, 0x2b, 0xde, 0x1a, 0xee, 0x65,
+      0x5f, 0xdb, 0xab, 0x80, 0xbd, 0x52, 0x95, 0xae, 0x6b, 0xe7};
+  const uint8_t test_vector_12_nonce[] = {0xf0, 0x76, 0x1e, 0x8d, 0xcd, 0x3d,
+                                          0x00, 0x01, 0x76, 0xd4, 0x57, 0xed};
+  const uint8_t test_vector_12_aad[] = {
+      0xe2, 0x01, 0x06, 0xd7, 0xcd, 0x0d, 0xf0, 0x76, 0x1e, 0x8d,
+      0xcd, 0x3d, 0x88, 0xe5, 0x4c, 0x2a, 0x76, 0xd4, 0x57, 0xed};
+  const uint8_t test_vector_12_plaintext[] = {
+      0x08, 0x00, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+      0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22,
+      0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
+      0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x00, 0x04};
+  const uint8_t test_vector_12_ciphertext_and_tag[] = {
+      0xc1, 0x62, 0x3f, 0x55, 0x73, 0x0c, 0x93, 0x53, 0x30, 0x97, 0xad, 0xda,
+      0xd2, 0x56, 0x64, 0x96, 0x61, 0x25, 0x35, 0x2b, 0x43, 0xad, 0xac, 0xbd,
+      0x61, 0xc5, 0xef, 0x3a, 0xc9, 0x0b, 0x5b, 0xee, 0x92, 0x9c, 0xe4, 0x63,
+      0x0e, 0xa7, 0x9f, 0x6c, 0xe5, 0x19, 0x12, 0xaf, 0x39, 0xc2, 0xd1, 0xfd,
+      0xc2, 0x05, 0x1f, 0x8b, 0x7b, 0x3c, 0x9d, 0x39, 0x7e, 0xf2};
+  gsec_aead_malloc_test_vector(
+      &test_vector_12, test_vector_12_key,
+      sizeof(test_vector_12_key) / sizeof(uint8_t), test_vector_12_nonce,
+      sizeof(test_vector_12_nonce) / sizeof(uint8_t), test_vector_12_aad,
+      sizeof(test_vector_12_aad) / sizeof(uint8_t), test_vector_12_plaintext,
+      sizeof(test_vector_12_plaintext) / sizeof(uint8_t),
+      test_vector_12_ciphertext_and_tag,
+      sizeof(test_vector_12_ciphertext_and_tag) / sizeof(uint8_t));
+  gsec_test_verify_crypter_on_test_vector(test_vector_12);
+  gsec_aead_free_test_vector(test_vector_12);
+
+  /* 2.5.1 65-byte auth */
+  gsec_aead_test_vector* test_vector_13;
+  const uint8_t test_vector_13_key[] = {0x01, 0x3f, 0xe0, 0x0b, 0x5f, 0x11,
+                                        0xbe, 0x7f, 0x86, 0x6d, 0x0c, 0xbb,
+                                        0xc5, 0x5a, 0x7a, 0x90};
+  const uint8_t test_vector_13_nonce[] = {0x7c, 0xfd, 0xe9, 0xf9, 0xe3, 0x37,
+                                          0x24, 0xc6, 0x89, 0x32, 0xd6, 0x12};
+  const uint8_t test_vector_13_aad[] = {
+      0x84, 0xc5, 0xd5, 0x13, 0xd2, 0xaa, 0xf6, 0xe5, 0xbb, 0xd2, 0x72, 0x77,
+      0x88, 0xe5, 0x23, 0x00, 0x89, 0x32, 0xd6, 0x12, 0x7c, 0xfd, 0xe9, 0xf9,
+      0xe3, 0x37, 0x24, 0xc6, 0x08, 0x00, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+      0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+      0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
+      0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+      0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x00, 0x05};
+  const uint8_t test_vector_13_plaintext[1] = {};
+  const uint8_t test_vector_13_ciphertext_and_tag[] = {
+      0x21, 0x78, 0x67, 0xe5, 0x0c, 0x2d, 0xad, 0x74,
+      0xc2, 0x8c, 0x3b, 0x50, 0xab, 0xdf, 0x69, 0x5a};
+  gsec_aead_malloc_test_vector(
+      &test_vector_13, test_vector_13_key,
+      sizeof(test_vector_13_key) / sizeof(uint8_t), test_vector_13_nonce,
+      sizeof(test_vector_13_nonce) / sizeof(uint8_t), test_vector_13_aad,
+      sizeof(test_vector_13_aad) / sizeof(uint8_t), test_vector_13_plaintext, 0,
+      test_vector_13_ciphertext_and_tag,
+      sizeof(test_vector_13_ciphertext_and_tag) / sizeof(uint8_t));
+  gsec_test_verify_crypter_on_test_vector(test_vector_13);
+  gsec_aead_free_test_vector(test_vector_13);
+
+  /* 2.5.2 65-byte auth */
+  gsec_aead_test_vector* test_vector_14;
+  const uint8_t test_vector_14_key[] = {
+      0x83, 0xc0, 0x93, 0xb5, 0x8d, 0xe7, 0xff, 0xe1, 0xc0, 0xda, 0x92,
+      0x6a, 0xc4, 0x3f, 0xb3, 0x60, 0x9a, 0xc1, 0xc8, 0x0f, 0xee, 0x1b,
+      0x62, 0x44, 0x97, 0xef, 0x94, 0x2e, 0x2f, 0x79, 0xa8, 0x23};
+  const uint8_t test_vector_14_nonce[] = {0x7c, 0xfd, 0xe9, 0xf9, 0xe3, 0x37,
+                                          0x24, 0xc6, 0x89, 0x32, 0xd6, 0x12};
+  const uint8_t test_vector_14_aad[] = {
+      0x84, 0xc5, 0xd5, 0x13, 0xd2, 0xaa, 0xf6, 0xe5, 0xbb, 0xd2, 0x72, 0x77,
+      0x88, 0xe5, 0x23, 0x00, 0x89, 0x32, 0xd6, 0x12, 0x7c, 0xfd, 0xe9, 0xf9,
+      0xe3, 0x37, 0x24, 0xc6, 0x08, 0x00, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+      0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+      0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
+      0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+      0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x00, 0x05};
+  const uint8_t test_vector_14_plaintext[1] = {};
+  const uint8_t test_vector_14_ciphertext_and_tag[] = {
+      0x6e, 0xe1, 0x60, 0xe8, 0xfa, 0xec, 0xa4, 0xb3,
+      0x6c, 0x86, 0xb2, 0x34, 0x92, 0x0c, 0xa9, 0x75};
+  gsec_aead_malloc_test_vector(
+      &test_vector_14, test_vector_14_key,
+      sizeof(test_vector_14_key) / sizeof(uint8_t), test_vector_14_nonce,
+      sizeof(test_vector_14_nonce) / sizeof(uint8_t), test_vector_14_aad,
+      sizeof(test_vector_14_aad) / sizeof(uint8_t), test_vector_14_plaintext, 0,
+      test_vector_14_ciphertext_and_tag,
+      sizeof(test_vector_14_ciphertext_and_tag) / sizeof(uint8_t));
+  gsec_test_verify_crypter_on_test_vector(test_vector_14);
+  gsec_aead_free_test_vector(test_vector_14);
+
+  /* 2.6.1 61-byte crypt */
+  gsec_aead_test_vector* test_vector_15;
+  const uint8_t test_vector_15_key[] = {0x01, 0x3f, 0xe0, 0x0b, 0x5f, 0x11,
+                                        0xbe, 0x7f, 0x86, 0x6d, 0x0c, 0xbb,
+                                        0xc5, 0x5a, 0x7a, 0x90};
+  const uint8_t test_vector_15_nonce[] = {0x7c, 0xfd, 0xe9, 0xf9, 0xe3, 0x37,
+                                          0x24, 0xc6, 0x89, 0x32, 0xd6, 0x12};
+  const uint8_t test_vector_15_aad[] = {
+      0x84, 0xc5, 0xd5, 0x13, 0xd2, 0xaa, 0xf6, 0xe5, 0xbb, 0xd2,
+      0x72, 0x77, 0x88, 0xe5, 0x2f, 0x00, 0x89, 0x32, 0xd6, 0x12,
+      0x7c, 0xfd, 0xe9, 0xf9, 0xe3, 0x37, 0x24, 0xc6};
+  const uint8_t test_vector_15_plaintext[] = {
+      0x08, 0x00, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+      0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+      0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
+      0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34,
+      0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x00, 0x06};
+  const uint8_t test_vector_15_ciphertext_and_tag[] = {
+      0x3a, 0x4d, 0xe6, 0xfa, 0x32, 0x19, 0x10, 0x14, 0xdb, 0xb3, 0x03,
+      0xd9, 0x2e, 0xe3, 0xa9, 0xe8, 0xa1, 0xb5, 0x99, 0xc1, 0x4d, 0x22,
+      0xfb, 0x08, 0x00, 0x96, 0xe1, 0x38, 0x11, 0x81, 0x6a, 0x3c, 0x9c,
+      0x9b, 0xcf, 0x7c, 0x1b, 0x9b, 0x96, 0xda, 0x80, 0x92, 0x04, 0xe2,
+      0x9d, 0x0e, 0x2a, 0x76, 0x42, 0xbf, 0xd3, 0x10, 0xa4, 0x83, 0x7c,
+      0x81, 0x6c, 0xcf, 0xa5, 0xac, 0x23, 0xab, 0x00, 0x39, 0x88};
+  gsec_aead_malloc_test_vector(
+      &test_vector_15, test_vector_15_key,
+      sizeof(test_vector_15_key) / sizeof(uint8_t), test_vector_15_nonce,
+      sizeof(test_vector_15_nonce) / sizeof(uint8_t), test_vector_15_aad,
+      sizeof(test_vector_15_aad) / sizeof(uint8_t), test_vector_15_plaintext,
+      sizeof(test_vector_15_plaintext) / sizeof(uint8_t),
+      test_vector_15_ciphertext_and_tag,
+      sizeof(test_vector_15_ciphertext_and_tag) / sizeof(uint8_t));
+  gsec_test_verify_crypter_on_test_vector(test_vector_15);
+  gsec_aead_free_test_vector(test_vector_15);
+
+  /* 2.6.2 61-byte crypt */
+  gsec_aead_test_vector* test_vector_16;
+  const uint8_t test_vector_16_key[] = {
+      0x83, 0xc0, 0x93, 0xb5, 0x8d, 0xe7, 0xff, 0xe1, 0xc0, 0xda, 0x92,
+      0x6a, 0xc4, 0x3f, 0xb3, 0x60, 0x9a, 0xc1, 0xc8, 0x0f, 0xee, 0x1b,
+      0x62, 0x44, 0x97, 0xef, 0x94, 0x2e, 0x2f, 0x79, 0xa8, 0x23};
+  const uint8_t test_vector_16_nonce[] = {0x7c, 0xfd, 0xe9, 0xf9, 0xe3, 0x37,
+                                          0x24, 0xc6, 0x89, 0x32, 0xd6, 0x12};
+  const uint8_t test_vector_16_aad[] = {
+      0x84, 0xc5, 0xd5, 0x13, 0xd2, 0xaa, 0xf6, 0xe5, 0xbb, 0xd2,
+      0x72, 0x77, 0x88, 0xe5, 0x2f, 0x00, 0x89, 0x32, 0xd6, 0x12,
+      0x7c, 0xfd, 0xe9, 0xf9, 0xe3, 0x37, 0x24, 0xc6};
+  const uint8_t test_vector_16_plaintext[] = {
+      0x08, 0x00, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+      0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+      0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
+      0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34,
+      0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x00, 0x06};
+  const uint8_t test_vector_16_ciphertext_and_tag[] = {
+      0x11, 0x02, 0x22, 0xff, 0x80, 0x50, 0xcb, 0xec, 0xe6, 0x6a, 0x81,
+      0x3a, 0xd0, 0x9a, 0x73, 0xed, 0x7a, 0x9a, 0x08, 0x9c, 0x10, 0x6b,
+      0x95, 0x93, 0x89, 0x16, 0x8e, 0xd6, 0xe8, 0x69, 0x8e, 0xa9, 0x02,
+      0xeb, 0x12, 0x77, 0xdb, 0xec, 0x2e, 0x68, 0xe4, 0x73, 0x15, 0x5a,
+      0x15, 0xa7, 0xda, 0xee, 0xd4, 0xa1, 0x0f, 0x4e, 0x05, 0x13, 0x9c,
+      0x23, 0xdf, 0x00, 0xb3, 0xaa, 0xdc, 0x71, 0xf0, 0x59, 0x6a};
+  gsec_aead_malloc_test_vector(
+      &test_vector_16, test_vector_16_key,
+      sizeof(test_vector_16_key) / sizeof(uint8_t), test_vector_16_nonce,
+      sizeof(test_vector_16_nonce) / sizeof(uint8_t), test_vector_16_aad,
+      sizeof(test_vector_16_aad) / sizeof(uint8_t), test_vector_16_plaintext,
+      sizeof(test_vector_16_plaintext) / sizeof(uint8_t),
+      test_vector_16_ciphertext_and_tag,
+      sizeof(test_vector_16_ciphertext_and_tag) / sizeof(uint8_t));
+  gsec_test_verify_crypter_on_test_vector(test_vector_16);
+  gsec_aead_free_test_vector(test_vector_16);
+
+  /* 2.7.1 79-byte crypt */
+  gsec_aead_test_vector* test_vector_17;
+  const uint8_t test_vector_17_key[] = {0x88, 0xee, 0x08, 0x7f, 0xd9, 0x5d,
+                                        0xa9, 0xfb, 0xf6, 0x72, 0x5a, 0xa9,
+                                        0xd7, 0x57, 0xb0, 0xcd};
+  const uint8_t test_vector_17_nonce[] = {0x7a, 0xe8, 0xe2, 0xca, 0x4e, 0xc5,
+                                          0x00, 0x01, 0x2e, 0x58, 0x49, 0x5c};
+  const uint8_t test_vector_17_aad[] = {
+      0x68, 0xf2, 0xe7, 0x76, 0x96, 0xce, 0x7a, 0xe8, 0xe2, 0xca, 0x4e,
+      0xc5, 0x88, 0xe5, 0x41, 0x00, 0x2e, 0x58, 0x49, 0x5c, 0x08, 0x00,
+      0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+      0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
+      0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+      0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a,
+      0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
+      0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x00, 0x07};
+  const uint8_t test_vector_17_plaintext[1] = {};
+  const uint8_t test_vector_17_ciphertext_and_tag[] = {
+      0x07, 0x92, 0x2b, 0x8e, 0xbc, 0xf1, 0x0b, 0xb2,
+      0x29, 0x75, 0x88, 0xca, 0x4c, 0x61, 0x45, 0x23};
+  gsec_aead_malloc_test_vector(
+      &test_vector_17, test_vector_17_key,
+      sizeof(test_vector_17_key) / sizeof(uint8_t), test_vector_17_nonce,
+      sizeof(test_vector_17_nonce) / sizeof(uint8_t), test_vector_17_aad,
+      sizeof(test_vector_17_aad) / sizeof(uint8_t), test_vector_17_plaintext, 0,
+      test_vector_17_ciphertext_and_tag,
+      sizeof(test_vector_17_ciphertext_and_tag) / sizeof(uint8_t));
+  gsec_test_verify_crypter_on_test_vector(test_vector_17);
+  gsec_aead_free_test_vector(test_vector_17);
+
+  /* 2.7.2 79-byte crypt */
+  gsec_aead_test_vector* test_vector_18;
+  const uint8_t test_vector_18_key[] = {
+      0x4c, 0x97, 0x3d, 0xbc, 0x73, 0x64, 0x62, 0x16, 0x74, 0xf8, 0xb5,
+      0xb8, 0x9e, 0x5c, 0x15, 0x51, 0x1f, 0xce, 0xd9, 0x21, 0x64, 0x90,
+      0xfb, 0x1c, 0x1a, 0x2c, 0xaa, 0x0f, 0xfe, 0x04, 0x07, 0xe5};
+  const uint8_t test_vector_18_nonce[] = {0x7a, 0xe8, 0xe2, 0xca, 0x4e, 0xc5,
+                                          0x00, 0x01, 0x2e, 0x58, 0x49, 0x5c};
+  const uint8_t test_vector_18_aad[] = {
+      0x68, 0xf2, 0xe7, 0x76, 0x96, 0xce, 0x7a, 0xe8, 0xe2, 0xca, 0x4e,
+      0xc5, 0x88, 0xe5, 0x41, 0x00, 0x2e, 0x58, 0x49, 0x5c, 0x08, 0x00,
+      0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+      0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
+      0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+      0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a,
+      0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
+      0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x00, 0x07};
+  const uint8_t test_vector_18_plaintext[1] = {};
+  const uint8_t test_vector_18_ciphertext_and_tag[] = {
+      0x00, 0xbd, 0xa1, 0xb7, 0xe8, 0x76, 0x08, 0xbc,
+      0xbf, 0x47, 0x0f, 0x12, 0x15, 0x7f, 0x4c, 0x07};
+  gsec_aead_malloc_test_vector(
+      &test_vector_18, test_vector_18_key,
+      sizeof(test_vector_18_key) / sizeof(uint8_t), test_vector_18_nonce,
+      sizeof(test_vector_18_nonce) / sizeof(uint8_t), test_vector_18_aad,
+      sizeof(test_vector_18_aad) / sizeof(uint8_t), test_vector_18_plaintext, 0,
+      test_vector_18_ciphertext_and_tag,
+      sizeof(test_vector_18_ciphertext_and_tag) / sizeof(uint8_t));
+  gsec_test_verify_crypter_on_test_vector(test_vector_18);
+  gsec_aead_free_test_vector(test_vector_18);
+
+  /* 2.8.1 61-byte crypt */
+  gsec_aead_test_vector* test_vector_19;
+  const uint8_t test_vector_19_key[] = {0x88, 0xee, 0x08, 0x7f, 0xd9, 0x5d,
+                                        0xa9, 0xfb, 0xf6, 0x72, 0x5a, 0xa9,
+                                        0xd7, 0x57, 0xb0, 0xcd};
+  const uint8_t test_vector_19_nonce[] = {0x7a, 0xe8, 0xe2, 0xca, 0x4e, 0xc5,
+                                          0x00, 0x01, 0x2e, 0x58, 0x49, 0x5c};
+  const uint8_t test_vector_19_aad[] = {
+      0x68, 0xf2, 0xe7, 0x76, 0x96, 0xce, 0x7a, 0xe8, 0xe2, 0xca,
+      0x4e, 0xc5, 0x88, 0xe5, 0x4d, 0x00, 0x2e, 0x58, 0x49, 0x5c};
+  const uint8_t test_vector_19_plaintext[] = {
+      0x08, 0x00, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+      0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22,
+      0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
+      0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+      0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43,
+      0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x00, 0x08};
+  const uint8_t test_vector_19_ciphertext_and_tag[] = {
+      0xc3, 0x1f, 0x53, 0xd9, 0x9e, 0x56, 0x87, 0xf7, 0x36, 0x51, 0x19, 0xb8,
+      0x32, 0xd2, 0xaa, 0xe7, 0x07, 0x41, 0xd5, 0x93, 0xf1, 0xf9, 0xe2, 0xab,
+      0x34, 0x55, 0x77, 0x9b, 0x07, 0x8e, 0xb8, 0xfe, 0xac, 0xdf, 0xec, 0x1f,
+      0x8e, 0x3e, 0x52, 0x77, 0xf8, 0x18, 0x0b, 0x43, 0x36, 0x1f, 0x65, 0x12,
+      0xad, 0xb1, 0x6d, 0x2e, 0x38, 0x54, 0x8a, 0x2c, 0x71, 0x9d, 0xba, 0x72,
+      0x28, 0xd8, 0x40, 0x88, 0xf8, 0x75, 0x7a, 0xdb, 0x8a, 0xa7, 0x88, 0xd8,
+      0xf6, 0x5a, 0xd6, 0x68, 0xbe, 0x70, 0xe7};
+  gsec_aead_malloc_test_vector(
+      &test_vector_19, test_vector_19_key,
+      sizeof(test_vector_19_key) / sizeof(uint8_t), test_vector_19_nonce,
+      sizeof(test_vector_19_nonce) / sizeof(uint8_t), test_vector_19_aad,
+      sizeof(test_vector_19_aad) / sizeof(uint8_t), test_vector_19_plaintext,
+      sizeof(test_vector_19_plaintext) / sizeof(uint8_t),
+      test_vector_19_ciphertext_and_tag,
+      sizeof(test_vector_19_ciphertext_and_tag) / sizeof(uint8_t));
+  gsec_test_verify_crypter_on_test_vector(test_vector_19);
+  gsec_aead_free_test_vector(test_vector_19);
+
+  /* 2.8.2 61-byte crypt */
+  gsec_aead_test_vector* test_vector_20;
+  const uint8_t test_vector_20_key[] = {
+      0x4c, 0x97, 0x3d, 0xbc, 0x73, 0x64, 0x62, 0x16, 0x74, 0xf8, 0xb5,
+      0xb8, 0x9e, 0x5c, 0x15, 0x51, 0x1f, 0xce, 0xd9, 0x21, 0x64, 0x90,
+      0xfb, 0x1c, 0x1a, 0x2c, 0xaa, 0x0f, 0xfe, 0x04, 0x07, 0xe5};
+  const uint8_t test_vector_20_nonce[] = {0x7a, 0xe8, 0xe2, 0xca, 0x4e, 0xc5,
+                                          0x00, 0x01, 0x2e, 0x58, 0x49, 0x5c};
+  const uint8_t test_vector_20_aad[] = {
+      0x68, 0xf2, 0xe7, 0x76, 0x96, 0xce, 0x7a, 0xe8, 0xe2, 0xca,
+      0x4e, 0xc5, 0x88, 0xe5, 0x4d, 0x00, 0x2e, 0x58, 0x49, 0x5c};
+  const uint8_t test_vector_20_plaintext[] = {
+      0x08, 0x00, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+      0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22,
+      0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
+      0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+      0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43,
+      0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x00, 0x08};
+  const uint8_t test_vector_20_ciphertext_and_tag[] = {
+      0xba, 0x8a, 0xe3, 0x1b, 0xc5, 0x06, 0x48, 0x6d, 0x68, 0x73, 0xe4, 0xfc,
+      0xe4, 0x60, 0xe7, 0xdc, 0x57, 0x59, 0x1f, 0xf0, 0x06, 0x11, 0xf3, 0x1c,
+      0x38, 0x34, 0xfe, 0x1c, 0x04, 0xad, 0x80, 0xb6, 0x68, 0x03, 0xaf, 0xcf,
+      0x5b, 0x27, 0xe6, 0x33, 0x3f, 0xa6, 0x7c, 0x99, 0xda, 0x47, 0xc2, 0xf0,
+      0xce, 0xd6, 0x8d, 0x53, 0x1b, 0xd7, 0x41, 0xa9, 0x43, 0xcf, 0xf7, 0xa6,
+      0x71, 0x3b, 0xd0, 0x26, 0x11, 0xcd, 0x7d, 0xaa, 0x01, 0xd6, 0x1c, 0x5c,
+      0x88, 0x6d, 0xc1, 0xa8, 0x17, 0x01, 0x07};
+  gsec_aead_malloc_test_vector(
+      &test_vector_20, test_vector_20_key,
+      sizeof(test_vector_20_key) / sizeof(uint8_t), test_vector_20_nonce,
+      sizeof(test_vector_20_nonce) / sizeof(uint8_t), test_vector_20_aad,
+      sizeof(test_vector_20_aad) / sizeof(uint8_t), test_vector_20_plaintext,
+      sizeof(test_vector_20_plaintext) / sizeof(uint8_t),
+      test_vector_20_ciphertext_and_tag,
+      sizeof(test_vector_20_ciphertext_and_tag) / sizeof(uint8_t));
+  gsec_test_verify_crypter_on_test_vector(test_vector_20);
+  gsec_aead_free_test_vector(test_vector_20);
+}
+
+int main(int argc, char** argv) {
+  grpc_init();
+  gsec_test_do_generic_crypter_tests();
+  gsec_test_do_vector_tests_nist();
+  gsec_test_do_vector_tests_ieee();
+  gsec_test_do_vector_tests_rekey_nist();
+  gsec_test_do_vector_tests_rekey_ieee();
+  grpc_shutdown();
+  return 0;
+}
diff --git a/test/core/tsi/alts/crypt/gsec_test_util.cc b/test/core/tsi/alts/crypt/gsec_test_util.cc
new file mode 100644
index 0000000..c682fb8
--- /dev/null
+++ b/test/core/tsi/alts/crypt/gsec_test_util.cc
@@ -0,0 +1,89 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "test/core/tsi/alts/crypt/gsec_test_util.h"
+
+#include <time.h>
+
+#include <grpc/support/alloc.h>
+
+void gsec_test_random_bytes(uint8_t* bytes, size_t length) {
+  srand(time(nullptr));
+  size_t ind;
+  for (ind = 0; ind < length; ind++) {
+    bytes[ind] = static_cast<uint8_t>(rand() % 255 + 1);
+  }
+}
+
+void gsec_test_random_array(uint8_t** bytes, size_t length) {
+  if (bytes != nullptr) {
+    *bytes = static_cast<uint8_t*>(gpr_malloc(length));
+    gsec_test_random_bytes(*bytes, length);
+  } else {
+    fprintf(stderr, "bytes buffer is nullptr in gsec_test_random_array().");
+    abort();
+  }
+}
+
+uint32_t gsec_test_bias_random_uint32(uint32_t max_length) {
+  uint32_t value;
+  gsec_test_random_bytes((uint8_t*)(&value), sizeof(value));
+  return value % max_length;
+}
+
+void gsec_test_copy(const uint8_t* src, uint8_t** des, size_t source_len) {
+  if (src != nullptr && des != nullptr) {
+    *des = static_cast<uint8_t*>(gpr_malloc(source_len));
+    memcpy(*des, src, source_len);
+  } else {
+    fprintf(stderr, "Either src or des buffer is nullptr in gsec_test_copy().");
+    abort();
+  }
+}
+
+void gsec_test_copy_and_alter_random_byte(const uint8_t* src, uint8_t** des,
+                                          size_t source_len) {
+  if (src != nullptr && des != nullptr) {
+    *des = static_cast<uint8_t*>(gpr_malloc(source_len));
+    memcpy(*des, src, source_len);
+    uint32_t offset;
+    offset = gsec_test_bias_random_uint32(static_cast<uint32_t>(source_len));
+    (*(*des + offset))++;
+  } else {
+    fprintf(stderr,
+            "Either src or des is nullptr in "
+            "gsec_test_copy_and_alter_random_byte().");
+    abort();
+  }
+}
+
+int gsec_test_expect_compare_code_and_substr(grpc_status_code status1,
+                                             grpc_status_code status2,
+                                             const char* msg1,
+                                             const char* msg2) {
+  int failure = 1;
+  if (status1 != status2) {
+    fprintf(stderr, "Status %d does not equal %d.\n", status1, status2);
+    failure = 0;
+  }
+  if (strstr(msg1, msg2) == nullptr) {
+    fprintf(stderr, "Status message <%s> does not contain <%s>.\n", msg1, msg2);
+    failure = 0;
+  }
+  return failure;
+}
diff --git a/test/core/tsi/alts/crypt/gsec_test_util.h b/test/core/tsi/alts/crypt/gsec_test_util.h
new file mode 100644
index 0000000..1bd7800
--- /dev/null
+++ b/test/core/tsi/alts/crypt/gsec_test_util.h
@@ -0,0 +1,89 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_TEST_CORE_TSI_ALTS_CRYPT_GSEC_TEST_UTIL_H_
+#define GRPC_TEST_CORE_TSI_ALTS_CRYPT_GSEC_TEST_UTIL_H_
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/grpc.h>
+
+/**
+ * This method returns random bytes of certain length.
+ *
+ * - bytes: buffer to hold random bytes.
+ * - length: length of buffer to be populated.
+ */
+void gsec_test_random_bytes(uint8_t* bytes, size_t length);
+
+/**
+ * This method returns an array of random bytes.
+ *
+ * - bytes: array to hold random bytes.
+ * - length: length of array to be populated.
+ */
+void gsec_test_random_array(uint8_t** bytes, size_t length);
+
+/**
+ * This method returns a uint32 that's not quite uniformly random, but good
+ * enough for tests.
+ *
+ * - max_length: a max value the returned random number can choose.
+ */
+uint32_t gsec_test_bias_random_uint32(uint32_t max_length);
+
+/**
+ * This method copies data from a source to a destination buffer.
+ *
+ * - src: a source buffer.
+ * - des: a destination buffer.
+ * - length: the length of source buffer to be copied from its beginning.
+ */
+void gsec_test_copy(const uint8_t* src, uint8_t** des, size_t length);
+
+/**
+ * This method copies data from a source to a destination buffer, and flips one
+ * byte in the destination buffer randomly.
+ *
+ * - src: a source buffer.
+ * - des: a destination buffer.
+ * - length: the length of source buffer to be copied from its beginning.
+ */
+void gsec_test_copy_and_alter_random_byte(const uint8_t* src, uint8_t** des,
+                                          size_t source_len);
+
+/**
+ * This method compares two grpc_status_code values, and verifies if one string
+ * is a substring of the other.
+ *
+ * - status1: the first grpc_status_code to be compared.
+ * - status2: the second grpc_status_code to be compared.
+ * - msg1: a string to be scanned.
+ * - msg2: a small string to be searched within msg1.
+ *
+ * If both checks succeed, the method returns 1 and otherwise, it returns 0.
+ */
+int gsec_test_expect_compare_code_and_substr(grpc_status_code status1,
+                                             grpc_status_code status2,
+                                             const char* msg1,
+                                             const char* msg2);
+
+#endif  // GRPC_TEST_CORE_TSI_ALTS_CRYPT_GSEC_TEST_UTIL_H_ */
diff --git a/test/core/tsi/alts/frame_protector/BUILD b/test/core/tsi/alts/frame_protector/BUILD
new file mode 100644
index 0000000..94c2ab3
--- /dev/null
+++ b/test/core/tsi/alts/frame_protector/BUILD
@@ -0,0 +1,71 @@
+# Copyright 2018 gRPC authors.
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_package")
+
+licenses(["notice"])  # Apache v2
+
+grpc_package(name = "frame_protector")
+
+grpc_cc_test(
+    name = "alts_counter_test",
+    srcs = ["alts_counter_test.cc"],
+    language = "C++",
+    deps = [
+        "//:alts_frame_protector",
+        "//:gpr",
+        "//:grpc",
+        "//test/core/tsi/alts/crypt:alts_crypt_test_util",
+    ],
+)
+
+grpc_cc_test(
+    name = "alts_crypter_test",
+    srcs = ["alts_crypter_test.cc"],
+    language = "C++",
+    deps = [
+        "//:alts_frame_protector",
+        "//:gpr",
+        "//:grpc",
+        "//test/core/tsi/alts/crypt:alts_crypt_test_util",
+    ],
+)
+
+grpc_cc_test(
+    name = "alts_frame_protector_test",
+    srcs = ["alts_frame_protector_test.cc"],
+    language = "C++",
+    deps = [
+        "//:alts_frame_protector",
+        "//:gpr",
+        "//:grpc",
+        "//:tsi",
+        "//:tsi_interface",
+        "//test/core/tsi/alts/crypt:alts_crypt_test_util",
+        "//test/core/tsi:transport_security_test_lib",
+    ],
+)
+
+grpc_cc_test(
+    name = "frame_handler_test",
+    srcs = ["frame_handler_test.cc"],
+    language = "C++",
+    deps = [
+        "//:alts_frame_protector",
+        "//:gpr",
+        "//:gpr_base",
+        "//:grpc",
+        "//test/core/tsi/alts/crypt:alts_crypt_test_util",
+    ],
+)
diff --git a/test/core/tsi/alts/frame_protector/alts_counter_test.cc b/test/core/tsi/alts/frame_protector/alts_counter_test.cc
new file mode 100644
index 0000000..49ff821
--- /dev/null
+++ b/test/core/tsi/alts/frame_protector/alts_counter_test.cc
@@ -0,0 +1,180 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/tsi/alts/frame_protector/alts_counter.h"
+#include "test/core/tsi/alts/crypt/gsec_test_util.h"
+
+const size_t kSmallCounterSize = 4;
+const size_t kSmallOverflowSize = 1;
+const size_t kGcmCounterSize = 12;
+const size_t kGcmOverflowSize = 5;
+
+static bool do_bytes_represent_client(alts_counter* ctr, unsigned char* counter,
+                                      size_t size) {
+  return (ctr->counter[size - 1] & 0x80) == 0x80;
+}
+
+static void alts_counter_test_input_sanity_check(size_t counter_size,
+                                                 size_t overflow_size) {
+  alts_counter* ctr = nullptr;
+  char* error_details = nullptr;
+
+  /* Input sanity check on alts_counter_create(). */
+  /* Invalid counter size. */
+  grpc_status_code status =
+      alts_counter_create(true, 0, overflow_size, &ctr, &error_details);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_details,
+      "counter_size is invalid."));
+  gpr_free(error_details);
+
+  /* Invalid overflow size. */
+  status = alts_counter_create(true, counter_size, 0, &ctr, &error_details);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_details,
+      "overflow_size is invalid."));
+  gpr_free(error_details);
+
+  /* alts_counter is nullptr. */
+  status = alts_counter_create(true, counter_size, overflow_size, nullptr,
+                               &error_details);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_details,
+      "crypter_counter is nullptr."));
+  gpr_free(error_details);
+
+  status = alts_counter_create(true, counter_size, overflow_size, &ctr,
+                               &error_details);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+
+  /* Input sanity check on alts_counter_increment(). */
+  /* crypter_counter is nullptr. */
+  bool is_overflow = false;
+  status = alts_counter_increment(nullptr, &is_overflow, &error_details);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_details,
+      "crypter_counter is nullptr."));
+  gpr_free(error_details);
+  /* is_overflow is nullptr. */
+  status = alts_counter_increment(ctr, nullptr, &error_details);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_details,
+      "is_overflow is nullptr."));
+  gpr_free(error_details);
+  alts_counter_destroy(ctr);
+}
+
+static void alts_counter_test_overflow_full_range(bool is_client,
+                                                  size_t counter_size,
+                                                  size_t overflow_size) {
+  alts_counter* ctr = nullptr;
+  char* error_details = nullptr;
+  grpc_status_code status = alts_counter_create(
+      is_client, counter_size, overflow_size, &ctr, &error_details);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  unsigned char* expected =
+      static_cast<unsigned char*>(gpr_zalloc(counter_size));
+  if (is_client) {
+    expected[counter_size - 1] = 0x80;
+  }
+  /* Do a single iteration to ensure the counter is initialized as expected. */
+  GPR_ASSERT(do_bytes_represent_client(ctr, alts_counter_get_counter(ctr),
+                                       counter_size) == is_client);
+  GPR_ASSERT(memcmp(alts_counter_get_counter(ctr), expected, counter_size) ==
+             0);
+  bool is_overflow = false;
+  GPR_ASSERT(alts_counter_increment(ctr, &is_overflow, &error_details) ==
+             GRPC_STATUS_OK);
+  GPR_ASSERT(!is_overflow);
+  /**
+   * The counter can return 2^{overflow_size * 8} counters. The
+   * high-order bit is fixed to the client/server. The last call will yield a
+   * useable counter, but overflow the counter object.
+   */
+  int iterations = 1 << (overflow_size * 8);
+  int ind = 1;
+  for (ind = 1; ind < iterations - 1; ind++) {
+    GPR_ASSERT(do_bytes_represent_client(ctr, alts_counter_get_counter(ctr),
+                                         counter_size) == is_client);
+    GPR_ASSERT(alts_counter_increment(ctr, &is_overflow, &error_details) ==
+               GRPC_STATUS_OK);
+    GPR_ASSERT(!is_overflow);
+  }
+  GPR_ASSERT(do_bytes_represent_client(ctr, alts_counter_get_counter(ctr),
+                                       counter_size) == is_client);
+  GPR_ASSERT(alts_counter_increment(ctr, &is_overflow, &error_details) ==
+             GRPC_STATUS_FAILED_PRECONDITION);
+  GPR_ASSERT(is_overflow);
+  gpr_free(expected);
+  alts_counter_destroy(ctr);
+}
+
+/* Set the counter manually and make sure it overflows as expected. */
+static void alts_counter_test_overflow_single_increment(bool is_client,
+                                                        size_t counter_size,
+                                                        size_t overflow_size) {
+  alts_counter* ctr = nullptr;
+  char* error_details = nullptr;
+  grpc_status_code status = alts_counter_create(
+      is_client, counter_size, overflow_size, &ctr, &error_details);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  unsigned char* expected =
+      static_cast<unsigned char*>(gpr_zalloc(counter_size));
+  memset(expected, 0xFF, overflow_size);
+  expected[0] = 0xFE;
+
+  if (is_client) {
+    expected[counter_size - 1] = 0x80;
+  }
+  memcpy(ctr->counter, expected, counter_size);
+  GPR_ASSERT(do_bytes_represent_client(ctr, alts_counter_get_counter(ctr),
+                                       counter_size) == is_client);
+  GPR_ASSERT(memcmp(expected, alts_counter_get_counter(ctr), counter_size) ==
+             0);
+  bool is_overflow = false;
+  GPR_ASSERT(alts_counter_increment(ctr, &is_overflow, &error_details) ==
+             GRPC_STATUS_OK);
+  GPR_ASSERT(!is_overflow);
+  GPR_ASSERT(do_bytes_represent_client(ctr, alts_counter_get_counter(ctr),
+                                       counter_size) == is_client);
+  expected[0] = static_cast<unsigned char>(expected[0] + 1);
+  GPR_ASSERT(memcmp(expected, alts_counter_get_counter(ctr), counter_size) ==
+             0);
+  GPR_ASSERT(alts_counter_increment(ctr, &is_overflow, &error_details) ==
+             GRPC_STATUS_FAILED_PRECONDITION);
+  GPR_ASSERT(is_overflow);
+  gpr_free(expected);
+  alts_counter_destroy(ctr);
+}
+
+int main(int argc, char** argv) {
+  alts_counter_test_input_sanity_check(kGcmCounterSize, kGcmOverflowSize);
+  alts_counter_test_overflow_full_range(true, kSmallCounterSize,
+                                        kSmallOverflowSize);
+  alts_counter_test_overflow_full_range(false, kSmallCounterSize,
+                                        kSmallOverflowSize);
+  alts_counter_test_overflow_single_increment(true, kGcmCounterSize,
+                                              kGcmOverflowSize);
+  alts_counter_test_overflow_single_increment(false, kGcmCounterSize,
+                                              kGcmOverflowSize);
+
+  return 0;
+}
diff --git a/test/core/tsi/alts/frame_protector/alts_crypter_test.cc b/test/core/tsi/alts/frame_protector/alts_crypter_test.cc
new file mode 100644
index 0000000..0ad616b
--- /dev/null
+++ b/test/core/tsi/alts/frame_protector/alts_crypter_test.cc
@@ -0,0 +1,493 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/tsi/alts/frame_protector/alts_crypter.h"
+#include "test/core/tsi/alts/crypt/gsec_test_util.h"
+
+static void alts_crypter_test_random_seal_unseal(alts_crypter* server_seal,
+                                                 alts_crypter* server_unseal,
+                                                 alts_crypter* client_seal,
+                                                 alts_crypter* client_unseal) {
+  size_t data_size = gsec_test_bias_random_uint32(1024) + 1;
+  size_t num_overhead_bytes = alts_crypter_num_overhead_bytes(server_seal);
+  size_t protected_data_size = data_size + num_overhead_bytes;
+  uint8_t* data_buffer = static_cast<uint8_t*>(gpr_malloc(protected_data_size));
+  gsec_test_random_bytes(data_buffer, data_size);
+  uint8_t* duplicate_buffer = nullptr;
+  gsec_test_copy(data_buffer, &duplicate_buffer, data_size);
+
+  /* Client seal and server unseal */
+  size_t size = data_size;
+  grpc_status_code status = alts_crypter_process_in_place(
+      client_seal, data_buffer, protected_data_size, size, &size, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(size == protected_data_size);
+  status = alts_crypter_process_in_place(
+      server_unseal, data_buffer, protected_data_size, size, &size, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(memcmp(data_buffer, duplicate_buffer, data_size) == 0);
+  GPR_ASSERT(size == data_size);
+  /* Server seal and client unseal */
+  status = alts_crypter_process_in_place(
+      server_seal, data_buffer, protected_data_size, size, &size, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(size == protected_data_size);
+  status = alts_crypter_process_in_place(
+      client_unseal, data_buffer, protected_data_size, size, &size, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(memcmp(data_buffer, duplicate_buffer, data_size) == 0);
+  GPR_ASSERT(size == data_size);
+  gpr_free(data_buffer);
+  gpr_free(duplicate_buffer);
+}
+
+static void alts_crypter_test_multiple_random_seal_unseal(
+    alts_crypter* server_seal, alts_crypter* server_unseal,
+    alts_crypter* client_seal, alts_crypter* client_unseal) {
+  size_t data_size = gsec_test_bias_random_uint32(1024) + 1;
+  size_t num_overhead_bytes = alts_crypter_num_overhead_bytes(server_seal);
+  size_t protected_data_size = data_size + num_overhead_bytes;
+
+  uint8_t* data_buffer1 =
+      static_cast<uint8_t*>(gpr_malloc(protected_data_size));
+  uint8_t* data_buffer2 =
+      static_cast<uint8_t*>(gpr_malloc(protected_data_size));
+  uint8_t* duplicate_buffer1 = nullptr;
+  uint8_t* duplicate_buffer2 = nullptr;
+  gsec_test_random_bytes(data_buffer1, data_size);
+  gsec_test_random_bytes(data_buffer2, data_size);
+  gsec_test_copy(data_buffer1, &duplicate_buffer1, data_size);
+  gsec_test_copy(data_buffer2, &duplicate_buffer2, data_size);
+
+  /* Client seal and server unseal */
+  size_t size1 = data_size, size2 = data_size;
+  grpc_status_code status = alts_crypter_process_in_place(
+      client_seal, data_buffer1, protected_data_size, size1, &size1, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(size1 == protected_data_size);
+  status = alts_crypter_process_in_place(
+      client_seal, data_buffer2, protected_data_size, size2, &size2, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(size2 == protected_data_size);
+  status = alts_crypter_process_in_place(
+      server_unseal, data_buffer1, protected_data_size, size1, &size1, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(memcmp(data_buffer1, duplicate_buffer1, data_size) == 0);
+  GPR_ASSERT(size1 == data_size);
+  status = alts_crypter_process_in_place(
+      server_unseal, data_buffer2, protected_data_size, size2, &size2, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(memcmp(data_buffer2, duplicate_buffer2, data_size) == 0);
+  GPR_ASSERT(size2 == data_size);
+
+  /* Server seal and client unseal */
+  status = alts_crypter_process_in_place(
+      server_seal, data_buffer1, protected_data_size, size1, &size1, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(size1 == protected_data_size);
+  status = alts_crypter_process_in_place(
+      server_seal, data_buffer2, protected_data_size, size2, &size2, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(size2 == protected_data_size);
+  status = alts_crypter_process_in_place(
+      client_unseal, data_buffer1, protected_data_size, size1, &size1, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(memcmp(data_buffer1, duplicate_buffer1, data_size) == 0);
+  GPR_ASSERT(size1 == data_size);
+  status = alts_crypter_process_in_place(
+      client_unseal, data_buffer2, protected_data_size, size2, &size2, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(memcmp(data_buffer2, duplicate_buffer2, data_size) == 0);
+  GPR_ASSERT(size2 == data_size);
+
+  gpr_free(data_buffer1);
+  gpr_free(data_buffer2);
+  gpr_free(duplicate_buffer1);
+  gpr_free(duplicate_buffer2);
+}
+
+static void alts_crypter_test_corrupted_unseal(alts_crypter* server_seal,
+                                               alts_crypter* server_unseal,
+                                               alts_crypter* client_seal,
+                                               alts_crypter* client_unseal) {
+  size_t data_size = gsec_test_bias_random_uint32(1024) + 1;
+  size_t num_overhead_bytes = alts_crypter_num_overhead_bytes(server_seal);
+  size_t protected_data_size = data_size + num_overhead_bytes;
+  auto* data_buffer = static_cast<uint8_t*>(gpr_malloc(protected_data_size));
+  auto* zero_buffer = static_cast<uint8_t*>(gpr_zalloc(data_size));
+
+  /* Corrupt a random byte in protected data. */
+  size_t size = data_size;
+  gsec_test_random_bytes(data_buffer, data_size);
+  grpc_status_code status = alts_crypter_process_in_place(
+      client_seal, data_buffer, protected_data_size, size, &size, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(size == protected_data_size);
+  uint8_t* corrupted_data_buffer;
+  char* error_message = nullptr;
+  gsec_test_copy_and_alter_random_byte(data_buffer, &corrupted_data_buffer,
+                                       protected_data_size);
+  status = alts_crypter_process_in_place(server_unseal, corrupted_data_buffer,
+                                         protected_data_size, size, &size,
+                                         &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_FAILED_PRECONDITION, error_message,
+      "Checking tag failed"));
+  GPR_ASSERT(memcmp(corrupted_data_buffer, zero_buffer, data_size) == 0);
+  gpr_free(corrupted_data_buffer);
+  gpr_free(error_message);
+
+  /* Corrupt the beginning of protected data. */
+  size = data_size;
+  gsec_test_random_bytes(data_buffer, data_size);
+  status = alts_crypter_process_in_place(
+      client_seal, data_buffer, protected_data_size, size, &size, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(size == protected_data_size);
+  gsec_test_copy(data_buffer, &corrupted_data_buffer, protected_data_size);
+  (*corrupted_data_buffer)++;
+  status = alts_crypter_process_in_place(server_unseal, corrupted_data_buffer,
+                                         protected_data_size, size, &size,
+                                         &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_FAILED_PRECONDITION, error_message,
+      "Checking tag failed"));
+  GPR_ASSERT(memcmp(corrupted_data_buffer, zero_buffer, data_size) == 0);
+  gpr_free(corrupted_data_buffer);
+  gpr_free(error_message);
+
+  /* Corrupt the end of protected data. */
+  size = data_size;
+  gsec_test_random_bytes(data_buffer, data_size);
+  status = alts_crypter_process_in_place(
+      client_seal, data_buffer, protected_data_size, size, &size, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(size == protected_data_size);
+  gsec_test_copy(data_buffer, &corrupted_data_buffer, protected_data_size);
+  (*(corrupted_data_buffer + protected_data_size - 1))++;
+  status = alts_crypter_process_in_place(server_unseal, corrupted_data_buffer,
+                                         protected_data_size, size, &size,
+                                         &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_FAILED_PRECONDITION, error_message,
+      "Checking tag failed"));
+  GPR_ASSERT(memcmp(corrupted_data_buffer, zero_buffer, data_size) == 0);
+  gpr_free(corrupted_data_buffer);
+  gpr_free(error_message);
+
+  gpr_free(data_buffer);
+  gpr_free(zero_buffer);
+}
+
+static void alts_crypter_test_unsync_seal_unseal(alts_crypter* server_seal,
+                                                 alts_crypter* server_unseal,
+                                                 alts_crypter* client_seal,
+                                                 alts_crypter* client_unseal) {
+  size_t data_size = gsec_test_bias_random_uint32(1024) + 1;
+  size_t num_overhead_bytes = alts_crypter_num_overhead_bytes(server_seal);
+  size_t protected_data_size = data_size + num_overhead_bytes;
+  auto* data_buffer = static_cast<uint8_t*>(gpr_malloc(protected_data_size));
+  auto* zero_buffer = static_cast<uint8_t*>(gpr_zalloc(data_size));
+
+  /* Perform two seals at client, one unseal at server. */
+  size_t size = data_size;
+  gsec_test_random_bytes(data_buffer, data_size);
+  grpc_status_code status = alts_crypter_process_in_place(
+      client_seal, data_buffer, protected_data_size, size, &size, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(size == protected_data_size);
+
+  size = data_size;
+  gsec_test_random_bytes(data_buffer, data_size);
+  status = alts_crypter_process_in_place(
+      client_seal, data_buffer, protected_data_size, size, &size, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(size == protected_data_size);
+
+  char* error_message = nullptr;
+  status = alts_crypter_process_in_place(server_unseal, data_buffer,
+                                         protected_data_size, size, &size,
+                                         &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_FAILED_PRECONDITION, error_message,
+      "Checking tag failed"));
+  GPR_ASSERT(memcmp(data_buffer, zero_buffer, data_size) == 0);
+  gpr_free(error_message);
+
+  /* Perform two seals at server, one unseal at client. */
+  size = data_size;
+  gsec_test_random_bytes(data_buffer, data_size);
+  status = alts_crypter_process_in_place(
+      server_seal, data_buffer, protected_data_size, size, &size, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(size == protected_data_size);
+
+  size = data_size;
+  gsec_test_random_bytes(data_buffer, data_size);
+  status = alts_crypter_process_in_place(
+      server_seal, data_buffer, protected_data_size, size, &size, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(size == protected_data_size);
+
+  status = alts_crypter_process_in_place(client_unseal, data_buffer,
+                                         protected_data_size, size, &size,
+                                         &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_FAILED_PRECONDITION, error_message,
+      "Checking tag failed"));
+  GPR_ASSERT(memcmp(data_buffer, zero_buffer, data_size) == 0);
+  gpr_free(error_message);
+  gpr_free(data_buffer);
+  gpr_free(zero_buffer);
+}
+
+static void alts_crypter_test_input_sanity_check(alts_crypter* crypter_seal,
+                                                 alts_crypter* crypter_unseal) {
+  size_t data_size = gsec_test_bias_random_uint32(1024) + 1;
+  size_t num_overhead_bytes = alts_crypter_num_overhead_bytes(crypter_seal);
+  size_t protected_data_size = data_size + num_overhead_bytes;
+  auto* data_buffer = static_cast<uint8_t*>(gpr_malloc(protected_data_size));
+  gsec_test_random_bytes(data_buffer, data_size);
+  char* error_message = nullptr;
+  size_t size = data_size;
+
+  /* Crypter is nullptr. */
+  grpc_status_code status = alts_crypter_process_in_place(
+      nullptr, data_buffer, protected_data_size, size, &size, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "crypter or crypter->vtable has not been initialized properly."));
+  gpr_free(error_message);
+
+  /* Seal data is nullptr. */
+  size = data_size;
+  status = alts_crypter_process_in_place(
+      crypter_seal, nullptr, protected_data_size, size, &size, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message, "data is nullptr."));
+  gpr_free(error_message);
+
+  /* Seal data size is 0. */
+  size = 0;
+  status = alts_crypter_process_in_place(crypter_seal, data_buffer,
+                                         protected_data_size, size, &size,
+                                         &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "data_size is zero."));
+  gpr_free(error_message);
+
+  /* Seal data buffer has a size smaller than the required. */
+  size = data_size;
+  status = alts_crypter_process_in_place(crypter_seal, data_buffer,
+                                         protected_data_size - 1, size, &size,
+                                         &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "data_allocated_size is smaller than sum of data_size and "
+      "num_overhead_bytes."));
+  gpr_free(error_message);
+
+  /* Unseal data is nullptr. */
+  size = data_size;
+  status = alts_crypter_process_in_place(crypter_unseal, nullptr,
+                                         protected_data_size, size, &size,
+                                         &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message, "data is nullptr."));
+  gpr_free(error_message);
+
+  /* Unseal data size is 0. */
+  size = 0;
+  status = alts_crypter_process_in_place(crypter_unseal, data_buffer,
+                                         protected_data_size, size, &size,
+                                         &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "data_size is smaller than num_overhead_bytes."));
+  gpr_free(error_message);
+
+  /* Unseal data size is smaller than number of overhead bytes. */
+  size = num_overhead_bytes - 1;
+  status = alts_crypter_process_in_place(crypter_unseal, data_buffer,
+                                         protected_data_size, size, &size,
+                                         &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "data_size is smaller than num_overhead_bytes."));
+  gpr_free(error_message);
+  gpr_free(data_buffer);
+}
+
+static void create_random_alts_seal_crypter(
+    alts_crypter** server_seal, alts_crypter** server_unseal,
+    alts_crypter** client_seal, alts_crypter** client_unseal,
+    gsec_aead_crypter** server_crypter_seal,
+    gsec_aead_crypter** server_crypter_unseal,
+    gsec_aead_crypter** client_crypter_seal,
+    gsec_aead_crypter** client_crypter_unseal, bool rekey) {
+  size_t key_length = rekey ? kAes128GcmRekeyKeyLength : kAes128GcmKeyLength;
+  uint8_t* key;
+  gsec_test_random_array(&key, key_length);
+  gsec_aes_gcm_aead_crypter_create(key, key_length, kAesGcmNonceLength,
+                                   kAesGcmTagLength, rekey, server_crypter_seal,
+                                   nullptr);
+  gsec_aes_gcm_aead_crypter_create(key, key_length, kAesGcmNonceLength,
+                                   kAesGcmTagLength, rekey,
+                                   server_crypter_unseal, nullptr);
+  gsec_aes_gcm_aead_crypter_create(key, key_length, kAesGcmNonceLength,
+                                   kAesGcmTagLength, rekey, client_crypter_seal,
+                                   nullptr);
+  gsec_aes_gcm_aead_crypter_create(key, key_length, kAesGcmNonceLength,
+                                   kAesGcmTagLength, rekey,
+                                   client_crypter_unseal, nullptr);
+
+  size_t overflow_size = rekey ? 8 : 5;
+  alts_seal_crypter_create(*client_crypter_seal, /*is_client=*/true,
+                           overflow_size, client_seal, nullptr);
+  alts_unseal_crypter_create(*client_crypter_unseal, /*is_client=*/true,
+                             overflow_size, client_unseal, nullptr);
+  alts_seal_crypter_create(*server_crypter_seal, /*is_client=*/false,
+                           overflow_size, server_seal, nullptr);
+  alts_unseal_crypter_create(*server_crypter_unseal, /*is_client=*/false,
+                             overflow_size, server_unseal, nullptr);
+  gpr_free(key);
+}
+
+static void destroy_random_alts_seal_crypter(alts_crypter* server_seal,
+                                             alts_crypter* server_unseal,
+                                             alts_crypter* client_seal,
+                                             alts_crypter* client_unseal) {
+  alts_crypter_destroy(server_seal);
+  alts_crypter_destroy(server_unseal);
+  alts_crypter_destroy(client_seal);
+  alts_crypter_destroy(client_unseal);
+}
+
+static void alts_crypter_do_generic_tests() {
+  alts_crypter *server_seal = nullptr, *server_unseal = nullptr,
+               *client_seal = nullptr, *client_unseal = nullptr;
+  gsec_aead_crypter *server_crypter_seal = nullptr,
+                    *server_crypter_unseal = nullptr,
+                    *client_crypter_seal = nullptr,
+                    *client_crypter_unseal = nullptr;
+  /* Random seal and unseal tests */
+  create_random_alts_seal_crypter(&server_seal, &server_unseal, &client_seal,
+                                  &client_unseal, &server_crypter_seal,
+                                  &server_crypter_unseal, &client_crypter_seal,
+                                  &client_crypter_unseal, /*rekey=*/false);
+  alts_crypter_test_random_seal_unseal(server_seal, server_unseal, client_seal,
+                                       client_unseal);
+  destroy_random_alts_seal_crypter(server_seal, server_unseal, client_seal,
+                                   client_unseal);
+
+  create_random_alts_seal_crypter(&server_seal, &server_unseal, &client_seal,
+                                  &client_unseal, &server_crypter_seal,
+                                  &server_crypter_unseal, &client_crypter_seal,
+                                  &client_crypter_unseal, /*rekey=*/true);
+  alts_crypter_test_random_seal_unseal(server_seal, server_unseal, client_seal,
+                                       client_unseal);
+  destroy_random_alts_seal_crypter(server_seal, server_unseal, client_seal,
+                                   client_unseal);
+
+  /* Multiple random seal and unseal tests */
+  create_random_alts_seal_crypter(&server_seal, &server_unseal, &client_seal,
+                                  &client_unseal, &server_crypter_seal,
+                                  &server_crypter_unseal, &client_crypter_seal,
+                                  &client_crypter_unseal, /*rekey=*/false);
+  alts_crypter_test_multiple_random_seal_unseal(server_seal, server_unseal,
+                                                client_seal, client_unseal);
+  destroy_random_alts_seal_crypter(server_seal, server_unseal, client_seal,
+                                   client_unseal);
+
+  create_random_alts_seal_crypter(&server_seal, &server_unseal, &client_seal,
+                                  &client_unseal, &server_crypter_seal,
+                                  &server_crypter_unseal, &client_crypter_seal,
+                                  &client_crypter_unseal, /*rekey=*/true);
+  alts_crypter_test_multiple_random_seal_unseal(server_seal, server_unseal,
+                                                client_seal, client_unseal);
+  destroy_random_alts_seal_crypter(server_seal, server_unseal, client_seal,
+                                   client_unseal);
+
+  /* Corrupted unseal tests */
+  create_random_alts_seal_crypter(&server_seal, &server_unseal, &client_seal,
+                                  &client_unseal, &server_crypter_seal,
+                                  &server_crypter_unseal, &client_crypter_seal,
+                                  &client_crypter_unseal, /*rekey=*/false);
+  alts_crypter_test_corrupted_unseal(server_seal, server_unseal, client_seal,
+                                     client_unseal);
+  destroy_random_alts_seal_crypter(server_seal, server_unseal, client_seal,
+                                   client_unseal);
+
+  create_random_alts_seal_crypter(&server_seal, &server_unseal, &client_seal,
+                                  &client_unseal, &server_crypter_seal,
+                                  &server_crypter_unseal, &client_crypter_seal,
+                                  &client_crypter_unseal, /*rekey=*/true);
+  alts_crypter_test_corrupted_unseal(server_seal, server_unseal, client_seal,
+                                     client_unseal);
+  destroy_random_alts_seal_crypter(server_seal, server_unseal, client_seal,
+                                   client_unseal);
+
+  /* Unsync seal and unseal tests */
+  create_random_alts_seal_crypter(&server_seal, &server_unseal, &client_seal,
+                                  &client_unseal, &server_crypter_seal,
+                                  &server_crypter_unseal, &client_crypter_seal,
+                                  &client_crypter_unseal, /*rekey=*/false);
+  alts_crypter_test_unsync_seal_unseal(server_seal, server_unseal, client_seal,
+                                       client_unseal);
+  destroy_random_alts_seal_crypter(server_seal, server_unseal, client_seal,
+                                   client_unseal);
+
+  create_random_alts_seal_crypter(&server_seal, &server_unseal, &client_seal,
+                                  &client_unseal, &server_crypter_seal,
+                                  &server_crypter_unseal, &client_crypter_seal,
+                                  &client_crypter_unseal, /*rekey=*/true);
+  alts_crypter_test_unsync_seal_unseal(server_seal, server_unseal, client_seal,
+                                       client_unseal);
+  destroy_random_alts_seal_crypter(server_seal, server_unseal, client_seal,
+                                   client_unseal);
+
+  /* Input sanity check tests */
+  create_random_alts_seal_crypter(&server_seal, &server_unseal, &client_seal,
+                                  &client_unseal, &server_crypter_seal,
+                                  &server_crypter_unseal, &client_crypter_seal,
+                                  &client_crypter_unseal, /*rekey=*/false);
+  alts_crypter_test_input_sanity_check(server_seal, server_unseal);
+  destroy_random_alts_seal_crypter(server_seal, server_unseal, client_seal,
+                                   client_unseal);
+
+  create_random_alts_seal_crypter(&server_seal, &server_unseal, &client_seal,
+                                  &client_unseal, &server_crypter_seal,
+                                  &server_crypter_unseal, &client_crypter_seal,
+                                  &client_crypter_unseal, /*rekey=*/true);
+  alts_crypter_test_input_sanity_check(server_seal, server_unseal);
+  destroy_random_alts_seal_crypter(server_seal, server_unseal, client_seal,
+                                   client_unseal);
+}
+
+int main(int argc, char** argv) {
+  alts_crypter_do_generic_tests();
+  return 0;
+}
diff --git a/test/core/tsi/alts/frame_protector/alts_frame_protector_test.cc b/test/core/tsi/alts/frame_protector/alts_frame_protector_test.cc
new file mode 100644
index 0000000..2bd4958
--- /dev/null
+++ b/test/core/tsi/alts/frame_protector/alts_frame_protector_test.cc
@@ -0,0 +1,394 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include <stdbool.h>
+
+#include "src/core/tsi/alts/crypt/gsec.h"
+#include "src/core/tsi/alts/frame_protector/alts_frame_protector.h"
+#include "src/core/tsi/transport_security_interface.h"
+#include "test/core/tsi/alts/crypt/gsec_test_util.h"
+#include "test/core/tsi/transport_security_test_lib.h"
+
+const size_t kChannelSize = 32768;
+
+static void alts_test_do_round_trip_check_frames(
+    tsi_test_frame_protector_fixture* fixture, const uint8_t* key,
+    const size_t key_size, bool rekey, const uint8_t* client_message,
+    const size_t client_message_size, const uint8_t* client_expected_frames,
+    const size_t client_frame_size, const uint8_t* server_message,
+    const size_t server_message_size, const uint8_t* server_expected_frames,
+    const size_t server_frame_size) {
+  GPR_ASSERT(fixture != nullptr);
+  GPR_ASSERT(fixture->config != nullptr);
+  tsi_frame_protector* client_frame_protector = nullptr;
+  tsi_frame_protector* server_frame_protector = nullptr;
+  tsi_test_frame_protector_config* config = fixture->config;
+  tsi_test_channel* channel = fixture->channel;
+  /* Create a client frame protector. */
+  size_t client_max_output_protected_frame_size =
+      config->client_max_output_protected_frame_size;
+  GPR_ASSERT(
+      alts_create_frame_protector(key, key_size, /*is_client=*/true, rekey,
+                                  client_max_output_protected_frame_size == 0
+                                      ? nullptr
+                                      : &client_max_output_protected_frame_size,
+                                  &client_frame_protector) == TSI_OK);
+  /* Create a server frame protector. */
+  size_t server_max_output_protected_frame_size =
+      config->server_max_output_protected_frame_size;
+  GPR_ASSERT(
+      alts_create_frame_protector(key, key_size, /*is_client=*/false, rekey,
+                                  server_max_output_protected_frame_size == 0
+                                      ? nullptr
+                                      : &server_max_output_protected_frame_size,
+                                  &server_frame_protector) == TSI_OK);
+  tsi_test_frame_protector_fixture_init(fixture, client_frame_protector,
+                                        server_frame_protector);
+  /* Client sends a message to server. */
+  uint8_t* saved_client_message = config->client_message;
+  config->client_message = const_cast<uint8_t*>(client_message);
+  config->client_message_size = client_message_size;
+  tsi_test_frame_protector_send_message_to_peer(config, channel,
+                                                client_frame_protector,
+                                                /*is_client=*/true);
+  /* Verify if the generated frame is the same as the expected. */
+  GPR_ASSERT(channel->bytes_written_to_server_channel == client_frame_size);
+  GPR_ASSERT(memcmp(client_expected_frames, channel->server_channel,
+                    client_frame_size) == 0);
+  unsigned char* server_received_message =
+      static_cast<unsigned char*>(gpr_malloc(kChannelSize));
+  size_t server_received_message_size = 0;
+  tsi_test_frame_protector_receive_message_from_peer(
+      config, channel, server_frame_protector, server_received_message,
+      &server_received_message_size, /*is_client=*/false);
+  GPR_ASSERT(config->client_message_size == server_received_message_size);
+  GPR_ASSERT(memcmp(config->client_message, server_received_message,
+                    server_received_message_size) == 0);
+  /* Server sends a message to client. */
+  uint8_t* saved_server_message = config->server_message;
+  config->server_message = const_cast<uint8_t*>(server_message);
+  config->server_message_size = server_message_size;
+  tsi_test_frame_protector_send_message_to_peer(config, channel,
+                                                server_frame_protector,
+                                                /*is_client=*/false);
+  /* Verify if the generated frame is the same as the expected. */
+  GPR_ASSERT(channel->bytes_written_to_client_channel == server_frame_size);
+  GPR_ASSERT(memcmp(server_expected_frames, channel->client_channel,
+                    server_frame_size) == 0);
+  unsigned char* client_received_message =
+      static_cast<unsigned char*>(gpr_malloc(kChannelSize));
+  size_t client_received_message_size = 0;
+  tsi_test_frame_protector_receive_message_from_peer(
+      config, channel, client_frame_protector, client_received_message,
+      &client_received_message_size,
+      /*is_client=*/true);
+  GPR_ASSERT(config->server_message_size == client_received_message_size);
+  GPR_ASSERT(memcmp(config->server_message, client_received_message,
+                    client_received_message_size) == 0);
+  config->client_message = saved_client_message;
+  config->server_message = saved_server_message;
+  /* Destroy server and client frame protectors. */
+  gpr_free(server_received_message);
+  gpr_free(client_received_message);
+}
+
+static void alts_test_do_round_trip_vector_tests() {
+  const uint8_t key[] = {0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+                         0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08};
+  const char small_message[] = {'C', 'h', 'a', 'p', 'i', ' ',
+                                'C', 'h', 'a', 'p', 'o'};
+  const uint8_t large_message[] = {
+      0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5,
+      0xaf, 0xf5, 0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+      0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95,
+      0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+      0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39,
+      0x1a, 0xaf, 0xd2, 0x55, 0xd6, 0x09, 0xb1, 0xf0, 0x56, 0x63, 0x7a, 0x0d,
+      0x46, 0xdf, 0x99, 0x8d, 0x88, 0xe5, 0x22, 0x2a, 0xb2, 0xc2, 0x84, 0x65,
+      0x12, 0x15, 0x35, 0x24, 0xc0, 0x89, 0x5e, 0x81, 0x08, 0x06, 0x0f, 0x10,
+      0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c,
+      0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+      0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30};
+  const size_t small_message_size = sizeof(small_message) / sizeof(uint8_t);
+  const size_t large_message_size = sizeof(large_message) / sizeof(uint8_t);
+  /* Test small client message and large server message. */
+  const uint8_t client_expected_frame1[] = {
+      0x1f, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x09, 0xd8, 0xd5, 0x92,
+      0x4d, 0x50, 0x32, 0xb7, 0x1f, 0xb8, 0xf2, 0xbb, 0x43, 0xc7, 0xe2, 0x94,
+      0x3d, 0x3e, 0x9a, 0x78, 0x76, 0xaa, 0x0a, 0x6b, 0xfa, 0x98, 0x3a};
+  const uint8_t server_expected_frame1[] = {
+      0x94, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa9, 0x4b, 0xf8, 0xc8,
+      0xe7, 0x8f, 0x1a, 0x26, 0x37, 0x44, 0xa2, 0x5c, 0x55, 0x94, 0x30, 0x4e,
+      0x3e, 0x16, 0xe7, 0x9e, 0x96, 0xe8, 0x1b, 0xc0, 0xdd, 0x52, 0x30, 0x06,
+      0xc2, 0x72, 0x9a, 0xa1, 0x0b, 0xdb, 0xdc, 0x19, 0x8c, 0x93, 0x5e, 0x84,
+      0x1f, 0x4b, 0x97, 0x26, 0xf0, 0x73, 0x85, 0x59, 0x00, 0x95, 0xc1, 0xc5,
+      0x22, 0x2f, 0x70, 0x85, 0x68, 0x2c, 0x4f, 0xfe, 0x30, 0x26, 0x91, 0xde,
+      0x62, 0x55, 0x1d, 0x35, 0x01, 0x96, 0x1c, 0xe7, 0xa2, 0x8b, 0x14, 0x8a,
+      0x5e, 0x1b, 0x4a, 0x3b, 0x4f, 0x65, 0x0f, 0xca, 0x79, 0x10, 0xb4, 0xdd,
+      0xf7, 0xa4, 0x8b, 0x64, 0x2f, 0x00, 0x39, 0x60, 0x03, 0xfc, 0xe1, 0x8b,
+      0x5c, 0x19, 0xba, 0xcc, 0x46, 0xba, 0x88, 0xdd, 0x40, 0x42, 0x27, 0x4f,
+      0xe4, 0x1a, 0x6a, 0x31, 0x6c, 0x1c, 0xb0, 0xb6, 0x5c, 0x3e, 0xca, 0x84,
+      0x9b, 0x5f, 0x04, 0x84, 0x11, 0xa9, 0xf8, 0x39, 0xe7, 0xe7, 0xc5, 0xc4,
+      0x33, 0x9f, 0x63, 0x21, 0x9a, 0x7c, 0x9c, 0x64};
+  const size_t client_frame_size1 =
+      sizeof(client_expected_frame1) / sizeof(uint8_t);
+  const size_t server_frame_size1 =
+      sizeof(server_expected_frame1) / sizeof(uint8_t);
+  tsi_test_frame_protector_fixture* fixture =
+      tsi_test_frame_protector_fixture_create();
+  alts_test_do_round_trip_check_frames(
+      fixture, key, kAes128GcmKeyLength, /*rekey=*/false,
+      reinterpret_cast<const uint8_t*>(small_message), small_message_size,
+      client_expected_frame1, client_frame_size1, large_message,
+      large_message_size, server_expected_frame1, server_frame_size1);
+  tsi_test_frame_protector_fixture_destroy(fixture);
+  /**
+   * Test large client message, small server message, and small
+   * message_buffer_allocated_size.
+   */
+  const uint8_t client_expected_frame2[] = {
+      0x94, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x93, 0x81, 0x86, 0xc7,
+      0xdc, 0xf4, 0x77, 0x3a, 0xdb, 0x91, 0x94, 0x61, 0xba, 0xed, 0xd5, 0x37,
+      0x47, 0x53, 0x0c, 0xe1, 0xbf, 0x59, 0x23, 0x20, 0xde, 0x8b, 0x25, 0x13,
+      0x72, 0xe7, 0x8a, 0x4f, 0x32, 0x61, 0xc6, 0xda, 0xc3, 0xe9, 0xff, 0x31,
+      0x33, 0x53, 0x4a, 0xf8, 0xc9, 0x98, 0xe4, 0x19, 0x71, 0x9c, 0x5e, 0x72,
+      0xc7, 0x35, 0x97, 0x78, 0x30, 0xf2, 0xc4, 0xd1, 0x53, 0xd5, 0x6e, 0x8f,
+      0x4f, 0xd9, 0x28, 0x5a, 0xfd, 0x22, 0x57, 0x7f, 0x95, 0xb4, 0x8a, 0x5e,
+      0x7c, 0x47, 0xa8, 0xcf, 0x64, 0x3d, 0x83, 0xa5, 0xcf, 0xc3, 0xfe, 0x54,
+      0xc2, 0x6a, 0x40, 0xc4, 0xfb, 0x8e, 0x07, 0x77, 0x70, 0x8f, 0x99, 0x94,
+      0xb1, 0xd5, 0xa7, 0xf9, 0x0d, 0xc7, 0x11, 0xc5, 0x6f, 0x4a, 0x4f, 0x56,
+      0xd5, 0xe2, 0x9c, 0xbb, 0x95, 0x7a, 0xd0, 0x9f, 0x30, 0x54, 0xca, 0x6d,
+      0x5c, 0x8e, 0x83, 0xa0, 0x04, 0x5e, 0xd0, 0x22, 0x8c, 0x2a, 0x7f, 0xdb,
+      0xfe, 0xb3, 0x2e, 0xae, 0x22, 0xe6, 0xf4, 0xb7};
+  const uint8_t server_expected_frame2[] = {
+      0x1f, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x33, 0x12, 0xab, 0x9d,
+      0x76, 0x2b, 0x5f, 0xab, 0xf3, 0x6d, 0xc4, 0xaa, 0xe5, 0x1e, 0x63, 0xc1,
+      0x7b, 0x7b, 0x10, 0xd5, 0x63, 0x0f, 0x29, 0xad, 0x17, 0x33, 0x73};
+  const size_t client_frame_size2 =
+      sizeof(client_expected_frame2) / sizeof(uint8_t);
+  const size_t server_frame_size2 =
+      sizeof(server_expected_frame2) / sizeof(uint8_t);
+  fixture = tsi_test_frame_protector_fixture_create();
+  alts_test_do_round_trip_check_frames(
+      fixture, key, kAes128GcmKeyLength, /*rekey=*/false, large_message,
+      large_message_size, client_expected_frame2, client_frame_size2,
+      reinterpret_cast<const uint8_t*>(small_message), small_message_size,
+      server_expected_frame2, server_frame_size2);
+  tsi_test_frame_protector_fixture_destroy(fixture);
+  /**
+   * Test large client message, small server message, and small
+   * protected_buffer_size.
+   */
+  const uint8_t client_expected_frame3[] = {
+      0x94, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x93, 0x81, 0x86, 0xc7,
+      0xdc, 0xf4, 0x77, 0x3a, 0xdb, 0x91, 0x94, 0x61, 0xba, 0xed, 0xd5, 0x37,
+      0x47, 0x53, 0x0c, 0xe1, 0xbf, 0x59, 0x23, 0x20, 0xde, 0x8b, 0x25, 0x13,
+      0x72, 0xe7, 0x8a, 0x4f, 0x32, 0x61, 0xc6, 0xda, 0xc3, 0xe9, 0xff, 0x31,
+      0x33, 0x53, 0x4a, 0xf8, 0xc9, 0x98, 0xe4, 0x19, 0x71, 0x9c, 0x5e, 0x72,
+      0xc7, 0x35, 0x97, 0x78, 0x30, 0xf2, 0xc4, 0xd1, 0x53, 0xd5, 0x6e, 0x8f,
+      0x4f, 0xd9, 0x28, 0x5a, 0xfd, 0x22, 0x57, 0x7f, 0x95, 0xb4, 0x8a, 0x5e,
+      0x7c, 0x47, 0xa8, 0xcf, 0x64, 0x3d, 0x83, 0xa5, 0xcf, 0xc3, 0xfe, 0x54,
+      0xc2, 0x6a, 0x40, 0xc4, 0xfb, 0x8e, 0x07, 0x77, 0x70, 0x8f, 0x99, 0x94,
+      0xb1, 0xd5, 0xa7, 0xf9, 0x0d, 0xc7, 0x11, 0xc5, 0x6f, 0x4a, 0x4f, 0x56,
+      0xd5, 0xe2, 0x9c, 0xbb, 0x95, 0x7a, 0xd0, 0x9f, 0x30, 0x54, 0xca, 0x6d,
+      0x5c, 0x8e, 0x83, 0xa0, 0x04, 0x5e, 0xd0, 0x22, 0x8c, 0x2a, 0x7f, 0xdb,
+      0xfe, 0xb3, 0x2e, 0xae, 0x22, 0xe6, 0xf4, 0xb7};
+  const uint8_t server_expected_frame3[] = {
+      0x1f, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x33, 0x12, 0xab, 0x9d,
+      0x76, 0x2b, 0x5f, 0xab, 0xf3, 0x6d, 0xc4, 0xaa, 0xe5, 0x1e, 0x63, 0xc1,
+      0x7b, 0x7b, 0x10, 0xd5, 0x63, 0x0f, 0x29, 0xad, 0x17, 0x33, 0x73};
+  const size_t client_frame_size3 =
+      sizeof(client_expected_frame3) / sizeof(uint8_t);
+  const size_t server_frame_size3 =
+      sizeof(server_expected_frame3) / sizeof(uint8_t);
+  fixture = tsi_test_frame_protector_fixture_create();
+  alts_test_do_round_trip_check_frames(
+      fixture, key, kAes128GcmKeyLength, /*rekey=*/false, large_message,
+      large_message_size, client_expected_frame3, client_frame_size3,
+      reinterpret_cast<const uint8_t*>(small_message), small_message_size,
+      server_expected_frame3, server_frame_size3);
+  tsi_test_frame_protector_fixture_destroy(fixture);
+  /**
+   * Test large client message, small server message, and small
+   * read_buffer_allocated_size.
+   */
+  const uint8_t client_expected_frame4[] = {
+      0x94, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x93, 0x81, 0x86, 0xc7,
+      0xdc, 0xf4, 0x77, 0x3a, 0xdb, 0x91, 0x94, 0x61, 0xba, 0xed, 0xd5, 0x37,
+      0x47, 0x53, 0x0c, 0xe1, 0xbf, 0x59, 0x23, 0x20, 0xde, 0x8b, 0x25, 0x13,
+      0x72, 0xe7, 0x8a, 0x4f, 0x32, 0x61, 0xc6, 0xda, 0xc3, 0xe9, 0xff, 0x31,
+      0x33, 0x53, 0x4a, 0xf8, 0xc9, 0x98, 0xe4, 0x19, 0x71, 0x9c, 0x5e, 0x72,
+      0xc7, 0x35, 0x97, 0x78, 0x30, 0xf2, 0xc4, 0xd1, 0x53, 0xd5, 0x6e, 0x8f,
+      0x4f, 0xd9, 0x28, 0x5a, 0xfd, 0x22, 0x57, 0x7f, 0x95, 0xb4, 0x8a, 0x5e,
+      0x7c, 0x47, 0xa8, 0xcf, 0x64, 0x3d, 0x83, 0xa5, 0xcf, 0xc3, 0xfe, 0x54,
+      0xc2, 0x6a, 0x40, 0xc4, 0xfb, 0x8e, 0x07, 0x77, 0x70, 0x8f, 0x99, 0x94,
+      0xb1, 0xd5, 0xa7, 0xf9, 0x0d, 0xc7, 0x11, 0xc5, 0x6f, 0x4a, 0x4f, 0x56,
+      0xd5, 0xe2, 0x9c, 0xbb, 0x95, 0x7a, 0xd0, 0x9f, 0x30, 0x54, 0xca, 0x6d,
+      0x5c, 0x8e, 0x83, 0xa0, 0x04, 0x5e, 0xd0, 0x22, 0x8c, 0x2a, 0x7f, 0xdb,
+      0xfe, 0xb3, 0x2e, 0xae, 0x22, 0xe6, 0xf4, 0xb7};
+  const uint8_t server_expected_frame4[] = {
+      0x1f, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x33, 0x12, 0xab, 0x9d,
+      0x76, 0x2b, 0x5f, 0xab, 0xf3, 0x6d, 0xc4, 0xaa, 0xe5, 0x1e, 0x63, 0xc1,
+      0x7b, 0x7b, 0x10, 0xd5, 0x63, 0x0f, 0x29, 0xad, 0x17, 0x33, 0x73};
+  const size_t client_frame_size4 =
+      sizeof(client_expected_frame4) / sizeof(uint8_t);
+  const size_t server_frame_size4 =
+      sizeof(server_expected_frame4) / sizeof(uint8_t);
+  fixture = tsi_test_frame_protector_fixture_create();
+  alts_test_do_round_trip_check_frames(
+      fixture, key, kAes128GcmKeyLength, /*rekey=*/false, large_message,
+      large_message_size, client_expected_frame4, client_frame_size4,
+      reinterpret_cast<const uint8_t*>(small_message), small_message_size,
+      server_expected_frame4, server_frame_size4);
+  tsi_test_frame_protector_fixture_destroy(fixture);
+  /**
+   * Test large client message, small server message, and small
+   * client_max_output_protected_frame_size.
+   */
+  const uint8_t client_expected_frame5[] = {
+      0x94, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x93, 0x81, 0x86, 0xc7,
+      0xdc, 0xf4, 0x77, 0x3a, 0xdb, 0x91, 0x94, 0x61, 0xba, 0xed, 0xd5, 0x37,
+      0x47, 0x53, 0x0c, 0xe1, 0xbf, 0x59, 0x23, 0x20, 0xde, 0x8b, 0x25, 0x13,
+      0x72, 0xe7, 0x8a, 0x4f, 0x32, 0x61, 0xc6, 0xda, 0xc3, 0xe9, 0xff, 0x31,
+      0x33, 0x53, 0x4a, 0xf8, 0xc9, 0x98, 0xe4, 0x19, 0x71, 0x9c, 0x5e, 0x72,
+      0xc7, 0x35, 0x97, 0x78, 0x30, 0xf2, 0xc4, 0xd1, 0x53, 0xd5, 0x6e, 0x8f,
+      0x4f, 0xd9, 0x28, 0x5a, 0xfd, 0x22, 0x57, 0x7f, 0x95, 0xb4, 0x8a, 0x5e,
+      0x7c, 0x47, 0xa8, 0xcf, 0x64, 0x3d, 0x83, 0xa5, 0xcf, 0xc3, 0xfe, 0x54,
+      0xc2, 0x6a, 0x40, 0xc4, 0xfb, 0x8e, 0x07, 0x77, 0x70, 0x8f, 0x99, 0x94,
+      0xb1, 0xd5, 0xa7, 0xf9, 0x0d, 0xc7, 0x11, 0xc5, 0x6f, 0x4a, 0x4f, 0x56,
+      0xd5, 0xe2, 0x9c, 0xbb, 0x95, 0x7a, 0xd0, 0x9f, 0x30, 0x54, 0xca, 0x6d,
+      0x5c, 0x8e, 0x83, 0xa0, 0x04, 0x5e, 0xd0, 0x22, 0x8c, 0x2a, 0x7f, 0xdb,
+      0xfe, 0xb3, 0x2e, 0xae, 0x22, 0xe6, 0xf4, 0xb7};
+  const uint8_t server_expected_frame5[] = {
+      0x1f, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x33, 0x12, 0xab, 0x9d,
+      0x76, 0x2b, 0x5f, 0xab, 0xf3, 0x6d, 0xc4, 0xaa, 0xe5, 0x1e, 0x63, 0xc1,
+      0x7b, 0x7b, 0x10, 0xd5, 0x63, 0x0f, 0x29, 0xad, 0x17, 0x33, 0x73};
+  const size_t client_frame_size5 =
+      sizeof(client_expected_frame5) / sizeof(uint8_t);
+  const size_t server_frame_size5 =
+      sizeof(server_expected_frame5) / sizeof(uint8_t);
+  fixture = tsi_test_frame_protector_fixture_create();
+  alts_test_do_round_trip_check_frames(
+      fixture, key, kAes128GcmKeyLength, /*rekey=*/false, large_message,
+      large_message_size, client_expected_frame5, client_frame_size5,
+      reinterpret_cast<const uint8_t*>(small_message), small_message_size,
+      server_expected_frame5, server_frame_size5);
+  tsi_test_frame_protector_fixture_destroy(fixture);
+  /**
+   * Test small client message, large server message, and small
+   * server_max_output_protected_frame_size.
+   */
+  const uint8_t client_expected_frame6[] = {
+      0x1f, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x09, 0xd8, 0xd5, 0x92,
+      0x4d, 0x50, 0x32, 0xb7, 0x1f, 0xb8, 0xf2, 0xbb, 0x43, 0xc7, 0xe2, 0x94,
+      0x3d, 0x3e, 0x9a, 0x78, 0x76, 0xaa, 0x0a, 0x6b, 0xfa, 0x98, 0x3a};
+  const uint8_t server_expected_frame6[] = {
+      0x94, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa9, 0x4b, 0xf8, 0xc8,
+      0xe7, 0x8f, 0x1a, 0x26, 0x37, 0x44, 0xa2, 0x5c, 0x55, 0x94, 0x30, 0x4e,
+      0x3e, 0x16, 0xe7, 0x9e, 0x96, 0xe8, 0x1b, 0xc0, 0xdd, 0x52, 0x30, 0x06,
+      0xc2, 0x72, 0x9a, 0xa1, 0x0b, 0xdb, 0xdc, 0x19, 0x8c, 0x93, 0x5e, 0x84,
+      0x1f, 0x4b, 0x97, 0x26, 0xf0, 0x73, 0x85, 0x59, 0x00, 0x95, 0xc1, 0xc5,
+      0x22, 0x2f, 0x70, 0x85, 0x68, 0x2c, 0x4f, 0xfe, 0x30, 0x26, 0x91, 0xde,
+      0x62, 0x55, 0x1d, 0x35, 0x01, 0x96, 0x1c, 0xe7, 0xa2, 0x8b, 0x14, 0x8a,
+      0x5e, 0x1b, 0x4a, 0x3b, 0x4f, 0x65, 0x0f, 0xca, 0x79, 0x10, 0xb4, 0xdd,
+      0xf7, 0xa4, 0x8b, 0x64, 0x2f, 0x00, 0x39, 0x60, 0x03, 0xfc, 0xe1, 0x8b,
+      0x5c, 0x19, 0xba, 0xcc, 0x46, 0xba, 0x88, 0xdd, 0x40, 0x42, 0x27, 0x4f,
+      0xe4, 0x1a, 0x6a, 0x31, 0x6c, 0x1c, 0xb0, 0xb6, 0x5c, 0x3e, 0xca, 0x84,
+      0x9b, 0x5f, 0x04, 0x84, 0x11, 0xa9, 0xf8, 0x39, 0xe7, 0xe7, 0xc5, 0xc4,
+      0x33, 0x9f, 0x63, 0x21, 0x9a, 0x7c, 0x9c, 0x64};
+  const size_t client_frame_size6 =
+      sizeof(client_expected_frame6) / sizeof(uint8_t);
+  const size_t server_frame_size6 =
+      sizeof(server_expected_frame6) / sizeof(uint8_t);
+  fixture = tsi_test_frame_protector_fixture_create();
+  alts_test_do_round_trip_check_frames(
+      fixture, key, kAes128GcmKeyLength, /*rekey=*/false,
+      reinterpret_cast<const uint8_t*>(small_message), small_message_size,
+      client_expected_frame6, client_frame_size6, large_message,
+      large_message_size, server_expected_frame6, server_frame_size6);
+  tsi_test_frame_protector_fixture_destroy(fixture);
+}
+
+static void alts_test_do_round_trip(tsi_test_frame_protector_fixture* fixture,
+                                    bool rekey) {
+  GPR_ASSERT(fixture != nullptr);
+  GPR_ASSERT(fixture->config != nullptr);
+  tsi_frame_protector* client_frame_protector = nullptr;
+  tsi_frame_protector* server_frame_protector = nullptr;
+  tsi_test_frame_protector_config* config = fixture->config;
+  /* Create a key to be used by both client and server. */
+  uint8_t* key = nullptr;
+  size_t key_length = rekey ? kAes128GcmRekeyKeyLength : kAes128GcmKeyLength;
+  gsec_test_random_array(&key, key_length);
+  /* Create a client frame protector. */
+  size_t client_max_output_protected_frame_size =
+      config->client_max_output_protected_frame_size;
+  GPR_ASSERT(
+      alts_create_frame_protector(key, key_length, /*is_client=*/true, rekey,
+                                  client_max_output_protected_frame_size == 0
+                                      ? nullptr
+                                      : &client_max_output_protected_frame_size,
+                                  &client_frame_protector) == TSI_OK);
+  /* Create a server frame protector. */
+  size_t server_max_output_protected_frame_size =
+      config->server_max_output_protected_frame_size;
+  GPR_ASSERT(
+      alts_create_frame_protector(key, key_length, /*is_client=*/false, rekey,
+                                  server_max_output_protected_frame_size == 0
+                                      ? nullptr
+                                      : &server_max_output_protected_frame_size,
+                                  &server_frame_protector) == TSI_OK);
+  tsi_test_frame_protector_fixture_init(fixture, client_frame_protector,
+                                        server_frame_protector);
+  tsi_test_frame_protector_do_round_trip_no_handshake(fixture);
+  gpr_free(key);
+}
+
+/* Run all combinations of different arguments of test config. */
+static void alts_test_do_round_trip_all(bool rekey) {
+  unsigned int* bit_array = static_cast<unsigned int*>(
+      gpr_malloc(sizeof(unsigned int) * TSI_TEST_NUM_OF_ARGUMENTS));
+  unsigned int mask = 1U << (TSI_TEST_NUM_OF_ARGUMENTS - 1);
+  unsigned int val = 0, ind = 0;
+  for (val = 0; val < TSI_TEST_NUM_OF_COMBINATIONS; val++) {
+    unsigned int v = val;
+    for (ind = 0; ind < TSI_TEST_NUM_OF_ARGUMENTS; ind++) {
+      bit_array[ind] = (v & mask) ? 1 : 0;
+      v <<= 1;
+    }
+    tsi_test_frame_protector_fixture* fixture =
+        tsi_test_frame_protector_fixture_create();
+    tsi_test_frame_protector_config_destroy(fixture->config);
+    fixture->config = tsi_test_frame_protector_config_create(
+        bit_array[0], bit_array[1], bit_array[2], bit_array[3], bit_array[4],
+        bit_array[5], bit_array[6]);
+    alts_test_do_round_trip(fixture, rekey);
+    tsi_test_frame_protector_fixture_destroy(fixture);
+  }
+  gpr_free(bit_array);
+}
+
+int main(int argc, char** argv) {
+  alts_test_do_round_trip_vector_tests();
+  alts_test_do_round_trip_all(/*rekey=*/false);
+  alts_test_do_round_trip_all(/*rekey=*/true);
+  return 0;
+}
diff --git a/test/core/tsi/alts/frame_protector/frame_handler_test.cc b/test/core/tsi/alts/frame_protector/frame_handler_test.cc
new file mode 100644
index 0000000..6434ea1
--- /dev/null
+++ b/test/core/tsi/alts/frame_protector/frame_handler_test.cc
@@ -0,0 +1,244 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/tsi/alts/frame_protector/frame_handler.h"
+#include "test/core/tsi/alts/crypt/gsec_test_util.h"
+
+const size_t kFrameHandlerTestBufferSize = 1024;
+
+typedef struct frame_handler {
+  alts_frame_writer* writer;
+  alts_frame_reader* reader;
+  unsigned char* buffer;
+  size_t buffer_size;
+} frame_handler;
+
+static size_t frame_length(size_t payload_length) {
+  return payload_length + kFrameHeaderSize;
+}
+
+static frame_handler* create_frame_handler() {
+  frame_handler* handler =
+      static_cast<frame_handler*>(gpr_malloc(sizeof(frame_handler)));
+  handler->writer = alts_create_frame_writer();
+  handler->reader = alts_create_frame_reader();
+  handler->buffer = nullptr;
+  handler->buffer_size = 0;
+  return handler;
+}
+
+static void destroy_frame_handler(frame_handler* handler) {
+  if (handler != nullptr) {
+    alts_destroy_frame_reader(handler->reader);
+    alts_destroy_frame_writer(handler->writer);
+    if (handler->buffer != nullptr) gpr_free(handler->buffer);
+    gpr_free(handler);
+  }
+}
+
+static void frame(frame_handler* handler, unsigned char* payload,
+                  size_t payload_length, size_t write_length) {
+  handler->buffer_size = frame_length(payload_length);
+  handler->buffer =
+      static_cast<unsigned char*>(gpr_malloc(handler->buffer_size));
+  GPR_ASSERT(alts_reset_frame_writer(handler->writer, payload, payload_length));
+  size_t offset = 0;
+  while (offset < handler->buffer_size &&
+         !alts_is_frame_writer_done(handler->writer)) {
+    size_t bytes_written = GPR_MIN(write_length, handler->buffer_size - offset);
+    GPR_ASSERT(alts_write_frame_bytes(handler->writer, handler->buffer + offset,
+                                      &bytes_written));
+    offset += bytes_written;
+  }
+  GPR_ASSERT(alts_is_frame_writer_done(handler->writer));
+  GPR_ASSERT(handler->buffer_size == offset);
+}
+
+static size_t deframe(frame_handler* handler, unsigned char* bytes,
+                      size_t read_length) {
+  GPR_ASSERT(alts_reset_frame_reader(handler->reader, bytes));
+  size_t offset = 0;
+  while (offset < handler->buffer_size &&
+         !alts_is_frame_reader_done(handler->reader)) {
+    size_t bytes_read = GPR_MIN(read_length, handler->buffer_size - offset);
+    GPR_ASSERT(alts_read_frame_bytes(handler->reader, handler->buffer + offset,
+                                     &bytes_read));
+    offset += bytes_read;
+  }
+  GPR_ASSERT(alts_is_frame_reader_done(handler->reader));
+  GPR_ASSERT(handler->buffer_size == offset);
+  return offset - handler->reader->header_bytes_read;
+}
+
+static void frame_n_deframe(frame_handler* handler, unsigned char* payload,
+                            size_t payload_length, size_t write_length,
+                            size_t read_length) {
+  frame(handler, payload, payload_length, write_length);
+  unsigned char* bytes =
+      static_cast<unsigned char*>(gpr_malloc(kFrameHandlerTestBufferSize));
+  size_t deframed_payload_length = deframe(handler, bytes, read_length);
+  GPR_ASSERT(payload_length == deframed_payload_length);
+  GPR_ASSERT(memcmp(payload, bytes, payload_length) == 0);
+  gpr_free(bytes);
+}
+
+static void frame_handler_test_frame_deframe() {
+  unsigned char payload[] = "hello world";
+  size_t payload_length = strlen((char*)payload) + 1;
+  frame_handler* handler = create_frame_handler();
+  frame_n_deframe(handler, payload, payload_length,
+                  frame_length(payload_length), frame_length(payload_length));
+  destroy_frame_handler(handler);
+}
+
+static void frame_handler_test_small_buffer() {
+  unsigned char payload[] = "hello world";
+  size_t payload_length = strlen(reinterpret_cast<char*>(payload)) + 1;
+  frame_handler* handler = create_frame_handler();
+  frame_n_deframe(handler, payload, payload_length, 1, 1);
+  destroy_frame_handler(handler);
+}
+
+static void frame_handler_test_null_input_stream() {
+  frame_handler* handler = create_frame_handler();
+  GPR_ASSERT(!alts_reset_frame_writer(handler->writer, nullptr, 0));
+  destroy_frame_handler(handler);
+}
+
+static void frame_handler_test_bad_input_length() {
+  unsigned char payload[] = "hello world";
+  frame_handler* handler = create_frame_handler();
+  GPR_ASSERT(!alts_reset_frame_writer(handler->writer, payload, SIZE_MAX));
+  destroy_frame_handler(handler);
+}
+
+static void frame_handler_test_null_writer_byte_length() {
+  unsigned char payload[] = "hello world";
+  size_t payload_length = strlen(reinterpret_cast<char*>(payload)) + 1;
+  frame_handler* handler = create_frame_handler();
+  GPR_ASSERT(alts_reset_frame_writer(handler->writer, payload, payload_length));
+  GPR_ASSERT(
+      !alts_write_frame_bytes(handler->writer, handler->buffer, nullptr));
+  destroy_frame_handler(handler);
+}
+
+static void frame_handler_test_null_writer_bytes() {
+  unsigned char payload[] = "hello world";
+  size_t payload_length = strlen(reinterpret_cast<char*>(payload)) + 1;
+  frame_handler* handler = create_frame_handler();
+  GPR_ASSERT(alts_reset_frame_writer(handler->writer, payload, payload_length));
+  GPR_ASSERT(
+      !alts_write_frame_bytes(handler->writer, nullptr, &payload_length));
+  destroy_frame_handler(handler);
+}
+
+static void frame_handler_test_bad_frame_length() {
+  unsigned char payload[] = "hello world";
+  size_t payload_length = strlen(reinterpret_cast<char*>(payload)) + 1;
+  frame_handler* handler = create_frame_handler();
+  frame(handler, payload, payload_length, payload_length);
+  memset(handler->buffer, 0x00, kFrameLengthFieldSize);
+  unsigned char* bytes =
+      static_cast<unsigned char*>(gpr_malloc(kFrameHandlerTestBufferSize));
+  GPR_ASSERT(alts_reset_frame_reader(handler->reader, bytes));
+  size_t bytes_read = handler->buffer_size;
+  GPR_ASSERT(
+      !alts_read_frame_bytes(handler->reader, handler->buffer, &bytes_read));
+  GPR_ASSERT(alts_is_frame_reader_done(handler->reader));
+  GPR_ASSERT(bytes_read == 0);
+  gpr_free(bytes);
+  destroy_frame_handler(handler);
+}
+
+static void frame_handler_test_unsupported_message_type() {
+  unsigned char payload[] = "hello world";
+  size_t payload_length = strlen(reinterpret_cast<char*>(payload)) + 1;
+  frame_handler* handler = create_frame_handler();
+  frame(handler, payload, payload_length, payload_length);
+  memset(handler->buffer + kFrameLengthFieldSize, 0x00,
+         kFrameMessageTypeFieldSize);
+  unsigned char* bytes =
+      static_cast<unsigned char*>(gpr_malloc(kFrameHandlerTestBufferSize));
+  GPR_ASSERT(alts_reset_frame_reader(handler->reader, bytes));
+  size_t bytes_read = handler->buffer_size;
+  GPR_ASSERT(
+      !alts_read_frame_bytes(handler->reader, handler->buffer, &bytes_read));
+  GPR_ASSERT(alts_is_frame_reader_done(handler->reader));
+  GPR_ASSERT(bytes_read == 0);
+  gpr_free(bytes);
+  destroy_frame_handler(handler);
+}
+
+static void frame_handler_test_null_output_stream() {
+  unsigned char payload[] = "hello world";
+  size_t payload_length = strlen(reinterpret_cast<char*>(payload)) + 1;
+  frame_handler* handler = create_frame_handler();
+  frame(handler, payload, payload_length, payload_length);
+  GPR_ASSERT(!alts_reset_frame_reader(handler->reader, nullptr));
+  destroy_frame_handler(handler);
+}
+
+static void frame_handler_test_null_reader_byte_length() {
+  unsigned char payload[] = "hello world";
+  size_t payload_length = strlen(reinterpret_cast<char*>(payload)) + 1;
+  frame_handler* handler = create_frame_handler();
+  frame(handler, payload, payload_length, payload_length);
+  unsigned char* bytes =
+      static_cast<unsigned char*>(gpr_malloc(kFrameHandlerTestBufferSize));
+  GPR_ASSERT(alts_reset_frame_reader(handler->reader, bytes));
+  GPR_ASSERT(!alts_read_frame_bytes(handler->reader, handler->buffer, nullptr));
+  gpr_free(bytes);
+  destroy_frame_handler(handler);
+}
+
+static void frame_handler_test_null_reader_bytes() {
+  unsigned char payload[] = "hello world";
+  size_t payload_length = strlen(reinterpret_cast<char*>(payload)) + 1;
+  frame_handler* handler = create_frame_handler();
+  frame(handler, payload, payload_length, payload_length);
+  unsigned char* bytes =
+      static_cast<unsigned char*>(gpr_malloc(kFrameHandlerTestBufferSize));
+  GPR_ASSERT(alts_reset_frame_reader(handler->reader, bytes));
+  size_t bytes_read = handler->buffer_size;
+  GPR_ASSERT(!alts_read_frame_bytes(handler->reader, nullptr, &bytes_read));
+  gpr_free(bytes);
+  destroy_frame_handler(handler);
+}
+
+int main(int argc, char** argv) {
+  frame_handler_test_frame_deframe();
+  frame_handler_test_small_buffer();
+  frame_handler_test_null_input_stream();
+  frame_handler_test_bad_input_length();
+  frame_handler_test_null_writer_byte_length();
+  frame_handler_test_null_writer_bytes();
+  frame_handler_test_bad_frame_length();
+  frame_handler_test_unsupported_message_type();
+  frame_handler_test_null_output_stream();
+  frame_handler_test_null_reader_byte_length();
+  frame_handler_test_null_reader_bytes();
+  return 0;
+}
diff --git a/test/core/tsi/alts/handshaker/BUILD b/test/core/tsi/alts/handshaker/BUILD
new file mode 100644
index 0000000..fc2c395
--- /dev/null
+++ b/test/core/tsi/alts/handshaker/BUILD
@@ -0,0 +1,86 @@
+# Copyright 2018 gRPC authors.
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_package")
+
+licenses(["notice"])  # Apache v2 
+         
+grpc_package(name = "handshaker")
+         
+grpc_cc_library(
+    name = "alts_handshaker_service_api_test_lib",
+    srcs = ["alts_handshaker_service_api_test_lib.cc"],
+    hdrs = ["alts_handshaker_service_api_test_lib.h"],
+    deps = [
+        "//:alts_util",
+        "//:grpc",
+    ], 
+)
+
+grpc_cc_test(
+    name = "alts_handshaker_client_test",
+    srcs = ["alts_handshaker_client_test.cc"],
+    language = "C++",
+    deps = [
+        ":alts_handshaker_service_api_test_lib",
+        "//:tsi",
+        "//:tsi_interface",
+        "//:grpc",
+    ],
+)
+
+grpc_cc_test(
+    name = "alts_handshaker_service_api_test",
+    srcs = ["alts_handshaker_service_api_test.cc"],
+    language = "C++",
+    deps = [
+        ":alts_handshaker_service_api_test_lib",
+        "//:grpc",
+    ],
+)
+
+grpc_cc_test(
+    name = "alts_tsi_handshaker_test",
+    srcs = ["alts_tsi_handshaker_test.cc"],
+    language = "C++",
+    deps = [
+        ":alts_handshaker_service_api_test_lib",
+        "//:gpr",
+        "//:gpr_base",
+        "//:grpc",
+        "//:tsi",
+    ],
+)
+
+grpc_cc_test(
+    name = "alts_tsi_utils_test",
+    srcs = ["alts_tsi_utils_test.cc"],
+    language = "C++",
+    deps = [
+        ":alts_handshaker_service_api_test_lib",
+        "//:grpc",
+        "//:tsi",
+    ],
+)
+
+grpc_cc_test(
+    name = "transport_security_common_api_test",
+    srcs = ["transport_security_common_api_test.cc"],
+    language = "C++",
+    deps = [
+        "//:alts_util",
+        "//:grpc",
+    ],
+)
+
diff --git a/test/core/tsi/alts/handshaker/alts_handshaker_client_test.cc b/test/core/tsi/alts/handshaker/alts_handshaker_client_test.cc
new file mode 100644
index 0000000..7072be6
--- /dev/null
+++ b/test/core/tsi/alts/handshaker/alts_handshaker_client_test.cc
@@ -0,0 +1,412 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/grpc.h>
+
+#include "src/core/tsi/alts/handshaker/alts_handshaker_client.h"
+#include "src/core/tsi/alts/handshaker/alts_tsi_event.h"
+#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h"
+#include "src/core/tsi/transport_security.h"
+#include "src/core/tsi/transport_security_interface.h"
+#include "test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.h"
+
+#define ALTS_HANDSHAKER_CLIENT_TEST_OUT_FRAME "Hello Google"
+#define ALTS_HANDSHAKER_CLIENT_TEST_HANDSHAKER_SERVICE_URL "lame"
+#define ALTS_HANDSHAKER_CLIENT_TEST_TARGET_NAME "bigtable.google.api.com"
+#define ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT1 "A@google.com"
+#define ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT2 "B@google.com"
+
+const size_t kHandshakerClientOpNum = 4;
+const size_t kMaxRpcVersionMajor = 3;
+const size_t kMaxRpcVersionMinor = 2;
+const size_t kMinRpcVersionMajor = 2;
+const size_t kMinRpcVersionMinor = 1;
+
+using grpc_core::internal::alts_handshaker_client_set_grpc_caller_for_testing;
+
+typedef struct alts_handshaker_client_test_config {
+  grpc_channel* channel;
+  grpc_completion_queue* cq;
+  alts_handshaker_client* client;
+  grpc_slice out_frame;
+} alts_handshaker_client_test_config;
+
+static alts_tsi_event* alts_tsi_event_create_for_testing(bool is_client) {
+  alts_tsi_event* e = static_cast<alts_tsi_event*>(gpr_zalloc(sizeof(*e)));
+  grpc_metadata_array_init(&e->initial_metadata);
+  grpc_metadata_array_init(&e->trailing_metadata);
+  e->options = is_client ? grpc_alts_credentials_client_options_create()
+                         : grpc_alts_credentials_server_options_create();
+  if (is_client) {
+    grpc_alts_credentials_client_options_add_target_service_account(
+        reinterpret_cast<grpc_alts_credentials_client_options*>(e->options),
+        ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT1);
+    grpc_alts_credentials_client_options_add_target_service_account(
+        reinterpret_cast<grpc_alts_credentials_client_options*>(e->options),
+        ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT2);
+  }
+  grpc_gcp_rpc_protocol_versions* versions = &e->options->rpc_versions;
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_max(
+      versions, kMaxRpcVersionMajor, kMaxRpcVersionMinor));
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_min(
+      versions, kMinRpcVersionMajor, kMinRpcVersionMinor));
+  e->target_name =
+      grpc_slice_from_static_string(ALTS_HANDSHAKER_CLIENT_TEST_TARGET_NAME);
+  return e;
+}
+
+static void validate_rpc_protocol_versions(
+    grpc_gcp_rpc_protocol_versions* versions) {
+  GPR_ASSERT(versions != nullptr);
+  GPR_ASSERT(versions->max_rpc_version.major == kMaxRpcVersionMajor);
+  GPR_ASSERT(versions->max_rpc_version.minor == kMaxRpcVersionMinor);
+  GPR_ASSERT(versions->min_rpc_version.major == kMinRpcVersionMajor);
+  GPR_ASSERT(versions->min_rpc_version.minor == kMinRpcVersionMinor);
+}
+
+static void validate_target_identities(
+    const repeated_field* target_identity_head) {
+  grpc_gcp_identity* target_identity1 = static_cast<grpc_gcp_identity*>(
+      const_cast<void*>(target_identity_head->next->data));
+  grpc_gcp_identity* target_identity2 = static_cast<grpc_gcp_identity*>(
+      const_cast<void*>(target_identity_head->data));
+  grpc_slice* service_account1 =
+      static_cast<grpc_slice*>(target_identity1->service_account.arg);
+  grpc_slice* service_account2 =
+      static_cast<grpc_slice*>(target_identity2->service_account.arg);
+  GPR_ASSERT(memcmp(GRPC_SLICE_START_PTR(*service_account1),
+                    ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT1,
+                    GRPC_SLICE_LENGTH(*service_account1)) == 0);
+  GPR_ASSERT(strlen(ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT1) ==
+             GRPC_SLICE_LENGTH(*service_account1));
+  GPR_ASSERT(memcmp(GRPC_SLICE_START_PTR(*service_account2),
+                    ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT2,
+                    GRPC_SLICE_LENGTH(*service_account2)) == 0);
+  GPR_ASSERT(strlen(ALTS_HANDSHAKER_CLIENT_TEST_TARGET_SERVICE_ACCOUNT2) ==
+             GRPC_SLICE_LENGTH(*service_account2));
+}
+
+/**
+ * Validate if grpc operation data is correctly populated with the fields of
+ * ALTS TSI event.
+ */
+static bool validate_op(alts_tsi_event* event, const grpc_op* op, size_t nops,
+                        bool is_start) {
+  GPR_ASSERT(event != nullptr && op != nullptr && nops != 0);
+  bool ok = true;
+  grpc_op* start_op = const_cast<grpc_op*>(op);
+  if (is_start) {
+    ok &= (op->op == GRPC_OP_SEND_INITIAL_METADATA);
+    ok &= (op->data.send_initial_metadata.count == 0);
+    op++;
+    GPR_ASSERT((size_t)(op - start_op) <= kHandshakerClientOpNum);
+
+    ok &= (op->op == GRPC_OP_RECV_INITIAL_METADATA);
+    ok &= (op->data.recv_initial_metadata.recv_initial_metadata ==
+           &event->initial_metadata);
+    op++;
+    GPR_ASSERT((size_t)(op - start_op) <= kHandshakerClientOpNum);
+  }
+  ok &= (op->op == GRPC_OP_SEND_MESSAGE);
+  ok &= (op->data.send_message.send_message == event->send_buffer);
+  op++;
+  GPR_ASSERT((size_t)(op - start_op) <= kHandshakerClientOpNum);
+
+  ok &= (op->op == GRPC_OP_RECV_MESSAGE);
+  ok &= (op->data.recv_message.recv_message == &event->recv_buffer);
+  op++;
+  GPR_ASSERT((size_t)(op - start_op) <= kHandshakerClientOpNum);
+
+  return ok;
+}
+
+static grpc_gcp_handshaker_req* deserialize_handshaker_req(
+    grpc_gcp_handshaker_req_type type, grpc_byte_buffer* buffer) {
+  GPR_ASSERT(buffer != nullptr);
+  grpc_gcp_handshaker_req* req = grpc_gcp_handshaker_decoded_req_create(type);
+  grpc_byte_buffer_reader bbr;
+  GPR_ASSERT(grpc_byte_buffer_reader_init(&bbr, buffer));
+  grpc_slice slice = grpc_byte_buffer_reader_readall(&bbr);
+  GPR_ASSERT(grpc_gcp_handshaker_req_decode(slice, req));
+  grpc_slice_unref(slice);
+  grpc_byte_buffer_reader_destroy(&bbr);
+  return req;
+}
+
+/**
+ * A mock grpc_caller used to check if client_start, server_start, and next
+ * operations correctly handle invalid arguments. It should not be called.
+ */
+static grpc_call_error check_must_not_be_called(grpc_call* call,
+                                                const grpc_op* ops, size_t nops,
+                                                void* tag) {
+  GPR_ASSERT(0);
+}
+
+/**
+ * A mock grpc_caller used to check correct execution of client_start operation.
+ * It checks if the client_start handshaker request is populated with correct
+ * handshake_security_protocol, application_protocol, and record_protocol, and
+ * op is correctly populated.
+ */
+static grpc_call_error check_client_start_success(grpc_call* call,
+                                                  const grpc_op* op,
+                                                  size_t nops, void* tag) {
+  alts_tsi_event* event = static_cast<alts_tsi_event*>(tag);
+  grpc_gcp_handshaker_req* req =
+      deserialize_handshaker_req(CLIENT_START_REQ, event->send_buffer);
+  GPR_ASSERT(req->client_start.handshake_security_protocol ==
+             grpc_gcp_HandshakeProtocol_ALTS);
+  const void* data = (static_cast<repeated_field*>(
+                          req->client_start.application_protocols.arg))
+                         ->data;
+  GPR_ASSERT(data != nullptr);
+  grpc_slice* application_protocol = (grpc_slice*)data;
+  data = (static_cast<repeated_field*>(req->client_start.record_protocols.arg))
+             ->data;
+  grpc_slice* record_protocol = (grpc_slice*)data;
+  GPR_ASSERT(memcmp(GRPC_SLICE_START_PTR(*application_protocol),
+                    ALTS_APPLICATION_PROTOCOL,
+                    GRPC_SLICE_LENGTH(*application_protocol)) == 0);
+  GPR_ASSERT(memcmp(GRPC_SLICE_START_PTR(*record_protocol),
+                    ALTS_RECORD_PROTOCOL,
+                    GRPC_SLICE_LENGTH(*record_protocol)) == 0);
+  validate_rpc_protocol_versions(&req->client_start.rpc_versions);
+  validate_target_identities(
+      static_cast<repeated_field*>(req->client_start.target_identities.arg));
+  grpc_slice* target_name =
+      static_cast<grpc_slice*>(req->client_start.target_name.arg);
+  GPR_ASSERT(memcmp(GRPC_SLICE_START_PTR(*target_name),
+                    ALTS_HANDSHAKER_CLIENT_TEST_TARGET_NAME,
+                    GRPC_SLICE_LENGTH(*target_name)) == 0);
+  GPR_ASSERT(GRPC_SLICE_LENGTH(*target_name) ==
+             strlen(ALTS_HANDSHAKER_CLIENT_TEST_TARGET_NAME));
+  GPR_ASSERT(validate_op(event, op, nops, true /* is_start */));
+  grpc_gcp_handshaker_req_destroy(req);
+  return GRPC_CALL_OK;
+}
+
+/**
+ * A mock grpc_caller used to check correct execution of server_start operation.
+ * It checks if the server_start handshaker request is populated with correct
+ * handshake_security_protocol, application_protocol, and record_protocol, and
+ * op is correctly populated.
+ */
+static grpc_call_error check_server_start_success(grpc_call* call,
+                                                  const grpc_op* op,
+                                                  size_t nops, void* tag) {
+  alts_tsi_event* event = static_cast<alts_tsi_event*>(tag);
+  grpc_gcp_handshaker_req* req =
+      deserialize_handshaker_req(SERVER_START_REQ, event->send_buffer);
+  const void* data = (static_cast<repeated_field*>(
+                          req->server_start.application_protocols.arg))
+                         ->data;
+  GPR_ASSERT(data != nullptr);
+  grpc_slice* application_protocol = (grpc_slice*)data;
+  GPR_ASSERT(memcmp(GRPC_SLICE_START_PTR(*application_protocol),
+                    ALTS_APPLICATION_PROTOCOL,
+                    GRPC_SLICE_LENGTH(*application_protocol)) == 0);
+  GPR_ASSERT(req->server_start.handshake_parameters_count == 1);
+  GPR_ASSERT(req->server_start.handshake_parameters[0].key ==
+             grpc_gcp_HandshakeProtocol_ALTS);
+  data = (static_cast<repeated_field*>(req->server_start.handshake_parameters[0]
+                                           .value.record_protocols.arg))
+             ->data;
+  GPR_ASSERT(data != nullptr);
+  grpc_slice* record_protocol = (grpc_slice*)data;
+  GPR_ASSERT(memcmp(GRPC_SLICE_START_PTR(*record_protocol),
+                    ALTS_RECORD_PROTOCOL,
+                    GRPC_SLICE_LENGTH(*record_protocol)) == 0);
+  validate_rpc_protocol_versions(&req->server_start.rpc_versions);
+  GPR_ASSERT(validate_op(event, op, nops, true /* is_start */));
+  grpc_gcp_handshaker_req_destroy(req);
+  return GRPC_CALL_OK;
+}
+
+/**
+ * A mock grpc_caller used to check correct execution of next operation. It
+ * checks if the next handshaker request is populated with correct information,
+ * and op is correctly populated.
+ */
+static grpc_call_error check_next_success(grpc_call* call, const grpc_op* op,
+                                          size_t nops, void* tag) {
+  alts_tsi_event* event = static_cast<alts_tsi_event*>(tag);
+  grpc_gcp_handshaker_req* req =
+      deserialize_handshaker_req(NEXT_REQ, event->send_buffer);
+  grpc_slice* in_bytes = static_cast<grpc_slice*>(req->next.in_bytes.arg);
+  GPR_ASSERT(in_bytes != nullptr);
+  GPR_ASSERT(memcmp(GRPC_SLICE_START_PTR(*in_bytes),
+                    ALTS_HANDSHAKER_CLIENT_TEST_OUT_FRAME,
+                    GRPC_SLICE_LENGTH(*in_bytes)) == 0);
+  GPR_ASSERT(validate_op(event, op, nops, false /* is_start */));
+  grpc_gcp_handshaker_req_destroy(req);
+  return GRPC_CALL_OK;
+}
+/**
+ * A mock grpc_caller used to check if client_start, server_start, and next
+ * operations correctly handle the situation when the grpc call made to the
+ * handshaker service fails.
+ */
+static grpc_call_error check_grpc_call_failure(grpc_call* call,
+                                               const grpc_op* op, size_t nops,
+                                               void* tag) {
+  return GRPC_CALL_ERROR;
+}
+
+static alts_handshaker_client_test_config* create_config() {
+  alts_handshaker_client_test_config* config =
+      static_cast<alts_handshaker_client_test_config*>(
+          gpr_zalloc(sizeof(*config)));
+  config->channel = grpc_insecure_channel_create(
+      ALTS_HANDSHAKER_CLIENT_TEST_HANDSHAKER_SERVICE_URL, nullptr, nullptr);
+  config->cq = grpc_completion_queue_create_for_next(nullptr);
+  config->client = alts_grpc_handshaker_client_create(
+      config->channel, config->cq,
+      ALTS_HANDSHAKER_CLIENT_TEST_HANDSHAKER_SERVICE_URL);
+  GPR_ASSERT(config->client != nullptr);
+  config->out_frame =
+      grpc_slice_from_static_string(ALTS_HANDSHAKER_CLIENT_TEST_OUT_FRAME);
+  return config;
+}
+
+static void destroy_config(alts_handshaker_client_test_config* config) {
+  if (config == nullptr) {
+    return;
+  }
+  grpc_completion_queue_destroy(config->cq);
+  grpc_channel_destroy(config->channel);
+  alts_handshaker_client_destroy(config->client);
+  grpc_slice_unref(config->out_frame);
+  gpr_free(config);
+}
+
+static void schedule_request_invalid_arg_test() {
+  /* Initialization. */
+  alts_handshaker_client_test_config* config = create_config();
+  alts_tsi_event* event = nullptr;
+
+  /* Tests. */
+  alts_handshaker_client_set_grpc_caller_for_testing(config->client,
+                                                     check_must_not_be_called);
+  event = alts_tsi_event_create_for_testing(true /* is_client */);
+  /* Check client_start. */
+  GPR_ASSERT(alts_handshaker_client_start_client(nullptr, event) ==
+             TSI_INVALID_ARGUMENT);
+  GPR_ASSERT(alts_handshaker_client_start_client(config->client, nullptr) ==
+             TSI_INVALID_ARGUMENT);
+
+  /* Check server_start. */
+  GPR_ASSERT(alts_handshaker_client_start_server(
+                 config->client, event, nullptr) == TSI_INVALID_ARGUMENT);
+  GPR_ASSERT(alts_handshaker_client_start_server(config->client, nullptr,
+                                                 &config->out_frame) ==
+             TSI_INVALID_ARGUMENT);
+  GPR_ASSERT(alts_handshaker_client_start_server(
+                 nullptr, event, &config->out_frame) == TSI_INVALID_ARGUMENT);
+
+  /* Check next. */
+  GPR_ASSERT(alts_handshaker_client_next(config->client, event, nullptr) ==
+             TSI_INVALID_ARGUMENT);
+  GPR_ASSERT(alts_handshaker_client_next(config->client, nullptr,
+                                         &config->out_frame) ==
+             TSI_INVALID_ARGUMENT);
+  GPR_ASSERT(alts_handshaker_client_next(nullptr, event, &config->out_frame) ==
+             TSI_INVALID_ARGUMENT);
+
+  /* Cleanup. */
+  alts_tsi_event_destroy(event);
+  destroy_config(config);
+}
+
+static void schedule_request_success_test() {
+  /* Initialization. */
+  alts_handshaker_client_test_config* config = create_config();
+  alts_tsi_event* event = nullptr;
+
+  /* Check client_start success. */
+  alts_handshaker_client_set_grpc_caller_for_testing(
+      config->client, check_client_start_success);
+  event = alts_tsi_event_create_for_testing(true /* is_client. */);
+  GPR_ASSERT(alts_handshaker_client_start_client(config->client, event) ==
+             TSI_OK);
+  alts_tsi_event_destroy(event);
+
+  /* Check server_start success. */
+  alts_handshaker_client_set_grpc_caller_for_testing(
+      config->client, check_server_start_success);
+  event = alts_tsi_event_create_for_testing(false /* is_client. */);
+  GPR_ASSERT(alts_handshaker_client_start_server(config->client, event,
+                                                 &config->out_frame) == TSI_OK);
+  alts_tsi_event_destroy(event);
+
+  /* Check next success. */
+  alts_handshaker_client_set_grpc_caller_for_testing(config->client,
+                                                     check_next_success);
+  event = alts_tsi_event_create_for_testing(true /* is_client. */);
+  GPR_ASSERT(alts_handshaker_client_next(config->client, event,
+                                         &config->out_frame) == TSI_OK);
+  alts_tsi_event_destroy(event);
+
+  /* Cleanup. */
+  destroy_config(config);
+}
+
+static void schedule_request_grpc_call_failure_test() {
+  /* Initialization. */
+  alts_handshaker_client_test_config* config = create_config();
+  alts_tsi_event* event = nullptr;
+
+  /* Check client_start failure. */
+  alts_handshaker_client_set_grpc_caller_for_testing(config->client,
+                                                     check_grpc_call_failure);
+  event = alts_tsi_event_create_for_testing(true /* is_client. */);
+  GPR_ASSERT(alts_handshaker_client_start_client(config->client, event) ==
+             TSI_INTERNAL_ERROR);
+  alts_tsi_event_destroy(event);
+
+  /* Check server_start failure. */
+  event = alts_tsi_event_create_for_testing(false /* is_client. */);
+  GPR_ASSERT(alts_handshaker_client_start_server(config->client, event,
+                                                 &config->out_frame) ==
+             TSI_INTERNAL_ERROR);
+  alts_tsi_event_destroy(event);
+
+  /* Check next failure. */
+  event = alts_tsi_event_create_for_testing(true /* is_cleint. */);
+  GPR_ASSERT(
+      alts_handshaker_client_next(config->client, event, &config->out_frame) ==
+      TSI_INTERNAL_ERROR);
+  alts_tsi_event_destroy(event);
+
+  /* Cleanup. */
+  destroy_config(config);
+}
+
+int main(int argc, char** argv) {
+  /* Initialization. */
+  grpc_init();
+
+  /* Tests. */
+  schedule_request_invalid_arg_test();
+  schedule_request_success_test();
+  schedule_request_grpc_call_failure_test();
+
+  /* Cleanup. */
+  grpc_shutdown();
+  return 0;
+}
diff --git a/test/core/tsi/alts/handshaker/alts_handshaker_service_api_test.cc b/test/core/tsi/alts/handshaker/alts_handshaker_service_api_test.cc
new file mode 100644
index 0000000..3506264
--- /dev/null
+++ b/test/core/tsi/alts/handshaker/alts_handshaker_service_api_test.cc
@@ -0,0 +1,149 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.h"
+
+int main(int argc, char** argv) {
+  const char in_bytes[] = "HELLO GOOGLE!";
+  const char out_frames[] = "HELLO WORLD!";
+  const char key_data[] = "THIS IS KEY DATA.";
+  const char details[] = "DETAILS NEED TO BE POPULATED";
+  const uint32_t max_rpc_version_major = 3;
+  const uint32_t max_rpc_version_minor = 2;
+  const uint32_t min_rpc_version_major = 2;
+  const uint32_t min_rpc_version_minor = 1;
+
+  /* handshaker_req_next. */
+  grpc_gcp_handshaker_req* req = grpc_gcp_handshaker_req_create(NEXT_REQ);
+  grpc_gcp_handshaker_req* decoded_req =
+      grpc_gcp_handshaker_decoded_req_create(NEXT_REQ);
+  GPR_ASSERT(
+      grpc_gcp_handshaker_req_set_in_bytes(req, in_bytes, strlen(in_bytes)));
+  grpc_slice encoded_req;
+  GPR_ASSERT(grpc_gcp_handshaker_req_encode(req, &encoded_req));
+  GPR_ASSERT(grpc_gcp_handshaker_req_decode(encoded_req, decoded_req));
+  GPR_ASSERT(grpc_gcp_handshaker_req_equals(req, decoded_req));
+  grpc_gcp_handshaker_req_destroy(req);
+  grpc_gcp_handshaker_req_destroy(decoded_req);
+  grpc_slice_unref(encoded_req);
+
+  /* handshaker_req_client_start. */
+  req = grpc_gcp_handshaker_req_create(CLIENT_START_REQ);
+  decoded_req = grpc_gcp_handshaker_decoded_req_create(CLIENT_START_REQ);
+  GPR_ASSERT(grpc_gcp_handshaker_req_set_handshake_protocol(
+      req, grpc_gcp_HandshakeProtocol_TLS));
+  GPR_ASSERT(grpc_gcp_handshaker_req_set_local_identity_hostname(
+      req, "www.google.com"));
+  GPR_ASSERT(grpc_gcp_handshaker_req_set_local_endpoint(
+      req, "2001:db8::8:800:200C:417a", 9876, grpc_gcp_NetworkProtocol_TCP));
+  GPR_ASSERT(grpc_gcp_handshaker_req_set_remote_endpoint(
+      req, "2001:db8::bac5::fed0:84a2", 1234, grpc_gcp_NetworkProtocol_TCP));
+  GPR_ASSERT(grpc_gcp_handshaker_req_add_application_protocol(req, "grpc"));
+  GPR_ASSERT(grpc_gcp_handshaker_req_add_application_protocol(req, "http2"));
+  GPR_ASSERT(
+      grpc_gcp_handshaker_req_add_record_protocol(req, "ALTSRP_GCM_AES256"));
+  GPR_ASSERT(
+      grpc_gcp_handshaker_req_add_record_protocol(req, "ALTSRP_GCM_AES384"));
+  GPR_ASSERT(grpc_gcp_handshaker_req_add_target_identity_service_account(
+      req, "foo@google.com"));
+  GPR_ASSERT(grpc_gcp_handshaker_req_set_target_name(
+      req, "google.example.library.service"));
+  GPR_ASSERT(grpc_gcp_handshaker_req_set_rpc_versions(
+      req, max_rpc_version_major, max_rpc_version_minor, min_rpc_version_major,
+      min_rpc_version_minor));
+  GPR_ASSERT(grpc_gcp_handshaker_req_encode(req, &encoded_req));
+  GPR_ASSERT(grpc_gcp_handshaker_req_decode(encoded_req, decoded_req));
+  GPR_ASSERT(grpc_gcp_handshaker_req_equals(req, decoded_req));
+  grpc_gcp_handshaker_req_destroy(req);
+  grpc_gcp_handshaker_req_destroy(decoded_req);
+  grpc_slice_unref(encoded_req);
+
+  /* handshaker_req_server_start. */
+  req = grpc_gcp_handshaker_req_create(SERVER_START_REQ);
+  decoded_req = grpc_gcp_handshaker_decoded_req_create(SERVER_START_REQ);
+  GPR_ASSERT(grpc_gcp_handshaker_req_add_application_protocol(req, "grpc"));
+  GPR_ASSERT(grpc_gcp_handshaker_req_add_application_protocol(req, "http2"));
+  GPR_ASSERT(grpc_gcp_handshaker_req_set_local_endpoint(
+      req, "2001:db8::8:800:200C:417a", 9876, grpc_gcp_NetworkProtocol_TCP));
+  GPR_ASSERT(grpc_gcp_handshaker_req_set_remote_endpoint(
+      req, "2001:db8::bac5::fed0:84a2", 1234, grpc_gcp_NetworkProtocol_UDP));
+  GPR_ASSERT(
+      grpc_gcp_handshaker_req_set_in_bytes(req, in_bytes, strlen(in_bytes)));
+  GPR_ASSERT(grpc_gcp_handshaker_req_param_add_record_protocol(
+      req, grpc_gcp_HandshakeProtocol_TLS, "ALTSRP_GCM_AES128"));
+  GPR_ASSERT(grpc_gcp_handshaker_req_param_add_local_identity_service_account(
+      req, grpc_gcp_HandshakeProtocol_TLS, "foo@google.com"));
+  GPR_ASSERT(grpc_gcp_handshaker_req_param_add_local_identity_hostname(
+      req, grpc_gcp_HandshakeProtocol_TLS, "yihuaz0.mtv.corp.google.com"));
+  GPR_ASSERT(grpc_gcp_handshaker_req_param_add_record_protocol(
+      req, grpc_gcp_HandshakeProtocol_ALTS, "ALTSRP_GCM_AES128"));
+  GPR_ASSERT(grpc_gcp_handshaker_req_param_add_local_identity_hostname(
+      req, grpc_gcp_HandshakeProtocol_ALTS, "www.amazon.com"));
+  GPR_ASSERT(grpc_gcp_handshaker_req_set_rpc_versions(
+      req, max_rpc_version_major, max_rpc_version_minor, min_rpc_version_major,
+      min_rpc_version_minor));
+
+  GPR_ASSERT(grpc_gcp_handshaker_req_encode(req, &encoded_req));
+  GPR_ASSERT(grpc_gcp_handshaker_req_decode(encoded_req, decoded_req));
+  GPR_ASSERT(grpc_gcp_handshaker_req_equals(req, decoded_req));
+  grpc_gcp_handshaker_req_destroy(req);
+  grpc_gcp_handshaker_req_destroy(decoded_req);
+  grpc_slice_unref(encoded_req);
+
+  /* handshaker_resp. */
+  grpc_gcp_handshaker_resp* resp = grpc_gcp_handshaker_resp_create();
+  grpc_gcp_handshaker_resp* decoded_resp = grpc_gcp_handshaker_resp_create();
+  GPR_ASSERT(grpc_gcp_handshaker_resp_set_out_frames(resp, out_frames,
+                                                     strlen(out_frames)));
+  GPR_ASSERT(grpc_gcp_handshaker_resp_set_bytes_consumed(resp, 1024));
+  GPR_ASSERT(grpc_gcp_handshaker_resp_set_application_protocol(resp, "http"));
+  GPR_ASSERT(
+      grpc_gcp_handshaker_resp_set_record_protocol(resp, "ALTSRP_GCM_AES128"));
+  GPR_ASSERT(
+      grpc_gcp_handshaker_resp_set_key_data(resp, key_data, strlen(key_data)));
+  GPR_ASSERT(grpc_gcp_handshaker_resp_set_local_identity_hostname(
+      resp, "www.faceboook.com"));
+  GPR_ASSERT(grpc_gcp_handshaker_resp_set_peer_identity_hostname(
+      resp, "www.amazon.com"));
+  GPR_ASSERT(grpc_gcp_handshaker_resp_set_channel_open(
+      resp, false /* channel_open */));
+  GPR_ASSERT(grpc_gcp_handshaker_resp_set_code(resp, 1023));
+  GPR_ASSERT(grpc_gcp_handshaker_resp_set_details(resp, details));
+  GPR_ASSERT(grpc_gcp_handshaker_resp_set_peer_rpc_versions(
+      resp, max_rpc_version_major, max_rpc_version_minor, min_rpc_version_major,
+      min_rpc_version_minor));
+  grpc_slice encoded_resp;
+  GPR_ASSERT(grpc_gcp_handshaker_resp_encode(resp, &encoded_resp));
+  GPR_ASSERT(grpc_gcp_handshaker_resp_decode(encoded_resp, decoded_resp));
+  GPR_ASSERT(grpc_gcp_handshaker_resp_equals(resp, decoded_resp));
+  grpc_gcp_handshaker_resp_destroy(resp);
+  grpc_gcp_handshaker_resp_destroy(decoded_resp);
+  grpc_slice_unref(encoded_resp);
+  /* Test invalid arguments. */
+  GPR_ASSERT(!grpc_gcp_handshaker_req_set_in_bytes(nullptr, in_bytes,
+                                                   strlen(in_bytes)));
+  GPR_ASSERT(!grpc_gcp_handshaker_req_param_add_record_protocol(
+      req, grpc_gcp_HandshakeProtocol_TLS, nullptr));
+  GPR_ASSERT(!grpc_gcp_handshaker_req_param_add_local_identity_service_account(
+      nullptr, grpc_gcp_HandshakeProtocol_TLS, nullptr));
+  GPR_ASSERT(!grpc_gcp_handshaker_resp_set_record_protocol(nullptr, nullptr));
+}
diff --git a/test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.cc b/test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.cc
new file mode 100644
index 0000000..ecca04d
--- /dev/null
+++ b/test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.cc
@@ -0,0 +1,642 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.h"
+
+const size_t kHandshakeProtocolNum = 3;
+
+grpc_gcp_handshaker_req* grpc_gcp_handshaker_decoded_req_create(
+    grpc_gcp_handshaker_req_type type) {
+  grpc_gcp_handshaker_req* req =
+      static_cast<grpc_gcp_handshaker_req*>(gpr_zalloc(sizeof(*req)));
+  switch (type) {
+    case CLIENT_START_REQ:
+      req->has_client_start = true;
+      req->client_start.target_identities.funcs.decode =
+          decode_repeated_identity_cb;
+      req->client_start.application_protocols.funcs.decode =
+          decode_repeated_string_cb;
+      req->client_start.record_protocols.funcs.decode =
+          decode_repeated_string_cb;
+      req->client_start.local_identity.hostname.funcs.decode =
+          decode_string_or_bytes_cb;
+      req->client_start.local_identity.service_account.funcs.decode =
+          decode_string_or_bytes_cb;
+      req->client_start.local_endpoint.ip_address.funcs.decode =
+          decode_string_or_bytes_cb;
+      req->client_start.remote_endpoint.ip_address.funcs.decode =
+          decode_string_or_bytes_cb;
+      req->client_start.target_name.funcs.decode = decode_string_or_bytes_cb;
+      break;
+    case SERVER_START_REQ:
+      req->has_server_start = true;
+      req->server_start.application_protocols.funcs.decode =
+          &decode_repeated_string_cb;
+      for (size_t i = 0; i < kHandshakeProtocolNum; i++) {
+        req->server_start.handshake_parameters[i]
+            .value.local_identities.funcs.decode = &decode_repeated_identity_cb;
+        req->server_start.handshake_parameters[i]
+            .value.record_protocols.funcs.decode = &decode_repeated_string_cb;
+      }
+      req->server_start.in_bytes.funcs.decode = decode_string_or_bytes_cb;
+      req->server_start.local_endpoint.ip_address.funcs.decode =
+          decode_string_or_bytes_cb;
+      req->server_start.remote_endpoint.ip_address.funcs.decode =
+          decode_string_or_bytes_cb;
+      break;
+    case NEXT_REQ:
+      req->has_next = true;
+      break;
+  }
+  return req;
+}
+
+bool grpc_gcp_handshaker_resp_set_application_protocol(
+    grpc_gcp_handshaker_resp* resp, const char* application_protocol) {
+  if (resp == nullptr || application_protocol == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to "
+            "handshaker_resp_set_application_protocol().");
+    return false;
+  }
+  resp->has_result = true;
+  grpc_slice* slice =
+      create_slice(application_protocol, strlen(application_protocol));
+  resp->result.application_protocol.arg = slice;
+  resp->result.application_protocol.funcs.encode = encode_string_or_bytes_cb;
+  return true;
+}
+
+bool grpc_gcp_handshaker_resp_set_record_protocol(
+    grpc_gcp_handshaker_resp* resp, const char* record_protocol) {
+  if (resp == nullptr || record_protocol == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to "
+            "handshaker_resp_set_record_protocol().");
+    return false;
+  }
+  resp->has_result = true;
+  grpc_slice* slice = create_slice(record_protocol, strlen(record_protocol));
+  resp->result.record_protocol.arg = slice;
+  resp->result.record_protocol.funcs.encode = encode_string_or_bytes_cb;
+  return true;
+}
+
+bool grpc_gcp_handshaker_resp_set_key_data(grpc_gcp_handshaker_resp* resp,
+                                           const char* key_data, size_t size) {
+  if (resp == nullptr || key_data == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to handshaker_resp_set_key_data().");
+    return false;
+  }
+  resp->has_result = true;
+  grpc_slice* slice = create_slice(key_data, size);
+  resp->result.key_data.arg = slice;
+  resp->result.key_data.funcs.encode = encode_string_or_bytes_cb;
+  return true;
+}
+
+static void set_identity_hostname(grpc_gcp_identity* identity,
+                                  const char* hostname) {
+  grpc_slice* slice = create_slice(hostname, strlen(hostname));
+  identity->hostname.arg = slice;
+  identity->hostname.funcs.encode = encode_string_or_bytes_cb;
+}
+
+static void set_identity_service_account(grpc_gcp_identity* identity,
+                                         const char* service_account) {
+  grpc_slice* slice = create_slice(service_account, strlen(service_account));
+  identity->service_account.arg = slice;
+  identity->service_account.funcs.encode = encode_string_or_bytes_cb;
+}
+
+bool grpc_gcp_handshaker_resp_set_local_identity_hostname(
+    grpc_gcp_handshaker_resp* resp, const char* hostname) {
+  if (resp == nullptr || hostname == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to "
+            "grpc_gcp_handshaker_resp_set_local_identity_hostname().");
+    return false;
+  }
+  resp->has_result = true;
+  resp->result.has_local_identity = true;
+  set_identity_hostname(&resp->result.local_identity, hostname);
+  return true;
+}
+
+bool grpc_gcp_handshaker_resp_set_local_identity_service_account(
+    grpc_gcp_handshaker_resp* resp, const char* service_account) {
+  if (resp == nullptr || service_account == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to "
+            "grpc_gcp_handshaker_resp_set_local_identity_service_account().");
+    return false;
+  }
+  resp->has_result = true;
+  resp->result.has_local_identity = true;
+  set_identity_service_account(&resp->result.local_identity, service_account);
+  return true;
+}
+
+bool grpc_gcp_handshaker_resp_set_peer_identity_hostname(
+    grpc_gcp_handshaker_resp* resp, const char* hostname) {
+  if (resp == nullptr || hostname == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to "
+            "grpc_gcp_handshaker_resp_set_peer_identity_hostname().");
+    return false;
+  }
+  resp->has_result = true;
+  resp->result.has_peer_identity = true;
+  set_identity_hostname(&resp->result.peer_identity, hostname);
+  return true;
+}
+
+bool grpc_gcp_handshaker_resp_set_peer_identity_service_account(
+    grpc_gcp_handshaker_resp* resp, const char* service_account) {
+  if (resp == nullptr || service_account == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to "
+            "grpc_gcp_handshaker_resp_set_peer_identity_service_account().");
+    return false;
+  }
+  resp->has_result = true;
+  resp->result.has_peer_identity = true;
+  set_identity_service_account(&resp->result.peer_identity, service_account);
+  return true;
+}
+
+bool grpc_gcp_handshaker_resp_set_channel_open(grpc_gcp_handshaker_resp* resp,
+                                               bool keep_channel_open) {
+  if (resp == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr argument to "
+            "grpc_gcp_handshaker_resp_set_channel_open().");
+    return false;
+  }
+  resp->has_result = true;
+  resp->result.has_keep_channel_open = true;
+  resp->result.keep_channel_open = keep_channel_open;
+  return true;
+}
+
+bool grpc_gcp_handshaker_resp_set_code(grpc_gcp_handshaker_resp* resp,
+                                       uint32_t code) {
+  if (resp == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr argument to grpc_gcp_handshaker_resp_set_code().");
+    return false;
+  }
+  resp->has_status = true;
+  resp->status.has_code = true;
+  resp->status.code = code;
+  return true;
+}
+
+bool grpc_gcp_handshaker_resp_set_details(grpc_gcp_handshaker_resp* resp,
+                                          const char* details) {
+  if (resp == nullptr || details == nullptr) {
+    gpr_log(
+        GPR_ERROR,
+        "Invalid nullptr arguments to grpc_gcp_handshaker_resp_set_details().");
+    return false;
+  }
+  resp->has_status = true;
+  grpc_slice* slice = create_slice(details, strlen(details));
+  resp->status.details.arg = slice;
+  resp->status.details.funcs.encode = encode_string_or_bytes_cb;
+  return true;
+}
+
+bool grpc_gcp_handshaker_resp_set_out_frames(grpc_gcp_handshaker_resp* resp,
+                                             const char* out_frames,
+                                             size_t size) {
+  if (resp == nullptr || out_frames == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to "
+            "grpc_gcp_handshaker_resp_set_out_frames().");
+    return false;
+  }
+  grpc_slice* slice = create_slice(out_frames, size);
+  resp->out_frames.arg = slice;
+  resp->out_frames.funcs.encode = encode_string_or_bytes_cb;
+  return true;
+}
+
+bool grpc_gcp_handshaker_resp_set_bytes_consumed(grpc_gcp_handshaker_resp* resp,
+                                                 int32_t bytes_consumed) {
+  if (resp == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr argument to "
+            "grpc_gcp_handshaker_resp_set_bytes_consumed().");
+    return false;
+  }
+  resp->has_bytes_consumed = true;
+  resp->bytes_consumed = bytes_consumed;
+  return true;
+}
+
+bool grpc_gcp_handshaker_resp_set_peer_rpc_versions(
+    grpc_gcp_handshaker_resp* resp, uint32_t max_major, uint32_t max_minor,
+    uint32_t min_major, uint32_t min_minor) {
+  if (resp == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr argument to "
+            "grpc_gcp_handshaker_resp_set_peer_rpc_versions().");
+    return false;
+  }
+  resp->has_result = true;
+  resp->result.has_peer_rpc_versions = true;
+  grpc_gcp_rpc_protocol_versions* versions = &resp->result.peer_rpc_versions;
+  versions->has_max_rpc_version = true;
+  versions->has_min_rpc_version = true;
+  versions->max_rpc_version.has_major = true;
+  versions->max_rpc_version.has_minor = true;
+  versions->min_rpc_version.has_major = true;
+  versions->min_rpc_version.has_minor = true;
+  versions->max_rpc_version.major = max_major;
+  versions->max_rpc_version.minor = max_minor;
+  versions->min_rpc_version.major = min_major;
+  versions->min_rpc_version.minor = min_minor;
+  return true;
+}
+
+bool grpc_gcp_handshaker_resp_encode(grpc_gcp_handshaker_resp* resp,
+                                     grpc_slice* slice) {
+  if (resp == nullptr || slice == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr arguments to grpc_gcp_handshaker_resp_encode().");
+    return false;
+  }
+  pb_ostream_t size_stream;
+  memset(&size_stream, 0, sizeof(pb_ostream_t));
+  if (!pb_encode(&size_stream, grpc_gcp_HandshakerResp_fields, resp)) {
+    gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&size_stream));
+    return false;
+  }
+  size_t encoded_length = size_stream.bytes_written;
+  *slice = grpc_slice_malloc(encoded_length);
+  pb_ostream_t output_stream =
+      pb_ostream_from_buffer(GRPC_SLICE_START_PTR(*slice), encoded_length);
+  if (!pb_encode(&output_stream, grpc_gcp_HandshakerResp_fields, resp)) {
+    gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&size_stream));
+    return false;
+  }
+  return true;
+}
+
+bool grpc_gcp_handshaker_req_decode(grpc_slice slice,
+                                    grpc_gcp_handshaker_req* req) {
+  if (req == nullptr) {
+    gpr_log(GPR_ERROR,
+            "Invalid nullptr argument to grpc_gcp_handshaker_req_decode().");
+    return false;
+  }
+  pb_istream_t stream = pb_istream_from_buffer(GRPC_SLICE_START_PTR(slice),
+                                               GRPC_SLICE_LENGTH(slice));
+  req->next.in_bytes.funcs.decode = decode_string_or_bytes_cb;
+  if (!pb_decode(&stream, grpc_gcp_HandshakerReq_fields, req)) {
+    gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream));
+    return false;
+  }
+  return true;
+}
+
+/* Check equality of a pair of grpc_slice fields. */
+static bool slice_equals(grpc_slice* l_slice, grpc_slice* r_slice) {
+  if (l_slice == nullptr && r_slice == nullptr) {
+    return true;
+  }
+  if (l_slice != nullptr && r_slice != nullptr) {
+    return grpc_slice_eq(*l_slice, *r_slice);
+  }
+  return false;
+}
+
+/* Check equality of a pair of grpc_gcp_identity fields. */
+static bool handshaker_identity_equals(const grpc_gcp_identity* l_id,
+                                       const grpc_gcp_identity* r_id) {
+  if (!((l_id->hostname.arg != nullptr) != (r_id->hostname.arg != nullptr))) {
+    if (l_id->hostname.arg != nullptr) {
+      return slice_equals(static_cast<grpc_slice*>(l_id->hostname.arg),
+                          static_cast<grpc_slice*>(r_id->hostname.arg));
+    }
+  } else {
+    return false;
+  }
+  if (!((l_id->service_account.arg != nullptr) !=
+        (r_id->service_account.arg != nullptr))) {
+    if (l_id->service_account.arg != nullptr) {
+      return slice_equals(static_cast<grpc_slice*>(l_id->service_account.arg),
+                          static_cast<grpc_slice*>(r_id->service_account.arg));
+    }
+  } else {
+    return false;
+  }
+  return true;
+}
+
+static bool handshaker_rpc_versions_equals(
+    const grpc_gcp_rpc_protocol_versions* l_version,
+    const grpc_gcp_rpc_protocol_versions* r_version) {
+  bool result = true;
+  result &=
+      (l_version->max_rpc_version.major == r_version->max_rpc_version.major);
+  result &=
+      (l_version->max_rpc_version.minor == r_version->max_rpc_version.minor);
+  result &=
+      (l_version->min_rpc_version.major == r_version->min_rpc_version.major);
+  result &=
+      (l_version->min_rpc_version.minor == r_version->min_rpc_version.minor);
+  return result;
+}
+
+/* Check equality of a pair of grpc_gcp_endpoint fields. */
+static bool handshaker_endpoint_equals(const grpc_gcp_endpoint* l_end,
+                                       const grpc_gcp_endpoint* r_end) {
+  bool result = true;
+  result &= (l_end->port == r_end->port);
+  result &= (l_end->protocol == r_end->protocol);
+  if (!((l_end->ip_address.arg != nullptr) !=
+        (r_end->ip_address.arg != nullptr))) {
+    if (l_end->ip_address.arg != nullptr) {
+      result &= slice_equals(static_cast<grpc_slice*>(l_end->ip_address.arg),
+                             static_cast<grpc_slice*>(r_end->ip_address.arg));
+    }
+  } else {
+    return false;
+  }
+  return result;
+}
+/**
+ * Check if a specific repeated field (i.e., target) is contained in a repeated
+ * field list (i.e., head).
+ */
+static bool repeated_field_list_contains_identity(
+    const repeated_field* head, const repeated_field* target) {
+  repeated_field* field = const_cast<repeated_field*>(head);
+  while (field != nullptr) {
+    if (handshaker_identity_equals(
+            static_cast<const grpc_gcp_identity*>(field->data),
+            static_cast<const grpc_gcp_identity*>(target->data))) {
+      return true;
+    }
+    field = field->next;
+  }
+  return false;
+}
+
+static bool repeated_field_list_contains_string(const repeated_field* head,
+                                                const repeated_field* target) {
+  repeated_field* field = const_cast<repeated_field*>(head);
+  while (field != nullptr) {
+    if (slice_equals((grpc_slice*)field->data, (grpc_slice*)target->data)) {
+      return true;
+    }
+    field = field->next;
+  }
+  return false;
+}
+
+/* Return a length of repeated field list. */
+static size_t repeated_field_list_get_length(const repeated_field* head) {
+  repeated_field* field = const_cast<repeated_field*>(head);
+  size_t len = 0;
+  while (field != nullptr) {
+    len++;
+    field = field->next;
+  }
+  return len;
+}
+
+/**
+ * Check if a pair of repeated field lists contain the same set of repeated
+ * fields.
+ */
+static bool repeated_field_list_equals_identity(const repeated_field* l_head,
+                                                const repeated_field* r_head) {
+  if (repeated_field_list_get_length(l_head) !=
+      repeated_field_list_get_length(r_head)) {
+    return false;
+  }
+  repeated_field* field = const_cast<repeated_field*>(l_head);
+  repeated_field* head = const_cast<repeated_field*>(r_head);
+  while (field != nullptr) {
+    if (!repeated_field_list_contains_identity(head, field)) {
+      return false;
+    }
+    field = field->next;
+  }
+  return true;
+}
+
+static bool repeated_field_list_equals_string(const repeated_field* l_head,
+                                              const repeated_field* r_head) {
+  if (repeated_field_list_get_length(l_head) !=
+      repeated_field_list_get_length(r_head)) {
+    return false;
+  }
+  repeated_field* field = const_cast<repeated_field*>(l_head);
+  repeated_field* head = const_cast<repeated_field*>(r_head);
+  while (field != nullptr) {
+    if (!repeated_field_list_contains_string(head, field)) {
+      return false;
+    }
+    field = field->next;
+  }
+  return true;
+}
+
+/* Check equality of a pair of ALTS client_start handshake requests. */
+bool grpc_gcp_handshaker_client_start_req_equals(
+    grpc_gcp_start_client_handshake_req* l_req,
+    grpc_gcp_start_client_handshake_req* r_req) {
+  bool result = true;
+  /* Compare handshake_security_protocol. */
+  result &=
+      l_req->handshake_security_protocol == r_req->handshake_security_protocol;
+  /* Compare application_protocols, record_protocols, and target_identities. */
+  result &= repeated_field_list_equals_string(
+      static_cast<const repeated_field*>(l_req->application_protocols.arg),
+      static_cast<const repeated_field*>(r_req->application_protocols.arg));
+  result &= repeated_field_list_equals_string(
+      static_cast<const repeated_field*>(l_req->record_protocols.arg),
+      static_cast<const repeated_field*>(r_req->record_protocols.arg));
+  result &= repeated_field_list_equals_identity(
+      static_cast<const repeated_field*>(l_req->target_identities.arg),
+      static_cast<const repeated_field*>(r_req->target_identities.arg));
+  if ((l_req->has_local_identity ^ r_req->has_local_identity) |
+      (l_req->has_local_endpoint ^ r_req->has_local_endpoint) |
+      ((l_req->has_remote_endpoint ^ r_req->has_remote_endpoint)) |
+      (l_req->has_rpc_versions ^ r_req->has_rpc_versions)) {
+    return false;
+  }
+  /* Compare local_identity, local_endpoint, and remote_endpoint. */
+  if (l_req->has_local_identity) {
+    result &= handshaker_identity_equals(&l_req->local_identity,
+                                         &r_req->local_identity);
+  }
+  if (l_req->has_local_endpoint) {
+    result &= handshaker_endpoint_equals(&l_req->local_endpoint,
+                                         &r_req->local_endpoint);
+  }
+  if (l_req->has_remote_endpoint) {
+    result &= handshaker_endpoint_equals(&l_req->remote_endpoint,
+                                         &r_req->remote_endpoint);
+  }
+  if (l_req->has_rpc_versions) {
+    result &= handshaker_rpc_versions_equals(&l_req->rpc_versions,
+                                             &r_req->rpc_versions);
+  }
+  return result;
+}
+
+/* Check equality of a pair of ALTS server_start handshake requests. */
+bool grpc_gcp_handshaker_server_start_req_equals(
+    grpc_gcp_start_server_handshake_req* l_req,
+    grpc_gcp_start_server_handshake_req* r_req) {
+  bool result = true;
+  /* Compare application_protocols. */
+  result &= repeated_field_list_equals_string(
+      static_cast<const repeated_field*>(l_req->application_protocols.arg),
+      static_cast<const repeated_field*>(r_req->application_protocols.arg));
+  /* Compare handshake_parameters. */
+  size_t i = 0, j = 0;
+  result &=
+      (l_req->handshake_parameters_count == r_req->handshake_parameters_count);
+  for (i = 0; i < l_req->handshake_parameters_count; i++) {
+    bool found = false;
+    for (j = 0; j < r_req->handshake_parameters_count; j++) {
+      if (l_req->handshake_parameters[i].key ==
+          r_req->handshake_parameters[j].key) {
+        found = true;
+        result &= repeated_field_list_equals_string(
+            static_cast<const repeated_field*>(
+                l_req->handshake_parameters[i].value.record_protocols.arg),
+            static_cast<const repeated_field*>(
+                r_req->handshake_parameters[j].value.record_protocols.arg));
+        result &= repeated_field_list_equals_identity(
+            static_cast<const repeated_field*>(
+                l_req->handshake_parameters[i].value.local_identities.arg),
+            static_cast<const repeated_field*>(
+                r_req->handshake_parameters[j].value.local_identities.arg));
+      }
+    }
+    if (!found) {
+      return false;
+    }
+  }
+  /* Compare in_bytes, local_endpoint, remote_endpoint. */
+  result &= slice_equals(static_cast<grpc_slice*>(l_req->in_bytes.arg),
+                         static_cast<grpc_slice*>(r_req->in_bytes.arg));
+  if ((l_req->has_local_endpoint ^ r_req->has_local_endpoint) |
+      (l_req->has_remote_endpoint ^ r_req->has_remote_endpoint) |
+      (l_req->has_rpc_versions ^ r_req->has_rpc_versions))
+    return false;
+  if (l_req->has_local_endpoint) {
+    result &= handshaker_endpoint_equals(&l_req->local_endpoint,
+                                         &r_req->local_endpoint);
+  }
+  if (l_req->has_remote_endpoint) {
+    result &= handshaker_endpoint_equals(&l_req->remote_endpoint,
+                                         &r_req->remote_endpoint);
+  }
+  if (l_req->has_rpc_versions) {
+    result &= handshaker_rpc_versions_equals(&l_req->rpc_versions,
+                                             &r_req->rpc_versions);
+  }
+  return result;
+}
+
+/* Check equality of a pair of ALTS handshake requests. */
+bool grpc_gcp_handshaker_req_equals(grpc_gcp_handshaker_req* l_req,
+                                    grpc_gcp_handshaker_req* r_req) {
+  if (l_req->has_next && r_req->has_next) {
+    return slice_equals(static_cast<grpc_slice*>(l_req->next.in_bytes.arg),
+                        static_cast<grpc_slice*>(r_req->next.in_bytes.arg));
+  } else if (l_req->has_client_start && r_req->has_client_start) {
+    return grpc_gcp_handshaker_client_start_req_equals(&l_req->client_start,
+                                                       &r_req->client_start);
+  } else if (l_req->has_server_start && r_req->has_server_start) {
+    return grpc_gcp_handshaker_server_start_req_equals(&l_req->server_start,
+                                                       &r_req->server_start);
+  }
+  return false;
+}
+
+/* Check equality of a pair of ALTS handshake results. */
+bool grpc_gcp_handshaker_resp_result_equals(
+    grpc_gcp_handshaker_result* l_result,
+    grpc_gcp_handshaker_result* r_result) {
+  bool result = true;
+  /* Compare application_protocol, record_protocol, and key_data. */
+  result &= slice_equals(
+      static_cast<grpc_slice*>(l_result->application_protocol.arg),
+      static_cast<grpc_slice*>(r_result->application_protocol.arg));
+  result &=
+      slice_equals(static_cast<grpc_slice*>(l_result->record_protocol.arg),
+                   static_cast<grpc_slice*>(r_result->record_protocol.arg));
+  result &= slice_equals(static_cast<grpc_slice*>(l_result->key_data.arg),
+                         static_cast<grpc_slice*>(r_result->key_data.arg));
+  /* Compare local_identity, peer_identity, and keep_channel_open. */
+  if ((l_result->has_local_identity ^ r_result->has_local_identity) |
+      (l_result->has_peer_identity ^ r_result->has_peer_identity) |
+      (l_result->has_peer_rpc_versions ^ r_result->has_peer_rpc_versions)) {
+    return false;
+  }
+  if (l_result->has_local_identity) {
+    result &= handshaker_identity_equals(&l_result->local_identity,
+                                         &r_result->local_identity);
+  }
+  if (l_result->has_peer_identity) {
+    result &= handshaker_identity_equals(&l_result->peer_identity,
+                                         &r_result->peer_identity);
+  }
+  if (l_result->has_peer_rpc_versions) {
+    result &= handshaker_rpc_versions_equals(&l_result->peer_rpc_versions,
+                                             &r_result->peer_rpc_versions);
+  }
+  result &= (l_result->keep_channel_open == r_result->keep_channel_open);
+  return result;
+}
+
+/* Check equality of a pair of ALTS handshake responses. */
+bool grpc_gcp_handshaker_resp_equals(grpc_gcp_handshaker_resp* l_resp,
+                                     grpc_gcp_handshaker_resp* r_resp) {
+  bool result = true;
+  /* Compare out_frames and bytes_consumed. */
+  result &= slice_equals(static_cast<grpc_slice*>(l_resp->out_frames.arg),
+                         static_cast<grpc_slice*>(r_resp->out_frames.arg));
+  result &= (l_resp->bytes_consumed == r_resp->bytes_consumed);
+  /* Compare result and status. */
+  if ((l_resp->has_result ^ r_resp->has_result) |
+      (l_resp->has_status ^ r_resp->has_status)) {
+    return false;
+  }
+  if (l_resp->has_result) {
+    result &= grpc_gcp_handshaker_resp_result_equals(&l_resp->result,
+                                                     &r_resp->result);
+  }
+  if (l_resp->has_status) {
+    result &= (l_resp->status.code == r_resp->status.code);
+    result &=
+        slice_equals(static_cast<grpc_slice*>(l_resp->status.details.arg),
+                     static_cast<grpc_slice*>(r_resp->status.details.arg));
+  }
+  return result;
+}
diff --git a/test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.h b/test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.h
new file mode 100644
index 0000000..2fcbb4e
--- /dev/null
+++ b/test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.h
@@ -0,0 +1,143 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_TEST_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_SERVICE_API_TEST_LIB_H
+#define GRPC_TEST_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_SERVICE_API_TEST_LIB_H
+
+#include "src/core/tsi/alts/handshaker/alts_handshaker_service_api.h"
+#include "src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h"
+#include "src/core/tsi/alts/handshaker/transport_security_common_api.h"
+
+/**
+ * The first part of this file contains function signatures for de-serializing
+ * ALTS handshake requests and setting/serializing ALTS handshake responses,
+ * which simulate the behaviour of grpc server that runs ALTS handshaker
+ * service.
+ */
+
+/**
+ * This method creates a ALTS handshaker request that is used to hold
+ * de-serialized result.
+ */
+grpc_gcp_handshaker_req* grpc_gcp_handshaker_decoded_req_create(
+    grpc_gcp_handshaker_req_type type);
+
+/* This method de-serializes a ALTS handshaker request. */
+bool grpc_gcp_handshaker_req_decode(grpc_slice slice,
+                                    grpc_gcp_handshaker_req* req);
+
+/* This method serializes a ALTS handshaker response. */
+bool grpc_gcp_handshaker_resp_encode(grpc_gcp_handshaker_resp* resp,
+                                     grpc_slice* slice);
+
+/* This method sets application protocol of ALTS handshaker response. */
+bool grpc_gcp_handshaker_resp_set_application_protocol(
+    grpc_gcp_handshaker_resp* resp, const char* application_protocol);
+
+/* This method sets record protocol of ALTS handshaker response. */
+bool grpc_gcp_handshaker_resp_set_record_protocol(
+    grpc_gcp_handshaker_resp* resp, const char* record_protocol);
+
+/* This method sets key_data of ALTS handshaker response. */
+bool grpc_gcp_handshaker_resp_set_key_data(grpc_gcp_handshaker_resp* resp,
+                                           const char* key_data, size_t size);
+
+/* This method sets local identity's hostname for ALTS handshaker response. */
+bool grpc_gcp_handshaker_resp_set_local_identity_hostname(
+    grpc_gcp_handshaker_resp* resp, const char* hostname);
+
+/**
+ * This method sets local identity's service account for ALTS handshaker
+ * response.
+ */
+bool grpc_gcp_handshaker_resp_set_local_identity_service_account(
+    grpc_gcp_handshaker_resp* resp, const char* service_account);
+
+/* This method sets peer identity's hostname for ALTS handshaker response. */
+bool grpc_gcp_handshaker_resp_set_peer_identity_hostname(
+    grpc_gcp_handshaker_resp* resp, const char* hostname);
+
+/**
+ * This method sets peer identity's service account for ALTS handshaker
+ * response.
+ */
+bool grpc_gcp_handshaker_resp_set_peer_identity_service_account(
+    grpc_gcp_handshaker_resp* resp, const char* service_account);
+
+/* This method sets keep_channel_open for ALTS handshaker response. */
+bool grpc_gcp_handshaker_resp_set_channel_open(grpc_gcp_handshaker_resp* resp,
+                                               bool keep_channel_open);
+
+/* This method sets code for ALTS handshaker response. */
+bool grpc_gcp_handshaker_resp_set_code(grpc_gcp_handshaker_resp* resp,
+                                       uint32_t code);
+
+/* This method sets details for ALTS handshaker response. */
+bool grpc_gcp_handshaker_resp_set_details(grpc_gcp_handshaker_resp* resp,
+                                          const char* details);
+
+/* This method sets out_frames for ALTS handshaker response. */
+bool grpc_gcp_handshaker_resp_set_out_frames(grpc_gcp_handshaker_resp* resp,
+                                             const char* out_frames,
+                                             size_t size);
+
+/* This method sets peer_rpc_versions for ALTS handshaker response. */
+bool grpc_gcp_handshaker_resp_set_peer_rpc_versions(
+    grpc_gcp_handshaker_resp* resp, uint32_t max_major, uint32_t max_minor,
+    uint32_t min_major, uint32_t min_minor);
+
+/* This method sets bytes_consumed for ALTS handshaker response. */
+bool grpc_gcp_handshaker_resp_set_bytes_consumed(grpc_gcp_handshaker_resp* resp,
+                                                 int32_t bytes_consumed);
+
+/* This method serializes ALTS handshaker response. */
+bool grpc_gcp_handshaker_resp_encode(grpc_gcp_handshaker_resp* resp,
+                                     grpc_slice* slice);
+
+/* This method de-serializes ALTS handshaker request. */
+bool grpc_gcp_handshaker_req_decode(grpc_slice slice,
+                                    grpc_gcp_handshaker_req* req);
+
+/**
+ * The second part contains function signatures for checking equality of a pair
+ * of ALTS handshake requests/responses.
+ */
+
+/* This method checks equality of two client_start handshaker requests. */
+bool grpc_gcp_handshaker_client_start_req_equals(
+    grpc_gcp_start_client_handshake_req* l_req,
+    grpc_gcp_start_client_handshake_req* r_req);
+
+/* This method checks equality of two server_start handshaker requests. */
+bool grpc_gcp_handshaker_server_start_req_equals(
+    grpc_gcp_start_server_handshake_req* l_req,
+    grpc_gcp_start_server_handshake_req* r_req);
+
+/* This method checks equality of two ALTS handshaker requests. */
+bool grpc_gcp_handshaker_req_equals(grpc_gcp_handshaker_req* l_req,
+                                    grpc_gcp_handshaker_req* r_req);
+
+/* This method checks equality of two handshaker response results. */
+bool grpc_gcp_handshaker_resp_result_equals(
+    grpc_gcp_handshaker_result* l_result, grpc_gcp_handshaker_result* r_result);
+
+/* This method checks equality of two ALTS handshaker responses. */
+bool grpc_gcp_handshaker_resp_equals(grpc_gcp_handshaker_resp* l_resp,
+                                     grpc_gcp_handshaker_resp* r_resp);
+
+#endif  // GRPC_TEST_CORE_TSI_ALTS_HANDSHAKER_ALTS_HANDSHAKER_SERVICE_API_TEST_LIB_H
diff --git a/test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc b/test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc
new file mode 100644
index 0000000..95724f8
--- /dev/null
+++ b/test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc
@@ -0,0 +1,682 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <stdio.h>
+#include <stdlib.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/sync.h>
+
+#include "src/core/lib/gprpp/thd.h"
+#include "src/core/tsi/alts/handshaker/alts_handshaker_client.h"
+#include "src/core/tsi/alts/handshaker/alts_tsi_event.h"
+#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h"
+#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h"
+#include "test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.h"
+
+#define ALTS_TSI_HANDSHAKER_TEST_RECV_BYTES "Hello World"
+#define ALTS_TSI_HANDSHAKER_TEST_OUT_FRAME "Hello Google"
+#define ALTS_TSI_HANDSHAKER_TEST_CONSUMED_BYTES "Hello "
+#define ALTS_TSI_HANDSHAKER_TEST_REMAIN_BYTES "Google"
+#define ALTS_TSI_HANDSHAKER_TEST_PEER_IDENTITY "chapi@service.google.com"
+#define ALTS_TSI_HANDSHAKER_TEST_KEY_DATA \
+  "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKL"
+#define ALTS_TSI_HANDSHAKER_TEST_BUFFER_SIZE 100
+#define ALTS_TSI_HANDSHAKER_TEST_SLEEP_TIME_IN_SECONDS 2
+#define ALTS_TSI_HANDSHAKER_TEST_MAX_RPC_VERSION_MAJOR 3
+#define ALTS_TSI_HANDSHAKER_TEST_MAX_RPC_VERSION_MINOR 2
+#define ALTS_TSI_HANDSHAKER_TEST_MIN_RPC_VERSION_MAJOR 2
+#define ALTS_TSI_HANDSHAKER_TEST_MIN_RPC_VERSION_MINOR 1
+
+using grpc_core::internal::
+    alts_tsi_handshaker_get_has_sent_start_message_for_testing;
+using grpc_core::internal::alts_tsi_handshaker_get_is_client_for_testing;
+using grpc_core::internal::alts_tsi_handshaker_get_recv_bytes_for_testing;
+using grpc_core::internal::alts_tsi_handshaker_set_client_for_testing;
+using grpc_core::internal::alts_tsi_handshaker_set_recv_bytes_for_testing;
+
+/* ALTS mock notification. */
+typedef struct notification {
+  gpr_cv cv;
+  gpr_mu mu;
+  bool notified;
+} notification;
+
+/* ALTS mock handshaker client. */
+typedef struct alts_mock_handshaker_client {
+  alts_handshaker_client base;
+  bool used_for_success_test;
+} alts_mock_handshaker_client;
+
+/* Type of ALTS handshaker response. */
+typedef enum {
+  INVALID,
+  FAILED,
+  CLIENT_START,
+  SERVER_START,
+  CLIENT_NEXT,
+  SERVER_NEXT,
+} alts_handshaker_response_type;
+
+static alts_tsi_event* client_start_event;
+static alts_tsi_event* client_next_event;
+static alts_tsi_event* server_start_event;
+static alts_tsi_event* server_next_event;
+static notification caller_to_tsi_notification;
+static notification tsi_to_caller_notification;
+
+static void notification_init(notification* n) {
+  gpr_mu_init(&n->mu);
+  gpr_cv_init(&n->cv);
+  n->notified = false;
+}
+
+static void notification_destroy(notification* n) {
+  gpr_mu_destroy(&n->mu);
+  gpr_cv_destroy(&n->cv);
+}
+
+static void signal(notification* n) {
+  gpr_mu_lock(&n->mu);
+  n->notified = true;
+  gpr_cv_signal(&n->cv);
+  gpr_mu_unlock(&n->mu);
+}
+
+static void wait(notification* n) {
+  gpr_mu_lock(&n->mu);
+  while (!n->notified) {
+    gpr_cv_wait(&n->cv, &n->mu, gpr_inf_future(GPR_CLOCK_REALTIME));
+  }
+  n->notified = false;
+  gpr_mu_unlock(&n->mu);
+}
+
+/**
+ * This method mocks ALTS handshaker service to generate handshaker response
+ * for a specific request.
+ */
+static grpc_byte_buffer* generate_handshaker_response(
+    alts_handshaker_response_type type) {
+  grpc_gcp_handshaker_resp* resp = grpc_gcp_handshaker_resp_create();
+  GPR_ASSERT(grpc_gcp_handshaker_resp_set_code(resp, 0));
+  switch (type) {
+    case INVALID:
+      break;
+    case CLIENT_START:
+    case SERVER_START:
+      GPR_ASSERT(grpc_gcp_handshaker_resp_set_out_frames(
+          resp, ALTS_TSI_HANDSHAKER_TEST_OUT_FRAME,
+          strlen(ALTS_TSI_HANDSHAKER_TEST_OUT_FRAME)));
+      break;
+    case CLIENT_NEXT:
+      GPR_ASSERT(grpc_gcp_handshaker_resp_set_out_frames(
+          resp, ALTS_TSI_HANDSHAKER_TEST_OUT_FRAME,
+          strlen(ALTS_TSI_HANDSHAKER_TEST_OUT_FRAME)));
+      GPR_ASSERT(grpc_gcp_handshaker_resp_set_peer_identity_service_account(
+          resp, ALTS_TSI_HANDSHAKER_TEST_PEER_IDENTITY));
+      GPR_ASSERT(grpc_gcp_handshaker_resp_set_bytes_consumed(
+          resp, strlen(ALTS_TSI_HANDSHAKER_TEST_CONSUMED_BYTES)));
+      GPR_ASSERT(grpc_gcp_handshaker_resp_set_key_data(
+          resp, ALTS_TSI_HANDSHAKER_TEST_KEY_DATA,
+          strlen(ALTS_TSI_HANDSHAKER_TEST_KEY_DATA)));
+      GPR_ASSERT(grpc_gcp_handshaker_resp_set_peer_rpc_versions(
+          resp, ALTS_TSI_HANDSHAKER_TEST_MAX_RPC_VERSION_MAJOR,
+          ALTS_TSI_HANDSHAKER_TEST_MAX_RPC_VERSION_MINOR,
+          ALTS_TSI_HANDSHAKER_TEST_MIN_RPC_VERSION_MAJOR,
+          ALTS_TSI_HANDSHAKER_TEST_MIN_RPC_VERSION_MINOR));
+      break;
+    case SERVER_NEXT:
+      GPR_ASSERT(grpc_gcp_handshaker_resp_set_peer_identity_service_account(
+          resp, ALTS_TSI_HANDSHAKER_TEST_PEER_IDENTITY));
+      GPR_ASSERT(grpc_gcp_handshaker_resp_set_bytes_consumed(
+          resp, strlen(ALTS_TSI_HANDSHAKER_TEST_OUT_FRAME)));
+      GPR_ASSERT(grpc_gcp_handshaker_resp_set_key_data(
+          resp, ALTS_TSI_HANDSHAKER_TEST_KEY_DATA,
+          strlen(ALTS_TSI_HANDSHAKER_TEST_KEY_DATA)));
+      GPR_ASSERT(grpc_gcp_handshaker_resp_set_peer_rpc_versions(
+          resp, ALTS_TSI_HANDSHAKER_TEST_MAX_RPC_VERSION_MAJOR,
+          ALTS_TSI_HANDSHAKER_TEST_MAX_RPC_VERSION_MINOR,
+          ALTS_TSI_HANDSHAKER_TEST_MIN_RPC_VERSION_MAJOR,
+          ALTS_TSI_HANDSHAKER_TEST_MIN_RPC_VERSION_MINOR));
+      break;
+    case FAILED:
+      GPR_ASSERT(
+          grpc_gcp_handshaker_resp_set_code(resp, 3 /* INVALID ARGUMENT */));
+      break;
+  }
+  grpc_slice slice;
+  GPR_ASSERT(grpc_gcp_handshaker_resp_encode(resp, &slice));
+  if (type == INVALID) {
+    grpc_slice bad_slice =
+        grpc_slice_split_head(&slice, GRPC_SLICE_LENGTH(slice) - 1);
+    grpc_slice_unref(slice);
+    slice = grpc_slice_ref(bad_slice);
+    grpc_slice_unref(bad_slice);
+  }
+  grpc_byte_buffer* buffer =
+      grpc_raw_byte_buffer_create(&slice, 1 /* number of slices */);
+  grpc_slice_unref(slice);
+  grpc_gcp_handshaker_resp_destroy(resp);
+  return buffer;
+}
+
+static void check_must_not_be_called(tsi_result status, void* user_data,
+                                     const unsigned char* bytes_to_send,
+                                     size_t bytes_to_send_size,
+                                     tsi_handshaker_result* result) {
+  GPR_ASSERT(0);
+}
+
+static void on_client_start_success_cb(tsi_result status, void* user_data,
+                                       const unsigned char* bytes_to_send,
+                                       size_t bytes_to_send_size,
+                                       tsi_handshaker_result* result) {
+  GPR_ASSERT(status == TSI_OK);
+  GPR_ASSERT(user_data == nullptr);
+  GPR_ASSERT(bytes_to_send_size == strlen(ALTS_TSI_HANDSHAKER_TEST_OUT_FRAME));
+  GPR_ASSERT(memcmp(bytes_to_send, ALTS_TSI_HANDSHAKER_TEST_OUT_FRAME,
+                    bytes_to_send_size) == 0);
+  GPR_ASSERT(result == nullptr);
+  /* Validate peer identity. */
+  tsi_peer peer;
+  GPR_ASSERT(tsi_handshaker_result_extract_peer(result, &peer) ==
+             TSI_INVALID_ARGUMENT);
+  /* Validate frame protector. */
+  tsi_frame_protector* protector = nullptr;
+  GPR_ASSERT(tsi_handshaker_result_create_frame_protector(
+                 result, nullptr, &protector) == TSI_INVALID_ARGUMENT);
+  /* Validate unused bytes. */
+  const unsigned char* unused_bytes = nullptr;
+  size_t unused_bytes_size = 0;
+  GPR_ASSERT(tsi_handshaker_result_get_unused_bytes(result, &unused_bytes,
+                                                    &unused_bytes_size) ==
+             TSI_INVALID_ARGUMENT);
+  signal(&tsi_to_caller_notification);
+}
+
+static void on_server_start_success_cb(tsi_result status, void* user_data,
+                                       const unsigned char* bytes_to_send,
+                                       size_t bytes_to_send_size,
+                                       tsi_handshaker_result* result) {
+  GPR_ASSERT(status == TSI_OK);
+  GPR_ASSERT(user_data == nullptr);
+  GPR_ASSERT(bytes_to_send_size == strlen(ALTS_TSI_HANDSHAKER_TEST_OUT_FRAME));
+  GPR_ASSERT(memcmp(bytes_to_send, ALTS_TSI_HANDSHAKER_TEST_OUT_FRAME,
+                    bytes_to_send_size) == 0);
+  GPR_ASSERT(result == nullptr);
+  /* Validate peer identity. */
+  tsi_peer peer;
+  GPR_ASSERT(tsi_handshaker_result_extract_peer(result, &peer) ==
+             TSI_INVALID_ARGUMENT);
+  /* Validate frame protector. */
+  tsi_frame_protector* protector = nullptr;
+  GPR_ASSERT(tsi_handshaker_result_create_frame_protector(
+                 result, nullptr, &protector) == TSI_INVALID_ARGUMENT);
+  /* Validate unused bytes. */
+  const unsigned char* unused_bytes = nullptr;
+  size_t unused_bytes_size = 0;
+  GPR_ASSERT(tsi_handshaker_result_get_unused_bytes(result, &unused_bytes,
+                                                    &unused_bytes_size) ==
+             TSI_INVALID_ARGUMENT);
+  signal(&tsi_to_caller_notification);
+}
+
+static void on_client_next_success_cb(tsi_result status, void* user_data,
+                                      const unsigned char* bytes_to_send,
+                                      size_t bytes_to_send_size,
+                                      tsi_handshaker_result* result) {
+  GPR_ASSERT(status == TSI_OK);
+  GPR_ASSERT(user_data == nullptr);
+  GPR_ASSERT(bytes_to_send_size == strlen(ALTS_TSI_HANDSHAKER_TEST_OUT_FRAME));
+  GPR_ASSERT(memcmp(bytes_to_send, ALTS_TSI_HANDSHAKER_TEST_OUT_FRAME,
+                    bytes_to_send_size) == 0);
+  GPR_ASSERT(result != nullptr);
+  /* Validate peer identity. */
+  tsi_peer peer;
+  GPR_ASSERT(tsi_handshaker_result_extract_peer(result, &peer) == TSI_OK);
+  GPR_ASSERT(peer.property_count == kTsiAltsNumOfPeerProperties);
+  GPR_ASSERT(memcmp(TSI_ALTS_CERTIFICATE_TYPE, peer.properties[0].value.data,
+                    peer.properties[0].value.length) == 0);
+  GPR_ASSERT(memcmp(ALTS_TSI_HANDSHAKER_TEST_PEER_IDENTITY,
+                    peer.properties[1].value.data,
+                    peer.properties[1].value.length) == 0);
+  tsi_peer_destruct(&peer);
+  /* Validate unused bytes. */
+  const unsigned char* bytes = nullptr;
+  size_t bytes_size = 0;
+  GPR_ASSERT(tsi_handshaker_result_get_unused_bytes(result, &bytes,
+                                                    &bytes_size) == TSI_OK);
+  GPR_ASSERT(bytes_size == strlen(ALTS_TSI_HANDSHAKER_TEST_REMAIN_BYTES));
+  GPR_ASSERT(memcmp(bytes, ALTS_TSI_HANDSHAKER_TEST_REMAIN_BYTES, bytes_size) ==
+             0);
+  /* Validate frame protector. */
+  tsi_frame_protector* protector = nullptr;
+  GPR_ASSERT(tsi_handshaker_result_create_frame_protector(
+                 result, nullptr, &protector) == TSI_OK);
+  GPR_ASSERT(protector != nullptr);
+  tsi_frame_protector_destroy(protector);
+  tsi_handshaker_result_destroy(result);
+  signal(&tsi_to_caller_notification);
+}
+
+static void on_server_next_success_cb(tsi_result status, void* user_data,
+                                      const unsigned char* bytes_to_send,
+                                      size_t bytes_to_send_size,
+                                      tsi_handshaker_result* result) {
+  GPR_ASSERT(status == TSI_OK);
+  GPR_ASSERT(user_data == nullptr);
+  GPR_ASSERT(bytes_to_send_size == 0);
+  GPR_ASSERT(bytes_to_send == nullptr);
+  GPR_ASSERT(result != nullptr);
+  /* Validate peer identity. */
+  tsi_peer peer;
+  GPR_ASSERT(tsi_handshaker_result_extract_peer(result, &peer) == TSI_OK);
+  GPR_ASSERT(peer.property_count == kTsiAltsNumOfPeerProperties);
+  GPR_ASSERT(memcmp(TSI_ALTS_CERTIFICATE_TYPE, peer.properties[0].value.data,
+                    peer.properties[0].value.length) == 0);
+  GPR_ASSERT(memcmp(ALTS_TSI_HANDSHAKER_TEST_PEER_IDENTITY,
+                    peer.properties[1].value.data,
+                    peer.properties[1].value.length) == 0);
+  tsi_peer_destruct(&peer);
+  /* Validate unused bytes. */
+  const unsigned char* bytes = nullptr;
+  size_t bytes_size = 0;
+  GPR_ASSERT(tsi_handshaker_result_get_unused_bytes(result, &bytes,
+                                                    &bytes_size) == TSI_OK);
+  GPR_ASSERT(bytes_size == 0);
+  GPR_ASSERT(bytes == nullptr);
+  /* Validate frame protector. */
+  tsi_frame_protector* protector = nullptr;
+  GPR_ASSERT(tsi_handshaker_result_create_frame_protector(
+                 result, nullptr, &protector) == TSI_OK);
+  GPR_ASSERT(protector != nullptr);
+  tsi_frame_protector_destroy(protector);
+  tsi_handshaker_result_destroy(result);
+  signal(&tsi_to_caller_notification);
+}
+
+static tsi_result mock_client_start(alts_handshaker_client* self,
+                                    alts_tsi_event* event) {
+  alts_mock_handshaker_client* client =
+      reinterpret_cast<alts_mock_handshaker_client*>(self);
+  if (!client->used_for_success_test) {
+    alts_tsi_event_destroy(event);
+    return TSI_INTERNAL_ERROR;
+  }
+  GPR_ASSERT(event->cb == on_client_start_success_cb);
+  GPR_ASSERT(event->user_data == nullptr);
+  GPR_ASSERT(!alts_tsi_handshaker_get_has_sent_start_message_for_testing(
+      event->handshaker));
+  /* Populate handshaker response for client_start request. */
+  event->recv_buffer = generate_handshaker_response(CLIENT_START);
+  client_start_event = event;
+  signal(&caller_to_tsi_notification);
+  return TSI_OK;
+}
+
+static tsi_result mock_server_start(alts_handshaker_client* self,
+                                    alts_tsi_event* event,
+                                    grpc_slice* bytes_received) {
+  alts_mock_handshaker_client* client =
+      reinterpret_cast<alts_mock_handshaker_client*>(self);
+  if (!client->used_for_success_test) {
+    alts_tsi_event_destroy(event);
+    return TSI_INTERNAL_ERROR;
+  }
+  GPR_ASSERT(event->cb == on_server_start_success_cb);
+  GPR_ASSERT(event->user_data == nullptr);
+  grpc_slice slice = grpc_empty_slice();
+  GPR_ASSERT(grpc_slice_cmp(*bytes_received, slice) == 0);
+  GPR_ASSERT(!alts_tsi_handshaker_get_has_sent_start_message_for_testing(
+      event->handshaker));
+  /* Populate handshaker response for server_start request. */
+  event->recv_buffer = generate_handshaker_response(SERVER_START);
+  server_start_event = event;
+  grpc_slice_unref(slice);
+  signal(&caller_to_tsi_notification);
+  return TSI_OK;
+}
+
+static tsi_result mock_next(alts_handshaker_client* self, alts_tsi_event* event,
+                            grpc_slice* bytes_received) {
+  alts_mock_handshaker_client* client =
+      reinterpret_cast<alts_mock_handshaker_client*>(self);
+  if (!client->used_for_success_test) {
+    alts_tsi_event_destroy(event);
+    return TSI_INTERNAL_ERROR;
+  }
+  bool is_client =
+      alts_tsi_handshaker_get_is_client_for_testing(event->handshaker);
+  if (is_client) {
+    GPR_ASSERT(event->cb == on_client_next_success_cb);
+  } else {
+    GPR_ASSERT(event->cb == on_server_next_success_cb);
+  }
+  GPR_ASSERT(event->user_data == nullptr);
+  GPR_ASSERT(bytes_received != nullptr);
+  GPR_ASSERT(memcmp(GRPC_SLICE_START_PTR(*bytes_received),
+                    ALTS_TSI_HANDSHAKER_TEST_RECV_BYTES,
+                    GRPC_SLICE_LENGTH(*bytes_received)) == 0);
+  GPR_ASSERT(grpc_slice_cmp(alts_tsi_handshaker_get_recv_bytes_for_testing(
+                                event->handshaker),
+                            *bytes_received) == 0);
+  GPR_ASSERT(alts_tsi_handshaker_get_has_sent_start_message_for_testing(
+      event->handshaker));
+  /* Populate handshaker response for next request. */
+  grpc_slice out_frame =
+      grpc_slice_from_static_string(ALTS_TSI_HANDSHAKER_TEST_OUT_FRAME);
+  if (is_client) {
+    event->recv_buffer = generate_handshaker_response(CLIENT_NEXT);
+  } else {
+    event->recv_buffer = generate_handshaker_response(SERVER_NEXT);
+  }
+  alts_tsi_handshaker_set_recv_bytes_for_testing(event->handshaker, &out_frame);
+  if (is_client) {
+    client_next_event = event;
+  } else {
+    server_next_event = event;
+  }
+  signal(&caller_to_tsi_notification);
+  grpc_slice_unref(out_frame);
+  return TSI_OK;
+}
+
+static void mock_destruct(alts_handshaker_client* client) {}
+
+static const alts_handshaker_client_vtable vtable = {
+    mock_client_start, mock_server_start, mock_next, mock_destruct};
+
+static alts_handshaker_client* alts_mock_handshaker_client_create(
+    bool used_for_success_test) {
+  alts_mock_handshaker_client* client =
+      static_cast<alts_mock_handshaker_client*>(gpr_zalloc(sizeof(*client)));
+  client->base.vtable = &vtable;
+  client->used_for_success_test = used_for_success_test;
+  return &client->base;
+}
+
+static tsi_handshaker* create_test_handshaker(bool used_for_success_test,
+                                              bool is_client) {
+  tsi_handshaker* handshaker = nullptr;
+  alts_handshaker_client* client =
+      alts_mock_handshaker_client_create(used_for_success_test);
+  grpc_alts_credentials_options* options =
+      grpc_alts_credentials_client_options_create();
+  alts_tsi_handshaker_create(options, "target_name", "lame", is_client,
+                             &handshaker);
+  alts_tsi_handshaker* alts_handshaker =
+      reinterpret_cast<alts_tsi_handshaker*>(handshaker);
+  alts_tsi_handshaker_set_client_for_testing(alts_handshaker, client);
+  grpc_alts_credentials_options_destroy(options);
+  return handshaker;
+}
+
+static void check_handshaker_next_invalid_input() {
+  /* Initialization. */
+  tsi_handshaker* handshaker = create_test_handshaker(true, true);
+  /* Check nullptr handshaker. */
+  GPR_ASSERT(tsi_handshaker_next(nullptr, nullptr, 0, nullptr, nullptr, nullptr,
+                                 check_must_not_be_called,
+                                 nullptr) == TSI_INVALID_ARGUMENT);
+  /* Check nullptr callback. */
+  GPR_ASSERT(tsi_handshaker_next(handshaker, nullptr, 0, nullptr, nullptr,
+                                 nullptr, nullptr,
+                                 nullptr) == TSI_INVALID_ARGUMENT);
+  /* Cleanup. */
+  tsi_handshaker_destroy(handshaker);
+}
+
+static void check_handshaker_next_success() {
+  /**
+   * Create handshakers for which internal mock client is going to do
+   * correctness check.
+   */
+  tsi_handshaker* client_handshaker = create_test_handshaker(
+      true /* used_for_success_test */, true /* is_client */);
+  tsi_handshaker* server_handshaker = create_test_handshaker(
+      true /* used_for_success_test */, false /* is_client */);
+  /* Client start. */
+  GPR_ASSERT(tsi_handshaker_next(client_handshaker, nullptr, 0, nullptr,
+                                 nullptr, nullptr, on_client_start_success_cb,
+                                 nullptr) == TSI_ASYNC);
+  wait(&tsi_to_caller_notification);
+  /* Client next. */
+  GPR_ASSERT(tsi_handshaker_next(
+                 client_handshaker,
+                 (const unsigned char*)ALTS_TSI_HANDSHAKER_TEST_RECV_BYTES,
+                 strlen(ALTS_TSI_HANDSHAKER_TEST_RECV_BYTES), nullptr, nullptr,
+                 nullptr, on_client_next_success_cb, nullptr) == TSI_ASYNC);
+  wait(&tsi_to_caller_notification);
+  /* Server start. */
+  GPR_ASSERT(tsi_handshaker_next(server_handshaker, nullptr, 0, nullptr,
+                                 nullptr, nullptr, on_server_start_success_cb,
+                                 nullptr) == TSI_ASYNC);
+  wait(&tsi_to_caller_notification);
+  /* Server next. */
+  GPR_ASSERT(tsi_handshaker_next(
+                 server_handshaker,
+                 (const unsigned char*)ALTS_TSI_HANDSHAKER_TEST_RECV_BYTES,
+                 strlen(ALTS_TSI_HANDSHAKER_TEST_RECV_BYTES), nullptr, nullptr,
+                 nullptr, on_server_next_success_cb, nullptr) == TSI_ASYNC);
+  wait(&tsi_to_caller_notification);
+  /* Cleanup. */
+  tsi_handshaker_destroy(server_handshaker);
+  tsi_handshaker_destroy(client_handshaker);
+}
+
+static void check_handshaker_next_failure() {
+  /**
+   * Create handshakers for which internal mock client is always going to fail.
+   */
+  tsi_handshaker* client_handshaker = create_test_handshaker(
+      false /* used_for_success_test */, true /* is_client */);
+  tsi_handshaker* server_handshaker = create_test_handshaker(
+      false /* used_for_success_test */, false /* is_client */);
+  /* Client start. */
+  GPR_ASSERT(tsi_handshaker_next(client_handshaker, nullptr, 0, nullptr,
+                                 nullptr, nullptr, check_must_not_be_called,
+                                 nullptr) == TSI_INTERNAL_ERROR);
+  /* Server start. */
+  GPR_ASSERT(tsi_handshaker_next(server_handshaker, nullptr, 0, nullptr,
+                                 nullptr, nullptr, check_must_not_be_called,
+                                 nullptr) == TSI_INTERNAL_ERROR);
+  /* Server next. */
+  GPR_ASSERT(tsi_handshaker_next(
+                 server_handshaker,
+                 (const unsigned char*)ALTS_TSI_HANDSHAKER_TEST_RECV_BYTES,
+                 strlen(ALTS_TSI_HANDSHAKER_TEST_RECV_BYTES), nullptr, nullptr,
+                 nullptr, check_must_not_be_called,
+                 nullptr) == TSI_INTERNAL_ERROR);
+  /* Client next. */
+  GPR_ASSERT(tsi_handshaker_next(
+                 client_handshaker,
+                 (const unsigned char*)ALTS_TSI_HANDSHAKER_TEST_RECV_BYTES,
+                 strlen(ALTS_TSI_HANDSHAKER_TEST_RECV_BYTES), nullptr, nullptr,
+                 nullptr, check_must_not_be_called,
+                 nullptr) == TSI_INTERNAL_ERROR);
+  /* Cleanup. */
+  tsi_handshaker_destroy(server_handshaker);
+  tsi_handshaker_destroy(client_handshaker);
+}
+
+static void on_invalid_input_cb(tsi_result status, void* user_data,
+                                const unsigned char* bytes_to_send,
+                                size_t bytes_to_send_size,
+                                tsi_handshaker_result* result) {
+  GPR_ASSERT(status == TSI_INTERNAL_ERROR);
+  GPR_ASSERT(user_data == nullptr);
+  GPR_ASSERT(bytes_to_send == nullptr);
+  GPR_ASSERT(bytes_to_send_size == 0);
+  GPR_ASSERT(result == nullptr);
+}
+
+static void on_failed_grpc_call_cb(tsi_result status, void* user_data,
+                                   const unsigned char* bytes_to_send,
+                                   size_t bytes_to_send_size,
+                                   tsi_handshaker_result* result) {
+  GPR_ASSERT(status == TSI_INTERNAL_ERROR);
+  GPR_ASSERT(user_data == nullptr);
+  GPR_ASSERT(bytes_to_send == nullptr);
+  GPR_ASSERT(bytes_to_send_size == 0);
+  GPR_ASSERT(result == nullptr);
+}
+
+static void check_handle_response_invalid_input() {
+  /**
+   * Create a handshaker at the client side, for which internal mock client is
+   * always going to fail.
+   */
+  tsi_handshaker* handshaker = create_test_handshaker(
+      false /* used_for_success_test */, true /* is_client */);
+  alts_tsi_handshaker* alts_handshaker =
+      reinterpret_cast<alts_tsi_handshaker*>(handshaker);
+  grpc_byte_buffer recv_buffer;
+  /* Check nullptr handshaker. */
+  alts_tsi_handshaker_handle_response(nullptr, &recv_buffer, GRPC_STATUS_OK,
+                                      nullptr, on_invalid_input_cb, nullptr,
+                                      true);
+  /* Check nullptr recv_bytes. */
+  alts_tsi_handshaker_handle_response(alts_handshaker, nullptr, GRPC_STATUS_OK,
+                                      nullptr, on_invalid_input_cb, nullptr,
+                                      true);
+  /* Check failed grpc call made to handshaker service. */
+  alts_tsi_handshaker_handle_response(alts_handshaker, &recv_buffer,
+                                      GRPC_STATUS_UNKNOWN, nullptr,
+                                      on_failed_grpc_call_cb, nullptr, true);
+
+  alts_tsi_handshaker_handle_response(alts_handshaker, &recv_buffer,
+                                      GRPC_STATUS_OK, nullptr,
+                                      on_failed_grpc_call_cb, nullptr, false);
+
+  /* Cleanup. */
+  tsi_handshaker_destroy(handshaker);
+}
+
+static void on_invalid_resp_cb(tsi_result status, void* user_data,
+                               const unsigned char* bytes_to_send,
+                               size_t bytes_to_send_size,
+                               tsi_handshaker_result* result) {
+  GPR_ASSERT(status == TSI_DATA_CORRUPTED);
+  GPR_ASSERT(user_data == nullptr);
+  GPR_ASSERT(bytes_to_send == nullptr);
+  GPR_ASSERT(bytes_to_send_size == 0);
+  GPR_ASSERT(result == nullptr);
+}
+
+static void check_handle_response_invalid_resp() {
+  /**
+   * Create a handshaker at the client side, for which internal mock client is
+   * always going to fail.
+   */
+  tsi_handshaker* handshaker = create_test_handshaker(
+      false /* used_for_success_test */, true /* is_client */);
+  alts_tsi_handshaker* alts_handshaker =
+      reinterpret_cast<alts_tsi_handshaker*>(handshaker);
+  /* Tests. */
+  grpc_byte_buffer* recv_buffer = generate_handshaker_response(INVALID);
+  alts_tsi_handshaker_handle_response(alts_handshaker, recv_buffer,
+                                      GRPC_STATUS_OK, nullptr,
+                                      on_invalid_resp_cb, nullptr, true);
+  /* Cleanup. */
+  grpc_byte_buffer_destroy(recv_buffer);
+  tsi_handshaker_destroy(handshaker);
+}
+
+static void check_handle_response_success(void* unused) {
+  /* Client start. */
+  wait(&caller_to_tsi_notification);
+  alts_tsi_event_dispatch_to_handshaker(client_start_event, true /* is_ok */);
+  alts_tsi_event_destroy(client_start_event);
+  /* Client next. */
+  wait(&caller_to_tsi_notification);
+  alts_tsi_event_dispatch_to_handshaker(client_next_event, true /* is_ok */);
+  alts_tsi_event_destroy(client_next_event);
+  /* Server start. */
+  wait(&caller_to_tsi_notification);
+  alts_tsi_event_dispatch_to_handshaker(server_start_event, true /* is_ok */);
+  alts_tsi_event_destroy(server_start_event);
+  /* Server next. */
+  wait(&caller_to_tsi_notification);
+  alts_tsi_event_dispatch_to_handshaker(server_next_event, true /* is_ok */);
+  alts_tsi_event_destroy(server_next_event);
+}
+
+static void on_failed_resp_cb(tsi_result status, void* user_data,
+                              const unsigned char* bytes_to_send,
+                              size_t bytes_to_send_size,
+                              tsi_handshaker_result* result) {
+  GPR_ASSERT(status == TSI_INVALID_ARGUMENT);
+  GPR_ASSERT(user_data == nullptr);
+  GPR_ASSERT(bytes_to_send == nullptr);
+  GPR_ASSERT(bytes_to_send_size == 0);
+  GPR_ASSERT(result == nullptr);
+}
+
+static void check_handle_response_failure() {
+  /**
+   * Create a handshaker at the client side, for which internal mock client is
+   * always going to fail.
+   */
+  tsi_handshaker* handshaker = create_test_handshaker(
+      false /* used_for_success_test */, true /* is_client */);
+  alts_tsi_handshaker* alts_handshaker =
+      reinterpret_cast<alts_tsi_handshaker*>(handshaker);
+  /* Tests. */
+  grpc_byte_buffer* recv_buffer = generate_handshaker_response(FAILED);
+  alts_tsi_handshaker_handle_response(alts_handshaker, recv_buffer,
+                                      GRPC_STATUS_OK, nullptr,
+                                      on_failed_resp_cb, nullptr, true);
+  grpc_byte_buffer_destroy(recv_buffer);
+  /* Cleanup. */
+  tsi_handshaker_destroy(handshaker);
+}
+
+void check_handshaker_success() {
+  /* Initialization. */
+  notification_init(&caller_to_tsi_notification);
+  notification_init(&tsi_to_caller_notification);
+  client_start_event = nullptr;
+  client_next_event = nullptr;
+  server_start_event = nullptr;
+  server_next_event = nullptr;
+  /* Tests. */
+  grpc_core::Thread thd("alts_tsi_handshaker_test",
+                        &check_handle_response_success, nullptr);
+  thd.Start();
+  check_handshaker_next_success();
+  thd.Join();
+  /* Cleanup. */
+  notification_destroy(&caller_to_tsi_notification);
+  notification_destroy(&tsi_to_caller_notification);
+}
+
+int main(int argc, char** argv) {
+  /* Initialization. */
+  grpc_init();
+  /* Tests. */
+  check_handshaker_success();
+  check_handshaker_next_invalid_input();
+  check_handshaker_next_failure();
+  check_handle_response_invalid_input();
+  check_handle_response_invalid_resp();
+  check_handle_response_failure();
+  /* Cleanup. */
+  grpc_shutdown();
+  return 0;
+}
diff --git a/test/core/tsi/alts/handshaker/alts_tsi_utils_test.cc b/test/core/tsi/alts/handshaker/alts_tsi_utils_test.cc
new file mode 100644
index 0000000..98c5d23
--- /dev/null
+++ b/test/core/tsi/alts/handshaker/alts_tsi_utils_test.cc
@@ -0,0 +1,73 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/core/tsi/alts/handshaker/alts_tsi_utils.h"
+#include "test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.h"
+
+#define ALTS_TSI_UTILS_TEST_OUT_FRAME "Hello Google"
+
+static void convert_to_tsi_result_test() {
+  GPR_ASSERT(alts_tsi_utils_convert_to_tsi_result(GRPC_STATUS_OK) == TSI_OK);
+  GPR_ASSERT(alts_tsi_utils_convert_to_tsi_result(GRPC_STATUS_UNKNOWN) ==
+             TSI_UNKNOWN_ERROR);
+  GPR_ASSERT(alts_tsi_utils_convert_to_tsi_result(
+                 GRPC_STATUS_INVALID_ARGUMENT) == TSI_INVALID_ARGUMENT);
+  GPR_ASSERT(alts_tsi_utils_convert_to_tsi_result(GRPC_STATUS_OUT_OF_RANGE) ==
+             TSI_UNKNOWN_ERROR);
+  GPR_ASSERT(alts_tsi_utils_convert_to_tsi_result(GRPC_STATUS_INTERNAL) ==
+             TSI_INTERNAL_ERROR);
+  GPR_ASSERT(alts_tsi_utils_convert_to_tsi_result(GRPC_STATUS_NOT_FOUND) ==
+             TSI_NOT_FOUND);
+}
+
+static void deserialize_response_test() {
+  grpc_gcp_handshaker_resp* resp = grpc_gcp_handshaker_resp_create();
+  GPR_ASSERT(grpc_gcp_handshaker_resp_set_out_frames(
+      resp, ALTS_TSI_UTILS_TEST_OUT_FRAME,
+      strlen(ALTS_TSI_UTILS_TEST_OUT_FRAME)));
+  grpc_slice slice;
+  GPR_ASSERT(grpc_gcp_handshaker_resp_encode(resp, &slice));
+
+  /* Valid serialization. */
+  grpc_byte_buffer* buffer =
+      grpc_raw_byte_buffer_create(&slice, 1 /* number of slices */);
+  grpc_gcp_handshaker_resp* decoded_resp =
+      alts_tsi_utils_deserialize_response(buffer);
+  GPR_ASSERT(grpc_gcp_handshaker_resp_equals(resp, decoded_resp));
+  grpc_byte_buffer_destroy(buffer);
+
+  /* Invalid serializaiton. */
+  grpc_slice bad_slice =
+      grpc_slice_split_head(&slice, GRPC_SLICE_LENGTH(slice) - 1);
+  buffer = grpc_raw_byte_buffer_create(&bad_slice, 1 /* number of slices */);
+  GPR_ASSERT(alts_tsi_utils_deserialize_response(buffer) == nullptr);
+
+  /* Clean up. */
+  grpc_slice_unref(slice);
+  grpc_slice_unref(bad_slice);
+  grpc_byte_buffer_destroy(buffer);
+  grpc_gcp_handshaker_resp_destroy(resp);
+  grpc_gcp_handshaker_resp_destroy(decoded_resp);
+}
+
+int main(int argc, char** argv) {
+  /* Tests. */
+  deserialize_response_test();
+  convert_to_tsi_result_test();
+  return 0;
+}
diff --git a/test/core/tsi/alts/handshaker/transport_security_common_api_test.cc b/test/core/tsi/alts/handshaker/transport_security_common_api_test.cc
new file mode 100644
index 0000000..6ff1357
--- /dev/null
+++ b/test/core/tsi/alts/handshaker/transport_security_common_api_test.cc
@@ -0,0 +1,196 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "src/core/tsi/alts/handshaker/transport_security_common_api.h"
+
+const size_t kMaxRpcVersionMajor = 3;
+const size_t kMaxRpcVersionMinor = 2;
+const size_t kMinRpcVersionMajor = 2;
+const size_t kMinRpcVersionMinor = 1;
+
+static bool grpc_gcp_rpc_protocol_versions_equal(
+    grpc_gcp_rpc_protocol_versions* l_versions,
+    grpc_gcp_rpc_protocol_versions* r_versions) {
+  GPR_ASSERT(l_versions != nullptr && r_versions != nullptr);
+  if ((l_versions->has_max_rpc_version ^ r_versions->has_max_rpc_version) |
+      (l_versions->has_min_rpc_version ^ r_versions->has_min_rpc_version)) {
+    return false;
+  }
+  if (l_versions->has_max_rpc_version) {
+    if ((l_versions->max_rpc_version.major !=
+         r_versions->max_rpc_version.major) ||
+        (l_versions->max_rpc_version.minor !=
+         r_versions->max_rpc_version.minor)) {
+      return false;
+    }
+  }
+  if (l_versions->has_min_rpc_version) {
+    if ((l_versions->min_rpc_version.major !=
+         r_versions->min_rpc_version.major) ||
+        (l_versions->min_rpc_version.minor !=
+         r_versions->min_rpc_version.minor)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+static void test_success() {
+  grpc_gcp_rpc_protocol_versions version;
+  grpc_gcp_rpc_protocol_versions decoded_version;
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_max(
+      &version, kMaxRpcVersionMajor, kMaxRpcVersionMinor));
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_min(
+      &version, kMinRpcVersionMajor, kMinRpcVersionMinor));
+  /* Serializes to raw bytes. */
+  size_t encoded_length =
+      grpc_gcp_rpc_protocol_versions_encode_length(&version);
+  uint8_t* encoded_bytes = static_cast<uint8_t*>(gpr_malloc(encoded_length));
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_encode_to_raw_bytes(
+      &version, encoded_bytes, encoded_length));
+  grpc_slice encoded_slice;
+  /* Serializes to grpc slice. */
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_encode(&version, &encoded_slice));
+  /* Checks serialized raw bytes and serialized grpc slice have same content. */
+  GPR_ASSERT(encoded_length == GRPC_SLICE_LENGTH(encoded_slice));
+  GPR_ASSERT(memcmp(encoded_bytes, GRPC_SLICE_START_PTR(encoded_slice),
+                    encoded_length) == 0);
+  /* Deserializes and compares with the original version. */
+  GPR_ASSERT(
+      grpc_gcp_rpc_protocol_versions_decode(encoded_slice, &decoded_version));
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_equal(&version, &decoded_version));
+  grpc_slice_unref(encoded_slice);
+  gpr_free(encoded_bytes);
+}
+
+static void test_failure() {
+  grpc_gcp_rpc_protocol_versions version, decoded_version;
+  grpc_slice encoded_slice;
+  /* Test for invalid arguments. */
+  GPR_ASSERT(!grpc_gcp_rpc_protocol_versions_set_max(
+      nullptr, kMaxRpcVersionMajor, kMaxRpcVersionMinor));
+  GPR_ASSERT(!grpc_gcp_rpc_protocol_versions_set_min(
+      nullptr, kMinRpcVersionMajor, kMinRpcVersionMinor));
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_encode_length(nullptr) == 0);
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_max(
+      &version, kMaxRpcVersionMajor, kMaxRpcVersionMinor));
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_min(
+      &version, kMinRpcVersionMajor, kMinRpcVersionMinor));
+  size_t encoded_length =
+      grpc_gcp_rpc_protocol_versions_encode_length(&version);
+  uint8_t* encoded_bytes = static_cast<uint8_t*>(gpr_malloc(encoded_length));
+  GPR_ASSERT(!grpc_gcp_rpc_protocol_versions_encode_to_raw_bytes(
+      nullptr, encoded_bytes, encoded_length));
+  GPR_ASSERT(!grpc_gcp_rpc_protocol_versions_encode_to_raw_bytes(
+      &version, nullptr, encoded_length));
+  GPR_ASSERT(!grpc_gcp_rpc_protocol_versions_encode_to_raw_bytes(
+      &version, encoded_bytes, 0));
+  GPR_ASSERT(!grpc_gcp_rpc_protocol_versions_encode(nullptr, &encoded_slice));
+  GPR_ASSERT(!grpc_gcp_rpc_protocol_versions_encode(&version, nullptr));
+  GPR_ASSERT(!grpc_gcp_rpc_protocol_versions_decode(encoded_slice, nullptr));
+  /* Test for nanopb decode. */
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_encode(&version, &encoded_slice));
+  grpc_slice bad_slice = grpc_slice_split_head(
+      &encoded_slice, GRPC_SLICE_LENGTH(encoded_slice) - 1);
+  grpc_slice_unref(encoded_slice);
+  GPR_ASSERT(
+      !grpc_gcp_rpc_protocol_versions_decode(bad_slice, &decoded_version));
+  grpc_slice_unref(bad_slice);
+  gpr_free(encoded_bytes);
+}
+
+static void test_copy() {
+  grpc_gcp_rpc_protocol_versions src;
+  grpc_gcp_rpc_protocol_versions des;
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_max(&src, kMaxRpcVersionMajor,
+                                                    kMaxRpcVersionMinor));
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_min(&src, kMinRpcVersionMajor,
+                                                    kMinRpcVersionMinor));
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_copy(&src, &des));
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_equal(&src, &des));
+}
+
+static void test_check_success() {
+  grpc_gcp_rpc_protocol_versions v1;
+  grpc_gcp_rpc_protocol_versions v2;
+  grpc_gcp_rpc_protocol_versions_version highest_common_version;
+  /* test equality. */
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_max(&v1, kMaxRpcVersionMajor,
+                                                    kMaxRpcVersionMinor));
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_min(&v1, kMaxRpcVersionMajor,
+                                                    kMaxRpcVersionMinor));
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_max(&v2, kMaxRpcVersionMajor,
+                                                    kMaxRpcVersionMinor));
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_min(&v2, kMaxRpcVersionMajor,
+                                                    kMaxRpcVersionMinor));
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_check(
+                 (const grpc_gcp_rpc_protocol_versions*)&v1,
+                 (const grpc_gcp_rpc_protocol_versions*)&v2,
+                 &highest_common_version) == 1);
+  GPR_ASSERT(grpc_core::internal::grpc_gcp_rpc_protocol_version_compare(
+                 &highest_common_version, &v1.max_rpc_version) == 0);
+
+  /* test inequality. */
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_max(&v1, kMaxRpcVersionMajor,
+                                                    kMaxRpcVersionMinor));
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_min(&v1, kMinRpcVersionMinor,
+                                                    kMinRpcVersionMinor));
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_max(&v2, kMaxRpcVersionMajor,
+                                                    kMinRpcVersionMinor));
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_min(&v2, kMinRpcVersionMajor,
+                                                    kMaxRpcVersionMinor));
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_check(
+                 (const grpc_gcp_rpc_protocol_versions*)&v1,
+                 (const grpc_gcp_rpc_protocol_versions*)&v2,
+                 &highest_common_version) == 1);
+  GPR_ASSERT(grpc_core::internal::grpc_gcp_rpc_protocol_version_compare(
+                 &highest_common_version, &v2.max_rpc_version) == 0);
+}
+
+static void test_check_failure() {
+  grpc_gcp_rpc_protocol_versions v1;
+  grpc_gcp_rpc_protocol_versions v2;
+  grpc_gcp_rpc_protocol_versions_version highest_common_version;
+
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_max(&v1, kMinRpcVersionMajor,
+                                                    kMinRpcVersionMinor));
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_min(&v1, kMinRpcVersionMajor,
+                                                    kMinRpcVersionMinor));
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_max(&v2, kMaxRpcVersionMajor,
+                                                    kMaxRpcVersionMinor));
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_set_min(&v2, kMaxRpcVersionMajor,
+                                                    kMaxRpcVersionMinor));
+  GPR_ASSERT(grpc_gcp_rpc_protocol_versions_check(
+                 (const grpc_gcp_rpc_protocol_versions*)&v1,
+                 (const grpc_gcp_rpc_protocol_versions*)&v2,
+                 &highest_common_version) == 0);
+}
+
+int main(int argc, char** argv) {
+  /* Run tests. */
+  test_success();
+  test_failure();
+  test_copy();
+  test_check_success();
+  test_check_failure();
+  return 0;
+}
diff --git a/test/core/tsi/alts/zero_copy_frame_protector/BUILD b/test/core/tsi/alts/zero_copy_frame_protector/BUILD
new file mode 100644
index 0000000..4c6fb91
--- /dev/null
+++ b/test/core/tsi/alts/zero_copy_frame_protector/BUILD
@@ -0,0 +1,57 @@
+# Copyright 2018 gRPC authors.
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_package")
+
+licenses(["notice"])  # Apache v2
+
+grpc_package(name = "zero_copy_frame_protector")
+
+grpc_cc_test(
+    name = "alts_grpc_record_protocol_test",
+    srcs = ["alts_grpc_record_protocol_test.cc"],
+    language = "C++",
+    deps = [
+        "//:alts_frame_protector",
+        "//:gpr",
+        "//:grpc",
+        "//:grpc_base_c",
+        "//test/core/tsi/alts/crypt:alts_crypt_test_util",
+    ],
+)
+
+grpc_cc_test(
+    name = "alts_iovec_record_protocol_test",
+    srcs = ["alts_iovec_record_protocol_test.cc"],
+    language = "C++",
+    deps = [
+        "//:alts_frame_protector",
+        "//:gpr",
+        "//:grpc",
+        "//test/core/tsi/alts/crypt:alts_crypt_test_util",
+    ],
+)
+
+grpc_cc_test(
+    name = "alts_zero_copy_grpc_protector_test",
+    srcs = ["alts_zero_copy_grpc_protector_test.cc"],
+    language = "C++",
+    deps = [
+        "//:alts_frame_protector",
+        "//:gpr",
+        "//:grpc",
+        "//:grpc_base_c",
+        "//test/core/tsi/alts/crypt:alts_crypt_test_util",
+    ],
+)
diff --git a/test/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_test.cc b/test/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_test.cc
new file mode 100644
index 0000000..b763f19
--- /dev/null
+++ b/test/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_test.cc
@@ -0,0 +1,450 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h"
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h"
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h"
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h"
+#include "test/core/tsi/alts/crypt/gsec_test_util.h"
+
+constexpr size_t kMaxSliceLength = 256;
+constexpr size_t kMaxSlices = 10;
+constexpr size_t kSealRepeatTimes = 5;
+constexpr size_t kTagLength = 16;
+
+/* Test fixtures for each test cases.  */
+struct alts_grpc_record_protocol_test_fixture {
+  alts_grpc_record_protocol* client_protect;
+  alts_grpc_record_protocol* client_unprotect;
+  alts_grpc_record_protocol* server_protect;
+  alts_grpc_record_protocol* server_unprotect;
+};
+
+/* Test input variables for protect/unprotect operations.  */
+struct alts_grpc_record_protocol_test_var {
+  size_t header_length;
+  size_t tag_length;
+  grpc_slice_buffer original_sb;
+  grpc_slice_buffer duplicate_sb;
+  grpc_slice_buffer protected_sb;
+  grpc_slice_buffer unprotected_sb;
+};
+
+/* --- Test utility functions. --- */
+
+static void create_random_slice_buffer(grpc_slice_buffer* sb) {
+  GPR_ASSERT(sb != nullptr);
+  size_t slice_count = gsec_test_bias_random_uint32(kMaxSlices) + 1;
+  for (size_t i = 0; i < slice_count; i++) {
+    size_t slice_length = gsec_test_bias_random_uint32(kMaxSliceLength) + 1;
+    grpc_slice slice = GRPC_SLICE_MALLOC(slice_length);
+    gsec_test_random_bytes(GRPC_SLICE_START_PTR(slice), slice_length);
+    grpc_slice_buffer_add(sb, slice);
+  }
+}
+
+static uint8_t* pointer_to_nth_byte(grpc_slice_buffer* sb, size_t index) {
+  GPR_ASSERT(sb != nullptr);
+  GPR_ASSERT(index < sb->length);
+  for (size_t i = 0; i < sb->count; i++) {
+    if (index < GRPC_SLICE_LENGTH(sb->slices[i])) {
+      return GRPC_SLICE_START_PTR(sb->slices[i]) + index;
+    } else {
+      index -= GRPC_SLICE_LENGTH(sb->slices[i]);
+    }
+  }
+  return nullptr;
+}
+
+/* Checks if two slice buffer contents are the same. It is not super efficient,
+ * but OK for testing.  */
+static bool are_slice_buffers_equal(grpc_slice_buffer* first,
+                                    grpc_slice_buffer* second) {
+  GPR_ASSERT(first != nullptr);
+  GPR_ASSERT(second != nullptr);
+  if (first->length != second->length) {
+    return false;
+  }
+  for (size_t i = 0; i < first->length; i++) {
+    uint8_t* first_ptr = pointer_to_nth_byte(first, i);
+    uint8_t* second_ptr = pointer_to_nth_byte(second, i);
+    GPR_ASSERT(first_ptr != nullptr);
+    GPR_ASSERT(second_ptr != nullptr);
+    if ((*first_ptr) != (*second_ptr)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+static void alter_random_byte(grpc_slice_buffer* sb) {
+  GPR_ASSERT(sb != nullptr);
+  if (sb->length == 0) {
+    return;
+  }
+  uint32_t offset =
+      gsec_test_bias_random_uint32(static_cast<uint32_t>(sb->length));
+  uint8_t* ptr = pointer_to_nth_byte(sb, offset);
+  (*ptr)++;
+}
+
+static alts_grpc_record_protocol_test_fixture*
+test_fixture_integrity_only_create(bool rekey) {
+  alts_grpc_record_protocol_test_fixture* fixture =
+      static_cast<alts_grpc_record_protocol_test_fixture*>(
+          gpr_zalloc(sizeof(alts_grpc_record_protocol_test_fixture)));
+  size_t key_length = rekey ? kAes128GcmRekeyKeyLength : kAes128GcmKeyLength;
+  uint8_t* key;
+  gsec_test_random_array(&key, key_length);
+  gsec_aead_crypter* crypter = nullptr;
+
+  /* Create client record protocol for protect. */
+  GPR_ASSERT(gsec_aes_gcm_aead_crypter_create(
+                 key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
+                 &crypter, nullptr) == GRPC_STATUS_OK);
+  GPR_ASSERT(alts_grpc_integrity_only_record_protocol_create(
+                 crypter, 8, /*is_client=*/true, /*is_protect=*/true,
+                 &fixture->client_protect) == TSI_OK);
+  /* Create client record protocol for unprotect.  */
+  GPR_ASSERT(gsec_aes_gcm_aead_crypter_create(
+                 key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
+                 &crypter, nullptr) == GRPC_STATUS_OK);
+  GPR_ASSERT(alts_grpc_integrity_only_record_protocol_create(
+                 crypter, 8, /*is_client=*/true, /*is_protect=*/false,
+                 &fixture->client_unprotect) == TSI_OK);
+  /* Create server record protocol for protect.  */
+  GPR_ASSERT(gsec_aes_gcm_aead_crypter_create(
+                 key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
+                 &crypter, nullptr) == GRPC_STATUS_OK);
+  GPR_ASSERT(alts_grpc_integrity_only_record_protocol_create(
+                 crypter, 8, /*is_client=*/false, /*is_protect=*/true,
+                 &fixture->server_protect) == TSI_OK);
+  /* Create server record protocol for unprotect.  */
+  GPR_ASSERT(gsec_aes_gcm_aead_crypter_create(
+                 key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
+                 &crypter, nullptr) == GRPC_STATUS_OK);
+  GPR_ASSERT(alts_grpc_integrity_only_record_protocol_create(
+                 crypter, 8, /*is_client=*/false, /*is_protect=*/false,
+                 &fixture->server_unprotect) == TSI_OK);
+
+  gpr_free(key);
+  return fixture;
+}
+
+static alts_grpc_record_protocol_test_fixture*
+test_fixture_integrity_only_no_rekey_create() {
+  return test_fixture_integrity_only_create(false);
+}
+
+static alts_grpc_record_protocol_test_fixture*
+test_fixture_integrity_only_rekey_create() {
+  return test_fixture_integrity_only_create(true);
+}
+
+static alts_grpc_record_protocol_test_fixture*
+test_fixture_privacy_integrity_create(bool rekey) {
+  alts_grpc_record_protocol_test_fixture* fixture =
+      static_cast<alts_grpc_record_protocol_test_fixture*>(
+          gpr_zalloc(sizeof(alts_grpc_record_protocol_test_fixture)));
+  size_t key_length = rekey ? kAes128GcmRekeyKeyLength : kAes128GcmKeyLength;
+  uint8_t* key;
+  gsec_test_random_array(&key, key_length);
+  gsec_aead_crypter* crypter = nullptr;
+
+  /* Create client record protocol for protect. */
+  GPR_ASSERT(gsec_aes_gcm_aead_crypter_create(
+                 key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
+                 &crypter, nullptr) == GRPC_STATUS_OK);
+  GPR_ASSERT(alts_grpc_privacy_integrity_record_protocol_create(
+                 crypter, 8, /*is_client=*/true, /*is_protect=*/true,
+                 &fixture->client_protect) == TSI_OK);
+  /* Create client record protocol for unprotect.  */
+  GPR_ASSERT(gsec_aes_gcm_aead_crypter_create(
+                 key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
+                 &crypter, nullptr) == GRPC_STATUS_OK);
+  GPR_ASSERT(alts_grpc_privacy_integrity_record_protocol_create(
+                 crypter, 8, /*is_client=*/true, /*is_protect=*/false,
+                 &fixture->client_unprotect) == TSI_OK);
+  /* Create server record protocol for protect.  */
+  GPR_ASSERT(gsec_aes_gcm_aead_crypter_create(
+                 key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
+                 &crypter, nullptr) == GRPC_STATUS_OK);
+  GPR_ASSERT(alts_grpc_privacy_integrity_record_protocol_create(
+                 crypter, 8, /*is_client=*/false, /*is_protect=*/true,
+                 &fixture->server_protect) == TSI_OK);
+  /* Create server record protocol for unprotect.  */
+  GPR_ASSERT(gsec_aes_gcm_aead_crypter_create(
+                 key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
+                 &crypter, nullptr) == GRPC_STATUS_OK);
+  GPR_ASSERT(alts_grpc_privacy_integrity_record_protocol_create(
+                 crypter, 8, /*is_client=*/false, /*is_protect=*/false,
+                 &fixture->server_unprotect) == TSI_OK);
+
+  gpr_free(key);
+  return fixture;
+}
+
+static alts_grpc_record_protocol_test_fixture*
+test_fixture_privacy_integrity_no_rekey_create() {
+  return test_fixture_privacy_integrity_create(false);
+}
+
+static alts_grpc_record_protocol_test_fixture*
+test_fixture_privacy_integrity_rekey_create() {
+  return test_fixture_privacy_integrity_create(true);
+}
+
+static void alts_grpc_record_protocol_test_fixture_destroy(
+    alts_grpc_record_protocol_test_fixture* fixture) {
+  if (fixture == nullptr) {
+    return;
+  }
+  grpc_core::ExecCtx exec_ctx;
+  alts_grpc_record_protocol_destroy(fixture->client_protect);
+  alts_grpc_record_protocol_destroy(fixture->client_unprotect);
+  alts_grpc_record_protocol_destroy(fixture->server_protect);
+  alts_grpc_record_protocol_destroy(fixture->server_unprotect);
+  grpc_core::ExecCtx::Get()->Flush();
+  gpr_free(fixture);
+}
+
+static alts_grpc_record_protocol_test_var*
+alts_grpc_record_protocol_test_var_create() {
+  alts_grpc_record_protocol_test_var* var =
+      static_cast<alts_grpc_record_protocol_test_var*>(
+          gpr_zalloc(sizeof(alts_grpc_record_protocol_test_var)));
+  var->header_length = alts_iovec_record_protocol_get_header_length();
+  var->tag_length = kTagLength;
+  /* Initialized slice buffers.  */
+  grpc_slice_buffer_init(&var->original_sb);
+  grpc_slice_buffer_init(&var->duplicate_sb);
+  grpc_slice_buffer_init(&var->protected_sb);
+  grpc_slice_buffer_init(&var->unprotected_sb);
+  /* Randomly sets content of original_sb, and copies into duplicate_sb.  */
+  create_random_slice_buffer(&var->original_sb);
+  for (size_t i = 0; i < var->original_sb.count; i++) {
+    grpc_slice_buffer_add(&var->duplicate_sb,
+                          grpc_slice_ref(var->original_sb.slices[i]));
+  }
+  return var;
+}
+
+static void alts_grpc_record_protocol_test_var_destroy(
+    alts_grpc_record_protocol_test_var* var) {
+  if (var == nullptr) {
+    return;
+  }
+  grpc_slice_buffer_destroy_internal(&var->original_sb);
+  grpc_slice_buffer_destroy_internal(&var->duplicate_sb);
+  grpc_slice_buffer_destroy_internal(&var->protected_sb);
+  grpc_slice_buffer_destroy_internal(&var->unprotected_sb);
+  gpr_free(var);
+}
+
+/* --- alts grpc record protocol tests. --- */
+
+static void random_seal_unseal(alts_grpc_record_protocol* sender,
+                               alts_grpc_record_protocol* receiver) {
+  grpc_core::ExecCtx exec_ctx;
+  for (size_t i = 0; i < kSealRepeatTimes; i++) {
+    alts_grpc_record_protocol_test_var* var =
+        alts_grpc_record_protocol_test_var_create();
+    /* Seals and then unseals.  */
+    size_t data_length = var->original_sb.length;
+    tsi_result status = alts_grpc_record_protocol_protect(
+        sender, &var->original_sb, &var->protected_sb);
+    GPR_ASSERT(status == TSI_OK);
+    GPR_ASSERT(var->protected_sb.length ==
+               data_length + var->header_length + var->tag_length);
+    status = alts_grpc_record_protocol_unprotect(receiver, &var->protected_sb,
+                                                 &var->unprotected_sb);
+    GPR_ASSERT(status == TSI_OK);
+    GPR_ASSERT(
+        are_slice_buffers_equal(&var->unprotected_sb, &var->duplicate_sb));
+    alts_grpc_record_protocol_test_var_destroy(var);
+  }
+  grpc_core::ExecCtx::Get()->Flush();
+}
+
+static void empty_seal_unseal(alts_grpc_record_protocol* sender,
+                              alts_grpc_record_protocol* receiver) {
+  grpc_core::ExecCtx exec_ctx;
+  for (size_t i = 0; i < kSealRepeatTimes; i++) {
+    alts_grpc_record_protocol_test_var* var =
+        alts_grpc_record_protocol_test_var_create();
+    /* Seals and then unseals empty payload.  */
+    grpc_slice_buffer_reset_and_unref_internal(&var->original_sb);
+    grpc_slice_buffer_reset_and_unref_internal(&var->duplicate_sb);
+    tsi_result status = alts_grpc_record_protocol_protect(
+        sender, &var->original_sb, &var->protected_sb);
+    GPR_ASSERT(status == TSI_OK);
+    GPR_ASSERT(var->protected_sb.length ==
+               var->header_length + var->tag_length);
+    status = alts_grpc_record_protocol_unprotect(receiver, &var->protected_sb,
+                                                 &var->unprotected_sb);
+    GPR_ASSERT(status == TSI_OK);
+    GPR_ASSERT(
+        are_slice_buffers_equal(&var->unprotected_sb, &var->duplicate_sb));
+    alts_grpc_record_protocol_test_var_destroy(var);
+  }
+  grpc_core::ExecCtx::Get()->Flush();
+}
+
+static void unsync_seal_unseal(alts_grpc_record_protocol* sender,
+                               alts_grpc_record_protocol* receiver) {
+  grpc_core::ExecCtx exec_ctx;
+  tsi_result status;
+  alts_grpc_record_protocol_test_var* var =
+      alts_grpc_record_protocol_test_var_create();
+  /* Seals once.  */
+  status = alts_grpc_record_protocol_protect(sender, &var->original_sb,
+                                             &var->protected_sb);
+  GPR_ASSERT(status == TSI_OK);
+  grpc_slice_buffer_reset_and_unref_internal(&var->protected_sb);
+  /* Seals again.  */
+  status = alts_grpc_record_protocol_protect(sender, &var->duplicate_sb,
+                                             &var->protected_sb);
+  GPR_ASSERT(status == TSI_OK);
+  /* Unseals the second frame.  */
+  status = alts_grpc_record_protocol_unprotect(receiver, &var->protected_sb,
+                                               &var->unprotected_sb);
+  GPR_ASSERT(status == TSI_INTERNAL_ERROR);
+  alts_grpc_record_protocol_test_var_destroy(var);
+  grpc_core::ExecCtx::Get()->Flush();
+}
+
+static void corrupted_data(alts_grpc_record_protocol* sender,
+                           alts_grpc_record_protocol* receiver) {
+  grpc_core::ExecCtx exec_ctx;
+  tsi_result status;
+  alts_grpc_record_protocol_test_var* var =
+      alts_grpc_record_protocol_test_var_create();
+  /* Seals once.  */
+  status = alts_grpc_record_protocol_protect(sender, &var->original_sb,
+                                             &var->protected_sb);
+  GPR_ASSERT(status == TSI_OK);
+  /* Corrupts one byte in protected_sb and tries to unprotect.  */
+  alter_random_byte(&var->protected_sb);
+  status = alts_grpc_record_protocol_unprotect(receiver, &var->protected_sb,
+                                               &var->unprotected_sb);
+  GPR_ASSERT(status == TSI_INTERNAL_ERROR);
+  alts_grpc_record_protocol_test_var_destroy(var);
+  grpc_core::ExecCtx::Get()->Flush();
+}
+
+static void input_check(alts_grpc_record_protocol* rp) {
+  grpc_core::ExecCtx exec_ctx;
+  tsi_result status;
+  alts_grpc_record_protocol_test_var* var =
+      alts_grpc_record_protocol_test_var_create();
+  /* Protects with nullptr input.  */
+  status = alts_grpc_record_protocol_protect(rp, nullptr, &var->protected_sb);
+  GPR_ASSERT(status == TSI_INVALID_ARGUMENT);
+  status = alts_grpc_record_protocol_protect(rp, &var->original_sb, nullptr);
+  GPR_ASSERT(status == TSI_INVALID_ARGUMENT);
+  /* Unprotects with nullptr input.  */
+  status = alts_grpc_record_protocol_protect(rp, &var->original_sb,
+                                             &var->protected_sb);
+  GPR_ASSERT(status == TSI_OK);
+  status =
+      alts_grpc_record_protocol_unprotect(rp, nullptr, &var->unprotected_sb);
+  GPR_ASSERT(status == TSI_INVALID_ARGUMENT);
+  status = alts_grpc_record_protocol_unprotect(rp, &var->protected_sb, nullptr);
+  GPR_ASSERT(status == TSI_INVALID_ARGUMENT);
+  /* Unprotects on a temporary slice buffer which length is smaller than header
+   * length plus tag length.  */
+  grpc_slice_buffer temp_sb;
+  grpc_slice_buffer_init(&temp_sb);
+  grpc_slice_buffer_move_first(
+      &var->protected_sb, var->header_length + var->tag_length - 1, &temp_sb);
+  status =
+      alts_grpc_record_protocol_unprotect(rp, &temp_sb, &var->unprotected_sb);
+  GPR_ASSERT(status == TSI_INVALID_ARGUMENT);
+  grpc_slice_buffer_destroy_internal(&temp_sb);
+  alts_grpc_record_protocol_test_var_destroy(var);
+  grpc_core::ExecCtx::Get()->Flush();
+}
+
+/* --- Test cases. --- */
+
+static void alts_grpc_record_protocol_random_seal_unseal_tests(
+    alts_grpc_record_protocol_test_fixture* fixture) {
+  random_seal_unseal(fixture->client_protect, fixture->server_unprotect);
+  random_seal_unseal(fixture->server_protect, fixture->client_unprotect);
+}
+
+static void alts_grpc_record_protocol_empty_seal_unseal_tests(
+    alts_grpc_record_protocol_test_fixture* fixture) {
+  empty_seal_unseal(fixture->client_protect, fixture->server_unprotect);
+  empty_seal_unseal(fixture->server_protect, fixture->client_unprotect);
+}
+
+static void alts_grpc_record_protocol_unsync_seal_unseal_tests(
+    alts_grpc_record_protocol_test_fixture* fixture) {
+  unsync_seal_unseal(fixture->client_protect, fixture->server_unprotect);
+  unsync_seal_unseal(fixture->server_protect, fixture->client_unprotect);
+}
+
+static void alts_grpc_record_protocol_corrupted_data_tests(
+    alts_grpc_record_protocol_test_fixture* fixture) {
+  corrupted_data(fixture->client_protect, fixture->server_unprotect);
+  corrupted_data(fixture->server_protect, fixture->client_unprotect);
+}
+
+static void alts_grpc_record_protocol_input_check_tests(
+    alts_grpc_record_protocol_test_fixture* fixture) {
+  input_check(fixture->client_protect);
+}
+
+static void alts_grpc_record_protocol_tests(
+    alts_grpc_record_protocol_test_fixture* (*fixture_create)()) {
+  auto* fixture_1 = fixture_create();
+  alts_grpc_record_protocol_random_seal_unseal_tests(fixture_1);
+  alts_grpc_record_protocol_test_fixture_destroy(fixture_1);
+
+  auto* fixture_2 = fixture_create();
+  alts_grpc_record_protocol_empty_seal_unseal_tests(fixture_2);
+  alts_grpc_record_protocol_test_fixture_destroy(fixture_2);
+
+  auto* fixture_3 = fixture_create();
+  alts_grpc_record_protocol_unsync_seal_unseal_tests(fixture_3);
+  alts_grpc_record_protocol_test_fixture_destroy(fixture_3);
+
+  auto* fixture_4 = fixture_create();
+  alts_grpc_record_protocol_corrupted_data_tests(fixture_4);
+  alts_grpc_record_protocol_test_fixture_destroy(fixture_4);
+
+  auto* fixture_5 = fixture_create();
+  alts_grpc_record_protocol_input_check_tests(fixture_5);
+  alts_grpc_record_protocol_test_fixture_destroy(fixture_5);
+}
+
+int main(int argc, char** argv) {
+  alts_grpc_record_protocol_tests(&test_fixture_integrity_only_no_rekey_create);
+  alts_grpc_record_protocol_tests(&test_fixture_integrity_only_rekey_create);
+  alts_grpc_record_protocol_tests(
+      &test_fixture_privacy_integrity_no_rekey_create);
+  alts_grpc_record_protocol_tests(&test_fixture_privacy_integrity_rekey_create);
+
+  return 0;
+}
diff --git a/test/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol_test.cc b/test/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol_test.cc
new file mode 100644
index 0000000..db1934b
--- /dev/null
+++ b/test/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol_test.cc
@@ -0,0 +1,928 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h"
+#include "test/core/tsi/alts/crypt/gsec_test_util.h"
+
+constexpr size_t kMaxDataSize = 1024;
+constexpr size_t kMaxSlices = 10;
+constexpr size_t kSealRepeatTimes = 5;
+constexpr size_t kTagLength = 16;
+
+/* Test fixtures for each test cases.  */
+struct alts_iovec_record_protocol_test_fixture {
+  alts_iovec_record_protocol* client_protect;
+  alts_iovec_record_protocol* client_unprotect;
+  alts_iovec_record_protocol* server_protect;
+  alts_iovec_record_protocol* server_unprotect;
+};
+
+/* Test variables for protect/unprotect operations.  */
+struct alts_iovec_record_protocol_test_var {
+  uint8_t* header_buf;
+  size_t header_length;
+  iovec_t header_iovec;
+  uint8_t* tag_buf;
+  size_t tag_length;
+  iovec_t tag_iovec;
+  uint8_t* data_buf;
+  uint8_t* dup_buf;
+  size_t data_length;
+  iovec_t* data_iovec;
+  size_t data_iovec_length;
+  uint8_t* protected_buf;
+  iovec_t protected_iovec;
+  iovec_t unprotected_iovec;
+};
+
+/* --- Test utility functions. --- */
+
+static void randomly_slice(uint8_t* input, size_t input_length,
+                           iovec_t** output, size_t* output_length) {
+  if (input_length == 0) {
+    *output = nullptr;
+    *output_length = 0;
+    return;
+  }
+  *output_length = gsec_test_bias_random_uint32(kMaxSlices) + 1;
+  *output = static_cast<iovec_t*>(gpr_malloc(*output_length * sizeof(iovec_t)));
+  for (size_t i = 0; i < *output_length - 1; i++) {
+    size_t slice_length =
+        gsec_test_bias_random_uint32(static_cast<uint32_t>(input_length));
+    iovec_t slice = {input, slice_length};
+    (*output)[i] = slice;
+    input += slice_length;
+    input_length -= slice_length;
+  }
+  iovec_t slice = {input, input_length};
+  (*output)[*output_length - 1] = slice;
+}
+
+static size_t alter_random_byte(uint8_t* buf, size_t buf_length) {
+  GPR_ASSERT(buf != nullptr);
+  uint32_t offset =
+      gsec_test_bias_random_uint32(static_cast<uint32_t>(buf_length));
+  (*(buf + offset))++;
+  return offset;
+}
+
+static void revert_back_alter(uint8_t* buf, size_t offset) {
+  GPR_ASSERT(buf != nullptr);
+  (*(buf + offset))--;
+}
+
+static alts_iovec_record_protocol_test_fixture*
+alts_iovec_record_protocol_test_fixture_create(bool rekey,
+                                               bool integrity_only) {
+  alts_iovec_record_protocol_test_fixture* fixture =
+      static_cast<alts_iovec_record_protocol_test_fixture*>(
+          gpr_malloc(sizeof(alts_iovec_record_protocol_test_fixture)));
+  size_t overflow_size = 8;
+  size_t key_length = rekey ? kAes128GcmRekeyKeyLength : kAes128GcmKeyLength;
+  uint8_t* key;
+  gsec_test_random_array(&key, key_length);
+  gsec_aead_crypter* crypter = nullptr;
+  /* Create client record protocol for protect.  */
+  GPR_ASSERT(gsec_aes_gcm_aead_crypter_create(
+                 key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
+                 &crypter, nullptr) == GRPC_STATUS_OK);
+  GPR_ASSERT(alts_iovec_record_protocol_create(
+                 crypter, overflow_size, /*is_client=*/true, integrity_only,
+                 /*is_protect=*/true, &fixture->client_protect,
+                 nullptr) == GRPC_STATUS_OK);
+  /* Create client record protocol for unprotect.  */
+  GPR_ASSERT(gsec_aes_gcm_aead_crypter_create(
+                 key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
+                 &crypter, nullptr) == GRPC_STATUS_OK);
+  GPR_ASSERT(alts_iovec_record_protocol_create(
+                 crypter, overflow_size, /*is_client=*/true, integrity_only,
+                 /*is_protect=*/false, &fixture->client_unprotect,
+                 nullptr) == GRPC_STATUS_OK);
+  /* Create server record protocol for protect.  */
+  GPR_ASSERT(gsec_aes_gcm_aead_crypter_create(
+                 key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
+                 &crypter, nullptr) == GRPC_STATUS_OK);
+  GPR_ASSERT(alts_iovec_record_protocol_create(
+                 crypter, overflow_size, /*is_client=*/false, integrity_only,
+                 /*is_protect=*/true, &fixture->server_protect,
+                 nullptr) == GRPC_STATUS_OK);
+  /* Create server record protocol for unprotect.  */
+  GPR_ASSERT(gsec_aes_gcm_aead_crypter_create(
+                 key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
+                 &crypter, nullptr) == GRPC_STATUS_OK);
+  GPR_ASSERT(alts_iovec_record_protocol_create(
+                 crypter, overflow_size, /*is_client=*/false, integrity_only,
+                 /*is_protect=*/false, &fixture->server_unprotect,
+                 nullptr) == GRPC_STATUS_OK);
+
+  gpr_free(key);
+  return fixture;
+}
+
+static void alts_iovec_record_protocol_test_fixture_destroy(
+    alts_iovec_record_protocol_test_fixture* fixture) {
+  if (fixture == nullptr) {
+    return;
+  }
+  alts_iovec_record_protocol_destroy(fixture->client_protect);
+  alts_iovec_record_protocol_destroy(fixture->client_unprotect);
+  alts_iovec_record_protocol_destroy(fixture->server_protect);
+  alts_iovec_record_protocol_destroy(fixture->server_unprotect);
+  gpr_free(fixture);
+}
+
+static alts_iovec_record_protocol_test_var*
+alts_iovec_record_protocol_test_var_create() {
+  auto* var = static_cast<alts_iovec_record_protocol_test_var*>(
+      gpr_zalloc(sizeof(alts_iovec_record_protocol_test_var)));
+  /* Sets header buffer.  */
+  var->header_length = alts_iovec_record_protocol_get_header_length();
+  var->header_buf = static_cast<uint8_t*>(gpr_malloc(var->header_length));
+  var->header_iovec.iov_base = var->header_buf;
+  var->header_iovec.iov_len = var->header_length;
+  /* Sets tag buffer.  */
+  var->tag_length = kTagLength;
+  var->tag_buf = static_cast<uint8_t*>(gpr_malloc(var->tag_length));
+  var->tag_iovec.iov_base = var->tag_buf;
+  var->tag_iovec.iov_len = var->tag_length;
+  /* Randomly sets data buffer and duplicates to dup_buf.  */
+  var->data_length = gsec_test_bias_random_uint32(kMaxDataSize) + 1;
+  var->data_buf = static_cast<uint8_t*>(gpr_malloc(var->data_length));
+  gsec_test_random_bytes(var->data_buf, var->data_length);
+  gsec_test_copy(var->data_buf, &var->dup_buf, var->data_length);
+  var->data_iovec = nullptr;
+  var->data_iovec_length = 0;
+  randomly_slice(var->data_buf, var->data_length, &var->data_iovec,
+                 &var->data_iovec_length);
+  /* Sets protected iovec.  */
+  size_t protected_buf_length =
+      var->header_length + var->data_length + var->tag_length;
+  var->protected_buf = static_cast<uint8_t*>(gpr_malloc(protected_buf_length));
+  var->protected_iovec.iov_base = var->protected_buf;
+  var->protected_iovec.iov_len = protected_buf_length;
+  /* Unprotected iovec points to data_buf.  */
+  var->unprotected_iovec.iov_base = var->data_buf;
+  var->unprotected_iovec.iov_len = var->data_length;
+  return var;
+}
+
+static void alts_iovec_record_protocol_test_var_destroy(
+    alts_iovec_record_protocol_test_var* var) {
+  if (var == nullptr) {
+    return;
+  }
+  gpr_free(var->header_buf);
+  gpr_free(var->tag_buf);
+  gpr_free(var->data_buf);
+  gpr_free(var->dup_buf);
+  gpr_free(var->data_iovec);
+  gpr_free(var->protected_buf);
+  gpr_free(var);
+}
+
+/* --- Integrity-only protect/unprotect tests. --- */
+
+static void integrity_only_random_seal_unseal(
+    alts_iovec_record_protocol* sender, alts_iovec_record_protocol* receiver) {
+  for (size_t i = 0; i < kSealRepeatTimes; i++) {
+    alts_iovec_record_protocol_test_var* var =
+        alts_iovec_record_protocol_test_var_create();
+    /* Seals and then unseals.  */
+    grpc_status_code status = alts_iovec_record_protocol_integrity_only_protect(
+        sender, var->data_iovec, var->data_iovec_length, var->header_iovec,
+        var->tag_iovec, nullptr);
+    GPR_ASSERT(status == GRPC_STATUS_OK);
+    gpr_free(var->data_iovec);
+    /* Randomly slices data buffer again.  */
+    randomly_slice(var->data_buf, var->data_length, &var->data_iovec,
+                   &var->data_iovec_length);
+    status = alts_iovec_record_protocol_integrity_only_unprotect(
+        receiver, var->data_iovec, var->data_iovec_length, var->header_iovec,
+        var->tag_iovec, nullptr);
+    GPR_ASSERT(status == GRPC_STATUS_OK);
+    /* Makes sure data buffer has not been modified during
+     * seal/unseal.  */
+    GPR_ASSERT(memcmp(var->data_buf, var->dup_buf, var->data_length) == 0);
+    alts_iovec_record_protocol_test_var_destroy(var);
+  }
+}
+
+static void integrity_only_empty_seal_unseal(
+    alts_iovec_record_protocol* sender, alts_iovec_record_protocol* receiver) {
+  for (size_t i = 0; i < kSealRepeatTimes; i++) {
+    alts_iovec_record_protocol_test_var* var =
+        alts_iovec_record_protocol_test_var_create();
+    /* Seals and then unseals empty payload.  */
+    grpc_status_code status = alts_iovec_record_protocol_integrity_only_protect(
+        sender, nullptr, 0, var->header_iovec, var->tag_iovec, nullptr);
+    GPR_ASSERT(status == GRPC_STATUS_OK);
+    status = alts_iovec_record_protocol_integrity_only_unprotect(
+        receiver, nullptr, 0, var->header_iovec, var->tag_iovec, nullptr);
+    GPR_ASSERT(status == GRPC_STATUS_OK);
+    alts_iovec_record_protocol_test_var_destroy(var);
+  }
+}
+
+static void integrity_only_unsync_seal_unseal(
+    alts_iovec_record_protocol* sender, alts_iovec_record_protocol* receiver) {
+  /* Seals once.  */
+  alts_iovec_record_protocol_test_var* var =
+      alts_iovec_record_protocol_test_var_create();
+  grpc_status_code status = alts_iovec_record_protocol_integrity_only_protect(
+      sender, var->data_iovec, var->data_iovec_length, var->header_iovec,
+      var->tag_iovec, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  alts_iovec_record_protocol_test_var_destroy(var);
+  /* Seals again.  */
+  var = alts_iovec_record_protocol_test_var_create();
+  status = alts_iovec_record_protocol_integrity_only_protect(
+      sender, var->data_iovec, var->data_iovec_length, var->header_iovec,
+      var->tag_iovec, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  /* Unseals the second frame.  */
+  char* error_message = nullptr;
+  status = alts_iovec_record_protocol_integrity_only_unprotect(
+      receiver, var->data_iovec, var->data_iovec_length, var->header_iovec,
+      var->tag_iovec, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INTERNAL, error_message,
+      "Frame tag verification failed."));
+  gpr_free(error_message);
+  alts_iovec_record_protocol_test_var_destroy(var);
+}
+
+static void integrity_only_corrupted_data(
+    alts_iovec_record_protocol* sender, alts_iovec_record_protocol* receiver) {
+  /* Seals the data first.  */
+  alts_iovec_record_protocol_test_var* var =
+      alts_iovec_record_protocol_test_var_create();
+  grpc_status_code status = alts_iovec_record_protocol_integrity_only_protect(
+      sender, var->data_iovec, var->data_iovec_length, var->header_iovec,
+      var->tag_iovec, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  /* Alter frame length field.  */
+  char* error_message = nullptr;
+  size_t offset =
+      alter_random_byte(var->header_buf, kZeroCopyFrameLengthFieldSize);
+  status = alts_iovec_record_protocol_integrity_only_unprotect(
+      receiver, var->data_iovec, var->data_iovec_length, var->header_iovec,
+      var->tag_iovec, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INTERNAL, error_message, "Bad frame length."));
+  gpr_free(error_message);
+  revert_back_alter(var->header_buf, offset);
+  /* Alter message type field.  */
+  offset = alter_random_byte(var->header_buf + kZeroCopyFrameLengthFieldSize,
+                             kZeroCopyFrameMessageTypeFieldSize);
+  status = alts_iovec_record_protocol_integrity_only_unprotect(
+      receiver, var->data_iovec, var->data_iovec_length, var->header_iovec,
+      var->tag_iovec, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INTERNAL, error_message,
+      "Unsupported message type."));
+  gpr_free(error_message);
+  revert_back_alter(var->header_buf + kZeroCopyFrameLengthFieldSize, offset);
+  /* Alter data.  */
+  offset = alter_random_byte(var->data_buf, var->data_length);
+  status = alts_iovec_record_protocol_integrity_only_unprotect(
+      receiver, var->data_iovec, var->data_iovec_length, var->header_iovec,
+      var->tag_iovec, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INTERNAL, error_message,
+      "Frame tag verification failed."));
+  gpr_free(error_message);
+  revert_back_alter(var->data_buf, offset);
+  /* Alter tag.  */
+  offset = alter_random_byte(var->tag_buf, var->tag_length);
+  status = alts_iovec_record_protocol_integrity_only_unprotect(
+      receiver, var->data_iovec, var->data_iovec_length, var->header_iovec,
+      var->tag_iovec, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INTERNAL, error_message,
+      "Frame tag verification failed."));
+  gpr_free(error_message);
+  revert_back_alter(var->tag_buf, offset);
+  /* Reverted protected data should be verified correctly.  */
+  status = alts_iovec_record_protocol_integrity_only_unprotect(
+      receiver, var->data_iovec, var->data_iovec_length, var->header_iovec,
+      var->tag_iovec, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(memcmp(var->data_buf, var->dup_buf, var->data_length) == 0);
+  alts_iovec_record_protocol_test_var_destroy(var);
+}
+
+static void integrity_only_protect_input_check(alts_iovec_record_protocol* rp) {
+  alts_iovec_record_protocol_test_var* var =
+      alts_iovec_record_protocol_test_var_create();
+  char* error_message = nullptr;
+  /* Header buffer is nullptr.  */
+  iovec_t header_iovec = {nullptr, var->header_length};
+  grpc_status_code status = alts_iovec_record_protocol_integrity_only_protect(
+      rp, var->data_iovec, var->data_iovec_length, header_iovec, var->tag_iovec,
+      &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "Header is nullptr."));
+  gpr_free(error_message);
+  /* Header buffer length is 0.  */
+  header_iovec.iov_base = var->header_buf;
+  header_iovec.iov_len = 0;
+  status = alts_iovec_record_protocol_integrity_only_protect(
+      rp, var->data_iovec, var->data_iovec_length, header_iovec, var->tag_iovec,
+      &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "Header length is incorrect."));
+  gpr_free(error_message);
+  /* Tag buffer is nullptr.  */
+  iovec_t tag_iovec = {nullptr, var->tag_length};
+  status = alts_iovec_record_protocol_integrity_only_protect(
+      rp, var->data_iovec, var->data_iovec_length, var->header_iovec, tag_iovec,
+      &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message, "Tag is nullptr."));
+  gpr_free(error_message);
+  /* Tag buffer length is 0.  */
+  tag_iovec.iov_base = var->tag_buf;
+  tag_iovec.iov_len = 0;
+  status = alts_iovec_record_protocol_integrity_only_protect(
+      rp, var->data_iovec, var->data_iovec_length, var->header_iovec, tag_iovec,
+      &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "Tag length is incorrect."));
+  gpr_free(error_message);
+  alts_iovec_record_protocol_test_var_destroy(var);
+}
+
+static void integrity_only_unprotect_input_check(
+    alts_iovec_record_protocol* rp) {
+  alts_iovec_record_protocol_test_var* var =
+      alts_iovec_record_protocol_test_var_create();
+  char* error_message = nullptr;
+  /* Header buffer is nullptr.  */
+  iovec_t header_iovec = {nullptr, var->header_length};
+  grpc_status_code status = alts_iovec_record_protocol_integrity_only_unprotect(
+      rp, var->data_iovec, var->data_iovec_length, header_iovec, var->tag_iovec,
+      &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "Header is nullptr."));
+  gpr_free(error_message);
+  /* Header buffer length is 0.  */
+  header_iovec.iov_base = var->header_buf;
+  header_iovec.iov_len = 0;
+  status = alts_iovec_record_protocol_integrity_only_unprotect(
+      rp, var->data_iovec, var->data_iovec_length, header_iovec, var->tag_iovec,
+      &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "Header length is incorrect."));
+  gpr_free(error_message);
+  /* Tag buffer is nullptr.  */
+  iovec_t tag_iovec = {nullptr, var->tag_length};
+  status = alts_iovec_record_protocol_integrity_only_unprotect(
+      rp, var->data_iovec, var->data_iovec_length, var->header_iovec, tag_iovec,
+      &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message, "Tag is nullptr."));
+  gpr_free(error_message);
+  /* Tag buffer length is 0.  */
+  tag_iovec.iov_base = var->tag_buf;
+  tag_iovec.iov_len = 0;
+  status = alts_iovec_record_protocol_integrity_only_unprotect(
+      rp, var->data_iovec, var->data_iovec_length, var->header_iovec, tag_iovec,
+      &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "Tag length is incorrect."));
+  gpr_free(error_message);
+  alts_iovec_record_protocol_test_var_destroy(var);
+}
+
+/* --- Privacy-integrity protect/unprotect tests. --- */
+
+static void privacy_integrity_random_seal_unseal(
+    alts_iovec_record_protocol* sender, alts_iovec_record_protocol* receiver) {
+  for (size_t i = 0; i < kSealRepeatTimes; i++) {
+    alts_iovec_record_protocol_test_var* var =
+        alts_iovec_record_protocol_test_var_create();
+    /* Seals and then unseals.  */
+    grpc_status_code status =
+        alts_iovec_record_protocol_privacy_integrity_protect(
+            sender, var->data_iovec, var->data_iovec_length,
+            var->protected_iovec, nullptr);
+    GPR_ASSERT(status == GRPC_STATUS_OK);
+    iovec_t header_iovec = {var->protected_buf, var->header_length};
+    gpr_free(var->data_iovec);
+    /* Randomly slices protected buffer, excluding the header.  */
+    randomly_slice(var->protected_buf + var->header_length,
+                   var->data_length + var->tag_length, &var->data_iovec,
+                   &var->data_iovec_length);
+    status = alts_iovec_record_protocol_privacy_integrity_unprotect(
+        receiver, header_iovec, var->data_iovec, var->data_iovec_length,
+        var->unprotected_iovec, nullptr);
+    GPR_ASSERT(status == GRPC_STATUS_OK);
+    /* Makes sure unprotected data are the same as the original.  */
+    GPR_ASSERT(memcmp(var->data_buf, var->dup_buf, var->data_length) == 0);
+    alts_iovec_record_protocol_test_var_destroy(var);
+  }
+}
+
+static void privacy_integrity_empty_seal_unseal(
+    alts_iovec_record_protocol* sender, alts_iovec_record_protocol* receiver) {
+  alts_iovec_record_protocol_test_var* var =
+      alts_iovec_record_protocol_test_var_create();
+  size_t empty_payload_frame_size = var->header_length + var->tag_length;
+  auto* protected_buf =
+      static_cast<uint8_t*>(gpr_malloc(empty_payload_frame_size));
+  for (size_t i = 0; i < kSealRepeatTimes; i++) {
+    iovec_t protected_iovec = {protected_buf, empty_payload_frame_size};
+    iovec_t unprotected_iovec = {nullptr, 0};
+    iovec_t data_iovec = {protected_buf + var->header_length, var->tag_length};
+    /* Seals and then unseals empty payload.  */
+    grpc_status_code status =
+        alts_iovec_record_protocol_privacy_integrity_protect(
+            sender, nullptr, 0, protected_iovec, nullptr);
+    GPR_ASSERT(status == GRPC_STATUS_OK);
+    iovec_t header_iovec = {protected_buf, var->header_length};
+    status = alts_iovec_record_protocol_privacy_integrity_unprotect(
+        receiver, header_iovec, &data_iovec, 1, unprotected_iovec, nullptr);
+    GPR_ASSERT(status == GRPC_STATUS_OK);
+  }
+  gpr_free(protected_buf);
+  alts_iovec_record_protocol_test_var_destroy(var);
+}
+
+static void privacy_integrity_unsync_seal_unseal(
+    alts_iovec_record_protocol* sender, alts_iovec_record_protocol* receiver) {
+  /* Seals once.  */
+  alts_iovec_record_protocol_test_var* var =
+      alts_iovec_record_protocol_test_var_create();
+  grpc_status_code status =
+      alts_iovec_record_protocol_privacy_integrity_protect(
+          sender, var->data_iovec, var->data_iovec_length, var->protected_iovec,
+          nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  alts_iovec_record_protocol_test_var_destroy(var);
+  /* Seals again.  */
+  var = alts_iovec_record_protocol_test_var_create();
+  status = alts_iovec_record_protocol_privacy_integrity_protect(
+      sender, var->data_iovec, var->data_iovec_length, var->protected_iovec,
+      nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  /* Unseals the second frame.  */
+  char* error_message = nullptr;
+  iovec_t header_iovec = {var->protected_buf, var->header_length};
+  iovec_t protected_iovec = {var->protected_buf + var->header_length,
+                             var->data_length + var->tag_length};
+  status = alts_iovec_record_protocol_privacy_integrity_unprotect(
+      receiver, header_iovec, &protected_iovec, 1, var->unprotected_iovec,
+      &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INTERNAL, error_message, "Frame decryption failed."));
+  gpr_free(error_message);
+  alts_iovec_record_protocol_test_var_destroy(var);
+}
+
+static void privacy_integrity_corrupted_data(
+    alts_iovec_record_protocol* sender, alts_iovec_record_protocol* receiver) {
+  /* Seals the data first.  */
+  alts_iovec_record_protocol_test_var* var =
+      alts_iovec_record_protocol_test_var_create();
+  grpc_status_code status =
+      alts_iovec_record_protocol_privacy_integrity_protect(
+          sender, var->data_iovec, var->data_iovec_length, var->protected_iovec,
+          nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  char* error_message = nullptr;
+  uint8_t* header_buf = var->protected_buf;
+  size_t header_length = var->header_length;
+  iovec_t header_iovec = {header_buf, header_length};
+  /* The following protected_buf and protected_length excludes header.  */
+  uint8_t* protected_buf = var->protected_buf + var->header_length;
+  size_t protected_length = var->data_length + var->tag_length;
+  iovec_t protected_iovec = {protected_buf, protected_length};
+  /* Alter frame length field.  */
+  size_t offset = alter_random_byte(header_buf, kZeroCopyFrameLengthFieldSize);
+  status = alts_iovec_record_protocol_privacy_integrity_unprotect(
+      receiver, header_iovec, &protected_iovec, 1, var->unprotected_iovec,
+      &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INTERNAL, error_message, "Bad frame length."));
+  gpr_free(error_message);
+  revert_back_alter(header_buf, offset);
+  /* Alter message type field.  */
+  offset = alter_random_byte(header_buf + kZeroCopyFrameLengthFieldSize,
+                             kZeroCopyFrameMessageTypeFieldSize);
+  status = alts_iovec_record_protocol_privacy_integrity_unprotect(
+      receiver, header_iovec, &protected_iovec, 1, var->unprotected_iovec,
+      &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INTERNAL, error_message,
+      "Unsupported message type."));
+  gpr_free(error_message);
+  revert_back_alter(header_buf + kZeroCopyFrameLengthFieldSize, offset);
+  /* Alter protected data.  */
+  offset = alter_random_byte(protected_buf, protected_length);
+  status = alts_iovec_record_protocol_privacy_integrity_unprotect(
+      receiver, header_iovec, &protected_iovec, 1, var->unprotected_iovec,
+      &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INTERNAL, error_message, "Frame decryption failed."));
+  gpr_free(error_message);
+  revert_back_alter(protected_buf, offset);
+  /* Reverted protected data should be verified correctly.  */
+  status = alts_iovec_record_protocol_privacy_integrity_unprotect(
+      receiver, header_iovec, &protected_iovec, 1, var->unprotected_iovec,
+      nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(memcmp(var->data_buf, var->dup_buf, var->data_length) == 0);
+  alts_iovec_record_protocol_test_var_destroy(var);
+}
+
+static void privacy_integrity_protect_input_check(
+    alts_iovec_record_protocol* rp) {
+  alts_iovec_record_protocol_test_var* var =
+      alts_iovec_record_protocol_test_var_create();
+  char* error_message = nullptr;
+  /* Protected output buffer is nullptr.  */
+  iovec_t protected_iovec = {nullptr, var->protected_iovec.iov_len};
+  grpc_status_code status =
+      alts_iovec_record_protocol_privacy_integrity_protect(
+          rp, var->data_iovec, var->data_iovec_length, protected_iovec,
+          &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "Protected frame is nullptr."));
+  gpr_free(error_message);
+  /* Protected output buffer length incorrect.  */
+  protected_iovec.iov_base = var->protected_buf;
+  protected_iovec.iov_len = var->header_length + var->data_length;
+  status = alts_iovec_record_protocol_privacy_integrity_protect(
+      rp, var->data_iovec, var->data_iovec_length, protected_iovec,
+      &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "Protected frame size is incorrect."));
+  gpr_free(error_message);
+  alts_iovec_record_protocol_test_var_destroy(var);
+}
+
+static void privacy_integrity_unprotect_input_check(
+    alts_iovec_record_protocol* rp) {
+  alts_iovec_record_protocol_test_var* var =
+      alts_iovec_record_protocol_test_var_create();
+  char* error_message = nullptr;
+  /* Header buffer is nullptr.  */
+  iovec_t header_iovec = {var->protected_buf, var->header_length};
+  iovec_t protected_iovec = {var->protected_buf + var->header_length,
+                             var->data_length + var->tag_length};
+  header_iovec.iov_base = nullptr;
+  grpc_status_code status =
+      alts_iovec_record_protocol_privacy_integrity_unprotect(
+          rp, header_iovec, &protected_iovec, 1, var->unprotected_iovec,
+          &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "Header is nullptr."));
+  gpr_free(error_message);
+  header_iovec.iov_base = var->protected_buf;
+  /* Header buffer length is 0.  */
+  header_iovec.iov_len = 0;
+  status = alts_iovec_record_protocol_privacy_integrity_unprotect(
+      rp, header_iovec, &protected_iovec, 1, var->unprotected_iovec,
+      &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "Header length is incorrect."));
+  gpr_free(error_message);
+  header_iovec.iov_len = var->header_length;
+  /* Unprotected output buffer length is incorrect.  */
+  iovec_t unprotected_iovec = {var->data_buf, var->data_length - 1};
+  status = alts_iovec_record_protocol_privacy_integrity_unprotect(
+      rp, header_iovec, &protected_iovec, 1, unprotected_iovec, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INVALID_ARGUMENT, error_message,
+      "Unprotected data size is incorrect."));
+  gpr_free(error_message);
+  alts_iovec_record_protocol_test_var_destroy(var);
+}
+
+/* --- Integrity-only and privacy-integrity mixed. --- */
+
+static void record_protocol_wrong_mode(
+    alts_iovec_record_protocol* integrity_only_protect_rp,
+    alts_iovec_record_protocol* integrity_only_unprotect_rp,
+    alts_iovec_record_protocol* privacy_integrity_protect_rp,
+    alts_iovec_record_protocol* privacy_integrity_unprotect_rp) {
+  alts_iovec_record_protocol_test_var* var =
+      alts_iovec_record_protocol_test_var_create();
+  grpc_status_code status;
+  char* error_message = nullptr;
+  /* Call integrity-only protect on privacy-integrity record protocol.  */
+  status = alts_iovec_record_protocol_integrity_only_protect(
+      privacy_integrity_protect_rp, var->data_iovec, var->data_iovec_length,
+      var->header_iovec, var->tag_iovec, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_FAILED_PRECONDITION, error_message,
+      "Integrity-only operations are not allowed for this object."));
+  gpr_free(error_message);
+  /* Call integrity-only unprotect on privacy-integrity record protocol.  */
+  status = alts_iovec_record_protocol_integrity_only_unprotect(
+      privacy_integrity_unprotect_rp, var->data_iovec, var->data_iovec_length,
+      var->header_iovec, var->tag_iovec, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_FAILED_PRECONDITION, error_message,
+      "Integrity-only operations are not allowed for this object."));
+  gpr_free(error_message);
+  /* Call privacy-integrity protect on integrity-only record protocol.  */
+  status = alts_iovec_record_protocol_privacy_integrity_protect(
+      integrity_only_protect_rp, var->data_iovec, var->data_iovec_length,
+      var->protected_iovec, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_FAILED_PRECONDITION, error_message,
+      "Privacy-integrity operations are not allowed for this object."));
+  gpr_free(error_message);
+  /* Call privacy-integrity unprotect on integrity-only record protocol.  */
+  status = alts_iovec_record_protocol_privacy_integrity_unprotect(
+      integrity_only_unprotect_rp, var->header_iovec, var->data_iovec,
+      var->data_iovec_length, var->unprotected_iovec, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_FAILED_PRECONDITION, error_message,
+      "Privacy-integrity operations are not allowed for this object."));
+  gpr_free(error_message);
+  alts_iovec_record_protocol_test_var_destroy(var);
+}
+
+static void integrity_seal_privacy_unseal(
+    alts_iovec_record_protocol* integrity_only_sender,
+    alts_iovec_record_protocol* privacy_integrity_receiver) {
+  alts_iovec_record_protocol_test_var* var =
+      alts_iovec_record_protocol_test_var_create();
+  grpc_status_code status;
+  char* error_message = nullptr;
+  /* Seals with integrity-only protect.  */
+  status = alts_iovec_record_protocol_integrity_only_protect(
+      integrity_only_sender, var->data_iovec, var->data_iovec_length,
+      var->header_iovec, var->tag_iovec, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  /* Unseal with privacy-integrity unprotect.  */
+  memcpy(var->protected_buf, var->data_buf, var->data_length);
+  memcpy(var->protected_buf + var->data_length, var->tag_buf, var->tag_length);
+  iovec_t protected_iovec = {var->protected_buf,
+                             var->data_length + var->tag_length};
+  status = alts_iovec_record_protocol_privacy_integrity_unprotect(
+      privacy_integrity_receiver, var->header_iovec, &protected_iovec, 1,
+      var->unprotected_iovec, &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INTERNAL, error_message, "Frame decryption failed."));
+  gpr_free(error_message);
+  alts_iovec_record_protocol_test_var_destroy(var);
+}
+
+static void privacy_seal_integrity_unseal(
+    alts_iovec_record_protocol* privacy_integrity_sender,
+    alts_iovec_record_protocol* integrity_only_receiver) {
+  alts_iovec_record_protocol_test_var* var =
+      alts_iovec_record_protocol_test_var_create();
+  grpc_status_code status;
+  char* error_message = nullptr;
+  /* Seals with privacy-integrity protect.  */
+  status = alts_iovec_record_protocol_privacy_integrity_protect(
+      privacy_integrity_sender, var->data_iovec, var->data_iovec_length,
+      var->protected_iovec, nullptr);
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  /* Unseal with integrity-only unprotect.  */
+  iovec_t header_iovec = {var->protected_buf, var->header_length};
+  iovec_t data_iovec = {var->protected_buf + var->header_length,
+                        var->data_length};
+  iovec_t tag_iovec = {
+      var->protected_buf + var->header_length + var->data_length,
+      var->tag_length};
+  status = alts_iovec_record_protocol_integrity_only_unprotect(
+      integrity_only_receiver, &data_iovec, 1, header_iovec, tag_iovec,
+      &error_message);
+  GPR_ASSERT(gsec_test_expect_compare_code_and_substr(
+      status, GRPC_STATUS_INTERNAL, error_message,
+      "Frame tag verification failed."));
+  gpr_free(error_message);
+  alts_iovec_record_protocol_test_var_destroy(var);
+}
+
+/* --- Test cases. --- */
+
+static void alts_iovec_record_protocol_random_seal_unseal_tests() {
+  alts_iovec_record_protocol_test_fixture* fixture =
+      alts_iovec_record_protocol_test_fixture_create(
+          /*rekey=*/false, /*integrity_only=*/true);
+  integrity_only_random_seal_unseal(fixture->client_protect,
+                                    fixture->server_unprotect);
+  integrity_only_random_seal_unseal(fixture->server_protect,
+                                    fixture->client_unprotect);
+  alts_iovec_record_protocol_test_fixture_destroy(fixture);
+
+  fixture = alts_iovec_record_protocol_test_fixture_create(
+      /*rekey=*/true, /*integrity_only=*/true);
+  integrity_only_random_seal_unseal(fixture->client_protect,
+                                    fixture->server_unprotect);
+  integrity_only_random_seal_unseal(fixture->server_protect,
+                                    fixture->client_unprotect);
+  alts_iovec_record_protocol_test_fixture_destroy(fixture);
+
+  fixture = alts_iovec_record_protocol_test_fixture_create(
+      /*rekey=*/false, /*integrity_only=*/false);
+  privacy_integrity_random_seal_unseal(fixture->client_protect,
+                                       fixture->server_unprotect);
+  privacy_integrity_random_seal_unseal(fixture->server_protect,
+                                       fixture->client_unprotect);
+  alts_iovec_record_protocol_test_fixture_destroy(fixture);
+
+  fixture = alts_iovec_record_protocol_test_fixture_create(
+      /*rekey=*/true, /*integrity_only=*/false);
+  privacy_integrity_random_seal_unseal(fixture->client_protect,
+                                       fixture->server_unprotect);
+  privacy_integrity_random_seal_unseal(fixture->server_protect,
+                                       fixture->client_unprotect);
+  alts_iovec_record_protocol_test_fixture_destroy(fixture);
+}
+
+static void alts_iovec_record_protocol_empty_seal_unseal_tests() {
+  alts_iovec_record_protocol_test_fixture* fixture =
+      alts_iovec_record_protocol_test_fixture_create(
+          /*rekey=*/false, /*integrity_only=*/true);
+  integrity_only_empty_seal_unseal(fixture->client_protect,
+                                   fixture->server_unprotect);
+  integrity_only_empty_seal_unseal(fixture->server_protect,
+                                   fixture->client_unprotect);
+  alts_iovec_record_protocol_test_fixture_destroy(fixture);
+
+  fixture = alts_iovec_record_protocol_test_fixture_create(
+      /*rekey=*/true, /*integrity_only=*/true);
+  integrity_only_empty_seal_unseal(fixture->client_protect,
+                                   fixture->server_unprotect);
+  integrity_only_empty_seal_unseal(fixture->server_protect,
+                                   fixture->client_unprotect);
+  alts_iovec_record_protocol_test_fixture_destroy(fixture);
+
+  fixture = alts_iovec_record_protocol_test_fixture_create(
+      /*rekey=*/false, /*integrity_only=*/false);
+  privacy_integrity_empty_seal_unseal(fixture->client_protect,
+                                      fixture->server_unprotect);
+  privacy_integrity_empty_seal_unseal(fixture->server_protect,
+                                      fixture->client_unprotect);
+  alts_iovec_record_protocol_test_fixture_destroy(fixture);
+
+  fixture = alts_iovec_record_protocol_test_fixture_create(
+      /*rekey=*/true, /*integrity_only=*/false);
+  privacy_integrity_empty_seal_unseal(fixture->client_protect,
+                                      fixture->server_unprotect);
+  privacy_integrity_empty_seal_unseal(fixture->server_protect,
+                                      fixture->client_unprotect);
+  alts_iovec_record_protocol_test_fixture_destroy(fixture);
+}
+
+static void alts_iovec_record_protocol_unsync_seal_unseal_tests() {
+  alts_iovec_record_protocol_test_fixture* fixture =
+      alts_iovec_record_protocol_test_fixture_create(
+          /*rekey=*/false, /*integrity_only=*/true);
+  integrity_only_unsync_seal_unseal(fixture->client_protect,
+                                    fixture->server_unprotect);
+  integrity_only_unsync_seal_unseal(fixture->server_protect,
+                                    fixture->client_unprotect);
+  alts_iovec_record_protocol_test_fixture_destroy(fixture);
+
+  fixture = alts_iovec_record_protocol_test_fixture_create(
+      /*rekey=*/true, /*integrity_only=*/true);
+  integrity_only_unsync_seal_unseal(fixture->client_protect,
+                                    fixture->server_unprotect);
+  integrity_only_unsync_seal_unseal(fixture->server_protect,
+                                    fixture->client_unprotect);
+  alts_iovec_record_protocol_test_fixture_destroy(fixture);
+
+  fixture = alts_iovec_record_protocol_test_fixture_create(
+      /*rekey=*/false, /*integrity_only=*/false);
+  privacy_integrity_unsync_seal_unseal(fixture->client_protect,
+                                       fixture->server_unprotect);
+  privacy_integrity_unsync_seal_unseal(fixture->server_protect,
+                                       fixture->client_unprotect);
+  alts_iovec_record_protocol_test_fixture_destroy(fixture);
+
+  fixture = alts_iovec_record_protocol_test_fixture_create(
+      /*rekey=*/true, /*integrity_only=*/false);
+  privacy_integrity_unsync_seal_unseal(fixture->client_protect,
+                                       fixture->server_unprotect);
+  privacy_integrity_unsync_seal_unseal(fixture->server_protect,
+                                       fixture->client_unprotect);
+  alts_iovec_record_protocol_test_fixture_destroy(fixture);
+}
+
+static void alts_iovec_record_protocol_corrupted_data_tests() {
+  alts_iovec_record_protocol_test_fixture* fixture =
+      alts_iovec_record_protocol_test_fixture_create(
+          /*rekey=*/false, /*integrity_only=*/true);
+  integrity_only_corrupted_data(fixture->client_protect,
+                                fixture->server_unprotect);
+  integrity_only_corrupted_data(fixture->server_protect,
+                                fixture->client_unprotect);
+  alts_iovec_record_protocol_test_fixture_destroy(fixture);
+
+  fixture = alts_iovec_record_protocol_test_fixture_create(
+      /*rekey=*/true, /*integrity_only=*/true);
+  integrity_only_corrupted_data(fixture->client_protect,
+                                fixture->server_unprotect);
+  integrity_only_corrupted_data(fixture->server_protect,
+                                fixture->client_unprotect);
+  alts_iovec_record_protocol_test_fixture_destroy(fixture);
+
+  fixture = alts_iovec_record_protocol_test_fixture_create(
+      /*rekey=*/false, /*integrity_only=*/false);
+  privacy_integrity_corrupted_data(fixture->client_protect,
+                                   fixture->server_unprotect);
+  privacy_integrity_corrupted_data(fixture->server_protect,
+                                   fixture->client_unprotect);
+  alts_iovec_record_protocol_test_fixture_destroy(fixture);
+
+  fixture = alts_iovec_record_protocol_test_fixture_create(
+      /*rekey=*/true, /*integrity_only=*/false);
+  privacy_integrity_corrupted_data(fixture->client_protect,
+                                   fixture->server_unprotect);
+  privacy_integrity_corrupted_data(fixture->server_protect,
+                                   fixture->client_unprotect);
+  alts_iovec_record_protocol_test_fixture_destroy(fixture);
+}
+
+static void alts_iovec_record_protocol_input_check_tests() {
+  alts_iovec_record_protocol_test_fixture* fixture =
+      alts_iovec_record_protocol_test_fixture_create(
+          /*rekey=*/false, /*integrity_only=*/true);
+  integrity_only_protect_input_check(fixture->client_protect);
+  integrity_only_unprotect_input_check(fixture->client_unprotect);
+  alts_iovec_record_protocol_test_fixture_destroy(fixture);
+
+  fixture = alts_iovec_record_protocol_test_fixture_create(
+      /*rekey=*/true, /*integrity_only=*/true);
+  integrity_only_protect_input_check(fixture->client_protect);
+  integrity_only_unprotect_input_check(fixture->client_unprotect);
+  alts_iovec_record_protocol_test_fixture_destroy(fixture);
+
+  fixture = alts_iovec_record_protocol_test_fixture_create(
+      /*rekey=*/false, /*integrity_only=*/false);
+  privacy_integrity_protect_input_check(fixture->client_protect);
+  privacy_integrity_unprotect_input_check(fixture->client_unprotect);
+  alts_iovec_record_protocol_test_fixture_destroy(fixture);
+
+  fixture = alts_iovec_record_protocol_test_fixture_create(
+      /*rekey=*/true, /*integrity_only=*/false);
+  privacy_integrity_protect_input_check(fixture->client_protect);
+  privacy_integrity_unprotect_input_check(fixture->client_unprotect);
+  alts_iovec_record_protocol_test_fixture_destroy(fixture);
+}
+
+static void alts_iovec_record_protocol_mix_operations_tests() {
+  alts_iovec_record_protocol_test_fixture* fixture_1 =
+      alts_iovec_record_protocol_test_fixture_create(
+          /*rekey=*/false, /*integrity_only=*/true);
+  alts_iovec_record_protocol_test_fixture* fixture_2 =
+      alts_iovec_record_protocol_test_fixture_create(
+          /*rekey=*/false, /*integrity_only=*/false);
+
+  record_protocol_wrong_mode(
+      fixture_1->client_protect, fixture_1->client_unprotect,
+      fixture_2->client_protect, fixture_2->client_unprotect);
+  integrity_seal_privacy_unseal(fixture_1->client_protect,
+                                fixture_2->server_unprotect);
+  privacy_seal_integrity_unseal(fixture_2->client_protect,
+                                fixture_1->server_unprotect);
+
+  alts_iovec_record_protocol_test_fixture_destroy(fixture_1);
+  alts_iovec_record_protocol_test_fixture_destroy(fixture_2);
+}
+
+int main(int argc, char** argv) {
+  alts_iovec_record_protocol_random_seal_unseal_tests();
+  alts_iovec_record_protocol_empty_seal_unseal_tests();
+  alts_iovec_record_protocol_unsync_seal_unseal_tests();
+  alts_iovec_record_protocol_corrupted_data_tests();
+  alts_iovec_record_protocol_input_check_tests();
+  alts_iovec_record_protocol_mix_operations_tests();
+  return 0;
+}
diff --git a/test/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector_test.cc b/test/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector_test.cc
new file mode 100644
index 0000000..32159e2
--- /dev/null
+++ b/test/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector_test.cc
@@ -0,0 +1,290 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/slice_buffer.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/tsi/alts/crypt/gsec.h"
+#include "src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h"
+#include "src/core/tsi/transport_security_grpc.h"
+#include "test/core/tsi/alts/crypt/gsec_test_util.h"
+
+/* TODO: tests zero_copy_grpc_protector under TSI test library, which
+ * has more comprehensive tests.  */
+
+constexpr size_t kSealRepeatTimes = 50;
+constexpr size_t kSmallBufferSize = 16;
+constexpr size_t kLargeBufferSize = 16384;
+constexpr size_t kChannelMaxSize = 2048;
+constexpr size_t kChannelMinSize = 128;
+
+/* Test fixtures for each test cases.  */
+struct alts_zero_copy_grpc_protector_test_fixture {
+  tsi_zero_copy_grpc_protector* client;
+  tsi_zero_copy_grpc_protector* server;
+};
+
+/* Test input variables for protect/unprotect operations.  */
+struct alts_zero_copy_grpc_protector_test_var {
+  grpc_slice_buffer original_sb;
+  grpc_slice_buffer duplicate_sb;
+  grpc_slice_buffer staging_sb;
+  grpc_slice_buffer protected_sb;
+  grpc_slice_buffer unprotected_sb;
+};
+
+/* --- Test utility functions. --- */
+
+static void create_random_slice_buffer(grpc_slice_buffer* sb,
+                                       grpc_slice_buffer* dup_sb,
+                                       size_t length) {
+  GPR_ASSERT(sb != nullptr);
+  GPR_ASSERT(dup_sb != nullptr);
+  GPR_ASSERT(length > 0);
+  grpc_slice slice = GRPC_SLICE_MALLOC(length);
+  gsec_test_random_bytes(GRPC_SLICE_START_PTR(slice), length);
+  grpc_slice_buffer_add(sb, grpc_slice_ref(slice));
+  grpc_slice_buffer_add(dup_sb, slice);
+}
+
+static uint8_t* pointer_to_nth_byte(grpc_slice_buffer* sb, size_t index) {
+  GPR_ASSERT(sb != nullptr);
+  GPR_ASSERT(index < sb->length);
+  for (size_t i = 0; i < sb->count; i++) {
+    if (index < GRPC_SLICE_LENGTH(sb->slices[i])) {
+      return GRPC_SLICE_START_PTR(sb->slices[i]) + index;
+    } else {
+      index -= GRPC_SLICE_LENGTH(sb->slices[i]);
+    }
+  }
+  return nullptr;
+}
+
+/* Checks if two slice buffer contents are the same. It is not super efficient,
+ * but OK for testing.  */
+static bool are_slice_buffers_equal(grpc_slice_buffer* first,
+                                    grpc_slice_buffer* second) {
+  GPR_ASSERT(first != nullptr);
+  GPR_ASSERT(second != nullptr);
+  if (first->length != second->length) {
+    return false;
+  }
+  for (size_t i = 0; i < first->length; i++) {
+    uint8_t* first_ptr = pointer_to_nth_byte(first, i);
+    uint8_t* second_ptr = pointer_to_nth_byte(second, i);
+    GPR_ASSERT(first_ptr != nullptr && second_ptr != nullptr);
+    if ((*first_ptr) != (*second_ptr)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+static alts_zero_copy_grpc_protector_test_fixture*
+alts_zero_copy_grpc_protector_test_fixture_create(bool rekey,
+                                                  bool integrity_only) {
+  alts_zero_copy_grpc_protector_test_fixture* fixture =
+      static_cast<alts_zero_copy_grpc_protector_test_fixture*>(
+          gpr_zalloc(sizeof(alts_zero_copy_grpc_protector_test_fixture)));
+  grpc_core::ExecCtx exec_ctx;
+  size_t key_length = rekey ? kAes128GcmRekeyKeyLength : kAes128GcmKeyLength;
+  uint8_t* key;
+  size_t max_protected_frame_size = 1024;
+  gsec_test_random_array(&key, key_length);
+  GPR_ASSERT(alts_zero_copy_grpc_protector_create(
+                 key, key_length, rekey, /*is_client=*/true, integrity_only,
+                 &max_protected_frame_size, &fixture->client) == TSI_OK);
+  GPR_ASSERT(alts_zero_copy_grpc_protector_create(
+                 key, key_length, rekey, /*is_client=*/false, integrity_only,
+                 &max_protected_frame_size, &fixture->server) == TSI_OK);
+  gpr_free(key);
+  grpc_core::ExecCtx::Get()->Flush();
+  return fixture;
+}
+
+static void alts_zero_copy_grpc_protector_test_fixture_destroy(
+    alts_zero_copy_grpc_protector_test_fixture* fixture) {
+  if (fixture == nullptr) {
+    return;
+  }
+  grpc_core::ExecCtx exec_ctx;
+  tsi_zero_copy_grpc_protector_destroy(fixture->client);
+  tsi_zero_copy_grpc_protector_destroy(fixture->server);
+  grpc_core::ExecCtx::Get()->Flush();
+  gpr_free(fixture);
+}
+
+static alts_zero_copy_grpc_protector_test_var*
+alts_zero_copy_grpc_protector_test_var_create() {
+  alts_zero_copy_grpc_protector_test_var* var =
+      static_cast<alts_zero_copy_grpc_protector_test_var*>(
+          gpr_zalloc(sizeof(alts_zero_copy_grpc_protector_test_var)));
+  grpc_slice_buffer_init(&var->original_sb);
+  grpc_slice_buffer_init(&var->duplicate_sb);
+  grpc_slice_buffer_init(&var->staging_sb);
+  grpc_slice_buffer_init(&var->protected_sb);
+  grpc_slice_buffer_init(&var->unprotected_sb);
+  return var;
+}
+
+static void alts_zero_copy_grpc_protector_test_var_destroy(
+    alts_zero_copy_grpc_protector_test_var* var) {
+  if (var == nullptr) {
+    return;
+  }
+  grpc_slice_buffer_destroy_internal(&var->original_sb);
+  grpc_slice_buffer_destroy_internal(&var->duplicate_sb);
+  grpc_slice_buffer_destroy_internal(&var->staging_sb);
+  grpc_slice_buffer_destroy_internal(&var->protected_sb);
+  grpc_slice_buffer_destroy_internal(&var->unprotected_sb);
+  gpr_free(var);
+}
+
+/* --- ALTS zero-copy protector tests. --- */
+
+static void seal_unseal_small_buffer(tsi_zero_copy_grpc_protector* sender,
+                                     tsi_zero_copy_grpc_protector* receiver) {
+  grpc_core::ExecCtx exec_ctx;
+  for (size_t i = 0; i < kSealRepeatTimes; i++) {
+    alts_zero_copy_grpc_protector_test_var* var =
+        alts_zero_copy_grpc_protector_test_var_create();
+    /* Creates a random small slice buffer and calls protect().  */
+    create_random_slice_buffer(&var->original_sb, &var->duplicate_sb,
+                               kSmallBufferSize);
+    GPR_ASSERT(tsi_zero_copy_grpc_protector_protect(
+                   sender, &var->original_sb, &var->protected_sb) == TSI_OK);
+    /* Splits protected slice buffer into two: first one is staging_sb, and
+     * second one is is protected_sb.  */
+    uint32_t staging_sb_size =
+        gsec_test_bias_random_uint32(
+            static_cast<uint32_t>(var->protected_sb.length - 1)) +
+        1;
+    grpc_slice_buffer_move_first(&var->protected_sb, staging_sb_size,
+                                 &var->staging_sb);
+    /* Unprotects one by one.  */
+    GPR_ASSERT(tsi_zero_copy_grpc_protector_unprotect(
+                   receiver, &var->staging_sb, &var->unprotected_sb) == TSI_OK);
+    GPR_ASSERT(var->unprotected_sb.length == 0);
+    GPR_ASSERT(tsi_zero_copy_grpc_protector_unprotect(
+                   receiver, &var->protected_sb, &var->unprotected_sb) ==
+               TSI_OK);
+    GPR_ASSERT(
+        are_slice_buffers_equal(&var->unprotected_sb, &var->duplicate_sb));
+    alts_zero_copy_grpc_protector_test_var_destroy(var);
+  }
+  grpc_core::ExecCtx::Get()->Flush();
+}
+
+static void seal_unseal_large_buffer(tsi_zero_copy_grpc_protector* sender,
+                                     tsi_zero_copy_grpc_protector* receiver) {
+  grpc_core::ExecCtx exec_ctx;
+  for (size_t i = 0; i < kSealRepeatTimes; i++) {
+    alts_zero_copy_grpc_protector_test_var* var =
+        alts_zero_copy_grpc_protector_test_var_create();
+    /* Creates a random large slice buffer and calls protect().  */
+    create_random_slice_buffer(&var->original_sb, &var->duplicate_sb,
+                               kLargeBufferSize);
+    GPR_ASSERT(tsi_zero_copy_grpc_protector_protect(
+                   sender, &var->original_sb, &var->protected_sb) == TSI_OK);
+    /* Splits protected slice buffer into multiple pieces. Receiver unprotects
+     * each slice buffer one by one.  */
+    uint32_t channel_size = gsec_test_bias_random_uint32(static_cast<uint32_t>(
+                                kChannelMaxSize + 1 - kChannelMinSize)) +
+                            static_cast<uint32_t>(kChannelMinSize);
+    while (var->protected_sb.length > channel_size) {
+      grpc_slice_buffer_reset_and_unref_internal(&var->staging_sb);
+      grpc_slice_buffer_move_first(&var->protected_sb, channel_size,
+                                   &var->staging_sb);
+      GPR_ASSERT(tsi_zero_copy_grpc_protector_unprotect(
+                     receiver, &var->staging_sb, &var->unprotected_sb) ==
+                 TSI_OK);
+    }
+    GPR_ASSERT(tsi_zero_copy_grpc_protector_unprotect(
+                   receiver, &var->protected_sb, &var->unprotected_sb) ==
+               TSI_OK);
+    GPR_ASSERT(
+        are_slice_buffers_equal(&var->unprotected_sb, &var->duplicate_sb));
+    alts_zero_copy_grpc_protector_test_var_destroy(var);
+  }
+  grpc_core::ExecCtx::Get()->Flush();
+}
+
+/* --- Test cases. --- */
+
+static void alts_zero_copy_protector_seal_unseal_small_buffer_tests() {
+  alts_zero_copy_grpc_protector_test_fixture* fixture =
+      alts_zero_copy_grpc_protector_test_fixture_create(
+          /*rekey=*/false, /*integrity_only=*/true);
+  seal_unseal_small_buffer(fixture->client, fixture->server);
+  seal_unseal_small_buffer(fixture->server, fixture->client);
+  alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
+
+  fixture = alts_zero_copy_grpc_protector_test_fixture_create(
+      /*rekey=*/false, /*integrity_only=*/false);
+  seal_unseal_small_buffer(fixture->client, fixture->server);
+  seal_unseal_small_buffer(fixture->server, fixture->client);
+  alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
+
+  fixture = alts_zero_copy_grpc_protector_test_fixture_create(
+      /*rekey=*/true, /*integrity_only=*/true);
+  seal_unseal_small_buffer(fixture->client, fixture->server);
+  seal_unseal_small_buffer(fixture->server, fixture->client);
+  alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
+
+  fixture = alts_zero_copy_grpc_protector_test_fixture_create(
+      /*rekey=*/true, /*integrity_only=*/false);
+  seal_unseal_small_buffer(fixture->client, fixture->server);
+  seal_unseal_small_buffer(fixture->server, fixture->client);
+  alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
+}
+
+static void alts_zero_copy_protector_seal_unseal_large_buffer_tests() {
+  alts_zero_copy_grpc_protector_test_fixture* fixture =
+      alts_zero_copy_grpc_protector_test_fixture_create(
+          /*rekey=*/false, /*integrity_only=*/true);
+  seal_unseal_large_buffer(fixture->client, fixture->server);
+  seal_unseal_large_buffer(fixture->server, fixture->client);
+  alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
+
+  fixture = alts_zero_copy_grpc_protector_test_fixture_create(
+      /*rekey=*/false, /*integrity_only=*/false);
+  seal_unseal_large_buffer(fixture->client, fixture->server);
+  seal_unseal_large_buffer(fixture->server, fixture->client);
+  alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
+
+  fixture = alts_zero_copy_grpc_protector_test_fixture_create(
+      /*rekey=*/true, /*integrity_only=*/true);
+  seal_unseal_large_buffer(fixture->client, fixture->server);
+  seal_unseal_large_buffer(fixture->server, fixture->client);
+  alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
+
+  fixture = alts_zero_copy_grpc_protector_test_fixture_create(
+      /*rekey=*/true, /*integrity_only=*/false);
+  seal_unseal_large_buffer(fixture->client, fixture->server);
+  seal_unseal_large_buffer(fixture->server, fixture->client);
+  alts_zero_copy_grpc_protector_test_fixture_destroy(fixture);
+}
+
+int main(int argc, char** argv) {
+  alts_zero_copy_protector_seal_unseal_small_buffer_tests();
+  alts_zero_copy_protector_seal_unseal_large_buffer_tests();
+  return 0;
+}
diff --git a/test/core/tsi/fake_transport_security_test.cc b/test/core/tsi/fake_transport_security_test.cc
index 73643fc..5e66719 100644
--- a/test/core/tsi/fake_transport_security_test.cc
+++ b/test/core/tsi/fake_transport_security_test.cc
@@ -20,7 +20,7 @@
 #include <stdio.h>
 #include <string.h>
 
-#include "src/core/lib/security/transport/security_connector.h"
+#include "src/core/lib/security/security_connector/security_connector.h"
 #include "src/core/tsi/fake_transport_security.h"
 #include "test/core/tsi/transport_security_test_lib.h"
 #include "test/core/util/test_config.h"
@@ -102,11 +102,12 @@
       v <<= 1;
     }
     tsi_test_fixture* fixture = fake_tsi_test_fixture_create();
-    fake_tsi_test_fixture* fake_fixture = (fake_tsi_test_fixture*)fixture;
+    fake_tsi_test_fixture* fake_fixture =
+        reinterpret_cast<fake_tsi_test_fixture*>(fixture);
     tsi_test_frame_protector_config_destroy(fake_fixture->base.config);
     fake_fixture->base.config = tsi_test_frame_protector_config_create(
         bit_array[0], bit_array[1], bit_array[2], bit_array[3], bit_array[4],
-        bit_array[5], bit_array[6], bit_array[7]);
+        bit_array[5], bit_array[6]);
     tsi_test_do_round_trip(&fake_fixture->base);
     tsi_test_fixture_destroy(fixture);
   }
@@ -123,7 +124,7 @@
           for (size_t ind5 = 0; ind5 < size; ind5++) {
             tsi_test_fixture* fixture = fake_tsi_test_fixture_create();
             fake_tsi_test_fixture* fake_fixture =
-                (fake_tsi_test_fixture*)fixture;
+                reinterpret_cast<fake_tsi_test_fixture*>(fixture);
             tsi_test_frame_protector_config_set_buffer_size(
                 fake_fixture->base.config, odd_sizes[ind1], odd_sizes[ind2],
                 odd_sizes[ind3], odd_sizes[ind4], odd_sizes[ind5]);
diff --git a/test/core/tsi/ssl_session_cache_test.cc b/test/core/tsi/ssl_session_cache_test.cc
new file mode 100644
index 0000000..72df0e5
--- /dev/null
+++ b/test/core/tsi/ssl_session_cache_test.cc
@@ -0,0 +1,154 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <unordered_set>
+
+#include "src/core/tsi/ssl/session_cache/ssl_session_cache.h"
+#include "test/core/util/test_config.h"
+
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include <gtest/gtest.h>
+
+namespace grpc_core {
+
+namespace {
+
+class SessionTracker;
+
+struct SessionExDataId {
+  SessionTracker* tracker;
+  long id;
+};
+
+class SessionTracker {
+ public:
+  SessionTracker() { ssl_context_ = SSL_CTX_new(TLSv1_2_method()); }
+
+  ~SessionTracker() { SSL_CTX_free(ssl_context_); }
+
+  tsi::SslSessionPtr NewSession(long id) {
+    static int ex_data_id = SSL_SESSION_get_ex_new_index(
+        0, nullptr, nullptr, nullptr, DestroyExData);
+    GPR_ASSERT(ex_data_id != -1);
+    // OpenSSL and different version of BoringSSL don't agree on API
+    // so try both.
+    tsi::SslSessionPtr session = NewSessionInternal(SSL_SESSION_new);
+    SessionExDataId* data = new SessionExDataId{this, id};
+    int result = SSL_SESSION_set_ex_data(session.get(), ex_data_id, data);
+    EXPECT_EQ(result, 1);
+    alive_sessions_.insert(id);
+    return session;
+  }
+
+  bool IsAlive(long id) const {
+    return alive_sessions_.find(id) != alive_sessions_.end();
+  }
+
+  size_t AliveCount() const { return alive_sessions_.size(); }
+
+ private:
+  tsi::SslSessionPtr NewSessionInternal(SSL_SESSION* (*cb)()) {
+    return tsi::SslSessionPtr(cb());
+  }
+
+  tsi::SslSessionPtr NewSessionInternal(SSL_SESSION* (*cb)(const SSL_CTX*)) {
+    return tsi::SslSessionPtr(cb(ssl_context_));
+  }
+
+  static void DestroyExData(void* parent, void* ptr, CRYPTO_EX_DATA* ad,
+                            int index, long argl, void* argp) {
+    SessionExDataId* data = static_cast<SessionExDataId*>(ptr);
+    data->tracker->alive_sessions_.erase(data->id);
+    delete data;
+  }
+
+  SSL_CTX* ssl_context_;
+  std::unordered_set<long> alive_sessions_;
+};
+
+TEST(SslSessionCacheTest, InitialState) {
+  SessionTracker tracker;
+  // Verify session initial state.
+  {
+    tsi::SslSessionPtr tmp_sess = tracker.NewSession(1);
+    EXPECT_EQ(tmp_sess->references, 1);
+    EXPECT_TRUE(tracker.IsAlive(1));
+    EXPECT_EQ(tracker.AliveCount(), 1);
+  }
+  EXPECT_FALSE(tracker.IsAlive(1));
+  EXPECT_EQ(tracker.AliveCount(), 0);
+}
+
+TEST(SslSessionCacheTest, LruCache) {
+  SessionTracker tracker;
+  {
+    RefCountedPtr<tsi::SslSessionLRUCache> cache =
+        tsi::SslSessionLRUCache::Create(3);
+    tsi::SslSessionPtr sess2 = tracker.NewSession(2);
+    SSL_SESSION* sess2_ptr = sess2.get();
+    cache->Put("first.dropbox.com", std::move(sess2));
+    EXPECT_EQ(cache->Get("first.dropbox.com").get(), sess2_ptr);
+    EXPECT_TRUE(tracker.IsAlive(2));
+    EXPECT_EQ(tracker.AliveCount(), 1);
+    // Putting element with the same key destroys old session.
+    tsi::SslSessionPtr sess3 = tracker.NewSession(3);
+    SSL_SESSION* sess3_ptr = sess3.get();
+    cache->Put("first.dropbox.com", std::move(sess3));
+    EXPECT_FALSE(tracker.IsAlive(2));
+    EXPECT_EQ(cache->Get("first.dropbox.com").get(), sess3_ptr);
+    EXPECT_TRUE(tracker.IsAlive(3));
+    EXPECT_EQ(tracker.AliveCount(), 1);
+    // Putting three more elements discards current one.
+    for (long id = 4; id < 7; id++) {
+      EXPECT_TRUE(tracker.IsAlive(3));
+      std::string domain = std::to_string(id) + ".random.domain";
+      cache->Put(domain.c_str(), tracker.NewSession(id));
+    }
+    EXPECT_EQ(cache->Size(), 3);
+    EXPECT_FALSE(tracker.IsAlive(3));
+    EXPECT_EQ(tracker.AliveCount(), 3);
+    // Accessing element moves it into front of the queue.
+    EXPECT_TRUE(cache->Get("4.random.domain"));
+    EXPECT_TRUE(tracker.IsAlive(4));
+    EXPECT_TRUE(tracker.IsAlive(5));
+    EXPECT_TRUE(tracker.IsAlive(6));
+    // One element has to be evicted from cache->
+    cache->Put("7.random.domain", tracker.NewSession(7));
+    EXPECT_TRUE(tracker.IsAlive(4));
+    EXPECT_FALSE(tracker.IsAlive(5));
+    EXPECT_TRUE(tracker.IsAlive(6));
+    EXPECT_TRUE(tracker.IsAlive(7));
+    EXPECT_EQ(tracker.AliveCount(), 3);
+  }
+  // Cache destructor destroys all sessions.
+  EXPECT_EQ(tracker.AliveCount(), 0);
+}
+
+}  // namespace
+}  // namespace grpc_core
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  grpc_test_init(argc, argv);
+  grpc_init();
+  int ret = RUN_ALL_TESTS();
+  grpc_shutdown();
+  return ret;
+}
diff --git a/test/core/tsi/ssl_transport_security_test.cc b/test/core/tsi/ssl_transport_security_test.cc
index bf54383..88f1abc 100644
--- a/test/core/tsi/ssl_transport_security_test.cc
+++ b/test/core/tsi/ssl_transport_security_test.cc
@@ -21,7 +21,7 @@
 #include <string.h>
 
 #include "src/core/lib/iomgr/load_file.h"
-#include "src/core/lib/security/transport/security_connector.h"
+#include "src/core/lib/security/security_connector/security_connector.h"
 #include "src/core/tsi/ssl_transport_security.h"
 #include "src/core/tsi/transport_security.h"
 #include "src/core/tsi/transport_security_adapter.h"
@@ -52,8 +52,8 @@
 
 typedef struct ssl_alpn_lib {
   AlpnMode alpn_mode;
-  char** server_alpn_protocols;
-  char** client_alpn_protocols;
+  const char** server_alpn_protocols;
+  const char** client_alpn_protocols;
   uint16_t num_server_alpn_protocols;
   uint16_t num_client_alpn_protocols;
 } ssl_alpn_lib;
@@ -61,7 +61,9 @@
 typedef struct ssl_key_cert_lib {
   bool use_bad_server_cert;
   bool use_bad_client_cert;
+  bool use_root_store;
   char* root_cert;
+  tsi_ssl_root_certs_store* root_store;
   tsi_ssl_pem_key_cert_pair* server_pem_key_cert_pairs;
   tsi_ssl_pem_key_cert_pair* bad_server_pem_key_cert_pairs;
   tsi_ssl_pem_key_cert_pair client_pem_key_cert_pair;
@@ -76,59 +78,79 @@
   ssl_alpn_lib* alpn_lib;
   bool force_client_auth;
   char* server_name_indication;
+  tsi_ssl_session_cache* session_cache;
+  bool session_reused;
+  const char* session_ticket_key;
+  size_t session_ticket_key_size;
   tsi_ssl_server_handshaker_factory* server_handshaker_factory;
   tsi_ssl_client_handshaker_factory* client_handshaker_factory;
 } ssl_tsi_test_fixture;
 
 static void ssl_test_setup_handshakers(tsi_test_fixture* fixture) {
-  ssl_tsi_test_fixture* ssl_fixture = (ssl_tsi_test_fixture*)fixture;
+  ssl_tsi_test_fixture* ssl_fixture =
+      reinterpret_cast<ssl_tsi_test_fixture*>(fixture);
   GPR_ASSERT(ssl_fixture != nullptr);
   GPR_ASSERT(ssl_fixture->key_cert_lib != nullptr);
   GPR_ASSERT(ssl_fixture->alpn_lib != nullptr);
   ssl_key_cert_lib* key_cert_lib = ssl_fixture->key_cert_lib;
   ssl_alpn_lib* alpn_lib = ssl_fixture->alpn_lib;
   /* Create client handshaker factory. */
-  tsi_ssl_pem_key_cert_pair* client_key_cert_pair = nullptr;
+  tsi_ssl_client_handshaker_options client_options;
+  memset(&client_options, 0, sizeof(client_options));
+  client_options.pem_root_certs = key_cert_lib->root_cert;
   if (ssl_fixture->force_client_auth) {
-    client_key_cert_pair = key_cert_lib->use_bad_client_cert
-                               ? &key_cert_lib->bad_client_pem_key_cert_pair
-                               : &key_cert_lib->client_pem_key_cert_pair;
+    client_options.pem_key_cert_pair =
+        key_cert_lib->use_bad_client_cert
+            ? &key_cert_lib->bad_client_pem_key_cert_pair
+            : &key_cert_lib->client_pem_key_cert_pair;
   }
-  char** client_alpn_protocols = nullptr;
-  uint16_t num_client_alpn_protocols = 0;
   if (alpn_lib->alpn_mode == ALPN_CLIENT_NO_SERVER ||
       alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_OK ||
       alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_MISMATCH) {
-    client_alpn_protocols = alpn_lib->client_alpn_protocols;
-    num_client_alpn_protocols = alpn_lib->num_client_alpn_protocols;
+    client_options.alpn_protocols = alpn_lib->client_alpn_protocols;
+    client_options.num_alpn_protocols = alpn_lib->num_client_alpn_protocols;
   }
-  GPR_ASSERT(tsi_create_ssl_client_handshaker_factory(
-                 client_key_cert_pair, key_cert_lib->root_cert, nullptr,
-                 (const char**)client_alpn_protocols, num_client_alpn_protocols,
-                 &ssl_fixture->client_handshaker_factory) == TSI_OK);
+  client_options.root_store =
+      key_cert_lib->use_root_store ? key_cert_lib->root_store : nullptr;
+  if (ssl_fixture->session_cache != nullptr) {
+    client_options.session_cache = ssl_fixture->session_cache;
+  }
+  GPR_ASSERT(tsi_create_ssl_client_handshaker_factory_with_options(
+                 &client_options, &ssl_fixture->client_handshaker_factory) ==
+             TSI_OK);
   /* Create server handshaker factory. */
-  char** server_alpn_protocols = nullptr;
-  uint16_t num_server_alpn_protocols = 0;
+  tsi_ssl_server_handshaker_options server_options;
+  memset(&server_options, 0, sizeof(server_options));
   if (alpn_lib->alpn_mode == ALPN_SERVER_NO_CLIENT ||
       alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_OK ||
       alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_MISMATCH) {
-    server_alpn_protocols = alpn_lib->server_alpn_protocols;
-    num_server_alpn_protocols = alpn_lib->num_server_alpn_protocols;
+    server_options.alpn_protocols = alpn_lib->server_alpn_protocols;
+    server_options.num_alpn_protocols = alpn_lib->num_server_alpn_protocols;
     if (alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_MISMATCH) {
-      num_server_alpn_protocols--;
+      server_options.num_alpn_protocols--;
     }
   }
-  GPR_ASSERT(tsi_create_ssl_server_handshaker_factory(
-                 key_cert_lib->use_bad_server_cert
-                     ? key_cert_lib->bad_server_pem_key_cert_pairs
-                     : key_cert_lib->server_pem_key_cert_pairs,
-                 key_cert_lib->use_bad_server_cert
-                     ? key_cert_lib->bad_server_num_key_cert_pairs
-                     : key_cert_lib->server_num_key_cert_pairs,
-                 key_cert_lib->root_cert, ssl_fixture->force_client_auth,
-                 nullptr, (const char**)server_alpn_protocols,
-                 num_server_alpn_protocols,
-                 &ssl_fixture->server_handshaker_factory) == TSI_OK);
+  server_options.pem_key_cert_pairs =
+      key_cert_lib->use_bad_server_cert
+          ? key_cert_lib->bad_server_pem_key_cert_pairs
+          : key_cert_lib->server_pem_key_cert_pairs;
+  server_options.num_key_cert_pairs =
+      key_cert_lib->use_bad_server_cert
+          ? key_cert_lib->bad_server_num_key_cert_pairs
+          : key_cert_lib->server_num_key_cert_pairs;
+  server_options.pem_client_root_certs = key_cert_lib->root_cert;
+  if (ssl_fixture->force_client_auth) {
+    server_options.client_certificate_request =
+        TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY;
+  } else {
+    server_options.client_certificate_request =
+        TSI_DONT_REQUEST_CLIENT_CERTIFICATE;
+  }
+  server_options.session_ticket_key = ssl_fixture->session_ticket_key;
+  server_options.session_ticket_key_size = ssl_fixture->session_ticket_key_size;
+  GPR_ASSERT(tsi_create_ssl_server_handshaker_factory_with_options(
+                 &server_options, &ssl_fixture->server_handshaker_factory) ==
+             TSI_OK);
   /* Create server and client handshakers. */
   tsi_handshaker* client_handshaker = nullptr;
   GPR_ASSERT(tsi_ssl_client_handshaker_factory_create_handshaker(
@@ -175,6 +197,18 @@
   return property;
 }
 
+static void check_session_reusage(ssl_tsi_test_fixture* ssl_fixture,
+                                  tsi_peer* peer) {
+  const tsi_peer_property* session_reused =
+      tsi_peer_get_property_by_name(peer, TSI_SSL_SESSION_REUSED_PEER_PROPERTY);
+  GPR_ASSERT(session_reused != nullptr);
+  if (ssl_fixture->session_reused) {
+    GPR_ASSERT(strcmp(session_reused->value.data, "true") == 0);
+  } else {
+    GPR_ASSERT(strcmp(session_reused->value.data, "false") == 0);
+  }
+}
+
 void check_server0_peer(tsi_peer* peer) {
   const tsi_peer_property* property =
       check_basic_authenticated_peer_and_get_common_name(peer);
@@ -232,7 +266,7 @@
   ssl_alpn_lib* alpn_lib = ssl_fixture->alpn_lib;
   if (!ssl_fixture->force_client_auth) {
     GPR_ASSERT(peer->property_count ==
-               (alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_OK ? 1 : 0));
+               (alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_OK ? 2 : 1));
   } else {
     const tsi_peer_property* property =
         check_basic_authenticated_peer_and_get_common_name(peer);
@@ -244,7 +278,8 @@
 }
 
 static void ssl_test_check_handshaker_peers(tsi_test_fixture* fixture) {
-  ssl_tsi_test_fixture* ssl_fixture = (ssl_tsi_test_fixture*)fixture;
+  ssl_tsi_test_fixture* ssl_fixture =
+      reinterpret_cast<ssl_tsi_test_fixture*>(fixture);
   GPR_ASSERT(ssl_fixture != nullptr);
   GPR_ASSERT(ssl_fixture->key_cert_lib != nullptr);
   ssl_key_cert_lib* key_cert_lib = ssl_fixture->key_cert_lib;
@@ -255,8 +290,8 @@
   if (expect_success) {
     GPR_ASSERT(tsi_handshaker_result_extract_peer(
                    ssl_fixture->base.client_result, &peer) == TSI_OK);
+    check_session_reusage(ssl_fixture, &peer);
     check_alpn(ssl_fixture, &peer);
-
     if (ssl_fixture->server_name_indication != nullptr) {
       check_server1_peer(&peer);
     } else {
@@ -268,6 +303,7 @@
   if (expect_success) {
     GPR_ASSERT(tsi_handshaker_result_extract_peer(
                    ssl_fixture->base.server_result, &peer) == TSI_OK);
+    check_session_reusage(ssl_fixture, &peer);
     check_alpn(ssl_fixture, &peer);
     check_client_peer(ssl_fixture, &peer);
   } else {
@@ -281,18 +317,19 @@
 }
 
 static void ssl_test_destruct(tsi_test_fixture* fixture) {
-  ssl_tsi_test_fixture* ssl_fixture = (ssl_tsi_test_fixture*)fixture;
+  ssl_tsi_test_fixture* ssl_fixture =
+      reinterpret_cast<ssl_tsi_test_fixture*>(fixture);
   if (ssl_fixture == nullptr) {
     return;
   }
   /* Destroy ssl_alpn_lib. */
   ssl_alpn_lib* alpn_lib = ssl_fixture->alpn_lib;
   for (size_t i = 0; i < alpn_lib->num_server_alpn_protocols; i++) {
-    gpr_free(alpn_lib->server_alpn_protocols[i]);
+    gpr_free(const_cast<char*>(alpn_lib->server_alpn_protocols[i]));
   }
   gpr_free(alpn_lib->server_alpn_protocols);
   for (size_t i = 0; i < alpn_lib->num_client_alpn_protocols; i++) {
-    gpr_free(alpn_lib->client_alpn_protocols[i]);
+    gpr_free(const_cast<char*>(alpn_lib->client_alpn_protocols[i]));
   }
   gpr_free(alpn_lib->client_alpn_protocols);
   gpr_free(alpn_lib);
@@ -312,7 +349,11 @@
   ssl_test_pem_key_cert_pair_destroy(
       key_cert_lib->bad_client_pem_key_cert_pair);
   gpr_free(key_cert_lib->root_cert);
+  tsi_ssl_root_certs_store_destroy(key_cert_lib->root_store);
   gpr_free(key_cert_lib);
+  if (ssl_fixture->session_cache != nullptr) {
+    tsi_ssl_session_cache_unref(ssl_fixture->session_cache);
+  }
   /* Unreference others. */
   tsi_ssl_server_handshaker_factory_unref(
       ssl_fixture->server_handshaker_factory);
@@ -348,6 +389,7 @@
       static_cast<ssl_key_cert_lib*>(gpr_zalloc(sizeof(*key_cert_lib)));
   key_cert_lib->use_bad_server_cert = false;
   key_cert_lib->use_bad_client_cert = false;
+  key_cert_lib->use_root_store = false;
   key_cert_lib->server_num_key_cert_pairs =
       SSL_TSI_TEST_SERVER_KEY_CERT_PAIRS_NUM;
   key_cert_lib->bad_server_num_key_cert_pairs =
@@ -381,14 +423,17 @@
   key_cert_lib->bad_client_pem_key_cert_pair.cert_chain =
       load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "badclient.pem");
   key_cert_lib->root_cert = load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "ca.pem");
+  key_cert_lib->root_store =
+      tsi_ssl_root_certs_store_create(key_cert_lib->root_cert);
+  GPR_ASSERT(key_cert_lib->root_store != nullptr);
   ssl_fixture->key_cert_lib = key_cert_lib;
   /* Create ssl_alpn_lib. */
   ssl_alpn_lib* alpn_lib =
       static_cast<ssl_alpn_lib*>(gpr_zalloc(sizeof(*alpn_lib)));
-  alpn_lib->server_alpn_protocols =
-      static_cast<char**>(gpr_zalloc(sizeof(char*) * SSL_TSI_TEST_ALPN_NUM));
-  alpn_lib->client_alpn_protocols =
-      static_cast<char**>(gpr_zalloc(sizeof(char*) * SSL_TSI_TEST_ALPN_NUM));
+  alpn_lib->server_alpn_protocols = static_cast<const char**>(
+      gpr_zalloc(sizeof(char*) * SSL_TSI_TEST_ALPN_NUM));
+  alpn_lib->client_alpn_protocols = static_cast<const char**>(
+      gpr_zalloc(sizeof(char*) * SSL_TSI_TEST_ALPN_NUM));
   alpn_lib->server_alpn_protocols[0] = gpr_strdup(SSL_TSI_TEST_ALPN1);
   alpn_lib->server_alpn_protocols[1] = gpr_strdup(SSL_TSI_TEST_ALPN3);
   alpn_lib->client_alpn_protocols[0] = gpr_strdup(SSL_TSI_TEST_ALPN2);
@@ -399,6 +444,9 @@
   ssl_fixture->alpn_lib = alpn_lib;
   ssl_fixture->base.vtable = &vtable;
   ssl_fixture->server_name_indication = nullptr;
+  ssl_fixture->session_reused = false;
+  ssl_fixture->session_ticket_key = nullptr;
+  ssl_fixture->session_ticket_key_size = 0;
   ssl_fixture->force_client_auth = false;
   return &ssl_fixture->base;
 }
@@ -423,18 +471,39 @@
   tsi_test_fixture_destroy(fixture);
 }
 
+void ssl_tsi_test_do_handshake_with_root_store() {
+  tsi_test_fixture* fixture = ssl_tsi_test_fixture_create();
+  ssl_tsi_test_fixture* ssl_fixture =
+      reinterpret_cast<ssl_tsi_test_fixture*>(fixture);
+  ssl_fixture->key_cert_lib->use_root_store = true;
+  tsi_test_do_handshake(fixture);
+  tsi_test_fixture_destroy(fixture);
+}
+
 void ssl_tsi_test_do_handshake_with_client_authentication() {
   tsi_test_fixture* fixture = ssl_tsi_test_fixture_create();
-  ssl_tsi_test_fixture* ssl_fixture = (ssl_tsi_test_fixture*)fixture;
+  ssl_tsi_test_fixture* ssl_fixture =
+      reinterpret_cast<ssl_tsi_test_fixture*>(fixture);
   ssl_fixture->force_client_auth = true;
   tsi_test_do_handshake(fixture);
   tsi_test_fixture_destroy(fixture);
 }
 
+void ssl_tsi_test_do_handshake_with_client_authentication_and_root_store() {
+  tsi_test_fixture* fixture = ssl_tsi_test_fixture_create();
+  ssl_tsi_test_fixture* ssl_fixture =
+      reinterpret_cast<ssl_tsi_test_fixture*>(fixture);
+  ssl_fixture->force_client_auth = true;
+  ssl_fixture->key_cert_lib->use_root_store = true;
+  tsi_test_do_handshake(fixture);
+  tsi_test_fixture_destroy(fixture);
+}
+
 void ssl_tsi_test_do_handshake_with_server_name_indication_exact_domain() {
   /* server1 cert contains "waterzooi.test.google.be" in SAN. */
   tsi_test_fixture* fixture = ssl_tsi_test_fixture_create();
-  ssl_tsi_test_fixture* ssl_fixture = (ssl_tsi_test_fixture*)fixture;
+  ssl_tsi_test_fixture* ssl_fixture =
+      reinterpret_cast<ssl_tsi_test_fixture*>(fixture);
   ssl_fixture->server_name_indication =
       const_cast<char*>("waterzooi.test.google.be");
   tsi_test_do_handshake(fixture);
@@ -444,7 +513,8 @@
 void ssl_tsi_test_do_handshake_with_server_name_indication_wild_star_domain() {
   /* server1 cert contains "*.test.google.fr" in SAN. */
   tsi_test_fixture* fixture = ssl_tsi_test_fixture_create();
-  ssl_tsi_test_fixture* ssl_fixture = (ssl_tsi_test_fixture*)fixture;
+  ssl_tsi_test_fixture* ssl_fixture =
+      reinterpret_cast<ssl_tsi_test_fixture*>(fixture);
   ssl_fixture->server_name_indication =
       const_cast<char*>("juju.test.google.fr");
   tsi_test_do_handshake(fixture);
@@ -453,7 +523,8 @@
 
 void ssl_tsi_test_do_handshake_with_bad_server_cert() {
   tsi_test_fixture* fixture = ssl_tsi_test_fixture_create();
-  ssl_tsi_test_fixture* ssl_fixture = (ssl_tsi_test_fixture*)fixture;
+  ssl_tsi_test_fixture* ssl_fixture =
+      reinterpret_cast<ssl_tsi_test_fixture*>(fixture);
   ssl_fixture->key_cert_lib->use_bad_server_cert = true;
   tsi_test_do_handshake(fixture);
   tsi_test_fixture_destroy(fixture);
@@ -461,7 +532,8 @@
 
 void ssl_tsi_test_do_handshake_with_bad_client_cert() {
   tsi_test_fixture* fixture = ssl_tsi_test_fixture_create();
-  ssl_tsi_test_fixture* ssl_fixture = (ssl_tsi_test_fixture*)fixture;
+  ssl_tsi_test_fixture* ssl_fixture =
+      reinterpret_cast<ssl_tsi_test_fixture*>(fixture);
   ssl_fixture->key_cert_lib->use_bad_client_cert = true;
   ssl_fixture->force_client_auth = true;
   tsi_test_do_handshake(fixture);
@@ -470,7 +542,8 @@
 
 void ssl_tsi_test_do_handshake_alpn_client_no_server() {
   tsi_test_fixture* fixture = ssl_tsi_test_fixture_create();
-  ssl_tsi_test_fixture* ssl_fixture = (ssl_tsi_test_fixture*)fixture;
+  ssl_tsi_test_fixture* ssl_fixture =
+      reinterpret_cast<ssl_tsi_test_fixture*>(fixture);
   ssl_fixture->alpn_lib->alpn_mode = ALPN_CLIENT_NO_SERVER;
   tsi_test_do_handshake(fixture);
   tsi_test_fixture_destroy(fixture);
@@ -478,7 +551,8 @@
 
 void ssl_tsi_test_do_handshake_alpn_server_no_client() {
   tsi_test_fixture* fixture = ssl_tsi_test_fixture_create();
-  ssl_tsi_test_fixture* ssl_fixture = (ssl_tsi_test_fixture*)fixture;
+  ssl_tsi_test_fixture* ssl_fixture =
+      reinterpret_cast<ssl_tsi_test_fixture*>(fixture);
   ssl_fixture->alpn_lib->alpn_mode = ALPN_SERVER_NO_CLIENT;
   tsi_test_do_handshake(fixture);
   tsi_test_fixture_destroy(fixture);
@@ -486,7 +560,8 @@
 
 void ssl_tsi_test_do_handshake_alpn_client_server_mismatch() {
   tsi_test_fixture* fixture = ssl_tsi_test_fixture_create();
-  ssl_tsi_test_fixture* ssl_fixture = (ssl_tsi_test_fixture*)fixture;
+  ssl_tsi_test_fixture* ssl_fixture =
+      reinterpret_cast<ssl_tsi_test_fixture*>(fixture);
   ssl_fixture->alpn_lib->alpn_mode = ALPN_CLIENT_SERVER_MISMATCH;
   tsi_test_do_handshake(fixture);
   tsi_test_fixture_destroy(fixture);
@@ -494,7 +569,8 @@
 
 void ssl_tsi_test_do_handshake_alpn_client_server_ok() {
   tsi_test_fixture* fixture = ssl_tsi_test_fixture_create();
-  ssl_tsi_test_fixture* ssl_fixture = (ssl_tsi_test_fixture*)fixture;
+  ssl_tsi_test_fixture* ssl_fixture =
+      reinterpret_cast<ssl_tsi_test_fixture*>(fixture);
   ssl_fixture->alpn_lib->alpn_mode = ALPN_CLIENT_SERVER_OK;
   tsi_test_do_handshake(fixture);
   tsi_test_fixture_destroy(fixture);
@@ -511,11 +587,12 @@
       v <<= 1;
     }
     tsi_test_fixture* fixture = ssl_tsi_test_fixture_create();
-    ssl_tsi_test_fixture* ssl_fixture = (ssl_tsi_test_fixture*)fixture;
+    ssl_tsi_test_fixture* ssl_fixture =
+        reinterpret_cast<ssl_tsi_test_fixture*>(fixture);
     tsi_test_frame_protector_config_destroy(ssl_fixture->base.config);
     ssl_fixture->base.config = tsi_test_frame_protector_config_create(
         bit_array[0], bit_array[1], bit_array[2], bit_array[3], bit_array[4],
-        bit_array[5], bit_array[6], bit_array[7]);
+        bit_array[5], bit_array[6]);
     tsi_test_do_round_trip(&ssl_fixture->base);
     tsi_test_fixture_destroy(fixture);
   }
@@ -531,7 +608,8 @@
         for (size_t ind4 = 0; ind4 < size; ind4++) {
           for (size_t ind5 = 0; ind5 < size; ind5++) {
             tsi_test_fixture* fixture = ssl_tsi_test_fixture_create();
-            ssl_tsi_test_fixture* ssl_fixture = (ssl_tsi_test_fixture*)fixture;
+            ssl_tsi_test_fixture* ssl_fixture =
+                reinterpret_cast<ssl_tsi_test_fixture*>(fixture);
             tsi_test_frame_protector_config_set_buffer_size(
                 ssl_fixture->base.config, odd_sizes[ind1], odd_sizes[ind2],
                 odd_sizes[ind3], odd_sizes[ind4], odd_sizes[ind5]);
@@ -544,6 +622,38 @@
   }
 }
 
+void ssl_tsi_test_do_handshake_session_cache() {
+  tsi_ssl_session_cache* session_cache = tsi_ssl_session_cache_create_lru(16);
+  char session_ticket_key[48];
+  auto do_handshake = [&session_ticket_key,
+                       &session_cache](bool session_reused) {
+    tsi_test_fixture* fixture = ssl_tsi_test_fixture_create();
+    ssl_tsi_test_fixture* ssl_fixture =
+        reinterpret_cast<ssl_tsi_test_fixture*>(fixture);
+    ssl_fixture->server_name_indication =
+        const_cast<char*>("waterzooi.test.google.be");
+    ssl_fixture->session_ticket_key = session_ticket_key;
+    ssl_fixture->session_ticket_key_size = 48;
+    tsi_ssl_session_cache_ref(session_cache);
+    ssl_fixture->session_cache = session_cache;
+    ssl_fixture->session_reused = session_reused;
+    tsi_test_do_round_trip(&ssl_fixture->base);
+    tsi_test_fixture_destroy(fixture);
+  };
+  memset(session_ticket_key, 'a', 48);
+  do_handshake(false);
+  do_handshake(true);
+  do_handshake(true);
+  // Changing session_ticket_key on server invalidates ticket.
+  memset(session_ticket_key, 'b', 48);
+  do_handshake(false);
+  do_handshake(true);
+  memset(session_ticket_key, 'c', 48);
+  do_handshake(false);
+  do_handshake(true);
+  tsi_ssl_session_cache_unref(session_cache);
+}
+
 static const tsi_ssl_handshaker_factory_vtable* original_vtable;
 static bool handshaker_factory_destructor_called;
 
@@ -561,17 +671,18 @@
 
 void test_tsi_ssl_client_handshaker_factory_refcounting() {
   int i;
-  const char* cert_chain =
-      load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "client.pem");
+  char* cert_chain = load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "client.pem");
 
+  tsi_ssl_client_handshaker_options options;
+  memset(&options, 0, sizeof(options));
+  options.pem_root_certs = cert_chain;
   tsi_ssl_client_handshaker_factory* client_handshaker_factory;
-  GPR_ASSERT(tsi_create_ssl_client_handshaker_factory(
-                 nullptr, cert_chain, nullptr, nullptr, 0,
-                 &client_handshaker_factory) == TSI_OK);
+  GPR_ASSERT(tsi_create_ssl_client_handshaker_factory_with_options(
+                 &options, &client_handshaker_factory) == TSI_OK);
 
   handshaker_factory_destructor_called = false;
   original_vtable = tsi_ssl_handshaker_factory_swap_vtable(
-      (tsi_ssl_handshaker_factory*)client_handshaker_factory,
+      reinterpret_cast<tsi_ssl_handshaker_factory*>(client_handshaker_factory),
       &test_handshaker_factory_vtable);
 
   tsi_handshaker* handshaker[3];
@@ -594,7 +705,7 @@
   tsi_handshaker_destroy(handshaker[2]);
   GPR_ASSERT(handshaker_factory_destructor_called);
 
-  gpr_free((void*)cert_chain);
+  gpr_free(cert_chain);
 }
 
 void test_tsi_ssl_server_handshaker_factory_refcounting() {
@@ -615,7 +726,7 @@
 
   handshaker_factory_destructor_called = false;
   original_vtable = tsi_ssl_handshaker_factory_swap_vtable(
-      (tsi_ssl_handshaker_factory*)server_handshaker_factory,
+      reinterpret_cast<tsi_ssl_handshaker_factory*>(server_handshaker_factory),
       &test_handshaker_factory_vtable);
 
   for (i = 0; i < 3; ++i) {
@@ -644,9 +755,11 @@
   const char* cert_chain = "This is not a valid PEM file.";
 
   tsi_ssl_client_handshaker_factory* client_handshaker_factory;
-  GPR_ASSERT(tsi_create_ssl_client_handshaker_factory(
-                 nullptr, cert_chain, nullptr, nullptr, 0,
-                 &client_handshaker_factory) == TSI_INVALID_ARGUMENT);
+  tsi_ssl_client_handshaker_options options;
+  memset(&options, 0, sizeof(options));
+  options.pem_root_certs = cert_chain;
+  GPR_ASSERT(tsi_create_ssl_client_handshaker_factory_with_options(
+                 &options, &client_handshaker_factory) == TSI_INVALID_ARGUMENT);
   tsi_ssl_client_handshaker_factory_unref(client_handshaker_factory);
 }
 
@@ -659,24 +772,25 @@
 int main(int argc, char** argv) {
   grpc_test_init(argc, argv);
   grpc_init();
+
   ssl_tsi_test_do_handshake_tiny_handshake_buffer();
   ssl_tsi_test_do_handshake_small_handshake_buffer();
   ssl_tsi_test_do_handshake();
+  ssl_tsi_test_do_handshake_with_root_store();
   ssl_tsi_test_do_handshake_with_client_authentication();
+  ssl_tsi_test_do_handshake_with_client_authentication_and_root_store();
   ssl_tsi_test_do_handshake_with_server_name_indication_exact_domain();
   ssl_tsi_test_do_handshake_with_server_name_indication_wild_star_domain();
   ssl_tsi_test_do_handshake_with_bad_server_cert();
   ssl_tsi_test_do_handshake_with_bad_client_cert();
-  // TODO: BoringSSL and OpenSSL have different behaviors on handling mismatched
-  // ALPN. Re-enable this test if we can detect in the runtime which SSL library
-  // is used.
-  // ssl_tsi_test_do_handshake_alpn_client_no_server();
+#ifdef OPENSSL_IS_BORINGSSL
+  // BoringSSL and OpenSSL have different behaviors on mismatched ALPN.
+  ssl_tsi_test_do_handshake_alpn_client_no_server();
+  ssl_tsi_test_do_handshake_alpn_client_server_mismatch();
+#endif
   ssl_tsi_test_do_handshake_alpn_server_no_client();
-  // TODO: BoringSSL and OpenSSL have different behaviors on handling mismatched
-  // ALPN. Re-enable this test if we can detect in the runtime which SSL library
-  // is used.
-  // ssl_tsi_test_do_handshake_alpn_client_server_mismatch();
   ssl_tsi_test_do_handshake_alpn_client_server_ok();
+  ssl_tsi_test_do_handshake_session_cache();
   ssl_tsi_test_do_round_trip_for_all_configs();
   ssl_tsi_test_do_round_trip_odd_buffer_size();
   ssl_tsi_test_handshaker_factory_internals();
diff --git a/test/core/tsi/transport_security_test.cc b/test/core/tsi/transport_security_test.cc
index 42e17df..5c92912 100644
--- a/test/core/tsi/transport_security_test.cc
+++ b/test/core/tsi/transport_security_test.cc
@@ -23,11 +23,11 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 
 #include <openssl/crypto.h>
 
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/tsi/fake_transport_security.h"
 #include "src/core/tsi/ssl_transport_security.h"
 #include "test/core/util/test_config.h"
diff --git a/test/core/tsi/transport_security_test_lib.cc b/test/core/tsi/transport_security_test_lib.cc
index 3537366..26349db 100644
--- a/test/core/tsi/transport_security_test_lib.cc
+++ b/test/core/tsi/transport_security_test_lib.cc
@@ -23,7 +23,7 @@
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/thd.h>
+
 #include "src/core/lib/security/transport/tsi_error.h"
 #include "test/core/tsi/transport_security_test_lib.h"
 
@@ -110,27 +110,29 @@
   fixture->vtable->check_handshaker_peers(fixture);
   /* Check unused bytes. */
   if (fixture->test_unused_bytes) {
+    tsi_test_channel* channel = fixture->channel;
     if (fixture->server_result != nullptr &&
         fixture->client_result != nullptr) {
       check_unused_bytes(fixture);
     }
-    fixture->bytes_written_to_server_channel = 0;
-    fixture->bytes_written_to_client_channel = 0;
-    fixture->bytes_read_from_client_channel = 0;
-    fixture->bytes_read_from_server_channel = 0;
+    channel->bytes_written_to_server_channel = 0;
+    channel->bytes_written_to_client_channel = 0;
+    channel->bytes_read_from_client_channel = 0;
+    channel->bytes_read_from_server_channel = 0;
   }
 }
 
-static void send_bytes_to_peer(tsi_test_fixture* fixture,
+static void send_bytes_to_peer(tsi_test_channel* test_channel,
                                const unsigned char* buf, size_t buf_size,
                                bool is_client) {
-  GPR_ASSERT(fixture != nullptr);
+  GPR_ASSERT(test_channel != nullptr);
   GPR_ASSERT(buf != nullptr);
   uint8_t* channel =
-      is_client ? fixture->server_channel : fixture->client_channel;
+      is_client ? test_channel->server_channel : test_channel->client_channel;
   GPR_ASSERT(channel != nullptr);
-  size_t* bytes_written = is_client ? &fixture->bytes_written_to_server_channel
-                                    : &fixture->bytes_written_to_client_channel;
+  size_t* bytes_written = is_client
+                              ? &test_channel->bytes_written_to_server_channel
+                              : &test_channel->bytes_written_to_client_channel;
   GPR_ASSERT(bytes_written != nullptr);
   GPR_ASSERT(*bytes_written + buf_size <= TSI_TEST_DEFAULT_CHANNEL_SIZE);
   /* Write data to channel. */
@@ -144,8 +146,10 @@
   tsi_test_fixture* fixture = args->fixture;
   if (fixture->test_unused_bytes && !args->appended_unused_bytes) {
     args->appended_unused_bytes = true;
-    send_bytes_to_peer(fixture, (const unsigned char*)TSI_TEST_UNUSED_BYTES,
-                       strlen(TSI_TEST_UNUSED_BYTES), args->is_client);
+    send_bytes_to_peer(
+        fixture->channel,
+        reinterpret_cast<const unsigned char*>(TSI_TEST_UNUSED_BYTES),
+        strlen(TSI_TEST_UNUSED_BYTES), args->is_client);
     if (fixture->client_result != nullptr &&
         fixture->server_result == nullptr) {
       fixture->has_client_finished_first = true;
@@ -153,19 +157,21 @@
   }
 }
 
-static void receive_bytes_from_peer(tsi_test_fixture* fixture,
+static void receive_bytes_from_peer(tsi_test_channel* test_channel,
                                     unsigned char** buf, size_t* buf_size,
                                     bool is_client) {
-  GPR_ASSERT(fixture != nullptr);
+  GPR_ASSERT(test_channel != nullptr);
   GPR_ASSERT(*buf != nullptr);
   GPR_ASSERT(buf_size != nullptr);
   uint8_t* channel =
-      is_client ? fixture->client_channel : fixture->server_channel;
+      is_client ? test_channel->client_channel : test_channel->server_channel;
   GPR_ASSERT(channel != nullptr);
-  size_t* bytes_read = is_client ? &fixture->bytes_read_from_client_channel
-                                 : &fixture->bytes_read_from_server_channel;
-  size_t* bytes_written = is_client ? &fixture->bytes_written_to_client_channel
-                                    : &fixture->bytes_written_to_server_channel;
+  size_t* bytes_read = is_client
+                           ? &test_channel->bytes_read_from_client_channel
+                           : &test_channel->bytes_read_from_server_channel;
+  size_t* bytes_written = is_client
+                              ? &test_channel->bytes_written_to_client_channel
+                              : &test_channel->bytes_written_to_server_channel;
   GPR_ASSERT(bytes_read != nullptr);
   GPR_ASSERT(bytes_written != nullptr);
   size_t to_read = *buf_size < *bytes_written - *bytes_read
@@ -177,14 +183,13 @@
   *bytes_read += to_read;
 }
 
-static void send_message_to_peer(tsi_test_fixture* fixture,
-                                 tsi_frame_protector* protector,
-                                 bool is_client) {
+void tsi_test_frame_protector_send_message_to_peer(
+    tsi_test_frame_protector_config* config, tsi_test_channel* channel,
+    tsi_frame_protector* protector, bool is_client) {
   /* Initialization. */
-  GPR_ASSERT(fixture != nullptr);
-  GPR_ASSERT(fixture->config != nullptr);
+  GPR_ASSERT(config != nullptr);
+  GPR_ASSERT(channel != nullptr);
   GPR_ASSERT(protector != nullptr);
-  tsi_test_frame_protector_config* config = fixture->config;
   unsigned char* protected_buffer =
       static_cast<unsigned char*>(gpr_zalloc(config->protected_buffer_size));
   size_t message_size =
@@ -204,7 +209,7 @@
         &protected_buffer_size_to_send);
     GPR_ASSERT(result == TSI_OK);
     /* Send protected data to peer. */
-    send_bytes_to_peer(fixture, protected_buffer, protected_buffer_size_to_send,
+    send_bytes_to_peer(channel, protected_buffer, protected_buffer_size_to_send,
                        is_client);
     message_bytes += processed_message_size;
     message_size -= processed_message_size;
@@ -217,7 +222,7 @@
             protector, protected_buffer, &protected_buffer_size_to_send,
             &still_pending_size);
         GPR_ASSERT(result == TSI_OK);
-        send_bytes_to_peer(fixture, protected_buffer,
+        send_bytes_to_peer(channel, protected_buffer,
                            protected_buffer_size_to_send, is_client);
       } while (still_pending_size > 0 && result == TSI_OK);
       GPR_ASSERT(result == TSI_OK);
@@ -227,17 +232,16 @@
   gpr_free(protected_buffer);
 }
 
-static void receive_message_from_peer(tsi_test_fixture* fixture,
-                                      tsi_frame_protector* protector,
-                                      unsigned char* message,
-                                      size_t* bytes_received, bool is_client) {
+void tsi_test_frame_protector_receive_message_from_peer(
+    tsi_test_frame_protector_config* config, tsi_test_channel* channel,
+    tsi_frame_protector* protector, unsigned char* message,
+    size_t* bytes_received, bool is_client) {
   /* Initialization. */
-  GPR_ASSERT(fixture != nullptr);
+  GPR_ASSERT(config != nullptr);
+  GPR_ASSERT(channel != nullptr);
   GPR_ASSERT(protector != nullptr);
   GPR_ASSERT(message != nullptr);
   GPR_ASSERT(bytes_received != nullptr);
-  GPR_ASSERT(fixture->config != nullptr);
-  tsi_test_frame_protector_config* config = fixture->config;
   size_t read_offset = 0;
   size_t message_offset = 0;
   size_t read_from_peer_size = 0;
@@ -252,7 +256,7 @@
     /* Receive data from peer. */
     if (read_from_peer_size == 0) {
       read_from_peer_size = config->read_buffer_allocated_size;
-      receive_bytes_from_peer(fixture, &read_buffer, &read_from_peer_size,
+      receive_bytes_from_peer(channel, &read_buffer, &read_from_peer_size,
                               is_client);
       read_offset = 0;
     }
@@ -288,7 +292,7 @@
                                    const unsigned char* bytes_to_send,
                                    size_t bytes_to_send_size,
                                    tsi_handshaker_result* handshaker_result) {
-  handshaker_args* args = (handshaker_args*)user_data;
+  handshaker_args* args = static_cast<handshaker_args*>(user_data);
   GPR_ASSERT(args != nullptr);
   GPR_ASSERT(args->fixture != nullptr);
   tsi_test_fixture* fixture = args->fixture;
@@ -313,7 +317,7 @@
   }
   /* Send data to peer, if needed. */
   if (bytes_to_send_size > 0) {
-    send_bytes_to_peer(args->fixture, bytes_to_send, bytes_to_send_size,
+    send_bytes_to_peer(fixture->channel, bytes_to_send, bytes_to_send_size,
                        args->is_client);
     args->transferred_data = true;
   }
@@ -327,7 +331,7 @@
 static void on_handshake_next_done_wrapper(
     tsi_result result, void* user_data, const unsigned char* bytes_to_send,
     size_t bytes_to_send_size, tsi_handshaker_result* handshaker_result) {
-  handshaker_args* args = (handshaker_args*)user_data;
+  handshaker_args* args = static_cast<handshaker_args*>(user_data);
   args->error = on_handshake_next_done(result, user_data, bytes_to_send,
                                        bytes_to_send_size, handshaker_result);
 }
@@ -360,8 +364,8 @@
   /* Receive data from peer, if available. */
   do {
     size_t buf_size = args->handshake_buffer_size;
-    receive_bytes_from_peer(args->fixture, &args->handshake_buffer, &buf_size,
-                            args->is_client);
+    receive_bytes_from_peer(fixture->channel, &args->handshake_buffer,
+                            &buf_size, args->is_client);
     if (buf_size > 0) {
       args->transferred_data = true;
     }
@@ -410,6 +414,50 @@
   handshaker_args_destroy(server_args);
 }
 
+static void tsi_test_do_ping_pong(tsi_test_frame_protector_config* config,
+                                  tsi_test_channel* channel,
+                                  tsi_frame_protector* client_frame_protector,
+                                  tsi_frame_protector* server_frame_protector) {
+  GPR_ASSERT(config != nullptr);
+  GPR_ASSERT(channel != nullptr);
+  GPR_ASSERT(client_frame_protector != nullptr);
+  GPR_ASSERT(server_frame_protector != nullptr);
+  /* Client sends a message to server. */
+  tsi_test_frame_protector_send_message_to_peer(
+      config, channel, client_frame_protector, true /* is_client */);
+  unsigned char* server_received_message =
+      static_cast<unsigned char*>(gpr_zalloc(TSI_TEST_DEFAULT_CHANNEL_SIZE));
+  size_t server_received_message_size = 0;
+  tsi_test_frame_protector_receive_message_from_peer(
+      config, channel, server_frame_protector, server_received_message,
+      &server_received_message_size, false /* is_client */);
+  GPR_ASSERT(config->client_message_size == server_received_message_size);
+  GPR_ASSERT(memcmp(config->client_message, server_received_message,
+                    server_received_message_size) == 0);
+  /* Server sends a message to client. */
+  tsi_test_frame_protector_send_message_to_peer(
+      config, channel, server_frame_protector, false /* is_client */);
+  unsigned char* client_received_message =
+      static_cast<unsigned char*>(gpr_zalloc(TSI_TEST_DEFAULT_CHANNEL_SIZE));
+  size_t client_received_message_size = 0;
+  tsi_test_frame_protector_receive_message_from_peer(
+      config, channel, client_frame_protector, client_received_message,
+      &client_received_message_size, true /* is_client */);
+  GPR_ASSERT(config->server_message_size == client_received_message_size);
+  GPR_ASSERT(memcmp(config->server_message, client_received_message,
+                    client_received_message_size) == 0);
+  gpr_free(server_received_message);
+  gpr_free(client_received_message);
+}
+
+void tsi_test_frame_protector_do_round_trip_no_handshake(
+    tsi_test_frame_protector_fixture* fixture) {
+  GPR_ASSERT(fixture != nullptr);
+  tsi_test_do_ping_pong(fixture->config, fixture->channel,
+                        fixture->client_frame_protector,
+                        fixture->server_frame_protector);
+}
+
 void tsi_test_do_round_trip(tsi_test_fixture* fixture) {
   /* Initialization. */
   GPR_ASSERT(fixture != nullptr);
@@ -436,33 +484,11 @@
                      ? nullptr
                      : &server_max_output_protected_frame_size,
                  &server_frame_protector) == TSI_OK);
-  /* Client sends a message to server. */
-  send_message_to_peer(fixture, client_frame_protector, true /* is_client */);
-  unsigned char* server_received_message =
-      static_cast<unsigned char*>(gpr_zalloc(TSI_TEST_DEFAULT_CHANNEL_SIZE));
-  size_t server_received_message_size = 0;
-  receive_message_from_peer(
-      fixture, server_frame_protector, server_received_message,
-      &server_received_message_size, false /* is_client */);
-  GPR_ASSERT(config->client_message_size == server_received_message_size);
-  GPR_ASSERT(memcmp(config->client_message, server_received_message,
-                    server_received_message_size) == 0);
-  /* Server sends a message to client. */
-  send_message_to_peer(fixture, server_frame_protector, false /* is_client */);
-  unsigned char* client_received_message =
-      static_cast<unsigned char*>(gpr_zalloc(TSI_TEST_DEFAULT_CHANNEL_SIZE));
-  size_t client_received_message_size = 0;
-  receive_message_from_peer(
-      fixture, client_frame_protector, client_received_message,
-      &client_received_message_size, true /* is_client */);
-  GPR_ASSERT(config->server_message_size == client_received_message_size);
-  GPR_ASSERT(memcmp(config->server_message, client_received_message,
-                    client_received_message_size) == 0);
+  tsi_test_do_ping_pong(config, fixture->channel, client_frame_protector,
+                        server_frame_protector);
   /* Destroy server and client frame protectors. */
   tsi_frame_protector_destroy(client_frame_protector);
   tsi_frame_protector_destroy(server_frame_protector);
-  gpr_free(server_received_message);
-  gpr_free(client_received_message);
 }
 
 static unsigned char* generate_random_message(size_t size) {
@@ -471,7 +497,7 @@
   unsigned char* output =
       static_cast<unsigned char*>(gpr_zalloc(sizeof(unsigned char) * size));
   for (i = 0; i < size - 1; ++i) {
-    output[i] = chars[rand() % (int)(sizeof(chars) - 1)];
+    output[i] = chars[rand() % static_cast<int>(sizeof(chars) - 1)];
   }
   return output;
 }
@@ -482,8 +508,7 @@
     bool use_default_protected_buffer_size, bool use_default_client_message,
     bool use_default_server_message,
     bool use_default_client_max_output_protected_frame_size,
-    bool use_default_server_max_output_protected_frame_size,
-    bool use_default_handshake_buffer_size) {
+    bool use_default_server_max_output_protected_frame_size) {
   tsi_test_frame_protector_config* config =
       static_cast<tsi_test_frame_protector_config*>(
           gpr_zalloc(sizeof(*config)));
@@ -551,24 +576,42 @@
 
 void tsi_test_frame_protector_config_destroy(
     tsi_test_frame_protector_config* config) {
-  GPR_ASSERT(config != nullptr);
+  if (config == nullptr) {
+    return;
+  }
   gpr_free(config->client_message);
   gpr_free(config->server_message);
   gpr_free(config);
 }
 
+static tsi_test_channel* tsi_test_channel_create() {
+  tsi_test_channel* channel =
+      static_cast<tsi_test_channel*>(gpr_zalloc(sizeof(*channel)));
+  channel->client_channel =
+      static_cast<uint8_t*>(gpr_zalloc(TSI_TEST_DEFAULT_CHANNEL_SIZE));
+  channel->server_channel =
+      static_cast<uint8_t*>(gpr_zalloc(TSI_TEST_DEFAULT_CHANNEL_SIZE));
+  channel->bytes_written_to_client_channel = 0;
+  channel->bytes_written_to_server_channel = 0;
+  channel->bytes_read_from_client_channel = 0;
+  channel->bytes_read_from_server_channel = 0;
+  return channel;
+}
+
+static void tsi_test_channel_destroy(tsi_test_channel* channel) {
+  if (channel == nullptr) {
+    return;
+  }
+  gpr_free(channel->client_channel);
+  gpr_free(channel->server_channel);
+  gpr_free(channel);
+}
+
 void tsi_test_fixture_init(tsi_test_fixture* fixture) {
   fixture->config = tsi_test_frame_protector_config_create(
-      true, true, true, true, true, true, true, true);
+      true, true, true, true, true, true, true);
   fixture->handshake_buffer_size = TSI_TEST_DEFAULT_BUFFER_SIZE;
-  fixture->client_channel =
-      static_cast<uint8_t*>(gpr_zalloc(TSI_TEST_DEFAULT_CHANNEL_SIZE));
-  fixture->server_channel =
-      static_cast<uint8_t*>(gpr_zalloc(TSI_TEST_DEFAULT_CHANNEL_SIZE));
-  fixture->bytes_written_to_client_channel = 0;
-  fixture->bytes_written_to_server_channel = 0;
-  fixture->bytes_read_from_client_channel = 0;
-  fixture->bytes_read_from_server_channel = 0;
+  fixture->channel = tsi_test_channel_create();
   fixture->test_unused_bytes = true;
   fixture->has_client_finished_first = false;
   gpr_mu_init(&fixture->mu);
@@ -577,14 +620,15 @@
 }
 
 void tsi_test_fixture_destroy(tsi_test_fixture* fixture) {
-  GPR_ASSERT(fixture != nullptr);
+  if (fixture == nullptr) {
+    return;
+  }
   tsi_test_frame_protector_config_destroy(fixture->config);
   tsi_handshaker_destroy(fixture->client_handshaker);
   tsi_handshaker_destroy(fixture->server_handshaker);
   tsi_handshaker_result_destroy(fixture->client_result);
   tsi_handshaker_result_destroy(fixture->server_result);
-  gpr_free(fixture->client_channel);
-  gpr_free(fixture->server_channel);
+  tsi_test_channel_destroy(fixture->channel);
   GPR_ASSERT(fixture->vtable != nullptr);
   GPR_ASSERT(fixture->vtable->destruct != nullptr);
   fixture->vtable->destruct(fixture);
@@ -592,3 +636,34 @@
   gpr_cv_destroy(&fixture->cv);
   gpr_free(fixture);
 }
+
+tsi_test_frame_protector_fixture* tsi_test_frame_protector_fixture_create() {
+  tsi_test_frame_protector_fixture* fixture =
+      static_cast<tsi_test_frame_protector_fixture*>(
+          gpr_zalloc(sizeof(*fixture)));
+  fixture->config = tsi_test_frame_protector_config_create(
+      true, true, true, true, true, true, true);
+  fixture->channel = tsi_test_channel_create();
+  return fixture;
+}
+
+void tsi_test_frame_protector_fixture_init(
+    tsi_test_frame_protector_fixture* fixture,
+    tsi_frame_protector* client_frame_protector,
+    tsi_frame_protector* server_frame_protector) {
+  GPR_ASSERT(fixture != nullptr);
+  fixture->client_frame_protector = client_frame_protector;
+  fixture->server_frame_protector = server_frame_protector;
+}
+
+void tsi_test_frame_protector_fixture_destroy(
+    tsi_test_frame_protector_fixture* fixture) {
+  if (fixture == nullptr) {
+    return;
+  }
+  tsi_test_frame_protector_config_destroy(fixture->config);
+  tsi_test_channel_destroy(fixture->channel);
+  tsi_frame_protector_destroy(fixture->client_frame_protector);
+  tsi_frame_protector_destroy(fixture->server_frame_protector);
+  gpr_free(fixture);
+}
diff --git a/test/core/tsi/transport_security_test_lib.h b/test/core/tsi/transport_security_test_lib.h
index 9b07448..b6a431f 100644
--- a/test/core/tsi/transport_security_test_lib.h
+++ b/test/core/tsi/transport_security_test_lib.h
@@ -35,8 +35,8 @@
 #define TSI_TEST_DEFAULT_CHANNEL_SIZE 32768
 #define TSI_TEST_BIG_MESSAGE_SIZE 17000
 #define TSI_TEST_SMALL_MESSAGE_SIZE 10
-#define TSI_TEST_NUM_OF_ARGUMENTS 8
-#define TSI_TEST_NUM_OF_COMBINATIONS 256
+#define TSI_TEST_NUM_OF_ARGUMENTS 7
+#define TSI_TEST_NUM_OF_COMBINATIONS 128
 #define TSI_TEST_UNUSED_BYTES "HELLO GOOGLE"
 
 /* ---  tsi_test_fixture object ---
@@ -46,12 +46,22 @@
   protect/unprotect operations with respect to TSI implementations. */
 typedef struct tsi_test_fixture tsi_test_fixture;
 
-/* ---  tsi_test_frame_protector_config object ---
+/* ---  tsi_test_frame_protector_fixture object ---
+  The object wraps all necessary information used to test correctness of TSI
+  frame protector implementations. */
+typedef struct tsi_test_frame_protector_fixture
+    tsi_test_frame_protector_fixture;
 
+/* ---  tsi_test_frame_protector_config object ---
   This object is used to configure different parameters of TSI frame protector
   APIs. */
 typedef struct tsi_test_frame_protector_config tsi_test_frame_protector_config;
 
+/* ---  tsi_test_channel object ---
+  This object represents simulated channels between the client and server
+  from/to which they could read/write the exchanged information. */
+typedef struct tsi_test_channel tsi_test_channel;
+
 /* V-table for tsi_test_fixture operations that are implemented differently in
    different TSI implementations. */
 typedef struct tsi_test_fixture_vtable {
@@ -73,17 +83,8 @@
   tsi_handshaker_result* server_result;
   /* size of buffer used to store data received from the peer. */
   size_t handshake_buffer_size;
-  /* simulated channels between client and server. If the server (client)
-     wants to send data to the client (server), he will write data to
-     client_channel (server_channel), which will be read by client (server). */
-  uint8_t* client_channel;
-  uint8_t* server_channel;
-  /* size of data written to the client/server channel. */
-  size_t bytes_written_to_client_channel;
-  size_t bytes_written_to_server_channel;
-  /* size of data read from the client/server channel */
-  size_t bytes_read_from_client_channel;
-  size_t bytes_read_from_server_channel;
+  /* tsi_test_channel instance. */
+  tsi_test_channel* channel;
   /* tsi_test_frame_protector_config instance */
   tsi_test_frame_protector_config* config;
   /* a flag indicating if client has finished TSI handshake first (i.e., before
@@ -106,6 +107,30 @@
   bool notified;
 };
 
+struct tsi_test_frame_protector_fixture {
+  /* client/server TSI frame protectors whose ownership are transferred. */
+  tsi_frame_protector* client_frame_protector;
+  tsi_frame_protector* server_frame_protector;
+  /* tsi_test_channel instance. */
+  tsi_test_channel* channel;
+  /* tsi_test_frame_protector_config instance */
+  tsi_test_frame_protector_config* config;
+};
+
+struct tsi_test_channel {
+  /* simulated channels between client and server. If the server (client)
+     wants to send data to the client (server), he will write data to
+     client_channel (server_channel), which will be read by client (server). */
+  uint8_t* client_channel;
+  uint8_t* server_channel;
+  /* size of data written to the client/server channel. */
+  size_t bytes_written_to_client_channel;
+  size_t bytes_written_to_server_channel;
+  /* size of data read from the client/server channel */
+  size_t bytes_read_from_client_channel;
+  size_t bytes_read_from_server_channel;
+};
+
 struct tsi_test_frame_protector_config {
   /* size of buffer used to store protected frames to be unprotected. */
   size_t read_buffer_allocated_size;
@@ -135,8 +160,7 @@
     bool use_default_protected_buffer_size, bool use_default_client_message,
     bool use_default_server_message,
     bool use_default_client_max_output_protected_frame_size,
-    bool use_default_server_max_output_protected_frame_size,
-    bool use_default_handshake_buffer_size);
+    bool use_default_server_max_output_protected_frame_size);
 
 /* This method sets different buffer and frame sizes of a
    tsi_test_frame_protector_config instance with user provided values. */
@@ -160,6 +184,35 @@
    this function. */
 void tsi_test_fixture_destroy(tsi_test_fixture* fixture);
 
+/* This method creates a tsi_test_frame_protector_fixture instance. */
+tsi_test_frame_protector_fixture* tsi_test_frame_protector_fixture_create();
+
+/* This method initializes members of tsi_test_frame_protector_fixture instance.
+   Note that the struct instance should be allocated before making
+   this call. */
+void tsi_test_frame_protector_fixture_init(
+    tsi_test_frame_protector_fixture* fixture,
+    tsi_frame_protector* client_frame_protector,
+    tsi_frame_protector* server_frame_protector);
+
+/* This method destroys a tsi_test_frame_protector_fixture instance. Note that
+   the fixture intance must be dynamically allocated and will be freed by this
+   function. */
+void tsi_test_frame_protector_fixture_destroy(
+    tsi_test_frame_protector_fixture* fixture);
+
+/* This method performs a protect opeation on raw data and sends the result to
+   peer. */
+void tsi_test_frame_protector_send_message_to_peer(
+    tsi_test_frame_protector_config* config, tsi_test_channel* channel,
+    tsi_frame_protector* protector, bool is_client);
+
+/* This method receives message from peer and unprotects it. */
+void tsi_test_frame_protector_receive_message_from_peer(
+    tsi_test_frame_protector_config* config, tsi_test_channel* channel,
+    tsi_frame_protector* protector, unsigned char* message,
+    size_t* bytes_received, bool is_client);
+
 /* This method performs a full TSI handshake between a client and a server.
    Note that the test library will implement the new TSI handshaker API to
    perform handshakes. */
@@ -171,4 +224,8 @@
    the client and server switching its role. */
 void tsi_test_do_round_trip(tsi_test_fixture* fixture);
 
+/* This method performs the above round trip test without doing handshakes. */
+void tsi_test_frame_protector_do_round_trip_no_handshake(
+    tsi_test_frame_protector_fixture* fixture);
+
 #endif  // GRPC_TEST_CORE_TSI_TRANSPORT_SECURITY_TEST_LIB_H_
diff --git a/test/core/util/BUILD b/test/core/util/BUILD
index 2237cfc..886cfdd 100644
--- a/test/core/util/BUILD
+++ b/test/core/util/BUILD
@@ -51,6 +51,7 @@
 grpc_cc_library(
     name = "grpc_test_util_base",
     srcs = [
+        "cmdline.cc",
         "grpc_profiler.cc",
         "histogram.cc",
         "mock_endpoint.cc",
@@ -61,11 +62,14 @@
         "port_server_client.cc",
         "reconnect_server.cc",
         "slice_splitter.cc",
+        "subprocess_posix.cc",
+        "subprocess_windows.cc",
         "test_tcp_server.cc",
         "tracer_util.cc",
         "trickle_endpoint.cc",
     ],
     hdrs = [
+        "cmdline.h",
         "grpc_profiler.h",
         "histogram.h",
         "mock_endpoint.h",
@@ -74,6 +78,7 @@
         "port.h",
         "port_server_client.h",
         "reconnect_server.h",
+        "subprocess.h",
         "slice_splitter.h",
         "test_tcp_server.h",
         "tracer_util.h",
@@ -109,6 +114,16 @@
     ],
 )
 
+grpc_cc_test(
+    name = "cmdline_test",
+    srcs = ["cmdline_test.cc"],
+    language = "C++",
+    deps = [
+        ":grpc_test_util",
+        "//:gpr",
+    ],
+)
+
 grpc_cc_library(
     name = "fuzzer_corpus_test",
     testonly = 1,
diff --git a/src/core/lib/gpr/cmdline.cc b/test/core/util/cmdline.cc
similarity index 91%
rename from src/core/lib/gpr/cmdline.cc
rename to test/core/util/cmdline.cc
index 4118f9a..e76acb5 100644
--- a/src/core/lib/gpr/cmdline.cc
+++ b/test/core/util/cmdline.cc
@@ -16,7 +16,7 @@
  *
  */
 
-#include <grpc/support/cmdline.h>
+#include "test/core/util/cmdline.h"
 
 #include <limits.h>
 #include <stdio.h>
@@ -56,7 +56,7 @@
 static int normal_state(gpr_cmdline* cl, char* arg);
 
 gpr_cmdline* gpr_cmdline_create(const char* description) {
-  gpr_cmdline* cl = (gpr_cmdline*)gpr_zalloc(sizeof(gpr_cmdline));
+  gpr_cmdline* cl = static_cast<gpr_cmdline*>(gpr_zalloc(sizeof(gpr_cmdline)));
 
   cl->description = description;
   cl->state = normal_state;
@@ -85,7 +85,7 @@
     GPR_ASSERT(0 != strcmp(a->name, name));
   }
 
-  a = (arg*)gpr_zalloc(sizeof(arg));
+  a = static_cast<arg*>(gpr_zalloc(sizeof(arg)));
   a->name = name;
   a->help = help;
   a->type = type;
@@ -223,13 +223,13 @@
                 cl->cur_arg->name);
         return print_usage_and_die(cl);
       }
-      *(int*)cl->cur_arg->value = (int)intval;
+      *static_cast<int*>(cl->cur_arg->value) = static_cast<int>(intval);
       break;
     case ARGTYPE_BOOL:
       if (0 == strcmp(str, "1") || 0 == strcmp(str, "true")) {
-        *(int*)cl->cur_arg->value = 1;
+        *static_cast<int*>(cl->cur_arg->value) = 1;
       } else if (0 == strcmp(str, "0") || 0 == strcmp(str, "false")) {
-        *(int*)cl->cur_arg->value = 0;
+        *static_cast<int*>(cl->cur_arg->value) = 0;
       } else {
         fprintf(stderr, "expected boolean, got '%s' for %s\n", str,
                 cl->cur_arg->name);
@@ -237,7 +237,7 @@
       }
       break;
     case ARGTYPE_STRING:
-      *(char**)cl->cur_arg->value = str;
+      *static_cast<char**>(cl->cur_arg->value) = str;
       break;
   }
 
@@ -281,14 +281,15 @@
         fprintf(stderr, "%s is not a flag argument\n", str);
         return print_usage_and_die(cl);
       }
-      *(int*)cl->cur_arg->value = 0;
+      *static_cast<int*>(cl->cur_arg->value) = 0;
       return 1; /* early out */
     }
     eq = strchr(str, '=');
     if (eq != nullptr) {
       /* copy the string into a temp buffer and extract the name */
-      tmp = arg_name = (char*)gpr_malloc((size_t)(eq - str + 1));
-      memcpy(arg_name, str, (size_t)(eq - str));
+      tmp = arg_name =
+          static_cast<char*>(gpr_malloc(static_cast<size_t>(eq - str + 1)));
+      memcpy(arg_name, str, static_cast<size_t>(eq - str));
       arg_name[eq - str] = 0;
     } else {
       arg_name = str;
@@ -305,7 +306,7 @@
       cl->state = value_state;
     } else {
       /* flag parameter: just set the value */
-      *(int*)cl->cur_arg->value = 1;
+      *static_cast<int*>(cl->cur_arg->value) = 1;
     }
   } else {
     r = extra_state(cl, str);
diff --git a/include/grpc/support/cmdline.h b/test/core/util/cmdline.h
similarity index 69%
rename from include/grpc/support/cmdline.h
rename to test/core/util/cmdline.h
index c34a109..3ae35d6 100644
--- a/include/grpc/support/cmdline.h
+++ b/test/core/util/cmdline.h
@@ -16,15 +16,11 @@
  *
  */
 
-#ifndef GRPC_SUPPORT_CMDLINE_H
-#define GRPC_SUPPORT_CMDLINE_H
+#ifndef GRPC_TEST_CORE_UTIL_CMDLINE_H
+#define GRPC_TEST_CORE_UTIL_CMDLINE_H
 
 #include <grpc/support/port_platform.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /** Simple command line parser.
 
    Supports flags that can be specified as -foo, --foo, --no-foo, -no-foo, etc
@@ -55,34 +51,30 @@
 
 /** Construct a command line parser: takes a short description of the tool
    doing the parsing */
-GPRAPI gpr_cmdline* gpr_cmdline_create(const char* description);
+gpr_cmdline* gpr_cmdline_create(const char* description);
 /** Add an integer parameter, with a name (used on the command line) and some
    helpful text (used in the command usage) */
-GPRAPI void gpr_cmdline_add_int(gpr_cmdline* cl, const char* name,
-                                const char* help, int* value);
+void gpr_cmdline_add_int(gpr_cmdline* cl, const char* name, const char* help,
+                         int* value);
 /** The same, for a boolean flag */
-GPRAPI void gpr_cmdline_add_flag(gpr_cmdline* cl, const char* name,
-                                 const char* help, int* value);
+void gpr_cmdline_add_flag(gpr_cmdline* cl, const char* name, const char* help,
+                          int* value);
 /** And for a string */
-GPRAPI void gpr_cmdline_add_string(gpr_cmdline* cl, const char* name,
-                                   const char* help, const char** value);
+void gpr_cmdline_add_string(gpr_cmdline* cl, const char* name, const char* help,
+                            const char** value);
 /** Set a callback for non-named arguments */
-GPRAPI void gpr_cmdline_on_extra_arg(
+void gpr_cmdline_on_extra_arg(
     gpr_cmdline* cl, const char* name, const char* help,
     void (*on_extra_arg)(void* user_data, const char* arg), void* user_data);
 /** Enable surviving failure: default behavior is to exit the process */
-GPRAPI void gpr_cmdline_set_survive_failure(gpr_cmdline* cl);
+void gpr_cmdline_set_survive_failure(gpr_cmdline* cl);
 /** Parse the command line; returns 1 on success, on failure either dies
    (by default) or returns 0 if gpr_cmdline_set_survive_failure() has been
    called */
-GPRAPI int gpr_cmdline_parse(gpr_cmdline* cl, int argc, char** argv);
+int gpr_cmdline_parse(gpr_cmdline* cl, int argc, char** argv);
 /** Destroy the parser */
-GPRAPI void gpr_cmdline_destroy(gpr_cmdline* cl);
+void gpr_cmdline_destroy(gpr_cmdline* cl);
 /** Get a string describing usage */
-GPRAPI char* gpr_cmdline_usage_string(gpr_cmdline* cl, const char* argv0);
+char* gpr_cmdline_usage_string(gpr_cmdline* cl, const char* argv0);
 
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_SUPPORT_CMDLINE_H */
+#endif /* GRPC_TEST_CORE_UTIL_CMDLINE_H */
diff --git a/test/core/gpr/cmdline_test.cc b/test/core/util/cmdline_test.cc
similarity index 99%
rename from test/core/gpr/cmdline_test.cc
rename to test/core/util/cmdline_test.cc
index 172efda..9f5ad88 100644
--- a/test/core/gpr/cmdline_test.cc
+++ b/test/core/util/cmdline_test.cc
@@ -16,13 +16,13 @@
  *
  */
 
-#include <grpc/support/cmdline.h>
-
 #include <string.h>
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
+#include "test/core/util/cmdline.h"
 #include "test/core/util/test_config.h"
 
 #define LOG_TEST() gpr_log(GPR_INFO, "test at %s:%d", __FILE__, __LINE__)
diff --git a/test/core/util/debugger_macros.cc b/test/core/util/debugger_macros.cc
index bb96fc7..05fb146 100644
--- a/test/core/util/debugger_macros.cc
+++ b/test/core/util/debugger_macros.cc
@@ -54,5 +54,6 @@
 }
 
 grpc_chttp2_stream* grpc_chttp2_stream_from_call(grpc_call* call) {
-  return (grpc_chttp2_stream*)grpc_transport_stream_from_call(call);
+  return reinterpret_cast<grpc_chttp2_stream*>(
+      grpc_transport_stream_from_call(call));
 }
diff --git a/test/core/util/fuzzer_corpus_test.cc b/test/core/util/fuzzer_corpus_test.cc
index 7849321..18bc0ad 100644
--- a/test/core/util/fuzzer_corpus_test.cc
+++ b/test/core/util/fuzzer_corpus_test.cc
@@ -25,6 +25,7 @@
 #include <stdio.h>
 #include <sys/types.h>
 
+#include "src/core/lib/gpr/env.h"
 #include "src/core/lib/iomgr/load_file.h"
 #include "test/core/util/test_config.h"
 
@@ -68,6 +69,12 @@
     if (examples_.empty()) {
       if (!FLAGS_file.empty()) examples_.push_back(FLAGS_file);
       if (!FLAGS_directory.empty()) {
+        char* test_srcdir = gpr_getenv("TEST_SRCDIR");
+        if (test_srcdir != nullptr) {
+          FLAGS_directory = test_srcdir +
+                            std::string("/com_github_grpc_grpc/") +
+                            FLAGS_directory;
+        }
         DIR* dp;
         struct dirent* ep;
         dp = opendir(FLAGS_directory.c_str());
diff --git a/test/core/util/fuzzer_one_entry_runner.sh b/test/core/util/fuzzer_one_entry_runner.sh
index 2634a1b..7c471af 100755
--- a/test/core/util/fuzzer_one_entry_runner.sh
+++ b/test/core/util/fuzzer_one_entry_runner.sh
@@ -15,4 +15,4 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-$1 $2
+"$1" "$2"
diff --git a/test/core/util/grpc_fuzzer.bzl b/test/core/util/grpc_fuzzer.bzl
index b8b270e..a6a60b0 100644
--- a/test/core/util/grpc_fuzzer.bzl
+++ b/test/core/util/grpc_fuzzer.bzl
@@ -14,7 +14,7 @@
 
 load("//bazel:grpc_build_system.bzl", "grpc_cc_test")
 
-def grpc_fuzzer(name, corpus, srcs = [], deps = [], **kwargs):
+def grpc_fuzzer(name, corpus, srcs = [], deps = [], size = "large", timeout = "long", **kwargs):
   grpc_cc_test(
     name = name,
     srcs = srcs,
@@ -23,5 +23,8 @@
     external_deps = [
       'gtest',
     ],
+    size = size,
+    timeout = timeout,
+    args = ["--directory=" + native.package_name() + "/" + corpus,],
     **kwargs
   )
diff --git a/test/core/util/histogram.cc b/test/core/util/histogram.cc
index 2f916f8..f028ac4 100644
--- a/test/core/util/histogram.cc
+++ b/test/core/util/histogram.cc
@@ -16,6 +16,8 @@
  *
  */
 
+#include "test/core/util/histogram.h"
+
 #include <math.h>
 #include <stddef.h>
 #include <string.h>
@@ -23,9 +25,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
-#include <grpc/support/useful.h>
 
-#include "test/core/util/histogram.h"
+#include "src/core/lib/gpr/useful.h"
 
 /* Histograms are stored with exponentially increasing bucket sizes.
    The first bucket is [0, m) where m = 1 + resolution
@@ -56,7 +57,7 @@
 
 /* determine a bucket index given a value - does no bounds checking */
 static size_t bucket_for_unchecked(grpc_histogram* h, double x) {
-  return (size_t)(log(x) * h->one_on_log_multiplier);
+  return static_cast<size_t>(log(x) * h->one_on_log_multiplier);
 }
 
 /* bounds checked version of the above */
@@ -73,7 +74,8 @@
 
 grpc_histogram* grpc_histogram_create(double resolution,
                                       double max_bucket_start) {
-  grpc_histogram* h = (grpc_histogram*)gpr_malloc(sizeof(grpc_histogram));
+  grpc_histogram* h =
+      static_cast<grpc_histogram*>(gpr_malloc(sizeof(grpc_histogram)));
   GPR_ASSERT(resolution > 0.0);
   GPR_ASSERT(max_bucket_start > resolution);
   h->sum = 0.0;
@@ -87,7 +89,8 @@
   h->num_buckets = bucket_for_unchecked(h, max_bucket_start) + 1;
   GPR_ASSERT(h->num_buckets > 1);
   GPR_ASSERT(h->num_buckets < 100000000);
-  h->buckets = (uint32_t*)gpr_zalloc(sizeof(uint32_t) * h->num_buckets);
+  h->buckets =
+      static_cast<uint32_t*>(gpr_zalloc(sizeof(uint32_t) * h->num_buckets));
   return h;
 }
 
@@ -175,14 +178,14 @@
         break;
       }
     }
-    return (bucket_start(h, (double)lower_idx) +
-            bucket_start(h, (double)upper_idx)) /
+    return (bucket_start(h, static_cast<double>(lower_idx)) +
+            bucket_start(h, static_cast<double>(upper_idx))) /
            2.0;
   } else {
     /* treat values as uniform throughout the bucket, and find where this value
        should lie */
-    lower_bound = bucket_start(h, (double)lower_idx);
-    upper_bound = bucket_start(h, (double)(lower_idx + 1));
+    lower_bound = bucket_start(h, static_cast<double>(lower_idx));
+    upper_bound = bucket_start(h, static_cast<double>(lower_idx + 1));
     return GPR_CLAMP(upper_bound - (upper_bound - lower_bound) *
                                        (count_so_far - count_below) /
                                        h->buckets[lower_idx],
diff --git a/test/core/util/memory_counters.cc b/test/core/util/memory_counters.cc
index 32d7b89..4960fe0 100644
--- a/test/core/util/memory_counters.cc
+++ b/test/core/util/memory_counters.cc
@@ -48,13 +48,13 @@
   NO_BARRIER_FETCH_ADD(&g_memory_counters.total_size_relative, (gpr_atm)size);
   NO_BARRIER_FETCH_ADD(&g_memory_counters.total_allocs_absolute, (gpr_atm)1);
   NO_BARRIER_FETCH_ADD(&g_memory_counters.total_allocs_relative, (gpr_atm)1);
-  ptr = (size_t*)g_old_allocs.malloc_fn(size + sizeof(size));
+  ptr = static_cast<size_t*>(g_old_allocs.malloc_fn(size + sizeof(size)));
   *ptr++ = size;
   return ptr;
 }
 
 static void* guard_realloc(void* vptr, size_t size) {
-  size_t* ptr = (size_t*)vptr;
+  size_t* ptr = static_cast<size_t*>(vptr);
   if (vptr == nullptr) {
     return guard_malloc(size);
   }
@@ -67,13 +67,13 @@
   NO_BARRIER_FETCH_ADD(&g_memory_counters.total_size_relative, -(gpr_atm)*ptr);
   NO_BARRIER_FETCH_ADD(&g_memory_counters.total_size_relative, (gpr_atm)size);
   NO_BARRIER_FETCH_ADD(&g_memory_counters.total_allocs_absolute, (gpr_atm)1);
-  ptr = (size_t*)g_old_allocs.realloc_fn(ptr, size + sizeof(size));
+  ptr = static_cast<size_t*>(g_old_allocs.realloc_fn(ptr, size + sizeof(size)));
   *ptr++ = size;
   return ptr;
 }
 
 static void guard_free(void* vptr) {
-  size_t* ptr = (size_t*)vptr;
+  size_t* ptr = static_cast<size_t*>(vptr);
   if (!vptr) return;
   --ptr;
   NO_BARRIER_FETCH_ADD(&g_memory_counters.total_size_relative, -(gpr_atm)*ptr);
diff --git a/test/core/util/mock_endpoint.cc b/test/core/util/mock_endpoint.cc
index 4b35a58..1156cd5 100644
--- a/test/core/util/mock_endpoint.cc
+++ b/test/core/util/mock_endpoint.cc
@@ -30,7 +30,7 @@
 #include <grpc/support/string_util.h>
 #include "src/core/lib/iomgr/sockaddr.h"
 
-typedef struct grpc_mock_endpoint {
+typedef struct mock_endpoint {
   grpc_endpoint base;
   gpr_mu mu;
   void (*on_write)(grpc_slice slice);
@@ -38,11 +38,11 @@
   grpc_slice_buffer* on_read_out;
   grpc_closure* on_read;
   grpc_resource_user* resource_user;
-} grpc_mock_endpoint;
+} mock_endpoint;
 
 static void me_read(grpc_endpoint* ep, grpc_slice_buffer* slices,
                     grpc_closure* cb) {
-  grpc_mock_endpoint* m = (grpc_mock_endpoint*)ep;
+  mock_endpoint* m = reinterpret_cast<mock_endpoint*>(ep);
   gpr_mu_lock(&m->mu);
   if (m->read_buffer.count > 0) {
     grpc_slice_buffer_swap(&m->read_buffer, slices);
@@ -56,7 +56,7 @@
 
 static void me_write(grpc_endpoint* ep, grpc_slice_buffer* slices,
                      grpc_closure* cb) {
-  grpc_mock_endpoint* m = (grpc_mock_endpoint*)ep;
+  mock_endpoint* m = reinterpret_cast<mock_endpoint*>(ep);
   for (size_t i = 0; i < slices->count; i++) {
     m->on_write(slices->slices[i]);
   }
@@ -72,7 +72,7 @@
                                        grpc_pollset_set* pollset) {}
 
 static void me_shutdown(grpc_endpoint* ep, grpc_error* why) {
-  grpc_mock_endpoint* m = (grpc_mock_endpoint*)ep;
+  mock_endpoint* m = reinterpret_cast<mock_endpoint*>(ep);
   gpr_mu_lock(&m->mu);
   if (m->on_read) {
     GRPC_CLOSURE_SCHED(m->on_read,
@@ -86,7 +86,7 @@
 }
 
 static void me_destroy(grpc_endpoint* ep) {
-  grpc_mock_endpoint* m = (grpc_mock_endpoint*)ep;
+  mock_endpoint* m = reinterpret_cast<mock_endpoint*>(ep);
   grpc_slice_buffer_destroy(&m->read_buffer);
   grpc_resource_user_unref(m->resource_user);
   gpr_free(m);
@@ -97,7 +97,7 @@
 }
 
 static grpc_resource_user* me_get_resource_user(grpc_endpoint* ep) {
-  grpc_mock_endpoint* m = (grpc_mock_endpoint*)ep;
+  mock_endpoint* m = reinterpret_cast<mock_endpoint*>(ep);
   return m->resource_user;
 }
 
@@ -118,7 +118,7 @@
 
 grpc_endpoint* grpc_mock_endpoint_create(void (*on_write)(grpc_slice slice),
                                          grpc_resource_quota* resource_quota) {
-  grpc_mock_endpoint* m = (grpc_mock_endpoint*)gpr_malloc(sizeof(*m));
+  mock_endpoint* m = static_cast<mock_endpoint*>(gpr_malloc(sizeof(*m)));
   m->base.vtable = &vtable;
   char* name;
   gpr_asprintf(&name, "mock_endpoint_%" PRIxPTR, (intptr_t)m);
@@ -132,7 +132,7 @@
 }
 
 void grpc_mock_endpoint_put_read(grpc_endpoint* ep, grpc_slice slice) {
-  grpc_mock_endpoint* m = (grpc_mock_endpoint*)ep;
+  mock_endpoint* m = reinterpret_cast<mock_endpoint*>(ep);
   gpr_mu_lock(&m->mu);
   if (m->on_read != nullptr) {
     grpc_slice_buffer_add(m->on_read_out, slice);
diff --git a/test/core/util/parse_hexstring.cc b/test/core/util/parse_hexstring.cc
index 622642a..cd64843 100644
--- a/test/core/util/parse_hexstring.cc
+++ b/test/core/util/parse_hexstring.cc
@@ -39,10 +39,11 @@
   temp = 0;
   for (p = hexstring; *p; p++) {
     if (*p >= '0' && *p <= '9') {
-      temp = (uint8_t)(temp << 4) | (uint8_t)(*p - '0');
+      temp = static_cast<uint8_t>(temp << 4) | static_cast<uint8_t>(*p - '0');
       nibbles++;
     } else if (*p >= 'a' && *p <= 'f') {
-      temp = (uint8_t)(temp << 4) | (uint8_t)(*p - 'a' + 10);
+      temp =
+          static_cast<uint8_t>(temp << 4) | static_cast<uint8_t>(*p - 'a' + 10);
       nibbles++;
     }
     if (nibbles == 2) {
diff --git a/test/core/util/passthru_endpoint.cc b/test/core/util/passthru_endpoint.cc
index 0da0765..5958216 100644
--- a/test/core/util/passthru_endpoint.cc
+++ b/test/core/util/passthru_endpoint.cc
@@ -55,7 +55,7 @@
 
 static void me_read(grpc_endpoint* ep, grpc_slice_buffer* slices,
                     grpc_closure* cb) {
-  half* m = (half*)ep;
+  half* m = reinterpret_cast<half*>(ep);
   gpr_mu_lock(&m->parent->mu);
   if (m->parent->shutdown) {
     GRPC_CLOSURE_SCHED(
@@ -77,7 +77,7 @@
 
 static void me_write(grpc_endpoint* ep, grpc_slice_buffer* slices,
                      grpc_closure* cb) {
-  half* m = other_half((half*)ep);
+  half* m = other_half(reinterpret_cast<half*>(ep));
   gpr_mu_lock(&m->parent->mu);
   grpc_error* error = GRPC_ERROR_NONE;
   gpr_atm_no_barrier_fetch_add(&m->parent->stats->num_writes, (gpr_atm)1);
@@ -108,7 +108,7 @@
                                        grpc_pollset_set* pollset) {}
 
 static void me_shutdown(grpc_endpoint* ep, grpc_error* why) {
-  half* m = (half*)ep;
+  half* m = reinterpret_cast<half*>(ep);
   gpr_mu_lock(&m->parent->mu);
   m->parent->shutdown = true;
   if (m->on_read) {
@@ -130,7 +130,7 @@
 }
 
 static void me_destroy(grpc_endpoint* ep) {
-  passthru_endpoint* p = ((half*)ep)->parent;
+  passthru_endpoint* p = (reinterpret_cast<half*>(ep))->parent;
   gpr_mu_lock(&p->mu);
   if (0 == --p->halves) {
     gpr_mu_unlock(&p->mu);
@@ -147,15 +147,16 @@
 }
 
 static char* me_get_peer(grpc_endpoint* ep) {
-  passthru_endpoint* p = ((half*)ep)->parent;
-  return ((half*)ep) == &p->client ? gpr_strdup("fake:mock_client_endpoint")
-                                   : gpr_strdup("fake:mock_server_endpoint");
+  passthru_endpoint* p = (reinterpret_cast<half*>(ep))->parent;
+  return (reinterpret_cast<half*>(ep)) == &p->client
+             ? gpr_strdup("fake:mock_client_endpoint")
+             : gpr_strdup("fake:mock_server_endpoint");
 }
 
 static int me_get_fd(grpc_endpoint* ep) { return -1; }
 
 static grpc_resource_user* me_get_resource_user(grpc_endpoint* ep) {
-  half* m = (half*)ep;
+  half* m = reinterpret_cast<half*>(ep);
   return m->resource_user;
 }
 
@@ -190,7 +191,8 @@
                                    grpc_endpoint** server,
                                    grpc_resource_quota* resource_quota,
                                    grpc_passthru_endpoint_stats* stats) {
-  passthru_endpoint* m = (passthru_endpoint*)gpr_malloc(sizeof(*m));
+  passthru_endpoint* m =
+      static_cast<passthru_endpoint*>(gpr_malloc(sizeof(*m)));
   m->halves = 2;
   m->shutdown = 0;
   if (stats == nullptr) {
@@ -208,8 +210,8 @@
 
 grpc_passthru_endpoint_stats* grpc_passthru_endpoint_stats_create() {
   grpc_passthru_endpoint_stats* stats =
-      (grpc_passthru_endpoint_stats*)gpr_malloc(
-          sizeof(grpc_passthru_endpoint_stats));
+      static_cast<grpc_passthru_endpoint_stats*>(
+          gpr_malloc(sizeof(grpc_passthru_endpoint_stats)));
   memset(stats, 0, sizeof(*stats));
   gpr_ref_init(&stats->refs, 1);
   return stats;
diff --git a/test/core/util/port.cc b/test/core/util/port.cc
index 9d02b67..303306d 100644
--- a/test/core/util/port.cc
+++ b/test/core/util/port.cc
@@ -75,8 +75,8 @@
     atexit(free_chosen_ports);
   }
   num_chosen_ports++;
-  chosen_ports =
-      (int*)gpr_realloc(chosen_ports, sizeof(int) * num_chosen_ports);
+  chosen_ports = static_cast<int*>(
+      gpr_realloc(chosen_ports, sizeof(int) * num_chosen_ports));
   chosen_ports[num_chosen_ports - 1] = port;
 }
 
diff --git a/test/core/util/port_server_client.cc b/test/core/util/port_server_client.cc
index 7e76c80..9a41599 100644
--- a/test/core/util/port_server_client.cc
+++ b/test/core/util/port_server_client.cc
@@ -41,13 +41,14 @@
 } freereq;
 
 static void destroy_pops_and_shutdown(void* p, grpc_error* error) {
-  grpc_pollset* pollset = grpc_polling_entity_pollset((grpc_polling_entity*)p);
+  grpc_pollset* pollset =
+      grpc_polling_entity_pollset(static_cast<grpc_polling_entity*>(p));
   grpc_pollset_destroy(pollset);
   gpr_free(pollset);
 }
 
 static void freed_port_from_server(void* arg, grpc_error* error) {
-  freereq* pr = (freereq*)arg;
+  freereq* pr = static_cast<freereq*>(arg);
   gpr_mu_lock(pr->mu);
   pr->done = 1;
   GRPC_LOG_IF_ERROR(
@@ -71,7 +72,8 @@
   memset(&req, 0, sizeof(req));
   memset(&rsp, 0, sizeof(rsp));
 
-  grpc_pollset* pollset = (grpc_pollset*)gpr_zalloc(grpc_pollset_size());
+  grpc_pollset* pollset =
+      static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
   grpc_pollset_init(pollset, &pr.mu);
   pr.pops = grpc_polling_entity_create_from_pollset(pollset);
   shutdown_closure = GRPC_CLOSURE_CREATE(destroy_pops_and_shutdown, &pr.pops,
@@ -127,7 +129,7 @@
 static void got_port_from_server(void* arg, grpc_error* error) {
   size_t i;
   int port = 0;
-  portreq* pr = (portreq*)arg;
+  portreq* pr = static_cast<portreq*>(arg);
   int failed = 0;
   grpc_httpcli_response* response = &pr->response;
 
@@ -158,7 +160,8 @@
     gpr_sleep_until(gpr_time_add(
         gpr_now(GPR_CLOCK_REALTIME),
         gpr_time_from_millis(
-            (int64_t)(1000.0 * (1 + pow(1.3, pr->retries) * rand() / RAND_MAX)),
+            static_cast<int64_t>(
+                1000.0 * (1 + pow(1.3, pr->retries) * rand() / RAND_MAX)),
             GPR_TIMESPAN)));
     pr->retries++;
     req.host = pr->server;
@@ -201,7 +204,8 @@
     grpc_core::ExecCtx exec_ctx;
     memset(&pr, 0, sizeof(pr));
     memset(&req, 0, sizeof(req));
-    grpc_pollset* pollset = (grpc_pollset*)gpr_zalloc(grpc_pollset_size());
+    grpc_pollset* pollset =
+        static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
     grpc_pollset_init(pollset, &pr.mu);
     pr.pops = grpc_polling_entity_create_from_pollset(pollset);
     shutdown_closure = GRPC_CLOSURE_CREATE(destroy_pops_and_shutdown, &pr.pops,
diff --git a/test/core/util/reconnect_server.cc b/test/core/util/reconnect_server.cc
index bcafc4e..ad7cf42 100644
--- a/test/core/util/reconnect_server.cc
+++ b/test/core/util/reconnect_server.cc
@@ -20,11 +20,12 @@
 
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 #include <string.h>
+
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/iomgr/tcp_server.h"
@@ -61,7 +62,7 @@
   gpr_free(acceptor);
   char* peer;
   char* last_colon;
-  reconnect_server* server = (reconnect_server*)arg;
+  reconnect_server* server = static_cast<reconnect_server*>(arg);
   gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
   timestamp_list* new_tail;
   peer = grpc_endpoint_get_peer(tcp);
@@ -75,8 +76,8 @@
     } else {
       if (last_colon == nullptr) {
         gpr_log(GPR_ERROR, "peer does not contain a ':'");
-      } else if (strncmp(server->peer, peer, (size_t)(last_colon - peer)) !=
-                 0) {
+      } else if (strncmp(server->peer, peer,
+                         static_cast<size_t>(last_colon - peer)) != 0) {
         gpr_log(GPR_ERROR, "mismatched peer! %s vs %s", server->peer, peer);
       }
       gpr_free(peer);
diff --git a/test/core/util/run_with_poller.sh b/test/core/util/run_with_poller.sh
index 0579145..382a63e 100755
--- a/test/core/util/run_with_poller.sh
+++ b/test/core/util/run_with_poller.sh
@@ -16,4 +16,4 @@
 set -ex
 export GRPC_POLL_STRATEGY=$1
 shift
-$@
+"$@"
diff --git a/test/core/util/slice_splitter.cc b/test/core/util/slice_splitter.cc
index 7225b6d..1f81d03 100644
--- a/test/core/util/slice_splitter.cc
+++ b/test/core/util/slice_splitter.cc
@@ -21,7 +21,8 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
 
 const char* grpc_slice_split_mode_name(grpc_slice_split_mode mode) {
   switch (mode) {
@@ -44,8 +45,8 @@
   switch (mode) {
     case GRPC_SLICE_SPLIT_IDENTITY:
       *dst_slice_count = src_slice_count;
-      *dst_slices =
-          (grpc_slice*)gpr_malloc(sizeof(grpc_slice) * src_slice_count);
+      *dst_slices = static_cast<grpc_slice*>(
+          gpr_malloc(sizeof(grpc_slice) * src_slice_count));
       for (i = 0; i < src_slice_count; i++) {
         (*dst_slices)[i] = src_slices[i];
         grpc_slice_ref((*dst_slices)[i]);
@@ -57,7 +58,7 @@
       for (i = 0; i < src_slice_count; i++) {
         length += GRPC_SLICE_LENGTH(src_slices[i]);
       }
-      *dst_slices = (grpc_slice*)gpr_malloc(sizeof(grpc_slice));
+      *dst_slices = static_cast<grpc_slice*>(gpr_malloc(sizeof(grpc_slice)));
       **dst_slices = grpc_slice_malloc(length);
       length = 0;
       for (i = 0; i < src_slice_count; i++) {
@@ -73,7 +74,8 @@
         length += GRPC_SLICE_LENGTH(src_slices[i]);
       }
       *dst_slice_count = length;
-      *dst_slices = (grpc_slice*)gpr_malloc(sizeof(grpc_slice) * length);
+      *dst_slices =
+          static_cast<grpc_slice*>(gpr_malloc(sizeof(grpc_slice) * length));
       length = 0;
       for (i = 0; i < src_slice_count; i++) {
         for (j = 0; j < GRPC_SLICE_LENGTH(src_slices[i]); j++) {
@@ -113,7 +115,7 @@
   for (i = 0; i < nslices; i++) {
     if (GRPC_SLICE_LENGTH(slices[i]) + length > capacity) {
       capacity = GPR_MAX(capacity * 2, GRPC_SLICE_LENGTH(slices[i]) + length);
-      out = (uint8_t*)gpr_realloc(out, capacity);
+      out = static_cast<uint8_t*>(gpr_realloc(out, capacity));
     }
     memcpy(out + length, GRPC_SLICE_START_PTR(slices[i]),
            GRPC_SLICE_LENGTH(slices[i]));
diff --git a/include/grpc/support/subprocess.h b/test/core/util/subprocess.h
similarity index 63%
rename from include/grpc/support/subprocess.h
rename to test/core/util/subprocess.h
index 175f7b5..c7fe9af 100644
--- a/include/grpc/support/subprocess.h
+++ b/test/core/util/subprocess.h
@@ -16,29 +16,21 @@
  *
  */
 
-#ifndef GRPC_SUPPORT_SUBPROCESS_H
-#define GRPC_SUPPORT_SUBPROCESS_H
+#ifndef GRPC_TEST_CORE_UTIL_SUBPROCESS_H
+#define GRPC_TEST_CORE_UTIL_SUBPROCESS_H
 
 #include <grpc/support/port_platform.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct gpr_subprocess gpr_subprocess;
 
 /** .exe on windows, empty on unices */
-GPRAPI const char* gpr_subprocess_binary_extension();
+const char* gpr_subprocess_binary_extension();
 
-GPRAPI gpr_subprocess* gpr_subprocess_create(int argc, const char** argv);
+gpr_subprocess* gpr_subprocess_create(int argc, const char** argv);
 /** if subprocess has not been joined, kill it */
-GPRAPI void gpr_subprocess_destroy(gpr_subprocess* p);
+void gpr_subprocess_destroy(gpr_subprocess* p);
 /** returns exit status; can be called at most once */
-GPRAPI int gpr_subprocess_join(gpr_subprocess* p);
-GPRAPI void gpr_subprocess_interrupt(gpr_subprocess* p);
+int gpr_subprocess_join(gpr_subprocess* p);
+void gpr_subprocess_interrupt(gpr_subprocess* p);
 
-#ifdef __cplusplus
-}  // extern "C"
-#endif
-
-#endif /* GRPC_SUPPORT_SUBPROCESS_H */
+#endif /* GRPC_TEST_CORE_UTIL_SUBPROCESS_H */
diff --git a/src/core/lib/gpr/subprocess_posix.cc b/test/core/util/subprocess_posix.cc
similarity index 87%
rename from src/core/lib/gpr/subprocess_posix.cc
rename to test/core/util/subprocess_posix.cc
index dc046b6..ab288d7 100644
--- a/src/core/lib/gpr/subprocess_posix.cc
+++ b/test/core/util/subprocess_posix.cc
@@ -20,8 +20,6 @@
 
 #ifdef GPR_POSIX_SUBPROCESS
 
-#include <grpc/support/subprocess.h>
-
 #include <assert.h>
 #include <errno.h>
 #include <signal.h>
@@ -36,6 +34,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
+#include "test/core/util/subprocess.h"
+
 struct gpr_subprocess {
   int pid;
   bool joined;
@@ -52,8 +52,9 @@
   if (pid == -1) {
     return nullptr;
   } else if (pid == 0) {
-    exec_args = (char**)gpr_malloc(((size_t)argc + 1) * sizeof(char*));
-    memcpy(exec_args, argv, (size_t)argc * sizeof(char*));
+    exec_args = static_cast<char**>(
+        gpr_malloc((static_cast<size_t>(argc) + 1) * sizeof(char*)));
+    memcpy(exec_args, argv, static_cast<size_t>(argc) * sizeof(char*));
     exec_args[argc] = nullptr;
     execv(exec_args[0], exec_args);
     /* if we reach here, an error has occurred */
@@ -61,7 +62,7 @@
     _exit(1);
     return nullptr;
   } else {
-    r = (gpr_subprocess*)gpr_zalloc(sizeof(gpr_subprocess));
+    r = static_cast<gpr_subprocess*>(gpr_zalloc(sizeof(gpr_subprocess)));
     r->pid = pid;
     return r;
   }
diff --git a/src/core/lib/gpr/subprocess_windows.cc b/test/core/util/subprocess_windows.cc
similarity index 98%
rename from src/core/lib/gpr/subprocess_windows.cc
rename to test/core/util/subprocess_windows.cc
index 1947d47..d329524 100644
--- a/src/core/lib/gpr/subprocess_windows.cc
+++ b/test/core/util/subprocess_windows.cc
@@ -26,9 +26,9 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/subprocess.h>
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gpr/string_windows.h"
+#include "test/core/util/subprocess.h"
 
 struct gpr_subprocess {
   PROCESS_INFORMATION pi;
diff --git a/test/core/util/test_config.cc b/test/core/util/test_config.cc
index 6b41044..6a0d444 100644
--- a/test/core/util/test_config.cc
+++ b/test/core/util/test_config.cc
@@ -18,6 +18,7 @@
 
 #include "test/core/util/test_config.h"
 
+#include <inttypes.h>
 #include <signal.h>
 #include <stdbool.h>
 #include <stdio.h>
@@ -29,13 +30,14 @@
 
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
 
 int64_t g_fixture_slowdown_factor = 1;
 int64_t g_poller_slowdown_factor = 1;
 
 #if GPR_GETPID_IN_UNISTD_H
 #include <unistd.h>
-static unsigned seed(void) { return (unsigned)getpid(); }
+static unsigned seed(void) { return static_cast<unsigned>(getpid()); }
 #endif
 
 #if GPR_GETPID_IN_PROCESS_H
@@ -196,7 +198,6 @@
 #elif GPR_POSIX_CRASH_HANDLER
 #include <errno.h>
 #include <execinfo.h>
-#include <grpc/support/useful.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -264,7 +265,7 @@
   ss.ss_size = sizeof(g_alt_stack);
   ss.ss_sp = g_alt_stack;
   GPR_ASSERT(sigaltstack(&ss, nullptr) == 0);
-  sa.sa_flags = (int)(SA_SIGINFO | SA_ONSTACK | SA_RESETHAND);
+  sa.sa_flags = static_cast<int>(SA_SIGINFO | SA_ONSTACK | SA_RESETHAND);
   sa.sa_sigaction = crash_handler;
   GPR_ASSERT(sigaction(SIGILL, &sa, nullptr) == 0);
   GPR_ASSERT(sigaction(SIGABRT, &sa, nullptr) == 0);
@@ -365,15 +366,17 @@
 gpr_timespec grpc_timeout_seconds_to_deadline(int64_t time_s) {
   return gpr_time_add(
       gpr_now(GPR_CLOCK_MONOTONIC),
-      gpr_time_from_millis(grpc_test_slowdown_factor() * (int64_t)1e3 * time_s,
-                           GPR_TIMESPAN));
+      gpr_time_from_millis(
+          grpc_test_slowdown_factor() * static_cast<int64_t>(1e3) * time_s,
+          GPR_TIMESPAN));
 }
 
 gpr_timespec grpc_timeout_milliseconds_to_deadline(int64_t time_ms) {
   return gpr_time_add(
       gpr_now(GPR_CLOCK_MONOTONIC),
-      gpr_time_from_micros(grpc_test_slowdown_factor() * (int64_t)1e3 * time_ms,
-                           GPR_TIMESPAN));
+      gpr_time_from_micros(
+          grpc_test_slowdown_factor() * static_cast<int64_t>(1e3) * time_ms,
+          GPR_TIMESPAN));
 }
 
 void grpc_test_init(int argc, char** argv) {
diff --git a/test/core/util/test_tcp_server.cc b/test/core/util/test_tcp_server.cc
index 5f6af4e..610a991 100644
--- a/test/core/util/test_tcp_server.cc
+++ b/test/core/util/test_tcp_server.cc
@@ -17,16 +17,18 @@
  */
 
 #include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/iomgr/socket_utils.h"
 
 #include "test/core/util/test_tcp_server.h"
 
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 #include <string.h>
+
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/tcp_server.h"
@@ -53,12 +55,13 @@
 
 void test_tcp_server_start(test_tcp_server* server, int port) {
   grpc_resolved_address resolved_addr;
-  struct sockaddr_in* addr = (struct sockaddr_in*)resolved_addr.addr;
+  grpc_sockaddr_in* addr =
+      reinterpret_cast<grpc_sockaddr_in*>(resolved_addr.addr);
   int port_added;
   grpc_core::ExecCtx exec_ctx;
 
-  addr->sin_family = AF_INET;
-  addr->sin_port = htons((uint16_t)port);
+  addr->sin_family = GRPC_AF_INET;
+  addr->sin_port = grpc_htons(static_cast<uint16_t>(port));
   memset(&addr->sin_addr, 0, sizeof(addr->sin_addr));
 
   grpc_error* error = grpc_tcp_server_create(&server->shutdown_complete,
diff --git a/test/core/util/trickle_endpoint.cc b/test/core/util/trickle_endpoint.cc
index f95ed62..f2efb04 100644
--- a/test/core/util/trickle_endpoint.cc
+++ b/test/core/util/trickle_endpoint.cc
@@ -26,7 +26,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/slice/slice_internal.h"
 
 #define WRITE_BUFFER_SIZE (2 * 1024 * 1024)
@@ -47,7 +48,7 @@
 
 static void te_read(grpc_endpoint* ep, grpc_slice_buffer* slices,
                     grpc_closure* cb) {
-  trickle_endpoint* te = (trickle_endpoint*)ep;
+  trickle_endpoint* te = reinterpret_cast<trickle_endpoint*>(ep);
   grpc_endpoint_read(te->wrapped, slices, cb);
 }
 
@@ -62,7 +63,7 @@
 
 static void te_write(grpc_endpoint* ep, grpc_slice_buffer* slices,
                      grpc_closure* cb) {
-  trickle_endpoint* te = (trickle_endpoint*)ep;
+  trickle_endpoint* te = reinterpret_cast<trickle_endpoint*>(ep);
   gpr_mu_lock(&te->mu);
   GPR_ASSERT(te->write_cb == nullptr);
   if (te->write_buffer.length == 0) {
@@ -78,24 +79,24 @@
 }
 
 static void te_add_to_pollset(grpc_endpoint* ep, grpc_pollset* pollset) {
-  trickle_endpoint* te = (trickle_endpoint*)ep;
+  trickle_endpoint* te = reinterpret_cast<trickle_endpoint*>(ep);
   grpc_endpoint_add_to_pollset(te->wrapped, pollset);
 }
 
 static void te_add_to_pollset_set(grpc_endpoint* ep,
                                   grpc_pollset_set* pollset_set) {
-  trickle_endpoint* te = (trickle_endpoint*)ep;
+  trickle_endpoint* te = reinterpret_cast<trickle_endpoint*>(ep);
   grpc_endpoint_add_to_pollset_set(te->wrapped, pollset_set);
 }
 
 static void te_delete_from_pollset_set(grpc_endpoint* ep,
                                        grpc_pollset_set* pollset_set) {
-  trickle_endpoint* te = (trickle_endpoint*)ep;
+  trickle_endpoint* te = reinterpret_cast<trickle_endpoint*>(ep);
   grpc_endpoint_delete_from_pollset_set(te->wrapped, pollset_set);
 }
 
 static void te_shutdown(grpc_endpoint* ep, grpc_error* why) {
-  trickle_endpoint* te = (trickle_endpoint*)ep;
+  trickle_endpoint* te = reinterpret_cast<trickle_endpoint*>(ep);
   gpr_mu_lock(&te->mu);
   if (te->error == GRPC_ERROR_NONE) {
     te->error = GRPC_ERROR_REF(why);
@@ -106,7 +107,7 @@
 }
 
 static void te_destroy(grpc_endpoint* ep) {
-  trickle_endpoint* te = (trickle_endpoint*)ep;
+  trickle_endpoint* te = reinterpret_cast<trickle_endpoint*>(ep);
   grpc_endpoint_destroy(te->wrapped);
   gpr_mu_destroy(&te->mu);
   grpc_slice_buffer_destroy_internal(&te->write_buffer);
@@ -116,22 +117,22 @@
 }
 
 static grpc_resource_user* te_get_resource_user(grpc_endpoint* ep) {
-  trickle_endpoint* te = (trickle_endpoint*)ep;
+  trickle_endpoint* te = reinterpret_cast<trickle_endpoint*>(ep);
   return grpc_endpoint_get_resource_user(te->wrapped);
 }
 
 static char* te_get_peer(grpc_endpoint* ep) {
-  trickle_endpoint* te = (trickle_endpoint*)ep;
+  trickle_endpoint* te = reinterpret_cast<trickle_endpoint*>(ep);
   return grpc_endpoint_get_peer(te->wrapped);
 }
 
 static int te_get_fd(grpc_endpoint* ep) {
-  trickle_endpoint* te = (trickle_endpoint*)ep;
+  trickle_endpoint* te = reinterpret_cast<trickle_endpoint*>(ep);
   return grpc_endpoint_get_fd(te->wrapped);
 }
 
 static void te_finish_write(void* arg, grpc_error* error) {
-  trickle_endpoint* te = (trickle_endpoint*)arg;
+  trickle_endpoint* te = static_cast<trickle_endpoint*>(arg);
   gpr_mu_lock(&te->mu);
   te->writing = false;
   grpc_slice_buffer_reset_and_unref(&te->writing_buffer);
@@ -151,7 +152,8 @@
 
 grpc_endpoint* grpc_trickle_endpoint_create(grpc_endpoint* wrap,
                                             double bytes_per_second) {
-  trickle_endpoint* te = (trickle_endpoint*)gpr_malloc(sizeof(*te));
+  trickle_endpoint* te =
+      static_cast<trickle_endpoint*>(gpr_malloc(sizeof(*te)));
   te->base.vtable = &vtable;
   te->wrapped = wrap;
   te->bytes_per_second = bytes_per_second;
@@ -165,16 +167,16 @@
 }
 
 static double ts2dbl(gpr_timespec s) {
-  return (double)s.tv_sec + 1e-9 * (double)s.tv_nsec;
+  return static_cast<double>(s.tv_sec) + 1e-9 * static_cast<double>(s.tv_nsec);
 }
 
 size_t grpc_trickle_endpoint_trickle(grpc_endpoint* ep) {
-  trickle_endpoint* te = (trickle_endpoint*)ep;
+  trickle_endpoint* te = reinterpret_cast<trickle_endpoint*>(ep);
   gpr_mu_lock(&te->mu);
   if (!te->writing && te->write_buffer.length > 0) {
     gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
     double elapsed = ts2dbl(gpr_time_sub(now, te->last_write));
-    size_t bytes = (size_t)(te->bytes_per_second * elapsed);
+    size_t bytes = static_cast<size_t>(te->bytes_per_second * elapsed);
     // gpr_log(GPR_DEBUG, "%lf elapsed --> %" PRIdPTR " bytes", elapsed, bytes);
     if (bytes > 0) {
       grpc_slice_buffer_move_first(&te->write_buffer,
@@ -194,7 +196,7 @@
 }
 
 size_t grpc_trickle_get_backlog(grpc_endpoint* ep) {
-  trickle_endpoint* te = (trickle_endpoint*)ep;
+  trickle_endpoint* te = reinterpret_cast<trickle_endpoint*>(ep);
   gpr_mu_lock(&te->mu);
   size_t backlog = te->write_buffer.length;
   gpr_mu_unlock(&te->mu);
diff --git a/test/cpp/client/client_channel_stress_test.cc b/test/cpp/client/client_channel_stress_test.cc
index 80d1583..826907a 100644
--- a/test/cpp/client/client_channel_stress_test.cc
+++ b/test/cpp/client/client_channel_stress_test.cc
@@ -23,19 +23,20 @@
 #include <sstream>
 #include <thread>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
 
 #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 
 #include "test/core/util/port.h"
@@ -230,8 +231,7 @@
     }
     grpc_arg fake_addresses = grpc_lb_addresses_create_channel_arg(addresses);
     grpc_channel_args fake_result = {1, &fake_addresses};
-    grpc_fake_resolver_response_generator_set_response(response_generator_,
-                                                       &fake_result);
+    response_generator_->SetResponse(&fake_result);
     grpc_lb_addresses_destroy(addresses);
   }
 
@@ -253,9 +253,10 @@
 
   void CreateStub() {
     ChannelArguments args;
-    response_generator_ = grpc_fake_resolver_response_generator_create();
+    response_generator_ =
+        grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
     args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR,
-                    response_generator_);
+                    response_generator_.get());
     std::ostringstream uri;
     uri << "fake:///servername_not_used";
     channel_ =
@@ -298,7 +299,6 @@
     for (size_t i = 0; i < backends_.size(); ++i) {
       backend_servers_[i].Shutdown();
     }
-    grpc_fake_resolver_response_generator_unref(response_generator_);
   }
 
   std::atomic_bool shutdown_{false};
@@ -310,7 +310,8 @@
   std::vector<std::unique_ptr<BalancerServiceImpl>> balancers_;
   std::vector<ServerThread<BackendServiceImpl>> backend_servers_;
   std::vector<ServerThread<BalancerServiceImpl>> balancer_servers_;
-  grpc_fake_resolver_response_generator* response_generator_;
+  grpc_core::RefCountedPtr<grpc_core::FakeResolverResponseGenerator>
+      response_generator_;
   std::vector<std::thread> client_threads_;
 };
 
diff --git a/test/cpp/client/credentials_test.cc b/test/cpp/client/credentials_test.cc
index 52efce1..e64e260 100644
--- a/test/cpp/client/credentials_test.cc
+++ b/test/cpp/client/credentials_test.cc
@@ -16,7 +16,7 @@
  *
  */
 
-#include <grpc++/security/credentials.h>
+#include <grpcpp/security/credentials.h>
 
 #include <memory>
 
diff --git a/test/cpp/cocoapods/generic/generic.mm b/test/cpp/cocoapods/generic/generic.mm
index 30b43ec..6e65176 100644
--- a/test/cpp/cocoapods/generic/generic.mm
+++ b/test/cpp/cocoapods/generic/generic.mm
@@ -20,19 +20,19 @@
 
 #include <sstream>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/generic/async_generic_service.h>
-#include <grpc++/generic/generic_stub.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
-#include <grpc++/support/slice.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/generic/async_generic_service.h>
+#include <grpcpp/generic/generic_stub.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
+#include <grpcpp/support/slice.h>
 #include <grpc/grpc.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
 
+#include "src/core/lib/gprpp/thd.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
diff --git a/test/cpp/cocoapods/test/server_context_test_spouse_test.mm b/test/cpp/cocoapods/test/server_context_test_spouse_test.mm
index fd6878e..7cb1b36 100644
--- a/test/cpp/cocoapods/test/server_context_test_spouse_test.mm
+++ b/test/cpp/cocoapods/test/server_context_test_spouse_test.mm
@@ -24,12 +24,12 @@
 
 #import <XCTest/XCTest.h>
 
-#include <grpc++/test/server_context_test_spouse.h>
+#include <grpcpp/test/server_context_test_spouse.h>
 
 #include <cstring>
 #include <vector>
 
-#include <grpc++/impl/grpc_library.h>
+#include <grpcpp/impl/grpc_library.h>
 
 static grpc::internal::GrpcLibraryInitializer g_initializer;
 
diff --git a/test/cpp/codegen/BUILD b/test/cpp/codegen/BUILD
index 1388dbc..12712a3 100644
--- a/test/cpp/codegen/BUILD
+++ b/test/cpp/codegen/BUILD
@@ -61,7 +61,6 @@
     srcs = ["golden_file_test.cc"],
     deps = [
         "//:grpc++",
-        "//src/proto/grpc/testing:compiler_test_proto",
         "//test/core/util:gpr_test_util",
     ],
     external_deps = [
@@ -70,6 +69,20 @@
     ],
 )
 
+genrule(
+    name = "copy_compiler_test_grpc_pb_h",
+    srcs = ["//src/proto/grpc/testing:_compiler_test_proto_grpc_codegen"],
+    cmd = "cat $(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.h > $@",
+    outs = ["compiler_test.grpc.pb.h"],
+)
+
+genrule(
+    name = "copy_compiler_test_mock_grpc_pb_h",
+    srcs = ["//src/proto/grpc/testing:_compiler_test_proto_grpc_codegen"],
+    cmd = "cat $(GENDIR)/src/proto/grpc/testing/compiler_test_mock.grpc.pb.h > $@",
+    outs = ["compiler_test_mock.grpc.pb.h"],
+)
+
 grpc_sh_test(
     name = "run_golden_file_test",
     srcs = ["run_golden_file_test.sh"],
@@ -77,6 +90,7 @@
         ":golden_file_test",
         ":compiler_test_golden",
         ":compiler_test_mock_golden",
-        "//src/proto/grpc/testing:_compiler_test_proto_grpc_codegen",
+        ":compiler_test.grpc.pb.h",
+        ":compiler_test_mock.grpc.pb.h",
     ],
 )
diff --git a/test/cpp/codegen/codegen_test_full.cc b/test/cpp/codegen/codegen_test_full.cc
index 98792bd..ccd310f 100644
--- a/test/cpp/codegen/codegen_test_full.cc
+++ b/test/cpp/codegen/codegen_test_full.cc
@@ -16,8 +16,8 @@
  *
  */
 
-#include <grpc++/completion_queue.h>
 #include <grpc/support/time.h>
+#include <grpcpp/completion_queue.h>
 #include <gtest/gtest.h>
 
 namespace grpc {
diff --git a/test/cpp/codegen/compiler_test_golden b/test/cpp/codegen/compiler_test_golden
index 026a941..ca7db5d 100644
--- a/test/cpp/codegen/compiler_test_golden
+++ b/test/cpp/codegen/compiler_test_golden
@@ -26,15 +26,15 @@
 
 #include "src/proto/grpc/testing/compiler_test.pb.h"
 
-#include <grpc++/impl/codegen/async_stream.h>
-#include <grpc++/impl/codegen/async_unary_call.h>
-#include <grpc++/impl/codegen/method_handler_impl.h>
-#include <grpc++/impl/codegen/proto_utils.h>
-#include <grpc++/impl/codegen/rpc_method.h>
-#include <grpc++/impl/codegen/service_type.h>
-#include <grpc++/impl/codegen/status.h>
-#include <grpc++/impl/codegen/stub_options.h>
-#include <grpc++/impl/codegen/sync_stream.h>
+#include <grpcpp/impl/codegen/async_stream.h>
+#include <grpcpp/impl/codegen/async_unary_call.h>
+#include <grpcpp/impl/codegen/method_handler_impl.h>
+#include <grpcpp/impl/codegen/proto_utils.h>
+#include <grpcpp/impl/codegen/rpc_method.h>
+#include <grpcpp/impl/codegen/service_type.h>
+#include <grpcpp/impl/codegen/status.h>
+#include <grpcpp/impl/codegen/stub_options.h>
+#include <grpcpp/impl/codegen/sync_stream.h>
 
 namespace grpc {
 class CompletionQueue;
diff --git a/test/cpp/codegen/compiler_test_mock_golden b/test/cpp/codegen/compiler_test_mock_golden
index f97c2dd..65a7cb0 100644
--- a/test/cpp/codegen/compiler_test_mock_golden
+++ b/test/cpp/codegen/compiler_test_mock_golden
@@ -5,8 +5,8 @@
 #include "src/proto/grpc/testing/compiler_test.pb.h"
 #include "src/proto/grpc/testing/compiler_test.grpc.pb.h"
 
-#include <grpc++/impl/codegen/async_stream.h>
-#include <grpc++/impl/codegen/sync_stream.h>
+#include <grpcpp/impl/codegen/async_stream.h>
+#include <grpcpp/impl/codegen/sync_stream.h>
 #include <gmock/gmock.h>
 namespace grpc {
 namespace testing {
diff --git a/test/cpp/codegen/proto_utils_test.cc b/test/cpp/codegen/proto_utils_test.cc
index cc355bb..836d3d8 100644
--- a/test/cpp/codegen/proto_utils_test.cc
+++ b/test/cpp/codegen/proto_utils_test.cc
@@ -16,11 +16,11 @@
  *
  */
 
-#include <grpc++/impl/codegen/grpc_library.h>
-#include <grpc++/impl/codegen/proto_utils.h>
-#include <grpc++/impl/grpc_library.h>
 #include <grpc/impl/codegen/byte_buffer.h>
 #include <grpc/slice.h>
+#include <grpcpp/impl/codegen/grpc_library.h>
+#include <grpcpp/impl/codegen/proto_utils.h>
+#include <grpcpp/impl/grpc_library.h>
 #include <gtest/gtest.h>
 
 namespace grpc {
@@ -103,7 +103,7 @@
       ASSERT_GT(backup_size, 0);
     }
     for (int i = 0; i < write_size; i++) {
-      ((uint8_t*)data)[i] = written_size % 128;
+      (static_cast<uint8_t*>(data))[i] = written_size % 128;
       written_size++;
     }
     if (should_backup) {
@@ -130,7 +130,7 @@
 }
 
 TEST(WriterTest, TinyBlockTinyBackup) {
-  for (int i = 2; i < (int)GRPC_SLICE_INLINED_SIZE; i++) {
+  for (int i = 2; i < static_cast<int> GRPC_SLICE_INLINED_SIZE; i++) {
     BufferWriterTest(i, 256, 1);
   }
 }
diff --git a/test/cpp/codegen/run_golden_file_test.sh b/test/cpp/codegen/run_golden_file_test.sh
index cdfaa96..8fe801c 100755
--- a/test/cpp/codegen/run_golden_file_test.sh
+++ b/test/cpp/codegen/run_golden_file_test.sh
@@ -13,7 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-set -ex
+set -eux
 
-GENERATED_FILES_PATH="$TEST_SRCDIR/../../../../../genfiles/src/proto/grpc/testing/"
-test/cpp/codegen/golden_file_test --generated_file_path="$GENERATED_FILES_PATH"
+GENERATED_PB_H_DIR="${TEST_SRCDIR}/com_github_grpc_grpc/test/cpp/codegen/"
+test/cpp/codegen/golden_file_test --generated_file_path="$GENERATED_PB_H_DIR"
diff --git a/test/cpp/common/alarm_test.cc b/test/cpp/common/alarm_test.cc
index 2a933a8..57d9583 100644
--- a/test/cpp/common/alarm_test.cc
+++ b/test/cpp/common/alarm_test.cc
@@ -16,8 +16,8 @@
  *
  */
 
-#include <grpc++/alarm.h>
-#include <grpc++/completion_queue.h>
+#include <grpcpp/alarm.h>
+#include <grpcpp/completion_queue.h>
 #include <thread>
 
 #include <gtest/gtest.h>
@@ -35,8 +35,8 @@
 
   void* output_tag;
   bool ok;
-  const CompletionQueue::NextStatus status = cq.AsyncNext(
-      (void**)&output_tag, &ok, grpc_timeout_seconds_to_deadline(2));
+  const CompletionQueue::NextStatus status =
+      cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
 
   EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
   EXPECT_TRUE(ok);
@@ -56,8 +56,8 @@
   });
 
   std::thread t2([&cq, &ok, &output_tag, &status] {
-    status = cq.AsyncNext((void**)&output_tag, &ok,
-                          grpc_timeout_seconds_to_deadline(2));
+    status =
+        cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
   });
 
   t1.join();
@@ -74,8 +74,8 @@
 
   void* output_tag;
   bool ok;
-  const CompletionQueue::NextStatus status = cq.AsyncNext(
-      (void**)&output_tag, &ok, grpc_timeout_seconds_to_deadline(2));
+  const CompletionQueue::NextStatus status =
+      cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
 
   EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
   EXPECT_TRUE(ok);
@@ -90,8 +90,8 @@
   Alarm second(std::move(first));
   void* output_tag;
   bool ok;
-  const CompletionQueue::NextStatus status = cq.AsyncNext(
-      (void**)&output_tag, &ok, grpc_timeout_seconds_to_deadline(2));
+  const CompletionQueue::NextStatus status =
+      cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
   EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
   EXPECT_TRUE(ok);
   EXPECT_EQ(junk, output_tag);
@@ -107,8 +107,8 @@
 
   void* output_tag;
   bool ok;
-  const CompletionQueue::NextStatus status = cq.AsyncNext(
-      (void**)&output_tag, &ok, grpc_timeout_seconds_to_deadline(2));
+  const CompletionQueue::NextStatus status =
+      cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
 
   EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
   EXPECT_TRUE(ok);
@@ -125,8 +125,8 @@
 
   void* output_tag;
   bool ok;
-  const CompletionQueue::NextStatus status = cq.AsyncNext(
-      (void**)&output_tag, &ok, grpc_timeout_seconds_to_deadline(2));
+  const CompletionQueue::NextStatus status =
+      cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(10));
 
   EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
   EXPECT_TRUE(ok);
@@ -141,8 +141,8 @@
 
   void* output_tag;
   bool ok;
-  const CompletionQueue::NextStatus status = cq.AsyncNext(
-      (void**)&output_tag, &ok, grpc_timeout_seconds_to_deadline(1));
+  const CompletionQueue::NextStatus status =
+      cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(1));
 
   EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
   EXPECT_TRUE(ok);
@@ -157,8 +157,8 @@
 
   void* output_tag;
   bool ok;
-  const CompletionQueue::NextStatus status = cq.AsyncNext(
-      (void**)&output_tag, &ok, grpc_timeout_seconds_to_deadline(1));
+  const CompletionQueue::NextStatus status =
+      cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(1));
 
   EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
   EXPECT_TRUE(ok);
@@ -169,13 +169,13 @@
   CompletionQueue cq;
   void* junk = reinterpret_cast<void*>(1618033);
   Alarm alarm;
-  alarm.Set(&cq, grpc_timeout_seconds_to_deadline(2), junk);
+  alarm.Set(&cq, grpc_timeout_seconds_to_deadline(10), junk);
   alarm.Cancel();
 
   void* output_tag;
   bool ok;
-  const CompletionQueue::NextStatus status = cq.AsyncNext(
-      (void**)&output_tag, &ok, grpc_timeout_seconds_to_deadline(1));
+  const CompletionQueue::NextStatus status =
+      cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(1));
 
   EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
   EXPECT_FALSE(ok);
@@ -187,13 +187,13 @@
   void* junk = reinterpret_cast<void*>(1618033);
   {
     Alarm alarm;
-    alarm.Set(&cq, grpc_timeout_seconds_to_deadline(2), junk);
+    alarm.Set(&cq, grpc_timeout_seconds_to_deadline(10), junk);
   }
 
   void* output_tag;
   bool ok;
-  const CompletionQueue::NextStatus status = cq.AsyncNext(
-      (void**)&output_tag, &ok, grpc_timeout_seconds_to_deadline(1));
+  const CompletionQueue::NextStatus status =
+      cq.AsyncNext(&output_tag, &ok, grpc_timeout_seconds_to_deadline(1));
 
   EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
   EXPECT_FALSE(ok);
diff --git a/test/cpp/common/auth_property_iterator_test.cc b/test/cpp/common/auth_property_iterator_test.cc
index fce409a..9634555 100644
--- a/test/cpp/common/auth_property_iterator_test.cc
+++ b/test/cpp/common/auth_property_iterator_test.cc
@@ -16,8 +16,8 @@
  *
  */
 
-#include <grpc++/security/auth_context.h>
 #include <grpc/grpc_security.h>
+#include <grpcpp/security/auth_context.h>
 #include <gtest/gtest.h>
 #include "src/cpp/common/secure_auth_context.h"
 #include "test/cpp/util/string_ref_helper.h"
diff --git a/test/cpp/common/channel_arguments_test.cc b/test/cpp/common/channel_arguments_test.cc
index f330c01..183d2af 100644
--- a/test/cpp/common/channel_arguments_test.cc
+++ b/test/cpp/common/channel_arguments_test.cc
@@ -16,13 +16,13 @@
  *
  */
 
-#include <grpc++/support/channel_arguments.h>
+#include <grpcpp/support/channel_arguments.h>
 
-#include <grpc++/grpc++.h>
 #include <grpc/grpc.h>
-#include <grpc/support/useful.h>
+#include <grpcpp/grpcpp.h>
 #include <gtest/gtest.h>
 
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/socket_mutator.h"
 
diff --git a/test/cpp/common/secure_auth_context_test.cc b/test/cpp/common/secure_auth_context_test.cc
index 7a0530c..6461f49 100644
--- a/test/cpp/common/secure_auth_context_test.cc
+++ b/test/cpp/common/secure_auth_context_test.cc
@@ -17,8 +17,8 @@
  */
 
 #include "src/cpp/common/secure_auth_context.h"
-#include <grpc++/security/auth_context.h>
 #include <grpc/grpc_security.h>
+#include <grpcpp/security/auth_context.h>
 #include <gtest/gtest.h>
 #include "test/cpp/util/string_ref_helper.h"
 
diff --git a/test/cpp/end2end/BUILD b/test/cpp/end2end/BUILD
index 27e8da1..8ab0811 100644
--- a/test/cpp/end2end/BUILD
+++ b/test/cpp/end2end/BUILD
@@ -201,6 +201,27 @@
 )
 
 grpc_cc_test(
+    name = "health_service_end2end_test",
+    srcs = ["health_service_end2end_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
+    deps = [
+        ":test_service_impl",
+        "//:gpr",
+        "//:grpc",
+        "//:grpc++",
+        "//src/proto/grpc/health/v1:health_proto",
+        "//src/proto/grpc/testing:echo_messages_proto",
+        "//src/proto/grpc/testing:echo_proto",
+        "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+        "//test/cpp/util:test_util",
+    ],
+)
+
+grpc_cc_test(
     name = "hybrid_end2end_test",
     srcs = ["hybrid_end2end_test.cc"],
     external_deps = [
@@ -242,6 +263,24 @@
 )
 
 grpc_cc_test(
+    name = "nonblocking_test",
+    srcs = ["nonblocking_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//:grpc++",
+        "//src/proto/grpc/testing:echo_messages_proto",
+        "//src/proto/grpc/testing:echo_proto",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+        "//test/cpp/util:test_util",
+    ],
+)
+
+grpc_cc_test(
     name = "client_lb_end2end_test",
     srcs = ["client_lb_end2end_test.cc"],
     external_deps = [
diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc
index 44cd81a..e8d2325 100644
--- a/test/cpp/end2end/async_end2end_test.cc
+++ b/test/cpp/end2end/async_end2end_test.cc
@@ -20,21 +20,20 @@
 #include <memory>
 #include <thread>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/ext/health_check_service_server_builder_option.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
-#include <grpc/support/tls.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/ext/health_check_service_server_builder_option.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
 
 #include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/tls.h"
 #include "src/core/lib/iomgr/port.h"
 #include "src/proto/grpc/health/v1/health.grpc.pb.h"
 #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
@@ -46,62 +45,22 @@
 
 #include <gtest/gtest.h>
 
-#ifdef GRPC_POSIX_SOCKET
-#include "src/core/lib/iomgr/ev_posix.h"
-#endif
-
 using grpc::testing::EchoRequest;
 using grpc::testing::EchoResponse;
 using grpc::testing::kTlsCredentialsType;
 using std::chrono::system_clock;
 
-GPR_TLS_DECL(g_is_async_end2end_test);
-
 namespace grpc {
 namespace testing {
 
 namespace {
 
-void* tag(int i) { return (void*)(intptr_t)i; }
+void* tag(int i) { return (void*)static_cast<intptr_t>(i); }
 int detag(void* p) { return static_cast<int>(reinterpret_cast<intptr_t>(p)); }
 
-#ifdef GRPC_POSIX_SOCKET
-static int maybe_assert_non_blocking_poll(struct pollfd* pfds, nfds_t nfds,
-                                          int timeout) {
-  if (gpr_tls_get(&g_is_async_end2end_test)) {
-    GPR_ASSERT(timeout == 0);
-  }
-  return poll(pfds, nfds, timeout);
-}
-
-class PollOverride {
- public:
-  PollOverride(grpc_poll_function_type f) {
-    prev_ = grpc_poll_function;
-    grpc_poll_function = f;
-  }
-
-  ~PollOverride() { grpc_poll_function = prev_; }
-
- private:
-  grpc_poll_function_type prev_;
-};
-
-class PollingOverrider : public PollOverride {
- public:
-  explicit PollingOverrider(bool allow_blocking)
-      : PollOverride(allow_blocking ? poll : maybe_assert_non_blocking_poll) {}
-};
-#else
-class PollingOverrider {
- public:
-  explicit PollingOverrider(bool allow_blocking) {}
-};
-#endif
-
 class Verifier {
  public:
-  explicit Verifier(bool spin) : spin_(spin), lambda_run_(false) {}
+  Verifier() : lambda_run_(false) {}
   // Expect sets the expected ok value for a specific tag
   Verifier& Expect(int i, bool expect_ok) {
     return ExpectUnless(i, expect_ok, false);
@@ -129,17 +88,7 @@
   int Next(CompletionQueue* cq, bool ignore_ok) {
     bool ok;
     void* got_tag;
-    if (spin_) {
-      for (;;) {
-        auto r = cq->AsyncNext(&got_tag, &ok, gpr_time_0(GPR_CLOCK_REALTIME));
-        if (r == CompletionQueue::TIMEOUT) continue;
-        if (r == CompletionQueue::GOT_EVENT) break;
-        gpr_log(GPR_ERROR, "unexpected result from AsyncNext");
-        abort();
-      }
-    } else {
-      EXPECT_TRUE(cq->Next(&got_tag, &ok));
-    }
+    EXPECT_TRUE(cq->Next(&got_tag, &ok));
     GotTag(got_tag, ok, ignore_ok);
     return detag(got_tag);
   }
@@ -175,34 +124,14 @@
     if (expectations_.empty()) {
       bool ok;
       void* got_tag;
-      if (spin_) {
-        while (std::chrono::system_clock::now() < deadline) {
-          EXPECT_EQ(
-              cq->AsyncNext(&got_tag, &ok, gpr_time_0(GPR_CLOCK_REALTIME)),
-              CompletionQueue::TIMEOUT);
-        }
-      } else {
-        EXPECT_EQ(cq->AsyncNext(&got_tag, &ok, deadline),
-                  CompletionQueue::TIMEOUT);
-      }
+      EXPECT_EQ(cq->AsyncNext(&got_tag, &ok, deadline),
+                CompletionQueue::TIMEOUT);
     } else {
       while (!expectations_.empty()) {
         bool ok;
         void* got_tag;
-        if (spin_) {
-          for (;;) {
-            GPR_ASSERT(std::chrono::system_clock::now() < deadline);
-            auto r =
-                cq->AsyncNext(&got_tag, &ok, gpr_time_0(GPR_CLOCK_REALTIME));
-            if (r == CompletionQueue::TIMEOUT) continue;
-            if (r == CompletionQueue::GOT_EVENT) break;
-            gpr_log(GPR_ERROR, "unexpected result from AsyncNext");
-            abort();
-          }
-        } else {
-          EXPECT_EQ(cq->AsyncNext(&got_tag, &ok, deadline),
-                    CompletionQueue::GOT_EVENT);
-        }
+        EXPECT_EQ(cq->AsyncNext(&got_tag, &ok, deadline),
+                  CompletionQueue::GOT_EVENT);
         GotTag(got_tag, ok, false);
       }
     }
@@ -217,33 +146,14 @@
     if (expectations_.empty()) {
       bool ok;
       void* got_tag;
-      if (spin_) {
-        while (std::chrono::system_clock::now() < deadline) {
-          EXPECT_EQ(DoOnceThenAsyncNext(cq, &got_tag, &ok, deadline, lambda),
-                    CompletionQueue::TIMEOUT);
-        }
-      } else {
-        EXPECT_EQ(DoOnceThenAsyncNext(cq, &got_tag, &ok, deadline, lambda),
-                  CompletionQueue::TIMEOUT);
-      }
+      EXPECT_EQ(DoOnceThenAsyncNext(cq, &got_tag, &ok, deadline, lambda),
+                CompletionQueue::TIMEOUT);
     } else {
       while (!expectations_.empty()) {
         bool ok;
         void* got_tag;
-        if (spin_) {
-          for (;;) {
-            GPR_ASSERT(std::chrono::system_clock::now() < deadline);
-            auto r = DoOnceThenAsyncNext(
-                cq, &got_tag, &ok, gpr_time_0(GPR_CLOCK_REALTIME), lambda);
-            if (r == CompletionQueue::TIMEOUT) continue;
-            if (r == CompletionQueue::GOT_EVENT) break;
-            gpr_log(GPR_ERROR, "unexpected result from AsyncNext");
-            abort();
-          }
-        } else {
-          EXPECT_EQ(DoOnceThenAsyncNext(cq, &got_tag, &ok, deadline, lambda),
-                    CompletionQueue::GOT_EVENT);
-        }
+        EXPECT_EQ(DoOnceThenAsyncNext(cq, &got_tag, &ok, deadline, lambda),
+                  CompletionQueue::GOT_EVENT);
         GotTag(got_tag, ok, false);
       }
     }
@@ -281,7 +191,6 @@
 
   std::map<void*, bool> expectations_;
   std::map<void*, MaybeExpect> maybe_expectations_;
-  bool spin_;
   bool lambda_run_;
 };
 
@@ -307,15 +216,13 @@
 
 class TestScenario {
  public:
-  TestScenario(bool non_block, bool inproc_stub, const grpc::string& creds_type,
-               bool hcs, const grpc::string& content)
-      : disable_blocking(non_block),
-        inproc(inproc_stub),
+  TestScenario(bool inproc_stub, const grpc::string& creds_type, bool hcs,
+               const grpc::string& content)
+      : inproc(inproc_stub),
         health_check_service(hcs),
         credentials_type(creds_type),
         message_content(content) {}
   void Log() const;
-  bool disable_blocking;
   bool inproc;
   bool health_check_service;
   const grpc::string credentials_type;
@@ -324,9 +231,7 @@
 
 static std::ostream& operator<<(std::ostream& out,
                                 const TestScenario& scenario) {
-  return out << "TestScenario{disable_blocking="
-             << (scenario.disable_blocking ? "true" : "false")
-             << ", inproc=" << (scenario.inproc ? "true" : "false")
+  return out << "TestScenario{inproc=" << (scenario.inproc ? "true" : "false")
              << ", credentials='" << scenario.credentials_type
              << ", health_check_service="
              << (scenario.health_check_service ? "true" : "false")
@@ -346,19 +251,14 @@
   AsyncEnd2endTest() { GetParam().Log(); }
 
   void SetUp() override {
-    poll_overrider_.reset(new PollingOverrider(!GetParam().disable_blocking));
-
     port_ = grpc_pick_unused_port_or_die();
     server_address_ << "localhost:" << port_;
 
     // Setup server
     BuildAndStartServer();
-
-    gpr_tls_set(&g_is_async_end2end_test, 1);
   }
 
   void TearDown() override {
-    gpr_tls_set(&g_is_async_end2end_test, 0);
     server_->Shutdown();
     void* ignored_tag;
     bool ignored_ok;
@@ -366,7 +266,6 @@
     while (cq_->Next(&ignored_tag, &ignored_ok))
       ;
     stub_.reset();
-    poll_overrider_.reset();
     grpc_recycle_unused_port(port_);
   }
 
@@ -420,16 +319,14 @@
       service_->RequestEcho(&srv_ctx, &recv_request, &response_writer,
                             cq_.get(), cq_.get(), tag(2));
 
-      Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
+      response_reader->Finish(&recv_response, &recv_status, tag(4));
+
+      Verifier().Expect(2, true).Verify(cq_.get());
       EXPECT_EQ(send_request.message(), recv_request.message());
 
       send_response.set_message(recv_request.message());
       response_writer.Finish(send_response, Status::OK, tag(3));
-      response_reader->Finish(&recv_response, &recv_status, tag(4));
-      Verifier(GetParam().disable_blocking)
-          .Expect(3, true)
-          .Expect(4, true)
-          .Verify(cq_.get());
+      Verifier().Expect(3, true).Expect(4, true).Verify(cq_.get());
 
       EXPECT_EQ(send_response.message(), recv_response.message());
       EXPECT_TRUE(recv_status.ok());
@@ -443,8 +340,6 @@
   HealthCheck health_check_;
   std::ostringstream server_address_;
   int port_;
-
-  std::unique_ptr<PollingOverrider> poll_overrider_;
 };
 
 TEST_P(AsyncEnd2endTest, SimpleRpc) {
@@ -500,7 +395,6 @@
   ResetStub();
   SendRpc(1);
   EXPECT_EQ(0, notify);
-  gpr_tls_set(&g_is_async_end2end_test, 0);
   server_->Shutdown();
   wait_thread.join();
   EXPECT_EQ(1, notify);
@@ -536,24 +430,20 @@
       std::chrono::system_clock::now());
   std::chrono::system_clock::time_point time_limit(
       std::chrono::system_clock::now() + std::chrono::seconds(10));
-  Verifier(GetParam().disable_blocking).Verify(cq_.get(), time_now);
-  Verifier(GetParam().disable_blocking).Verify(cq_.get(), time_now);
+  Verifier().Verify(cq_.get(), time_now);
+  Verifier().Verify(cq_.get(), time_now);
 
   service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
                         cq_.get(), tag(2));
+  response_reader->Finish(&recv_response, &recv_status, tag(4));
 
-  Verifier(GetParam().disable_blocking)
-      .Expect(2, true)
-      .Verify(cq_.get(), time_limit);
+  Verifier().Expect(2, true).Verify(cq_.get(), time_limit);
   EXPECT_EQ(send_request.message(), recv_request.message());
 
   send_response.set_message(recv_request.message());
   response_writer.Finish(send_response, Status::OK, tag(3));
-  response_reader->Finish(&recv_response, &recv_status, tag(4));
-  Verifier(GetParam().disable_blocking)
-      .Expect(3, true)
-      .Expect(4, true)
-      .Verify(cq_.get(), std::chrono::system_clock::time_point::max());
+  Verifier().Expect(3, true).Expect(4, true).Verify(
+      cq_.get(), std::chrono::system_clock::time_point::max());
 
   EXPECT_EQ(send_response.message(), recv_response.message());
   EXPECT_TRUE(recv_status.ok());
@@ -581,33 +471,25 @@
       std::chrono::system_clock::now());
   std::chrono::system_clock::time_point time_limit(
       std::chrono::system_clock::now() + std::chrono::seconds(10));
-  Verifier(GetParam().disable_blocking).Verify(cq_.get(), time_now);
-  Verifier(GetParam().disable_blocking).Verify(cq_.get(), time_now);
+  Verifier().Verify(cq_.get(), time_now);
+  Verifier().Verify(cq_.get(), time_now);
 
   auto resp_writer_ptr = &response_writer;
   auto lambda_2 = [&, this, resp_writer_ptr]() {
-    gpr_log(GPR_ERROR, "CALLED");
     service_->RequestEcho(&srv_ctx, &recv_request, resp_writer_ptr, cq_.get(),
                           cq_.get(), tag(2));
   };
+  response_reader->Finish(&recv_response, &recv_status, tag(4));
 
-  Verifier(GetParam().disable_blocking)
-      .Expect(2, true)
-      .Verify(cq_.get(), time_limit, lambda_2);
+  Verifier().Expect(2, true).Verify(cq_.get(), time_limit, lambda_2);
   EXPECT_EQ(send_request.message(), recv_request.message());
 
-  auto recv_resp_ptr = &recv_response;
-  auto status_ptr = &recv_status;
   send_response.set_message(recv_request.message());
-  auto lambda_3 = [&, this, resp_writer_ptr, send_response]() {
+  auto lambda_3 = [resp_writer_ptr, send_response]() {
     resp_writer_ptr->Finish(send_response, Status::OK, tag(3));
   };
-  response_reader->Finish(recv_resp_ptr, status_ptr, tag(4));
-  Verifier(GetParam().disable_blocking)
-      .Expect(3, true)
-      .Expect(4, true)
-      .Verify(cq_.get(), std::chrono::system_clock::time_point::max(),
-              lambda_3);
+  Verifier().Expect(3, true).Expect(4, true).Verify(
+      cq_.get(), std::chrono::system_clock::time_point::max(), lambda_3);
 
   EXPECT_EQ(send_response.message(), recv_response.message());
   EXPECT_TRUE(recv_status.ok());
@@ -633,41 +515,26 @@
   service_->RequestRequestStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(),
                                  tag(2));
 
-  Verifier(GetParam().disable_blocking)
-      .Expect(2, true)
-      .Expect(1, true)
-      .Verify(cq_.get());
+  Verifier().Expect(2, true).Expect(1, true).Verify(cq_.get());
 
   cli_stream->Write(send_request, tag(3));
   srv_stream.Read(&recv_request, tag(4));
-  Verifier(GetParam().disable_blocking)
-      .Expect(3, true)
-      .Expect(4, true)
-      .Verify(cq_.get());
+  Verifier().Expect(3, true).Expect(4, true).Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
 
   cli_stream->Write(send_request, tag(5));
   srv_stream.Read(&recv_request, tag(6));
-  Verifier(GetParam().disable_blocking)
-      .Expect(5, true)
-      .Expect(6, true)
-      .Verify(cq_.get());
+  Verifier().Expect(5, true).Expect(6, true).Verify(cq_.get());
 
   EXPECT_EQ(send_request.message(), recv_request.message());
   cli_stream->WritesDone(tag(7));
   srv_stream.Read(&recv_request, tag(8));
-  Verifier(GetParam().disable_blocking)
-      .Expect(7, true)
-      .Expect(8, false)
-      .Verify(cq_.get());
+  Verifier().Expect(7, true).Expect(8, false).Verify(cq_.get());
 
   send_response.set_message(recv_request.message());
   srv_stream.Finish(send_response, Status::OK, tag(9));
   cli_stream->Finish(&recv_status, tag(10));
-  Verifier(GetParam().disable_blocking)
-      .Expect(9, true)
-      .Expect(10, true)
-      .Verify(cq_.get());
+  Verifier().Expect(9, true).Expect(10, true).Verify(cq_.get());
 
   EXPECT_EQ(send_response.message(), recv_response.message());
   EXPECT_TRUE(recv_status.ok());
@@ -699,38 +566,26 @@
 
   bool seen3 = false;
 
-  Verifier(GetParam().disable_blocking)
-      .Expect(2, true)
-      .ExpectMaybe(3, true, &seen3)
-      .Verify(cq_.get());
+  Verifier().Expect(2, true).ExpectMaybe(3, true, &seen3).Verify(cq_.get());
 
   srv_stream.Read(&recv_request, tag(4));
 
-  Verifier(GetParam().disable_blocking)
-      .ExpectUnless(3, true, seen3)
-      .Expect(4, true)
-      .Verify(cq_.get());
+  Verifier().ExpectUnless(3, true, seen3).Expect(4, true).Verify(cq_.get());
 
   EXPECT_EQ(send_request.message(), recv_request.message());
 
   cli_stream->WriteLast(send_request, WriteOptions(), tag(5));
   srv_stream.Read(&recv_request, tag(6));
-  Verifier(GetParam().disable_blocking)
-      .Expect(5, true)
-      .Expect(6, true)
-      .Verify(cq_.get());
+  Verifier().Expect(5, true).Expect(6, true).Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
 
   srv_stream.Read(&recv_request, tag(7));
-  Verifier(GetParam().disable_blocking).Expect(7, false).Verify(cq_.get());
+  Verifier().Expect(7, false).Verify(cq_.get());
 
   send_response.set_message(recv_request.message());
   srv_stream.Finish(send_response, Status::OK, tag(8));
   cli_stream->Finish(&recv_status, tag(9));
-  Verifier(GetParam().disable_blocking)
-      .Expect(8, true)
-      .Expect(9, true)
-      .Verify(cq_.get());
+  Verifier().Expect(8, true).Expect(9, true).Verify(cq_.get());
 
   EXPECT_EQ(send_response.message(), recv_response.message());
   EXPECT_TRUE(recv_status.ok());
@@ -756,38 +611,26 @@
   service_->RequestResponseStream(&srv_ctx, &recv_request, &srv_stream,
                                   cq_.get(), cq_.get(), tag(2));
 
-  Verifier(GetParam().disable_blocking)
-      .Expect(1, true)
-      .Expect(2, true)
-      .Verify(cq_.get());
+  Verifier().Expect(1, true).Expect(2, true).Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
 
   send_response.set_message(recv_request.message());
   srv_stream.Write(send_response, tag(3));
   cli_stream->Read(&recv_response, tag(4));
-  Verifier(GetParam().disable_blocking)
-      .Expect(3, true)
-      .Expect(4, true)
-      .Verify(cq_.get());
+  Verifier().Expect(3, true).Expect(4, true).Verify(cq_.get());
   EXPECT_EQ(send_response.message(), recv_response.message());
 
   srv_stream.Write(send_response, tag(5));
   cli_stream->Read(&recv_response, tag(6));
-  Verifier(GetParam().disable_blocking)
-      .Expect(5, true)
-      .Expect(6, true)
-      .Verify(cq_.get());
+  Verifier().Expect(5, true).Expect(6, true).Verify(cq_.get());
   EXPECT_EQ(send_response.message(), recv_response.message());
 
   srv_stream.Finish(Status::OK, tag(7));
   cli_stream->Read(&recv_response, tag(8));
-  Verifier(GetParam().disable_blocking)
-      .Expect(7, true)
-      .Expect(8, false)
-      .Verify(cq_.get());
+  Verifier().Expect(7, true).Expect(8, false).Verify(cq_.get());
 
   cli_stream->Finish(&recv_status, tag(9));
-  Verifier(GetParam().disable_blocking).Expect(9, true).Verify(cq_.get());
+  Verifier().Expect(9, true).Verify(cq_.get());
 
   EXPECT_TRUE(recv_status.ok());
 }
@@ -812,34 +655,25 @@
   service_->RequestResponseStream(&srv_ctx, &recv_request, &srv_stream,
                                   cq_.get(), cq_.get(), tag(2));
 
-  Verifier(GetParam().disable_blocking)
-      .Expect(1, true)
-      .Expect(2, true)
-      .Verify(cq_.get());
+  Verifier().Expect(1, true).Expect(2, true).Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
 
   send_response.set_message(recv_request.message());
   srv_stream.Write(send_response, tag(3));
   cli_stream->Read(&recv_response, tag(4));
-  Verifier(GetParam().disable_blocking)
-      .Expect(3, true)
-      .Expect(4, true)
-      .Verify(cq_.get());
+  Verifier().Expect(3, true).Expect(4, true).Verify(cq_.get());
   EXPECT_EQ(send_response.message(), recv_response.message());
 
   srv_stream.WriteAndFinish(send_response, WriteOptions(), Status::OK, tag(5));
   cli_stream->Read(&recv_response, tag(6));
-  Verifier(GetParam().disable_blocking)
-      .Expect(5, true)
-      .Expect(6, true)
-      .Verify(cq_.get());
+  Verifier().Expect(5, true).Expect(6, true).Verify(cq_.get());
   EXPECT_EQ(send_response.message(), recv_response.message());
 
   cli_stream->Read(&recv_response, tag(7));
-  Verifier(GetParam().disable_blocking).Expect(7, false).Verify(cq_.get());
+  Verifier().Expect(7, false).Verify(cq_.get());
 
   cli_stream->Finish(&recv_status, tag(8));
-  Verifier(GetParam().disable_blocking).Expect(8, true).Verify(cq_.get());
+  Verifier().Expect(8, true).Verify(cq_.get());
 
   EXPECT_TRUE(recv_status.ok());
 }
@@ -864,36 +698,26 @@
   service_->RequestResponseStream(&srv_ctx, &recv_request, &srv_stream,
                                   cq_.get(), cq_.get(), tag(2));
 
-  Verifier(GetParam().disable_blocking)
-      .Expect(1, true)
-      .Expect(2, true)
-      .Verify(cq_.get());
+  Verifier().Expect(1, true).Expect(2, true).Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
 
   send_response.set_message(recv_request.message());
   srv_stream.Write(send_response, tag(3));
   cli_stream->Read(&recv_response, tag(4));
-  Verifier(GetParam().disable_blocking)
-      .Expect(3, true)
-      .Expect(4, true)
-      .Verify(cq_.get());
+  Verifier().Expect(3, true).Expect(4, true).Verify(cq_.get());
   EXPECT_EQ(send_response.message(), recv_response.message());
 
   srv_stream.WriteLast(send_response, WriteOptions(), tag(5));
   cli_stream->Read(&recv_response, tag(6));
   srv_stream.Finish(Status::OK, tag(7));
-  Verifier(GetParam().disable_blocking)
-      .Expect(5, true)
-      .Expect(6, true)
-      .Expect(7, true)
-      .Verify(cq_.get());
+  Verifier().Expect(5, true).Expect(6, true).Expect(7, true).Verify(cq_.get());
   EXPECT_EQ(send_response.message(), recv_response.message());
 
   cli_stream->Read(&recv_response, tag(8));
-  Verifier(GetParam().disable_blocking).Expect(8, false).Verify(cq_.get());
+  Verifier().Expect(8, false).Verify(cq_.get());
 
   cli_stream->Finish(&recv_status, tag(9));
-  Verifier(GetParam().disable_blocking).Expect(9, true).Verify(cq_.get());
+  Verifier().Expect(9, true).Verify(cq_.get());
 
   EXPECT_TRUE(recv_status.ok());
 }
@@ -918,41 +742,26 @@
   service_->RequestBidiStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(),
                               tag(2));
 
-  Verifier(GetParam().disable_blocking)
-      .Expect(1, true)
-      .Expect(2, true)
-      .Verify(cq_.get());
+  Verifier().Expect(1, true).Expect(2, true).Verify(cq_.get());
 
   cli_stream->Write(send_request, tag(3));
   srv_stream.Read(&recv_request, tag(4));
-  Verifier(GetParam().disable_blocking)
-      .Expect(3, true)
-      .Expect(4, true)
-      .Verify(cq_.get());
+  Verifier().Expect(3, true).Expect(4, true).Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
 
   send_response.set_message(recv_request.message());
   srv_stream.Write(send_response, tag(5));
   cli_stream->Read(&recv_response, tag(6));
-  Verifier(GetParam().disable_blocking)
-      .Expect(5, true)
-      .Expect(6, true)
-      .Verify(cq_.get());
+  Verifier().Expect(5, true).Expect(6, true).Verify(cq_.get());
   EXPECT_EQ(send_response.message(), recv_response.message());
 
   cli_stream->WritesDone(tag(7));
   srv_stream.Read(&recv_request, tag(8));
-  Verifier(GetParam().disable_blocking)
-      .Expect(7, true)
-      .Expect(8, false)
-      .Verify(cq_.get());
+  Verifier().Expect(7, true).Expect(8, false).Verify(cq_.get());
 
   srv_stream.Finish(Status::OK, tag(9));
   cli_stream->Finish(&recv_status, tag(10));
-  Verifier(GetParam().disable_blocking)
-      .Expect(9, true)
-      .Expect(10, true)
-      .Verify(cq_.get());
+  Verifier().Expect(9, true).Expect(10, true).Verify(cq_.get());
 
   EXPECT_TRUE(recv_status.ok());
 }
@@ -982,33 +791,24 @@
 
   bool seen3 = false;
 
-  Verifier(GetParam().disable_blocking)
-      .Expect(2, true)
-      .ExpectMaybe(3, true, &seen3)
-      .Verify(cq_.get());
+  Verifier().Expect(2, true).ExpectMaybe(3, true, &seen3).Verify(cq_.get());
 
   srv_stream.Read(&recv_request, tag(4));
 
-  Verifier(GetParam().disable_blocking)
-      .ExpectUnless(3, true, seen3)
-      .Expect(4, true)
-      .Verify(cq_.get());
+  Verifier().ExpectUnless(3, true, seen3).Expect(4, true).Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
 
   srv_stream.Read(&recv_request, tag(5));
-  Verifier(GetParam().disable_blocking).Expect(5, false).Verify(cq_.get());
+  Verifier().Expect(5, false).Verify(cq_.get());
 
   send_response.set_message(recv_request.message());
   srv_stream.WriteAndFinish(send_response, WriteOptions(), Status::OK, tag(6));
   cli_stream->Read(&recv_response, tag(7));
-  Verifier(GetParam().disable_blocking)
-      .Expect(6, true)
-      .Expect(7, true)
-      .Verify(cq_.get());
+  Verifier().Expect(6, true).Expect(7, true).Verify(cq_.get());
   EXPECT_EQ(send_response.message(), recv_response.message());
 
   cli_stream->Finish(&recv_status, tag(8));
-  Verifier(GetParam().disable_blocking).Expect(8, true).Verify(cq_.get());
+  Verifier().Expect(8, true).Verify(cq_.get());
 
   EXPECT_TRUE(recv_status.ok());
 }
@@ -1038,35 +838,25 @@
 
   bool seen3 = false;
 
-  Verifier(GetParam().disable_blocking)
-      .Expect(2, true)
-      .ExpectMaybe(3, true, &seen3)
-      .Verify(cq_.get());
+  Verifier().Expect(2, true).ExpectMaybe(3, true, &seen3).Verify(cq_.get());
 
   srv_stream.Read(&recv_request, tag(4));
 
-  Verifier(GetParam().disable_blocking)
-      .ExpectUnless(3, true, seen3)
-      .Expect(4, true)
-      .Verify(cq_.get());
+  Verifier().ExpectUnless(3, true, seen3).Expect(4, true).Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
 
   srv_stream.Read(&recv_request, tag(5));
-  Verifier(GetParam().disable_blocking).Expect(5, false).Verify(cq_.get());
+  Verifier().Expect(5, false).Verify(cq_.get());
 
   send_response.set_message(recv_request.message());
   srv_stream.WriteLast(send_response, WriteOptions(), tag(6));
   srv_stream.Finish(Status::OK, tag(7));
   cli_stream->Read(&recv_response, tag(8));
-  Verifier(GetParam().disable_blocking)
-      .Expect(6, true)
-      .Expect(7, true)
-      .Expect(8, true)
-      .Verify(cq_.get());
+  Verifier().Expect(6, true).Expect(7, true).Expect(8, true).Verify(cq_.get());
   EXPECT_EQ(send_response.message(), recv_response.message());
 
   cli_stream->Finish(&recv_status, tag(9));
-  Verifier(GetParam().disable_blocking).Expect(9, true).Verify(cq_.get());
+  Verifier().Expect(9, true).Verify(cq_.get());
 
   EXPECT_TRUE(recv_status.ok());
 }
@@ -1095,10 +885,11 @@
 
   std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
       stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
+  response_reader->Finish(&recv_response, &recv_status, tag(4));
 
   service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
                         cq_.get(), tag(2));
-  Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
+  Verifier().Expect(2, true).Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
   auto client_initial_metadata = srv_ctx.client_metadata();
   EXPECT_EQ(meta1.second,
@@ -1111,11 +902,7 @@
 
   send_response.set_message(recv_request.message());
   response_writer.Finish(send_response, Status::OK, tag(3));
-  response_reader->Finish(&recv_response, &recv_status, tag(4));
-  Verifier(GetParam().disable_blocking)
-      .Expect(3, true)
-      .Expect(4, true)
-      .Verify(cq_.get());
+  Verifier().Expect(3, true).Expect(4, true).Verify(cq_.get());
 
   EXPECT_EQ(send_response.message(), recv_response.message());
   EXPECT_TRUE(recv_status.ok());
@@ -1140,18 +927,16 @@
 
   std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
       stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
+  response_reader->ReadInitialMetadata(tag(4));
 
   service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
                         cq_.get(), tag(2));
-  Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
+  Verifier().Expect(2, true).Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
   srv_ctx.AddInitialMetadata(meta1.first, meta1.second);
   srv_ctx.AddInitialMetadata(meta2.first, meta2.second);
   response_writer.SendInitialMetadata(tag(3));
-  Verifier(GetParam().disable_blocking).Expect(3, true).Verify(cq_.get());
-
-  response_reader->ReadInitialMetadata(tag(4));
-  Verifier(GetParam().disable_blocking).Expect(4, true).Verify(cq_.get());
+  Verifier().Expect(3, true).Expect(4, true).Verify(cq_.get());
   auto server_initial_metadata = cli_ctx.GetServerInitialMetadata();
   EXPECT_EQ(meta1.second,
             ToString(server_initial_metadata.find(meta1.first)->second));
@@ -1162,10 +947,7 @@
   send_response.set_message(recv_request.message());
   response_writer.Finish(send_response, Status::OK, tag(5));
   response_reader->Finish(&recv_response, &recv_status, tag(6));
-  Verifier(GetParam().disable_blocking)
-      .Expect(5, true)
-      .Expect(6, true)
-      .Verify(cq_.get());
+  Verifier().Expect(5, true).Expect(6, true).Verify(cq_.get());
 
   EXPECT_EQ(send_response.message(), recv_response.message());
   EXPECT_TRUE(recv_status.ok());
@@ -1190,24 +972,21 @@
 
   std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
       stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
+  response_reader->Finish(&recv_response, &recv_status, tag(5));
 
   service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
                         cq_.get(), tag(2));
-  Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
+  Verifier().Expect(2, true).Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
   response_writer.SendInitialMetadata(tag(3));
-  Verifier(GetParam().disable_blocking).Expect(3, true).Verify(cq_.get());
+  Verifier().Expect(3, true).Verify(cq_.get());
 
   send_response.set_message(recv_request.message());
   srv_ctx.AddTrailingMetadata(meta1.first, meta1.second);
   srv_ctx.AddTrailingMetadata(meta2.first, meta2.second);
   response_writer.Finish(send_response, Status::OK, tag(4));
-  response_reader->Finish(&recv_response, &recv_status, tag(5));
 
-  Verifier(GetParam().disable_blocking)
-      .Expect(4, true)
-      .Expect(5, true)
-      .Verify(cq_.get());
+  Verifier().Expect(4, true).Expect(5, true).Verify(cq_.get());
 
   EXPECT_EQ(send_response.message(), recv_response.message());
   EXPECT_TRUE(recv_status.ok());
@@ -1253,10 +1032,11 @@
 
   std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
       stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
+  response_reader->ReadInitialMetadata(tag(4));
 
   service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
                         cq_.get(), tag(2));
-  Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
+  Verifier().Expect(2, true).Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
   auto client_initial_metadata = srv_ctx.client_metadata();
   EXPECT_EQ(meta1.second,
@@ -1268,9 +1048,7 @@
   srv_ctx.AddInitialMetadata(meta3.first, meta3.second);
   srv_ctx.AddInitialMetadata(meta4.first, meta4.second);
   response_writer.SendInitialMetadata(tag(3));
-  Verifier(GetParam().disable_blocking).Expect(3, true).Verify(cq_.get());
-  response_reader->ReadInitialMetadata(tag(4));
-  Verifier(GetParam().disable_blocking).Expect(4, true).Verify(cq_.get());
+  Verifier().Expect(3, true).Expect(4, true).Verify(cq_.get());
   auto server_initial_metadata = cli_ctx.GetServerInitialMetadata();
   EXPECT_EQ(meta3.second,
             ToString(server_initial_metadata.find(meta3.first)->second));
@@ -1284,10 +1062,7 @@
   response_writer.Finish(send_response, Status::OK, tag(5));
   response_reader->Finish(&recv_response, &recv_status, tag(6));
 
-  Verifier(GetParam().disable_blocking)
-      .Expect(5, true)
-      .Expect(6, true)
-      .Verify(cq_.get());
+  Verifier().Expect(5, true).Expect(6, true).Verify(cq_.get());
 
   EXPECT_EQ(send_response.message(), recv_response.message());
   EXPECT_TRUE(recv_status.ok());
@@ -1316,21 +1091,19 @@
   send_request.set_message(GetParam().message_content);
   std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
       stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
+  response_reader->Finish(&recv_response, &recv_status, tag(4));
 
   srv_ctx.AsyncNotifyWhenDone(tag(5));
   service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
                         cq_.get(), tag(2));
 
-  Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
+  Verifier().Expect(2, true).Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
 
   cli_ctx.TryCancel();
-  Verifier(GetParam().disable_blocking).Expect(5, true).Verify(cq_.get());
+  Verifier().Expect(5, true).Expect(4, true).Verify(cq_.get());
   EXPECT_TRUE(srv_ctx.IsCancelled());
 
-  response_reader->Finish(&recv_response, &recv_status, tag(4));
-  Verifier(GetParam().disable_blocking).Expect(4, true).Verify(cq_.get());
-
   EXPECT_EQ(StatusCode::CANCELLED, recv_status.error_code());
 }
 
@@ -1351,22 +1124,18 @@
   send_request.set_message(GetParam().message_content);
   std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
       stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
+  response_reader->Finish(&recv_response, &recv_status, tag(4));
 
   srv_ctx.AsyncNotifyWhenDone(tag(5));
   service_->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
                         cq_.get(), tag(2));
 
-  Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
+  Verifier().Expect(2, true).Verify(cq_.get());
   EXPECT_EQ(send_request.message(), recv_request.message());
 
   send_response.set_message(recv_request.message());
   response_writer.Finish(send_response, Status::OK, tag(3));
-  response_reader->Finish(&recv_response, &recv_status, tag(4));
-  Verifier(GetParam().disable_blocking)
-      .Expect(3, true)
-      .Expect(4, true)
-      .Expect(5, true)
-      .Verify(cq_.get());
+  Verifier().Expect(3, true).Expect(4, true).Expect(5, true).Verify(cq_.get());
   EXPECT_FALSE(srv_ctx.IsCancelled());
 
   EXPECT_EQ(send_response.message(), recv_response.message());
@@ -1393,7 +1162,7 @@
       stub->AsyncUnimplemented(&cli_ctx, send_request, cq_.get()));
 
   response_reader->Finish(&recv_response, &recv_status, tag(4));
-  Verifier(GetParam().disable_blocking).Expect(4, true).Verify(cq_.get());
+  Verifier().Expect(4, true).Verify(cq_.get());
 
   EXPECT_EQ(StatusCode::UNIMPLEMENTED, recv_status.error_code());
   EXPECT_EQ("", recv_status.error_message());
@@ -1447,10 +1216,8 @@
     srv_ctx.AsyncNotifyWhenDone(tag(11));
     service_->RequestRequestStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(),
                                    tag(2));
-    std::thread t1([this, &cli_cq] {
-      Verifier(GetParam().disable_blocking).Expect(1, true).Verify(&cli_cq);
-    });
-    Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
+    std::thread t1([&cli_cq] { Verifier().Expect(1, true).Verify(&cli_cq); });
+    Verifier().Expect(2, true).Verify(cq_.get());
     t1.join();
 
     bool expected_server_cq_result = true;
@@ -1458,7 +1225,7 @@
 
     if (server_try_cancel == CANCEL_BEFORE_PROCESSING) {
       srv_ctx.TryCancel();
-      Verifier(GetParam().disable_blocking).Expect(11, true).Verify(cq_.get());
+      Verifier().Expect(11, true).Verify(cq_.get());
       EXPECT_TRUE(srv_ctx.IsCancelled());
 
       // Since cancellation is done before server reads any results, we know
@@ -1473,19 +1240,19 @@
         (server_try_cancel == CANCEL_BEFORE_PROCESSING);
 
     std::thread cli_thread([&cli_cq, &cli_stream, &expected_client_cq_result,
-                            &ignore_client_cq_result, this] {
+                            &ignore_client_cq_result] {
       EchoRequest send_request;
       // Client sends 3 messages (tags 3, 4 and 5)
       for (int tag_idx = 3; tag_idx <= 5; tag_idx++) {
         send_request.set_message("Ping " + grpc::to_string(tag_idx));
         cli_stream->Write(send_request, tag(tag_idx));
-        Verifier(GetParam().disable_blocking)
+        Verifier()
             .Expect(tag_idx, expected_client_cq_result)
             .Verify(&cli_cq, ignore_client_cq_result);
       }
       cli_stream->WritesDone(tag(6));
       // Ignore ok on WritesDone since cancel can affect it
-      Verifier(GetParam().disable_blocking)
+      Verifier()
           .Expect(6, expected_client_cq_result)
           .Verify(&cli_cq, ignore_client_cq_result);
     });
@@ -1494,7 +1261,7 @@
     bool want_done_tag = false;
     std::thread* server_try_cancel_thd = nullptr;
 
-    auto verif = Verifier(GetParam().disable_blocking);
+    auto verif = Verifier();
 
     if (server_try_cancel == CANCEL_DURING_PROCESSING) {
       server_try_cancel_thd =
@@ -1554,11 +1321,11 @@
     // Server sends the final message and cancelled status (but the RPC is
     // already cancelled at this point. So we expect the operation to fail)
     srv_stream.Finish(send_response, Status::CANCELLED, tag(9));
-    Verifier(GetParam().disable_blocking).Expect(9, false).Verify(cq_.get());
+    Verifier().Expect(9, false).Verify(cq_.get());
 
     // Client will see the cancellation
     cli_stream->Finish(&recv_status, tag(10));
-    Verifier(GetParam().disable_blocking).Expect(10, true).Verify(&cli_cq);
+    Verifier().Expect(10, true).Verify(&cli_cq);
     EXPECT_FALSE(recv_status.ok());
     EXPECT_EQ(::grpc::StatusCode::CANCELLED, recv_status.error_code());
 
@@ -1604,10 +1371,8 @@
     service_->RequestResponseStream(&srv_ctx, &recv_request, &srv_stream,
                                     cq_.get(), cq_.get(), tag(2));
 
-    std::thread t1([this, &cli_cq] {
-      Verifier(GetParam().disable_blocking).Expect(1, true).Verify(&cli_cq);
-    });
-    Verifier(GetParam().disable_blocking).Expect(2, true).Verify(cq_.get());
+    std::thread t1([&cli_cq] { Verifier().Expect(1, true).Verify(&cli_cq); });
+    Verifier().Expect(2, true).Verify(cq_.get());
     t1.join();
 
     EXPECT_EQ(send_request.message(), recv_request.message());
@@ -1621,7 +1386,7 @@
 
     if (server_try_cancel == CANCEL_BEFORE_PROCESSING) {
       srv_ctx.TryCancel();
-      Verifier(GetParam().disable_blocking).Expect(11, true).Verify(cq_.get());
+      Verifier().Expect(11, true).Verify(cq_.get());
       EXPECT_TRUE(srv_ctx.IsCancelled());
 
       // We know for sure that all cq results will be false from this point
@@ -1631,12 +1396,12 @@
     }
 
     std::thread cli_thread([&cli_cq, &cli_stream, &expected_client_cq_result,
-                            &ignore_client_cq_result, this] {
+                            &ignore_client_cq_result] {
       // Client attempts to read the three messages from the server
       for (int tag_idx = 6; tag_idx <= 8; tag_idx++) {
         EchoResponse recv_response;
         cli_stream->Read(&recv_response, tag(tag_idx));
-        Verifier(GetParam().disable_blocking)
+        Verifier()
             .Expect(tag_idx, expected_client_cq_result)
             .Verify(&cli_cq, ignore_client_cq_result);
       }
@@ -1644,7 +1409,7 @@
 
     std::thread* server_try_cancel_thd = nullptr;
 
-    auto verif = Verifier(GetParam().disable_blocking);
+    auto verif = Verifier();
 
     if (server_try_cancel == CANCEL_DURING_PROCESSING) {
       server_try_cancel_thd =
@@ -1705,11 +1470,11 @@
 
     // Server finishes the stream (but the RPC is already cancelled)
     srv_stream.Finish(Status::CANCELLED, tag(9));
-    Verifier(GetParam().disable_blocking).Expect(9, false).Verify(cq_.get());
+    Verifier().Expect(9, false).Verify(cq_.get());
 
     // Client will see the cancellation
     cli_stream->Finish(&recv_status, tag(10));
-    Verifier(GetParam().disable_blocking).Expect(10, true).Verify(&cli_cq);
+    Verifier().Expect(10, true).Verify(&cli_cq);
     EXPECT_FALSE(recv_status.ok());
     EXPECT_EQ(::grpc::StatusCode::CANCELLED, recv_status.error_code());
 
@@ -1756,12 +1521,9 @@
     srv_ctx.AsyncNotifyWhenDone(tag(11));
     service_->RequestBidiStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(),
                                 tag(2));
-    Verifier(GetParam().disable_blocking)
-        .Expect(1, true)
-        .Expect(2, true)
-        .Verify(cq_.get());
+    Verifier().Expect(1, true).Expect(2, true).Verify(cq_.get());
 
-    auto verif = Verifier(GetParam().disable_blocking);
+    auto verif = Verifier();
 
     // Client sends the first and the only message
     send_request.set_message("Ping");
@@ -1901,10 +1663,10 @@
     // know that cq results are supposed to return false on server.
 
     srv_stream.Finish(Status::CANCELLED, tag(9));
-    Verifier(GetParam().disable_blocking).Expect(9, false).Verify(cq_.get());
+    Verifier().Expect(9, false).Verify(cq_.get());
 
     cli_stream->Finish(&recv_status, tag(10));
-    Verifier(GetParam().disable_blocking).Expect(10, true).Verify(cq_.get());
+    Verifier().Expect(10, true).Verify(cq_.get());
     EXPECT_FALSE(recv_status.ok());
     EXPECT_EQ(grpc::StatusCode::CANCELLED, recv_status.error_code());
   }
@@ -1946,8 +1708,7 @@
   TestBidiStreamingServerCancel(CANCEL_AFTER_PROCESSING);
 }
 
-std::vector<TestScenario> CreateTestScenarios(bool test_disable_blocking,
-                                              bool test_secure,
+std::vector<TestScenario> CreateTestScenarios(bool test_secure,
                                               int test_big_limit) {
   std::vector<TestScenario> scenarios;
   std::vector<grpc::string> credentials_types;
@@ -1985,14 +1746,10 @@
     for (auto msg = messages.begin(); msg != messages.end(); msg++) {
       for (auto cred = credentials_types.begin();
            cred != credentials_types.end(); ++cred) {
-        scenarios.emplace_back(false, false, *cred, health_check_service, *msg);
-        if (test_disable_blocking) {
-          scenarios.emplace_back(true, false, *cred, health_check_service,
-                                 *msg);
-        }
+        scenarios.emplace_back(false, *cred, health_check_service, *msg);
       }
       if (insec_ok()) {
-        scenarios.emplace_back(false, true, kInsecureCredentialsType,
+        scenarios.emplace_back(true, kInsecureCredentialsType,
                                health_check_service, *msg);
       }
     }
@@ -2001,12 +1758,10 @@
 }
 
 INSTANTIATE_TEST_CASE_P(AsyncEnd2end, AsyncEnd2endTest,
-                        ::testing::ValuesIn(CreateTestScenarios(true, true,
-                                                                1024)));
+                        ::testing::ValuesIn(CreateTestScenarios(true, 1024)));
 INSTANTIATE_TEST_CASE_P(AsyncEnd2endServerTryCancel,
                         AsyncEnd2endServerTryCancelTest,
-                        ::testing::ValuesIn(CreateTestScenarios(false, false,
-                                                                0)));
+                        ::testing::ValuesIn(CreateTestScenarios(false, 0)));
 
 }  // namespace
 }  // namespace testing
@@ -2017,9 +1772,7 @@
   // ReconnectChannel test
   gpr_setenv("GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS", "100");
   grpc_test_init(argc, argv);
-  gpr_tls_init(&g_is_async_end2end_test);
   ::testing::InitGoogleTest(&argc, argv);
   int ret = RUN_ALL_TESTS();
-  gpr_tls_destroy(&g_is_async_end2end_test);
   return ret;
 }
diff --git a/test/cpp/end2end/client_crash_test.cc b/test/cpp/end2end/client_crash_test.cc
index f34b275..2a06f44 100644
--- a/test/cpp/end2end/client_crash_test.cc
+++ b/test/cpp/end2end/client_crash_test.cc
@@ -16,16 +16,15 @@
  *
  */
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
 
 #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
diff --git a/test/cpp/end2end/client_crash_test_server.cc b/test/cpp/end2end/client_crash_test_server.cc
index 887504d..cb4afd7 100644
--- a/test/cpp/end2end/client_crash_test_server.cc
+++ b/test/cpp/end2end/client_crash_test_server.cc
@@ -21,10 +21,10 @@
 #include <memory>
 #include <string>
 
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
 #include <grpc/support/log.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
 
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
 
diff --git a/test/cpp/end2end/client_lb_end2end_test.cc b/test/cpp/end2end/client_lb_end2end_test.cc
index b85e286..a39e443 100644
--- a/test/cpp/end2end/client_lb_end2end_test.cc
+++ b/test/cpp/end2end/client_lb_end2end_test.cc
@@ -22,23 +22,25 @@
 #include <random>
 #include <thread>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/atm.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
 
 #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
 #include "src/core/ext/filters/client_channel/subchannel_index.h"
 #include "src/core/lib/backoff/backoff.h"
 #include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gprpp/debug_location.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
+#include "src/core/lib/iomgr/tcp_client.h"
 
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
 #include "test/core/util/port.h"
@@ -51,13 +53,10 @@
 using grpc::testing::EchoResponse;
 using std::chrono::system_clock;
 
-// defined in tcp_client_posix.c
-extern void (*grpc_tcp_client_connect_impl)(
-    grpc_closure* closure, grpc_endpoint** ep,
-    grpc_pollset_set* interested_parties, const grpc_channel_args* channel_args,
-    const grpc_resolved_address* addr, grpc_millis deadline);
+// defined in tcp_client.cc
+extern grpc_tcp_client_vtable* grpc_tcp_client_impl;
 
-const auto original_tcp_connect_fn = grpc_tcp_client_connect_impl;
+static grpc_tcp_client_vtable* default_client_impl;
 
 namespace grpc {
 namespace testing {
@@ -74,10 +73,12 @@
   if (delay_ms > 0) {
     gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(delay_ms));
   }
-  original_tcp_connect_fn(closure, ep, interested_parties, channel_args, addr,
-                          deadline + delay_ms);
+  default_client_impl->connect(closure, ep, interested_parties, channel_args,
+                               addr, deadline + delay_ms);
 }
 
+grpc_tcp_client_vtable delayed_connect = {tcp_client_connect_with_delay};
+
 // Subclass of TestServiceImpl that increments a request counter for
 // every call to the Echo RPC.
 class MyTestServiceImpl : public TestServiceImpl {
@@ -118,11 +119,11 @@
   }
 
   void SetUp() override {
-    response_generator_ = grpc_fake_resolver_response_generator_create();
+    response_generator_ =
+        grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
   }
 
   void TearDown() override {
-    grpc_fake_resolver_response_generator_unref(response_generator_);
     for (size_t i = 0; i < servers_.size(); ++i) {
       servers_[i]->Shutdown();
     }
@@ -137,8 +138,7 @@
     }
   }
 
-  void SetNextResolution(const std::vector<int>& ports) {
-    grpc_core::ExecCtx exec_ctx;
+  grpc_channel_args* BuildFakeResults(const std::vector<int>& ports) {
     grpc_lb_addresses* addresses =
         grpc_lb_addresses_create(ports.size(), nullptr);
     for (size_t i = 0; i < ports.size(); ++i) {
@@ -154,12 +154,24 @@
     }
     const grpc_arg fake_addresses =
         grpc_lb_addresses_create_channel_arg(addresses);
-    grpc_channel_args* fake_result =
+    grpc_channel_args* fake_results =
         grpc_channel_args_copy_and_add(nullptr, &fake_addresses, 1);
-    grpc_fake_resolver_response_generator_set_response(response_generator_,
-                                                       fake_result);
-    grpc_channel_args_destroy(fake_result);
     grpc_lb_addresses_destroy(addresses);
+    return fake_results;
+  }
+
+  void SetNextResolution(const std::vector<int>& ports) {
+    grpc_core::ExecCtx exec_ctx;
+    grpc_channel_args* fake_results = BuildFakeResults(ports);
+    response_generator_->SetResponse(fake_results);
+    grpc_channel_args_destroy(fake_results);
+  }
+
+  void SetNextResolutionUponError(const std::vector<int>& ports) {
+    grpc_core::ExecCtx exec_ctx;
+    grpc_channel_args* fake_results = BuildFakeResults(ports);
+    response_generator_->SetReresolutionResponse(fake_results);
+    grpc_channel_args_destroy(fake_results);
   }
 
   std::vector<int> GetServersPorts() {
@@ -168,38 +180,51 @@
     return ports;
   }
 
-  void ResetStub(const grpc::string& lb_policy_name,
-                 ChannelArguments args = ChannelArguments()) {
+  std::unique_ptr<grpc::testing::EchoTestService::Stub> BuildStub(
+      const std::shared_ptr<Channel>& channel) {
+    return grpc::testing::EchoTestService::NewStub(channel);
+  }
+
+  std::shared_ptr<Channel> BuildChannel(
+      const grpc::string& lb_policy_name,
+      ChannelArguments args = ChannelArguments()) {
     if (lb_policy_name.size() > 0) {
       args.SetLoadBalancingPolicyName(lb_policy_name);
     }  // else, default to pick first
     args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR,
-                    response_generator_);
-    channel_ =
-        CreateCustomChannel("fake:///", InsecureChannelCredentials(), args);
-    stub_ = grpc::testing::EchoTestService::NewStub(channel_);
+                    response_generator_.get());
+    return CreateCustomChannel("fake:///", InsecureChannelCredentials(), args);
   }
 
-  bool SendRpc(EchoResponse* response = nullptr) {
+  bool SendRpc(
+      const std::unique_ptr<grpc::testing::EchoTestService::Stub>& stub,
+      EchoResponse* response = nullptr, int timeout_ms = 1000) {
     const bool local_response = (response == nullptr);
     if (local_response) response = new EchoResponse;
     EchoRequest request;
     request.set_message(kRequestMessage_);
     ClientContext context;
-    Status status = stub_->Echo(&context, request, response);
+    context.set_deadline(grpc_timeout_milliseconds_to_deadline(timeout_ms));
+    Status status = stub->Echo(&context, request, response);
     if (local_response) delete response;
     return status.ok();
   }
 
-  void CheckRpcSendOk() {
+  void CheckRpcSendOk(
+      const std::unique_ptr<grpc::testing::EchoTestService::Stub>& stub,
+      const grpc_core::DebugLocation& location) {
     EchoResponse response;
-    const bool success = SendRpc(&response);
-    EXPECT_TRUE(success);
-    EXPECT_EQ(response.message(), kRequestMessage_);
+    const bool success = SendRpc(stub, &response);
+    if (!success) abort();
+    ASSERT_TRUE(success) << "From " << location.file() << ":"
+                         << location.line();
+    ASSERT_EQ(response.message(), kRequestMessage_)
+        << "From " << location.file() << ":" << location.line();
   }
 
-  void CheckRpcSendFailure() {
-    const bool success = SendRpc();
+  void CheckRpcSendFailure(
+      const std::unique_ptr<grpc::testing::EchoTestService::Stub>& stub) {
+    const bool success = SendRpc(stub);
     EXPECT_FALSE(success);
   }
 
@@ -238,7 +263,7 @@
     }
 
     void Shutdown(bool join = true) {
-      server_->Shutdown();
+      server_->Shutdown(grpc_timeout_milliseconds_to_deadline(0));
       if (join) thread_->join();
     }
   };
@@ -247,9 +272,11 @@
     for (const auto& server : servers_) server->service_.ResetCounters();
   }
 
-  void WaitForServer(size_t server_idx) {
+  void WaitForServer(
+      const std::unique_ptr<grpc::testing::EchoTestService::Stub>& stub,
+      size_t server_idx, const grpc_core::DebugLocation& location) {
     do {
-      CheckRpcSendOk();
+      CheckRpcSendOk(stub, location);
     } while (servers_[server_idx]->service_.request_count() == 0);
     ResetCounters();
   }
@@ -280,10 +307,10 @@
   }
 
   const grpc::string server_host_;
-  std::shared_ptr<Channel> channel_;
   std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
   std::vector<std::unique_ptr<ServerData>> servers_;
-  grpc_fake_resolver_response_generator* response_generator_;
+  grpc_core::RefCountedPtr<grpc_core::FakeResolverResponseGenerator>
+      response_generator_;
   const grpc::string kRequestMessage_;
 };
 
@@ -291,14 +318,15 @@
   // Start servers and send one RPC per server.
   const int kNumServers = 3;
   StartServers(kNumServers);
-  ResetStub("");  // test that pick first is the default.
+  auto channel = BuildChannel("");  // test that pick first is the default.
+  auto stub = BuildStub(channel);
   std::vector<int> ports;
   for (size_t i = 0; i < servers_.size(); ++i) {
     ports.emplace_back(servers_[i]->port_);
   }
   SetNextResolution(ports);
   for (size_t i = 0; i < servers_.size(); ++i) {
-    CheckRpcSendOk();
+    CheckRpcSendOk(stub, DEBUG_LOCATION);
   }
   // All requests should have gone to a single server.
   bool found = false;
@@ -312,7 +340,7 @@
   }
   EXPECT_TRUE(found);
   // Check LB policy name for the channel.
-  EXPECT_EQ("pick_first", channel_->GetLoadBalancingPolicyName());
+  EXPECT_EQ("pick_first", channel->GetLoadBalancingPolicyName());
 }
 
 TEST_F(ClientLbEnd2endTest, PickFirstBackOffInitialReconnect) {
@@ -321,15 +349,16 @@
   args.SetInt(GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS, kInitialBackOffMs);
   const std::vector<int> ports = {grpc_pick_unused_port_or_die()};
   const gpr_timespec t0 = gpr_now(GPR_CLOCK_MONOTONIC);
-  ResetStub("pick_first", args);
+  auto channel = BuildChannel("pick_first", args);
+  auto stub = BuildStub(channel);
   SetNextResolution(ports);
   // The channel won't become connected (there's no server).
-  ASSERT_FALSE(channel_->WaitForConnected(
+  ASSERT_FALSE(channel->WaitForConnected(
       grpc_timeout_milliseconds_to_deadline(kInitialBackOffMs * 2)));
   // Bring up a server on the chosen port.
   StartServers(1, ports);
   // Now it will.
-  ASSERT_TRUE(channel_->WaitForConnected(
+  ASSERT_TRUE(channel->WaitForConnected(
       grpc_timeout_milliseconds_to_deadline(kInitialBackOffMs * 2)));
   const gpr_timespec t1 = gpr_now(GPR_CLOCK_MONOTONIC);
   const grpc_millis waited_ms = gpr_time_to_millis(gpr_time_sub(t1, t0));
@@ -349,14 +378,16 @@
   constexpr int kMinReconnectBackOffMs = 1000;
   args.SetInt(GRPC_ARG_MIN_RECONNECT_BACKOFF_MS, kMinReconnectBackOffMs);
   const std::vector<int> ports = {grpc_pick_unused_port_or_die()};
-  ResetStub("pick_first", args);
+  auto channel = BuildChannel("pick_first", args);
+  auto stub = BuildStub(channel);
   SetNextResolution(ports);
   // Make connection delay a 10% longer than it's willing to in order to make
   // sure we are hitting the codepath that waits for the min reconnect backoff.
   gpr_atm_rel_store(&g_connection_delay_ms, kMinReconnectBackOffMs * 1.10);
-  grpc_tcp_client_connect_impl = tcp_client_connect_with_delay;
+  default_client_impl = grpc_tcp_client_impl;
+  grpc_set_tcp_client_impl(&delayed_connect);
   const gpr_timespec t0 = gpr_now(GPR_CLOCK_MONOTONIC);
-  channel_->WaitForConnected(
+  channel->WaitForConnected(
       grpc_timeout_milliseconds_to_deadline(kMinReconnectBackOffMs * 2));
   const gpr_timespec t1 = gpr_now(GPR_CLOCK_MONOTONIC);
   const grpc_millis waited_ms = gpr_time_to_millis(gpr_time_sub(t1, t0));
@@ -371,14 +402,16 @@
   // Start servers and send one RPC per server.
   const int kNumServers = 3;
   StartServers(kNumServers);
-  ResetStub("pick_first");
+  auto channel = BuildChannel("pick_first");
+  auto stub = BuildStub(channel);
+
   std::vector<int> ports;
 
   // Perform one RPC against the first server.
   ports.emplace_back(servers_[0]->port_);
   SetNextResolution(ports);
   gpr_log(GPR_INFO, "****** SET [0] *******");
-  CheckRpcSendOk();
+  CheckRpcSendOk(stub, DEBUG_LOCATION);
   EXPECT_EQ(servers_[0]->service_.request_count(), 1);
 
   // An empty update will result in the channel going into TRANSIENT_FAILURE.
@@ -387,7 +420,7 @@
   gpr_log(GPR_INFO, "****** SET none *******");
   grpc_connectivity_state channel_state;
   do {
-    channel_state = channel_->GetState(true /* try to connect */);
+    channel_state = channel->GetState(true /* try to connect */);
   } while (channel_state == GRPC_CHANNEL_READY);
   GPR_ASSERT(channel_state != GRPC_CHANNEL_READY);
   servers_[0]->service_.ResetCounters();
@@ -397,7 +430,7 @@
   ports.emplace_back(servers_[1]->port_);
   SetNextResolution(ports);
   gpr_log(GPR_INFO, "****** SET [1] *******");
-  WaitForServer(1);
+  WaitForServer(stub, 1, DEBUG_LOCATION);
   EXPECT_EQ(servers_[0]->service_.request_count(), 0);
 
   // And again for servers_[2]
@@ -405,26 +438,28 @@
   ports.emplace_back(servers_[2]->port_);
   SetNextResolution(ports);
   gpr_log(GPR_INFO, "****** SET [2] *******");
-  WaitForServer(2);
+  WaitForServer(stub, 2, DEBUG_LOCATION);
   EXPECT_EQ(servers_[0]->service_.request_count(), 0);
   EXPECT_EQ(servers_[1]->service_.request_count(), 0);
 
   // Check LB policy name for the channel.
-  EXPECT_EQ("pick_first", channel_->GetLoadBalancingPolicyName());
+  EXPECT_EQ("pick_first", channel->GetLoadBalancingPolicyName());
 }
 
 TEST_F(ClientLbEnd2endTest, PickFirstUpdateSuperset) {
   // Start servers and send one RPC per server.
   const int kNumServers = 3;
   StartServers(kNumServers);
-  ResetStub("pick_first");
+  auto channel = BuildChannel("pick_first");
+  auto stub = BuildStub(channel);
+
   std::vector<int> ports;
 
   // Perform one RPC against the first server.
   ports.emplace_back(servers_[0]->port_);
   SetNextResolution(ports);
   gpr_log(GPR_INFO, "****** SET [0] *******");
-  CheckRpcSendOk();
+  CheckRpcSendOk(stub, DEBUG_LOCATION);
   EXPECT_EQ(servers_[0]->service_.request_count(), 1);
   servers_[0]->service_.ResetCounters();
 
@@ -434,20 +469,21 @@
   ports.emplace_back(servers_[0]->port_);
   SetNextResolution(ports);
   gpr_log(GPR_INFO, "****** SET superset *******");
-  CheckRpcSendOk();
+  CheckRpcSendOk(stub, DEBUG_LOCATION);
   // We stick to the previously connected server.
-  WaitForServer(0);
+  WaitForServer(stub, 0, DEBUG_LOCATION);
   EXPECT_EQ(0, servers_[1]->service_.request_count());
 
   // Check LB policy name for the channel.
-  EXPECT_EQ("pick_first", channel_->GetLoadBalancingPolicyName());
+  EXPECT_EQ("pick_first", channel->GetLoadBalancingPolicyName());
 }
 
 TEST_F(ClientLbEnd2endTest, PickFirstManyUpdates) {
   // Start servers and send one RPC per server.
   const int kNumServers = 3;
   StartServers(kNumServers);
-  ResetStub("pick_first");
+  auto channel = BuildChannel("pick_first");
+  auto stub = BuildStub(channel);
   std::vector<int> ports;
   for (size_t i = 0; i < servers_.size(); ++i) {
     ports.emplace_back(servers_[i]->port_);
@@ -459,18 +495,19 @@
       std::shuffle(ports.begin(), ports.end(),
                    std::mt19937(std::random_device()()));
       SetNextResolution(ports);
-      if (i % 10 == 0) CheckRpcSendOk();
+      if (i % 10 == 0) CheckRpcSendOk(stub, DEBUG_LOCATION);
     }
   }
   // Check LB policy name for the channel.
-  EXPECT_EQ("pick_first", channel_->GetLoadBalancingPolicyName());
+  EXPECT_EQ("pick_first", channel->GetLoadBalancingPolicyName());
 }
 
 TEST_F(ClientLbEnd2endTest, RoundRobin) {
   // Start servers and send one RPC per server.
   const int kNumServers = 3;
   StartServers(kNumServers);
-  ResetStub("round_robin");
+  auto channel = BuildChannel("round_robin");
+  auto stub = BuildStub(channel);
   std::vector<int> ports;
   for (const auto& server : servers_) {
     ports.emplace_back(server->port_);
@@ -478,15 +515,15 @@
   SetNextResolution(ports);
   // Wait until all backends are ready.
   do {
-    CheckRpcSendOk();
+    CheckRpcSendOk(stub, DEBUG_LOCATION);
   } while (!SeenAllServers());
   ResetCounters();
   // "Sync" to the end of the list. Next sequence of picks will start at the
   // first server (index 0).
-  WaitForServer(servers_.size() - 1);
+  WaitForServer(stub, servers_.size() - 1, DEBUG_LOCATION);
   std::vector<int> connection_order;
   for (size_t i = 0; i < servers_.size(); ++i) {
-    CheckRpcSendOk();
+    CheckRpcSendOk(stub, DEBUG_LOCATION);
     UpdateConnectionOrder(servers_, &connection_order);
   }
   // Backends should be iterated over in the order in which the addresses were
@@ -494,22 +531,23 @@
   const auto expected = std::vector<int>{0, 1, 2};
   EXPECT_EQ(expected, connection_order);
   // Check LB policy name for the channel.
-  EXPECT_EQ("round_robin", channel_->GetLoadBalancingPolicyName());
+  EXPECT_EQ("round_robin", channel->GetLoadBalancingPolicyName());
 }
 
 TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) {
   // Start servers and send one RPC per server.
   const int kNumServers = 3;
   StartServers(kNumServers);
-  ResetStub("round_robin");
+  auto channel = BuildChannel("round_robin");
+  auto stub = BuildStub(channel);
   std::vector<int> ports;
 
   // Start with a single server.
   ports.emplace_back(servers_[0]->port_);
   SetNextResolution(ports);
-  WaitForServer(0);
+  WaitForServer(stub, 0, DEBUG_LOCATION);
   // Send RPCs. They should all go servers_[0]
-  for (size_t i = 0; i < 10; ++i) CheckRpcSendOk();
+  for (size_t i = 0; i < 10; ++i) CheckRpcSendOk(stub, DEBUG_LOCATION);
   EXPECT_EQ(10, servers_[0]->service_.request_count());
   EXPECT_EQ(0, servers_[1]->service_.request_count());
   EXPECT_EQ(0, servers_[2]->service_.request_count());
@@ -523,9 +561,9 @@
   // Wait until update has been processed, as signaled by the second backend
   // receiving a request.
   EXPECT_EQ(0, servers_[1]->service_.request_count());
-  WaitForServer(1);
+  WaitForServer(stub, 1, DEBUG_LOCATION);
 
-  for (size_t i = 0; i < 10; ++i) CheckRpcSendOk();
+  for (size_t i = 0; i < 10; ++i) CheckRpcSendOk(stub, DEBUG_LOCATION);
   EXPECT_EQ(0, servers_[0]->service_.request_count());
   EXPECT_EQ(10, servers_[1]->service_.request_count());
   EXPECT_EQ(0, servers_[2]->service_.request_count());
@@ -535,9 +573,9 @@
   ports.clear();
   ports.emplace_back(servers_[2]->port_);
   SetNextResolution(ports);
-  WaitForServer(2);
+  WaitForServer(stub, 2, DEBUG_LOCATION);
 
-  for (size_t i = 0; i < 10; ++i) CheckRpcSendOk();
+  for (size_t i = 0; i < 10; ++i) CheckRpcSendOk(stub, DEBUG_LOCATION);
   EXPECT_EQ(0, servers_[0]->service_.request_count());
   EXPECT_EQ(0, servers_[1]->service_.request_count());
   EXPECT_EQ(10, servers_[2]->service_.request_count());
@@ -549,12 +587,12 @@
   ports.emplace_back(servers_[1]->port_);
   ports.emplace_back(servers_[2]->port_);
   SetNextResolution(ports);
-  WaitForServer(0);
-  WaitForServer(1);
-  WaitForServer(2);
+  WaitForServer(stub, 0, DEBUG_LOCATION);
+  WaitForServer(stub, 1, DEBUG_LOCATION);
+  WaitForServer(stub, 2, DEBUG_LOCATION);
 
   // Send three RPCs, one per server.
-  for (size_t i = 0; i < 3; ++i) CheckRpcSendOk();
+  for (size_t i = 0; i < 3; ++i) CheckRpcSendOk(stub, DEBUG_LOCATION);
   EXPECT_EQ(1, servers_[0]->service_.request_count());
   EXPECT_EQ(1, servers_[1]->service_.request_count());
   EXPECT_EQ(1, servers_[2]->service_.request_count());
@@ -564,7 +602,7 @@
   SetNextResolution(ports);
   grpc_connectivity_state channel_state;
   do {
-    channel_state = channel_->GetState(true /* try to connect */);
+    channel_state = channel->GetState(true /* try to connect */);
   } while (channel_state == GRPC_CHANNEL_READY);
   GPR_ASSERT(channel_state != GRPC_CHANNEL_READY);
   servers_[0]->service_.ResetCounters();
@@ -573,26 +611,27 @@
   ports.clear();
   ports.emplace_back(servers_[1]->port_);
   SetNextResolution(ports);
-  WaitForServer(1);
-  channel_state = channel_->GetState(false /* try to connect */);
+  WaitForServer(stub, 1, DEBUG_LOCATION);
+  channel_state = channel->GetState(false /* try to connect */);
   GPR_ASSERT(channel_state == GRPC_CHANNEL_READY);
 
   // Check LB policy name for the channel.
-  EXPECT_EQ("round_robin", channel_->GetLoadBalancingPolicyName());
+  EXPECT_EQ("round_robin", channel->GetLoadBalancingPolicyName());
 }
 
 TEST_F(ClientLbEnd2endTest, RoundRobinUpdateInError) {
   const int kNumServers = 3;
   StartServers(kNumServers);
-  ResetStub("round_robin");
+  auto channel = BuildChannel("round_robin");
+  auto stub = BuildStub(channel);
   std::vector<int> ports;
 
   // Start with a single server.
   ports.emplace_back(servers_[0]->port_);
   SetNextResolution(ports);
-  WaitForServer(0);
+  WaitForServer(stub, 0, DEBUG_LOCATION);
   // Send RPCs. They should all go to servers_[0]
-  for (size_t i = 0; i < 10; ++i) SendRpc();
+  for (size_t i = 0; i < 10; ++i) SendRpc(stub);
   EXPECT_EQ(10, servers_[0]->service_.request_count());
   EXPECT_EQ(0, servers_[1]->service_.request_count());
   EXPECT_EQ(0, servers_[2]->service_.request_count());
@@ -603,11 +642,11 @@
   ports.emplace_back(servers_[1]->port_);
   ports.emplace_back(servers_[2]->port_);
   SetNextResolution(ports);
-  WaitForServer(0);
-  WaitForServer(2);
+  WaitForServer(stub, 0, DEBUG_LOCATION);
+  WaitForServer(stub, 2, DEBUG_LOCATION);
 
   // Send three RPCs, one per server.
-  for (size_t i = 0; i < kNumServers; ++i) SendRpc();
+  for (size_t i = 0; i < kNumServers; ++i) SendRpc(stub);
   // The server in shutdown shouldn't receive any.
   EXPECT_EQ(0, servers_[1]->service_.request_count());
 }
@@ -616,7 +655,8 @@
   // Start servers and send one RPC per server.
   const int kNumServers = 3;
   StartServers(kNumServers);
-  ResetStub("round_robin");
+  auto channel = BuildChannel("round_robin");
+  auto stub = BuildStub(channel);
   std::vector<int> ports;
   for (size_t i = 0; i < servers_.size(); ++i) {
     ports.emplace_back(servers_[i]->port_);
@@ -625,10 +665,10 @@
     std::shuffle(ports.begin(), ports.end(),
                  std::mt19937(std::random_device()()));
     SetNextResolution(ports);
-    if (i % 10 == 0) CheckRpcSendOk();
+    if (i % 10 == 0) CheckRpcSendOk(stub, DEBUG_LOCATION);
   }
   // Check LB policy name for the channel.
-  EXPECT_EQ("round_robin", channel_->GetLoadBalancingPolicyName());
+  EXPECT_EQ("round_robin", channel->GetLoadBalancingPolicyName());
 }
 
 TEST_F(ClientLbEnd2endTest, RoundRobinConcurrentUpdates) {
@@ -639,16 +679,21 @@
 TEST_F(ClientLbEnd2endTest, RoundRobinReresolve) {
   // Start servers and send one RPC per server.
   const int kNumServers = 3;
-  std::vector<int> ports;
+  std::vector<int> first_ports;
+  std::vector<int> second_ports;
   for (int i = 0; i < kNumServers; ++i) {
-    ports.push_back(grpc_pick_unused_port_or_die());
+    first_ports.push_back(grpc_pick_unused_port_or_die());
   }
-  StartServers(kNumServers, ports);
-  ResetStub("round_robin");
-  SetNextResolution(ports);
+  for (int i = 0; i < kNumServers; ++i) {
+    second_ports.push_back(grpc_pick_unused_port_or_die());
+  }
+  StartServers(kNumServers, first_ports);
+  auto channel = BuildChannel("round_robin");
+  auto stub = BuildStub(channel);
+  SetNextResolution(first_ports);
   // Send a number of RPCs, which succeed.
   for (size_t i = 0; i < 100; ++i) {
-    CheckRpcSendOk();
+    CheckRpcSendOk(stub, DEBUG_LOCATION);
   }
   // Kill all servers
   gpr_log(GPR_INFO, "****** ABOUT TO KILL SERVERS *******");
@@ -658,18 +703,25 @@
   gpr_log(GPR_INFO, "****** SERVERS KILLED *******");
   gpr_log(GPR_INFO, "****** SENDING DOOMED REQUESTS *******");
   // Client requests should fail. Send enough to tickle all subchannels.
-  for (size_t i = 0; i < servers_.size(); ++i) CheckRpcSendFailure();
+  for (size_t i = 0; i < servers_.size(); ++i) CheckRpcSendFailure(stub);
   gpr_log(GPR_INFO, "****** DOOMED REQUESTS SENT *******");
-  // Bring servers back up on the same port (we aren't recreating the channel).
+  // Bring servers back up on a different set of ports. We need to do this to be
+  // sure that the eventual success is *not* due to subchannel reconnection
+  // attempts and that an actual re-resolution has happened as a result of the
+  // RR policy going into transient failure when all its subchannels become
+  // unavailable (in transient failure as well).
   gpr_log(GPR_INFO, "****** RESTARTING SERVERS *******");
-  StartServers(kNumServers, ports);
+  StartServers(kNumServers, second_ports);
+  // Don't notify of the update. Wait for the LB policy's re-resolution to
+  // "pull" the new ports.
+  SetNextResolutionUponError(second_ports);
   gpr_log(GPR_INFO, "****** SERVERS RESTARTED *******");
   gpr_log(GPR_INFO, "****** SENDING REQUEST TO SUCCEED *******");
   // Client request should eventually (but still fairly soon) succeed.
   const gpr_timespec deadline = grpc_timeout_seconds_to_deadline(5);
   gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
   while (gpr_time_cmp(deadline, now) > 0) {
-    if (SendRpc()) break;
+    if (SendRpc(stub)) break;
     now = gpr_now(GPR_CLOCK_MONOTONIC);
   }
   GPR_ASSERT(gpr_time_cmp(deadline, now) > 0);
@@ -679,11 +731,13 @@
   const int kNumServers = 3;
   StartServers(kNumServers);
   const auto ports = GetServersPorts();
-  ResetStub("round_robin");
+  auto channel = BuildChannel("round_robin");
+  auto stub = BuildStub(channel);
   SetNextResolution(ports);
-  for (size_t i = 0; i < kNumServers; ++i) WaitForServer(i);
+  for (size_t i = 0; i < kNumServers; ++i)
+    WaitForServer(stub, i, DEBUG_LOCATION);
   for (size_t i = 0; i < servers_.size(); ++i) {
-    CheckRpcSendOk();
+    CheckRpcSendOk(stub, DEBUG_LOCATION);
     EXPECT_EQ(1, servers_[i]->service_.request_count()) << "for backend #" << i;
   }
   // One request should have gone to each server.
@@ -695,10 +749,12 @@
   servers_[0]->Shutdown(true);
   // Client request still succeed. May need retrying if RR had returned a pick
   // before noticing the change in the server's connectivity.
-  while (!SendRpc())
-    ;  // Retry until success.
+  while (!SendRpc(stub)) {
+  }  // Retry until success.
   // Send a bunch of RPCs that should succeed.
-  for (int i = 0; i < 10 * kNumServers; ++i) CheckRpcSendOk();
+  for (int i = 0; i < 10 * kNumServers; ++i) {
+    CheckRpcSendOk(stub, DEBUG_LOCATION);
+  }
   const auto post_death = servers_[0]->service_.request_count();
   // No requests have gone to the deceased server.
   EXPECT_EQ(pre_death, post_death);
@@ -708,7 +764,7 @@
   // the server managed to start before the RR policy retried the subchannel) or
   // after the subchannel retry delay otherwise (RR's subchannel retried before
   // the server was fully back up).
-  WaitForServer(0);
+  WaitForServer(stub, 0, DEBUG_LOCATION);
 }
 
 }  // namespace
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index 578f26e..60238e9 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -19,21 +19,20 @@
 #include <mutex>
 #include <thread>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/resource_quota.h>
-#include <grpc++/security/auth_metadata_processor.h>
-#include <grpc++/security/credentials.h>
-#include <grpc++/security/server_credentials.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/resource_quota.h>
+#include <grpcpp/security/auth_metadata_processor.h>
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
 
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/security/credentials/credentials.h"
@@ -347,10 +346,11 @@
   for (int i = 0; i < num_rpcs; ++i) {
     ClientContext context;
     if (with_binary_metadata) {
-      char bytes[8] = {'\0', '\1', '\2', '\3', '\4', '\5', '\6', (char)i};
+      char bytes[8] = {'\0', '\1', '\2', '\3',
+                       '\4', '\5', '\6', static_cast<char>(i)};
       context.AddMetadata("custom-bin", grpc::string(bytes, 8));
     }
-    context.set_compression_algorithm(GRPC_COMPRESS_MESSAGE_GZIP);
+    context.set_compression_algorithm(GRPC_COMPRESS_GZIP);
     Status s = stub->Echo(&context, request, &response);
     EXPECT_EQ(response.message(), request.message());
     EXPECT_TRUE(s.ok());
diff --git a/test/cpp/end2end/exception_test.cc b/test/cpp/end2end/exception_test.cc
index 76272ad..5343997 100644
--- a/test/cpp/end2end/exception_test.cc
+++ b/test/cpp/end2end/exception_test.cc
@@ -19,12 +19,12 @@
 #include <exception>
 #include <memory>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
 #include <grpc/impl/codegen/port_platform.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
 
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
 #include "test/core/util/test_config.h"
@@ -87,24 +87,28 @@
   EchoRequest request;
   EchoResponse response;
   request.set_message("test");
-  ClientContext context;
 
-  Status s = stub_->Echo(&context, request, &response);
-  EXPECT_FALSE(s.ok());
-  EXPECT_EQ(s.error_code(), StatusCode::UNKNOWN);
+  for (int i = 0; i < 10; i++) {
+    ClientContext context;
+    Status s = stub_->Echo(&context, request, &response);
+    EXPECT_FALSE(s.ok());
+    EXPECT_EQ(s.error_code(), StatusCode::UNKNOWN);
+  }
 }
 
 TEST_F(ExceptionTest, RequestStream) {
   ResetStub();
   EchoResponse response;
-  ClientContext context;
 
-  auto stream = stub_->RequestStream(&context, &response);
-  stream->WritesDone();
-  Status s = stream->Finish();
+  for (int i = 0; i < 10; i++) {
+    ClientContext context;
+    auto stream = stub_->RequestStream(&context, &response);
+    stream->WritesDone();
+    Status s = stream->Finish();
 
-  EXPECT_FALSE(s.ok());
-  EXPECT_EQ(s.error_code(), StatusCode::UNKNOWN);
+    EXPECT_FALSE(s.ok());
+    EXPECT_EQ(s.error_code(), StatusCode::UNKNOWN);
+  }
 }
 
 #endif  // GRPC_ALLOW_EXCEPTIONS
diff --git a/test/cpp/end2end/filter_end2end_test.cc b/test/cpp/end2end/filter_end2end_test.cc
index be99a1a..88f8f38 100644
--- a/test/cpp/end2end/filter_end2end_test.cc
+++ b/test/cpp/end2end/filter_end2end_test.cc
@@ -19,20 +19,19 @@
 #include <memory>
 #include <mutex>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/generic/async_generic_service.h>
-#include <grpc++/generic/generic_stub.h>
-#include <grpc++/impl/codegen/proto_utils.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
-#include <grpc++/support/config.h>
-#include <grpc++/support/slice.h>
 #include <grpc/grpc.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/generic/async_generic_service.h>
+#include <grpcpp/generic/generic_stub.h>
+#include <grpcpp/impl/codegen/proto_utils.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
+#include <grpcpp/support/config.h>
+#include <grpcpp/support/slice.h>
 
 #include "src/cpp/common/channel_filter.h"
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
@@ -50,7 +49,7 @@
 namespace testing {
 namespace {
 
-void* tag(int i) { return (void*)(intptr_t)i; }
+void* tag(int i) { return (void*)static_cast<intptr_t>(i); }
 
 void verify_ok(CompletionQueue* cq, int i, bool expect_ok) {
   bool ok;
@@ -175,7 +174,8 @@
       // The string needs to be long enough to test heap-based slice.
       send_request.set_message("Hello world. Hello world. Hello world.");
       std::unique_ptr<GenericClientAsyncReaderWriter> call =
-          generic_stub_->Call(&cli_ctx, kMethodName, &cli_cq_, tag(1));
+          generic_stub_->PrepareCall(&cli_ctx, kMethodName, &cli_cq_);
+      call->StartCall(tag(1));
       client_ok(1);
       std::unique_ptr<ByteBuffer> send_buffer =
           SerializeToByteBuffer(&send_request);
@@ -265,10 +265,11 @@
   GenericServerContext srv_ctx;
   GenericServerAsyncReaderWriter srv_stream(&srv_ctx);
 
-  cli_ctx.set_compression_algorithm(GRPC_COMPRESS_MESSAGE_GZIP);
+  cli_ctx.set_compression_algorithm(GRPC_COMPRESS_GZIP);
   send_request.set_message("Hello");
   std::unique_ptr<GenericClientAsyncReaderWriter> cli_stream =
-      generic_stub_->Call(&cli_ctx, kMethodName, &cli_cq_, tag(1));
+      generic_stub_->PrepareCall(&cli_ctx, kMethodName, &cli_cq_);
+  cli_stream->StartCall(tag(1));
   client_ok(1);
 
   generic_service_.RequestCall(&srv_ctx, &srv_stream, srv_cq_.get(),
diff --git a/test/cpp/end2end/generic_end2end_test.cc b/test/cpp/end2end/generic_end2end_test.cc
index bf43284..88a1227 100644
--- a/test/cpp/end2end/generic_end2end_test.cc
+++ b/test/cpp/end2end/generic_end2end_test.cc
@@ -18,19 +18,18 @@
 
 #include <memory>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/generic/async_generic_service.h>
-#include <grpc++/generic/generic_stub.h>
-#include <grpc++/impl/codegen/proto_utils.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
-#include <grpc++/support/slice.h>
 #include <grpc/grpc.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/generic/async_generic_service.h>
+#include <grpcpp/generic/generic_stub.h>
+#include <grpcpp/impl/codegen/proto_utils.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
+#include <grpcpp/support/slice.h>
 
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
 #include "test/core/util/port.h"
@@ -47,7 +46,7 @@
 namespace testing {
 namespace {
 
-void* tag(int i) { return (void*)(intptr_t)i; }
+void* tag(int i) { return (void*)static_cast<intptr_t>(i); }
 
 void verify_ok(CompletionQueue* cq, int i, bool expect_ok) {
   bool ok;
@@ -125,7 +124,8 @@
       }
 
       std::unique_ptr<GenericClientAsyncReaderWriter> call =
-          generic_stub_->Call(&cli_ctx, kMethodName, &cli_cq_, tag(1));
+          generic_stub_->PrepareCall(&cli_ctx, kMethodName, &cli_cq_);
+      call->StartCall(tag(1));
       client_ok(1);
       std::unique_ptr<ByteBuffer> send_buffer =
           SerializeToByteBuffer(&send_request);
@@ -268,10 +268,11 @@
   GenericServerContext srv_ctx;
   GenericServerAsyncReaderWriter srv_stream(&srv_ctx);
 
-  cli_ctx.set_compression_algorithm(GRPC_COMPRESS_MESSAGE_GZIP);
+  cli_ctx.set_compression_algorithm(GRPC_COMPRESS_GZIP);
   send_request.set_message("Hello");
   std::unique_ptr<GenericClientAsyncReaderWriter> cli_stream =
-      generic_stub_->Call(&cli_ctx, kMethodName, &cli_cq_, tag(1));
+      generic_stub_->PrepareCall(&cli_ctx, kMethodName, &cli_cq_);
+  cli_stream->StartCall(tag(1));
   client_ok(1);
 
   generic_service_.RequestCall(&srv_ctx, &srv_stream, srv_cq_.get(),
diff --git a/test/cpp/end2end/grpclb_end2end_test.cc b/test/cpp/end2end/grpclb_end2end_test.cc
index 5591acf..5578456 100644
--- a/test/cpp/end2end/grpclb_end2end_test.cc
+++ b/test/cpp/end2end/grpclb_end2end_test.cc
@@ -21,21 +21,25 @@
 #include <sstream>
 #include <thread>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
 
 #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
 #include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/security/credentials/fake/fake_credentials.h"
+#include "src/cpp/server/secure_server_credentials.h"
+
+#include "src/cpp/client/secure_credentials.h"
 
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
@@ -120,12 +124,22 @@
 using BackendService = CountedService<TestServiceImpl>;
 using BalancerService = CountedService<LoadBalancer::Service>;
 
+const char g_kCallCredsMdKey[] = "Balancer should not ...";
+const char g_kCallCredsMdValue[] = "... receive me";
+
 class BackendServiceImpl : public BackendService {
  public:
   BackendServiceImpl() {}
 
   Status Echo(ServerContext* context, const EchoRequest* request,
               EchoResponse* response) override {
+    // Backend should receive the call credentials metadata.
+    auto call_credentials_entry =
+        context->client_metadata().find(g_kCallCredsMdKey);
+    EXPECT_NE(call_credentials_entry, context->client_metadata().end());
+    if (call_credentials_entry != context->client_metadata().end()) {
+      EXPECT_EQ(call_credentials_entry->second, g_kCallCredsMdValue);
+    }
     IncreaseRequestCount();
     const auto status = TestServiceImpl::Echo(context, request, response);
     IncreaseResponseCount();
@@ -184,13 +198,21 @@
         shutdown_(false) {}
 
   Status BalanceLoad(ServerContext* context, Stream* stream) override {
+    // Balancer shouldn't receive the call credentials metadata.
+    EXPECT_EQ(context->client_metadata().find(g_kCallCredsMdKey),
+              context->client_metadata().end());
     gpr_log(GPR_INFO, "LB[%p]: BalanceLoad", this);
     LoadBalanceRequest request;
-    stream->Read(&request);
+    std::vector<ResponseDelayPair> responses_and_delays;
+
+    if (!stream->Read(&request)) {
+      goto done;
+    }
     IncreaseRequestCount();
-    gpr_log(GPR_INFO, "LB[%p]: recv msg '%s'", this,
+    gpr_log(GPR_INFO, "LB[%p]: received initial message '%s'", this,
             request.DebugString().c_str());
 
+    // TODO(juanlishen): Initial response should always be the first response.
     if (client_load_reporting_interval_seconds_ > 0) {
       LoadBalanceResponse initial_response;
       initial_response.mutable_initial_response()
@@ -199,7 +221,6 @@
       stream->Write(initial_response);
     }
 
-    std::vector<ResponseDelayPair> responses_and_delays;
     {
       std::unique_lock<std::mutex> lock(mu_);
       responses_and_delays = responses_and_delays_;
@@ -215,14 +236,13 @@
       std::unique_lock<std::mutex> lock(mu_);
       if (shutdown_) goto done;
       serverlist_cond_.wait(lock, [this] { return serverlist_ready_; });
-      serverlist_ready_ = false;
     }
 
     if (client_load_reporting_interval_seconds_ > 0) {
       request.Clear();
       if (stream->Read(&request)) {
-        gpr_log(GPR_INFO, "LB[%p]: recv client load report msg: '%s'", this,
-                request.DebugString().c_str());
+        gpr_log(GPR_INFO, "LB[%p]: received client load report message '%s'",
+                this, request.DebugString().c_str());
         GPR_ASSERT(request.has_client_stats());
         // We need to acquire the lock here in order to prevent the notify_one
         // below from firing before its corresponding wait is executed.
@@ -295,7 +315,7 @@
   void NotifyDoneWithServerlists() {
     std::lock_guard<std::mutex> lock(mu_);
     serverlist_ready_ = true;
-    serverlist_cond_.notify_one();
+    serverlist_cond_.notify_all();
   }
 
  private:
@@ -303,9 +323,7 @@
                     int delay_ms) {
     gpr_log(GPR_INFO, "LB[%p]: sleeping for %d ms...", this, delay_ms);
     if (delay_ms > 0) {
-      gpr_sleep_until(
-          gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
-                       gpr_time_from_millis(delay_ms, GPR_TIMESPAN)));
+      gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(delay_ms));
     }
     gpr_log(GPR_INFO, "LB[%p]: Woke up! Sending response '%s'", this,
             response.DebugString().c_str());
@@ -339,7 +357,8 @@
   }
 
   void SetUp() override {
-    response_generator_ = grpc_fake_resolver_response_generator_create();
+    response_generator_ =
+        grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
     // Start the backends.
     for (size_t i = 0; i < num_backends_; ++i) {
       backends_.emplace_back(new BackendServiceImpl());
@@ -363,7 +382,6 @@
     for (size_t i = 0; i < balancers_.size(); ++i) {
       if (balancers_[i]->Shutdown()) balancer_servers_[i].Shutdown();
     }
-    grpc_fake_resolver_response_generator_unref(response_generator_);
   }
 
   void SetNextResolutionAllBalancers() {
@@ -374,15 +392,29 @@
     SetNextResolution(addresses);
   }
 
-  void ResetStub(int fallback_timeout = 0) {
+  void ResetStub(int fallback_timeout = 0,
+                 const grpc::string& expected_targets = "") {
     ChannelArguments args;
     args.SetGrpclbFallbackTimeout(fallback_timeout);
     args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR,
-                    response_generator_);
+                    response_generator_.get());
+    if (!expected_targets.empty()) {
+      args.SetString(GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS, expected_targets);
+    }
     std::ostringstream uri;
-    uri << "fake:///servername_not_used";
-    channel_ =
-        CreateCustomChannel(uri.str(), InsecureChannelCredentials(), args);
+    uri << "fake:///" << kApplicationTargetName_;
+    // TODO(dgq): templatize tests to run everything using both secure and
+    // insecure channel credentials.
+    grpc_channel_credentials* channel_creds =
+        grpc_fake_transport_security_credentials_create();
+    grpc_call_credentials* call_creds = grpc_md_only_test_credentials_create(
+        g_kCallCredsMdKey, g_kCallCredsMdValue, false);
+    std::shared_ptr<ChannelCredentials> creds(
+        new SecureChannelCredentials(grpc_composite_channel_credentials_create(
+            channel_creds, call_creds, nullptr)));
+    grpc_call_credentials_unref(call_creds);
+    grpc_channel_credentials_unref(channel_creds);
+    channel_ = CreateCustomChannel(uri.str(), creds, args);
     stub_ = grpc::testing::EchoTestService::NewStub(channel_);
   }
 
@@ -443,7 +475,7 @@
 
   void WaitForBackend(size_t backend_idx) {
     do {
-      CheckRpcSendOk();
+      (void)SendRpc();
     } while (backends_[backend_idx]->request_count() == 0);
     ResetBackendCounters();
   }
@@ -478,20 +510,18 @@
         CreateLbAddressesFromAddressDataList(address_data);
     grpc_arg fake_addresses = grpc_lb_addresses_create_channel_arg(addresses);
     grpc_channel_args fake_result = {1, &fake_addresses};
-    grpc_fake_resolver_response_generator_set_response(response_generator_,
-                                                       &fake_result);
+    response_generator_->SetResponse(&fake_result);
     grpc_lb_addresses_destroy(addresses);
   }
 
-  void SetNextResolutionUponError(
+  void SetNextReresolutionResponse(
       const std::vector<AddressData>& address_data) {
     grpc_core::ExecCtx exec_ctx;
     grpc_lb_addresses* addresses =
         CreateLbAddressesFromAddressDataList(address_data);
     grpc_arg fake_addresses = grpc_lb_addresses_create_channel_arg(addresses);
     grpc_channel_args fake_result = {1, &fake_addresses};
-    grpc_fake_resolver_response_generator_set_response_upon_error(
-        response_generator_, &fake_result);
+    response_generator_->SetReresolutionResponse(&fake_result);
     grpc_lb_addresses_destroy(addresses);
   }
 
@@ -521,10 +551,10 @@
     return status;
   }
 
-  void CheckRpcSendOk(const size_t times = 1) {
+  void CheckRpcSendOk(const size_t times = 1, const int timeout_ms = 1000) {
     for (size_t i = 0; i < times; ++i) {
       EchoResponse response;
-      const Status status = SendRpc(&response);
+      const Status status = SendRpc(&response, timeout_ms);
       EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
                                << " message=" << status.error_message();
       EXPECT_EQ(response.message(), kRequestMessage_);
@@ -562,8 +592,9 @@
       std::ostringstream server_address;
       server_address << server_host << ":" << port_;
       ServerBuilder builder;
-      builder.AddListeningPort(server_address.str(),
-                               InsecureServerCredentials());
+      std::shared_ptr<ServerCredentials> creds(new SecureServerCredentials(
+          grpc_fake_transport_security_server_credentials_create()));
+      builder.AddListeningPort(server_address.str(), creds);
       builder.RegisterService(service_);
       server_ = builder.BuildAndStart();
       cond->notify_one();
@@ -593,8 +624,10 @@
   std::vector<std::unique_ptr<BalancerServiceImpl>> balancers_;
   std::vector<ServerThread<BackendService>> backend_servers_;
   std::vector<ServerThread<BalancerService>> balancer_servers_;
-  grpc_fake_resolver_response_generator* response_generator_;
+  grpc_core::RefCountedPtr<grpc_core::FakeResolverResponseGenerator>
+      response_generator_;
   const grpc::string kRequestMessage_ = "Live long and prosper.";
+  const grpc::string kApplicationTargetName_ = "application_target_name";
 };
 
 class SingleBalancerTest : public GrpclbEnd2endTest {
@@ -630,11 +663,52 @@
   EXPECT_EQ("grpclb", channel_->GetLoadBalancingPolicyName());
 }
 
+TEST_F(SingleBalancerTest, SecureNaming) {
+  ResetStub(0, kApplicationTargetName_ + ";lb");
+  SetNextResolution({AddressData{balancer_servers_[0].port_, true, "lb"}});
+  const size_t kNumRpcsPerAddress = 100;
+  ScheduleResponseForBalancer(
+      0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), {}),
+      0);
+  // Make sure that trying to connect works without a call.
+  channel_->GetState(true /* try_to_connect */);
+  // We need to wait for all backends to come online.
+  WaitForAllBackends();
+  // Send kNumRpcsPerAddress RPCs per server.
+  CheckRpcSendOk(kNumRpcsPerAddress * num_backends_);
+
+  // Each backend should have gotten 100 requests.
+  for (size_t i = 0; i < backends_.size(); ++i) {
+    EXPECT_EQ(kNumRpcsPerAddress,
+              backend_servers_[i].service_->request_count());
+  }
+  balancers_[0]->NotifyDoneWithServerlists();
+  // The balancer got a single request.
+  EXPECT_EQ(1U, balancer_servers_[0].service_->request_count());
+  // and sent a single response.
+  EXPECT_EQ(1U, balancer_servers_[0].service_->response_count());
+  // Check LB policy name for the channel.
+  EXPECT_EQ("grpclb", channel_->GetLoadBalancingPolicyName());
+}
+
+TEST_F(SingleBalancerTest, SecureNamingDeathTest) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  // Make sure that we blow up (via abort() from the security connector) when
+  // the name from the balancer doesn't match expectations.
+  ASSERT_DEATH(
+      {
+        ResetStub(0, kApplicationTargetName_ + ";lb");
+        SetNextResolution(
+            {AddressData{balancer_servers_[0].port_, true, "woops"}});
+        channel_->WaitForConnected(grpc_timeout_seconds_to_deadline(1));
+      },
+      "");
+}
+
 TEST_F(SingleBalancerTest, InitiallyEmptyServerlist) {
   SetNextResolutionAllBalancers();
   const int kServerlistDelayMs = 500 * grpc_test_slowdown_factor();
-  const int kCallDeadlineMs = 1000 * grpc_test_slowdown_factor();
-
+  const int kCallDeadlineMs = kServerlistDelayMs * 2;
   // First response is an empty serverlist, sent right away.
   ScheduleResponseForBalancer(0, LoadBalanceResponse(), 0);
   // Send non-empty serverlist only after kServerlistDelayMs
@@ -644,28 +718,20 @@
 
   const auto t0 = system_clock::now();
   // Client will block: LB will initially send empty serverlist.
-  CheckRpcSendOk(num_backends_);
+  CheckRpcSendOk(1, kCallDeadlineMs);
   const auto ellapsed_ms =
       std::chrono::duration_cast<std::chrono::milliseconds>(
           system_clock::now() - t0);
   // but eventually, the LB sends a serverlist update that allows the call to
   // proceed. The call delay must be larger than the delay in sending the
-  // populated serverlist but under the call's deadline.
+  // populated serverlist but under the call's deadline (which is enforced by
+  // the call's deadline).
   EXPECT_GT(ellapsed_ms.count(), kServerlistDelayMs);
-  EXPECT_LT(ellapsed_ms.count(), kCallDeadlineMs);
-
-  // Each backend should have gotten 1 request.
-  for (size_t i = 0; i < backends_.size(); ++i) {
-    EXPECT_EQ(1U, backend_servers_[i].service_->request_count());
-  }
   balancers_[0]->NotifyDoneWithServerlists();
   // The balancer got a single request.
   EXPECT_EQ(1U, balancer_servers_[0].service_->request_count());
   // and sent two responses.
   EXPECT_EQ(2U, balancer_servers_[0].service_->response_count());
-
-  // Check LB policy name for the channel.
-  EXPECT_EQ("grpclb", channel_->GetLoadBalancingPolicyName());
 }
 
 TEST_F(SingleBalancerTest, Fallback) {
@@ -874,8 +940,6 @@
   // machinery to either update the LB responses "on the fly" or instruct
   // backends which ports to restart on.
   CheckRpcSendFailure();
-  // Check LB policy name for the channel.
-  EXPECT_EQ("grpclb", channel_->GetLoadBalancingPolicyName());
 }
 
 class UpdatesTest : public GrpclbEnd2endTest {
@@ -892,7 +956,10 @@
   ScheduleResponseForBalancer(
       1, BalancerServiceImpl::BuildResponseForBackends(second_backend, {}), 0);
 
-  // Start servers and send 10 RPCs per server.
+  // Wait until the first backend is ready.
+  WaitForBackend(0);
+
+  // Send 10 requests.
   gpr_log(GPR_INFO, "========= BEFORE FIRST BATCH ==========");
   CheckRpcSendOk(10);
   gpr_log(GPR_INFO, "========= DONE WITH FIRST BATCH ==========");
@@ -939,8 +1006,6 @@
   EXPECT_EQ(1U, balancer_servers_[1].service_->response_count());
   EXPECT_EQ(0U, balancer_servers_[2].service_->request_count());
   EXPECT_EQ(0U, balancer_servers_[2].service_->response_count());
-  // Check LB policy name for the channel.
-  EXPECT_EQ("grpclb", channel_->GetLoadBalancingPolicyName());
 }
 
 // Send an update with the same set of LBs as the one in SetUp() in order to
@@ -956,7 +1021,10 @@
   ScheduleResponseForBalancer(
       1, BalancerServiceImpl::BuildResponseForBackends(second_backend, {}), 0);
 
-  // Start servers and send 10 RPCs per server.
+  // Wait until the first backend is ready.
+  WaitForBackend(0);
+
+  // Send 10 requests.
   gpr_log(GPR_INFO, "========= BEFORE FIRST BATCH ==========");
   CheckRpcSendOk(10);
   gpr_log(GPR_INFO, "========= DONE WITH FIRST BATCH ==========");
@@ -1012,9 +1080,6 @@
   // doesn't assign the second backend.
   EXPECT_EQ(0U, backend_servers_[1].service_->request_count());
   balancers_[0]->NotifyDoneWithServerlists();
-
-  // Check LB policy name for the channel.
-  EXPECT_EQ("grpclb", channel_->GetLoadBalancingPolicyName());
 }
 
 TEST_F(UpdatesTest, UpdateBalancersDeadUpdate) {
@@ -1097,8 +1162,134 @@
   EXPECT_LE(balancer_servers_[1].service_->response_count(), 2U);
   EXPECT_EQ(0U, balancer_servers_[2].service_->request_count());
   EXPECT_EQ(0U, balancer_servers_[2].service_->response_count());
-  // Check LB policy name for the channel.
-  EXPECT_EQ("grpclb", channel_->GetLoadBalancingPolicyName());
+}
+
+TEST_F(UpdatesTest, ReresolveDeadBackend) {
+  ResetStub(500);
+  // The first resolution contains the addresses of a balancer that never
+  // responds, and a fallback backend.
+  std::vector<AddressData> addresses;
+  addresses.emplace_back(AddressData{balancer_servers_[0].port_, true, ""});
+  addresses.emplace_back(AddressData{backend_servers_[0].port_, false, ""});
+  SetNextResolution(addresses);
+  // The re-resolution result will contain the addresses of the same balancer
+  // and a new fallback backend.
+  addresses.clear();
+  addresses.emplace_back(AddressData{balancer_servers_[0].port_, true, ""});
+  addresses.emplace_back(AddressData{backend_servers_[1].port_, false, ""});
+  SetNextReresolutionResponse(addresses);
+
+  // Start servers and send 10 RPCs per server.
+  gpr_log(GPR_INFO, "========= BEFORE FIRST BATCH ==========");
+  CheckRpcSendOk(10);
+  gpr_log(GPR_INFO, "========= DONE WITH FIRST BATCH ==========");
+  // All 10 requests should have gone to the fallback backend.
+  EXPECT_EQ(10U, backend_servers_[0].service_->request_count());
+
+  // Kill backend 0.
+  gpr_log(GPR_INFO, "********** ABOUT TO KILL BACKEND 0 *************");
+  if (backends_[0]->Shutdown()) backend_servers_[0].Shutdown();
+  gpr_log(GPR_INFO, "********** KILLED BACKEND 0 *************");
+
+  // Wait until re-resolution has finished, as signaled by the second backend
+  // receiving a request.
+  WaitForBackend(1);
+
+  gpr_log(GPR_INFO, "========= BEFORE SECOND BATCH ==========");
+  CheckRpcSendOk(10);
+  gpr_log(GPR_INFO, "========= DONE WITH SECOND BATCH ==========");
+  // All 10 requests should have gone to the second backend.
+  EXPECT_EQ(10U, backend_servers_[1].service_->request_count());
+
+  balancers_[0]->NotifyDoneWithServerlists();
+  balancers_[1]->NotifyDoneWithServerlists();
+  balancers_[2]->NotifyDoneWithServerlists();
+  EXPECT_EQ(1U, balancer_servers_[0].service_->request_count());
+  EXPECT_EQ(0U, balancer_servers_[0].service_->response_count());
+  EXPECT_EQ(0U, balancer_servers_[1].service_->request_count());
+  EXPECT_EQ(0U, balancer_servers_[1].service_->response_count());
+  EXPECT_EQ(0U, balancer_servers_[2].service_->request_count());
+  EXPECT_EQ(0U, balancer_servers_[2].service_->response_count());
+}
+
+// TODO(juanlishen): Should be removed when the first response is always the
+// initial response. Currently, if client load reporting is not enabled, the
+// balancer doesn't send initial response. When the backend shuts down, an
+// unexpected re-resolution will happen. This test configuration is a workaround
+// for test ReresolveDeadBalancer.
+class UpdatesWithClientLoadReportingTest : public GrpclbEnd2endTest {
+ public:
+  UpdatesWithClientLoadReportingTest() : GrpclbEnd2endTest(4, 3, 2) {}
+};
+
+TEST_F(UpdatesWithClientLoadReportingTest, ReresolveDeadBalancer) {
+  std::vector<AddressData> addresses;
+  addresses.emplace_back(AddressData{balancer_servers_[0].port_, true, ""});
+  SetNextResolution(addresses);
+  addresses.clear();
+  addresses.emplace_back(AddressData{balancer_servers_[1].port_, true, ""});
+  SetNextReresolutionResponse(addresses);
+  const std::vector<int> first_backend{GetBackendPorts()[0]};
+  const std::vector<int> second_backend{GetBackendPorts()[1]};
+
+  ScheduleResponseForBalancer(
+      0, BalancerServiceImpl::BuildResponseForBackends(first_backend, {}), 0);
+  ScheduleResponseForBalancer(
+      1, BalancerServiceImpl::BuildResponseForBackends(second_backend, {}), 0);
+
+  // Start servers and send 10 RPCs per server.
+  gpr_log(GPR_INFO, "========= BEFORE FIRST BATCH ==========");
+  CheckRpcSendOk(10);
+  gpr_log(GPR_INFO, "========= DONE WITH FIRST BATCH ==========");
+  // All 10 requests should have gone to the first backend.
+  EXPECT_EQ(10U, backend_servers_[0].service_->request_count());
+
+  // Kill backend 0.
+  gpr_log(GPR_INFO, "********** ABOUT TO KILL BACKEND 0 *************");
+  if (backends_[0]->Shutdown()) backend_servers_[0].Shutdown();
+  gpr_log(GPR_INFO, "********** KILLED BACKEND 0 *************");
+
+  CheckRpcSendFailure();
+
+  // Balancer 0 got a single request.
+  EXPECT_EQ(1U, balancer_servers_[0].service_->request_count());
+  // and sent a single response.
+  EXPECT_EQ(1U, balancer_servers_[0].service_->response_count());
+  EXPECT_EQ(0U, balancer_servers_[1].service_->request_count());
+  EXPECT_EQ(0U, balancer_servers_[1].service_->response_count());
+  EXPECT_EQ(0U, balancer_servers_[2].service_->request_count());
+  EXPECT_EQ(0U, balancer_servers_[2].service_->response_count());
+
+  // Kill balancer 0.
+  gpr_log(GPR_INFO, "********** ABOUT TO KILL BALANCER 0 *************");
+  if (balancers_[0]->Shutdown()) balancer_servers_[0].Shutdown();
+  gpr_log(GPR_INFO, "********** KILLED BALANCER 0 *************");
+
+  // Wait until re-resolution has finished, as signaled by the second backend
+  // receiving a request.
+  WaitForBackend(1);
+
+  // This is serviced by the new serverlist.
+  gpr_log(GPR_INFO, "========= BEFORE SECOND BATCH ==========");
+  CheckRpcSendOk(10);
+  gpr_log(GPR_INFO, "========= DONE WITH SECOND BATCH ==========");
+  // All 10 requests should have gone to the second backend.
+  EXPECT_EQ(10U, backend_servers_[1].service_->request_count());
+
+  EXPECT_EQ(1U, balancer_servers_[0].service_->request_count());
+  EXPECT_EQ(1U, balancer_servers_[0].service_->response_count());
+  // After balancer 0 is killed, we restart an LB call immediately (because we
+  // disconnect to a previously connected balancer). Although we will cancel
+  // this call when the re-resolution update is done and another LB call restart
+  // is needed, this old call may still succeed reaching the LB server if
+  // re-resolution is slow. So balancer 1 may have received 2 requests and sent
+  // 2 responses.
+  EXPECT_GE(balancer_servers_[1].service_->request_count(), 1U);
+  EXPECT_GE(balancer_servers_[1].service_->response_count(), 1U);
+  EXPECT_LE(balancer_servers_[1].service_->request_count(), 2U);
+  EXPECT_LE(balancer_servers_[1].service_->response_count(), 2U);
+  EXPECT_EQ(0U, balancer_servers_[2].service_->request_count());
+  EXPECT_EQ(0U, balancer_servers_[2].service_->response_count());
 }
 
 TEST_F(SingleBalancerTest, Drop) {
diff --git a/test/cpp/end2end/health_service_end2end_test.cc b/test/cpp/end2end/health_service_end2end_test.cc
index de732e0..1c48b9d 100644
--- a/test/cpp/end2end/health_service_end2end_test.cc
+++ b/test/cpp/end2end/health_service_end2end_test.cc
@@ -21,16 +21,16 @@
 #include <thread>
 #include <vector>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/ext/health_check_service_server_builder_option.h>
-#include <grpc++/health_check_service_interface.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/ext/health_check_service_server_builder_option.h>
+#include <grpcpp/health_check_service_interface.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
 
 #include "src/proto/grpc/health/v1/health.grpc.pb.h"
 #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
diff --git a/test/cpp/end2end/hybrid_end2end_test.cc b/test/cpp/end2end/hybrid_end2end_test.cc
index cb51553..10e1642 100644
--- a/test/cpp/end2end/hybrid_end2end_test.cc
+++ b/test/cpp/end2end/hybrid_end2end_test.cc
@@ -19,14 +19,14 @@
 #include <memory>
 #include <thread>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/generic/async_generic_service.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
 #include <grpc/grpc.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/generic/async_generic_service.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
 
 #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
@@ -42,7 +42,7 @@
 
 namespace {
 
-void* tag(int i) { return (void*)(intptr_t)i; }
+void* tag(int i) { return (void*)static_cast<intptr_t>(i); }
 
 bool VerifyReturnSuccess(CompletionQueue* cq, int i) {
   void* got_tag;
diff --git a/test/cpp/end2end/mock_test.cc b/test/cpp/end2end/mock_test.cc
index 175ecea..ff49902 100644
--- a/test/cpp/end2end/mock_test.cc
+++ b/test/cpp/end2end/mock_test.cc
@@ -19,16 +19,15 @@
 #include <climits>
 #include <thread>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
 
 #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
@@ -36,7 +35,7 @@
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
-#include <grpc++/test/mock_stream.h>
+#include <grpcpp/test/mock_stream.h>
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
diff --git a/test/cpp/end2end/nonblocking_test.cc b/test/cpp/end2end/nonblocking_test.cc
new file mode 100644
index 0000000..d8337ba
--- /dev/null
+++ b/test/cpp/end2end/nonblocking_test.cc
@@ -0,0 +1,194 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
+
+#include "src/core/lib/gpr/tls.h"
+#include "src/core/lib/iomgr/port.h"
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+
+#ifdef GRPC_POSIX_SOCKET
+#include "src/core/lib/iomgr/ev_posix.h"
+#endif  // GRPC_POSIX_SOCKET
+
+#include <gtest/gtest.h>
+
+#ifdef GRPC_POSIX_SOCKET
+// Thread-local variable to so that only polls from this test assert
+// non-blocking (not polls from resolver, timer thread, etc)
+GPR_TLS_DECL(g_is_nonblocking_test);
+
+namespace {
+
+int maybe_assert_non_blocking_poll(struct pollfd* pfds, nfds_t nfds,
+                                   int timeout) {
+  if (gpr_tls_get(&g_is_nonblocking_test)) {
+    GPR_ASSERT(timeout == 0);
+  }
+  return poll(pfds, nfds, timeout);
+}
+
+}  // namespace
+
+namespace grpc {
+namespace testing {
+namespace {
+
+void* tag(int i) { return reinterpret_cast<void*>(static_cast<intptr_t>(i)); }
+int detag(void* p) { return static_cast<int>(reinterpret_cast<intptr_t>(p)); }
+
+class NonblockingTest : public ::testing::Test {
+ protected:
+  NonblockingTest() {}
+
+  void SetUp() override {
+    port_ = grpc_pick_unused_port_or_die();
+    server_address_ << "localhost:" << port_;
+
+    // Setup server
+    BuildAndStartServer();
+  }
+
+  bool LoopForTag(void** tag, bool* ok) {
+    for (;;) {
+      auto r = cq_->AsyncNext(tag, ok, gpr_time_0(GPR_CLOCK_REALTIME));
+      if (r == CompletionQueue::SHUTDOWN) {
+        return false;
+      } else if (r == CompletionQueue::GOT_EVENT) {
+        return true;
+      }
+    }
+  }
+
+  void TearDown() override {
+    server_->Shutdown();
+    void* ignored_tag;
+    bool ignored_ok;
+    cq_->Shutdown();
+    while (LoopForTag(&ignored_tag, &ignored_ok))
+      ;
+    stub_.reset();
+    grpc_recycle_unused_port(port_);
+  }
+
+  void BuildAndStartServer() {
+    ServerBuilder builder;
+    builder.AddListeningPort(server_address_.str(),
+                             grpc::InsecureServerCredentials());
+    service_.reset(new grpc::testing::EchoTestService::AsyncService());
+    builder.RegisterService(service_.get());
+    cq_ = builder.AddCompletionQueue();
+    server_ = builder.BuildAndStart();
+  }
+
+  void ResetStub() {
+    std::shared_ptr<Channel> channel = CreateChannel(
+        server_address_.str(), grpc::InsecureChannelCredentials());
+    stub_ = grpc::testing::EchoTestService::NewStub(channel);
+  }
+
+  void SendRpc(int num_rpcs) {
+    for (int i = 0; i < num_rpcs; i++) {
+      EchoRequest send_request;
+      EchoRequest recv_request;
+      EchoResponse send_response;
+      EchoResponse recv_response;
+      Status recv_status;
+
+      ClientContext cli_ctx;
+      ServerContext srv_ctx;
+      grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
+
+      send_request.set_message("hello non-blocking world");
+      std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
+          stub_->PrepareAsyncEcho(&cli_ctx, send_request, cq_.get()));
+
+      response_reader->StartCall();
+      response_reader->Finish(&recv_response, &recv_status, tag(4));
+
+      service_->RequestEcho(&srv_ctx, &recv_request, &response_writer,
+                            cq_.get(), cq_.get(), tag(2));
+
+      void* got_tag;
+      bool ok;
+      EXPECT_TRUE(LoopForTag(&got_tag, &ok));
+      EXPECT_TRUE(ok);
+      EXPECT_EQ(detag(got_tag), 2);
+      EXPECT_EQ(send_request.message(), recv_request.message());
+
+      send_response.set_message(recv_request.message());
+      response_writer.Finish(send_response, Status::OK, tag(3));
+
+      int tagsum = 0;
+      int tagprod = 1;
+      EXPECT_TRUE(LoopForTag(&got_tag, &ok));
+      EXPECT_TRUE(ok);
+      tagsum += detag(got_tag);
+      tagprod *= detag(got_tag);
+
+      EXPECT_TRUE(LoopForTag(&got_tag, &ok));
+      EXPECT_TRUE(ok);
+      tagsum += detag(got_tag);
+      tagprod *= detag(got_tag);
+
+      EXPECT_EQ(tagsum, 7);
+      EXPECT_EQ(tagprod, 12);
+      EXPECT_EQ(send_response.message(), recv_response.message());
+      EXPECT_TRUE(recv_status.ok());
+    }
+  }
+
+  std::unique_ptr<ServerCompletionQueue> cq_;
+  std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
+  std::unique_ptr<Server> server_;
+  std::unique_ptr<grpc::testing::EchoTestService::AsyncService> service_;
+  std::ostringstream server_address_;
+  int port_;
+};
+
+TEST_F(NonblockingTest, SimpleRpc) {
+  ResetStub();
+  SendRpc(10);
+}
+
+}  // namespace
+}  // namespace testing
+}  // namespace grpc
+
+#endif  // GRPC_POSIX_SOCKET
+
+int main(int argc, char** argv) {
+#ifdef GRPC_POSIX_SOCKET
+  // Override the poll function before anything else can happen
+  grpc_poll_function = maybe_assert_non_blocking_poll;
+#endif  // GRPC_POSIX_SOCKET
+
+  grpc_test_init(argc, argv);
+  ::testing::InitGoogleTest(&argc, argv);
+  int ret = RUN_ALL_TESTS();
+  return ret;
+}
diff --git a/test/cpp/end2end/proto_server_reflection_test.cc b/test/cpp/end2end/proto_server_reflection_test.cc
index b645d90..21a275e 100644
--- a/test/cpp/end2end/proto_server_reflection_test.cc
+++ b/test/cpp/end2end/proto_server_reflection_test.cc
@@ -16,16 +16,16 @@
  *
  */
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/ext/proto_server_reflection_plugin.h>
-#include <grpc++/security/credentials.h>
-#include <grpc++/security/server_credentials.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
 #include <grpc/grpc.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/ext/proto_server_reflection_plugin.h>
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
 
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
 #include "test/core/util/port.h"
diff --git a/test/cpp/end2end/round_robin_end2end_test.cc b/test/cpp/end2end/round_robin_end2end_test.cc
index eee32ce..846347e 100644
--- a/test/cpp/end2end/round_robin_end2end_test.cc
+++ b/test/cpp/end2end/round_robin_end2end_test.cc
@@ -20,14 +20,14 @@
 #include <mutex>
 #include <thread>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
 
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
 #include "test/core/util/port.h"
diff --git a/test/cpp/end2end/server_builder_plugin_test.cc b/test/cpp/end2end/server_builder_plugin_test.cc
index a1ce4eb..d54523f 100644
--- a/test/cpp/end2end/server_builder_plugin_test.cc
+++ b/test/cpp/end2end/server_builder_plugin_test.cc
@@ -18,18 +18,18 @@
 
 #include <thread>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/impl/server_builder_option.h>
-#include <grpc++/impl/server_builder_plugin.h>
-#include <grpc++/impl/server_initializer.h>
-#include <grpc++/security/credentials.h>
-#include <grpc++/security/server_credentials.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
 #include <grpc/grpc.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/impl/server_builder_option.h>
+#include <grpcpp/impl/server_builder_plugin.h>
+#include <grpcpp/impl/server_initializer.h>
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
 
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
 #include "test/core/util/port.h"
@@ -251,7 +251,7 @@
   EchoResponse response;
   request.set_message("Hello hello hello hello");
   ClientContext context;
-  context.set_compression_algorithm(GRPC_COMPRESS_MESSAGE_GZIP);
+  context.set_compression_algorithm(GRPC_COMPRESS_GZIP);
   Status s = stub_->Echo(&context, request, &response);
   EXPECT_EQ(response.message(), request.message());
   EXPECT_TRUE(s.ok());
diff --git a/test/cpp/end2end/server_crash_test.cc b/test/cpp/end2end/server_crash_test.cc
index 528951b..93257b2 100644
--- a/test/cpp/end2end/server_crash_test.cc
+++ b/test/cpp/end2end/server_crash_test.cc
@@ -16,16 +16,15 @@
  *
  */
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
 
 #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
diff --git a/test/cpp/end2end/server_crash_test_client.cc b/test/cpp/end2end/server_crash_test_client.cc
index 4599576..c05fcfd 100644
--- a/test/cpp/end2end/server_crash_test_client.cc
+++ b/test/cpp/end2end/server_crash_test_client.cc
@@ -22,10 +22,10 @@
 #include <sstream>
 #include <string>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
 #include <grpc/support/log.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
 
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
 
diff --git a/test/cpp/end2end/server_early_return_test.cc b/test/cpp/end2end/server_early_return_test.cc
index 6fd26fc..8948e5b 100644
--- a/test/cpp/end2end/server_early_return_test.cc
+++ b/test/cpp/end2end/server_early_return_test.cc
@@ -16,19 +16,18 @@
  *
  */
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/security/credentials.h>
-#include <grpc++/security/server_credentials.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
 
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
 #include "test/core/util/port.h"
diff --git a/test/cpp/end2end/shutdown_test.cc b/test/cpp/end2end/shutdown_test.cc
index 9119102..a53de69 100644
--- a/test/cpp/end2end/shutdown_test.cc
+++ b/test/cpp/end2end/shutdown_test.cc
@@ -18,15 +18,15 @@
 
 #include <thread>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
 
 #include "src/core/lib/gpr/env.h"
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
diff --git a/test/cpp/end2end/streaming_throughput_test.cc b/test/cpp/end2end/streaming_throughput_test.cc
index 8fcb8b1..898d1ec 100644
--- a/test/cpp/end2end/streaming_throughput_test.cc
+++ b/test/cpp/end2end/streaming_throughput_test.cc
@@ -20,19 +20,18 @@
 #include <mutex>
 #include <thread>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/security/credentials.h>
-#include <grpc++/security/server_credentials.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
 #include <grpc/grpc.h>
 #include <grpc/support/atm.h>
 #include <grpc/support/log.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
 
 #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
diff --git a/test/cpp/end2end/test_service_impl.cc b/test/cpp/end2end/test_service_impl.cc
index 875a27b..3c3a5d9 100644
--- a/test/cpp/end2end/test_service_impl.cc
+++ b/test/cpp/end2end/test_service_impl.cc
@@ -21,9 +21,9 @@
 #include <string>
 #include <thread>
 
-#include <grpc++/security/credentials.h>
-#include <grpc++/server_context.h>
 #include <grpc/support/log.h>
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/server_context.h>
 
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
 #include "test/cpp/util/string_ref_helper.h"
diff --git a/test/cpp/end2end/test_service_impl.h b/test/cpp/end2end/test_service_impl.h
index 070f357..052543a 100644
--- a/test/cpp/end2end/test_service_impl.h
+++ b/test/cpp/end2end/test_service_impl.h
@@ -21,8 +21,8 @@
 #include <memory>
 #include <mutex>
 
-#include <grpc++/server_context.h>
 #include <grpc/grpc.h>
+#include <grpcpp/server_context.h>
 
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
 
diff --git a/test/cpp/end2end/thread_stress_test.cc b/test/cpp/end2end/thread_stress_test.cc
index 90b2edd..e709a25 100644
--- a/test/cpp/end2end/thread_stress_test.cc
+++ b/test/cpp/end2end/thread_stress_test.cc
@@ -19,15 +19,14 @@
 #include <mutex>
 #include <thread>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
 #include <grpc/grpc.h>
-#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
 
 #include "src/core/lib/surface/api_trace.h"
 #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
@@ -265,7 +264,7 @@
       service_.RequestEcho(contexts_[i].srv_ctx.get(),
                            &contexts_[i].recv_request,
                            contexts_[i].response_writer.get(), cq_.get(),
-                           cq_.get(), (void*)(intptr_t)i);
+                           cq_.get(), (void*)static_cast<intptr_t>(i));
     }
   }
   struct Context {
diff --git a/test/cpp/grpclb/BUILD b/test/cpp/grpclb/BUILD
new file mode 100644
index 0000000..8319eb5
--- /dev/null
+++ b/test/cpp/grpclb/BUILD
@@ -0,0 +1,39 @@
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 v2
+
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_package", "grpc_cc_binary")
+
+grpc_package(
+    name = "test/cpp/grpclb",
+    visibility = "public",
+)  # Allows external users to implement grpclb tests.
+
+grpc_cc_test(
+    name = "grpclb_api_test",
+    srcs = ["grpclb_api_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//:grpc++",
+        "//src/proto/grpc/lb/v1:load_balancer_proto",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+        "//test/cpp/util:test_util",
+    ],
+)
diff --git a/test/cpp/grpclb/grpclb_api_test.cc b/test/cpp/grpclb/grpclb_api_test.cc
index 1f2ef0c..ecba9f9 100644
--- a/test/cpp/grpclb/grpclb_api_test.cc
+++ b/test/cpp/grpclb/grpclb_api_test.cc
@@ -16,8 +16,8 @@
  *
  */
 
-#include <grpc++/impl/codegen/config.h>
 #include <grpc/grpc.h>
+#include <grpcpp/impl/codegen/config.h>
 #include <gtest/gtest.h>
 
 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h"
diff --git a/test/cpp/grpclb/grpclb_test.cc b/test/cpp/grpclb/grpclb_test.cc
deleted file mode 100644
index d241594..0000000
--- a/test/cpp/grpclb/grpclb_test.cc
+++ /dev/null
@@ -1,795 +0,0 @@
-/*
- *
- * Copyright 2016 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <cinttypes>
-#include <cstdarg>
-#include <cstdint>
-#include <cstring>
-#include <string>
-
-#include <gtest/gtest.h>
-
-#include <grpc/grpc.h>
-#include <grpc/impl/codegen/byte_buffer_reader.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/time.h>
-
-#include <grpc++/impl/codegen/config.h>
-
-#include "src/core/ext/filters/client_channel/client_channel.h"
-#include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
-#include "src/core/lib/channel/channel_args.h"
-#include "src/core/lib/channel/channel_stack.h"
-#include "src/core/lib/gpr/env.h"
-#include "src/core/lib/gpr/string.h"
-#include "src/core/lib/gpr/tmpfile.h"
-#include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/security/credentials/fake/fake_credentials.h"
-#include "src/core/lib/surface/channel.h"
-#include "src/core/lib/surface/server.h"
-#include "test/core/end2end/cq_verifier.h"
-#include "test/core/util/port.h"
-#include "test/core/util/test_config.h"
-
-#include "src/proto/grpc/lb/v1/load_balancer.pb.h"
-
-#define NUM_BACKENDS 4
-#define PAYLOAD "hello you"
-
-// TODO(dgq): Other scenarios in need of testing:
-// - Send an empty serverlist update and verify that the client request blocks
-//   until a new serverlist with actual contents is available.
-// - Send identical serverlist update
-// - Send a serverlist with faulty ip:port addresses (port > 2^16, etc).
-// - Test reception of invalid serverlist
-// - Test pinging
-// - Test against a non-LB server.
-// - Random LB server closing the stream unexpectedly.
-// - Test using DNS-resolvable names (localhost?)
-// - Test handling of creation of faulty RR instance by having the LB return a
-//   serverlist with non-existent backends after having initially returned a
-//   valid one.
-//
-// Findings from end to end testing to be covered here:
-// - Handling of LB servers restart, including reconnection after backing-off
-//   retries.
-// - Destruction of load balanced channel (and therefore of grpclb instance)
-//   while:
-//   1) the internal LB call is still active. This should work by virtue
-//   of the weak reference the LB call holds. The call should be terminated as
-//   part of the grpclb shutdown process.
-//   2) the retry timer is active. Again, the weak reference it holds should
-//   prevent a premature call to \a glb_destroy.
-// - Restart of backend servers with no changes to serverlist. This exercises
-//   the RR handover mechanism.
-
-namespace grpc {
-namespace {
-
-typedef struct client_fixture {
-  grpc_channel* client;
-  char* server_uri;
-  grpc_completion_queue* cq;
-} client_fixture;
-
-typedef struct server_fixture {
-  grpc_server* server;
-  grpc_call* server_call;
-  grpc_completion_queue* cq;
-  char* servers_hostport;
-  const char* balancer_name;
-  int port;
-  const char* lb_token_prefix;
-  gpr_thd_id tid;
-  int num_calls_serviced;
-} server_fixture;
-
-typedef struct test_fixture {
-  server_fixture lb_server;
-  server_fixture lb_backends[NUM_BACKENDS];
-  client_fixture client;
-  int lb_server_update_delay_ms;
-} test_fixture;
-
-static void* tag(intptr_t t) { return (void*)t; }
-
-static grpc_slice build_response_payload_slice(const char* host, int* ports,
-                                               size_t nports,
-                                               const char* token_prefix) {
-  // server_list {
-  //   servers {
-  //     ip_address: <in_addr/6 bytes of an IP>
-  //     port: <16 bit uint>
-  //     load_balance_token: "token..."
-  //   }
-  //   ...
-  // }
-  grpc::lb::v1::LoadBalanceResponse response;
-  auto* serverlist = response.mutable_server_list();
-
-  for (size_t i = 0; i < nports; i++) {
-    auto* server = serverlist->add_servers();
-    // TODO(dgq): test ipv6
-    struct in_addr ip4;
-    GPR_ASSERT(inet_pton(AF_INET, host, &ip4) == 1);
-    server->set_ip_address(
-        string(reinterpret_cast<const char*>(&ip4), sizeof(ip4)));
-    server->set_port(ports[i]);
-    // Missing tokens are acceptable. Test that path.
-    if (strlen(token_prefix) > 0) {
-      string token_data = token_prefix + std::to_string(ports[i]);
-      server->set_load_balance_token(token_data);
-    }
-  }
-  const string& enc_resp = response.SerializeAsString();
-  return grpc_slice_from_copied_buffer(enc_resp.data(), enc_resp.size());
-}
-
-static void drain_cq(grpc_completion_queue* cq) {
-  grpc_event ev;
-  do {
-    ev = grpc_completion_queue_next(cq, grpc_timeout_seconds_to_deadline(5),
-                                    nullptr);
-  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
-}
-
-static void sleep_ms(int delay_ms) {
-  gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
-                               gpr_time_from_millis(delay_ms, GPR_TIMESPAN)));
-}
-
-static void start_lb_server(server_fixture* sf, int* ports, size_t nports,
-                            int update_delay_ms) {
-  grpc_call* s;
-  cq_verifier* cqv = cq_verifier_create(sf->cq);
-  grpc_op ops[6];
-  grpc_op* op;
-  grpc_metadata_array request_metadata_recv;
-  grpc_call_details call_details;
-  grpc_call_error error;
-  int was_cancelled = 2;
-  grpc_byte_buffer* request_payload_recv;
-  grpc_byte_buffer* response_payload;
-
-  memset(ops, 0, sizeof(ops));
-  grpc_metadata_array_init(&request_metadata_recv);
-  grpc_call_details_init(&call_details);
-
-  error = grpc_server_request_call(sf->server, &s, &call_details,
-                                   &request_metadata_recv, sf->cq, sf->cq,
-                                   tag(200));
-  GPR_ASSERT(GRPC_CALL_OK == error);
-  gpr_log(GPR_INFO, "LB Server[%s](%s) up", sf->servers_hostport,
-          sf->balancer_name);
-  CQ_EXPECT_COMPLETION(cqv, tag(200), 1);
-  cq_verify(cqv);
-  gpr_log(GPR_INFO, "LB Server[%s](%s) after tag 200", sf->servers_hostport,
-          sf->balancer_name);
-
-  // make sure we've received the initial metadata from the grpclb request.
-  GPR_ASSERT(request_metadata_recv.count > 0);
-  GPR_ASSERT(request_metadata_recv.metadata != nullptr);
-
-  // receive request for backends
-  op = ops;
-  op->op = GRPC_OP_RECV_MESSAGE;
-  op->data.recv_message.recv_message = &request_payload_recv;
-  op->flags = 0;
-  op->reserved = nullptr;
-  op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(202), nullptr);
-  GPR_ASSERT(GRPC_CALL_OK == error);
-  CQ_EXPECT_COMPLETION(cqv, tag(202), 1);
-  cq_verify(cqv);
-  gpr_log(GPR_INFO, "LB Server[%s](%s) after RECV_MSG", sf->servers_hostport,
-          sf->balancer_name);
-
-  // validate initial request.
-  grpc_byte_buffer_reader bbr;
-  grpc_byte_buffer_reader_init(&bbr, request_payload_recv);
-  grpc_slice request_payload_slice = grpc_byte_buffer_reader_readall(&bbr);
-  grpc::lb::v1::LoadBalanceRequest request;
-  request.ParseFromArray(GRPC_SLICE_START_PTR(request_payload_slice),
-                         GRPC_SLICE_LENGTH(request_payload_slice));
-  GPR_ASSERT(request.has_initial_request());
-  GPR_ASSERT(request.initial_request().name() == sf->servers_hostport);
-  grpc_slice_unref(request_payload_slice);
-  grpc_byte_buffer_reader_destroy(&bbr);
-  grpc_byte_buffer_destroy(request_payload_recv);
-
-  grpc_slice response_payload_slice;
-  op = ops;
-  op->op = GRPC_OP_SEND_INITIAL_METADATA;
-  op->data.send_initial_metadata.count = 0;
-  op->flags = 0;
-  op->reserved = nullptr;
-  op++;
-  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
-  op->data.recv_close_on_server.cancelled = &was_cancelled;
-  op->flags = 0;
-  op->reserved = nullptr;
-  op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(201), nullptr);
-  GPR_ASSERT(GRPC_CALL_OK == error);
-  gpr_log(GPR_INFO, "LB Server[%s](%s) after tag 201", sf->servers_hostport,
-          sf->balancer_name);
-
-  for (int i = 0; i < 2; i++) {
-    if (i == 0) {
-      // First half of the ports.
-      response_payload_slice = build_response_payload_slice(
-          "127.0.0.1", ports, nports / 2, sf->lb_token_prefix);
-    } else {
-      // Second half of the ports.
-      sleep_ms(update_delay_ms);
-      response_payload_slice = build_response_payload_slice(
-          "127.0.0.1", ports + (nports / 2), (nports + 1) / 2 /* ceil */,
-          "" /* this half doesn't get to receive an LB token */);
-    }
-
-    response_payload = grpc_raw_byte_buffer_create(&response_payload_slice, 1);
-    op = ops;
-    op->op = GRPC_OP_SEND_MESSAGE;
-    op->data.send_message.send_message = response_payload;
-    op->flags = 0;
-    op->reserved = nullptr;
-    op++;
-    error =
-        grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(203), nullptr);
-    GPR_ASSERT(GRPC_CALL_OK == error);
-    CQ_EXPECT_COMPLETION(cqv, tag(203), 1);
-    cq_verify(cqv);
-    gpr_log(GPR_INFO, "LB Server[%s](%s) after SEND_MESSAGE, iter %d",
-            sf->servers_hostport, sf->balancer_name, i);
-
-    grpc_byte_buffer_destroy(response_payload);
-    grpc_slice_unref(response_payload_slice);
-  }
-  gpr_log(GPR_INFO, "LB Server[%s](%s) shutting down", sf->servers_hostport,
-          sf->balancer_name);
-
-  op = ops;
-  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
-  op->data.send_status_from_server.trailing_metadata_count = 0;
-  op->data.send_status_from_server.status = GRPC_STATUS_OK;
-  grpc_slice status_details = grpc_slice_from_static_string("xyz");
-  op->data.send_status_from_server.status_details = &status_details;
-  op->flags = 0;
-  op->reserved = nullptr;
-  op++;
-  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(204), nullptr);
-  GPR_ASSERT(GRPC_CALL_OK == error);
-
-  CQ_EXPECT_COMPLETION(cqv, tag(201), 1);
-  CQ_EXPECT_COMPLETION(cqv, tag(204), 1);
-  cq_verify(cqv);
-  gpr_log(GPR_INFO, "LB Server[%s](%s) after tag 204. All done. LB server out",
-          sf->servers_hostport, sf->balancer_name);
-
-  grpc_call_unref(s);
-
-  cq_verifier_destroy(cqv);
-
-  grpc_metadata_array_destroy(&request_metadata_recv);
-  grpc_call_details_destroy(&call_details);
-}
-
-static void start_backend_server(server_fixture* sf) {
-  grpc_call* s;
-  cq_verifier* cqv;
-  grpc_op ops[6];
-  grpc_op* op;
-  grpc_metadata_array request_metadata_recv;
-  grpc_call_details call_details;
-  grpc_call_error error;
-  int was_cancelled;
-  grpc_byte_buffer* request_payload_recv;
-  grpc_byte_buffer* response_payload;
-  grpc_event ev;
-
-  while (true) {
-    memset(ops, 0, sizeof(ops));
-    cqv = cq_verifier_create(sf->cq);
-    was_cancelled = 2;
-    grpc_metadata_array_init(&request_metadata_recv);
-    grpc_call_details_init(&call_details);
-
-    error = grpc_server_request_call(sf->server, &s, &call_details,
-                                     &request_metadata_recv, sf->cq, sf->cq,
-                                     tag(100));
-    GPR_ASSERT(GRPC_CALL_OK == error);
-    gpr_log(GPR_INFO, "Server[%s] up", sf->servers_hostport);
-    ev = grpc_completion_queue_next(
-        sf->cq, grpc_timeout_seconds_to_deadline(60), nullptr);
-    if (!ev.success) {
-      gpr_log(GPR_INFO, "Server[%s] being torn down", sf->servers_hostport);
-      cq_verifier_destroy(cqv);
-      grpc_metadata_array_destroy(&request_metadata_recv);
-      grpc_call_details_destroy(&call_details);
-      return;
-    }
-    GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
-    const string expected_token =
-        strlen(sf->lb_token_prefix) == 0
-            ? ""
-            : sf->lb_token_prefix + std::to_string(sf->port);
-    GPR_ASSERT(contains_metadata(&request_metadata_recv, "lb-token",
-                                 expected_token.c_str()));
-
-    gpr_log(GPR_INFO, "Server[%s] after tag 100", sf->servers_hostport);
-
-    op = ops;
-    op->op = GRPC_OP_SEND_INITIAL_METADATA;
-    op->data.send_initial_metadata.count = 0;
-    op->flags = 0;
-    op->reserved = nullptr;
-    op++;
-    op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
-    op->data.recv_close_on_server.cancelled = &was_cancelled;
-    op->flags = 0;
-    op->reserved = nullptr;
-    op++;
-    error =
-        grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(101), nullptr);
-    GPR_ASSERT(GRPC_CALL_OK == error);
-    gpr_log(GPR_INFO, "Server[%s] after tag 101", sf->servers_hostport);
-
-    bool exit = false;
-    grpc_slice response_payload_slice = grpc_slice_from_copied_string(PAYLOAD);
-    while (!exit) {
-      op = ops;
-      op->op = GRPC_OP_RECV_MESSAGE;
-      op->data.recv_message.recv_message = &request_payload_recv;
-      op->flags = 0;
-      op->reserved = nullptr;
-      op++;
-      error =
-          grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
-      GPR_ASSERT(GRPC_CALL_OK == error);
-      ev = grpc_completion_queue_next(
-          sf->cq, grpc_timeout_seconds_to_deadline(3), nullptr);
-      if (ev.type == GRPC_OP_COMPLETE && ev.success) {
-        GPR_ASSERT(ev.tag = tag(102));
-        if (request_payload_recv == nullptr) {
-          exit = true;
-          gpr_log(GPR_INFO,
-                  "Server[%s] recv \"close\" from client, exiting. Call #%d",
-                  sf->servers_hostport, sf->num_calls_serviced);
-        }
-      } else {
-        gpr_log(GPR_INFO, "Server[%s] forced to shutdown. Call #%d",
-                sf->servers_hostport, sf->num_calls_serviced);
-        exit = true;
-      }
-      gpr_log(GPR_INFO, "Server[%s] after tag 102. Call #%d",
-              sf->servers_hostport, sf->num_calls_serviced);
-
-      if (!exit) {
-        response_payload =
-            grpc_raw_byte_buffer_create(&response_payload_slice, 1);
-        op = ops;
-        op->op = GRPC_OP_SEND_MESSAGE;
-        op->data.send_message.send_message = response_payload;
-        op->flags = 0;
-        op->reserved = nullptr;
-        op++;
-        error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103),
-                                      nullptr);
-        GPR_ASSERT(GRPC_CALL_OK == error);
-        ev = grpc_completion_queue_next(
-            sf->cq, grpc_timeout_seconds_to_deadline(3), nullptr);
-        if (ev.type == GRPC_OP_COMPLETE && ev.success) {
-          GPR_ASSERT(ev.tag = tag(103));
-        } else {
-          gpr_log(GPR_INFO, "Server[%s] forced to shutdown. Call #%d",
-                  sf->servers_hostport, sf->num_calls_serviced);
-          exit = true;
-        }
-        gpr_log(GPR_INFO, "Server[%s] after tag 103. Call #%d",
-                sf->servers_hostport, sf->num_calls_serviced);
-        grpc_byte_buffer_destroy(response_payload);
-      }
-
-      grpc_byte_buffer_destroy(request_payload_recv);
-    }
-    ++sf->num_calls_serviced;
-
-    gpr_log(GPR_INFO, "Server[%s] OUT OF THE LOOP", sf->servers_hostport);
-    grpc_slice_unref(response_payload_slice);
-
-    op = ops;
-    op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
-    op->data.send_status_from_server.trailing_metadata_count = 0;
-    op->data.send_status_from_server.status = GRPC_STATUS_OK;
-    grpc_slice status_details =
-        grpc_slice_from_static_string("Backend server out a-ok");
-    op->data.send_status_from_server.status_details = &status_details;
-    op->flags = 0;
-    op->reserved = nullptr;
-    op++;
-    error =
-        grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), nullptr);
-    GPR_ASSERT(GRPC_CALL_OK == error);
-
-    CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
-    CQ_EXPECT_COMPLETION(cqv, tag(104), 1);
-    cq_verify(cqv);
-    gpr_log(GPR_INFO, "Server[%s] DONE. After servicing %d calls",
-            sf->servers_hostport, sf->num_calls_serviced);
-
-    grpc_call_unref(s);
-    cq_verifier_destroy(cqv);
-    grpc_metadata_array_destroy(&request_metadata_recv);
-    grpc_call_details_destroy(&call_details);
-  }
-}
-
-static void perform_request(client_fixture* cf) {
-  grpc_call* c;
-  cq_verifier* cqv = cq_verifier_create(cf->cq);
-  grpc_op ops[6];
-  grpc_op* op;
-  grpc_metadata_array initial_metadata_recv;
-  grpc_metadata_array trailing_metadata_recv;
-  grpc_status_code status;
-  grpc_call_error error;
-  grpc_slice details;
-  grpc_byte_buffer* request_payload;
-  grpc_byte_buffer* response_payload_recv;
-  int i;
-
-  memset(ops, 0, sizeof(ops));
-  grpc_slice request_payload_slice =
-      grpc_slice_from_copied_string("hello world");
-
-  grpc_slice host = grpc_slice_from_static_string("foo.test.google.fr:1234");
-  c = grpc_channel_create_call(cf->client, nullptr, GRPC_PROPAGATE_DEFAULTS,
-                               cf->cq, grpc_slice_from_static_string("/foo"),
-                               &host, grpc_timeout_seconds_to_deadline(5),
-                               nullptr);
-  gpr_log(GPR_INFO, "Call 0x%" PRIxPTR " created", (intptr_t)c);
-  GPR_ASSERT(c);
-  char* peer;
-
-  grpc_metadata_array_init(&initial_metadata_recv);
-  grpc_metadata_array_init(&trailing_metadata_recv);
-
-  op = ops;
-  op->op = GRPC_OP_SEND_INITIAL_METADATA;
-  op->data.send_initial_metadata.count = 0;
-  op->flags = 0;
-  op->reserved = nullptr;
-  op++;
-  op->op = GRPC_OP_RECV_INITIAL_METADATA;
-  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
-  op->flags = 0;
-  op->reserved = nullptr;
-  op++;
-  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
-  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
-  op->data.recv_status_on_client.status = &status;
-  op->data.recv_status_on_client.status_details = &details;
-  op->flags = 0;
-  op->reserved = nullptr;
-  op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
-  GPR_ASSERT(GRPC_CALL_OK == error);
-
-  for (i = 0; i < 4; i++) {
-    request_payload = grpc_raw_byte_buffer_create(&request_payload_slice, 1);
-
-    op = ops;
-    op->op = GRPC_OP_SEND_MESSAGE;
-    op->data.send_message.send_message = request_payload;
-    op->flags = 0;
-    op->reserved = nullptr;
-    op++;
-    op->op = GRPC_OP_RECV_MESSAGE;
-    op->data.recv_message.recv_message = &response_payload_recv;
-    op->flags = 0;
-    op->reserved = nullptr;
-    op++;
-    error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
-    GPR_ASSERT(GRPC_CALL_OK == error);
-
-    CQ_EXPECT_COMPLETION(cqv, tag(2), 1);
-    cq_verify(cqv);
-    gpr_log(GPR_INFO, "Client after sending msg %d / 4", i + 1);
-    GPR_ASSERT(byte_buffer_eq_string(response_payload_recv, PAYLOAD));
-
-    grpc_byte_buffer_destroy(request_payload);
-    grpc_byte_buffer_destroy(response_payload_recv);
-  }
-
-  grpc_slice_unref(request_payload_slice);
-
-  op = ops;
-  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
-  op->flags = 0;
-  op->reserved = nullptr;
-  op++;
-  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), nullptr);
-  GPR_ASSERT(GRPC_CALL_OK == error);
-
-  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
-  CQ_EXPECT_COMPLETION(cqv, tag(3), 1);
-  cq_verify(cqv);
-  peer = grpc_call_get_peer(c);
-  gpr_log(GPR_INFO, "Client DONE WITH SERVER %s ", peer);
-
-  grpc_call_unref(c);
-
-  cq_verify_empty_timeout(cqv, 1 /* seconds */);
-  cq_verifier_destroy(cqv);
-
-  grpc_metadata_array_destroy(&initial_metadata_recv);
-  grpc_metadata_array_destroy(&trailing_metadata_recv);
-  grpc_slice_unref(details);
-  gpr_log(GPR_INFO, "Client call (peer %s) DESTROYED.", peer);
-  gpr_free(peer);
-}
-
-#define BALANCERS_NAME "lb.name"
-static void setup_client(const server_fixture* lb_server,
-                         const server_fixture* backends, client_fixture* cf) {
-  grpc_core::ExecCtx exec_ctx;
-
-  char* expected_target_names = nullptr;
-  const char* backends_name = lb_server->servers_hostport;
-  gpr_asprintf(&expected_target_names, "%s;%s", backends_name, BALANCERS_NAME);
-
-  grpc_fake_resolver_response_generator* response_generator =
-      grpc_fake_resolver_response_generator_create();
-
-  grpc_lb_addresses* addresses = grpc_lb_addresses_create(1, nullptr);
-  char* lb_uri_str;
-  gpr_asprintf(&lb_uri_str, "ipv4:%s", lb_server->servers_hostport);
-  grpc_uri* lb_uri = grpc_uri_parse(lb_uri_str, true);
-  GPR_ASSERT(lb_uri != nullptr);
-  grpc_lb_addresses_set_address_from_uri(addresses, 0, lb_uri, true,
-                                         lb_server->balancer_name, nullptr);
-  grpc_uri_destroy(lb_uri);
-  gpr_free(lb_uri_str);
-
-  gpr_asprintf(&cf->server_uri, "fake:///%s", lb_server->servers_hostport);
-  const grpc_arg fake_addresses =
-      grpc_lb_addresses_create_channel_arg(addresses);
-  grpc_channel_args* fake_result =
-      grpc_channel_args_copy_and_add(nullptr, &fake_addresses, 1);
-  grpc_lb_addresses_destroy(addresses);
-
-  const grpc_arg new_args[] = {
-      grpc_fake_transport_expected_targets_arg(expected_target_names),
-      grpc_fake_resolver_response_generator_arg(response_generator)};
-
-  grpc_channel_args* args = grpc_channel_args_copy_and_add(
-      nullptr, new_args, GPR_ARRAY_SIZE(new_args));
-  gpr_free(expected_target_names);
-
-  cf->cq = grpc_completion_queue_create_for_next(nullptr);
-  grpc_channel_credentials* fake_creds =
-      grpc_fake_transport_security_credentials_create();
-  cf->client =
-      grpc_secure_channel_create(fake_creds, cf->server_uri, args, nullptr);
-  grpc_fake_resolver_response_generator_set_response(response_generator,
-                                                     fake_result);
-  grpc_channel_args_destroy(fake_result);
-  grpc_channel_credentials_unref(fake_creds);
-  grpc_channel_args_destroy(args);
-  grpc_fake_resolver_response_generator_unref(response_generator);
-}
-
-static void teardown_client(client_fixture* cf) {
-  grpc_completion_queue_shutdown(cf->cq);
-  drain_cq(cf->cq);
-  grpc_completion_queue_destroy(cf->cq);
-  cf->cq = nullptr;
-  grpc_channel_destroy(cf->client);
-  cf->client = nullptr;
-  gpr_free(cf->server_uri);
-}
-
-static void setup_server(const char* host, server_fixture* sf) {
-  int assigned_port;
-
-  sf->cq = grpc_completion_queue_create_for_next(nullptr);
-  const char* colon_idx = strchr(host, ':');
-  if (colon_idx) {
-    const char* port_str = colon_idx + 1;
-    sf->port = atoi(port_str);
-    sf->servers_hostport = gpr_strdup(host);
-  } else {
-    sf->port = grpc_pick_unused_port_or_die();
-    gpr_join_host_port(&sf->servers_hostport, host, sf->port);
-  }
-
-  grpc_server_credentials* server_creds =
-      grpc_fake_transport_security_server_credentials_create();
-
-  sf->server = grpc_server_create(nullptr, nullptr);
-  grpc_server_register_completion_queue(sf->server, sf->cq, nullptr);
-  GPR_ASSERT((assigned_port = grpc_server_add_secure_http2_port(
-                  sf->server, sf->servers_hostport, server_creds)) > 0);
-  grpc_server_credentials_release(server_creds);
-  GPR_ASSERT(sf->port == assigned_port);
-  grpc_server_start(sf->server);
-}
-
-static void teardown_server(server_fixture* sf) {
-  if (!sf->server) return;
-
-  gpr_log(GPR_INFO, "Server[%s] shutting down", sf->servers_hostport);
-
-  grpc_completion_queue* shutdown_cq =
-      grpc_completion_queue_create_for_pluck(nullptr);
-  grpc_server_shutdown_and_notify(sf->server, shutdown_cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(shutdown_cq, tag(1000),
-                                         grpc_timeout_seconds_to_deadline(5),
-                                         nullptr)
-                 .type == GRPC_OP_COMPLETE);
-  grpc_completion_queue_destroy(shutdown_cq);
-  grpc_server_destroy(sf->server);
-  gpr_thd_join(sf->tid);
-
-  sf->server = nullptr;
-  grpc_completion_queue_shutdown(sf->cq);
-  drain_cq(sf->cq);
-  grpc_completion_queue_destroy(sf->cq);
-
-  gpr_log(GPR_INFO, "Server[%s] bye bye", sf->servers_hostport);
-  gpr_free(sf->servers_hostport);
-}
-
-static void fork_backend_server(void* arg) {
-  server_fixture* sf = static_cast<server_fixture*>(arg);
-  start_backend_server(sf);
-}
-
-static void fork_lb_server(void* arg) {
-  test_fixture* tf = static_cast<test_fixture*>(arg);
-  int ports[NUM_BACKENDS];
-  for (int i = 0; i < NUM_BACKENDS; i++) {
-    ports[i] = tf->lb_backends[i].port;
-  }
-  start_lb_server(&tf->lb_server, ports, NUM_BACKENDS,
-                  tf->lb_server_update_delay_ms);
-}
-
-#define LB_TOKEN_PREFIX "token"
-static test_fixture setup_test_fixture(int lb_server_update_delay_ms) {
-  test_fixture tf;
-  memset(&tf, 0, sizeof(tf));
-  tf.lb_server_update_delay_ms = lb_server_update_delay_ms;
-
-  gpr_thd_options options = gpr_thd_options_default();
-  gpr_thd_options_set_joinable(&options);
-
-  for (int i = 0; i < NUM_BACKENDS; ++i) {
-    // Only the first half of the servers expect an LB token.
-    if (i < NUM_BACKENDS / 2) {
-      tf.lb_backends[i].lb_token_prefix = LB_TOKEN_PREFIX;
-    } else {
-      tf.lb_backends[i].lb_token_prefix = "";
-    }
-    setup_server("127.0.0.1", &tf.lb_backends[i]);
-    gpr_thd_new(&tf.lb_backends[i].tid, "grpclb_backend", fork_backend_server,
-                &tf.lb_backends[i], &options);
-  }
-
-  tf.lb_server.lb_token_prefix = LB_TOKEN_PREFIX;
-  tf.lb_server.balancer_name = BALANCERS_NAME;
-  setup_server("127.0.0.1", &tf.lb_server);
-  gpr_thd_new(&tf.lb_server.tid, "grpclb_server", fork_lb_server, &tf.lb_server,
-              &options);
-  setup_client(&tf.lb_server, tf.lb_backends, &tf.client);
-  return tf;
-}
-
-static void teardown_test_fixture(test_fixture* tf) {
-  teardown_client(&tf->client);
-  for (int i = 0; i < NUM_BACKENDS; ++i) {
-    teardown_server(&tf->lb_backends[i]);
-  }
-  teardown_server(&tf->lb_server);
-}
-
-// The LB server will send two updates: batch 1 and batch 2. Each batch contains
-// two addresses, both of a valid and running backend server. Batch 1 is readily
-// available and provided as soon as the client establishes the streaming call.
-// Batch 2 is sent after a delay of \a lb_server_update_delay_ms milliseconds.
-static test_fixture test_update(int lb_server_update_delay_ms) {
-  gpr_log(GPR_INFO, "start %s(%d)", __func__, lb_server_update_delay_ms);
-  test_fixture tf = setup_test_fixture(lb_server_update_delay_ms);
-  perform_request(
-      &tf.client);  // "consumes" 1st backend server of 1st serverlist
-  perform_request(
-      &tf.client);  // "consumes" 2nd backend server of 1st serverlist
-
-  perform_request(
-      &tf.client);  // "consumes" 1st backend server of 2nd serverlist
-  perform_request(
-      &tf.client);  // "consumes" 2nd backend server of 2nd serverlist
-
-  teardown_test_fixture(&tf);
-  gpr_log(GPR_INFO, "end %s(%d)", __func__, lb_server_update_delay_ms);
-  return tf;
-}
-
-TEST(GrpclbTest, Updates) {
-  grpc::test_fixture tf_result;
-  // Clients take at least one second to complete a call (the last part of the
-  // call sleeps for 1 second while verifying the client's completion queue is
-  // empty), more if the system is under load. Therefore:
-  //
-  // If the LB server waits 800ms before sending an update, it will arrive
-  // before the first client request finishes, skipping the second server from
-  // batch 1. All subsequent picks will come from the second half of the
-  // backends, those coming in the LB update.
-  tf_result = grpc::test_update(800);
-  GPR_ASSERT(tf_result.lb_backends[0].num_calls_serviced +
-                 tf_result.lb_backends[1].num_calls_serviced ==
-             1);
-  GPR_ASSERT(tf_result.lb_backends[2].num_calls_serviced +
-                 tf_result.lb_backends[3].num_calls_serviced >
-             0);
-  int num_serviced_calls = 0;
-  for (int i = 0; i < 4; i++) {
-    num_serviced_calls += tf_result.lb_backends[i].num_calls_serviced;
-  }
-  GPR_ASSERT(num_serviced_calls == 4);
-
-  // If the LB server waits 2500ms, the update arrives after two calls and three
-  // picks. The third pick will be the 1st server of the 1st update (RR policy
-  // going around). The fourth and final pick will come from the second LB
-  // update. In any case, the total number of serviced calls must again be equal
-  // to four across all the backends.
-  tf_result = grpc::test_update(2500);
-  GPR_ASSERT(tf_result.lb_backends[0].num_calls_serviced +
-                 tf_result.lb_backends[1].num_calls_serviced >=
-             2);
-  GPR_ASSERT(tf_result.lb_backends[2].num_calls_serviced +
-                 tf_result.lb_backends[3].num_calls_serviced >
-             0);
-  num_serviced_calls = 0;
-  for (int i = 0; i < 4; i++) {
-    num_serviced_calls += tf_result.lb_backends[i].num_calls_serviced;
-  }
-  GPR_ASSERT(num_serviced_calls == 4);
-}
-
-TEST(GrpclbTest, InvalidAddressInServerlist) {}
-
-}  // namespace
-}  // namespace grpc
-
-int main(int argc, char** argv) {
-  ::testing::InitGoogleTest(&argc, argv);
-  grpc_test_init(argc, argv);
-  // Make the backup poller poll very frequently in order to pick up
-  // updates from all the subchannels's FDs.
-  gpr_setenv("GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS", "1");
-  grpc_init();
-  const auto result = RUN_ALL_TESTS();
-  grpc_shutdown();
-  return result;
-}
diff --git a/test/cpp/interop/client.cc b/test/cpp/interop/client.cc
index 8958b98..ca8ee3d 100644
--- a/test/cpp/interop/client.cc
+++ b/test/cpp/interop/client.cc
@@ -20,12 +20,11 @@
 #include <unordered_map>
 
 #include <gflags/gflags.h>
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
 
 #include "src/core/lib/gpr/string.h"
 #include "test/cpp/interop/client_helper.h"
diff --git a/test/cpp/interop/client_helper.cc b/test/cpp/interop/client_helper.cc
index fee34c5..4041f95 100644
--- a/test/cpp/interop/client_helper.cc
+++ b/test/cpp/interop/client_helper.cc
@@ -23,12 +23,12 @@
 #include <sstream>
 
 #include <gflags/gflags.h>
-#include <grpc++/channel.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/security/credentials.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/security/credentials.h>
 
 #include "src/cpp/client/secure_credentials.h"
 #include "test/core/security/oauth2_utils.h"
diff --git a/test/cpp/interop/client_helper.h b/test/cpp/interop/client_helper.h
index f6e5bc9..eada2f6 100644
--- a/test/cpp/interop/client_helper.h
+++ b/test/cpp/interop/client_helper.h
@@ -22,7 +22,7 @@
 #include <memory>
 #include <unordered_map>
 
-#include <grpc++/channel.h>
+#include <grpcpp/channel.h>
 
 #include "src/core/lib/surface/call_test_only.h"
 
diff --git a/test/cpp/interop/http2_client.cc b/test/cpp/interop/http2_client.cc
index 7a9e3ce..821815c 100644
--- a/test/cpp/interop/http2_client.cc
+++ b/test/cpp/interop/http2_client.cc
@@ -19,11 +19,10 @@
 #include <thread>
 
 #include <gflags/gflags.h>
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
 
 #include "src/core/lib/transport/byte_stream.h"
 #include "src/proto/grpc/testing/messages.pb.h"
@@ -31,6 +30,7 @@
 #include "test/cpp/interop/http2_client.h"
 
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
 #include "test/cpp/util/create_test_channel.h"
 #include "test/cpp/util/test_config.h"
 
diff --git a/test/cpp/interop/http2_client.h b/test/cpp/interop/http2_client.h
index f64041a..2bcfdd6 100644
--- a/test/cpp/interop/http2_client.h
+++ b/test/cpp/interop/http2_client.h
@@ -21,8 +21,8 @@
 
 #include <memory>
 
-#include <grpc++/channel.h>
 #include <grpc/grpc.h>
+#include <grpcpp/channel.h>
 #include "src/proto/grpc/testing/messages.pb.h"
 #include "src/proto/grpc/testing/test.grpc.pb.h"
 
diff --git a/test/cpp/interop/interop_client.cc b/test/cpp/interop/interop_client.cc
index 6b59584..68bf1e6 100644
--- a/test/cpp/interop/interop_client.cc
+++ b/test/cpp/interop/interop_client.cc
@@ -20,15 +20,14 @@
 #include <fstream>
 #include <memory>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/security/credentials.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/security/credentials.h>
 
 #include "src/core/lib/transport/byte_stream.h"
 #include "src/proto/grpc/testing/empty.pb.h"
@@ -189,7 +188,7 @@
   request->mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
   if (request->has_expect_compressed()) {
     if (request->expect_compressed().value()) {
-      context.set_compression_algorithm(GRPC_COMPRESS_MESSAGE_GZIP);
+      context.set_compression_algorithm(GRPC_COMPRESS_GZIP);
     } else {
       context.set_compression_algorithm(GRPC_COMPRESS_NONE);
     }
@@ -497,7 +496,7 @@
   StreamingInputCallRequest request;
   StreamingInputCallResponse response;
 
-  context.set_compression_algorithm(GRPC_COMPRESS_MESSAGE_GZIP);
+  context.set_compression_algorithm(GRPC_COMPRESS_GZIP);
   std::unique_ptr<ClientWriter<StreamingInputCallRequest>> stream(
       serviceStub_.Get()->StreamingInputCall(&context, &response));
 
@@ -876,7 +875,8 @@
 
   // Create request with current timestamp
   gpr_timespec ts = gpr_now(GPR_CLOCK_PRECISE);
-  std::string timestamp = std::to_string((long long unsigned)ts.tv_nsec);
+  std::string timestamp =
+      std::to_string(static_cast<long long unsigned>(ts.tv_nsec));
   SimpleRequest request;
   request.mutable_payload()->set_body(timestamp.c_str(), timestamp.size());
 
@@ -915,7 +915,7 @@
   // Request 3
   // Modify the request body so it will not get a cache hit
   ts = gpr_now(GPR_CLOCK_PRECISE);
-  timestamp = std::to_string((long long unsigned)ts.tv_nsec);
+  timestamp = std::to_string(static_cast<long long unsigned>(ts.tv_nsec));
   SimpleRequest request1;
   request1.mutable_payload()->set_body(timestamp.c_str(), timestamp.size());
   ClientContext context3;
diff --git a/test/cpp/interop/interop_client.h b/test/cpp/interop/interop_client.h
index b8bb134..79ff24f 100644
--- a/test/cpp/interop/interop_client.h
+++ b/test/cpp/interop/interop_client.h
@@ -21,8 +21,8 @@
 
 #include <memory>
 
-#include <grpc++/channel.h>
 #include <grpc/grpc.h>
+#include <grpcpp/channel.h>
 #include "src/proto/grpc/testing/messages.pb.h"
 #include "src/proto/grpc/testing/test.grpc.pb.h"
 
diff --git a/test/cpp/interop/interop_server.cc b/test/cpp/interop/interop_server.cc
index 7cfdb2f..5fa1a33 100644
--- a/test/cpp/interop/interop_server.cc
+++ b/test/cpp/interop/interop_server.cc
@@ -22,14 +22,13 @@
 #include <thread>
 
 #include <gflags/gflags.h>
-#include <grpc++/security/server_credentials.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <grpc/support/useful.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
 
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/transport/byte_stream.h"
diff --git a/test/cpp/interop/interop_test.cc b/test/cpp/interop/interop_test.cc
index 563b7ab..ae155b6 100644
--- a/test/cpp/interop/interop_test.cc
+++ b/test/cpp/interop/interop_test.cc
@@ -31,12 +31,12 @@
 
 #include <gflags/gflags.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include "test/core/util/port.h"
 #include "test/cpp/util/test_config.h"
 
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/socket_utils_posix.h"
 
diff --git a/test/cpp/interop/metrics_client.cc b/test/cpp/interop/metrics_client.cc
index 1c62378..02cd564 100644
--- a/test/cpp/interop/metrics_client.cc
+++ b/test/cpp/interop/metrics_client.cc
@@ -20,8 +20,8 @@
 #include <string>
 
 #include <gflags/gflags.h>
-#include <grpc++/grpc++.h>
 #include <grpc/support/log.h>
+#include <grpcpp/grpcpp.h>
 
 #include "src/proto/grpc/testing/metrics.grpc.pb.h"
 #include "src/proto/grpc/testing/metrics.pb.h"
diff --git a/test/cpp/interop/reconnect_interop_client.cc b/test/cpp/interop/reconnect_interop_client.cc
index 2d9397a..9a451fa 100644
--- a/test/cpp/interop/reconnect_interop_client.cc
+++ b/test/cpp/interop/reconnect_interop_client.cc
@@ -20,11 +20,11 @@
 #include <sstream>
 
 #include <gflags/gflags.h>
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/support/channel_arguments.h>
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/support/channel_arguments.h>
 #include "src/proto/grpc/testing/empty.pb.h"
 #include "src/proto/grpc/testing/messages.pb.h"
 #include "src/proto/grpc/testing/test.grpc.pb.h"
diff --git a/test/cpp/interop/reconnect_interop_server.cc b/test/cpp/interop/reconnect_interop_server.cc
index 5e257e1..e690c8f 100644
--- a/test/cpp/interop/reconnect_interop_server.cc
+++ b/test/cpp/interop/reconnect_interop_server.cc
@@ -26,11 +26,11 @@
 #include <sstream>
 
 #include <gflags/gflags.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
 
 #include "src/proto/grpc/testing/empty.pb.h"
 #include "src/proto/grpc/testing/messages.pb.h"
diff --git a/test/cpp/interop/server_helper.cc b/test/cpp/interop/server_helper.cc
index be449a9..93ffd52 100644
--- a/test/cpp/interop/server_helper.cc
+++ b/test/cpp/interop/server_helper.cc
@@ -21,7 +21,7 @@
 #include <memory>
 
 #include <gflags/gflags.h>
-#include <grpc++/security/server_credentials.h>
+#include <grpcpp/security/server_credentials.h>
 
 #include "src/core/lib/surface/call_test_only.h"
 #include "test/cpp/util/test_credentials_provider.h"
diff --git a/test/cpp/interop/server_helper.h b/test/cpp/interop/server_helper.h
index 1bf7db1..3004e7f 100644
--- a/test/cpp/interop/server_helper.h
+++ b/test/cpp/interop/server_helper.h
@@ -25,8 +25,8 @@
 #include <grpc/compression.h>
 #include <grpc/impl/codegen/atm.h>
 
-#include <grpc++/security/server_credentials.h>
-#include <grpc++/server_context.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server_context.h>
 
 namespace grpc {
 namespace testing {
diff --git a/test/cpp/interop/stress_interop_client.cc b/test/cpp/interop/stress_interop_client.cc
index 7afddbb..30a8351 100644
--- a/test/cpp/interop/stress_interop_client.cc
+++ b/test/cpp/interop/stress_interop_client.cc
@@ -22,8 +22,8 @@
 #include <string>
 #include <vector>
 
-#include <grpc++/create_channel.h>
 #include <grpc/support/log.h>
+#include <grpcpp/create_channel.h>
 
 #include "test/cpp/interop/interop_client.h"
 #include "test/cpp/util/metrics_server.h"
diff --git a/test/cpp/interop/stress_interop_client.h b/test/cpp/interop/stress_interop_client.h
index ee15be0..a306dc3 100644
--- a/test/cpp/interop/stress_interop_client.h
+++ b/test/cpp/interop/stress_interop_client.h
@@ -23,7 +23,7 @@
 #include <string>
 #include <vector>
 
-#include <grpc++/create_channel.h>
+#include <grpcpp/create_channel.h>
 
 #include "test/cpp/interop/interop_client.h"
 #include "test/cpp/util/metrics_server.h"
diff --git a/test/cpp/interop/stress_test.cc b/test/cpp/interop/stress_test.cc
index 4b39dc3..6e8134a 100644
--- a/test/cpp/interop/stress_test.cc
+++ b/test/cpp/interop/stress_test.cc
@@ -23,10 +23,10 @@
 #include <vector>
 
 #include <gflags/gflags.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/grpc++.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/grpcpp.h>
 
 #include "src/proto/grpc/testing/metrics.grpc.pb.h"
 #include "src/proto/grpc/testing/metrics.pb.h"
diff --git a/test/cpp/microbenchmarks/BUILD b/test/cpp/microbenchmarks/BUILD
index 0b69e9b..67f7e44 100644
--- a/test/cpp/microbenchmarks/BUILD
+++ b/test/cpp/microbenchmarks/BUILD
@@ -143,3 +143,10 @@
     srcs = ["bm_metadata.cc"],
     deps = [":helpers"],
 )
+
+grpc_cc_binary(
+    name = "bm_chttp2_hpack",
+    testonly = 1,
+    srcs = ["bm_chttp2_hpack.cc"],
+    deps = [":helpers"],
+)
diff --git a/test/cpp/microbenchmarks/bm_call_create.cc b/test/cpp/microbenchmarks/bm_call_create.cc
index 5c2c38c..85a9f5e 100644
--- a/test/cpp/microbenchmarks/bm_call_create.cc
+++ b/test/cpp/microbenchmarks/bm_call_create.cc
@@ -23,11 +23,11 @@
 #include <string.h>
 #include <sstream>
 
-#include <grpc++/channel.h>
-#include <grpc++/support/channel_arguments.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/support/channel_arguments.h>
 
 #include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/filters/deadline/deadline_filter.h"
diff --git a/test/cpp/microbenchmarks/bm_chttp2_hpack.cc b/test/cpp/microbenchmarks/bm_chttp2_hpack.cc
index 4b73103..d0f3ec8 100644
--- a/test/cpp/microbenchmarks/bm_chttp2_hpack.cc
+++ b/test/cpp/microbenchmarks/bm_chttp2_hpack.cc
@@ -18,9 +18,11 @@
 
 /* Microbenchmarks around CHTTP2 HPACK operations */
 
+#include <benchmark/benchmark.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <string.h>
+#include <memory>
 #include <sstream>
 
 #include "src/core/ext/transport/chttp2/transport/hpack_encoder.h"
@@ -31,7 +33,6 @@
 #include "src/core/lib/transport/timeout_encoding.h"
 
 #include "test/cpp/microbenchmarks/helpers.h"
-#include "third_party/benchmark/include/benchmark/benchmark.h"
 
 auto& force_library_initialization = Library::get();
 
@@ -51,10 +52,11 @@
 static void BM_HpackEncoderInitDestroy(benchmark::State& state) {
   TrackCounters track_counters;
   grpc_core::ExecCtx exec_ctx;
-  grpc_chttp2_hpack_compressor c;
+  std::unique_ptr<grpc_chttp2_hpack_compressor> c(
+      new grpc_chttp2_hpack_compressor);
   while (state.KeepRunning()) {
-    grpc_chttp2_hpack_compressor_init(&c);
-    grpc_chttp2_hpack_compressor_destroy(&c);
+    grpc_chttp2_hpack_compressor_init(c.get());
+    grpc_chttp2_hpack_compressor_destroy(c.get());
     grpc_core::ExecCtx::Get()->Flush();
   }
 
@@ -71,8 +73,9 @@
   grpc_metadata_batch_init(&b);
   b.deadline = saved_now + 30 * 1000;
 
-  grpc_chttp2_hpack_compressor c;
-  grpc_chttp2_hpack_compressor_init(&c);
+  std::unique_ptr<grpc_chttp2_hpack_compressor> c(
+      new grpc_chttp2_hpack_compressor);
+  grpc_chttp2_hpack_compressor_init(c.get());
   grpc_transport_one_way_stats stats;
   memset(&stats, 0, sizeof(stats));
   grpc_slice_buffer outbuf;
@@ -82,15 +85,15 @@
         static_cast<uint32_t>(state.iterations()),
         true,
         false,
-        (size_t)1024,
+        static_cast<size_t>(1024),
         &stats,
     };
-    grpc_chttp2_encode_header(&c, nullptr, 0, &b, &hopt, &outbuf);
+    grpc_chttp2_encode_header(c.get(), nullptr, 0, &b, &hopt, &outbuf);
     grpc_slice_buffer_reset_and_unref_internal(&outbuf);
     grpc_core::ExecCtx::Get()->Flush();
   }
   grpc_metadata_batch_destroy(&b);
-  grpc_chttp2_hpack_compressor_destroy(&c);
+  grpc_chttp2_hpack_compressor_destroy(c.get());
   grpc_slice_buffer_destroy_internal(&outbuf);
 
   std::ostringstream label;
@@ -120,8 +123,9 @@
         "addmd", grpc_metadata_batch_add_tail(&b, &storage[i], elems[i])));
   }
 
-  grpc_chttp2_hpack_compressor c;
-  grpc_chttp2_hpack_compressor_init(&c);
+  std::unique_ptr<grpc_chttp2_hpack_compressor> c(
+      new grpc_chttp2_hpack_compressor);
+  grpc_chttp2_hpack_compressor_init(c.get());
   grpc_transport_one_way_stats stats;
   memset(&stats, 0, sizeof(stats));
   grpc_slice_buffer outbuf;
@@ -131,10 +135,10 @@
         static_cast<uint32_t>(state.iterations()),
         state.range(0) != 0,
         Fixture::kEnableTrueBinary,
-        (size_t)state.range(1),
+        static_cast<size_t>(state.range(1)),
         &stats,
     };
-    grpc_chttp2_encode_header(&c, nullptr, 0, &b, &hopt, &outbuf);
+    grpc_chttp2_encode_header(c.get(), nullptr, 0, &b, &hopt, &outbuf);
     if (!logged_representative_output && state.iterations() > 3) {
       logged_representative_output = true;
       for (size_t i = 0; i < outbuf.count; i++) {
@@ -147,7 +151,7 @@
     grpc_core::ExecCtx::Get()->Flush();
   }
   grpc_metadata_batch_destroy(&b);
-  grpc_chttp2_hpack_compressor_destroy(&c);
+  grpc_chttp2_hpack_compressor_destroy(c.get());
   grpc_slice_buffer_destroy_internal(&outbuf);
 
   std::ostringstream label;
@@ -777,7 +781,8 @@
       if (GRPC_MDELEM_IS_INTERNED(md)) {
         /* not already parsed: parse it now, and store the
          * result away */
-        cached_timeout = (grpc_millis*)gpr_malloc(sizeof(grpc_millis));
+        cached_timeout =
+            static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis)));
         *cached_timeout = timeout;
         grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
       }
diff --git a/test/cpp/microbenchmarks/bm_chttp2_transport.cc b/test/cpp/microbenchmarks/bm_chttp2_transport.cc
index fcb1677..d00c79b 100644
--- a/test/cpp/microbenchmarks/bm_chttp2_transport.cc
+++ b/test/cpp/microbenchmarks/bm_chttp2_transport.cc
@@ -18,10 +18,10 @@
 
 /* Microbenchmarks around CHTTP2 transport operations */
 
-#include <grpc++/support/channel_arguments.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
+#include <grpcpp/support/channel_arguments.h>
 #include <string.h>
 #include <memory>
 #include <queue>
@@ -398,13 +398,13 @@
     memset(&op, 0, sizeof(op));
     op.payload = &op_payload;
   };
-  grpc_slice_buffer_stream send_stream;
-  grpc_slice_buffer send_buffer;
-  grpc_slice_buffer_init(&send_buffer);
-  grpc_slice_buffer_add(&send_buffer, gpr_slice_malloc(state.range(0)));
-  memset(GRPC_SLICE_START_PTR(send_buffer.slices[0]), 0,
-         GRPC_SLICE_LENGTH(send_buffer.slices[0]));
-
+  // Create the send_message payload slice.
+  // Note: We use grpc_slice_malloc_large() instead of grpc_slice_malloc()
+  // to force the slice to be refcounted, so that it remains alive when it
+  // is unreffed after each send_message op.
+  grpc_slice send_slice = grpc_slice_malloc_large(state.range(0));
+  memset(GRPC_SLICE_START_PTR(send_slice), 0, GRPC_SLICE_LENGTH(send_slice));
+  grpc_core::ManualConstructor<grpc_core::SliceBufferByteStream> send_stream;
   grpc_metadata_batch b;
   grpc_metadata_batch_init(&b);
   b.deadline = GRPC_MILLIS_INF_FUTURE;
@@ -424,14 +424,18 @@
       gpr_event_set(bm_done, (void*)1);
       return;
     }
+    grpc_slice_buffer send_buffer;
+    grpc_slice_buffer_init(&send_buffer);
+    grpc_slice_buffer_add(&send_buffer, grpc_slice_ref(send_slice));
+    send_stream.Init(&send_buffer, 0);
+    grpc_slice_buffer_destroy(&send_buffer);
     // force outgoing window to be yuge
     s->chttp2_stream()->flow_control->TestOnlyForceHugeWindow();
     f.chttp2_transport()->flow_control->TestOnlyForceHugeWindow();
-    grpc_slice_buffer_stream_init(&send_stream, &send_buffer, 0);
     reset_op();
     op.on_complete = c.get();
     op.send_message = true;
-    op.payload->send_message.send_message = &send_stream.base;
+    op.payload->send_message.send_message.reset(send_stream.get());
     s->Op(&op);
   });
 
@@ -454,7 +458,7 @@
   s.reset();
   track_counters.Finish(state);
   grpc_metadata_batch_destroy(&b);
-  grpc_slice_buffer_destroy(&send_buffer);
+  grpc_slice_unref(send_slice);
 }
 BENCHMARK(BM_TransportStreamSend)->Range(0, 128 * 1024 * 1024);
 
@@ -524,7 +528,7 @@
   grpc_transport_stream_op_batch_payload op_payload;
   memset(&op_payload, 0, sizeof(op_payload));
   grpc_transport_stream_op_batch op;
-  grpc_byte_stream* recv_stream;
+  grpc_core::OrphanablePtr<grpc_core::ByteStream> recv_stream;
   grpc_slice incoming_data = CreateIncomingDataSlice(state.range(0), 16384);
 
   auto reset_op = [&]() {
@@ -579,21 +583,20 @@
 
   drain = MakeClosure([&](grpc_error* error) {
     do {
-      if (received == recv_stream->length) {
-        grpc_byte_stream_destroy(recv_stream);
+      if (received == recv_stream->length()) {
+        recv_stream.reset();
         GRPC_CLOSURE_SCHED(c.get(), GRPC_ERROR_NONE);
         return;
       }
-    } while (grpc_byte_stream_next(recv_stream, recv_stream->length - received,
-                                   drain_continue.get()) &&
-             GRPC_ERROR_NONE ==
-                 grpc_byte_stream_pull(recv_stream, &recv_slice) &&
+    } while (recv_stream->Next(recv_stream->length() - received,
+                               drain_continue.get()) &&
+             GRPC_ERROR_NONE == recv_stream->Pull(&recv_slice) &&
              (received += GRPC_SLICE_LENGTH(recv_slice),
               grpc_slice_unref_internal(recv_slice), true));
   });
 
   drain_continue = MakeClosure([&](grpc_error* error) {
-    grpc_byte_stream_pull(recv_stream, &recv_slice);
+    recv_stream->Pull(&recv_slice);
     received += GRPC_SLICE_LENGTH(recv_slice);
     grpc_slice_unref_internal(recv_slice);
     GRPC_CLOSURE_RUN(drain.get(), GRPC_ERROR_NONE);
diff --git a/test/cpp/microbenchmarks/bm_cq.cc b/test/cpp/microbenchmarks/bm_cq.cc
index 9724259..342a95e 100644
--- a/test/cpp/microbenchmarks/bm_cq.cc
+++ b/test/cpp/microbenchmarks/bm_cq.cc
@@ -20,10 +20,10 @@
  * working */
 
 #include <benchmark/benchmark.h>
-#include <grpc++/completion_queue.h>
-#include <grpc++/impl/grpc_library.h>
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
+#include <grpcpp/completion_queue.h>
+#include <grpcpp/impl/grpc_library.h>
 #include "test/cpp/microbenchmarks/helpers.h"
 
 #include "src/core/lib/surface/completion_queue.h"
diff --git a/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc b/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
index 874c834..ec79b95 100644
--- a/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
+++ b/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
@@ -38,7 +38,7 @@
 
 auto& force_library_initialization = Library::get();
 
-static void* g_tag = (void*)(intptr_t)10;  // Some random number
+static void* g_tag = (void*)static_cast<intptr_t>(10);  // Some random number
 static grpc_completion_queue* g_cq;
 static grpc_event_engine_vtable g_vtable;
 static const grpc_event_engine_vtable* g_old_vtable;
@@ -74,8 +74,9 @@
 
   gpr_mu_unlock(&ps->mu);
   GPR_ASSERT(grpc_cq_begin_op(g_cq, g_tag));
-  grpc_cq_end_op(g_cq, g_tag, GRPC_ERROR_NONE, cq_done_cb, nullptr,
-                 (grpc_cq_completion*)gpr_malloc(sizeof(grpc_cq_completion)));
+  grpc_cq_end_op(
+      g_cq, g_tag, GRPC_ERROR_NONE, cq_done_cb, nullptr,
+      static_cast<grpc_cq_completion*>(gpr_malloc(sizeof(grpc_cq_completion))));
   grpc_core::ExecCtx::Get()->Flush();
   gpr_mu_lock(&ps->mu);
   return GRPC_ERROR_NONE;
diff --git a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc
index 294f1fe..3b21c4c 100644
--- a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc
+++ b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc
@@ -394,13 +394,13 @@
         stub->AsyncEcho(&cli_ctx, send_request, fixture->cq()));
     void* t;
     bool ok;
+    response_reader->Finish(&recv_response, &recv_status, tag(4));
     TrickleCQNext(fixture.get(), &t, &ok, in_warmup ? -1 : state.iterations());
     GPR_ASSERT(ok);
     GPR_ASSERT(t == tag(0) || t == tag(1));
     intptr_t slot = reinterpret_cast<intptr_t>(t);
     ServerEnv* senv = server_env[slot];
     senv->response_writer.Finish(send_response, Status::OK, tag(3));
-    response_reader->Finish(&recv_response, &recv_status, tag(4));
     for (int i = (1 << 3) | (1 << 4); i != 0;) {
       TrickleCQNext(fixture.get(), &t, &ok,
                     in_warmup ? -1 : state.iterations());
diff --git a/test/cpp/microbenchmarks/bm_pollset.cc b/test/cpp/microbenchmarks/bm_pollset.cc
index d9d5164..f49f667 100644
--- a/test/cpp/microbenchmarks/bm_pollset.cc
+++ b/test/cpp/microbenchmarks/bm_pollset.cc
@@ -21,8 +21,8 @@
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/useful.h>
 
+#include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/pollset.h"
 #include "src/core/lib/iomgr/port.h"
diff --git a/test/cpp/microbenchmarks/fullstack_context_mutators.h b/test/cpp/microbenchmarks/fullstack_context_mutators.h
index cafbeff..6e7fd57 100644
--- a/test/cpp/microbenchmarks/fullstack_context_mutators.h
+++ b/test/cpp/microbenchmarks/fullstack_context_mutators.h
@@ -19,14 +19,14 @@
 #ifndef TEST_CPP_MICROBENCHMARKS_FULLSTACK_CONTEXT_MUTATORS_H
 #define TEST_CPP_MICROBENCHMARKS_FULLSTACK_CONTEXT_MUTATORS_H
 
-#include <grpc++/channel.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/security/credentials.h>
-#include <grpc++/security/server_credentials.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
 #include <grpc/support/log.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
 
 #include "test/cpp/microbenchmarks/helpers.h"
 
@@ -72,7 +72,7 @@
     grpc::string s;
     s.reserve(length + 1);
     for (int i = 0; i < length; i++) {
-      s += (char)rand();
+      s += static_cast<char>(rand());
     }
     return s;
   }
@@ -95,7 +95,7 @@
     grpc::string s;
     s.reserve(length + 1);
     for (int i = 0; i < length; i++) {
-      s += (char)(rand() % 26 + 'a');
+      s += static_cast<char>(rand() % 26 + 'a');
     }
     return s;
   }
diff --git a/test/cpp/microbenchmarks/fullstack_fixtures.h b/test/cpp/microbenchmarks/fullstack_fixtures.h
index d73caa0..9d70277 100644
--- a/test/cpp/microbenchmarks/fullstack_fixtures.h
+++ b/test/cpp/microbenchmarks/fullstack_fixtures.h
@@ -19,14 +19,14 @@
 #ifndef TEST_CPP_MICROBENCHMARKS_FULLSTACK_FIXTURES_H
 #define TEST_CPP_MICROBENCHMARKS_FULLSTACK_FIXTURES_H
 
-#include <grpc++/channel.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/security/credentials.h>
-#include <grpc++/security/server_credentials.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
 #include <grpc/support/atm.h>
 #include <grpc/support/log.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
 
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/channel_args.h"
@@ -61,6 +61,15 @@
 
 class BaseFixture : public TrackCounters {};
 
+// Special tag to be used in Server shutdown. This tag is *NEVER* returned when
+// Cq->Next() API is called (This is because FinalizeResult() function in this
+// class always returns 'false'). This is intentional and makes writing shutdown
+// code easier.
+class ShutdownTag : public internal::CompletionQueueTag {
+ public:
+  bool FinalizeResult(void** tag, bool* status) { return false; }
+};
+
 class FullstackFixture : public BaseFixture {
  public:
   FullstackFixture(Service* service, const FixtureConfiguration& config,
@@ -84,7 +93,11 @@
   }
 
   virtual ~FullstackFixture() {
-    server_->Shutdown(gpr_inf_past(GPR_CLOCK_MONOTONIC));
+    // Dummy shutdown tag (this tag is swallowed by cq->Next() and is not
+    // returned to the user) see ShutdownTag definition for more details
+    ShutdownTag shutdown_tag;
+    grpc_server_shutdown_and_notify(server_->c_server(), cq_->cq(),
+                                    &shutdown_tag);
     cq_->Shutdown();
     void* tag;
     bool ok;
@@ -95,7 +108,8 @@
   void AddToLabel(std::ostream& out, benchmark::State& state) {
     BaseFixture::AddToLabel(out, state);
     out << " polls/iter:"
-        << (double)grpc_get_cq_poll_num(this->cq()->cq()) / state.iterations();
+        << static_cast<double>(grpc_get_cq_poll_num(this->cq()->cq())) /
+               state.iterations();
   }
 
   ServerCompletionQueue* cq() { return cq_.get(); }
@@ -208,7 +222,11 @@
   }
 
   virtual ~EndpointPairFixture() {
-    server_->Shutdown(gpr_inf_past(GPR_CLOCK_MONOTONIC));
+    // Dummy shutdown tag (this tag is swallowed by cq->Next() and is not
+    // returned to the user) see ShutdownTag definition for more details
+    ShutdownTag shutdown_tag;
+    grpc_server_shutdown_and_notify(server_->c_server(), cq_->cq(),
+                                    &shutdown_tag);
     cq_->Shutdown();
     void* tag;
     bool ok;
@@ -219,7 +237,8 @@
   void AddToLabel(std::ostream& out, benchmark::State& state) {
     BaseFixture::AddToLabel(out, state);
     out << " polls/iter:"
-        << (double)grpc_get_cq_poll_num(this->cq()->cq()) / state.iterations();
+        << static_cast<double>(grpc_get_cq_poll_num(this->cq()->cq())) /
+               state.iterations();
   }
 
   ServerCompletionQueue* cq() { return cq_.get(); }
diff --git a/test/cpp/microbenchmarks/fullstack_streaming_ping_pong.h b/test/cpp/microbenchmarks/fullstack_streaming_ping_pong.h
index 0763d07..f399949 100644
--- a/test/cpp/microbenchmarks/fullstack_streaming_ping_pong.h
+++ b/test/cpp/microbenchmarks/fullstack_streaming_ping_pong.h
@@ -83,7 +83,7 @@
       while (need_tags) {
         GPR_ASSERT(fixture->cq()->Next(&t, &ok));
         GPR_ASSERT(ok);
-        int i = (int)(intptr_t)t;
+        int i = static_cast<int>((intptr_t)t);
         GPR_ASSERT(need_tags & (1 << i));
         need_tags &= ~(1 << i);
       }
@@ -99,7 +99,7 @@
         while (need_tags) {
           GPR_ASSERT(fixture->cq()->Next(&t, &ok));
           GPR_ASSERT(ok);
-          int i = (int)(intptr_t)t;
+          int i = static_cast<int>((intptr_t)t);
 
           // If server recv is complete, start the server send operation
           if (i == 1) {
@@ -122,7 +122,7 @@
       need_tags = (1 << 0) | (1 << 1) | (1 << 2);
       while (need_tags) {
         GPR_ASSERT(fixture->cq()->Next(&t, &ok));
-        int i = (int)(intptr_t)t;
+        int i = static_cast<int>((intptr_t)t);
         GPR_ASSERT(need_tags & (1 << i));
         need_tags &= ~(1 << i);
       }
@@ -175,7 +175,7 @@
     while (need_tags) {
       GPR_ASSERT(fixture->cq()->Next(&t, &ok));
       GPR_ASSERT(ok);
-      int i = (int)(intptr_t)t;
+      int i = static_cast<int>((intptr_t)t);
       GPR_ASSERT(need_tags & (1 << i));
       need_tags &= ~(1 << i);
     }
@@ -190,7 +190,7 @@
       while (need_tags) {
         GPR_ASSERT(fixture->cq()->Next(&t, &ok));
         GPR_ASSERT(ok);
-        int i = (int)(intptr_t)t;
+        int i = static_cast<int>((intptr_t)t);
 
         // If server recv is complete, start the server send operation
         if (i == 1) {
@@ -210,7 +210,7 @@
     need_tags = (1 << 0) | (1 << 1) | (1 << 2);
     while (need_tags) {
       GPR_ASSERT(fixture->cq()->Next(&t, &ok));
-      int i = (int)(intptr_t)t;
+      int i = static_cast<int>((intptr_t)t);
       GPR_ASSERT(need_tags & (1 << i));
       need_tags &= ~(1 << i);
     }
@@ -297,10 +297,10 @@
           // established). It is necessary when client init metadata is
           // coalesced
           GPR_ASSERT(fixture->cq()->Next(&t, &ok));
-          while ((int)(intptr_t)t != 0) {
+          while (static_cast<int>((intptr_t)t) != 0) {
             // In some cases tag:2 comes before tag:0 (write tag comes out
             // first), this while loop is to make sure get tag:0.
-            int i = (int)(intptr_t)t;
+            int i = static_cast<int>((intptr_t)t);
             GPR_ASSERT(await_tags & (1 << i));
             await_tags &= ~(1 << i);
             GPR_ASSERT(fixture->cq()->Next(&t, &ok));
@@ -317,7 +317,7 @@
         while (await_tags != 0) {
           GPR_ASSERT(fixture->cq()->Next(&t, &ok));
           GPR_ASSERT(ok);
-          int i = (int)(intptr_t)t;
+          int i = static_cast<int>((intptr_t)t);
 
           // If server recv is complete, start the server send operation
           if (i == 3) {
@@ -367,8 +367,8 @@
         // wait for server call data structure(call_hook, etc.) to be
         // initialized, since initial metadata is corked.
         GPR_ASSERT(fixture->cq()->Next(&t, &ok));
-        while ((int)(intptr_t)t != 0) {
-          int i = (int)(intptr_t)t;
+        while (static_cast<int>((intptr_t)t) != 0) {
+          int i = static_cast<int>((intptr_t)t);
           GPR_ASSERT(expect_tags & (1 << i));
           expect_tags &= ~(1 << i);
           GPR_ASSERT(fixture->cq()->Next(&t, &ok));
@@ -385,7 +385,7 @@
 
       while (expect_tags) {
         GPR_ASSERT(fixture->cq()->Next(&t, &ok));
-        int i = (int)(intptr_t)t;
+        int i = static_cast<int>((intptr_t)t);
         GPR_ASSERT(expect_tags & (1 << i));
         expect_tags &= ~(1 << i);
       }
diff --git a/test/cpp/microbenchmarks/fullstack_streaming_pump.h b/test/cpp/microbenchmarks/fullstack_streaming_pump.h
index 9e82609..3623e37 100644
--- a/test/cpp/microbenchmarks/fullstack_streaming_pump.h
+++ b/test/cpp/microbenchmarks/fullstack_streaming_pump.h
@@ -62,7 +62,7 @@
     while (need_tags) {
       GPR_ASSERT(fixture->cq()->Next(&t, &ok));
       GPR_ASSERT(ok);
-      int i = (int)(intptr_t)t;
+      int i = static_cast<int>((intptr_t)t);
       GPR_ASSERT(need_tags & (1 << i));
       need_tags &= ~(1 << i);
     }
@@ -85,7 +85,7 @@
     need_tags = (1 << 0) | (1 << 1);
     while (need_tags) {
       GPR_ASSERT(fixture->cq()->Next(&t, &ok));
-      int i = (int)(intptr_t)t;
+      int i = static_cast<int>((intptr_t)t);
       GPR_ASSERT(need_tags & (1 << i));
       need_tags &= ~(1 << i);
     }
@@ -95,7 +95,7 @@
     need_tags = (1 << 0) | (1 << 1);
     while (need_tags) {
       GPR_ASSERT(fixture->cq()->Next(&t, &ok));
-      int i = (int)(intptr_t)t;
+      int i = static_cast<int>((intptr_t)t);
       GPR_ASSERT(need_tags & (1 << i));
       need_tags &= ~(1 << i);
     }
@@ -131,7 +131,7 @@
     while (need_tags) {
       GPR_ASSERT(fixture->cq()->Next(&t, &ok));
       GPR_ASSERT(ok);
-      int i = (int)(intptr_t)t;
+      int i = static_cast<int>((intptr_t)t);
       GPR_ASSERT(need_tags & (1 << i));
       need_tags &= ~(1 << i);
     }
@@ -154,7 +154,7 @@
     need_tags = (1 << 0) | (1 << 1);
     while (need_tags) {
       GPR_ASSERT(fixture->cq()->Next(&t, &ok));
-      int i = (int)(intptr_t)t;
+      int i = static_cast<int>((intptr_t)t);
       GPR_ASSERT(need_tags & (1 << i));
       need_tags &= ~(1 << i);
     }
diff --git a/test/cpp/microbenchmarks/fullstack_unary_ping_pong.h b/test/cpp/microbenchmarks/fullstack_unary_ping_pong.h
index d448938..843c8e1 100644
--- a/test/cpp/microbenchmarks/fullstack_unary_ping_pong.h
+++ b/test/cpp/microbenchmarks/fullstack_unary_ping_pong.h
@@ -78,6 +78,7 @@
     ClientContextMutator cli_ctx_mut(&cli_ctx);
     std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
         stub->AsyncEcho(&cli_ctx, send_request, fixture->cq()));
+    response_reader->Finish(&recv_response, &recv_status, tag(4));
     void* t;
     bool ok;
     GPR_ASSERT(fixture->cq()->Next(&t, &ok));
@@ -87,11 +88,10 @@
     ServerEnv* senv = server_env[slot];
     ServerContextMutator svr_ctx_mut(&senv->ctx);
     senv->response_writer.Finish(send_response, Status::OK, tag(3));
-    response_reader->Finish(&recv_response, &recv_status, tag(4));
     for (int i = (1 << 3) | (1 << 4); i != 0;) {
       GPR_ASSERT(fixture->cq()->Next(&t, &ok));
       GPR_ASSERT(ok);
-      int tagnum = (int)reinterpret_cast<intptr_t>(t);
+      int tagnum = static_cast<int>(reinterpret_cast<intptr_t>(t));
       GPR_ASSERT(i & (1 << tagnum));
       i -= 1 << tagnum;
     }
diff --git a/test/cpp/microbenchmarks/helpers.cc b/test/cpp/microbenchmarks/helpers.cc
index a4c0a3a..e4a31f5 100644
--- a/test/cpp/microbenchmarks/helpers.cc
+++ b/test/cpp/microbenchmarks/helpers.cc
@@ -43,18 +43,21 @@
   grpc_stats_data stats;
   grpc_stats_diff(&stats_end, &stats_begin_, &stats);
   for (int i = 0; i < GRPC_STATS_COUNTER_COUNT; i++) {
-    out << " " << grpc_stats_counter_name[i]
-        << "/iter:" << ((double)stats.counters[i] / (double)state.iterations());
+    out << " " << grpc_stats_counter_name[i] << "/iter:"
+        << (static_cast<double>(stats.counters[i]) /
+            static_cast<double>(state.iterations()));
   }
   for (int i = 0; i < GRPC_STATS_HISTOGRAM_COUNT; i++) {
     std::ostringstream median_ss;
     median_ss << grpc_stats_histogram_name[i] << "-median";
-    state.counters[median_ss.str()] = benchmark::Counter(
-        grpc_stats_histo_percentile(&stats, (grpc_stats_histograms)i, 50.0));
+    state.counters[median_ss.str()] =
+        benchmark::Counter(grpc_stats_histo_percentile(
+            &stats, static_cast<grpc_stats_histograms>(i), 50.0));
     std::ostringstream tail_ss;
     tail_ss << grpc_stats_histogram_name[i] << "-99p";
-    state.counters[tail_ss.str()] = benchmark::Counter(
-        grpc_stats_histo_percentile(&stats, (grpc_stats_histograms)i, 99.0));
+    state.counters[tail_ss.str()] =
+        benchmark::Counter(grpc_stats_histo_percentile(
+            &stats, static_cast<grpc_stats_histograms>(i), 99.0));
   }
 #ifdef GPR_LOW_LEVEL_COUNTERS
   grpc_memory_counters counters_at_end = grpc_memory_counters_snapshot();
diff --git a/test/cpp/microbenchmarks/helpers.h b/test/cpp/microbenchmarks/helpers.h
index afa3e0f..4aabd40 100644
--- a/test/cpp/microbenchmarks/helpers.h
+++ b/test/cpp/microbenchmarks/helpers.h
@@ -27,7 +27,7 @@
 #include "test/core/util/memory_counters.h"
 
 #include <benchmark/benchmark.h>
-#include <grpc++/impl/grpc_library.h>
+#include <grpcpp/impl/grpc_library.h>
 
 class Library {
  public:
diff --git a/test/cpp/naming/BUILD b/test/cpp/naming/BUILD
index 24c3d1a..54b53d2 100644
--- a/test/cpp/naming/BUILD
+++ b/test/cpp/naming/BUILD
@@ -34,16 +34,4 @@
     ],
 )
 
-grpc_py_binary(
-  name = "test_dns_server",
-  srcs = ["test_dns_server.py"],
-  data = [
-      "resolver_test_record_groups.yaml",
-  ],
-  deps = [
-      "twisted",
-      "yaml",
-  ]
-)
-
 generate_resolver_component_tests()
diff --git a/test/cpp/naming/address_sorting_test.cc b/test/cpp/naming/address_sorting_test.cc
new file mode 100644
index 0000000..df93ff6
--- /dev/null
+++ b/test/cpp/naming/address_sorting_test.cc
@@ -0,0 +1,737 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.h>
+#include <string.h>
+
+#include <arpa/inet.h>
+#include <gflags/gflags.h>
+#include <gmock/gmock.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <vector>
+
+#include <address_sorting/address_sorting.h>
+#include "test/cpp/util/subprocess.h"
+#include "test/cpp/util/test_config.h"
+
+#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/resolver.h"
+#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
+#include "src/core/ext/filters/client_channel/resolver_registry.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/host_port.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/iomgr/combiner.h"
+#include "src/core/lib/iomgr/executor.h"
+#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+
+namespace {
+
+struct TestAddress {
+  std::string dest_addr;
+  int family;
+};
+
+grpc_resolved_address TestAddressToGrpcResolvedAddress(TestAddress test_addr) {
+  char* host;
+  char* port;
+  grpc_resolved_address resolved_addr;
+  gpr_split_host_port(test_addr.dest_addr.c_str(), &host, &port);
+  if (test_addr.family == AF_INET) {
+    sockaddr_in in_dest;
+    memset(&in_dest, 0, sizeof(sockaddr_in));
+    in_dest.sin_port = htons(atoi(port));
+    in_dest.sin_family = AF_INET;
+    GPR_ASSERT(inet_pton(AF_INET, host, &in_dest.sin_addr) == 1);
+    memcpy(&resolved_addr.addr, &in_dest, sizeof(sockaddr_in));
+    resolved_addr.len = sizeof(sockaddr_in);
+  } else {
+    GPR_ASSERT(test_addr.family == AF_INET6);
+    sockaddr_in6 in6_dest;
+    memset(&in6_dest, 0, sizeof(sockaddr_in6));
+    in6_dest.sin6_port = htons(atoi(port));
+    in6_dest.sin6_family = AF_INET6;
+    GPR_ASSERT(inet_pton(AF_INET6, host, &in6_dest.sin6_addr) == 1);
+    memcpy(&resolved_addr.addr, &in6_dest, sizeof(sockaddr_in6));
+    resolved_addr.len = sizeof(sockaddr_in6);
+  }
+  gpr_free(host);
+  gpr_free(port);
+  return resolved_addr;
+}
+
+class MockSourceAddrFactory : public address_sorting_source_addr_factory {
+ public:
+  MockSourceAddrFactory(
+      bool ipv4_supported, bool ipv6_supported,
+      const std::map<std::string, TestAddress>& dest_addr_to_src_addr)
+      : ipv4_supported_(ipv4_supported),
+        ipv6_supported_(ipv6_supported),
+        dest_addr_to_src_addr_(dest_addr_to_src_addr) {}
+
+  bool GetSourceAddr(const address_sorting_address* dest_addr,
+                     address_sorting_address* source_addr) {
+    if ((address_sorting_abstract_get_family(dest_addr) ==
+             ADDRESS_SORTING_AF_INET &&
+         !ipv4_supported_) ||
+        (address_sorting_abstract_get_family(dest_addr) ==
+             ADDRESS_SORTING_AF_INET6 &&
+         !ipv6_supported_)) {
+      return false;
+    }
+    char* ip_addr_str;
+    grpc_resolved_address dest_addr_as_resolved_addr;
+    memcpy(&dest_addr_as_resolved_addr.addr, dest_addr, dest_addr->len);
+    dest_addr_as_resolved_addr.len = dest_addr->len;
+    grpc_sockaddr_to_string(&ip_addr_str, &dest_addr_as_resolved_addr,
+                            false /* normalize */);
+    auto it = dest_addr_to_src_addr_.find(ip_addr_str);
+    if (it == dest_addr_to_src_addr_.end()) {
+      gpr_log(GPR_DEBUG, "can't find |%s| in dest to src map", ip_addr_str);
+      gpr_free(ip_addr_str);
+      return false;
+    }
+    gpr_free(ip_addr_str);
+    grpc_resolved_address source_addr_as_resolved_addr =
+        TestAddressToGrpcResolvedAddress(it->second);
+    memcpy(source_addr->addr, &source_addr_as_resolved_addr.addr,
+           source_addr_as_resolved_addr.len);
+    source_addr->len = source_addr_as_resolved_addr.len;
+    return true;
+  }
+
+ private:
+  // user provided test config
+  bool ipv4_supported_;
+  bool ipv6_supported_;
+  std::map<std::string, TestAddress> dest_addr_to_src_addr_;
+};
+
+static bool mock_source_addr_factory_wrapper_get_source_addr(
+    address_sorting_source_addr_factory* factory,
+    const address_sorting_address* dest_addr,
+    address_sorting_address* source_addr) {
+  MockSourceAddrFactory* mock =
+      reinterpret_cast<MockSourceAddrFactory*>(factory);
+  return mock->GetSourceAddr(dest_addr, source_addr);
+}
+
+void mock_source_addr_factory_wrapper_destroy(
+    address_sorting_source_addr_factory* factory) {
+  MockSourceAddrFactory* mock =
+      reinterpret_cast<MockSourceAddrFactory*>(factory);
+  delete mock;
+}
+
+const address_sorting_source_addr_factory_vtable kMockSourceAddrFactoryVtable =
+    {
+        mock_source_addr_factory_wrapper_get_source_addr,
+        mock_source_addr_factory_wrapper_destroy,
+};
+
+void OverrideAddressSortingSourceAddrFactory(
+    bool ipv4_supported, bool ipv6_supported,
+    const std::map<std::string, TestAddress>& dest_addr_to_src_addr) {
+  address_sorting_source_addr_factory* factory = new MockSourceAddrFactory(
+      ipv4_supported, ipv6_supported, dest_addr_to_src_addr);
+  factory->vtable = &kMockSourceAddrFactoryVtable;
+  address_sorting_override_source_addr_factory_for_testing(factory);
+}
+
+grpc_lb_addresses* BuildLbAddrInputs(std::vector<TestAddress> test_addrs) {
+  grpc_lb_addresses* lb_addrs = grpc_lb_addresses_create(0, nullptr);
+  lb_addrs->addresses =
+      (grpc_lb_address*)gpr_zalloc(sizeof(grpc_lb_address) * test_addrs.size());
+  lb_addrs->num_addresses = test_addrs.size();
+  for (size_t i = 0; i < test_addrs.size(); i++) {
+    lb_addrs->addresses[i].address =
+        TestAddressToGrpcResolvedAddress(test_addrs[i]);
+  }
+  return lb_addrs;
+}
+
+void VerifyLbAddrOutputs(grpc_lb_addresses* lb_addrs,
+                         std::vector<std::string> expected_addrs) {
+  EXPECT_EQ(lb_addrs->num_addresses, expected_addrs.size());
+  for (size_t i = 0; i < lb_addrs->num_addresses; i++) {
+    char* ip_addr_str;
+    grpc_sockaddr_to_string(&ip_addr_str, &lb_addrs->addresses[i].address,
+                            false /* normalize */);
+    EXPECT_EQ(expected_addrs[i], ip_addr_str);
+    gpr_free(ip_addr_str);
+  }
+  grpc_core::ExecCtx exec_ctx;
+  grpc_lb_addresses_destroy(lb_addrs);
+}
+
+}  // namespace
+
+/* Tests for rule 1 */
+TEST(AddressSortingTest, TestDepriotizesUnreachableAddresses) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = true;
+  OverrideAddressSortingSourceAddrFactory(
+      ipv4_supported, ipv6_supported,
+      {
+          {"1.2.3.4:443", {"4.3.2.1:443", AF_INET}},
+      });
+  auto* lb_addrs = BuildLbAddrInputs({
+      {"1.2.3.4:443", AF_INET},
+      {"5.6.7.8:443", AF_INET},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(lb_addrs, {
+                                    "1.2.3.4:443",
+                                    "5.6.7.8:443",
+                                });
+}
+
+TEST(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv6) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = false;
+  OverrideAddressSortingSourceAddrFactory(
+      ipv4_supported, ipv6_supported,
+      {
+          {"1.2.3.4:443", {"4.3.2.1:0", AF_INET}},
+      });
+  auto lb_addrs = BuildLbAddrInputs({
+      {"[2607:f8b0:400a:801::1002]:443", AF_INET6},
+      {"1.2.3.4:443", AF_INET},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(lb_addrs, {
+                                    "1.2.3.4:443",
+                                    "[2607:f8b0:400a:801::1002]:443",
+                                });
+}
+
+TEST(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv4) {
+  bool ipv4_supported = false;
+  bool ipv6_supported = true;
+  OverrideAddressSortingSourceAddrFactory(
+      ipv4_supported, ipv6_supported,
+      {
+          {"1.2.3.4:443", {"4.3.2.1:0", AF_INET}},
+          {"[2607:f8b0:400a:801::1002]:443", {"[fec0::1234]:0", AF_INET6}},
+      });
+  grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({
+      {"[2607:f8b0:400a:801::1002]:443", AF_INET6},
+      {"1.2.3.4:443", AF_INET},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(lb_addrs, {
+                                    "[2607:f8b0:400a:801::1002]:443",
+                                    "1.2.3.4:443",
+                                });
+}
+
+/* Tests for rule 2 */
+
+TEST(AddressSortingTest, TestDepriotizesNonMatchingScope) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = true;
+  OverrideAddressSortingSourceAddrFactory(
+      ipv4_supported, ipv6_supported,
+      {
+          {"[2000:f8b0:400a:801::1002]:443",
+           {"[fec0::1000]:0", AF_INET6}},  // global and site-local scope
+          {"[fec0::5000]:443",
+           {"[fec0::5001]:0", AF_INET6}},  // site-local and site-local scope
+      });
+  grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({
+      {"[2000:f8b0:400a:801::1002]:443", AF_INET6},
+      {"[fec0::5000]:443", AF_INET6},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(lb_addrs, {
+                                    "[fec0::5000]:443",
+                                    "[2000:f8b0:400a:801::1002]:443",
+                                });
+}
+
+/* Tests for rule 5 */
+
+TEST(AddressSortingTest, TestUsesLabelFromDefaultTable) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = true;
+  OverrideAddressSortingSourceAddrFactory(
+      ipv4_supported, ipv6_supported,
+      {
+          {"[2002::5001]:443", {"[2001::5002]:0", AF_INET6}},
+          {"[2001::5001]:443",
+           {"[2001::5002]:0", AF_INET6}},  // matching labels
+      });
+  grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({
+      {"[2002::5001]:443", AF_INET6},
+      {"[2001::5001]:443", AF_INET6},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(lb_addrs, {
+                                    "[2001::5001]:443",
+                                    "[2002::5001]:443",
+                                });
+}
+
+/* Tests for rule 6 */
+
+TEST(AddressSortingTest,
+     TestUsesDestinationWithHigherPrecedenceWithAnIpv4Address) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = true;
+  OverrideAddressSortingSourceAddrFactory(
+      ipv4_supported, ipv6_supported,
+      {
+          {"[3ffe::5001]:443", {"[3ffe::5002]:0", AF_INET6}},
+          {"1.2.3.4:443", {"5.6.7.8:0", AF_INET}},
+      });
+  grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({
+      {"[3ffe::5001]:443", AF_INET6},
+      {"1.2.3.4:443", AF_INET},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(
+      lb_addrs, {
+                    // The AF_INET address should be IPv4-mapped by the sort,
+                    // and IPv4-mapped
+                    // addresses have higher precedence than 3ffe::/16 by spec.
+                    "1.2.3.4:443",
+                    "[3ffe::5001]:443",
+                });
+}
+
+TEST(AddressSortingTest,
+     TestUsesDestinationWithHigherPrecedenceWithV4CompatAndLocalhostAddress) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = true;
+// Handle unique observed behavior of inet_ntop(v4-compatible-address) on OS X.
+#if GPR_APPLE == 1
+  const char* v4_compat_dest = "[::0.0.0.2]:443";
+  const char* v4_compat_src = "[::0.0.0.2]:0";
+#else
+  const char* v4_compat_dest = "[::2]:443";
+  const char* v4_compat_src = "[::2]:0";
+#endif
+  OverrideAddressSortingSourceAddrFactory(
+      ipv4_supported, ipv6_supported,
+      {
+          {"[::1]:443", {"[::1]:0", AF_INET6}},
+          {v4_compat_dest, {v4_compat_src, AF_INET6}},
+      });
+  grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({
+      {v4_compat_dest, AF_INET6},
+      {"[::1]:443", AF_INET6},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(lb_addrs, {
+                                    "[::1]:443",
+                                    v4_compat_dest,
+                                });
+}
+
+TEST(AddressSortingTest,
+     TestUsesDestinationWithHigherPrecedenceWithCatchAllAndLocalhostAddress) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = true;
+  OverrideAddressSortingSourceAddrFactory(
+      ipv4_supported, ipv6_supported,
+      {
+          // 1234::2 for src and dest to make sure that prefix matching has no
+          // influence on this test.
+          {"[1234::2]:443", {"[1234::2]:0", AF_INET6}},
+          {"[::1]:443", {"[::1]:0", AF_INET6}},
+      });
+  grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({
+      {"[1234::2]:443", AF_INET6},
+      {"[::1]:443", AF_INET6},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(
+      lb_addrs,
+      {
+          // ::1 should match the localhost precedence entry and be prioritized
+          "[::1]:443",
+          "[1234::2]:443",
+      });
+}
+
+TEST(AddressSortingTest,
+     TestUsesDestinationWithHigherPrecedenceWith2000PrefixedAddress) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = true;
+  OverrideAddressSortingSourceAddrFactory(
+      ipv4_supported, ipv6_supported,
+      {
+          {"[2001::1234]:443", {"[2001::5678]:0", AF_INET6}},
+          {"[2000::5001]:443", {"[2000::5002]:0", AF_INET6}},
+      });
+  grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({
+      {"[2001::1234]:443", AF_INET6},
+      {"[2000::5001]:443", AF_INET6},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(
+      lb_addrs, {
+                    // The 2000::/16 address should match the ::/0 prefix rule
+                    "[2000::5001]:443",
+                    "[2001::1234]:443",
+                });
+}
+
+TEST(
+    AddressSortingTest,
+    TestUsesDestinationWithHigherPrecedenceWith2000PrefixedAddressEnsurePrefixMatchHasNoEffect) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = true;
+  OverrideAddressSortingSourceAddrFactory(
+      ipv4_supported, ipv6_supported,
+      {
+          {"[2001::1231]:443", {"[2001::1232]:0", AF_INET6}},
+          {"[2000::5001]:443", {"[2000::5002]:0", AF_INET6}},
+      });
+  grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({
+      {"[2001::1231]:443", AF_INET6},
+      {"[2000::5001]:443", AF_INET6},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(lb_addrs, {
+                                    "[2000::5001]:443",
+                                    "[2001::1231]:443",
+                                });
+}
+
+TEST(AddressSortingTest,
+     TestUsesDestinationWithHigherPrecedenceWithLinkAndSiteLocalAddresses) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = true;
+  OverrideAddressSortingSourceAddrFactory(
+      ipv4_supported, ipv6_supported,
+      {
+          {"[fec0::1234]:443", {"[fec0::5678]:0", AF_INET6}},
+          {"[fc00::5001]:443", {"[fc00::5002]:0", AF_INET6}},
+      });
+  grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({
+      {"[fec0::1234]:443", AF_INET6},
+      {"[fc00::5001]:443", AF_INET6},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(lb_addrs, {
+                                    "[fc00::5001]:443",
+                                    "[fec0::1234]:443",
+                                });
+}
+
+TEST(
+    AddressSortingTest,
+    TestUsesDestinationWithHigherPrecedenceWithCatchAllAndAndV4MappedAddresses) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = true;
+  OverrideAddressSortingSourceAddrFactory(
+      ipv4_supported, ipv6_supported,
+      {
+          {"[::ffff:0.0.0.2]:443", {"[::ffff:0.0.0.3]:0", AF_INET6}},
+          {"[1234::2]:443", {"[1234::3]:0", AF_INET6}},
+      });
+  grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({
+      {"[::ffff:0.0.0.2]:443", AF_INET6},
+      {"[1234::2]:443", AF_INET6},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(lb_addrs, {
+                                    // ::ffff:0:2 should match the v4-mapped
+                                    // precedence entry and be deprioritized.
+                                    "[1234::2]:443",
+                                    "[::ffff:0.0.0.2]:443",
+                                });
+}
+
+/* Tests for rule 8 */
+
+TEST(AddressSortingTest, TestPrefersSmallerScope) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = true;
+  OverrideAddressSortingSourceAddrFactory(
+      ipv4_supported, ipv6_supported,
+      {
+          // Both of these destinations have the same precedence in default
+          // policy
+          // table.
+          {"[fec0::1234]:443", {"[fec0::5678]:0", AF_INET6}},
+          {"[3ffe::5001]:443", {"[3ffe::5002]:0", AF_INET6}},
+      });
+  grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({
+      {"[3ffe::5001]:443", AF_INET6},
+      {"[fec0::1234]:443", AF_INET6},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(lb_addrs, {
+                                    "[fec0::1234]:443",
+                                    "[3ffe::5001]:443",
+                                });
+}
+
+/* Tests for rule 9 */
+
+TEST(AddressSortingTest, TestPrefersLongestMatchingSrcDstPrefix) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = true;
+  OverrideAddressSortingSourceAddrFactory(
+      ipv4_supported, ipv6_supported,
+      {
+          // Both of these destinations have the same precedence in default
+          // policy
+          // table.
+          {"[3ffe:1234::]:443", {"[3ffe:1235::]:0", AF_INET6}},
+          {"[3ffe:5001::]:443", {"[3ffe:4321::]:0", AF_INET6}},
+      });
+  grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({
+      {"[3ffe:5001::]:443", AF_INET6},
+      {"[3ffe:1234::]:443", AF_INET6},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(lb_addrs, {
+                                    "[3ffe:1234::]:443",
+                                    "[3ffe:5001::]:443",
+                                });
+}
+
+TEST(AddressSortingTest,
+     TestPrefersLongestMatchingSrcDstPrefixMatchesWholeAddress) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = true;
+  OverrideAddressSortingSourceAddrFactory(
+      ipv4_supported, ipv6_supported,
+      {
+          {"[3ffe::1234]:443", {"[3ffe::1235]:0", AF_INET6}},
+          {"[3ffe::5001]:443", {"[3ffe::4321]:0", AF_INET6}},
+      });
+  grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({
+      {"[3ffe::5001]:443", AF_INET6},
+      {"[3ffe::1234]:443", AF_INET6},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(lb_addrs, {
+                                    "[3ffe::1234]:443",
+                                    "[3ffe::5001]:443",
+                                });
+}
+
+TEST(AddressSortingTest, TestPrefersLongestPrefixStressInnerBytePrefix) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = true;
+  OverrideAddressSortingSourceAddrFactory(
+      ipv4_supported, ipv6_supported,
+      {
+          {"[3ffe:8000::]:443", {"[3ffe:C000::]:0", AF_INET6}},
+          {"[3ffe:2000::]:443", {"[3ffe:3000::]:0", AF_INET6}},
+      });
+  grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({
+      {"[3ffe:8000::]:443", AF_INET6},
+      {"[3ffe:2000::]:443", AF_INET6},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(lb_addrs, {
+                                    "[3ffe:2000::]:443",
+                                    "[3ffe:8000::]:443",
+                                });
+}
+
+TEST(AddressSortingTest, TestPrefersLongestPrefixDiffersOnHighestBitOfByte) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = true;
+  OverrideAddressSortingSourceAddrFactory(
+      ipv4_supported, ipv6_supported,
+      {
+          {"[3ffe:6::]:443", {"[3ffe:8::]:0", AF_INET6}},
+          {"[3ffe:c::]:443", {"[3ffe:8::]:0", AF_INET6}},
+      });
+  grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({
+      {"[3ffe:6::]:443", AF_INET6},
+      {"[3ffe:c::]:443", AF_INET6},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(lb_addrs, {
+                                    "[3ffe:c::]:443",
+                                    "[3ffe:6::]:443",
+                                });
+}
+
+TEST(AddressSortingTest, TestPrefersLongestPrefixDiffersByLastBit) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = true;
+  OverrideAddressSortingSourceAddrFactory(
+      ipv4_supported, ipv6_supported,
+      {
+          {"[3ffe:1111:1111:1111::]:443",
+           {"[3ffe:1111:1111:1111::]:0", AF_INET6}},
+          {"[3ffe:1111:1111:1110::]:443",
+           {"[3ffe:1111:1111:1111::]:0", AF_INET6}},
+      });
+  grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({
+      {"[3ffe:1111:1111:1110::]:443", AF_INET6},
+      {"[3ffe:1111:1111:1111::]:443", AF_INET6},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(lb_addrs, {
+                                    "[3ffe:1111:1111:1111::]:443",
+                                    "[3ffe:1111:1111:1110::]:443",
+                                });
+}
+
+/* Tests for rule 10 */
+
+TEST(AddressSortingTest, TestStableSort) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = true;
+  OverrideAddressSortingSourceAddrFactory(
+      ipv4_supported, ipv6_supported,
+      {
+          {"[3ffe::1234]:443", {"[3ffe::1236]:0", AF_INET6}},
+          {"[3ffe::1235]:443", {"[3ffe::1237]:0", AF_INET6}},
+      });
+  grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({
+      {"[3ffe::1234]:443", AF_INET6},
+      {"[3ffe::1235]:443", AF_INET6},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(lb_addrs, {
+                                    "[3ffe::1234]:443",
+                                    "[3ffe::1235]:443",
+                                });
+}
+
+TEST(AddressSortingTest, TestStableSortFiveElements) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = true;
+  OverrideAddressSortingSourceAddrFactory(
+      ipv4_supported, ipv6_supported,
+      {
+          {"[3ffe::1231]:443", {"[3ffe::1201]:0", AF_INET6}},
+          {"[3ffe::1232]:443", {"[3ffe::1202]:0", AF_INET6}},
+          {"[3ffe::1233]:443", {"[3ffe::1203]:0", AF_INET6}},
+          {"[3ffe::1234]:443", {"[3ffe::1204]:0", AF_INET6}},
+          {"[3ffe::1235]:443", {"[3ffe::1205]:0", AF_INET6}},
+      });
+  grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({
+      {"[3ffe::1231]:443", AF_INET6},
+      {"[3ffe::1232]:443", AF_INET6},
+      {"[3ffe::1233]:443", AF_INET6},
+      {"[3ffe::1234]:443", AF_INET6},
+      {"[3ffe::1235]:443", AF_INET6},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(lb_addrs, {
+                                    "[3ffe::1231]:443",
+                                    "[3ffe::1232]:443",
+                                    "[3ffe::1233]:443",
+                                    "[3ffe::1234]:443",
+                                    "[3ffe::1235]:443",
+                                });
+}
+
+TEST(AddressSortingTest, TestStableSortNoSrcAddrsExist) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = true;
+  OverrideAddressSortingSourceAddrFactory(ipv4_supported, ipv6_supported, {});
+  grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({
+      {"[3ffe::1231]:443", AF_INET6},
+      {"[3ffe::1232]:443", AF_INET6},
+      {"[3ffe::1233]:443", AF_INET6},
+      {"[3ffe::1234]:443", AF_INET6},
+      {"[3ffe::1235]:443", AF_INET6},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(lb_addrs, {
+                                    "[3ffe::1231]:443",
+                                    "[3ffe::1232]:443",
+                                    "[3ffe::1233]:443",
+                                    "[3ffe::1234]:443",
+                                    "[3ffe::1235]:443",
+                                });
+}
+
+TEST(AddressSortingTest, TestStableSortNoSrcAddrsExistWithIpv4) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = true;
+  OverrideAddressSortingSourceAddrFactory(ipv4_supported, ipv6_supported, {});
+  grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({
+      {"[::ffff:5.6.7.8]:443", AF_INET6},
+      {"1.2.3.4:443", AF_INET},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(lb_addrs, {
+                                    "[::ffff:5.6.7.8]:443",
+                                    "1.2.3.4:443",
+                                });
+}
+
+TEST(AddressSortingTest, TestStableSortV4CompatAndSiteLocalAddresses) {
+  bool ipv4_supported = true;
+  bool ipv6_supported = true;
+// Handle unique observed behavior of inet_ntop(v4-compatible-address) on OS X.
+#if GPR_APPLE == 1
+  const char* v4_compat_dest = "[::0.0.0.2]:443";
+  const char* v4_compat_src = "[::0.0.0.3]:0";
+#else
+  const char* v4_compat_dest = "[::2]:443";
+  const char* v4_compat_src = "[::3]:0";
+#endif
+  OverrideAddressSortingSourceAddrFactory(
+      ipv4_supported, ipv6_supported,
+      {
+          {"[fec0::2000]:443", {"[fec0::2001]:0", AF_INET6}},
+          {v4_compat_dest, {v4_compat_src, AF_INET6}},
+      });
+  grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({
+      {"[fec0::2000]:443", AF_INET6},
+      {v4_compat_dest, AF_INET6},
+  });
+  grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+  VerifyLbAddrOutputs(lb_addrs,
+                      {
+                          // The sort should be stable since
+                          // v4-compatible has same precedence as site-local.
+                          "[fec0::2000]:443",
+                          v4_compat_dest,
+                      });
+}
+
+int main(int argc, char** argv) {
+  const char* resolver = gpr_getenv("GRPC_DNS_RESOLVER");
+  if (resolver == nullptr || strlen(resolver) == 0) {
+    gpr_setenv("GRPC_DNS_RESOLVER", "ares");
+  } else if (strcmp("ares", resolver)) {
+    gpr_log(GPR_INFO, "GRPC_DNS_RESOLVER != ares: %s.", resolver);
+  }
+  grpc_test_init(argc, argv);
+  ::testing::InitGoogleTest(&argc, argv);
+  grpc_init();
+  auto result = RUN_ALL_TESTS();
+  grpc_shutdown();
+  return result;
+}
diff --git a/test/cpp/naming/create_private_dns_zone.sh b/test/cpp/naming/create_private_dns_zone.sh
index 55a4cfe..5c9364c 100755
--- a/test/cpp/naming/create_private_dns_zone.sh
+++ b/test/cpp/naming/create_private_dns_zone.sh
@@ -17,7 +17,7 @@
 
 set -ex
 
-cd $(dirname $0)/../../..
+cd "$(dirname "$0")/../../.."
 
 gcloud alpha dns managed-zones create \
   resolver-tests-version-4-grpctestingexp-zone-id \
diff --git a/test/cpp/naming/gen_build_yaml.py b/test/cpp/naming/gen_build_yaml.py
index 9171815..adebc62 100755
--- a/test/cpp/naming/gen_build_yaml.py
+++ b/test/cpp/naming/gen_build_yaml.py
@@ -182,6 +182,25 @@
                   '--running_under_bazel=false',
               ],
           } for unsecure_build_config_suffix in ['_unsecure', '']
+      ] + [
+          {
+              'name': 'address_sorting_test' + unsecure_build_config_suffix,
+              'build': 'test',
+              'language': 'c++',
+              'gtest': True,
+              'run': True,
+              'src': ['test/cpp/naming/address_sorting_test.cc'],
+              'platforms': ['linux', 'posix', 'mac'],
+              'deps': [
+                  'grpc++_test_util' + unsecure_build_config_suffix,
+                  'grpc_test_util' + unsecure_build_config_suffix,
+                  'gpr_test_util',
+                  'grpc++' + unsecure_build_config_suffix,
+                  'grpc' + unsecure_build_config_suffix,
+                  'gpr',
+                  'grpc++_test_config',
+              ],
+          } for unsecure_build_config_suffix in ['_unsecure', '']
       ]
   }
 
diff --git a/test/cpp/naming/generate_resolver_component_tests.bzl b/test/cpp/naming/generate_resolver_component_tests.bzl
index 118d945..ebc1679 100755
--- a/test/cpp/naming/generate_resolver_component_tests.bzl
+++ b/test/cpp/naming/generate_resolver_component_tests.bzl
@@ -17,6 +17,24 @@
 
 def generate_resolver_component_tests():
   for unsecure_build_config_suffix in ['_unsecure', '']:
+    grpc_cc_test(
+        name = "address_sorting_test%s" % unsecure_build_config_suffix,
+        srcs = [
+            "address_sorting_test.cc",
+        ],
+        external_deps = [
+            "gmock",
+        ],
+        deps = [
+            "//test/cpp/util:test_util%s" % unsecure_build_config_suffix,
+            "//test/core/util:grpc_test_util%s" % unsecure_build_config_suffix,
+            "//test/core/util:gpr_test_util",
+            "//:grpc++%s" % unsecure_build_config_suffix,
+            "//:grpc%s" % unsecure_build_config_suffix,
+            "//:gpr",
+            "//test/cpp/util:test_config",
+        ],
+    )
     # meant to be invoked only through the top-level shell script driver
     grpc_cc_binary(
         name = "resolver_component_test%s" % unsecure_build_config_suffix,
@@ -54,7 +72,9 @@
         data = [
             ":resolver_component_tests_runner",
             ":resolver_component_test%s" % unsecure_build_config_suffix,
-            ":test_dns_server",
+            "//test/cpp/naming/utils:dns_server",
+            "//test/cpp/naming/utils:dns_resolver",
+            "//test/cpp/naming/utils:tcp_connect",
             "resolver_test_record_groups.yaml", # include the transitive dependency so that the dns sever py binary can locate this
         ],
         args = [
diff --git a/test/cpp/naming/private_dns_zone_init.sh b/test/cpp/naming/private_dns_zone_init.sh
index 8fa5a8a..fba8a00 100755
--- a/test/cpp/naming/private_dns_zone_init.sh
+++ b/test/cpp/naming/private_dns_zone_init.sh
@@ -17,7 +17,7 @@
 
 set -ex
 
-cd $(dirname $0)/../../..
+cd "$(dirname "$0")/../../.."
 
 gcloud dns record-sets transaction start -z=resolver-tests-version-4-grpctestingexp-zone-id
 
diff --git a/test/cpp/naming/resolver_component_test.cc b/test/cpp/naming/resolver_component_test.cc
index 8b5523f..bfdcd96 100644
--- a/test/cpp/naming/resolver_component_test.cc
+++ b/test/cpp/naming/resolver_component_test.cc
@@ -18,7 +18,6 @@
 
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
@@ -38,7 +37,9 @@
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/orphanable.h"
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/iomgr.h"
@@ -61,11 +62,14 @@
 
 DEFINE_string(target_name, "", "Target name to resolve.");
 DEFINE_string(expected_addrs, "",
-              "Comma-separated list of expected "
-              "'<ip0:port0>,<is_balancer0>;<ip1:port1>,<is_balancer1>;...' "
-              "addresses of "
-              "backend and/or balancers. 'is_balancer' should be bool, i.e. "
-              "true or false.");
+              "List of expected backend or balancer addresses in the form "
+              "'<ip0:port0>,<is_balancer0>;<ip1:port1>,<is_balancer1>;...'. "
+              "'is_balancer' should be bool, i.e. true or false.");
+DEFINE_bool(allow_extra_addrs, false,
+            "Permit extra resolved addresses in the final list of "
+            "resolved addresses. This is useful in certain integration "
+            "test environments in which DNS responses are not fully "
+            "deterministic.");
 DEFINE_string(expected_chosen_service_config, "",
               "Expected service config json string that gets chosen (no "
               "whitespace). Empty for none.");
@@ -102,12 +106,10 @@
     // get the next <ip>,<port> (v4 or v6)
     size_t next_comma = expected_addrs.find(",");
     if (next_comma == std::string::npos) {
-      gpr_log(
-          GPR_ERROR,
-          "Missing ','. Expected_addrs arg should be a semi-colon-separated "
-          "list of "
-          "<ip-port>,<bool> pairs. Left-to-be-parsed arg is |%s|",
-          expected_addrs.c_str());
+      gpr_log(GPR_ERROR,
+              "Missing ','. Expected_addrs arg should be a semicolon-separated "
+              "list of <ip-port>,<bool> pairs. Left-to-be-parsed arg is |%s|",
+              expected_addrs.c_str());
       abort();
     }
     std::string next_addr = expected_addrs.substr(0, next_comma);
@@ -125,7 +127,7 @@
   }
   if (out.size() == 0) {
     gpr_log(GPR_ERROR,
-            "expected_addrs arg should be a comma-separated list of "
+            "expected_addrs arg should be a semicolon-separated list of "
             "<ip-port>,<bool> pairs");
     abort();
   }
@@ -243,9 +245,11 @@
   GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER);
   grpc_lb_addresses* addresses =
       (grpc_lb_addresses*)channel_arg->value.pointer.p;
-  gpr_log(GPR_INFO, "num addrs found: %" PRIdPTR ". expected %" PRIdPTR,
-          addresses->num_addresses, args->expected_addrs.size());
-  GPR_ASSERT(addresses->num_addresses == args->expected_addrs.size());
+  gpr_log(GPR_INFO,
+          "num addrs found: %" PRIdPTR ". expected %" PRIdPTR
+          ". Allow extra addresses:%d.",
+          addresses->num_addresses, args->expected_addrs.size(),
+          FLAGS_allow_extra_addrs);
   std::vector<GrpcLBAddress> found_lb_addrs;
   for (size_t i = 0; i < addresses->num_addresses; i++) {
     grpc_lb_address addr = addresses->addresses[i];
@@ -257,13 +261,20 @@
     gpr_free(str);
   }
   if (args->expected_addrs.size() != found_lb_addrs.size()) {
-    gpr_log(GPR_DEBUG,
-            "found lb addrs size is: %" PRIdPTR
-            ". expected addrs size is %" PRIdPTR,
-            found_lb_addrs.size(), args->expected_addrs.size());
-    abort();
+    // Permit extra resolved addresses if "--allow_extra_addrs" was set.
+    if (!(FLAGS_allow_extra_addrs &&
+          found_lb_addrs.size() > args->expected_addrs.size())) {
+      gpr_log(GPR_DEBUG,
+              "found lb addrs size is: %" PRIdPTR
+              ". expected addrs size is %" PRIdPTR ". --allow_extra_addrs=%d.",
+              found_lb_addrs.size(), args->expected_addrs.size(),
+              FLAGS_allow_extra_addrs);
+      abort();
+    }
   }
-  EXPECT_THAT(args->expected_addrs, UnorderedElementsAreArray(found_lb_addrs));
+  for (size_t i = 0; i < args->expected_addrs.size(); i++) {
+    EXPECT_THAT(found_lb_addrs, ::testing::Contains(args->expected_addrs[i]));
+  }
   CheckServiceConfigResultLocked(channel_args, args);
   if (args->expected_service_config_string == "") {
     CheckLBPolicyResultLocked(channel_args, args);
@@ -287,17 +298,16 @@
                       FLAGS_local_dns_server_address.c_str(),
                       FLAGS_target_name.c_str()));
   // create resolver and resolve
-  grpc_resolver* resolver =
-      grpc_resolver_create(whole_uri, nullptr, args.pollset_set, args.lock);
+  grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
+      grpc_core::ResolverRegistry::CreateResolver(whole_uri, nullptr,
+                                                  args.pollset_set, args.lock);
   gpr_free(whole_uri);
   grpc_closure on_resolver_result_changed;
   GRPC_CLOSURE_INIT(&on_resolver_result_changed, CheckResolverResultLocked,
                     (void*)&args, grpc_combiner_scheduler(args.lock));
-  grpc_resolver_next_locked(resolver, &args.channel_args,
-                            &on_resolver_result_changed);
+  resolver->NextLocked(&args.channel_args, &on_resolver_result_changed);
   grpc_core::ExecCtx::Get()->Flush();
   PollPollsetUntilRequestDone(&args);
-  GRPC_RESOLVER_UNREF(resolver, nullptr);
   ArgsFinish(&args);
 }
 
diff --git a/test/cpp/naming/resolver_component_tests_runner.sh b/test/cpp/naming/resolver_component_tests_runner.sh
index 11a45d7..18b56ab 100755
--- a/test/cpp/naming/resolver_component_tests_runner.sh
+++ b/test/cpp/naming/resolver_component_tests_runner.sh
@@ -18,12 +18,14 @@
 set -ex
 
 # all command args required in this set order
-FLAGS_test_bin_path=`echo "$1" | grep '\--test_bin_path=' | cut -d "=" -f 2`
-FLAGS_dns_server_bin_path=`echo "$2" | grep '\--dns_server_bin_path=' | cut -d "=" -f 2`
-FLAGS_records_config_path=`echo "$3" | grep '\--records_config_path=' | cut -d "=" -f 2`
-FLAGS_test_dns_server_port=`echo "$4" | grep '\--test_dns_server_port=' | cut -d "=" -f 2`
+FLAGS_test_bin_path=$(echo "$1" | grep '\--test_bin_path=' | sed 's/^--test_bin_path=//')
+FLAGS_dns_server_bin_path=$(echo "$2" | grep '\--dns_server_bin_path=' | sed 's/^--dns_server_bin_path=//')
+FLAGS_records_config_path=$(echo "$3" | grep '\--records_config_path=' | sed 's/^--records_config_path=//')
+FLAGS_dns_server_port=$(echo "$4" | grep '\--dns_server_port=' | sed 's/^--dns_server_port=//')
+FLAGS_dns_resolver_bin_path=$(echo "$5" | grep '\--dns_resolver_bin_path=' | sed 's/^--dns_resolver_bin_path=//')
+FLAGS_tcp_connect_bin_path=$(echo "$6" | grep '\--tcp_connect_bin_path=' | sed 's/^--tcp_connect_bin_path=//')
 
-for cmd_arg in "$FLAGS_test_bin_path" "$FLAGS_dns_server_bin_path" "$FLAGS_records_config_path" "$FLAGS_test_dns_server_port"; do
+for cmd_arg in "$FLAGS_test_bin_path" "$FLAGS_dns_server_bin_path" "$FLAGS_records_config_path" "$FLAGS_dns_server_port" "$FLAGS_dns_resolver_bin_path" "$FLAGS_tcp_connect_bin_path"; do
   if [[ "$cmd_arg" == "" ]]; then
     echo "Missing a CMD arg" && exit 1
   fi
@@ -34,17 +36,17 @@
 fi
 export GRPC_DNS_RESOLVER=ares
 
-"$FLAGS_dns_server_bin_path" --records_config_path="$FLAGS_records_config_path" --port="$FLAGS_test_dns_server_port" 2>&1 > /dev/null &
+"$FLAGS_dns_server_bin_path" --records_config_path="$FLAGS_records_config_path" --port="$FLAGS_dns_server_port" > /dev/null 2>&1 &
 DNS_SERVER_PID=$!
 echo "Local DNS server started. PID: $DNS_SERVER_PID"
 
 # Health check local DNS server TCP and UDP ports
 for ((i=0;i<30;i++));
 do
-  echo "Retry health-check DNS query to local DNS server over tcp and udp"
+  echo "Retry health-check local DNS server by attempting a DNS query and TCP handshake"
   RETRY=0
-  dig A health-check-local-dns-server-is-alive.resolver-tests.grpctestingexp. @localhost -p "$FLAGS_test_dns_server_port" +tries=1 +timeout=1 | grep '123.123.123.123' || RETRY=1
-  dig A health-check-local-dns-server-is-alive.resolver-tests.grpctestingexp. @localhost -p "$FLAGS_test_dns_server_port" +tries=1 +timeout=1 +tcp | grep '123.123.123.123' || RETRY=1
+  $FLAGS_dns_resolver_bin_path -s 127.0.0.1 -p "$FLAGS_dns_server_port" -n health-check-local-dns-server-is-alive.resolver-tests.grpctestingexp. -t 1 | grep '123.123.123.123' || RETRY=1
+  $FLAGS_tcp_connect_bin_path -s 127.0.0.1 -p "$FLAGS_dns_server_port" -t 1 || RETRY=1
   if [[ "$RETRY" == 0 ]]; then
     break
   fi;
@@ -53,15 +55,15 @@
 
 if [[ $RETRY == 1 ]]; then
   echo "FAILED TO START LOCAL DNS SERVER"
-  kill -SIGTERM $DNS_SERVER_PID
+  kill -SIGTERM "$DNS_SERVER_PID"
   wait
   exit 1
 fi
 
 function terminate_all {
   echo "Received signal. Terminating $! and $DNS_SERVER_PID"
-  kill -SIGTERM $! || true
-  kill -SIGTERM $DNS_SERVER_PID || true
+  kill -SIGTERM "$!" || true
+  kill -SIGTERM "$DNS_SERVER_PID" || true
   wait
   exit 1
 }
@@ -77,105 +79,105 @@
   --expected_addrs='1.2.3.4:1234,True' \
   --expected_chosen_service_config='' \
   --expected_lb_policy='' \
-  --local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port &
-wait $! || EXIT_CODE=1
+  --local_dns_server_address="127.0.0.1:$FLAGS_dns_server_port" &
+wait "$!" || EXIT_CODE=1
 
 $FLAGS_test_bin_path \
   --target_name='srv-ipv4-multi-target.resolver-tests-version-4.grpctestingexp.' \
   --expected_addrs='1.2.3.5:1234,True;1.2.3.6:1234,True;1.2.3.7:1234,True' \
   --expected_chosen_service_config='' \
   --expected_lb_policy='' \
-  --local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port &
-wait $! || EXIT_CODE=1
+  --local_dns_server_address="127.0.0.1:$FLAGS_dns_server_port" &
+wait "$!" || EXIT_CODE=1
 
 $FLAGS_test_bin_path \
   --target_name='srv-ipv6-single-target.resolver-tests-version-4.grpctestingexp.' \
   --expected_addrs='[2607:f8b0:400a:801::1001]:1234,True' \
   --expected_chosen_service_config='' \
   --expected_lb_policy='' \
-  --local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port &
-wait $! || EXIT_CODE=1
+  --local_dns_server_address="127.0.0.1:$FLAGS_dns_server_port" &
+wait "$!" || EXIT_CODE=1
 
 $FLAGS_test_bin_path \
   --target_name='srv-ipv6-multi-target.resolver-tests-version-4.grpctestingexp.' \
   --expected_addrs='[2607:f8b0:400a:801::1002]:1234,True;[2607:f8b0:400a:801::1003]:1234,True;[2607:f8b0:400a:801::1004]:1234,True' \
   --expected_chosen_service_config='' \
   --expected_lb_policy='' \
-  --local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port &
-wait $! || EXIT_CODE=1
+  --local_dns_server_address="127.0.0.1:$FLAGS_dns_server_port" &
+wait "$!" || EXIT_CODE=1
 
 $FLAGS_test_bin_path \
   --target_name='srv-ipv4-simple-service-config.resolver-tests-version-4.grpctestingexp.' \
   --expected_addrs='1.2.3.4:1234,True' \
   --expected_chosen_service_config='{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]}]}' \
   --expected_lb_policy='round_robin' \
-  --local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port &
-wait $! || EXIT_CODE=1
+  --local_dns_server_address="127.0.0.1:$FLAGS_dns_server_port" &
+wait "$!" || EXIT_CODE=1
 
 $FLAGS_test_bin_path \
   --target_name='ipv4-no-srv-simple-service-config.resolver-tests-version-4.grpctestingexp.' \
   --expected_addrs='1.2.3.4:443,False' \
   --expected_chosen_service_config='{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NoSrvSimpleService","waitForReady":true}]}]}' \
   --expected_lb_policy='round_robin' \
-  --local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port &
-wait $! || EXIT_CODE=1
+  --local_dns_server_address="127.0.0.1:$FLAGS_dns_server_port" &
+wait "$!" || EXIT_CODE=1
 
 $FLAGS_test_bin_path \
   --target_name='ipv4-no-config-for-cpp.resolver-tests-version-4.grpctestingexp.' \
   --expected_addrs='1.2.3.4:443,False' \
   --expected_chosen_service_config='' \
   --expected_lb_policy='' \
-  --local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port &
-wait $! || EXIT_CODE=1
+  --local_dns_server_address="127.0.0.1:$FLAGS_dns_server_port" &
+wait "$!" || EXIT_CODE=1
 
 $FLAGS_test_bin_path \
   --target_name='ipv4-cpp-config-has-zero-percentage.resolver-tests-version-4.grpctestingexp.' \
   --expected_addrs='1.2.3.4:443,False' \
   --expected_chosen_service_config='' \
   --expected_lb_policy='' \
-  --local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port &
-wait $! || EXIT_CODE=1
+  --local_dns_server_address="127.0.0.1:$FLAGS_dns_server_port" &
+wait "$!" || EXIT_CODE=1
 
 $FLAGS_test_bin_path \
   --target_name='ipv4-second-language-is-cpp.resolver-tests-version-4.grpctestingexp.' \
   --expected_addrs='1.2.3.4:443,False' \
   --expected_chosen_service_config='{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService","waitForReady":true}]}]}' \
   --expected_lb_policy='round_robin' \
-  --local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port &
-wait $! || EXIT_CODE=1
+  --local_dns_server_address="127.0.0.1:$FLAGS_dns_server_port" &
+wait "$!" || EXIT_CODE=1
 
 $FLAGS_test_bin_path \
   --target_name='ipv4-config-with-percentages.resolver-tests-version-4.grpctestingexp.' \
   --expected_addrs='1.2.3.4:443,False' \
   --expected_chosen_service_config='{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"AlwaysPickedService","waitForReady":true}]}]}' \
   --expected_lb_policy='round_robin' \
-  --local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port &
-wait $! || EXIT_CODE=1
+  --local_dns_server_address="127.0.0.1:$FLAGS_dns_server_port" &
+wait "$!" || EXIT_CODE=1
 
 $FLAGS_test_bin_path \
   --target_name='srv-ipv4-target-has-backend-and-balancer.resolver-tests-version-4.grpctestingexp.' \
   --expected_addrs='1.2.3.4:1234,True;1.2.3.4:443,False' \
   --expected_chosen_service_config='' \
   --expected_lb_policy='' \
-  --local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port &
-wait $! || EXIT_CODE=1
+  --local_dns_server_address="127.0.0.1:$FLAGS_dns_server_port" &
+wait "$!" || EXIT_CODE=1
 
 $FLAGS_test_bin_path \
   --target_name='srv-ipv6-target-has-backend-and-balancer.resolver-tests-version-4.grpctestingexp.' \
   --expected_addrs='[2607:f8b0:400a:801::1002]:1234,True;[2607:f8b0:400a:801::1002]:443,False' \
   --expected_chosen_service_config='' \
   --expected_lb_policy='' \
-  --local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port &
-wait $! || EXIT_CODE=1
+  --local_dns_server_address="127.0.0.1:$FLAGS_dns_server_port" &
+wait "$!" || EXIT_CODE=1
 
 $FLAGS_test_bin_path \
   --target_name='ipv4-config-causing-fallback-to-tcp.resolver-tests-version-4.grpctestingexp.' \
   --expected_addrs='1.2.3.4:443,False' \
   --expected_chosen_service_config='{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooThree","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFour","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFive","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSix","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSeven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEight","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooNine","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTen","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEleven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]}]}' \
   --expected_lb_policy='' \
-  --local_dns_server_address=127.0.0.1:$FLAGS_test_dns_server_port &
-wait $! || EXIT_CODE=1
+  --local_dns_server_address="127.0.0.1:$FLAGS_dns_server_port" &
+wait "$!" || EXIT_CODE=1
 
-kill -SIGTERM $DNS_SERVER_PID || true
+kill -SIGTERM "$DNS_SERVER_PID" || true
 wait
 exit $EXIT_CODE
diff --git a/test/cpp/naming/resolver_component_tests_runner_invoker.cc b/test/cpp/naming/resolver_component_tests_runner_invoker.cc
index 306c322..b2a7890 100644
--- a/test/cpp/naming/resolver_component_tests_runner_invoker.cc
+++ b/test/cpp/naming/resolver_component_tests_runner_invoker.cc
@@ -102,14 +102,18 @@
 void InvokeResolverComponentTestsRunner(std::string test_runner_bin_path,
                                         std::string test_bin_path,
                                         std::string dns_server_bin_path,
-                                        std::string records_config_path) {
-  int test_dns_server_port = grpc_pick_unused_port_or_die();
+                                        std::string records_config_path,
+                                        std::string dns_resolver_bin_path,
+                                        std::string tcp_connect_bin_path) {
+  int dns_server_port = grpc_pick_unused_port_or_die();
 
-  SubProcess* test_driver = new SubProcess(
-      {test_runner_bin_path, "--test_bin_path=" + test_bin_path,
-       "--dns_server_bin_path=" + dns_server_bin_path,
-       "--records_config_path=" + records_config_path,
-       "--test_dns_server_port=" + std::to_string(test_dns_server_port)});
+  SubProcess* test_driver =
+      new SubProcess({test_runner_bin_path, "--test_bin_path=" + test_bin_path,
+                      "--dns_server_bin_path=" + dns_server_bin_path,
+                      "--records_config_path=" + records_config_path,
+                      "--dns_server_port=" + std::to_string(dns_server_port),
+                      "--dns_resolver_bin_path=" + dns_resolver_bin_path,
+                      "--tcp_connect_bin_path=" + tcp_connect_bin_path});
   gpr_mu test_driver_mu;
   gpr_mu_init(&test_driver_mu);
   gpr_cv test_driver_cv;
@@ -170,8 +174,9 @@
     // sure that we're using bazel's test environment.
     grpc::testing::InvokeResolverComponentTestsRunner(
         bin_dir + "/resolver_component_tests_runner",
-        bin_dir + "/" + FLAGS_test_bin_name, bin_dir + "/test_dns_server",
-        bin_dir + "/resolver_test_record_groups.yaml");
+        bin_dir + "/" + FLAGS_test_bin_name, bin_dir + "/utils/dns_server",
+        bin_dir + "/resolver_test_record_groups.yaml",
+        bin_dir + "/utils/dns_resolver", bin_dir + "/utils/tcp_connect");
   } else {
     // Get the current binary's directory relative to repo root to invoke the
     // correct build config (asan/tsan/dbg, etc.).
@@ -180,8 +185,10 @@
     grpc::testing::InvokeResolverComponentTestsRunner(
         "test/cpp/naming/resolver_component_tests_runner.sh",
         bin_dir + "/" + FLAGS_test_bin_name,
-        "test/cpp/naming/test_dns_server.py",
-        "test/cpp/naming/resolver_test_record_groups.yaml");
+        "test/cpp/naming/utils/dns_server.py",
+        "test/cpp/naming/resolver_test_record_groups.yaml",
+        "test/cpp/naming/utils/dns_resolver.py",
+        "test/cpp/naming/utils/tcp_connect.py");
   }
   grpc_shutdown();
   return 0;
diff --git a/test/cpp/naming/resolver_gce_integration_tests_runner.sh b/test/cpp/naming/resolver_gce_integration_tests_runner.sh
index 091f9ef..2f673a5 100755
--- a/test/cpp/naming/resolver_gce_integration_tests_runner.sh
+++ b/test/cpp/naming/resolver_gce_integration_tests_runner.sh
@@ -24,7 +24,7 @@
   exit 1
 fi
 
-cd $(dirname $0)/../../..
+cd "$(dirname "$0")/../../.."
 
 if [[ "$CONFIG" == "" ]]; then
   export CONFIG=opt
diff --git a/test/cpp/naming/utils/BUILD b/test/cpp/naming/utils/BUILD
new file mode 100644
index 0000000..e7b6bc5
--- /dev/null
+++ b/test/cpp/naming/utils/BUILD
@@ -0,0 +1,50 @@
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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"],
+    features = [
+        "-layering_check",
+        "-parse_headers",
+    ],
+)
+
+licenses(["notice"])  # Apache v2
+
+load("//bazel:grpc_build_system.bzl", "grpc_py_binary")
+
+grpc_py_binary(
+  name = "dns_server",
+  srcs = ["dns_server.py"],
+  testonly = True,
+  external_deps = [
+      "twisted",
+      "yaml",
+  ]
+)
+
+grpc_py_binary(
+  name = "dns_resolver",
+  srcs = ["dns_resolver.py"],
+  testonly = True,
+  external_deps = [
+      "twisted",
+  ]
+)
+
+grpc_py_binary(
+  name = "tcp_connect",
+  srcs = ["tcp_connect.py"],
+  testonly = True,
+)
diff --git a/test/cpp/naming/utils/dns_resolver.py b/test/cpp/naming/utils/dns_resolver.py
new file mode 100755
index 0000000..6b27244
--- /dev/null
+++ b/test/cpp/naming/utils/dns_resolver.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python2.7
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Makes DNS queries for A records to specified servers"""
+
+import argparse
+import signal
+import twisted.internet.task as task
+import twisted.names.client as client
+
+def main():
+  argp = argparse.ArgumentParser(description='Make DNS queries for A records')
+  argp.add_argument('-s', '--server_host', default='127.0.0.1', type=str,
+                    help='Host for DNS server to listen on for TCP and UDP.')
+  argp.add_argument('-p', '--server_port', default=53, type=int,
+                    help='Port that the DNS server is listening on.')
+  argp.add_argument('-n', '--qname', default=None, type=str,
+                    help=('Name of the record to query for. '))
+  argp.add_argument('-t', '--timeout', default=1, type=int,
+                    help=('Force process exit after this number of seconds.'))
+  args = argp.parse_args()
+  signal.alarm(args.timeout)
+  def OnResolverResultAvailable(result):
+    answers, authority, additional = result
+    for a in answers:
+      print(a.payload)
+  def BeginQuery(reactor, qname):
+    servers = [(args.server_host, args.server_port)]
+    resolver = client.Resolver(servers=servers)
+    deferred_result = resolver.lookupAddress(args.qname)
+    deferred_result.addCallback(OnResolverResultAvailable)
+    return deferred_result
+  task.react(BeginQuery, [args.qname])
+
+if __name__ == '__main__':
+  main()
diff --git a/test/cpp/naming/test_dns_server.py b/test/cpp/naming/utils/dns_server.py
similarity index 100%
rename from test/cpp/naming/test_dns_server.py
rename to test/cpp/naming/utils/dns_server.py
diff --git a/test/cpp/naming/utils/tcp_connect.py b/test/cpp/naming/utils/tcp_connect.py
new file mode 100755
index 0000000..bf7455e
--- /dev/null
+++ b/test/cpp/naming/utils/tcp_connect.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python2.7
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Opens a TCP connection to a specified server and then exits."""
+
+import argparse
+import signal
+import socket
+
+def main():
+  argp = argparse.ArgumentParser(description='Open a TCP handshake to a server')
+  argp.add_argument('-s', '--server_host', default=None, type=str,
+                    help='Server host name or IP.')
+  argp.add_argument('-p', '--server_port', default=0, type=int,
+                    help='Port that the server is listening on.')
+  argp.add_argument('-t', '--timeout', default=1, type=int,
+                    help='Force process exit after this number of seconds.')
+  args = argp.parse_args()
+  signal.alarm(args.timeout)
+  socket.create_connection([args.server_host, args.server_port])
+
+if __name__ == '__main__':
+  main()
diff --git a/test/cpp/performance/BUILD b/test/cpp/performance/BUILD
new file mode 100644
index 0000000..4fe95d5
--- /dev/null
+++ b/test/cpp/performance/BUILD
@@ -0,0 +1,34 @@
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 v2
+
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_package")
+
+grpc_package(name = "test/cpp/performance")
+
+grpc_cc_test(
+    name = "writes_per_rpc_test",
+    srcs = ["writes_per_rpc_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//:grpc++",
+        "//src/proto/grpc/testing:echo_proto",
+        "//test/core/util:grpc_test_util_base",
+    ],
+)
diff --git a/test/cpp/performance/writes_per_rpc_test.cc b/test/cpp/performance/writes_per_rpc_test.cc
index b7d951a..0ea3181 100644
--- a/test/cpp/performance/writes_per_rpc_test.cc
+++ b/test/cpp/performance/writes_per_rpc_test.cc
@@ -16,14 +16,14 @@
  *
  */
 
-#include <grpc++/channel.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/impl/grpc_library.h>
-#include <grpc++/security/credentials.h>
-#include <grpc++/security/server_credentials.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
 #include <grpc/support/log.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/impl/grpc_library.h>
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
 #include <gtest/gtest.h>
 
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
@@ -207,17 +207,17 @@
         stub->AsyncEcho(&cli_ctx, send_request, fixture->cq()));
     void* t;
     bool ok;
+    response_reader->Finish(&recv_response, &recv_status, tag(4));
     GPR_ASSERT(fixture->cq()->Next(&t, &ok));
     GPR_ASSERT(ok);
     GPR_ASSERT(t == tag(0) || t == tag(1));
     intptr_t slot = reinterpret_cast<intptr_t>(t);
     ServerEnv* senv = server_env[slot];
     senv->response_writer.Finish(send_response, Status::OK, tag(3));
-    response_reader->Finish(&recv_response, &recv_status, tag(4));
     for (int i = (1 << 3) | (1 << 4); i != 0;) {
       GPR_ASSERT(fixture->cq()->Next(&t, &ok));
       GPR_ASSERT(ok);
-      int tagnum = (int)reinterpret_cast<intptr_t>(t);
+      int tagnum = static_cast<int>(reinterpret_cast<intptr_t>(t));
       GPR_ASSERT(i & (1 << tagnum));
       i -= 1 << tagnum;
     }
@@ -230,7 +230,8 @@
   }
 
   double writes_per_iteration =
-      (double)fixture->writes_performed() / (double)kIterations;
+      static_cast<double>(fixture->writes_performed()) /
+      static_cast<double>(kIterations);
 
   fixture.reset();
   server_env[0]->~ServerEnv();
diff --git a/test/cpp/qps/benchmark_config.cc b/test/cpp/qps/benchmark_config.cc
index fb1e060..a4fd9de 100644
--- a/test/cpp/qps/benchmark_config.cc
+++ b/test/cpp/qps/benchmark_config.cc
@@ -18,9 +18,9 @@
 
 #include "test/cpp/qps/benchmark_config.h"
 #include <gflags/gflags.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/security/credentials.h>
 #include <grpc/support/log.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/security/credentials.h>
 
 DEFINE_bool(enable_log_reporter, true,
             "Enable reporting of benchmark results through GprLog");
diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h
index 82c6361..77743a1 100644
--- a/test/cpp/qps/client.h
+++ b/test/cpp/qps/client.h
@@ -24,12 +24,12 @@
 #include <unordered_map>
 #include <vector>
 
-#include <grpc++/channel.h>
-#include <grpc++/support/byte_buffer.h>
-#include <grpc++/support/channel_arguments.h>
-#include <grpc++/support/slice.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/support/byte_buffer.h>
+#include <grpcpp/support/channel_arguments.h>
+#include <grpcpp/support/slice.h>
 
 #include "src/proto/grpc/testing/payloads.pb.h"
 #include "src/proto/grpc/testing/services.grpc.pb.h"
diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc
index e3fba36..f9bef91 100644
--- a/test/cpp/qps/client_async.cc
+++ b/test/cpp/qps/client_async.cc
@@ -26,13 +26,13 @@
 #include <thread>
 #include <vector>
 
-#include <grpc++/alarm.h>
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/generic/generic_stub.h>
 #include <grpc/grpc.h>
 #include <grpc/support/cpu.h>
 #include <grpc/support/log.h>
+#include <grpcpp/alarm.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/generic/generic_stub.h>
 
 #include "src/core/lib/surface/completion_queue.h"
 #include "src/proto/grpc/testing/services.grpc.pb.h"
@@ -50,9 +50,9 @@
   // next state, return false if done. Collect stats when appropriate
   virtual bool RunNextState(bool, HistogramEntry* entry) = 0;
   virtual void StartNewClone(CompletionQueue* cq) = 0;
-  static void* tag(ClientRpcContext* c) { return reinterpret_cast<void*>(c); }
+  static void* tag(ClientRpcContext* c) { return static_cast<void*>(c); }
   static ClientRpcContext* detag(void* t) {
-    return reinterpret_cast<ClientRpcContext*>(t);
+    return static_cast<ClientRpcContext*>(t);
   }
 
   virtual void Start(CompletionQueue* cq, const ClientConfig& config) = 0;
diff --git a/test/cpp/qps/client_sync.cc b/test/cpp/qps/client_sync.cc
index a2ddbeb..5185eef 100644
--- a/test/cpp/qps/client_sync.cc
+++ b/test/cpp/qps/client_sync.cc
@@ -24,16 +24,16 @@
 #include <thread>
 #include <vector>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
 
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/profiling/timers.h"
 #include "src/proto/grpc/testing/services.grpc.pb.h"
 #include "test/cpp/qps/client.h"
diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc
index a809a27..361ee43 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -23,15 +23,15 @@
 #include <unordered_map>
 #include <vector>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
 
 #include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/profiling/timers.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
diff --git a/test/cpp/qps/gen_build_yaml.py b/test/cpp/qps/gen_build_yaml.py
index bd40d0a..1ef8f65 100755
--- a/test/cpp/qps/gen_build_yaml.py
+++ b/test/cpp/qps/gen_build_yaml.py
@@ -101,26 +101,24 @@
     }
     for scenario_json in scenario_config.CXXLanguage().scenarios()
     if 'inproc' in scenario_json.get('CATEGORIES', [])
+  ] + [
+    {
+      'name': 'json_run_localhost',
+      'shortname': 'json_run_localhost:%s_low_thread_count' % scenario_json['name'],
+      'args': ['--scenarios_json', _scenario_json_string(scenario_json, True)],
+      'ci_platforms': ['linux'],
+      'platforms': ['linux'],
+      'flaky': False,
+      'language': 'c++',
+      'boringssl': True,
+      'defaults': 'boringssl',
+      'cpu_cost': guess_cpu(scenario_json, True),
+      'exclude_configs': sorted(c for c in configs_from_yaml if c not in ('tsan', 'asan')),
+      'timeout_seconds': 10*60,
+      'excluded_poll_engines': scenario_json.get('EXCLUDED_POLL_ENGINES', []),
+      'auto_timeout_scaling': False
+   }
+    for scenario_json in scenario_config.CXXLanguage().scenarios()
+    if 'scalable' in scenario_json.get('CATEGORIES', [])
   ]
-  # Disabled until https://github.com/grpc/grpc/issues/13122 is resolved.
-  # + [
-  #   {
-  #     'name': 'json_run_localhost',
-  #     'shortname': 'json_run_localhost:%s_low_thread_count' % scenario_json['name'],
-  #     'args': ['--scenarios_json', _scenario_json_string(scenario_json, True)],
-  #     'ci_platforms': ['linux'],
-  #     'platforms': ['linux'],
-  #     'flaky': False,
-  #     'language': 'c++',
-  #     'boringssl': True,
-  #     'defaults': 'boringssl',
-  #     'cpu_cost': guess_cpu(scenario_json, True),
-  #     'exclude_configs': sorted(c for c in configs_from_yaml if c not in ('tsan', 'asan')),
-  #     'timeout_seconds': 10*60,
-  #     'excluded_poll_engines': scenario_json.get('EXCLUDED_POLL_ENGINES', []),
-  #     'auto_timeout_scaling': False
-  #  }
-  #   for scenario_json in scenario_config.CXXLanguage().scenarios()
-  #   if 'scalable' in scenario_json.get('CATEGORIES', [])
-  # ]
 })
diff --git a/test/cpp/qps/interarrival.h b/test/cpp/qps/interarrival.h
index 9c48066..ce4bf3d 100644
--- a/test/cpp/qps/interarrival.h
+++ b/test/cpp/qps/interarrival.h
@@ -24,7 +24,7 @@
 #include <random>
 #include <vector>
 
-#include <grpc++/support/config.h>
+#include <grpcpp/support/config.h>
 
 namespace grpc {
 namespace testing {
diff --git a/test/cpp/qps/parse_json.h b/test/cpp/qps/parse_json.h
index f2fffb5..089d998 100644
--- a/test/cpp/qps/parse_json.h
+++ b/test/cpp/qps/parse_json.h
@@ -19,8 +19,8 @@
 #ifndef TEST_QPS_PARSE_JSON_H
 #define TEST_QPS_PARSE_JSON_H
 
-#include <grpc++/impl/codegen/config_protobuf.h>
-#include <grpc++/support/config.h>
+#include <grpcpp/impl/codegen/config_protobuf.h>
+#include <grpcpp/support/config.h>
 
 namespace grpc {
 namespace testing {
diff --git a/test/cpp/qps/qps_json_driver.cc b/test/cpp/qps/qps_json_driver.cc
index b2449da..0ff6922 100644
--- a/test/cpp/qps/qps_json_driver.cc
+++ b/test/cpp/qps/qps_json_driver.cc
@@ -21,7 +21,7 @@
 #include <memory>
 #include <set>
 
-#include <grpc++/impl/codegen/config_protobuf.h>
+#include <grpcpp/impl/codegen/config_protobuf.h>
 
 #include <gflags/gflags.h>
 #include <grpc/support/log.h>
diff --git a/test/cpp/qps/qps_worker.cc b/test/cpp/qps/qps_worker.cc
index 4c9ab0e..aaffb1d 100644
--- a/test/cpp/qps/qps_worker.cc
+++ b/test/cpp/qps/qps_worker.cc
@@ -25,16 +25,16 @@
 #include <thread>
 #include <vector>
 
-#include <grpc++/client_context.h>
-#include <grpc++/security/server_credentials.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/cpu.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
 
+#include "src/core/lib/gpr/host_port.h"
 #include "src/proto/grpc/testing/services.pb.h"
 #include "test/core/util/grpc_profiler.h"
 #include "test/core/util/histogram.h"
diff --git a/test/cpp/qps/qps_worker.h b/test/cpp/qps/qps_worker.h
index a516742..3a8796e 100644
--- a/test/cpp/qps/qps_worker.h
+++ b/test/cpp/qps/qps_worker.h
@@ -21,10 +21,10 @@
 
 #include <memory>
 
-#include <grpc++/server.h>
-#include <grpc++/support/channel_arguments.h>
-#include <grpc++/support/config.h>
 #include <grpc/support/atm.h>
+#include <grpcpp/server.h>
+#include <grpcpp/support/channel_arguments.h>
+#include <grpcpp/support/config.h>
 
 #include "test/cpp/qps/server.h"
 
diff --git a/test/cpp/qps/report.cc b/test/cpp/qps/report.cc
index 42ebeff..0a2565d 100644
--- a/test/cpp/qps/report.cc
+++ b/test/cpp/qps/report.cc
@@ -25,7 +25,7 @@
 #include "test/cpp/qps/parse_json.h"
 #include "test/cpp/qps/stats.h"
 
-#include <grpc++/client_context.h>
+#include <grpcpp/client_context.h>
 #include "src/cpp/util/core_stats.h"
 #include "src/proto/grpc/testing/services.grpc.pb.h"
 
@@ -109,9 +109,12 @@
   for (int i = 0; i < GRPC_STATS_HISTOGRAM_COUNT; i++) {
     gpr_log(GPR_DEBUG, "%s[%d].%s = %.1lf/%.1lf/%.1lf (50/95/99%%-ile)", name,
             idx, grpc_stats_histogram_name[i],
-            grpc_stats_histo_percentile(&data, (grpc_stats_histograms)i, 50),
-            grpc_stats_histo_percentile(&data, (grpc_stats_histograms)i, 95),
-            grpc_stats_histo_percentile(&data, (grpc_stats_histograms)i, 99));
+            grpc_stats_histo_percentile(
+                &data, static_cast<grpc_stats_histograms>(i), 50),
+            grpc_stats_histo_percentile(
+                &data, static_cast<grpc_stats_histograms>(i), 95),
+            grpc_stats_histo_percentile(
+                &data, static_cast<grpc_stats_histograms>(i), 99));
   }
 }
 
diff --git a/test/cpp/qps/report.h b/test/cpp/qps/report.h
index 1d7b2b5..c5dd138 100644
--- a/test/cpp/qps/report.h
+++ b/test/cpp/qps/report.h
@@ -23,11 +23,11 @@
 #include <set>
 #include <vector>
 
-#include <grpc++/support/config.h>
+#include <grpcpp/support/config.h>
 
 #include "test/cpp/qps/driver.h"
 
-#include <grpc++/channel.h>
+#include <grpcpp/channel.h>
 #include "src/proto/grpc/testing/services.grpc.pb.h"
 
 namespace grpc {
diff --git a/test/cpp/qps/server.h b/test/cpp/qps/server.h
index 9da3356..6b1ef93 100644
--- a/test/cpp/qps/server.h
+++ b/test/cpp/qps/server.h
@@ -19,11 +19,11 @@
 #ifndef TEST_QPS_SERVER_H
 #define TEST_QPS_SERVER_H
 
-#include <grpc++/resource_quota.h>
-#include <grpc++/security/server_credentials.h>
-#include <grpc++/server_builder.h>
 #include <grpc/support/cpu.h>
 #include <grpc/support/log.h>
+#include <grpcpp/resource_quota.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server_builder.h>
 #include <vector>
 
 #include "src/cpp/util/core_stats.h"
@@ -84,7 +84,7 @@
     }
     payload->set_type(type);
     // Don't waste time creating a new payload of identical size.
-    if (payload->body().length() != (size_t)size) {
+    if (payload->body().length() != static_cast<size_t>(size)) {
       std::unique_ptr<char[]> body(new char[size]());
       payload->set_body(body.get(), size);
     }
diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc
index 72ae772..9cb05cd 100644
--- a/test/cpp/qps/server_async.cc
+++ b/test/cpp/qps/server_async.cc
@@ -23,18 +23,18 @@
 #include <mutex>
 #include <thread>
 
-#include <grpc++/generic/async_generic_service.h>
-#include <grpc++/resource_quota.h>
-#include <grpc++/security/server_credentials.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
-#include <grpc++/support/config.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
+#include <grpcpp/generic/async_generic_service.h>
+#include <grpcpp/resource_quota.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
+#include <grpcpp/support/config.h>
 
+#include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/surface/completion_queue.h"
 #include "src/proto/grpc/testing/services.grpc.pb.h"
 #include "test/core/util/test_config.h"
@@ -240,11 +240,9 @@
    private:
     std::mutex mu_;
   };
-  static void* tag(ServerRpcContext* func) {
-    return reinterpret_cast<void*>(func);
-  }
+  static void* tag(ServerRpcContext* func) { return static_cast<void*>(func); }
   static ServerRpcContext* detag(void* tag) {
-    return reinterpret_cast<ServerRpcContext*>(tag);
+    return static_cast<ServerRpcContext*>(tag);
   }
 
   class ServerRpcContextUnaryImpl final : public ServerRpcContext {
diff --git a/test/cpp/qps/server_sync.cc b/test/cpp/qps/server_sync.cc
index ea89a30..9dfd362 100644
--- a/test/cpp/qps/server_sync.cc
+++ b/test/cpp/qps/server_sync.cc
@@ -19,13 +19,13 @@
 #include <atomic>
 #include <thread>
 
-#include <grpc++/security/server_credentials.h>
-#include <grpc++/server.h>
-#include <grpc++/server_context.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_context.h>
 
+#include "src/core/lib/gpr/host_port.h"
 #include "src/proto/grpc/testing/services.grpc.pb.h"
 #include "test/cpp/qps/server.h"
 #include "test/cpp/qps/usage_timer.h"
diff --git a/test/cpp/server/server_builder_test.cc b/test/cpp/server/server_builder_test.cc
index 694ce54..2752b58 100644
--- a/test/cpp/server/server_builder_test.cc
+++ b/test/cpp/server/server_builder_test.cc
@@ -16,11 +16,11 @@
  *
  */
 
-#include <grpc++/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/config.h>
 #include <gtest/gtest.h>
 
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
 
 #include <grpc/grpc.h>
 
diff --git a/test/cpp/server/server_request_call_test.cc b/test/cpp/server/server_request_call_test.cc
index b0a2fa4..9831c06 100644
--- a/test/cpp/server/server_request_call_test.cc
+++ b/test/cpp/server/server_request_call_test.cc
@@ -18,13 +18,13 @@
 
 #include <thread>
 
-#include <grpc++/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/config.h>
 
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
 
-#include <grpc++/create_channel.h>
-#include <grpc++/security/credentials.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/security/credentials.h>
 
 #include <grpc/support/log.h>
 
diff --git a/test/cpp/test/BUILD b/test/cpp/test/BUILD
new file mode 100644
index 0000000..c549478
--- /dev/null
+++ b/test/cpp/test/BUILD
@@ -0,0 +1,39 @@
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 v2
+
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_package", "grpc_cc_binary")
+
+grpc_package(
+    name = "test/cpp/test",
+    visibility = "public",
+)
+
+grpc_cc_test(
+    name = "server_context_test_spouse_test",
+    srcs = ["server_context_test_spouse_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//:grpc++",
+        "//:grpc++_test",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+        "//test/cpp/util:test_util",
+    ],
+)
diff --git a/test/cpp/test/server_context_test_spouse_test.cc b/test/cpp/test/server_context_test_spouse_test.cc
index d1dc9d7..e199a0f 100644
--- a/test/cpp/test/server_context_test_spouse_test.cc
+++ b/test/cpp/test/server_context_test_spouse_test.cc
@@ -16,12 +16,12 @@
  *
  */
 
-#include <grpc++/test/server_context_test_spouse.h>
+#include <grpcpp/test/server_context_test_spouse.h>
 
 #include <cstring>
 #include <vector>
 
-#include <grpc++/impl/grpc_library.h>
+#include <grpcpp/impl/grpc_library.h>
 #include <gtest/gtest.h>
 
 namespace grpc {
diff --git a/test/cpp/thread_manager/BUILD b/test/cpp/thread_manager/BUILD
new file mode 100644
index 0000000..093e51e
--- /dev/null
+++ b/test/cpp/thread_manager/BUILD
@@ -0,0 +1,40 @@
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 v2
+
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_package", "grpc_cc_binary")
+
+grpc_package(
+    name = "test/cpp/thread_manager",
+    visibility = "public",
+)
+
+grpc_cc_test(
+    name = "thread_manager_test",
+    srcs = ["thread_manager_test.cc"],
+    external_deps = [
+        "gflags",
+        "gtest",
+    ],
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//:grpc++",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+        "//test/cpp/util:test_config",
+        "//test/cpp/util:test_util",
+    ],
+)
diff --git a/test/cpp/thread_manager/thread_manager_test.cc b/test/cpp/thread_manager/thread_manager_test.cc
index 8282d46..7a95a9f 100644
--- a/test/cpp/thread_manager/thread_manager_test.cc
+++ b/test/cpp/thread_manager/thread_manager_test.cc
@@ -16,14 +16,15 @@
  *is % allowed in string
  */
 
+#include <inttypes.h>
 #include <ctime>
 #include <memory>
 #include <string>
 
 #include <gflags/gflags.h>
-#include <grpc++/grpc++.h>
 #include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
+#include <grpcpp/grpcpp.h>
 
 #include "src/cpp/thread_manager/thread_manager.h"
 #include "test/cpp/util/test_config.h"
diff --git a/test/cpp/util/BUILD b/test/cpp/util/BUILD
index af25fca..f53bc7e 100644
--- a/test/cpp/util/BUILD
+++ b/test/cpp/util/BUILD
@@ -16,7 +16,10 @@
 
 load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_binary", "grpc_cc_test", "grpc_package")
 
-grpc_package(name = "test/cpp/util", visibility = "public")
+grpc_package(
+    name = "test/cpp/util",
+    visibility = "public",
+)
 
 grpc_cc_library(
     name = "test_config",
@@ -49,7 +52,7 @@
     ],
 )
 
-GRPCXX_TESTUTIL_SRCS  = [
+GRPCXX_TESTUTIL_SRCS = [
     "byte_buffer_proto_helper.cc",
     "string_ref_helper.cc",
     "subprocess.cc",
@@ -71,11 +74,31 @@
         "create_test_channel.h",
         "test_credentials_provider.h",
     ],
+    external_deps = [
+        "protobuf",
+    ],
     deps = [
         "//:grpc++",
         "//test/core/end2end:ssl_test_data",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+grpc_cc_library(
+    name = "channel_trace_proto_helper",
+    testonly = 1,
+    srcs = [
+        "channel_trace_proto_helper.cc",
+    ],
+    hdrs = [
+        "channel_trace_proto_helper.h",
+    ],
+    deps = [
+        "//:grpc++",
+        "//src/proto/grpc/channelz:channelz_proto",
     ],
     external_deps = [
+        "gtest",
         "protobuf",
     ],
 )
@@ -84,12 +107,13 @@
     name = "test_util_unsecure",
     srcs = GRPCXX_TESTUTIL_SRCS,
     hdrs = GRPCXX_TESTUTIL_HDRS,
-    deps = [
-        "//:grpc++_unsecure",
-    ],
     external_deps = [
         "protobuf",
     ],
+    deps = [
+        "//:grpc++_unsecure",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
 grpc_cc_library(
@@ -109,16 +133,16 @@
         "proto_file_parser.h",
         "service_describer.h",
     ],
-    deps = [
-        "//:grpc++",
-        "//src/proto/grpc/reflection/v1alpha:reflection_proto",
-        ":grpc++_proto_reflection_desc_db",
-    ],
     external_deps = [
         "gflags",
         "protobuf",
         "protobuf_clib",
     ],
+    deps = [
+        ":grpc++_proto_reflection_desc_db",
+        "//:grpc++",
+        "//src/proto/grpc/reflection/v1alpha:reflection_proto",
+    ],
 )
 
 grpc_cc_library(
@@ -130,8 +154,8 @@
         "metrics_server.h",
     ],
     deps = [
-        "//src/proto/grpc/testing:metrics_proto",
         "//:grpc++",
+        "//src/proto/grpc/testing:metrics_proto",
     ],
 )
 
@@ -142,19 +166,19 @@
     ],
     data = [
         "//src/proto/grpc/testing:echo.proto",
-        "//src/proto/grpc/testing:echo_messages.proto"
-    ],       
-    deps = [
-        ":grpc_cli_libs",
-	":test_util",
-	"//:grpc++_reflection",
-        "//src/proto/grpc/testing:echo_proto",
-        "//src/proto/grpc/testing:echo_messages_proto",
-	"//test/core/util:grpc_test_util",
+        "//src/proto/grpc/testing:echo_messages.proto",
     ],
     external_deps = [
         "gtest",
     ],
+    deps = [
+        ":grpc_cli_libs",
+        ":test_util",
+        "//:grpc++_reflection",
+        "//src/proto/grpc/testing:echo_messages_proto",
+        "//src/proto/grpc/testing:echo_proto",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
 grpc_cc_test(
@@ -162,12 +186,12 @@
     srcs = [
         "byte_buffer_test.cc",
     ],
-    deps = [
-	":test_util",
-    ],
     external_deps = [
         "gtest",
     ],
+    deps = [
+        ":test_util",
+    ],
 )
 
 grpc_cc_test(
@@ -175,12 +199,12 @@
     srcs = [
         "slice_test.cc",
     ],
-    deps = [
-	":test_util",
-    ],
     external_deps = [
         "gtest",
     ],
+    deps = [
+        ":test_util",
+    ],
 )
 
 grpc_cc_test(
@@ -188,12 +212,12 @@
     srcs = [
         "string_ref_test.cc",
     ],
-    deps = [
-	"//:grpc++",
-    ],
     external_deps = [
         "gtest",
     ],
+    deps = [
+        "//:grpc++",
+    ],
 )
 
 grpc_cc_test(
@@ -201,24 +225,11 @@
     srcs = [
         "time_test.cc",
     ],
-    deps = [
-	":test_util",
-    ],
     external_deps = [
         "gtest",
     ],
-)
-
-grpc_cc_test(
-    name = "status_test",
-    srcs = [
-        "status_test.cc",
-    ],
     deps = [
-	":test_util",
-    ],
-    external_deps = [
-        "gtest",
+        ":test_util",
     ],
 )
 
@@ -227,15 +238,15 @@
     srcs = [
         "cli_call_test.cc",
     ],
-    deps = [
-        ":grpc_cli_libs",
-	":test_util",
-        "//src/proto/grpc/testing:echo_proto",
-	"//test/core/util:grpc_test_util",
-    ],
     external_deps = [
         "gtest",
     ],
+    deps = [
+        ":grpc_cli_libs",
+        ":test_util",
+        "//src/proto/grpc/testing:echo_proto",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
 grpc_cc_test(
@@ -243,13 +254,13 @@
     srcs = [
         "error_details_test.cc",
     ],
+    external_deps = [
+        "gtest",
+    ],
     deps = [
         "//:grpc++_error_details",
         "//src/proto/grpc/testing:echo_messages_proto",
     ],
-    external_deps = [
-        "gtest",
-    ],
 )
 
 grpc_cc_binary(
@@ -272,11 +283,11 @@
         "test_config.h",
         "test_config_cc.cc",
     ],
+    external_deps = [
+        "gflags",
+    ],
     deps = [
         "//:grpc++",
         "//src/proto/grpc/reflection/v1alpha:reflection_proto",
     ],
-    external_deps = [
-        "gflags",
-    ],
 )
diff --git a/test/cpp/util/byte_buffer_proto_helper.h b/test/cpp/util/byte_buffer_proto_helper.h
index 1a9955e..94603db 100644
--- a/test/cpp/util/byte_buffer_proto_helper.h
+++ b/test/cpp/util/byte_buffer_proto_helper.h
@@ -21,8 +21,8 @@
 
 #include <memory>
 
-#include <grpc++/impl/codegen/config_protobuf.h>
-#include <grpc++/support/byte_buffer.h>
+#include <grpcpp/impl/codegen/config_protobuf.h>
+#include <grpcpp/support/byte_buffer.h>
 
 namespace grpc {
 namespace testing {
diff --git a/test/cpp/util/byte_buffer_test.cc b/test/cpp/util/byte_buffer_test.cc
index d603b28..605ef15 100644
--- a/test/cpp/util/byte_buffer_test.cc
+++ b/test/cpp/util/byte_buffer_test.cc
@@ -16,14 +16,14 @@
  *
  */
 
-#include <grpc++/support/byte_buffer.h>
+#include <grpcpp/support/byte_buffer.h>
 
 #include <cstring>
 #include <vector>
 
-#include <grpc++/support/slice.h>
 #include <grpc/grpc.h>
 #include <grpc/slice.h>
+#include <grpcpp/support/slice.h>
 #include <gtest/gtest.h>
 
 namespace grpc {
diff --git a/test/cpp/util/channel_trace_proto_helper.cc b/test/cpp/util/channel_trace_proto_helper.cc
new file mode 100644
index 0000000..fbc9f15
--- /dev/null
+++ b/test/cpp/util/channel_trace_proto_helper.cc
@@ -0,0 +1,56 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "test/cpp/util/channel_trace_proto_helper.h"
+
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/util/json_util.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include <gtest/gtest.h>
+
+#include "src/proto/grpc/channelz/channelz.pb.h"
+
+namespace grpc {
+namespace testing {
+
+void ValidateChannelTraceProtoJsonTranslation(char* tracer_json_c_str) {
+  std::string tracer_json_str(tracer_json_c_str);
+  grpc::channelz::ChannelTrace channel_trace;
+  google::protobuf::util::JsonParseOptions parse_options;
+  // If the following line is failing, then uncomment the last line of the
+  // comment, and uncomment the lines that print the two strings. You can
+  // then compare the output, and determine what fields are missing.
+  //
+  // options.ignore_unknown_fields = true;
+  ASSERT_EQ(google::protobuf::util::JsonStringToMessage(
+                tracer_json_str, &channel_trace, parse_options),
+            google::protobuf::util::Status::OK);
+  std::string proto_json_str;
+  ASSERT_EQ(google::protobuf::util::MessageToJsonString(channel_trace,
+                                                        &proto_json_str),
+            google::protobuf::util::Status::OK);
+  // uncomment these to compare the the json strings.
+  // gpr_log(GPR_ERROR, "tracer json: %s", tracer_json_str.c_str());
+  // gpr_log(GPR_ERROR, "proto  json: %s", proto_json_str.c_str());
+  ASSERT_EQ(tracer_json_str, proto_json_str);
+}
+
+}  // namespace testing
+}  // namespace grpc
diff --git a/test/cpp/util/channel_trace_proto_helper.h b/test/cpp/util/channel_trace_proto_helper.h
new file mode 100644
index 0000000..d7043d9
--- /dev/null
+++ b/test/cpp/util/channel_trace_proto_helper.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 GRPC_TEST_CPP_UTIL_CHANNEL_TRACE_PROTO_HELPER_H
+#define GRPC_TEST_CPP_UTIL_CHANNEL_TRACE_PROTO_HELPER_H
+
+namespace grpc {
+namespace testing {
+
+void ValidateChannelTraceProtoJsonTranslation(char* tracer_json_c_str);
+
+}  // namespace testing
+}  // namespace grpc
+
+#endif  // GRPC_TEST_CPP_UTIL_CHANNEL_TRACE_PROTO_HELPER_H
diff --git a/test/cpp/util/cli_call.cc b/test/cpp/util/cli_call.cc
index 4f1a20c..a3992ab 100644
--- a/test/cpp/util/cli_call.cc
+++ b/test/cpp/util/cli_call.cc
@@ -20,17 +20,17 @@
 
 #include <iostream>
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/support/byte_buffer.h>
 #include <grpc/grpc.h>
 #include <grpc/slice.h>
 #include <grpc/support/log.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/support/byte_buffer.h>
 
 namespace grpc {
 namespace testing {
 namespace {
-void* tag(int i) { return (void*)(intptr_t)i; }
+void* tag(int i) { return (void*)static_cast<intptr_t>(i); }
 }  // namespace
 
 Status CliCall::Call(std::shared_ptr<grpc::Channel> channel,
@@ -60,7 +60,8 @@
       ctx_.AddMetadata(iter->first, iter->second);
     }
   }
-  call_ = stub_->Call(&ctx_, method, &cq_, tag(1));
+  call_ = stub_->PrepareCall(&ctx_, method, &cq_);
+  call_->StartCall(tag(1));
   void* got_tag;
   bool ok;
   cq_.Next(&got_tag, &ok);
diff --git a/test/cpp/util/cli_call.h b/test/cpp/util/cli_call.h
index eff18ee..51ffafd 100644
--- a/test/cpp/util/cli_call.h
+++ b/test/cpp/util/cli_call.h
@@ -21,11 +21,11 @@
 
 #include <map>
 
-#include <grpc++/channel.h>
-#include <grpc++/completion_queue.h>
-#include <grpc++/generic/generic_stub.h>
-#include <grpc++/support/status.h>
-#include <grpc++/support/string_ref.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/completion_queue.h>
+#include <grpcpp/generic/generic_stub.h>
+#include <grpcpp/support/status.h>
+#include <grpcpp/support/string_ref.h>
 
 namespace grpc {
 
diff --git a/test/cpp/util/cli_call_test.cc b/test/cpp/util/cli_call_test.cc
index e54cc85..516f3fa 100644
--- a/test/cpp/util/cli_call_test.cc
+++ b/test/cpp/util/cli_call_test.cc
@@ -18,13 +18,13 @@
 
 #include "test/cpp/util/cli_call.h"
 
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
 #include <grpc/grpc.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
 #include <gtest/gtest.h>
 
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
diff --git a/test/cpp/util/cli_credentials.h b/test/cpp/util/cli_credentials.h
index 469e8c5..b1358e7 100644
--- a/test/cpp/util/cli_credentials.h
+++ b/test/cpp/util/cli_credentials.h
@@ -19,8 +19,8 @@
 #ifndef GRPC_TEST_CPP_UTIL_CLI_CREDENTIALS_H
 #define GRPC_TEST_CPP_UTIL_CLI_CREDENTIALS_H
 
-#include <grpc++/security/credentials.h>
-#include <grpc++/support/config.h>
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/support/config.h>
 
 namespace grpc {
 namespace testing {
diff --git a/test/cpp/util/config_grpc_cli.h b/test/cpp/util/config_grpc_cli.h
index c157aab..3588841 100644
--- a/test/cpp/util/config_grpc_cli.h
+++ b/test/cpp/util/config_grpc_cli.h
@@ -19,7 +19,7 @@
 #ifndef GRPC_TEST_CPP_UTIL_CONFIG_GRPC_CLI_H
 #define GRPC_TEST_CPP_UTIL_CONFIG_GRPC_CLI_H
 
-#include <grpc++/impl/codegen/config_protobuf.h>
+#include <grpcpp/impl/codegen/config_protobuf.h>
 
 #ifndef GRPC_CUSTOM_DYNAMICMESSAGEFACTORY
 #include <google/protobuf/dynamic_message.h>
diff --git a/test/cpp/util/create_test_channel.cc b/test/cpp/util/create_test_channel.cc
index 4d04747..1047d44 100644
--- a/test/cpp/util/create_test_channel.cc
+++ b/test/cpp/util/create_test_channel.cc
@@ -18,9 +18,9 @@
 
 #include "test/cpp/util/create_test_channel.h"
 
-#include <grpc++/create_channel.h>
-#include <grpc++/security/credentials.h>
 #include <grpc/support/log.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/security/credentials.h>
 
 #include "test/cpp/util/test_credentials_provider.h"
 
diff --git a/test/cpp/util/create_test_channel.h b/test/cpp/util/create_test_channel.h
index e2ca8f9..ddaa99f 100644
--- a/test/cpp/util/create_test_channel.h
+++ b/test/cpp/util/create_test_channel.h
@@ -21,7 +21,7 @@
 
 #include <memory>
 
-#include <grpc++/security/credentials.h>
+#include <grpcpp/security/credentials.h>
 
 namespace grpc {
 class Channel;
diff --git a/test/cpp/util/error_details_test.cc b/test/cpp/util/error_details_test.cc
index 16a00fb..f71dfc0 100644
--- a/test/cpp/util/error_details_test.cc
+++ b/test/cpp/util/error_details_test.cc
@@ -16,7 +16,7 @@
  *
  */
 
-#include <grpc++/support/error_details.h>
+#include <grpcpp/support/error_details.h>
 #include <gtest/gtest.h>
 
 #include "src/proto/grpc/status/status.pb.h"
diff --git a/test/cpp/util/grpc_cli.cc b/test/cpp/util/grpc_cli.cc
index 6735943..10e13d9 100644
--- a/test/cpp/util/grpc_cli.cc
+++ b/test/cpp/util/grpc_cli.cc
@@ -58,7 +58,7 @@
 #include <iostream>
 
 #include <gflags/gflags.h>
-#include <grpc++/support/config.h>
+#include <grpcpp/support/config.h>
 #include "test/cpp/util/cli_credentials.h"
 #include "test/cpp/util/grpc_tool.h"
 #include "test/cpp/util/test_config.h"
diff --git a/test/cpp/util/grpc_tool.cc b/test/cpp/util/grpc_tool.cc
index 30c43b2..195b6bd 100644
--- a/test/cpp/util/grpc_tool.cc
+++ b/test/cpp/util/grpc_tool.cc
@@ -27,13 +27,13 @@
 #include <thread>
 
 #include <gflags/gflags.h>
-#include <grpc++/channel.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/grpc++.h>
-#include <grpc++/security/credentials.h>
-#include <grpc++/support/string_ref.h>
 #include <grpc/grpc.h>
 #include <grpc/support/port_platform.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/grpcpp.h>
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/support/string_ref.h>
 
 #include "test/cpp/util/cli_call.h"
 #include "test/cpp/util/proto_file_parser.h"
@@ -747,6 +747,8 @@
       }
     }
     Status status = call.Finish(&server_trailing_metadata);
+    PrintMetadata(server_trailing_metadata,
+                  "Received trailing metadata from server:");
     if (status.ok()) {
       fprintf(stderr, "Rpc succeeded with OK status\n");
       return true;
diff --git a/test/cpp/util/grpc_tool.h b/test/cpp/util/grpc_tool.h
index a10422f..fb53af7 100644
--- a/test/cpp/util/grpc_tool.h
+++ b/test/cpp/util/grpc_tool.h
@@ -21,7 +21,7 @@
 
 #include <functional>
 
-#include <grpc++/support/config.h>
+#include <grpcpp/support/config.h>
 
 #include "test/cpp/util/cli_credentials.h"
 
diff --git a/test/cpp/util/grpc_tool_test.cc b/test/cpp/util/grpc_tool_test.cc
index 135cfdc..9f7fec5 100644
--- a/test/cpp/util/grpc_tool_test.cc
+++ b/test/cpp/util/grpc_tool_test.cc
@@ -21,14 +21,14 @@
 #include <sstream>
 
 #include <gflags/gflags.h>
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/ext/proto_server_reflection_plugin.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
 #include <grpc/grpc.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/ext/proto_server_reflection_plugin.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
 #include <gtest/gtest.h>
 
 #include "src/core/lib/gpr/env.h"
diff --git a/test/cpp/util/metrics_server.cc b/test/cpp/util/metrics_server.cc
index 5982815..a058206 100644
--- a/test/cpp/util/metrics_server.cc
+++ b/test/cpp/util/metrics_server.cc
@@ -18,9 +18,9 @@
 
 #include "test/cpp/util/metrics_server.h"
 
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
 #include <grpc/support/log.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
 
 #include "src/proto/grpc/testing/metrics.grpc.pb.h"
 #include "src/proto/grpc/testing/metrics.pb.h"
diff --git a/test/cpp/util/proto_file_parser.cc b/test/cpp/util/proto_file_parser.cc
index e2c8b05..3fc96f3 100644
--- a/test/cpp/util/proto_file_parser.cc
+++ b/test/cpp/util/proto_file_parser.cc
@@ -23,7 +23,7 @@
 #include <sstream>
 #include <unordered_set>
 
-#include <grpc++/support/config.h>
+#include <grpcpp/support/config.h>
 
 namespace grpc {
 namespace testing {
diff --git a/test/cpp/util/proto_file_parser.h b/test/cpp/util/proto_file_parser.h
index 35f3782..2236b59 100644
--- a/test/cpp/util/proto_file_parser.h
+++ b/test/cpp/util/proto_file_parser.h
@@ -21,7 +21,7 @@
 
 #include <memory>
 
-#include <grpc++/channel.h>
+#include <grpcpp/channel.h>
 
 #include "test/cpp/util/config_grpc_cli.h"
 #include "test/cpp/util/proto_reflection_descriptor_database.h"
diff --git a/test/cpp/util/proto_reflection_descriptor_database.cc b/test/cpp/util/proto_reflection_descriptor_database.cc
index 0f77934..0adbf20 100644
--- a/test/cpp/util/proto_reflection_descriptor_database.cc
+++ b/test/cpp/util/proto_reflection_descriptor_database.cc
@@ -43,9 +43,15 @@
     stream_->WritesDone();
     Status status = stream_->Finish();
     if (!status.ok()) {
+      if (status.error_code() == StatusCode::UNIMPLEMENTED) {
+        gpr_log(GPR_INFO,
+                "Reflection request not implemented; "
+                "is the ServerReflection service enabled?");
+      }
       gpr_log(GPR_INFO,
               "ServerReflectionInfo rpc failed. Error code: %d, details: %s",
-              (int)status.error_code(), status.error_message().c_str());
+              static_cast<int>(status.error_code()),
+              status.error_message().c_str());
     }
   }
 }
@@ -64,7 +70,9 @@
   request.set_file_by_filename(filename);
   ServerReflectionResponse response;
 
-  DoOneRequest(request, response);
+  if (!DoOneRequest(request, response)) {
+    return false;
+  }
 
   if (response.message_response_case() ==
       ServerReflectionResponse::MessageResponseCase::kFileDescriptorResponse) {
@@ -109,7 +117,9 @@
   request.set_file_containing_symbol(symbol_name);
   ServerReflectionResponse response;
 
-  DoOneRequest(request, response);
+  if (!DoOneRequest(request, response)) {
+    return false;
+  }
 
   if (response.message_response_case() ==
       ServerReflectionResponse::MessageResponseCase::kFileDescriptorResponse) {
@@ -163,7 +173,9 @@
       field_number);
   ServerReflectionResponse response;
 
-  DoOneRequest(request, response);
+  if (!DoOneRequest(request, response)) {
+    return false;
+  }
 
   if (response.message_response_case() ==
       ServerReflectionResponse::MessageResponseCase::kFileDescriptorResponse) {
@@ -213,7 +225,9 @@
   request.set_all_extension_numbers_of_type(extendee_type);
   ServerReflectionResponse response;
 
-  DoOneRequest(request, response);
+  if (!DoOneRequest(request, response)) {
+    return false;
+  }
 
   if (response.message_response_case() ==
       ServerReflectionResponse::MessageResponseCase::
@@ -245,7 +259,9 @@
   request.set_list_services("");
   ServerReflectionResponse response;
 
-  DoOneRequest(request, response);
+  if (!DoOneRequest(request, response)) {
+    return false;
+  }
 
   if (response.message_response_case() ==
       ServerReflectionResponse::MessageResponseCase::kListServicesResponse) {
diff --git a/test/cpp/util/proto_reflection_descriptor_database.h b/test/cpp/util/proto_reflection_descriptor_database.h
index a6776c2..e4cf2f2 100644
--- a/test/cpp/util/proto_reflection_descriptor_database.h
+++ b/test/cpp/util/proto_reflection_descriptor_database.h
@@ -23,8 +23,8 @@
 #include <unordered_set>
 #include <vector>
 
-#include <grpc++/grpc++.h>
-#include <grpc++/impl/codegen/config_protobuf.h>
+#include <grpcpp/grpcpp.h>
+#include <grpcpp/impl/codegen/config_protobuf.h>
 #include "src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.h"
 
 namespace grpc {
diff --git a/test/cpp/util/service_describer.h b/test/cpp/util/service_describer.h
index b7ab757..f7ef50c 100644
--- a/test/cpp/util/service_describer.h
+++ b/test/cpp/util/service_describer.h
@@ -19,7 +19,7 @@
 #ifndef GRPC_TEST_CPP_UTIL_SERVICE_DESCRIBER_H
 #define GRPC_TEST_CPP_UTIL_SERVICE_DESCRIBER_H
 
-#include <grpc++/support/config.h>
+#include <grpcpp/support/config.h>
 #include "test/cpp/util/config_grpc_cli.h"
 
 namespace grpc {
diff --git a/test/cpp/util/slice_test.cc b/test/cpp/util/slice_test.cc
index c2e55f3..8e06062 100644
--- a/test/cpp/util/slice_test.cc
+++ b/test/cpp/util/slice_test.cc
@@ -16,7 +16,7 @@
  *
  */
 
-#include <grpc++/support/slice.h>
+#include <grpcpp/support/slice.h>
 
 #include <grpc/grpc.h>
 #include <grpc/slice.h>
@@ -67,7 +67,7 @@
 TEST_F(SliceTest, SliceNew) {
   char* x = new char[strlen(kContent) + 1];
   strcpy(x, kContent);
-  Slice spp(x, strlen(x), [](void* p) { delete[] reinterpret_cast<char*>(p); });
+  Slice spp(x, strlen(x), [](void* p) { delete[] static_cast<char*>(p); });
   CheckSlice(spp, kContent);
 }
 
@@ -86,7 +86,7 @@
   strcpy(t->x, kContent);
   Slice spp(t->x, strlen(t->x),
             [](void* p) {
-              auto* t = reinterpret_cast<stest*>(p);
+              auto* t = static_cast<stest*>(p);
               delete[] t->x;
               delete t;
             },
diff --git a/test/cpp/util/status_test.cc b/test/cpp/util/status_test.cc
deleted file mode 100644
index 1047cdb..0000000
--- a/test/cpp/util/status_test.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <grpc++/support/status.h>
-
-#include <grpc/status.h>
-#include <grpc/support/log.h>
-
-// Make sure the existing grpc_status_code match with grpc::Code.
-int main(int argc, char** argv) {
-  GPR_ASSERT(grpc::StatusCode::OK ==
-             static_cast<grpc::StatusCode>(GRPC_STATUS_OK));
-  GPR_ASSERT(grpc::StatusCode::CANCELLED ==
-             static_cast<grpc::StatusCode>(GRPC_STATUS_CANCELLED));
-  GPR_ASSERT(grpc::StatusCode::UNKNOWN ==
-             static_cast<grpc::StatusCode>(GRPC_STATUS_UNKNOWN));
-  GPR_ASSERT(grpc::StatusCode::INVALID_ARGUMENT ==
-             static_cast<grpc::StatusCode>(GRPC_STATUS_INVALID_ARGUMENT));
-  GPR_ASSERT(grpc::StatusCode::DEADLINE_EXCEEDED ==
-             static_cast<grpc::StatusCode>(GRPC_STATUS_DEADLINE_EXCEEDED));
-  GPR_ASSERT(grpc::StatusCode::NOT_FOUND ==
-             static_cast<grpc::StatusCode>(GRPC_STATUS_NOT_FOUND));
-  GPR_ASSERT(grpc::StatusCode::ALREADY_EXISTS ==
-             static_cast<grpc::StatusCode>(GRPC_STATUS_ALREADY_EXISTS));
-  GPR_ASSERT(grpc::StatusCode::PERMISSION_DENIED ==
-             static_cast<grpc::StatusCode>(GRPC_STATUS_PERMISSION_DENIED));
-  GPR_ASSERT(grpc::StatusCode::UNAUTHENTICATED ==
-             static_cast<grpc::StatusCode>(GRPC_STATUS_UNAUTHENTICATED));
-  GPR_ASSERT(grpc::StatusCode::RESOURCE_EXHAUSTED ==
-             static_cast<grpc::StatusCode>(GRPC_STATUS_RESOURCE_EXHAUSTED));
-  GPR_ASSERT(grpc::StatusCode::FAILED_PRECONDITION ==
-             static_cast<grpc::StatusCode>(GRPC_STATUS_FAILED_PRECONDITION));
-  GPR_ASSERT(grpc::StatusCode::ABORTED ==
-             static_cast<grpc::StatusCode>(GRPC_STATUS_ABORTED));
-  GPR_ASSERT(grpc::StatusCode::OUT_OF_RANGE ==
-             static_cast<grpc::StatusCode>(GRPC_STATUS_OUT_OF_RANGE));
-  GPR_ASSERT(grpc::StatusCode::UNIMPLEMENTED ==
-             static_cast<grpc::StatusCode>(GRPC_STATUS_UNIMPLEMENTED));
-  GPR_ASSERT(grpc::StatusCode::INTERNAL ==
-             static_cast<grpc::StatusCode>(GRPC_STATUS_INTERNAL));
-  GPR_ASSERT(grpc::StatusCode::UNAVAILABLE ==
-             static_cast<grpc::StatusCode>(GRPC_STATUS_UNAVAILABLE));
-  GPR_ASSERT(grpc::StatusCode::DATA_LOSS ==
-             static_cast<grpc::StatusCode>(GRPC_STATUS_DATA_LOSS));
-
-  return 0;
-}
diff --git a/test/cpp/util/string_ref_helper.h b/test/cpp/util/string_ref_helper.h
index e4cb71a..707767d 100644
--- a/test/cpp/util/string_ref_helper.h
+++ b/test/cpp/util/string_ref_helper.h
@@ -19,7 +19,7 @@
 #ifndef GRPC_TEST_CPP_UTIL_STRING_REF_HELPER_H
 #define GRPC_TEST_CPP_UTIL_STRING_REF_HELPER_H
 
-#include <grpc++/support/string_ref.h>
+#include <grpcpp/support/string_ref.h>
 
 namespace grpc {
 namespace testing {
diff --git a/test/cpp/util/string_ref_test.cc b/test/cpp/util/string_ref_test.cc
index 3f62760..8f7986e 100644
--- a/test/cpp/util/string_ref_test.cc
+++ b/test/cpp/util/string_ref_test.cc
@@ -16,7 +16,7 @@
  *
  */
 
-#include <grpc++/support/string_ref.h>
+#include <grpcpp/support/string_ref.h>
 
 #include <string.h>
 
diff --git a/test/cpp/util/subprocess.cc b/test/cpp/util/subprocess.cc
index a54d0c0..ddaad89 100644
--- a/test/cpp/util/subprocess.cc
+++ b/test/cpp/util/subprocess.cc
@@ -20,7 +20,7 @@
 
 #include <vector>
 
-#include <grpc/support/subprocess.h>
+#include "test/core/util/subprocess.h"
 
 namespace grpc {
 
diff --git a/test/cpp/util/test_credentials_provider.h b/test/cpp/util/test_credentials_provider.h
index 6f8f768..f489a2c 100644
--- a/test/cpp/util/test_credentials_provider.h
+++ b/test/cpp/util/test_credentials_provider.h
@@ -21,9 +21,9 @@
 
 #include <memory>
 
-#include <grpc++/security/credentials.h>
-#include <grpc++/security/server_credentials.h>
-#include <grpc++/support/channel_arguments.h>
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/support/channel_arguments.h>
 
 namespace grpc {
 namespace testing {
diff --git a/test/cpp/util/time_test.cc b/test/cpp/util/time_test.cc
index 73ec44c..a8851a5 100644
--- a/test/cpp/util/time_test.cc
+++ b/test/cpp/util/time_test.cc
@@ -16,8 +16,8 @@
  *
  */
 
-#include <grpc++/support/time.h>
 #include <grpc/support/time.h>
+#include <grpcpp/support/time.h>
 #include <gtest/gtest.h>
 
 using std::chrono::duration_cast;
diff --git a/test/distrib/cpp/run_distrib_test_cmake.bat b/test/distrib/cpp/run_distrib_test_cmake.bat
index f920768..8eb3b20 100644
--- a/test/distrib/cpp/run_distrib_test_cmake.bat
+++ b/test/distrib/cpp/run_distrib_test_cmake.bat
@@ -54,7 +54,7 @@
 cd cmake
 mkdir build
 cd build
-cmake -DCMAKE_INSTALL_PREFIX=%INSTALL_DIR% -DOPENSSL_ROOT_DIR=%OPENSSL_DIR% -DOPENSSL_INCLUDE_DIR=%OPENSSL_DIR%/include -DZLIB_LIBRARY=%INSTALL_DIR%/lib/zlibstatic.lib -DZLIB_INCLUDE_DIR=%INSTALL_DIR%/include -DgRPC_INSTALL=ON -DgRPC_BUILD_TESTS=OFF -DgRPC_PROTOBUF_PROVIDER=package -DgRPC_ZLIB_PROVIDER=package -DgRPC_CARES_PROVIDER=package -DgRPC_SSL_PROVIDER=package -DCMAKE_BUILD_TYPE=Release ../.. || goto :error
+cmake -DCMAKE_INSTALL_PREFIX=%INSTALL_DIR% -DOPENSSL_ROOT_DIR=%OPENSSL_DIR% -DZLIB_ROOT=%INSTALL_DIR% -DgRPC_INSTALL=ON -DgRPC_BUILD_TESTS=OFF -DgRPC_PROTOBUF_PROVIDER=package -DgRPC_ZLIB_PROVIDER=package -DgRPC_CARES_PROVIDER=package -DgRPC_SSL_PROVIDER=package -DCMAKE_BUILD_TYPE=Release ../.. || goto :error
 cmake --build . --config Release --target install || goto :error
 cd ../..
 
@@ -64,7 +64,7 @@
 cd cmake
 mkdir build
 cd build
-cmake -DCMAKE_INSTALL_PREFIX=%INSTALL_DIR% -DOPENSSL_ROOT_DIR=%OPENSSL_DIR% -DOPENSSL_INCLUDE_DIR=%OPENSSL_DIR%/include ../.. || goto :error
+cmake -DCMAKE_INSTALL_PREFIX=%INSTALL_DIR% -DOPENSSL_ROOT_DIR=%OPENSSL_DIR% -DZLIB_ROOT=%INSTALL_DIR% ../.. || goto :error
 cmake --build . --config Release || goto :error
 cd ../../../../..
 
diff --git a/test/distrib/cpp/run_distrib_test_cmake.sh b/test/distrib/cpp/run_distrib_test_cmake.sh
index a9c081c..6ec3cab 100755
--- a/test/distrib/cpp/run_distrib_test_cmake.sh
+++ b/test/distrib/cpp/run_distrib_test_cmake.sh
@@ -15,7 +15,7 @@
 
 set -ex
 
-cd $(dirname $0)/../../..
+cd "$(dirname "$0")/../../.."
 
 echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list
 apt-get update
diff --git a/test/distrib/cpp/run_distrib_test_routeguide.sh b/test/distrib/cpp/run_distrib_test_routeguide.sh
index b043075..dc69ab8 100755
--- a/test/distrib/cpp/run_distrib_test_routeguide.sh
+++ b/test/distrib/cpp/run_distrib_test_routeguide.sh
@@ -16,7 +16,7 @@
 set -ex
 
 # change to grpc repo root
-cd $(dirname $0)/../../..
+cd "$(dirname "$0")/../../.."
 
 cd third_party/protobuf && ./autogen.sh && \
 ./configure && make -j4 && make check && make install && ldconfig
diff --git a/test/distrib/csharp/run_distrib_test.sh b/test/distrib/csharp/run_distrib_test.sh
index 99cdb5e..b968727 100755
--- a/test/distrib/csharp/run_distrib_test.sh
+++ b/test/distrib/csharp/run_distrib_test.sh
@@ -15,12 +15,17 @@
 
 set -ex
 
-cd $(dirname $0)
+cd "$(dirname "$0")"
 
 unzip -o "$EXTERNAL_GIT_ROOT/input_artifacts/csharp_nugets_windows_dotnetcli.zip" -d TestNugetFeed
 
 ./update_version.sh auto
 
+# With a recent-enough version of mono, the "nuget restore" command would
+# restore packages based on project.json files, but we want to restore packages
+# based on the net45 legacy "packages.config" file instead.
+rm DistribTest/*project.json
+
 nuget restore
 
 xbuild DistribTest.sln
diff --git a/test/distrib/csharp/run_distrib_test_dotnetcli.sh b/test/distrib/csharp/run_distrib_test_dotnetcli.sh
index 53117d4..9e31945 100755
--- a/test/distrib/csharp/run_distrib_test_dotnetcli.sh
+++ b/test/distrib/csharp/run_distrib_test_dotnetcli.sh
@@ -15,7 +15,7 @@
 
 set -ex
 
-cd $(dirname $0)
+cd "$(dirname "$0")"
 
 unzip -o "$EXTERNAL_GIT_ROOT/input_artifacts/csharp_nugets_windows_dotnetcli.zip" -d TestNugetFeed
 
diff --git a/test/distrib/csharp/update_version.sh b/test/distrib/csharp/update_version.sh
index 2e9050c..734ec21 100755
--- a/test/distrib/csharp/update_version.sh
+++ b/test/distrib/csharp/update_version.sh
@@ -15,12 +15,14 @@
 
 set -e
 
-cd $(dirname $0)
+cd "$(dirname "$0")"
 
 CSHARP_VERSION="$1"
 if [ "$CSHARP_VERSION" == "auto" ]
 then
   # autodetect C# version from the name of Grpc.Core.0.0.0-x.nupkg file
+  # TODO: find a better shellcheck-compliant way to write the following line
+  # shellcheck disable=SC2010
   CSHARP_VERSION=$(ls TestNugetFeed | grep -m 1 '^Grpc\.Core\.[0-9].*\.nupkg$' | sed s/^Grpc\.Core\.// | sed s/\.nupkg$// | sed s/\.symbols$//)
   echo "Autodetected nuget ${CSHARP_VERSION}"
 fi
diff --git a/test/distrib/php/run_distrib_test.sh b/test/distrib/php/run_distrib_test.sh
index 70ebaf8..a6102f6 100755
--- a/test/distrib/php/run_distrib_test.sh
+++ b/test/distrib/php/run_distrib_test.sh
@@ -15,11 +15,11 @@
 
 set -ex
 
-cd $(dirname $0)
+cd "$(dirname "$0")"
 
-cp -r $EXTERNAL_GIT_ROOT/input_artifacts/grpc-*.tgz .
+cp -r "$EXTERNAL_GIT_ROOT"/input_artifacts/grpc-*.tgz .
 
-find . -regextype sed -regex ".*/grpc-[0-9].*.tgz" | cut -b3- | \
+find . -regex ".*/grpc-[0-9].*.tgz" | cut -b3- | \
     xargs pecl install
 
 php -d extension=grpc.so -d max_execution_time=300 distribtest.php
diff --git a/tools/dockerfile/distribtest/node_ubuntu1504_x64/Dockerfile b/test/distrib/php/run_distrib_test_macos.sh
old mode 100644
new mode 100755
similarity index 65%
copy from tools/dockerfile/distribtest/node_ubuntu1504_x64/Dockerfile
copy to test/distrib/php/run_distrib_test_macos.sh
index 399a43a..8def049
--- a/tools/dockerfile/distribtest/node_ubuntu1504_x64/Dockerfile
+++ b/test/distrib/php/run_distrib_test_macos.sh
@@ -1,4 +1,5 @@
-# Copyright 2016 gRPC authors.
+#!/bin/bash
+# Copyright 2018 gRPC authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -12,10 +13,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM ubuntu:15.04
+set -ex
 
-RUN apt-get update && apt-get install -y curl
+cd "$(dirname "$0")"
 
-# Install nvm
-RUN touch .profile
-RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash
\ No newline at end of file
+cp -r "$EXTERNAL_GIT_ROOT"/input_artifacts/grpc-*.tgz .
+
+find . -regex ".*/grpc-[0-9].*.tgz" | cut -b3- | \
+    xargs sudo pecl install
+
+php -d extension=grpc.so -d max_execution_time=300 distribtest.php
diff --git a/test/distrib/python/run_distrib_test.sh b/test/distrib/python/run_distrib_test.sh
index 02654be..a855ae3 100755
--- a/test/distrib/python/run_distrib_test.sh
+++ b/test/distrib/python/run_distrib_test.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 # Copyright 2015 gRPC authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,23 +15,25 @@
 
 set -ex
 
-cd $(dirname $0)
+cd "$(dirname "$0")"
+
+shopt -s nullglob
 
 # Pick up the source dist archive whatever its version is
-SDIST_ARCHIVES=$EXTERNAL_GIT_ROOT/input_artifacts/grpcio-*.tar.gz
-BDIST_ARCHIVES=$EXTERNAL_GIT_ROOT/input_artifacts/grpcio-*.whl
-TOOLS_SDIST_ARCHIVES=$EXTERNAL_GIT_ROOT/input_artifacts/grpcio_tools-*.tar.gz
-TOOLS_BDIST_ARCHIVES=$EXTERNAL_GIT_ROOT/input_artifacts/grpcio_tools-*.whl
+SDIST_ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio-*.tar.gz)
+BDIST_ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio-*.whl)
+TOOLS_SDIST_ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio_tools-*.tar.gz)
+TOOLS_BDIST_ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio_tools-*.whl)
 
 function make_virtualenv() {
-  virtualenv $1
-  $1/bin/python -m pip install --upgrade six pip
-  $1/bin/python -m pip install cython
+  virtualenv "$1"
+  "$1/bin/python" -m pip install --upgrade six pip
+  "$1/bin/python" -m pip install cython
 }
 
 function at_least_one_installs() {
   for file in "$@"; do
-    if python -m pip install $file; then
+    if python -m pip install "$file"; then
       return 0
     fi
   done
@@ -45,11 +47,11 @@
 # Install our distributions in order of dependencies
 #
 
-(source bdist_test/bin/activate && at_least_one_installs ${BDIST_ARCHIVES})
-(source bdist_test/bin/activate && at_least_one_installs ${TOOLS_BDIST_ARCHIVES})
+(source bdist_test/bin/activate && at_least_one_installs "${BDIST_ARCHIVES[@]}")
+(source bdist_test/bin/activate && at_least_one_installs "${TOOLS_BDIST_ARCHIVES[@]}")
 
-(source sdist_test/bin/activate && at_least_one_installs ${SDIST_ARCHIVES})
-(source sdist_test/bin/activate && at_least_one_installs ${TOOLS_SDIST_ARCHIVES})
+(source sdist_test/bin/activate && at_least_one_installs "${SDIST_ARCHIVES[@]}")
+(source sdist_test/bin/activate && at_least_one_installs "${TOOLS_SDIST_ARCHIVES[@]}")
 
 #
 # Test our distributions
diff --git a/test/distrib/ruby/run_distrib_test.sh b/test/distrib/ruby/run_distrib_test.sh
index d74f4cd..cb2eb1f 100755
--- a/test/distrib/ruby/run_distrib_test.sh
+++ b/test/distrib/ruby/run_distrib_test.sh
@@ -15,21 +15,44 @@
 
 set -ex
 
-cd $(dirname $0)
+cd "$(dirname "$0")"
 
 ARCH=$1
 PLATFORM=$2
 # Create an indexed local gem source with gRPC gems to test
 GEM_SOURCE=../../../gem_source
-mkdir -p ${GEM_SOURCE}/gems
-cp $EXTERNAL_GIT_ROOT/input_artifacts/grpc-*$ARCH-$PLATFORM.gem ${GEM_SOURCE}/gems
-if [[ "$(ls ${GEM_SOURCE}/gems | grep grpc | wc -l)" != 1 ]]; then
+mkdir -p "${GEM_SOURCE}/gems"
+cp "$EXTERNAL_GIT_ROOT"/input_artifacts/grpc-*"$ARCH-$PLATFORM".gem "${GEM_SOURCE}/gems"
+# TODO: rewrite the following line to be shellcheck-compliant
+# shellcheck disable=SC2010
+if [[ "$(ls "${GEM_SOURCE}/gems" | grep -c grpc)" != 1 ]]; then
   echo "Sanity check failed. Copied over more than one grpc gem into the gem source directory."
   exit 1
 fi;
 gem install builder
-gem generate_index --directory ${GEM_SOURCE}
+gem generate_index --directory "${GEM_SOURCE}"
 
 bundle install
 
 bundle exec ./distribtest.rb
+
+# Attempt to repro https://github.com/google/protobuf/issues/4210.
+# TODO: This sanity check only works for linux-based distrib tests and for
+# binary gRPC packages. It will need to be ran conditionally if this test script is
+# used for other types of distrib tests.
+INSTALLATION_DIR="$(gem env | grep '\- INSTALLATION DIRECTORY' | awk '{ print $4 }')"
+if [[ "$(find "$INSTALLATION_DIR" -name 'grpc_c.so' | wc -l)" == 0 ]]; then
+  echo "Sanity check failed. The gRPC package is not installed in $INSTALLATION_DIR."
+  exit 1
+fi
+LIBRUBY_DEPENDENCY_EXISTS="$(find "$INSTALLATION_DIR" -name 'grpc_c.so' -exec ldd {} \; | grep -c 'libruby')" || true
+if [[ "$LIBRUBY_DEPENDENCY_EXISTS" != 0 ]]; then
+  echo "A grpc_c.so file in this binary gRPC package is dynamically linked to libruby."
+fi
+DEPENDENCY_NOT_FOUND="$(find "$INSTALLATION_DIR" -name 'grpc_c.so' -exec ldd {} \; | grep -c 'not found')" || true
+if [[ "$DEPENDENCY_NOT_FOUND" != 0 ]]; then
+  echo "A grpc_c.so file in this binary gRPC package has an non-portable dependency."
+fi
+if [ "$LIBRUBY_DEPENDENCY_EXISTS" != 0 ] || [ "$DEPENDENCY_NOT_FOUND" != 0 ]; then
+  exit 1
+fi
diff --git a/third_party/BUILD b/third_party/BUILD
index dea1229..f06c5e9 100644
--- a/third_party/BUILD
+++ b/third_party/BUILD
@@ -3,4 +3,9 @@
     "gtest.BUILD",
     "objective_c/Cronet/bidirectional_stream_c.h",
     "zlib.BUILD",
+    "twisted.BUILD",
+    "yaml.BUILD",
+    "incremental.BUILD",
+    "zope_interface.BUILD",
+    "constantly.BUILD",
 ])
diff --git a/third_party/address_sorting/BUILD b/third_party/address_sorting/BUILD
new file mode 100644
index 0000000..7d5fb9d
--- /dev/null
+++ b/third_party/address_sorting/BUILD
@@ -0,0 +1,60 @@
+#	$NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $	*/
+#	$KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $	*/
+#
+# Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. 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.
+# 3. Neither the name of the project nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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.
+
+package(
+    default_visibility = ["//visibility:public"],
+    features = [
+        "-layering_check",
+        "-parse_headers",
+    ],
+)
+
+load(":address_sorting.bzl", "address_sorting_cc_library")
+
+licenses(["notice"])  # BSD
+
+exports_files(["LICENSE"])
+
+address_sorting_cc_library(
+    name = "address_sorting",
+    srcs = [
+        "address_sorting.c",
+        "address_sorting_posix.c",
+        "address_sorting_windows.c",
+    ],
+    hdrs = [
+        "include/address_sorting/address_sorting.h",
+        "address_sorting_internal.h",
+    ],
+    copts = ["-std=c99"],
+    includes = [
+        "include",
+    ],
+)
diff --git a/third_party/address_sorting/LICENSE b/third_party/address_sorting/LICENSE
new file mode 100644
index 0000000..db4b5a5
--- /dev/null
+++ b/third_party/address_sorting/LICENSE
@@ -0,0 +1,6101 @@
+   Copyright (c) 2014, ARM Limited
+   All rights Reserved.
+   Copyright (c) 2014, Linaro Ltd.
+
+   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 company nor the names of its contributors
+         may be used to endorse or promote products derived from this
+         software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+   Copyright (c) 2014, Linaro Limited
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+       * Redistributions of source code must retain the above copyright
+         notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above copyright
+         notice, this list of conditions and the following disclaimer in the
+         documentation and/or other materials provided with the distribution.
+       * Neither the name of the Linaro nor the
+         names of its contributors may be used to endorse or promote products
+         derived from this software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+ Copyright (c) 1993 John Brezak
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. 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.
+ 3. The name of the author may be used to endorse or promote products
+    derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR `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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+ Copyright (c) 2009-2013 The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+     * Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+     * Neither the name of The Linux 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 COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+====================================================
+Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+
+Developed at SunPro, a Sun Microsystems, Inc. business.
+Permission to use, copy, modify, and distribute this
+software is freely granted, provided that this notice
+is preserved.
+
+-------------------------------------------------------------------
+
+====================================================
+Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+
+Developed at SunPro, a Sun Microsystems, Inc. business.
+Permission to use, copy, modify, and distribute this
+software is freely granted, provided that this notice
+is preserved.
+====================================================
+
+Optimized by Bruce D. Evans.
+
+-------------------------------------------------------------------
+
+====================================================
+Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+
+Developed at SunSoft, a Sun Microsystems, Inc. business.
+Permission to use, copy, modify, and distribute this
+software is freely granted, provided that this notice
+is preserved.
+
+-------------------------------------------------------------------
+
+====================================================
+Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+
+Developed at SunSoft, a Sun Microsystems, Inc. business.
+Permission to use, copy, modify, and distribute this
+software is freely granted, provided that this notice
+is preserved.
+====================================================
+
+Optimized by Bruce D. Evans.
+
+-------------------------------------------------------------------
+
+====================================================
+Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans.
+
+Developed at SunSoft, a Sun Microsystems, Inc. business.
+Permission to use, copy, modify, and distribute this
+software is freely granted, provided that this notice
+is preserved.
+
+-------------------------------------------------------------------
+
+====================================================
+Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans.
+
+Developed at SunSoft, a Sun Microsystems, Inc. business.
+Permission to use, copy, modify, and distribute this
+software is freely granted, provided that this notice
+is preserved.
+====================================================
+
+Optimized by Bruce D. Evans.
+
+-------------------------------------------------------------------
+
+====================================================
+Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+Copyright (c) 2009-2011, Bruce D. Evans, Steven G. Kargl, David Schultz.
+
+Developed at SunPro, a Sun Microsystems, Inc. business.
+Permission to use, copy, modify, and distribute this
+software is freely granted, provided that this notice
+is preserved.
+====================================================
+
+The argument reduction and testing for exceptional cases was
+written by Steven G. Kargl with input from Bruce D. Evans
+and David A. Schultz.
+
+-------------------------------------------------------------------
+
+====================================================
+Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+
+Permission to use, copy, modify, and distribute this
+software is freely granted, provided that this notice
+is preserved.
+
+-------------------------------------------------------------------
+
+====================================================
+Copyright 2004 Sun Microsystems, Inc.  All Rights Reserved.
+
+Permission to use, copy, modify, and distribute this
+software is freely granted, provided that this notice
+is preserved.
+
+-------------------------------------------------------------------
+
+====================================================
+Copyright 2004 Sun Microsystems, Inc.  All Rights Reserved.
+Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans.
+
+Permission to use, copy, modify, and distribute this
+software is freely granted, provided that this notice
+is preserved.
+
+-------------------------------------------------------------------
+
+Based on the UCB version with the ID appearing below.
+This is ANSIish only when "multibyte character == plain character".
+
+Copyright (c) 1989, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the project nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2004, 2005, 2008  Internet Systems Consortium, Inc. ("ISC")
+Copyright (C) 1995-1999, 2001, 2003  Internet Software Consortium.
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2004, 2005, 2008  Internet Systems Consortium, Inc. ("ISC")
+Copyright (C) 1997-2001  Internet Software Consortium.
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2006 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2006 The Android Open Source Project
+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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2007 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2007 The Android Open Source Project
+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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2008 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2008 The Android Open Source Project
+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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2008 The Android Open Source Project
+All rights reserved.
+Copyright (c) 2013-2014, NVIDIA Corporation.  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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2009 The Android Open Source Project
+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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2010 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2010 The Android Open Source Project
+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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2010 The Android Open Source Project
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2010 The Android Open Source Project
+Copyright (c) 2008 ARM Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. The name of the company may not be used to endorse or promote
+   products derived from this software without specific prior written
+   permission.
+
+THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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.
+
+Android adaptation and tweak by Jim Huang <jserv@0xlab.org>.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2011 The Android Open Source Project
+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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2012 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2012 The Android Open Source Project
+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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2013 The Android Open Source Project
+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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2013 The Android Open Source Project
+All rights reserved.
+Copyright (c) 2013-2014 NVIDIA Corporation.  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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2013 The Android Open Source Project
+Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2014 The Android Open Source Project
+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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2014 The Android Open Source Project
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2015 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2015 The Android Open Source Project
+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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2016 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2016 The Android Open Source Project
+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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2017 The Android Open Source Project
+All rights reserved.
+
+Copyright (c) 2009-2011, Code Aurora Forum. 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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2017 The Android Open Source Project
+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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1980, 1983, 1988, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+   This product includes software developed by the University of
+   California, Berkeley and its contributors.
+4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+
+Portions Copyright (c) 1993 by Digital Equipment Corporation.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies, and that
+the name of Digital Equipment Corporation not be used in advertising or
+publicity pertaining to distribution of the document or software without
+specific, written prior permission.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
+CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1982, 1986, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1982, 1986, 1993
+   The Regents of the University of California.  All rights reserved.
+(c) UNIX System Laboratories, Inc.
+All or some portions of this file are derived from material licensed
+to the University of California by American Telephone and Telegraph
+Co. or Unix System Laboratories, Inc. and are reproduced herein with
+the permission of UNIX System Laboratories, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1983, 1987, 1989
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1983, 1989
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+    This product includes software developed by the University of
+    California, Berkeley and its contributors.
+4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1983, 1989, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1983, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1985
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+    This product includes software developed by the University of
+    California, Berkeley and its contributors.
+4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1985 Regents of the University of California.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1985, 1988, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+Portions Copyright (c) 1993 by Digital Equipment Corporation.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies, and that
+the name of Digital Equipment Corporation not be used in advertising or
+publicity pertaining to distribution of the document or software without
+specific, written prior permission.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
+CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1985, 1989, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+    This product includes software developed by the University of
+    California, Berkeley and its contributors.
+4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1985, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+    This product includes software developed by the University of
+    California, Berkeley and its contributors.
+4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1985, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+   This product includes software developed by the University of
+   California, Berkeley and its contributors.
+4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1985, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1987 Regents of the University of California.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1987, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+    This product includes software developed by the University of
+    California, Berkeley and its contributors.
+4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1987, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1988 Regents of the University of California.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1988 The Regents of the University of California.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1988, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+    This product includes software developed by the University of
+    California, Berkeley and its contributors.
+4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1988, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+   This product includes software developed by the University of
+   California, Berkeley and its contributors.
+4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1988, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1988, 1993
+   The Regents of the University of California.  All rights reserved.
+
+This code is derived from software written by Ken Arnold and
+published in UNIX Review, Vol. 6, No. 8.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1989 The Regents of the University of California.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1989 The Regents of the University of California.
+All rights reserved.
+(c) UNIX System Laboratories, Inc.
+All or some portions of this file are derived from material licensed
+to the University of California by American Telephone and Telegraph
+Co. or Unix System Laboratories, Inc. and are reproduced herein with
+the permission of UNIX System Laboratories, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1989, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1989, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1989, 1993
+   The Regents of the University of California.  All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Guido van Rossum.
+
+Copyright (c) 2011 The FreeBSD Foundation
+All rights reserved.
+Portions of this software were developed by David Chisnall
+under sponsorship from the FreeBSD Foundation.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1989, 1993
+   The Regents of the University of California.  All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Guido van Rossum.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1989, 1993
+   The Regents of the University of California.  All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Roger L. Snyder.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1989, 1993
+   The Regents of the University of California.  All rights reserved.
+(c) UNIX System Laboratories, Inc.
+All or some portions of this file are derived from material licensed
+to the University of California by American Telephone and Telegraph
+Co. or Unix System Laboratories, Inc. and are reproduced herein with
+the permission of UNIX System Laboratories, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1990 Regents of the University of California.
+All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Chris Torek.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1990 The Regents of the University of California.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1990 The Regents of the University of California.
+All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Chris Torek.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1990 The Regents of the University of California.
+All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+William Jolitz.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1990, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1990, 1993
+   The Regents of the University of California.  All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Chris Torek.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1990, 1993
+   The Regents of the University of California.  All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Donn Seeley at UUNET Technologies, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1990, 1993
+   The Regents of the University of California.  All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Donn Seeley at UUNET Technologies, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1990, 1993
+   The Regents of the University of California.  All rights reserved.
+(c) UNIX System Laboratories, Inc.
+All or some portions of this file are derived from material licensed
+to the University of California by American Telephone and Telegraph
+Co. or Unix System Laboratories, Inc. and are reproduced herein with
+the permission of UNIX System Laboratories, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1990, 1993, 1994
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1990, 1993, 1994
+   The Regents of the University of California.  All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Chris Torek.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1991 The Regents of the University of California.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1991, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1991, 1993
+   The Regents of the University of California.  All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Berkeley Software Design, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1991, 1993
+   The Regents of the University of California.  All rights reserved.
+(c) UNIX System Laboratories, Inc.
+All or some portions of this file are derived from material licensed
+to the University of California by American Telephone and Telegraph
+Co. or Unix System Laboratories, Inc. and are reproduced herein with
+the permission of UNIX System Laboratories, Inc.
+
+This code is derived from software contributed to Berkeley by
+Hugh Smith at The University of Guelph.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1991, 1993, 1995,
+   The Regents of the University of California.  All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Havard Eidnes.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1992 Henry Spencer.
+Copyright (c) 1992, 1993
+   The Regents of the University of California.  All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Henry Spencer of the University of Toronto.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1992 The Regents of the University of California.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1992, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+   This product includes software developed by the University of
+   California, Berkeley and its contributors.
+4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1992, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1992, 1993
+   The Regents of the University of California.  All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Ralph Campbell.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1992, 1993
+   The Regents of the University of California.  All rights reserved.
+
+This software was developed by the Computer Systems Engineering group
+at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+contributed to Berkeley.
+
+All advertising materials mentioning features or use of this software
+must display the following acknowledgement:
+   This product includes software developed by the University of
+   California, Lawrence Berkeley Laboratory.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+   This product includes software developed by the University of
+   California, Berkeley and its contributors.
+4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1992, 1993
+   The Regents of the University of California.  All rights reserved.
+(c) UNIX System Laboratories, Inc.
+All or some portions of this file are derived from material licensed
+to the University of California by American Telephone and Telegraph
+Co. or Unix System Laboratories, Inc. and are reproduced herein with
+the permission of UNIX System Laboratories, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1992, 1993, 1994
+   The Regents of the University of California.  All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Henry Spencer.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1992, 1993, 1994 Henry Spencer.
+
+This code is derived from software contributed to Berkeley by
+Henry Spencer.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+   This product includes software developed by the University of
+   California, Berkeley and its contributors.
+4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1993 Martin Birgmeier
+All rights reserved.
+
+You may redistribute unmodified or modified versions of this source
+code provided that the above copyright notice and this and the
+following conditions are retained.
+
+This software is provided ``as is'', and comes with no warranties
+of any kind. I shall in no event be liable for anything that happens
+to anyone/anything when using this software.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1994 SigmaSoft, Th. Lockert <tholo@sigmasoft.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1996 by Internet Software Consortium.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1996, David Mazieres <dm@uun.org>
+Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1996, David Mazieres <dm@uun.org>
+Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
+Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1996-1998, 2008 Theo de Raadt
+Copyright (c) 1997, 2008-2009 Todd C. Miller
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1997 Mark Brinicombe
+Copyright (C) 2010 The Android Open Source Project
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+   This product includes software developed by Mark Brinicombe
+4. Neither the name of the University 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1997 Niklas Hallqvist.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR ``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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
+All rights reserved.
+
+This code was contributed to The NetBSD Foundation by Klaus Klein.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+       This product includes software developed by the NetBSD
+       Foundation, Inc. and its contributors.
+4. Neither the name of The NetBSD 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 NETBSD FOUNDATION, INC. 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1997, 1998, 1999, 2004 The NetBSD Foundation, Inc.
+All rights reserved.
+
+This code is derived from software contributed to The NetBSD Foundation
+by Luke Mewburn.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 NETBSD FOUNDATION, INC. 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1997, 1998, 1999, 2004 The NetBSD Foundation, Inc.
+All rights reserved.
+
+This code is derived from software contributed to The NetBSD Foundation
+by Luke Mewburn; and by Jason R. Thorpe.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+       This product includes software developed by the NetBSD
+       Foundation, Inc. and its contributors.
+4. Neither the name of The NetBSD 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 NETBSD FOUNDATION, INC. 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1997, 2005 Todd C. Miller <Todd.Miller@courtesan.com>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1998 Softweyr LLC.  All rights reserved.
+
+strtok_r, from Berkeley strtok
+Oct 13, 1998 by Wes Peters <wes@softweyr.com>
+
+Copyright (c) 1988, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notices, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notices, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the University 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 SOFTWEYR LLC, THE REGENTS 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 SOFTWEYR LLC, THE
+REGENTS, 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1998 The NetBSD Foundation, Inc.
+All rights reserved.
+
+This code is derived from software contributed to The NetBSD Foundation
+by Klaus Klein.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+       This product includes software developed by the NetBSD
+       Foundation, Inc. and its contributors.
+4. Neither the name of The NetBSD 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 NETBSD FOUNDATION, INC. 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1999
+   David E. O'Brien
+Copyright (c) 1988, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2000 Ben Harris.
+Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the project nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2000 The NetBSD Foundation, Inc.
+All rights reserved.
+
+This code is derived from software contributed to The NetBSD Foundation
+by Dieter Baron and Thomas Klausner.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 NETBSD FOUNDATION, INC. 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2001 Wasabi Systems, Inc.
+All rights reserved.
+
+Written by Frank van der Linden for Wasabi Systems, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+     This product includes software developed for the NetBSD Project by
+     Wasabi Systems, Inc.
+4. The name of Wasabi Systems, Inc. may not be used to endorse
+   or promote products derived from this software without specific prior
+   written permission.
+
+THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2001-2002 Opsycon AB  (www.opsycon.se / www.opsycon.com)
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR ``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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2001-2002 Opsycon AB  (www.opsycon.se / www.opsycon.com)
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of Opsycon AB 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 AUTHOR ``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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2001-2011 The FreeBSD Project.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2002 Daniel Hartmeier
+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 HOLDERS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2002 The NetBSD Foundation, Inc.
+All rights reserved.
+
+This code is derived from software contributed to The NetBSD Foundation
+by Christos Zoulas.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 NETBSD FOUNDATION, INC. 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2002 Tim J. Robbins
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2002 Tim J. Robbins.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Sponsored in part by the Defense Advanced Research Projects
+Agency (DARPA) and Air Force Research Laboratory, Air Force
+Materiel Command, USAF, under agreement number F39502-99-1-0512.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2002, 2003 Tim J. Robbins.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2002-2004 Tim J. Robbins
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2002-2004 Tim J. Robbins.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. The names of the authors may not be used to endorse or promote
+   products derived from this software without specific prior written
+   permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2003 Dag-Erling Smørgrav
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer
+   in this position and unchanged.
+2. 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.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org>
+Copyright (c) 2002 David Schultz <das@FreeBSD.ORG>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2003 Networks Associates Technology, Inc.
+All rights reserved.
+
+Portions of this software were developed for the FreeBSD Project by
+Jacques A. Vidrine, Safeport Network Services, and Network
+Associates Laboratories, the Security Research Division of Network
+Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+("CBOSS"), as part of the DARPA CHATS research program.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Sponsored in part by the Defense Advanced Research Projects
+Agency (DARPA) and Air Force Research Laboratory, Air Force
+Materiel Command, USAF, under agreement number F39502-99-1-0512.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2003, 2004 Todd C. Miller <Todd.Miller@courtesan.com>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Sponsored in part by the Defense Advanced Research Projects
+Agency (DARPA) and Air Force Research Laboratory, Air Force
+Materiel Command, USAF, under agreement number F39502-99-1-0512.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2003, Steven G. Kargl
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice unmodified, this list of conditions, and the following
+   disclaimer.
+2. 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 AUTHOR ``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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2004 Stefan Farfeleder
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+Copyright (c) 1995,1999 by Internet Software Consortium.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+Copyright (c) 1995-1999 by Internet Software Consortium
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+Copyright (c) 1995-1999 by Internet Software Consortium.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+Copyright (c) 1996,1999 by Internet Software Consortium.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+Copyright (c) 1996-1999 by Internet Software Consortium
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+Copyright (c) 1996-1999 by Internet Software Consortium.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+Copyright (c) 1997,1999 by Internet Software Consortium.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+Copyright (c) 1999 by Internet Software Consortium.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2004, 2005 David Schultz <das@FreeBSD.ORG>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2004-2005 David Schultz <das (at) FreeBSD.ORG>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice unmodified, this list of conditions, and the following
+   disclaimer.
+2. 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 AUTHOR ``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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2005 David Schultz <das@FreeBSD.ORG>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2005 Tim J. Robbins.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2005 by Internet Systems Consortium, Inc. ("ISC")
+Copyright (c) 1995-1999 by Internet Software Consortium
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2005-2008 David Schultz <das@FreeBSD.ORG>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2005-2011 David Schultz <das@FreeBSD.ORG>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2007 David Schultz
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2007 David Schultz <das@FreeBSD.ORG>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2007 David Schultz <das@FreeBSD.ORG>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+Derived from s_modf.c, which has the following Copyright:
+====================================================
+Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+
+Developed at SunPro, a Sun Microsystems, Inc. business.
+Permission to use, copy, modify, and distribute this
+software is freely granted, provided that this notice
+is preserved.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2007 Steven G. Kargl
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice unmodified, this list of conditions, and the following
+   disclaimer.
+2. 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 AUTHOR ``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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2007 The NetBSD Foundation, Inc.
+All rights reserved.
+
+This code is derived from software written by Stephen L. Moshier.
+It is redistributed by the NetBSD Foundation by permission of the author.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 NETBSD FOUNDATION, INC. 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2007 Todd C. Miller <Todd.Miller@courtesan.com>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2007-2008  Michael G Schwern
+
+This software originally derived from Paul Sheer's pivotal_gmtime_r.c.
+
+The MIT License:
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2007-2008  Michael G Schwern
+
+This software originally derived from Paul Sheer's pivotal_gmtime_r.c.
+
+The MIT License:
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+Origin: http://code.google.com/p/y2038
+Modified for Bionic by the Android Open Source Project
+
+-------------------------------------------------------------------
+
+Copyright (c) 2007-2008 David Schultz <das@FreeBSD.ORG>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2007-2013 Bruce D. Evans
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice unmodified, this list of conditions, and the following
+   disclaimer.
+2. 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 AUTHOR ``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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2008 David Schultz <das@FreeBSD.ORG>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2008 Todd C. Miller <millert@openbsd.org>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+All rights reserved.
+
+Copyright (c) 2011 The FreeBSD Foundation
+All rights reserved.
+Portions of this software were developed by David Chisnall
+under sponsorship from the FreeBSD Foundation.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2009 The NetBSD Foundation, Inc.
+
+This code is derived from software contributed to The NetBSD Foundation
+by Roy Marples.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR ``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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2009-2013 Steven G. Kargl
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice unmodified, this list of conditions, and the following
+   disclaimer.
+2. 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 AUTHOR ``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 AUTHOR 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.
+
+Optimized by Bruce D. Evans.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2010 The NetBSD Foundation, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 NETBSD FOUNDATION, INC. 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2010 Todd C. Miller <Todd.Miller@courtesan.com>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2010, 2011, 2012, 2013 Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+    * this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+    * this list of conditions and the following disclaimer in the documentation
+    * and/or other materials provided with the distribution.
+
+    * Neither the name of Intel Corporation nor the names of its contributors
+    * may be used to endorse or promote products derived from this software
+    * without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2010, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+    * this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+    * this list of conditions and the following disclaimer in the documentation
+    * and/or other materials provided with the distribution.
+
+    * Neither the name of Intel Corporation nor the names of its contributors
+    * may be used to endorse or promote products derived from this software
+    * without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2011 David Chisnall
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2011 David Schultz
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice unmodified, this list of conditions, and the following
+   disclaimer.
+2. 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 AUTHOR ``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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2011 David Schultz <das@FreeBSD.ORG>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2011 Ed Schouten <ed@FreeBSD.org>
+                   David Chisnall <theraven@FreeBSD.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2011 Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+    * this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+    * this list of conditions and the following disclaimer in the documentation
+    * and/or other materials provided with the distribution.
+
+    * Neither the name of Intel Corporation nor the names of its contributors
+    * may be used to endorse or promote products derived from this software
+    * without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2011 The Android Open Source Project
+Copyright (c) 2008 ARM Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. The name of the company may not be used to endorse or promote
+   products derived from this software without specific prior written
+   permission.
+
+THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2011, 2012, 2013 Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+    * this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+    * this list of conditions and the following disclaimer in the documentation
+    * and/or other materials provided with the distribution.
+
+    * Neither the name of Intel Corporation nor the names of its contributors
+    * may be used to endorse or promote products derived from this software
+    * without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2011, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+    * this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+    * this list of conditions and the following disclaimer in the documentation
+    * and/or other materials provided with the distribution.
+
+    * Neither the name of Intel Corporation nor the names of its contributors
+    * may be used to endorse or promote products derived from this software
+    * without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2011, VMware, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the VMware, Inc. 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 VMWARE, INC. 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2012 Stephen Montgomery-Smith <stephen@FreeBSD.ORG>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2012, Linaro Limited
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+       * Redistributions of source code must retain the above copyright
+         notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above copyright
+         notice, this list of conditions and the following disclaimer in the
+         documentation and/or other materials provided with the distribution.
+       * Neither the name of the Linaro nor the
+         names of its contributors may be used to endorse or promote products
+         derived from this software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2012, Linaro Limited
+   All rights reserved.
+   Copyright (c) 2014, NVIDIA Corporation.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+       * Redistributions of source code must retain the above copyright
+         notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above copyright
+         notice, this list of conditions and the following disclaimer in the
+         documentation and/or other materials provided with the distribution.
+       * Neither the name of the Linaro nor the
+         names of its contributors may be used to endorse or promote products
+         derived from this software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2012-2013, Linaro Limited
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+       * Redistributions of source code must retain the above copyright
+         notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above copyright
+         notice, this list of conditions and the following disclaimer in the
+         documentation and/or other materials provided with the distribution.
+       * Neither the name of the Linaro nor the
+         names of its contributors may be used to endorse or promote products
+         derived from this software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+
+-------------------------------------------------------------------
+
+Copyright (c) 2013
+     MIPS Technologies, Inc., California.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the MIPS Technologies, Inc., 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 MIPS TECHNOLOGIES, INC. ``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 MIPS TECHNOLOGIES, INC. 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2013 ARM Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. The name of the company may not be used to endorse or promote
+   products derived from this software without specific prior written
+   permission.
+
+THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2013 Antoine Jacoutot <ajacoutot@openbsd.org>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2013 The NetBSD Foundation, Inc.
+All rights reserved.
+
+This code is derived from software contributed to The NetBSD Foundation
+by Christos Zoulas.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 NETBSD FOUNDATION, INC. 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2013, Linaro Limited
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+       * Redistributions of source code must retain the above copyright
+         notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above copyright
+         notice, this list of conditions and the following disclaimer in the
+         documentation and/or other materials provided with the distribution.
+       * Neither the name of the Linaro nor the
+         names of its contributors may be used to endorse or promote products
+         derived from this software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+
+-------------------------------------------------------------------
+
+Copyright (c) 2013-2014, NVIDIA Corporation.  All rights reserved.
+Johnny Qiu <joqiu@nvidia.com>
+Shu Zhang <chazhang@nvidia.com>
+
+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 Linux 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2013-2015, Linaro Limited
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+       * Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+       * Neither the name of the Linaro nor the
+     names of its contributors may be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+
+-------------------------------------------------------------------
+
+Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org>
+Copyright (c) 2014 Bob Beck <beck@obtuse.com>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Emulation of getentropy(2) as documented at:
+http://man.openbsd.org/getentropy.2
+
+-------------------------------------------------------------------
+
+Copyright (c) 2014, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+    * this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+    * this list of conditions and the following disclaimer in the documentation
+    * and/or other materials provided with the distribution.
+
+    * Neither the name of Intel Corporation nor the names of its contributors
+    * may be used to endorse or promote products derived from this software
+    * without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2014, Linaro Limited
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+       * Redistributions of source code must retain the above copyright
+         notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above copyright
+         notice, this list of conditions and the following disclaimer in the
+         documentation and/or other materials provided with the distribution.
+       * Neither the name of the Linaro nor the
+         names of its contributors may be used to endorse or promote products
+         derived from this software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2015 ARM Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. The name of the company may not be used to endorse or promote
+   products derived from this software without specific prior written
+   permission.
+
+THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2015 Joerg Sonnenberger <joerg@NetBSD.org>.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 HOLDERS 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2015 Nuxi, https://nuxi.nl/
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2017 ARM Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. The name of the company may not be used to endorse or promote
+   products derived from this software without specific prior written
+   permission.
+
+THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2017 Imagination Technologies.
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+     * Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer
+       in the documentation and/or other materials provided with
+       the distribution.
+     * Neither the name of Imagination Technologies nor the names of its
+       contributors may be used to endorse or promote products derived
+       from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+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.
+
+-------------------------------------------------------------------
+
+Copyright (c)1999 Citrus Project,
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c)2001 Citrus Project,
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright (c)2003 Citrus Project,
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+Copyright 1989 The Regents of the University of California.
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   1. Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+   2. 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.
+   3. Neither the name of the University 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 REGENTS 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 REGENTS 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
+
+-------------------------------------------------------------------
+
+Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
+Copyright 2008 Damien Miller <djm@openbsd.org>
+All rights reserved.
+
+Theo de Raadt <deraadt@openbsd.org> came up with the idea of using
+such a mathematical system to generate more random (yet non-repeating)
+ids to solve the resolver/named problem.  But Niels designed the
+actual system based on the constraints.
+
+Later modified by Damien Miller to wrap the LCG output in a 15-bit
+permutation generator based on a Luby-Rackoff block cipher. This
+ensures the output is non-repeating and preserves the MSB twiddle
+trick, but makes it more resistant to LCG prediction.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR ``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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
+From: @(#)s_ilogb.c 5.1 93/09/24
+====================================================
+Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+
+Developed at SunPro, a Sun Microsystems, Inc. business.
+Permission to use, copy, modify, and distribute this
+software is freely granted, provided that this notice
+is preserved.
+
+-------------------------------------------------------------------
+
+Portions Copyright (C) 2004, 2005, 2008, 2009  Internet Systems Consortium, Inc. ("ISC")
+Portions Copyright (C) 1996-2003  Internet Software Consortium.
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+Portions Copyright (c) 1993 by Digital Equipment Corporation.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies, and that
+the name of Digital Equipment Corporation not be used in advertising or
+publicity pertaining to distribution of the document or software without
+specific, written prior permission.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
+CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+-------------------------------------------------------------------
+
+Portions Copyright (c) 1995 by International Business Machines, Inc.
+
+International Business Machines, Inc. (hereinafter called IBM) grants
+permission under its copyrights to use, copy, modify, and distribute this
+Software with or without fee, provided that the above copyright notice and
+all paragraphs of this notice appear in all copies, and that the name of IBM
+not be used in connection with the marketing of any product incorporating
+the Software or modifications thereof, without specific, written prior
+permission.
+
+To the extent it has a right to do so, IBM grants an immunity from suit
+under its patents, if any, for the use, sale or manufacture of products to
+the extent that such products are used for performing Domain Name System
+dynamic updates in TCP/IP networks by means of the Software.  No immunity is
+granted for any product per se or for any other function of any product.
+
+THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+-------------------------------------------------------------------
+
+Portions Copyright(C) 1995, Jason Downs.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR(S) ``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 AUTHOR(S) 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.
+
+-------------------------------------------------------------------
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 2000 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998-2000 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998-2001 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
+The author of this software is David M. Gay.
+
+Copyright (C) 2000 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
diff --git a/third_party/address_sorting/address_sorting.bzl b/third_party/address_sorting/address_sorting.bzl
new file mode 100644
index 0000000..25d0084
--- /dev/null
+++ b/third_party/address_sorting/address_sorting.bzl
@@ -0,0 +1,38 @@
+#	$NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $	*/
+#	$KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $	*/
+#
+# Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. 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.
+# 3. Neither the name of the project nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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.
+
+def address_sorting_cc_library(name, srcs, hdrs, copts, includes):
+  native.cc_library(
+      name = name,
+      srcs = srcs,
+      hdrs = hdrs,
+      copts = copts,
+      includes = includes,
+  )
diff --git a/third_party/address_sorting/address_sorting.c b/third_party/address_sorting/address_sorting.c
new file mode 100644
index 0000000..ec46099
--- /dev/null
+++ b/third_party/address_sorting/address_sorting.c
@@ -0,0 +1,369 @@
+/*	$NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $	*/
+/*	$KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $	*/
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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.
+ *
+ */
+
+/*
+ * This is an adaptation of Android's implementation of RFC 6724
+ * (in Android's getaddrinfo.c). It has some cosmetic differences
+ * from Android's getaddrinfo.c, but Android's getaddrinfo.c was
+ * used as a guide or example of a way to implement the RFC 6724 spec when
+ * this was written.
+ */
+
+#include "address_sorting_internal.h"
+
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+// Scope values increase with increase in scope.
+static const int kIPv6AddrScopeLinkLocal = 1;
+static const int kIPv6AddrScopeSiteLocal = 2;
+static const int kIPv6AddrScopeGlobal = 3;
+
+static address_sorting_source_addr_factory* g_current_source_addr_factory =
+    NULL;
+
+static int address_sorting_get_source_addr(const address_sorting_address* dest,
+                                           address_sorting_address* source) {
+  return g_current_source_addr_factory->vtable->get_source_addr(
+      g_current_source_addr_factory, dest, source);
+}
+
+static int ipv6_prefix_match_length(const struct sockaddr_in6* sa,
+                                    const struct sockaddr_in6* sb) {
+  unsigned char* a = (unsigned char*)&sa->sin6_addr;
+  unsigned char* b = (unsigned char*)&sb->sin6_addr;
+  int cur_bit = 0;
+  while (cur_bit < 128) {
+    int high_bit = 1 << (CHAR_BIT - 1);
+    int a_val = a[cur_bit / CHAR_BIT] & (high_bit >> (cur_bit % CHAR_BIT));
+    int b_val = b[cur_bit / CHAR_BIT] & (high_bit >> (cur_bit % CHAR_BIT));
+    if (a_val == b_val) {
+      cur_bit++;
+    } else {
+      break;
+    }
+  }
+  return cur_bit;
+}
+
+static int in6_is_addr_loopback(const struct in6_addr* ipv6_address) {
+  uint32_t* bits32 = (uint32_t*)ipv6_address;
+  return bits32[0] == 0 && bits32[1] == 0 && bits32[2] == 0 &&
+         bits32[3] == htonl(1);
+}
+
+static int in6_is_addr_v4mapped(const struct in6_addr* ipv6_address) {
+  uint32_t* bits32 = (uint32_t*)ipv6_address;
+  return bits32[0] == 0 && bits32[1] == 0 && bits32[2] == htonl(0x0000ffff);
+}
+
+static int in6_is_addr_v4compat(const struct in6_addr* ipv6_address) {
+  uint32_t* bits32 = (uint32_t*)ipv6_address;
+  return bits32[0] == 0 && bits32[1] == 0 && bits32[2] == 0 && bits32[3] != 0 &&
+         bits32[3] != htonl(1);
+}
+
+static int in6_is_addr_sitelocal(const struct in6_addr* ipv6_address) {
+  uint8_t* bytes = (uint8_t*)ipv6_address;
+  return bytes[0] == 0xfe && (bytes[1] & 0xc0) == 0xc0;
+}
+
+static int in6_is_addr_linklocal(const struct in6_addr* ipv6_address) {
+  uint8_t* bytes = (uint8_t*)ipv6_address;
+  return bytes[0] == 0xfe && (bytes[1] & 0xc0) == 0x80;
+}
+
+static int in6_is_addr_6to4(const struct in6_addr* ipv6_address) {
+  uint8_t* bytes = (uint8_t*)ipv6_address;
+  return bytes[0] == 0x20 && bytes[1] == 0x02;
+}
+
+static int in6_is_addr_ula(const struct in6_addr* ipv6_address) {
+  uint8_t* bytes = (uint8_t*)ipv6_address;
+  return (bytes[0] & 0xfe) == 0xfc;
+}
+
+static int in6_is_addr_teredo(const struct in6_addr* ipv6_address) {
+  uint8_t* bytes = (uint8_t*)ipv6_address;
+  return bytes[0] == 0x20 && bytes[1] == 0x01 && bytes[2] == 0x00 &&
+         bytes[3] == 0x00;
+}
+
+static int in6_is_addr_6bone(const struct in6_addr* ipv6_address) {
+  uint8_t* bytes = (uint8_t*)ipv6_address;
+  return bytes[0] == 0x3f && bytes[1] == 0xfe;
+}
+
+address_sorting_family address_sorting_abstract_get_family(
+    const address_sorting_address* address) {
+  switch (((struct sockaddr*)address)->sa_family) {
+    case AF_INET:
+      return ADDRESS_SORTING_AF_INET;
+    case AF_INET6:
+      return ADDRESS_SORTING_AF_INET6;
+    default:
+      return ADDRESS_SORTING_UNKNOWN_FAMILY;
+  }
+}
+
+static int get_label_value(const address_sorting_address* resolved_addr) {
+  if (address_sorting_abstract_get_family(resolved_addr) ==
+      ADDRESS_SORTING_AF_INET) {
+    return 4;
+  } else if (address_sorting_abstract_get_family(resolved_addr) !=
+             ADDRESS_SORTING_AF_INET6) {
+    return 1;
+  }
+  struct sockaddr_in6* ipv6_addr = (struct sockaddr_in6*)&resolved_addr->addr;
+  if (in6_is_addr_loopback(&ipv6_addr->sin6_addr)) {
+    return 0;
+  } else if (in6_is_addr_v4mapped(&ipv6_addr->sin6_addr)) {
+    return 4;
+  } else if (in6_is_addr_6to4(&ipv6_addr->sin6_addr)) {
+    return 2;
+  } else if (in6_is_addr_teredo(&ipv6_addr->sin6_addr)) {
+    return 5;
+  } else if (in6_is_addr_ula(&ipv6_addr->sin6_addr)) {
+    return 13;
+  } else if (in6_is_addr_v4compat(&ipv6_addr->sin6_addr)) {
+    return 3;
+  } else if (in6_is_addr_sitelocal(&ipv6_addr->sin6_addr)) {
+    return 11;
+  } else if (in6_is_addr_6bone(&ipv6_addr->sin6_addr)) {
+    return 12;
+  }
+  return 1;
+}
+
+static int get_precedence_value(const address_sorting_address* resolved_addr) {
+  if (address_sorting_abstract_get_family(resolved_addr) ==
+      ADDRESS_SORTING_AF_INET) {
+    return 35;
+  } else if (address_sorting_abstract_get_family(resolved_addr) !=
+             ADDRESS_SORTING_AF_INET6) {
+    return 1;
+  }
+  struct sockaddr_in6* ipv6_addr = (struct sockaddr_in6*)&resolved_addr->addr;
+  if (in6_is_addr_loopback(&ipv6_addr->sin6_addr)) {
+    return 50;
+  } else if (in6_is_addr_v4mapped(&ipv6_addr->sin6_addr)) {
+    return 35;
+  } else if (in6_is_addr_6to4(&ipv6_addr->sin6_addr)) {
+    return 30;
+  } else if (in6_is_addr_teredo(&ipv6_addr->sin6_addr)) {
+    return 5;
+  } else if (in6_is_addr_ula(&ipv6_addr->sin6_addr)) {
+    return 3;
+  } else if (in6_is_addr_v4compat(&ipv6_addr->sin6_addr) ||
+             in6_is_addr_sitelocal(&ipv6_addr->sin6_addr) ||
+             in6_is_addr_6bone(&ipv6_addr->sin6_addr)) {
+    return 1;
+  }
+  return 40;
+}
+
+static int sockaddr_get_scope(const address_sorting_address* resolved_addr) {
+  if (address_sorting_abstract_get_family(resolved_addr) ==
+      ADDRESS_SORTING_AF_INET) {
+    return kIPv6AddrScopeGlobal;
+  } else if (address_sorting_abstract_get_family(resolved_addr) ==
+             ADDRESS_SORTING_AF_INET6) {
+    struct sockaddr_in6* ipv6_addr = (struct sockaddr_in6*)&resolved_addr->addr;
+    if (in6_is_addr_loopback(&ipv6_addr->sin6_addr) ||
+        in6_is_addr_linklocal(&ipv6_addr->sin6_addr)) {
+      return kIPv6AddrScopeLinkLocal;
+    }
+    if (in6_is_addr_sitelocal(&ipv6_addr->sin6_addr)) {
+      return kIPv6AddrScopeSiteLocal;
+    }
+    return kIPv6AddrScopeGlobal;
+  }
+  return 0;
+}
+
+static int compare_source_addr_exists(const address_sorting_sortable* first,
+                                      const address_sorting_sortable* second) {
+  if (first->source_addr_exists != second->source_addr_exists) {
+    return first->source_addr_exists ? -1 : 1;
+  }
+  return 0;
+}
+
+static int compare_source_dest_scope_matches(
+    const address_sorting_sortable* first,
+    const address_sorting_sortable* second) {
+  int first_src_dst_scope_matches = 0;
+  if (sockaddr_get_scope(&first->dest_addr) ==
+      sockaddr_get_scope(&first->source_addr)) {
+    first_src_dst_scope_matches = 1;
+  }
+  int second_src_dst_scope_matches = 0;
+  if (sockaddr_get_scope(&second->dest_addr) ==
+      sockaddr_get_scope(&second->source_addr)) {
+    second_src_dst_scope_matches = 1;
+  }
+  if (first_src_dst_scope_matches != second_src_dst_scope_matches) {
+    return first_src_dst_scope_matches ? -1 : 1;
+  }
+  return 0;
+}
+
+static int compare_source_dest_labels_match(
+    const address_sorting_sortable* first,
+    const address_sorting_sortable* second) {
+  int first_label_matches = 0;
+  if (get_label_value(&first->dest_addr) ==
+      get_label_value(&first->source_addr)) {
+    first_label_matches = 1;
+  }
+  int second_label_matches = 0;
+  if (get_label_value(&second->dest_addr) ==
+      get_label_value(&second->source_addr)) {
+    second_label_matches = 1;
+  }
+  if (first_label_matches != second_label_matches) {
+    return first_label_matches ? 1 : 1;
+  }
+  return 0;
+}
+
+static int compare_dest_precedence(const address_sorting_sortable* first,
+                                   const address_sorting_sortable* second) {
+  return get_precedence_value(&second->dest_addr) -
+         get_precedence_value(&first->dest_addr);
+}
+
+static int compare_dest_scope(const address_sorting_sortable* first,
+                              const address_sorting_sortable* second) {
+  return sockaddr_get_scope(&first->dest_addr) -
+         sockaddr_get_scope(&second->dest_addr);
+}
+
+static int compare_source_dest_prefix_match_lengths(
+    const address_sorting_sortable* first,
+    const address_sorting_sortable* second) {
+  if (first->source_addr_exists &&
+      address_sorting_abstract_get_family(&first->source_addr) ==
+          ADDRESS_SORTING_AF_INET6 &&
+      second->source_addr_exists &&
+      address_sorting_abstract_get_family(&second->source_addr) ==
+          ADDRESS_SORTING_AF_INET6) {
+    int first_match_length =
+        ipv6_prefix_match_length((struct sockaddr_in6*)&first->source_addr.addr,
+                                 (struct sockaddr_in6*)&first->dest_addr.addr);
+    int second_match_length = ipv6_prefix_match_length(
+        (struct sockaddr_in6*)&second->source_addr.addr,
+        (struct sockaddr_in6*)&second->dest_addr.addr);
+    return second_match_length - first_match_length;
+  }
+  return 0;
+}
+
+static int rfc_6724_compare(const void* a, const void* b) {
+  const address_sorting_sortable* first = (address_sorting_sortable*)a;
+  const address_sorting_sortable* second = (address_sorting_sortable*)b;
+  int out = 0;
+  if ((out = compare_source_addr_exists(first, second))) {
+    return out;
+  }
+  if ((out = compare_source_dest_scope_matches(first, second))) {
+    return out;
+  }
+  if ((out = compare_source_dest_labels_match(first, second))) {
+    return out;
+  }
+  // TODO: Implement rule 3; avoid deprecated addresses.
+  // TODO: Implement rule 4; avoid temporary addresses.
+  if ((out = compare_dest_precedence(first, second))) {
+    return out;
+  }
+  // TODO: Implement rule 7; prefer native transports.
+  if ((out = compare_dest_scope(first, second))) {
+    return out;
+  }
+  if ((out = compare_source_dest_prefix_match_lengths(first, second))) {
+    return out;
+  }
+  // Prefer that the sort be stable otherwise
+  return (int)(first->original_index - second->original_index);
+}
+
+void address_sorting_override_source_addr_factory_for_testing(
+    address_sorting_source_addr_factory* factory) {
+  if (g_current_source_addr_factory == NULL) {
+    abort();
+  }
+  g_current_source_addr_factory->vtable->destroy(g_current_source_addr_factory);
+  g_current_source_addr_factory = factory;
+}
+
+static void sanity_check_private_fields_are_unused(
+    const address_sorting_sortable* sortable) {
+  address_sorting_address expected_source_addr;
+  memset(&expected_source_addr, 0, sizeof(expected_source_addr));
+  if (memcmp(&expected_source_addr, &sortable->source_addr,
+             sizeof(address_sorting_address)) ||
+      sortable->original_index || sortable->source_addr_exists) {
+    abort();
+  }
+}
+
+void address_sorting_rfc_6724_sort(address_sorting_sortable* sortables,
+                                   size_t sortables_len) {
+  for (size_t i = 0; i < sortables_len; i++) {
+    sanity_check_private_fields_are_unused(&sortables[i]);
+    sortables[i].original_index = i;
+    sortables[i].source_addr_exists = address_sorting_get_source_addr(
+        &sortables[i].dest_addr, &sortables[i].source_addr);
+  }
+  qsort(sortables, sortables_len, sizeof(address_sorting_sortable),
+        rfc_6724_compare);
+}
+
+void address_sorting_init() {
+  if (g_current_source_addr_factory != NULL) {
+    abort();
+  }
+  g_current_source_addr_factory =
+      address_sorting_create_source_addr_factory_for_current_platform();
+}
+
+void address_sorting_shutdown() {
+  if (g_current_source_addr_factory == NULL) {
+    abort();
+  }
+  g_current_source_addr_factory->vtable->destroy(g_current_source_addr_factory);
+}
diff --git a/third_party/address_sorting/address_sorting_internal.h b/third_party/address_sorting/address_sorting_internal.h
new file mode 100644
index 0000000..be59d44
--- /dev/null
+++ b/third_party/address_sorting/address_sorting_internal.h
@@ -0,0 +1,70 @@
+/*	$NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $	*/
+/*	$KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $	*/
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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.
+ *
+ */
+
+/*
+ * This is an adaptation of Android's implementation of RFC 6724
+ * (in Android's getaddrinfo.c). It has some cosmetic differences
+ * from Android's getaddrinfo.c, but Android's getaddrinfo.c was
+ * used as a guide or example of a way to implement the RFC 6724 spec when
+ * this was written.
+ */
+
+#ifndef ADDRESS_SORTING_INTERNAL_H
+#define ADDRESS_SORTING_INTERNAL_H
+
+#if defined(_WIN64) || defined(WIN64) || defined(_WIN32) || defined(WIN32)
+#include <winsock2.h>
+#include <ws2tcpip.h>
+// comment to prevent formatter from moving mswock.h upwards
+#include <mswsock.h>
+#define ADDRESS_SORTING_WINDOWS 1
+#else
+/* Workaround for issue described in
+ *
+ * https://bugs.launchpad.net/ubuntu/+source/eglibc/+bug/1187301 */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#define ADDRESS_SORTING_POSIX 1
+#endif
+
+#include <stdbool.h>
+
+#include <address_sorting/address_sorting.h>
+
+address_sorting_source_addr_factory*
+address_sorting_create_source_addr_factory_for_current_platform();
+
+#endif  // ADDRESS_SORTING_INTERNAL_H
diff --git a/third_party/address_sorting/address_sorting_posix.c b/third_party/address_sorting/address_sorting_posix.c
new file mode 100644
index 0000000..d0dfe12
--- /dev/null
+++ b/third_party/address_sorting/address_sorting_posix.c
@@ -0,0 +1,97 @@
+/*	$NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $	*/
+/*	$KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $	*/
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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.
+ *
+ */
+
+/*
+ * This is an adaptation of Android's implementation of RFC 6724
+ * (in Android's getaddrinfo.c). It has some cosmetic differences
+ * from Android's getaddrinfo.c, but Android's getaddrinfo.c was
+ * used as a guide or example of a way to implement the RFC 6724 spec when
+ * this was written.
+ */
+
+#include "address_sorting_internal.h"
+
+#if defined(ADDRESS_SORTING_POSIX)
+
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static bool posix_source_addr_factory_get_source_addr(
+    address_sorting_source_addr_factory* factory,
+    const address_sorting_address* dest_addr,
+    address_sorting_address* source_addr) {
+  bool source_addr_exists = false;
+  // Android sets SOCK_CLOEXEC. Don't set this here for portability.
+  int s = socket(((struct sockaddr*)dest_addr)->sa_family, SOCK_DGRAM, 0);
+  if (s != -1) {
+    if (connect(s, (const struct sockaddr*)&dest_addr->addr,
+                (socklen_t)dest_addr->len) != -1) {
+      address_sorting_address found_source_addr;
+      memset(&found_source_addr, 0, sizeof(found_source_addr));
+      found_source_addr.len = sizeof(found_source_addr.addr);
+      if (getsockname(s, (struct sockaddr*)&found_source_addr.addr,
+                      (socklen_t*)&found_source_addr.len) != -1) {
+        source_addr_exists = true;
+        *source_addr = found_source_addr;
+      }
+    }
+  }
+  close(s);
+  return source_addr_exists;
+}
+
+static void posix_source_addr_factory_destroy(
+    address_sorting_source_addr_factory* self) {
+  free(self);
+}
+
+static const address_sorting_source_addr_factory_vtable
+    posix_source_addr_factory_vtable = {
+        posix_source_addr_factory_get_source_addr,
+        posix_source_addr_factory_destroy,
+};
+
+address_sorting_source_addr_factory*
+address_sorting_create_source_addr_factory_for_current_platform() {
+  address_sorting_source_addr_factory* factory =
+      malloc(sizeof(address_sorting_source_addr_factory));
+  memset(factory, 0, sizeof(address_sorting_source_addr_factory));
+  factory->vtable = &posix_source_addr_factory_vtable;
+  return factory;
+}
+
+#endif  // defined(ADDRESS_SORTING_POSIX)
diff --git a/third_party/address_sorting/address_sorting_windows.c b/third_party/address_sorting/address_sorting_windows.c
new file mode 100644
index 0000000..b2f5708
--- /dev/null
+++ b/third_party/address_sorting/address_sorting_windows.c
@@ -0,0 +1,55 @@
+/*	$NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $	*/
+/*	$KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $	*/
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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.
+ *
+ */
+
+/*
+ * This is an adaptation of Android's implementation of RFC 6724
+ * (in Android's getaddrinfo.c). It has some cosmetic differences
+ * from Android's getaddrinfo.c, but Android's getaddrinfo.c was
+ * used as a guide or example of a way to implement the RFC 6724 spec when
+ * this was written.
+ */
+
+#include "address_sorting_internal.h"
+
+#if defined(ADDRESS_SORTING_WINDOWS)
+
+#include <stdlib.h>
+
+/* TODO : Add address sorting functionality to work on windows. */
+
+address_sorting_source_addr_factory*
+address_sorting_create_source_addr_factory_for_current_platform() {
+  abort();
+  return NULL;
+}
+
+#endif  // defined(ADDRESS_SORTING_WINDOWS)
diff --git a/third_party/address_sorting/include/address_sorting/address_sorting.h b/third_party/address_sorting/include/address_sorting/address_sorting.h
new file mode 100644
index 0000000..f11cd42
--- /dev/null
+++ b/third_party/address_sorting/include/address_sorting/address_sorting.h
@@ -0,0 +1,110 @@
+/*	$NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $	*/
+/*	$KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $	*/
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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.
+ *
+ */
+
+/*
+ * This is an adaptation of Android's implementation of RFC 6724
+ * (in Android's getaddrinfo.c). It has some cosmetic differences
+ * from Android's getaddrinfo.c, but Android's getaddrinfo.c was
+ * used as a guide or example of a way to implement the RFC 6724 spec when
+ * this was written.
+ */
+
+#ifndef ADDRESS_SORTING_H
+#define ADDRESS_SORTING_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct address_sorting_address {
+  char addr[128];
+  size_t len;
+} address_sorting_address;
+
+/* address_sorting_sortable represents one entry in a list of destination
+ * IP addresses to sort. It contains the destination IP address
+ * "sorting key", along with placeholder and scratch fields. */
+typedef struct address_sorting_sortable {
+  // input data; sorting key
+  address_sorting_address dest_addr;
+  // input data; optional value to attach to the sorting key
+  void* user_data;
+  // internal fields, these must be zero'd when passed to sort function
+  address_sorting_address source_addr;
+  bool source_addr_exists;
+  size_t original_index;
+} address_sorting_sortable;
+
+void address_sorting_rfc_6724_sort(address_sorting_sortable* sortables,
+                                   size_t sortables_len);
+
+void address_sorting_init();
+void address_sorting_shutdown();
+
+struct address_sorting_source_addr_factory;
+
+/* The interfaces below are exposed only for testing */
+typedef struct {
+  /* Gets the source address that would be used for the passed-in destination
+   * address, and fills in *source_addr* with it if one exists.
+   * Returns true if a source address exists for the destination address,
+   * and false otherwise. */
+  bool (*get_source_addr)(struct address_sorting_source_addr_factory* factory,
+                          const address_sorting_address* dest_addr,
+                          address_sorting_address* source_addr);
+  void (*destroy)(struct address_sorting_source_addr_factory* factory);
+} address_sorting_source_addr_factory_vtable;
+
+typedef struct address_sorting_source_addr_factory {
+  const address_sorting_source_addr_factory_vtable* vtable;
+} address_sorting_source_addr_factory;
+
+/* Platform-compatible address family types */
+typedef enum {
+  ADDRESS_SORTING_AF_INET,
+  ADDRESS_SORTING_AF_INET6,
+  ADDRESS_SORTING_UNKNOWN_FAMILY,
+} address_sorting_family;
+
+/* Indicates whether the address is AF_INET, AF_INET6, or another address
+ * family. */
+address_sorting_family address_sorting_abstract_get_family(
+    const address_sorting_address* address);
+
+void address_sorting_override_source_addr_factory_for_testing(
+    address_sorting_source_addr_factory* factory);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // ADDRESS_SORTING_H
diff --git a/third_party/boringssl b/third_party/boringssl
index 4d7ba4e..a20bb7f 160000
--- a/third_party/boringssl
+++ b/third_party/boringssl
@@ -1 +1 @@
-Subproject commit 4d7ba4e4e57195fcebdabe01489534b446ad02cb
+Subproject commit a20bb7ff8bb5057065a2e7941249773f9676cf45
diff --git a/third_party/constantly.BUILD b/third_party/constantly.BUILD
new file mode 100644
index 0000000..f1f93cb
--- /dev/null
+++ b/third_party/constantly.BUILD
@@ -0,0 +1,7 @@
+py_library(
+    name = "constantly",
+    srcs = glob(["constantly/*.py"]),
+    visibility = [
+        "//visibility:public",
+    ],
+)
diff --git a/third_party/incremental.BUILD b/third_party/incremental.BUILD
new file mode 100644
index 0000000..f2a06b4
--- /dev/null
+++ b/third_party/incremental.BUILD
@@ -0,0 +1,10 @@
+py_library(
+    name = "incremental",
+    srcs = glob(["src/incremental/*.py"]),
+    imports = [
+        "src",
+    ],
+    visibility = [
+        "//visibility:public",
+    ],
+)
diff --git a/third_party/nanopb/pb.h b/third_party/nanopb/pb.h
index 4576f79..62dca73 100644
--- a/third_party/nanopb/pb.h
+++ b/third_party/nanopb/pb.h
@@ -25,7 +25,7 @@
 /* #define PB_FIELD_16BIT 1 */
 
 /* Add support for tag numbers > 65536 and fields larger than 65536 bytes. */
-/* #define PB_FIELD_32BIT 1 */
+/* #define PB_FIELD_32BIT 1 */ 
 
 /* Disable support for error messages in order to save some code space. */
 /* #define PB_NO_ERRMSG 1 */
diff --git a/third_party/twisted.BUILD b/third_party/twisted.BUILD
new file mode 100644
index 0000000..5005c5a
--- /dev/null
+++ b/third_party/twisted.BUILD
@@ -0,0 +1,15 @@
+py_library(
+    name = "twisted",
+    srcs = glob(["src/twisted/**/*.py"]),
+    imports = [
+        "src",
+    ],
+    visibility = [
+        "//visibility:public",
+    ],
+    deps = [
+        "@com_github_twisted_incremental//:incremental",
+        "@com_github_twisted_constantly//:constantly",
+        "@com_github_zopefoundation_zope_interface//:zope_interface",
+    ],
+)
diff --git a/third_party/yaml.BUILD b/third_party/yaml.BUILD
new file mode 100644
index 0000000..f88854c
--- /dev/null
+++ b/third_party/yaml.BUILD
@@ -0,0 +1,10 @@
+py_library(
+    name = "yaml",
+    srcs = glob(["lib/yaml/*.py"]),
+    imports = [
+        "lib",
+    ],
+    visibility = [
+        "//visibility:public",
+    ],
+)
diff --git a/third_party/zope_interface.BUILD b/third_party/zope_interface.BUILD
new file mode 100644
index 0000000..b7b8d1e
--- /dev/null
+++ b/third_party/zope_interface.BUILD
@@ -0,0 +1,13 @@
+py_library(
+    name = "zope_interface",
+    srcs = glob([
+        "src/zope/interface/*.py",
+        "src/zope/interface/common/*.py",
+    ]),
+    imports = [
+        "src",
+    ],
+    visibility = [
+        "//visibility:public",
+    ],
+)
diff --git a/tools/bazel.rc b/tools/bazel.rc
index 8af2fc9..ed9169f 100644
--- a/tools/bazel.rc
+++ b/tools/bazel.rc
@@ -1,5 +1,6 @@
 build --client_env=CC=clang
 build --copt -DGRPC_BAZEL_BUILD
+build --copt -Wframe-larger-than=16384
 
 build:asan --strip=never
 build:asan --copt -fsanitize-coverage=edge
diff --git a/tools/buildgen/plugins/expand_version.py b/tools/buildgen/plugins/expand_version.py
index facf349..a734469 100755
--- a/tools/buildgen/plugins/expand_version.py
+++ b/tools/buildgen/plugins/expand_version.py
@@ -24,6 +24,7 @@
     'core',
     'cpp',
     'csharp',
+    'node',
     'objc',
     'php',
     'python',
diff --git a/tools/codegen/core/gen_nano_proto.sh b/tools/codegen/core/gen_nano_proto.sh
index 4246840..6ce1517 100755
--- a/tools/codegen/core/gen_nano_proto.sh
+++ b/tools/codegen/core/gen_nano_proto.sh
@@ -43,9 +43,9 @@
   echo "Input proto file '$INPUT_PROTO' doesn't exist."
   exit 2
 fi
+
 if [[ ! -f "${EXPECTED_OPTIONS_FILE_PATH}" ]]; then
-  echo "Expected nanopb options file '${EXPECTED_OPTIONS_FILE_PATH}' missing"
-  exit 3
+  echo "Input proto file may need .options file to be correctly compiled."
 fi
 
 if [[ "${OUTPUT_DIR:0:1}" != '/' ]]; then
@@ -81,6 +81,11 @@
 sed -i "s:$PROTO_BASENAME.pb.h:${GRPC_OUTPUT_DIR}/$PROTO_BASENAME.pb.h:g" \
   "$OUTPUT_DIR/$PROTO_BASENAME.pb.c"
 
+if [ $PROTO_BASENAME == "handshaker" ] || [ $PROTO_BASENAME == "altscontext" ]; then
+  sed -i "s:transport_security_common.pb.h:${GRPC_OUTPUT_DIR}/transport_security_common.pb.h:g" \
+    "$OUTPUT_DIR/$PROTO_BASENAME.pb.h"
+fi
+
 # Fix up the include guards such that they pass the check_include_guards.py
 # test. Assumes that the generated files are being placed in gRPC src dir.
 readonly INCLUDE_GUARD_BASE=`echo $GRPC_OUTPUT_DIR | tr [a-z/] [A-Z_] | sed s:^.*SRC_::`
diff --git a/tools/codegen/core/gen_static_metadata.py b/tools/codegen/core/gen_static_metadata.py
index d4c0052..25da3fd 100755
--- a/tools/codegen/core/gen_static_metadata.py
+++ b/tools/codegen/core/gen_static_metadata.py
@@ -45,6 +45,12 @@
     'grpc-server-stats-bin',
     'grpc-tags-bin',
     'grpc-trace-bin',
+    'grpc-previous-rpc-attempts',
+    'grpc-retry-pushback-ms',
+    '1',
+    '2',
+    '3',
+    '4',
     '',
     # channel arg keys
     'grpc.wait_for_ready',
@@ -54,8 +60,8 @@
     # well known method names
     '/grpc.lb.v1.LoadBalancer/BalanceLoad',
     # compression algorithm names
-    'message/deflate',
-    'message/gzip',
+    'deflate',
+    'gzip',
     'stream/gzip',
     # metadata elements
     ('grpc-status', '0'),
@@ -163,6 +169,8 @@
     ('user-agent', True),
     ('host', True),
     ('lb-token', True),
+    ('grpc-previous-rpc-attempts', True),
+    ('grpc-retry-pushback-ms', True),
 ]
 
 COMPRESSION_ALGORITHMS = [
diff --git a/tools/distrib/check_copyright.py b/tools/distrib/check_copyright.py
index 55cec93..e7893a1 100755
--- a/tools/distrib/check_copyright.py
+++ b/tools/distrib/check_copyright.py
@@ -77,6 +77,12 @@
     'examples/python/route_guide/route_guide_pb2_grpc.py',
     'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
     'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
+    'src/core/tsi/alts/handshaker/altscontext.pb.h',
+    'src/core/tsi/alts/handshaker/altscontext.pb.c',
+    'src/core/tsi/alts/handshaker/handshaker.pb.h',
+    'src/core/tsi/alts/handshaker/handshaker.pb.c',
+    'src/core/tsi/alts/handshaker/transport_security_common.pb.h',
+    'src/core/tsi/alts/handshaker/transport_security_common.pb.c',
     'src/cpp/server/health/health.pb.h',
     'src/cpp/server/health/health.pb.c',
 
@@ -86,6 +92,9 @@
     'tools/grpcz/census.proto',
     # status.proto copied from googleapis
     'src/proto/grpc/status/status.proto',
+
+    # Gradle wrapper used to build for Android
+    'examples/android/helloworld/gradlew.bat',
 ))
 
 RE_YEAR = r'Copyright (?P<first_year>[0-9]+\-)?(?P<last_year>[0-9]+) gRPC authors.'
diff --git a/tools/distrib/check_include_guards.py b/tools/distrib/check_include_guards.py
index 6fc606f..b356a74 100755
--- a/tools/distrib/check_include_guards.py
+++ b/tools/distrib/check_include_guards.py
@@ -49,7 +49,7 @@
         self.failed = False
 
     def fail(self, fpath, regexp, fcontents, match_txt, correct, fix):
-        cpp_header = 'grpc++' in fpath
+        cpp_header = 'grpc++' in fpath or 'grpcpp' in fpath
         self.failed = True
         invalid_guards_msg_template = (
             '{0}: Missing preprocessor guards (RE {1}). '
@@ -78,7 +78,7 @@
         return fcontents
 
     def check(self, fpath, fix):
-        cpp_header = 'grpc++' in fpath
+        cpp_header = 'grpc++' in fpath or 'grpcpp' in fpath
         valid_guard = build_valid_guard(fpath)
 
         fcontents = load(fpath)
@@ -157,6 +157,9 @@
 
 KNOWN_BAD = set([
     'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
+    'src/core/tsi/alts/handshaker/altscontext.pb.h',
+    'src/core/tsi/alts/handshaker/handshaker.pb.h',
+    'src/core/tsi/alts/handshaker/transport_security_common.pb.h',
     'include/grpc++/ext/reflection.grpc.pb.h',
     'include/grpc++/ext/reflection.pb.h',
 ])
diff --git a/tools/distrib/check_nanopb_output.sh b/tools/distrib/check_nanopb_output.sh
index a30b73f..8b5823b 100755
--- a/tools/distrib/check_nanopb_output.sh
+++ b/tools/distrib/check_nanopb_output.sh
@@ -15,6 +15,7 @@
 
 set -ex
 
+readonly NANOPB_ALTS_TMP_OUTPUT="$(mktemp -d)"
 readonly NANOPB_TMP_OUTPUT="$(mktemp -d)"
 readonly PROTOBUF_INSTALL_PREFIX="$(mktemp -d)"
 
@@ -55,3 +56,29 @@
   echo "Outputs differ: $NANOPB_TMP_OUTPUT vs $LOAD_BALANCER_GRPC_OUTPUT_PATH"
   exit 2
 fi
+
+#
+# Checks for handshaker.proto and transport_security_common.proto
+#
+readonly HANDSHAKER_GRPC_OUTPUT_PATH='src/core/tsi/alts/handshaker'
+# nanopb-compile the proto to a temp location
+./tools/codegen/core/gen_nano_proto.sh \
+  src/core/tsi/alts/handshaker/proto/handshaker.proto \
+  "$NANOPB_ALTS_TMP_OUTPUT" \
+  "$HANDSHAKER_GRPC_OUTPUT_PATH"
+./tools/codegen/core/gen_nano_proto.sh \
+  src/core/tsi/alts/handshaker/proto/transport_security_common.proto \
+  "$NANOPB_ALTS_TMP_OUTPUT" \
+  "$HANDSHAKER_GRPC_OUTPUT_PATH"
+./tools/codegen/core/gen_nano_proto.sh \
+  src/core/tsi/alts/handshaker/proto/altscontext.proto \
+  "$NANOPB_ALTS_TMP_OUTPUT" \
+  "$HANDSHAKER_GRPC_OUTPUT_PATH"
+
+# compare outputs to checked compiled code
+for NANOPB_OUTPUT_FILE in $NANOPB_ALTS_TMP_OUTPUT/*.pb.*; do
+  if ! diff "$NANOPB_OUTPUT_FILE" "src/core/tsi/alts/handshaker/$(basename $NANOPB_OUTPUT_FILE)"; then
+    echo "Outputs differ: $NANOPB_ALTS_TMP_OUTPUT vs $HANDSHAKER_GRPC_OUTPUT_PATH"
+    exit 2
+  fi
+done
diff --git a/tools/distrib/clang_format_code.sh b/tools/distrib/clang_format_code.sh
index 9233a23..cd7553e 100755
--- a/tools/distrib/clang_format_code.sh
+++ b/tools/distrib/clang_format_code.sh
@@ -25,7 +25,9 @@
   docker build -t grpc_clang_format tools/dockerfile/grpc_clang_format
 
   # run clang-format against the checked out codebase
-  docker run -e TEST=$TEST -e CHANGED_FILES="$CHANGED_FILES" -e CLANG_FORMAT_ROOT="/local-code" --rm=true -v "${REPO_ROOT}":/local-code -t grpc_clang_format /clang_format_all_the_things.sh
+  # when modifying the checked-out files, the current user will be impersonated
+  # so that the updated files don't end up being owned by "root".
+  docker run -e TEST="$TEST" -e CHANGED_FILES="$CHANGED_FILES" -e CLANG_FORMAT_ROOT="/local-code" --rm=true -v "${REPO_ROOT}":/local-code --user "$(id -u):$(id -g)" -t grpc_clang_format /clang_format_all_the_things.sh
 else
   CLANG_FORMAT_ROOT="${REPO_ROOT}" tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
 fi
diff --git a/tools/distrib/clang_tidy_code.sh b/tools/distrib/clang_tidy_code.sh
index 5da86aa..9262b6b 100755
--- a/tools/distrib/clang_tidy_code.sh
+++ b/tools/distrib/clang_tidy_code.sh
@@ -27,7 +27,9 @@
   docker build -t grpc_clang_tidy tools/dockerfile/grpc_clang_tidy
 
   # run clang-tidy against the checked out codebase
-  docker run -e TEST=$TEST -e CHANGED_FILES="$CHANGED_FILES" -e CLANG_TIDY_ROOT="/local-code" --rm=true -v "${REPO_ROOT}":/local-code -t grpc_clang_tidy /clang_tidy_all_the_things.sh "$@"
+  # when modifying the checked-out files, the current user will be impersonated
+  # so that the updated files don't end up being owned by "root".
+  docker run -e TEST="$TEST" -e CHANGED_FILES="$CHANGED_FILES" -e CLANG_TIDY_ROOT="/local-code" --rm=true -v "${REPO_ROOT}":/local-code --user "$(id -u):$(id -g)" -t grpc_clang_tidy /clang_tidy_all_the_things.sh "$@"
 else
   CLANG_TIDY_ROOT="${REPO_ROOT}" tools/dockerfile/grpc_clang_tidy/clang_tidy_all_the_things.sh "$@"
 fi
diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py
index 5caa1d1..e8ca685 100644
--- a/tools/distrib/python/grpcio_tools/grpc_version.py
+++ b/tools/distrib/python/grpcio_tools/grpc_version.py
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
 
-VERSION = '1.10.0.dev0'
+VERSION = '1.11.0.dev0'
diff --git a/tools/distrib/python_wrapper.sh b/tools/distrib/python_wrapper.sh
index 9ace915..a099b2f 100755
--- a/tools/distrib/python_wrapper.sh
+++ b/tools/distrib/python_wrapper.sh
@@ -16,7 +16,7 @@
 
 for p in python2.7 python2.6 python2 python not_found ; do 
 
-  python=`which $p || echo not_found`
+  python=$(which $p || echo not_found)
 
   if [ -x "$python" ] ; then
     break
@@ -25,7 +25,7 @@
 done
 
 if [ -x "$python" ] ; then
-  exec $python $@
+  exec "$python" "$@"
 else
   echo "No acceptable version of python found on the system"
   exit 1
diff --git a/tools/dockerfile/distribtest/csharp_ubuntu1504_x64/Dockerfile b/tools/dockerfile/distribtest/csharp_ubuntu1504_x64/Dockerfile
deleted file mode 100644
index 3e6273f..0000000
--- a/tools/dockerfile/distribtest/csharp_ubuntu1504_x64/Dockerfile
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright 2015 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-FROM ubuntu:15.04
-
-RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy main" | tee /etc/apt/sources.list.d/mono-xamarin.list
-
-RUN apt-get update && apt-get install -y \
-    mono-devel \
-    ca-certificates-mono \
-    nuget
-
-# make sure we have nuget 2.12+ (in case there's an older cached docker image)
-RUN apt-get update && apt-get install -y nuget
-
-RUN apt-get update && apt-get install -y unzip
diff --git a/tools/dockerfile/distribtest/csharp_ubuntu1510_x64/Dockerfile b/tools/dockerfile/distribtest/csharp_ubuntu1510_x64/Dockerfile
deleted file mode 100644
index fb29f3e..0000000
--- a/tools/dockerfile/distribtest/csharp_ubuntu1510_x64/Dockerfile
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright 2015 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-FROM ubuntu:15.10
-
-RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy main" | tee /etc/apt/sources.list.d/mono-xamarin.list
-
-RUN apt-get update && apt-get install -y \
-    mono-devel \
-    ca-certificates-mono \
-    nuget
-
-# make sure we have nuget 2.12+ (in case there's an older cached docker image)
-RUN apt-get update && apt-get install -y nuget
-
-RUN apt-get update && apt-get install -y unzip
diff --git a/tools/dockerfile/distribtest/node_ubuntu1510_x64/Dockerfile b/tools/dockerfile/distribtest/node_ubuntu1510_x64/Dockerfile
deleted file mode 100644
index 41752d3..0000000
--- a/tools/dockerfile/distribtest/node_ubuntu1510_x64/Dockerfile
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright 2016 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-FROM ubuntu:15.10
-
-RUN apt-get update && apt-get install -y curl
-
-# Install nvm
-RUN touch .profile
-RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash
\ No newline at end of file
diff --git a/tools/dockerfile/distribtest/python_arch_x64/Dockerfile b/tools/dockerfile/distribtest/python_arch_x64/Dockerfile
index d8fb74d..9e43d00 100644
--- a/tools/dockerfile/distribtest/python_arch_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/python_arch_x64/Dockerfile
@@ -18,4 +18,4 @@
 RUN pacman --noconfirm -S openssl
 RUN pacman --noconfirm -S python2
 RUN pacman --noconfirm -S python2-pip
-RUN pip install virtualenv
+RUN pip2 install virtualenv
diff --git a/tools/dockerfile/distribtest/python_ubuntu1204_x64/Dockerfile b/tools/dockerfile/distribtest/python_ubuntu1204_x64/Dockerfile
index 7476d5f..7dd499f 100644
--- a/tools/dockerfile/distribtest/python_ubuntu1204_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/python_ubuntu1204_x64/Dockerfile
@@ -16,4 +16,6 @@
 
 RUN apt-get update -y && apt-get install -y python python-pip
 
-RUN pip install virtualenv
+# Use --index-url to workaround
+# https://stackoverflow.com/questions/21294997/pip-connection-failure-cannot-fetch-index-base-url-http-pypi-python-org-simpl
+RUN pip install --index-url=https://pypi.python.org/simple/ virtualenv
diff --git a/tools/dockerfile/distribtest/python_ubuntu1504_x64/Dockerfile b/tools/dockerfile/distribtest/python_ubuntu1504_x64/Dockerfile
deleted file mode 100644
index 76941de..0000000
--- a/tools/dockerfile/distribtest/python_ubuntu1504_x64/Dockerfile
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright 2015 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-FROM ubuntu:15.04
-
-RUN apt-get update -y && apt-get install -y python python-pip
-
-RUN pip install virtualenv
diff --git a/tools/dockerfile/distribtest/python_ubuntu1510_x64/Dockerfile b/tools/dockerfile/distribtest/python_ubuntu1510_x64/Dockerfile
deleted file mode 100644
index 43db310..0000000
--- a/tools/dockerfile/distribtest/python_ubuntu1510_x64/Dockerfile
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright 2015 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-FROM ubuntu:15.10
-
-RUN apt-get update -y && apt-get install -y python python-pip
-
-RUN pip install virtualenv
diff --git a/tools/dockerfile/distribtest/python_wheezy_x64/Dockerfile b/tools/dockerfile/distribtest/python_wheezy_x64/Dockerfile
index 0572cc1..c17d7bc 100644
--- a/tools/dockerfile/distribtest/python_wheezy_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/python_wheezy_x64/Dockerfile
@@ -16,4 +16,6 @@
 
 RUN apt-get update -y && apt-get install -y python python-pip
 
-RUN pip install virtualenv
+# Use --index-url to workaround
+# https://stackoverflow.com/questions/21294997/pip-connection-failure-cannot-fetch-index-base-url-http-pypi-python-org-simpl
+RUN pip install --index-url=https://pypi.python.org/simple/ virtualenv
diff --git a/tools/dockerfile/distribtest/ruby_fedora20_x64/Dockerfile b/tools/dockerfile/distribtest/ruby_fedora20_x64/Dockerfile
index 5ea5121..200c5c2 100644
--- a/tools/dockerfile/distribtest/ruby_fedora20_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/ruby_fedora20_x64/Dockerfile
@@ -14,6 +14,6 @@
 
 FROM fedora:20
 
-RUN yum clean all && yum update -y && yum install -y ruby
+RUN yum clean all && yum update -y && yum install -y ruby findutils
 
 RUN gem install bundler
diff --git a/tools/dockerfile/distribtest/ruby_fedora21_x64/Dockerfile b/tools/dockerfile/distribtest/ruby_fedora21_x64/Dockerfile
index b903401..e1177fd 100644
--- a/tools/dockerfile/distribtest/ruby_fedora21_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/ruby_fedora21_x64/Dockerfile
@@ -19,6 +19,6 @@
 # https://github.com/docker/docker/issues/10180
 RUN yum install -y yum-plugin-ovl
 
-RUN yum clean all && yum update -y && yum install -y ruby
+RUN yum clean all && yum update -y && yum install -y ruby findutils
 
 RUN gem install bundler
diff --git a/tools/dockerfile/distribtest/ruby_fedora22_x64/Dockerfile b/tools/dockerfile/distribtest/ruby_fedora22_x64/Dockerfile
index 0d57370..848c5be 100644
--- a/tools/dockerfile/distribtest/ruby_fedora22_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/ruby_fedora22_x64/Dockerfile
@@ -14,6 +14,6 @@
 
 FROM fedora:22
 
-RUN yum clean all && yum update -y && yum install -y ruby
+RUN yum clean all && yum update -y && yum install -y ruby findutils
 
 RUN gem install bundler
diff --git a/tools/dockerfile/distribtest/ruby_fedora23_x64/Dockerfile b/tools/dockerfile/distribtest/ruby_fedora23_x64/Dockerfile
index 318993b..47dd577 100644
--- a/tools/dockerfile/distribtest/ruby_fedora23_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/ruby_fedora23_x64/Dockerfile
@@ -14,6 +14,6 @@
 
 FROM fedora:23
 
-RUN yum clean all && yum update -y && yum install -y ruby
+RUN yum clean all && yum update -y && yum install -y ruby findutils
 
 RUN gem install bundler
diff --git a/tools/dockerfile/distribtest/ruby_ubuntu1504_x64/Dockerfile b/tools/dockerfile/distribtest/ruby_ubuntu1504_x64/Dockerfile
deleted file mode 100644
index 3300efd..0000000
--- a/tools/dockerfile/distribtest/ruby_ubuntu1504_x64/Dockerfile
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright 2015 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-FROM ubuntu:15.04
-
-RUN apt-get update -y && apt-get install -y ruby-full
-
-RUN gem install bundler
diff --git a/tools/dockerfile/grpc_artifact_python_manylinux_x64/Dockerfile b/tools/dockerfile/grpc_artifact_python_manylinux_x64/Dockerfile
index 6f61e17..07604c7 100644
--- a/tools/dockerfile/grpc_artifact_python_manylinux_x64/Dockerfile
+++ b/tools/dockerfile/grpc_artifact_python_manylinux_x64/Dockerfile
@@ -18,19 +18,7 @@
 
 # Update the package manager
 RUN yum update -y
-
-#############################################################
-# Update Git to allow cloning submodules with --reference arg
-RUN yum remove -y git
 RUN yum install -y curl-devel expat-devel gettext-devel linux-headers openssl-devel zlib-devel gcc
-RUN cd /usr/src && \
-  curl -O -L https://kernel.org/pub/software/scm/git/git-2.0.5.tar.gz && \
-  tar xzf git-2.0.5.tar.gz
-RUN cd /usr/src/git-2.0.5 && \
-  make prefix=/usr/local/git all && \
-  make prefix=/usr/local/git install
-ENV PATH /usr/local/git/bin:$PATH
-RUN source /etc/bashrc
 
 ###################################
 # Install Python build requirements
diff --git a/tools/dockerfile/grpc_artifact_python_manylinux_x86/Dockerfile b/tools/dockerfile/grpc_artifact_python_manylinux_x86/Dockerfile
index 5c3c351..96ab515 100644
--- a/tools/dockerfile/grpc_artifact_python_manylinux_x86/Dockerfile
+++ b/tools/dockerfile/grpc_artifact_python_manylinux_x86/Dockerfile
@@ -18,19 +18,7 @@
 
 # Update the package manager
 RUN yum update -y
-
-#############################################################
-# Update Git to allow cloning submodules with --reference arg
-RUN yum remove -y git
 RUN yum install -y curl-devel expat-devel gettext-devel linux-headers openssl-devel zlib-devel gcc
-RUN cd /usr/src && \
-  curl -O -L https://kernel.org/pub/software/scm/git/git-2.0.5.tar.gz && \
-  tar xzf git-2.0.5.tar.gz
-RUN cd /usr/src/git-2.0.5 && \
-  make prefix=/usr/local/git all && \
-  make prefix=/usr/local/git install
-ENV PATH /usr/local/git/bin:$PATH
-RUN source /etc/bashrc
 
 ###################################
 # Install Python build requirements
diff --git a/tools/dockerfile/grpc_clang_format/Dockerfile b/tools/dockerfile/grpc_clang_format/Dockerfile
index 8801315..ecdc52e 100644
--- a/tools/dockerfile/grpc_clang_format/Dockerfile
+++ b/tools/dockerfile/grpc_clang_format/Dockerfile
@@ -23,4 +23,9 @@
 ENV CLANG_TIDY=clang-tidy
 
 ADD clang_format_all_the_things.sh /
+
+# When running locally, we'll be impersonating the current user, so we need
+# to make the script runnable by everyone.
+RUN chmod a+rx /clang_format_all_the_things.sh
+
 CMD ["echo 'Run with tools/distrib/clang_format_code.sh'"]
diff --git a/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh b/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
index 7247199..08c6a96 100755
--- a/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
+++ b/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
@@ -16,7 +16,7 @@
 set -e
 
 # directories to run against
-DIRS="src/core/lib src/core/tsi src/core/ext src/cpp test/core test/cpp include src/compiler src/csharp src/ruby"
+DIRS="src/core/lib src/core/tsi src/core/ext src/cpp test/core test/cpp include src/compiler src/csharp src/ruby third_party/address_sorting"
 
 # file matching patterns to check
 GLOB="*.h *.c *.cc"
diff --git a/tools/dockerfile/grpc_clang_tidy/Dockerfile b/tools/dockerfile/grpc_clang_tidy/Dockerfile
index 9d9d701..eeba455 100644
--- a/tools/dockerfile/grpc_clang_tidy/Dockerfile
+++ b/tools/dockerfile/grpc_clang_tidy/Dockerfile
@@ -38,4 +38,9 @@
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 ADD clang_tidy_all_the_things.sh /
+
+# When running locally, we'll be impersonating the current user, so we need
+# to make the script runnable by everyone.
+RUN chmod a+rx /clang_tidy_all_the_things.sh
+
 CMD ["echo 'Run with tools/distrib/clang_tidy_code.sh'"]
diff --git a/src/python/grpcio_tests/tests/unit/framework/interfaces/__init__.py b/tools/dockerfile/interoptest/grpc_interop_dart/Dockerfile
similarity index 83%
rename from src/python/grpcio_tests/tests/unit/framework/interfaces/__init__.py
rename to tools/dockerfile/interoptest/grpc_interop_dart/Dockerfile
index 5fb4f3c..d754996 100644
--- a/src/python/grpcio_tests/tests/unit/framework/interfaces/__init__.py
+++ b/tools/dockerfile/interoptest/grpc_interop_dart/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2015 gRPC authors.
+# Copyright 2017 gRPC authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -11,3 +11,8 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
+
+FROM google/dart:latest
+
+# Define the default command.
+CMD ["bash"]
diff --git a/src/python/grpcio_tests/tests/unit/framework/interfaces/face/_3069_test_constant.py b/tools/dockerfile/interoptest/grpc_interop_dart/build_interop.sh
similarity index 60%
rename from src/python/grpcio_tests/tests/unit/framework/interfaces/face/_3069_test_constant.py
rename to tools/dockerfile/interoptest/grpc_interop_dart/build_interop.sh
index 6eb7ba3..c4cb682 100644
--- a/src/python/grpcio_tests/tests/unit/framework/interfaces/face/_3069_test_constant.py
+++ b/tools/dockerfile/interoptest/grpc_interop_dart/build_interop.sh
@@ -1,4 +1,5 @@
-# Copyright 2015 gRPC authors.
+#!/bin/bash
+# Copyright 2017 gRPC authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -11,11 +12,15 @@
 # WITHOUT 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 test constant working around issue 3069."""
+#
+# Builds Dart interop server and client in a base image.
+set -e
 
-# test_constants is referenced from specification in this module.
-from tests.unit.framework.common import test_constants  # pylint: disable=unused-import
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc-dart /var/local/git/grpc-dart
 
-# TODO(issue 3069): Replace uses of this constant with
-# test_constants.SHORT_TIMEOUT.
-REALLY_SHORT_TIMEOUT = 0.1
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+cd /var/local/git/grpc-dart/interop
+/usr/lib/dart/bin/pub get
diff --git a/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
index 17671a3..b480d31 100644
--- a/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
@@ -75,7 +75,8 @@
 RUN /bin/bash -l -c "nvm install 5 && npm config set cache /tmp/npm-cache && npm install -g npm"
 RUN /bin/bash -l -c "nvm install 6 && npm config set cache /tmp/npm-cache && npm install -g npm"
 RUN /bin/bash -l -c "nvm install 8 && npm config set cache /tmp/npm-cache && npm install -g npm"
-RUN /bin/bash -l -c "nvm alias default 8"
+RUN /bin/bash -l -c "nvm install 9 && npm config set cache /tmp/npm-cache && npm install -g npm"
+RUN /bin/bash -l -c "nvm alias default 9"
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
 RUN ln -s /usr/bin/ccache /usr/local/bin/g++
diff --git a/tools/dockerfile/interoptest/grpc_interop_nodepurejs/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_nodepurejs/Dockerfile
new file mode 100644
index 0000000..7f3b20a
--- /dev/null
+++ b/tools/dockerfile/interoptest/grpc_interop_nodepurejs/Dockerfile
@@ -0,0 +1,77 @@
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+FROM debian:jessie
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  dnsutils \
+  gcc \
+  gcc-multilib \
+  git \
+  golang \
+  gyp \
+  lcov \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  perl \
+  strace \
+  python-dev \
+  python-setuptools \
+  python-yaml \
+  telnet \
+  unzip \
+  wget \
+  zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#==================
+# Node dependencies
+
+# Install nvm
+RUN touch .profile
+RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
+# Install all versions of node that we want to test
+RUN /bin/bash -l -c "nvm install 4 && npm config set cache /tmp/npm-cache && npm install -g npm"
+RUN /bin/bash -l -c "nvm install 5 && npm config set cache /tmp/npm-cache && npm install -g npm"
+RUN /bin/bash -l -c "nvm install 6 && npm config set cache /tmp/npm-cache && npm install -g npm"
+RUN /bin/bash -l -c "nvm install 8 && npm config set cache /tmp/npm-cache && npm install -g npm"
+RUN /bin/bash -l -c "nvm install 9 && npm config set cache /tmp/npm-cache && npm install -g npm"
+RUN /bin/bash -l -c "nvm alias default 9"
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+
+RUN mkdir /var/local/jenkins
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/dockerfile/interoptest/grpc_interop_nodepurejs/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_nodepurejs/build_interop.sh
new file mode 100755
index 0000000..d41ccac
--- /dev/null
+++ b/tools/dockerfile/interoptest/grpc_interop_nodepurejs/build_interop.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Builds Node interop server and client in a base image.
+set -e
+
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc-node /var/local/git/grpc-node
+# clone gRPC submodules, use data from locally cloned submodules where possible
+(cd /var/local/jenkins/grpc-node/ && git submodule foreach 'cd /var/local/git/grpc-node \
+&& git submodule update --init --recursive --reference /var/local/jenkins/grpc-node/${name} \
+${name}')
+
+# copy service account keys if available
+cp -r /var/local/jenkins/service_account $HOME || true
+
+cd /var/local/git/grpc-node
+
+# build Node interop client & server
+npm install -g gulp
+npm install
+gulp js.core.install
+gulp protobuf.install
+gulp internal.test.install
diff --git a/tools/dockerfile/push_testing_images.sh b/tools/dockerfile/push_testing_images.sh
index b76ceea..2831e8a 100755
--- a/tools/dockerfile/push_testing_images.sh
+++ b/tools/dockerfile/push_testing_images.sh
@@ -29,7 +29,7 @@
 
 DOCKERHUB_ORGANIZATION=grpctesting
 
-for DOCKERFILE_DIR in tools/dockerfile/test/* tools/dockerfile/grpc_artifact_* tools/dockerfile/interoptest/* tools/dockerfile/distribtest/cpp_jessie_x64 third_party/rake-compiler-dock
+for DOCKERFILE_DIR in tools/dockerfile/test/* tools/dockerfile/grpc_artifact_* tools/dockerfile/interoptest/* tools/dockerfile/distribtest/* third_party/rake-compiler-dock
 do
   # Generate image name based on Dockerfile checksum. That works well as long
   # as can count on dockerfiles being written in a way that changing the logical 
diff --git a/tools/dockerfile/test/bazel/Dockerfile b/tools/dockerfile/test/bazel/Dockerfile
index ba668ea..e5e8113 100644
--- a/tools/dockerfile/test/bazel/Dockerfile
+++ b/tools/dockerfile/test/bazel/Dockerfile
@@ -33,12 +33,12 @@
 RUN apt-get -y update
 RUN apt-get -y install bazel
 
-# Pin Bazel to 0.4.4
-# Installing Bazel via apt-get first is required before installing 0.4.4 to
+# Pin Bazel to 0.9.0
+# Installing Bazel via apt-get first is required before installing 0.9.0 to
 # allow gRPC to build without errors. See https://github.com/grpc/grpc/issues/10553
-RUN curl -fSsL -O https://github.com/bazelbuild/bazel/releases/download/0.4.4/bazel-0.4.4-installer-linux-x86_64.sh
-RUN chmod +x ./bazel-0.4.4-installer-linux-x86_64.sh
-RUN ./bazel-0.4.4-installer-linux-x86_64.sh
+RUN curl -fSsL -O https://github.com/bazelbuild/bazel/releases/download/0.9.0/bazel-0.9.0-installer-linux-x86_64.sh
+RUN chmod +x ./bazel-0.9.0-installer-linux-x86_64.sh
+RUN ./bazel-0.9.0-installer-linux-x86_64.sh
 
 RUN mkdir -p /var/local/jenkins
 
diff --git a/tools/dockerfile/test/cxx_alpine_x64/Dockerfile b/tools/dockerfile/test/cxx_alpine_x64/Dockerfile
index 8e5403f..c68a5dd 100644
--- a/tools/dockerfile/test/cxx_alpine_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_alpine_x64/Dockerfile
@@ -39,23 +39,27 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 # Google Cloud platform API libraries
 RUN pip install --upgrade google-api-python-client
 
-# Prepare ccache
-RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
-RUN ln -s /usr/bin/ccache /usr/local/bin/g++
-RUN ln -s /usr/bin/ccache /usr/local/bin/cc 
-RUN ln -s /usr/bin/ccache /usr/local/bin/c++
-
 # Install gflags
 RUN git clone https://github.com/gflags/gflags.git && cd gflags && git checkout v2.2.0
 RUN cd gflags && cmake . && make && make install
 RUN ln -s /usr/local/include/gflags /usr/include/gflags
 
-RUN mkdir -p /var/local/jenkins
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+
+RUN mkdir /var/local/jenkins
+
 
 # Define the default command.
 CMD ["bash"]
diff --git a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
index 362c061..5818ff9 100644
--- a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
@@ -104,7 +104,8 @@
 RUN /bin/bash -l -c "nvm install 5 && npm config set cache /tmp/npm-cache && npm install -g npm"
 RUN /bin/bash -l -c "nvm install 6 && npm config set cache /tmp/npm-cache && npm install -g npm"
 RUN /bin/bash -l -c "nvm install 8 && npm config set cache /tmp/npm-cache && npm install -g npm"
-RUN /bin/bash -l -c "nvm alias default 8"
+RUN /bin/bash -l -c "nvm install 9 && npm config set cache /tmp/npm-cache && npm install -g npm"
+RUN /bin/bash -l -c "nvm alias default 9"
 #=================
 # PHP dependencies
 
diff --git a/tools/dockerfile/test/node_jessie_x64/Dockerfile b/tools/dockerfile/test/node_jessie_x64/Dockerfile
index 9f19e76..05c8319 100644
--- a/tools/dockerfile/test/node_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/node_jessie_x64/Dockerfile
@@ -90,7 +90,8 @@
 RUN /bin/bash -l -c "nvm install 5 && npm config set cache /tmp/npm-cache && npm install -g npm"
 RUN /bin/bash -l -c "nvm install 6 && npm config set cache /tmp/npm-cache && npm install -g npm"
 RUN /bin/bash -l -c "nvm install 8 && npm config set cache /tmp/npm-cache && npm install -g npm"
-RUN /bin/bash -l -c "nvm alias default 8"
+RUN /bin/bash -l -c "nvm install 9 && npm config set cache /tmp/npm-cache && npm install -g npm"
+RUN /bin/bash -l -c "nvm alias default 9"
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
 RUN ln -s /usr/bin/ccache /usr/local/bin/g++
diff --git a/tools/dockerfile/test/sanity/Dockerfile b/tools/dockerfile/test/sanity/Dockerfile
index 7a8e1c0..f65adf5 100644
--- a/tools/dockerfile/test/sanity/Dockerfile
+++ b/tools/dockerfile/test/sanity/Dockerfile
@@ -98,12 +98,12 @@
 RUN apt-get -y update
 RUN apt-get -y install bazel
 
-# Pin Bazel to 0.4.4
-# Installing Bazel via apt-get first is required before installing 0.4.4 to
+# Pin Bazel to 0.9.0
+# Installing Bazel via apt-get first is required before installing 0.9.0 to
 # allow gRPC to build without errors. See https://github.com/grpc/grpc/issues/10553
-RUN curl -fSsL -O https://github.com/bazelbuild/bazel/releases/download/0.4.4/bazel-0.4.4-installer-linux-x86_64.sh
-RUN chmod +x ./bazel-0.4.4-installer-linux-x86_64.sh
-RUN ./bazel-0.4.4-installer-linux-x86_64.sh
+RUN curl -fSsL -O https://github.com/bazelbuild/bazel/releases/download/0.9.0/bazel-0.9.0-installer-linux-x86_64.sh
+RUN chmod +x ./bazel-0.9.0-installer-linux-x86_64.sh
+RUN ./bazel-0.9.0-installer-linux-x86_64.sh
 
 RUN apt-get update && apt-get -y install wget xz-utils
 RUN wget http://releases.llvm.org/5.0.0/clang+llvm-5.0.0-linux-x86_64-ubuntu14.04.tar.xz
diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index 6873256..eb6700d 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.10.0-dev
+PROJECT_NUMBER         = 1.11.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -875,7 +875,6 @@
 include/grpc/byte_buffer.h \
 include/grpc/byte_buffer_reader.h \
 include/grpc/compression.h \
-include/grpc/compression_ruby.h \
 include/grpc/fork.h \
 include/grpc/grpc.h \
 include/grpc/grpc_posix.h \
@@ -910,28 +909,96 @@
 include/grpc/support/atm_gcc_atomic.h \
 include/grpc/support/atm_gcc_sync.h \
 include/grpc/support/atm_windows.h \
-include/grpc/support/avl.h \
-include/grpc/support/cmdline.h \
 include/grpc/support/cpu.h \
-include/grpc/support/host_port.h \
 include/grpc/support/log.h \
 include/grpc/support/log_windows.h \
 include/grpc/support/port_platform.h \
 include/grpc/support/string_util.h \
-include/grpc/support/subprocess.h \
 include/grpc/support/sync.h \
 include/grpc/support/sync_custom.h \
 include/grpc/support/sync_generic.h \
 include/grpc/support/sync_posix.h \
 include/grpc/support/sync_windows.h \
-include/grpc/support/thd.h \
+include/grpc/support/thd_id.h \
 include/grpc/support/time.h \
-include/grpc/support/tls.h \
-include/grpc/support/tls_gcc.h \
-include/grpc/support/tls_msvc.h \
-include/grpc/support/tls_pthread.h \
-include/grpc/support/useful.h \
-include/grpc/support/workaround_list.h
+include/grpc/support/workaround_list.h \
+include/grpcpp/alarm.h \
+include/grpcpp/channel.h \
+include/grpcpp/client_context.h \
+include/grpcpp/completion_queue.h \
+include/grpcpp/create_channel.h \
+include/grpcpp/create_channel_posix.h \
+include/grpcpp/ext/health_check_service_server_builder_option.h \
+include/grpcpp/generic/async_generic_service.h \
+include/grpcpp/generic/generic_stub.h \
+include/grpcpp/grpcpp.h \
+include/grpcpp/health_check_service_interface.h \
+include/grpcpp/impl/call.h \
+include/grpcpp/impl/channel_argument_option.h \
+include/grpcpp/impl/client_unary_call.h \
+include/grpcpp/impl/codegen/async_stream.h \
+include/grpcpp/impl/codegen/async_unary_call.h \
+include/grpcpp/impl/codegen/byte_buffer.h \
+include/grpcpp/impl/codegen/call.h \
+include/grpcpp/impl/codegen/call_hook.h \
+include/grpcpp/impl/codegen/channel_interface.h \
+include/grpcpp/impl/codegen/client_context.h \
+include/grpcpp/impl/codegen/client_unary_call.h \
+include/grpcpp/impl/codegen/completion_queue.h \
+include/grpcpp/impl/codegen/completion_queue_tag.h \
+include/grpcpp/impl/codegen/config.h \
+include/grpcpp/impl/codegen/config_protobuf.h \
+include/grpcpp/impl/codegen/core_codegen.h \
+include/grpcpp/impl/codegen/core_codegen_interface.h \
+include/grpcpp/impl/codegen/create_auth_context.h \
+include/grpcpp/impl/codegen/grpc_library.h \
+include/grpcpp/impl/codegen/metadata_map.h \
+include/grpcpp/impl/codegen/method_handler_impl.h \
+include/grpcpp/impl/codegen/proto_utils.h \
+include/grpcpp/impl/codegen/rpc_method.h \
+include/grpcpp/impl/codegen/rpc_service_method.h \
+include/grpcpp/impl/codegen/security/auth_context.h \
+include/grpcpp/impl/codegen/serialization_traits.h \
+include/grpcpp/impl/codegen/server_context.h \
+include/grpcpp/impl/codegen/server_interface.h \
+include/grpcpp/impl/codegen/service_type.h \
+include/grpcpp/impl/codegen/slice.h \
+include/grpcpp/impl/codegen/status.h \
+include/grpcpp/impl/codegen/status_code_enum.h \
+include/grpcpp/impl/codegen/string_ref.h \
+include/grpcpp/impl/codegen/stub_options.h \
+include/grpcpp/impl/codegen/sync_stream.h \
+include/grpcpp/impl/codegen/time.h \
+include/grpcpp/impl/grpc_library.h \
+include/grpcpp/impl/method_handler_impl.h \
+include/grpcpp/impl/rpc_method.h \
+include/grpcpp/impl/rpc_service_method.h \
+include/grpcpp/impl/serialization_traits.h \
+include/grpcpp/impl/server_builder_option.h \
+include/grpcpp/impl/server_builder_plugin.h \
+include/grpcpp/impl/server_initializer.h \
+include/grpcpp/impl/service_type.h \
+include/grpcpp/resource_quota.h \
+include/grpcpp/security/auth_context.h \
+include/grpcpp/security/auth_metadata_processor.h \
+include/grpcpp/security/credentials.h \
+include/grpcpp/security/server_credentials.h \
+include/grpcpp/server.h \
+include/grpcpp/server_builder.h \
+include/grpcpp/server_context.h \
+include/grpcpp/server_posix.h \
+include/grpcpp/support/async_stream.h \
+include/grpcpp/support/async_unary_call.h \
+include/grpcpp/support/byte_buffer.h \
+include/grpcpp/support/channel_arguments.h \
+include/grpcpp/support/config.h \
+include/grpcpp/support/slice.h \
+include/grpcpp/support/status.h \
+include/grpcpp/support/status_code_enum.h \
+include/grpcpp/support/string_ref.h \
+include/grpcpp/support/stub_options.h \
+include/grpcpp/support/sync_stream.h \
+include/grpcpp/support/time.h
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 0ffbe9f..52a16d6 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.10.0-dev
+PROJECT_NUMBER         = 1.11.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -876,7 +876,6 @@
 include/grpc/byte_buffer.h \
 include/grpc/byte_buffer_reader.h \
 include/grpc/compression.h \
-include/grpc/compression_ruby.h \
 include/grpc/fork.h \
 include/grpc/grpc.h \
 include/grpc/grpc_posix.h \
@@ -911,38 +910,111 @@
 include/grpc/support/atm_gcc_atomic.h \
 include/grpc/support/atm_gcc_sync.h \
 include/grpc/support/atm_windows.h \
-include/grpc/support/avl.h \
-include/grpc/support/cmdline.h \
 include/grpc/support/cpu.h \
-include/grpc/support/host_port.h \
 include/grpc/support/log.h \
 include/grpc/support/log_windows.h \
 include/grpc/support/port_platform.h \
 include/grpc/support/string_util.h \
-include/grpc/support/subprocess.h \
 include/grpc/support/sync.h \
 include/grpc/support/sync_custom.h \
 include/grpc/support/sync_generic.h \
 include/grpc/support/sync_posix.h \
 include/grpc/support/sync_windows.h \
-include/grpc/support/thd.h \
+include/grpc/support/thd_id.h \
 include/grpc/support/time.h \
-include/grpc/support/tls.h \
-include/grpc/support/tls_gcc.h \
-include/grpc/support/tls_msvc.h \
-include/grpc/support/tls_pthread.h \
-include/grpc/support/useful.h \
 include/grpc/support/workaround_list.h \
+include/grpcpp/alarm.h \
+include/grpcpp/channel.h \
+include/grpcpp/client_context.h \
+include/grpcpp/completion_queue.h \
+include/grpcpp/create_channel.h \
+include/grpcpp/create_channel_posix.h \
+include/grpcpp/ext/health_check_service_server_builder_option.h \
+include/grpcpp/generic/async_generic_service.h \
+include/grpcpp/generic/generic_stub.h \
+include/grpcpp/grpcpp.h \
+include/grpcpp/health_check_service_interface.h \
+include/grpcpp/impl/call.h \
+include/grpcpp/impl/channel_argument_option.h \
+include/grpcpp/impl/client_unary_call.h \
+include/grpcpp/impl/codegen/async_stream.h \
+include/grpcpp/impl/codegen/async_unary_call.h \
+include/grpcpp/impl/codegen/byte_buffer.h \
+include/grpcpp/impl/codegen/call.h \
+include/grpcpp/impl/codegen/call_hook.h \
+include/grpcpp/impl/codegen/channel_interface.h \
+include/grpcpp/impl/codegen/client_context.h \
+include/grpcpp/impl/codegen/client_unary_call.h \
+include/grpcpp/impl/codegen/completion_queue.h \
+include/grpcpp/impl/codegen/completion_queue_tag.h \
+include/grpcpp/impl/codegen/config.h \
+include/grpcpp/impl/codegen/config_protobuf.h \
+include/grpcpp/impl/codegen/core_codegen.h \
+include/grpcpp/impl/codegen/core_codegen.h \
+include/grpcpp/impl/codegen/core_codegen_interface.h \
+include/grpcpp/impl/codegen/create_auth_context.h \
+include/grpcpp/impl/codegen/grpc_library.h \
+include/grpcpp/impl/codegen/metadata_map.h \
+include/grpcpp/impl/codegen/method_handler_impl.h \
+include/grpcpp/impl/codegen/proto_utils.h \
+include/grpcpp/impl/codegen/rpc_method.h \
+include/grpcpp/impl/codegen/rpc_service_method.h \
+include/grpcpp/impl/codegen/security/auth_context.h \
+include/grpcpp/impl/codegen/serialization_traits.h \
+include/grpcpp/impl/codegen/server_context.h \
+include/grpcpp/impl/codegen/server_interface.h \
+include/grpcpp/impl/codegen/service_type.h \
+include/grpcpp/impl/codegen/slice.h \
+include/grpcpp/impl/codegen/status.h \
+include/grpcpp/impl/codegen/status_code_enum.h \
+include/grpcpp/impl/codegen/string_ref.h \
+include/grpcpp/impl/codegen/stub_options.h \
+include/grpcpp/impl/codegen/sync_stream.h \
+include/grpcpp/impl/codegen/time.h \
+include/grpcpp/impl/grpc_library.h \
+include/grpcpp/impl/method_handler_impl.h \
+include/grpcpp/impl/rpc_method.h \
+include/grpcpp/impl/rpc_service_method.h \
+include/grpcpp/impl/serialization_traits.h \
+include/grpcpp/impl/server_builder_option.h \
+include/grpcpp/impl/server_builder_plugin.h \
+include/grpcpp/impl/server_initializer.h \
+include/grpcpp/impl/service_type.h \
+include/grpcpp/resource_quota.h \
+include/grpcpp/security/auth_context.h \
+include/grpcpp/security/auth_metadata_processor.h \
+include/grpcpp/security/credentials.h \
+include/grpcpp/security/server_credentials.h \
+include/grpcpp/server.h \
+include/grpcpp/server_builder.h \
+include/grpcpp/server_context.h \
+include/grpcpp/server_posix.h \
+include/grpcpp/support/async_stream.h \
+include/grpcpp/support/async_unary_call.h \
+include/grpcpp/support/byte_buffer.h \
+include/grpcpp/support/channel_arguments.h \
+include/grpcpp/support/config.h \
+include/grpcpp/support/slice.h \
+include/grpcpp/support/status.h \
+include/grpcpp/support/status_code_enum.h \
+include/grpcpp/support/string_ref.h \
+include/grpcpp/support/stub_options.h \
+include/grpcpp/support/sync_stream.h \
+include/grpcpp/support/time.h \
 src/core/ext/transport/inproc/inproc_transport.h \
+src/core/lib/avl/avl.h \
 src/core/lib/backoff/backoff.h \
 src/core/lib/channel/channel_args.h \
 src/core/lib/channel/channel_stack.h \
 src/core/lib/channel/channel_stack_builder.h \
+src/core/lib/channel/channel_trace.h \
+src/core/lib/channel/channel_trace_registry.h \
 src/core/lib/channel/connected_channel.h \
 src/core/lib/channel/context.h \
 src/core/lib/channel/handshaker.h \
 src/core/lib/channel/handshaker_factory.h \
 src/core/lib/channel/handshaker_registry.h \
+src/core/lib/channel/status_util.h \
 src/core/lib/compression/algorithm_metadata.h \
 src/core/lib/compression/compression_internal.h \
 src/core/lib/compression/message_compress.h \
@@ -955,14 +1027,19 @@
 src/core/lib/gpr/arena.h \
 src/core/lib/gpr/env.h \
 src/core/lib/gpr/fork.h \
+src/core/lib/gpr/host_port.h \
 src/core/lib/gpr/mpscq.h \
 src/core/lib/gpr/murmur_hash.h \
 src/core/lib/gpr/spinlock.h \
 src/core/lib/gpr/string.h \
 src/core/lib/gpr/string_windows.h \
-src/core/lib/gpr/thd_internal.h \
 src/core/lib/gpr/time_precise.h \
+src/core/lib/gpr/tls.h \
+src/core/lib/gpr/tls_gcc.h \
+src/core/lib/gpr/tls_msvc.h \
+src/core/lib/gpr/tls_pthread.h \
 src/core/lib/gpr/tmpfile.h \
+src/core/lib/gpr/useful.h \
 src/core/lib/gprpp/abstract.h \
 src/core/lib/gprpp/atomic.h \
 src/core/lib/gprpp/atomic_with_atm.h \
@@ -974,6 +1051,7 @@
 src/core/lib/gprpp/orphanable.h \
 src/core/lib/gprpp/ref_counted.h \
 src/core/lib/gprpp/ref_counted_ptr.h \
+src/core/lib/gprpp/thd.h \
 src/core/lib/http/format_request.h \
 src/core/lib/http/httpcli.h \
 src/core/lib/http/parser.h \
@@ -995,9 +1073,9 @@
 src/core/lib/iomgr/gethostname.h \
 src/core/lib/iomgr/iocp_windows.h \
 src/core/lib/iomgr/iomgr.h \
+src/core/lib/iomgr/iomgr_custom.h \
 src/core/lib/iomgr/iomgr_internal.h \
 src/core/lib/iomgr/iomgr_posix.h \
-src/core/lib/iomgr/iomgr_uv.h \
 src/core/lib/iomgr/is_epollexclusive_available.h \
 src/core/lib/iomgr/load_file.h \
 src/core/lib/iomgr/lockfree_event.h \
@@ -1005,14 +1083,17 @@
 src/core/lib/iomgr/network_status_tracker.h \
 src/core/lib/iomgr/polling_entity.h \
 src/core/lib/iomgr/pollset.h \
+src/core/lib/iomgr/pollset_custom.h \
 src/core/lib/iomgr/pollset_set.h \
+src/core/lib/iomgr/pollset_set_custom.h \
 src/core/lib/iomgr/pollset_set_windows.h \
-src/core/lib/iomgr/pollset_uv.h \
 src/core/lib/iomgr/pollset_windows.h \
 src/core/lib/iomgr/port.h \
 src/core/lib/iomgr/resolve_address.h \
+src/core/lib/iomgr/resolve_address_custom.h \
 src/core/lib/iomgr/resource_quota.h \
 src/core/lib/iomgr/sockaddr.h \
+src/core/lib/iomgr/sockaddr_custom.h \
 src/core/lib/iomgr/sockaddr_posix.h \
 src/core/lib/iomgr/sockaddr_utils.h \
 src/core/lib/iomgr/sockaddr_windows.h \
@@ -1024,17 +1105,16 @@
 src/core/lib/iomgr/sys_epoll_wrapper.h \
 src/core/lib/iomgr/tcp_client.h \
 src/core/lib/iomgr/tcp_client_posix.h \
+src/core/lib/iomgr/tcp_custom.h \
 src/core/lib/iomgr/tcp_posix.h \
 src/core/lib/iomgr/tcp_server.h \
 src/core/lib/iomgr/tcp_server_utils_posix.h \
-src/core/lib/iomgr/tcp_uv.h \
 src/core/lib/iomgr/tcp_windows.h \
 src/core/lib/iomgr/time_averaged_stats.h \
 src/core/lib/iomgr/timer.h \
-src/core/lib/iomgr/timer_generic.h \
+src/core/lib/iomgr/timer_custom.h \
 src/core/lib/iomgr/timer_heap.h \
 src/core/lib/iomgr/timer_manager.h \
-src/core/lib/iomgr/timer_uv.h \
 src/core/lib/iomgr/udp_server.h \
 src/core/lib/iomgr/unix_sockets_posix.h \
 src/core/lib/iomgr/wakeup_fd_cv.h \
@@ -1050,6 +1130,7 @@
 src/core/lib/slice/slice_hash_table.h \
 src/core/lib/slice/slice_internal.h \
 src/core/lib/slice/slice_string_helpers.h \
+src/core/lib/slice/slice_weak_hash_table.h \
 src/core/lib/surface/api_trace.h \
 src/core/lib/surface/call.h \
 src/core/lib/surface/call_test_only.h \
@@ -1074,6 +1155,7 @@
 src/core/lib/transport/service_config.h \
 src/core/lib/transport/static_metadata.h \
 src/core/lib/transport/status_conversion.h \
+src/core/lib/transport/status_metadata.h \
 src/core/lib/transport/timeout_encoding.h \
 src/core/lib/transport/transport.h \
 src/core/lib/transport/transport_impl.h \
diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core
index b289660..04f9d78 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -801,7 +801,6 @@
 include/grpc/byte_buffer_reader.h \
 include/grpc/census.h \
 include/grpc/compression.h \
-include/grpc/compression_ruby.h \
 include/grpc/fork.h \
 include/grpc/grpc.h \
 include/grpc/grpc_posix.h \
@@ -850,27 +849,18 @@
 include/grpc/support/atm_gcc_atomic.h \
 include/grpc/support/atm_gcc_sync.h \
 include/grpc/support/atm_windows.h \
-include/grpc/support/avl.h \
-include/grpc/support/cmdline.h \
 include/grpc/support/cpu.h \
-include/grpc/support/host_port.h \
 include/grpc/support/log.h \
 include/grpc/support/log_windows.h \
 include/grpc/support/port_platform.h \
 include/grpc/support/string_util.h \
-include/grpc/support/subprocess.h \
 include/grpc/support/sync.h \
 include/grpc/support/sync_custom.h \
 include/grpc/support/sync_generic.h \
 include/grpc/support/sync_posix.h \
 include/grpc/support/sync_windows.h \
-include/grpc/support/thd.h \
+include/grpc/support/thd_id.h \
 include/grpc/support/time.h \
-include/grpc/support/tls.h \
-include/grpc/support/tls_gcc.h \
-include/grpc/support/tls_msvc.h \
-include/grpc/support/tls_pthread.h \
-include/grpc/support/useful.h \
 include/grpc/support/workaround_list.h
 
 # This tag can be used to specify the character encoding of the source files
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 90ba2a7..85675e9 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -801,7 +801,6 @@
 include/grpc/byte_buffer_reader.h \
 include/grpc/census.h \
 include/grpc/compression.h \
-include/grpc/compression_ruby.h \
 include/grpc/fork.h \
 include/grpc/grpc.h \
 include/grpc/grpc_posix.h \
@@ -850,27 +849,18 @@
 include/grpc/support/atm_gcc_atomic.h \
 include/grpc/support/atm_gcc_sync.h \
 include/grpc/support/atm_windows.h \
-include/grpc/support/avl.h \
-include/grpc/support/cmdline.h \
 include/grpc/support/cpu.h \
-include/grpc/support/host_port.h \
 include/grpc/support/log.h \
 include/grpc/support/log_windows.h \
 include/grpc/support/port_platform.h \
 include/grpc/support/string_util.h \
-include/grpc/support/subprocess.h \
 include/grpc/support/sync.h \
 include/grpc/support/sync_custom.h \
 include/grpc/support/sync_generic.h \
 include/grpc/support/sync_posix.h \
 include/grpc/support/sync_windows.h \
-include/grpc/support/thd.h \
+include/grpc/support/thd_id.h \
 include/grpc/support/time.h \
-include/grpc/support/tls.h \
-include/grpc/support/tls_gcc.h \
-include/grpc/support/tls_msvc.h \
-include/grpc/support/tls_pthread.h \
-include/grpc/support/useful.h \
 include/grpc/support/workaround_list.h \
 src/core/README.md \
 src/core/ext/README.md \
@@ -895,7 +885,6 @@
 src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc \
 src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h \
 src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc \
-src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h \
 src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h \
 src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc \
 src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc \
@@ -912,6 +901,8 @@
 src/core/ext/filters/client_channel/lb_policy_factory.h \
 src/core/ext/filters/client_channel/lb_policy_registry.cc \
 src/core/ext/filters/client_channel/lb_policy_registry.h \
+src/core/ext/filters/client_channel/method_params.cc \
+src/core/ext/filters/client_channel/method_params.h \
 src/core/ext/filters/client_channel/parse_address.cc \
 src/core/ext/filters/client_channel/parse_address.h \
 src/core/ext/filters/client_channel/proxy_mapper.cc \
@@ -933,7 +924,6 @@
 src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h \
 src/core/ext/filters/client_channel/resolver/sockaddr/README.md \
 src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \
-src/core/ext/filters/client_channel/resolver_factory.cc \
 src/core/ext/filters/client_channel/resolver_factory.h \
 src/core/ext/filters/client_channel/resolver_registry.cc \
 src/core/ext/filters/client_channel/resolver_registry.h \
@@ -1031,6 +1021,8 @@
 src/core/ext/transport/inproc/inproc_transport.cc \
 src/core/ext/transport/inproc/inproc_transport.h \
 src/core/lib/README.md \
+src/core/lib/avl/avl.cc \
+src/core/lib/avl/avl.h \
 src/core/lib/backoff/backoff.cc \
 src/core/lib/backoff/backoff.h \
 src/core/lib/channel/README.md \
@@ -1040,6 +1032,10 @@
 src/core/lib/channel/channel_stack.h \
 src/core/lib/channel/channel_stack_builder.cc \
 src/core/lib/channel/channel_stack_builder.h \
+src/core/lib/channel/channel_trace.cc \
+src/core/lib/channel/channel_trace.h \
+src/core/lib/channel/channel_trace_registry.cc \
+src/core/lib/channel/channel_trace_registry.h \
 src/core/lib/channel/connected_channel.cc \
 src/core/lib/channel/connected_channel.h \
 src/core/lib/channel/context.h \
@@ -1049,11 +1045,12 @@
 src/core/lib/channel/handshaker_factory.h \
 src/core/lib/channel/handshaker_registry.cc \
 src/core/lib/channel/handshaker_registry.h \
+src/core/lib/channel/status_util.cc \
+src/core/lib/channel/status_util.h \
 src/core/lib/compression/algorithm_metadata.h \
 src/core/lib/compression/compression.cc \
 src/core/lib/compression/compression_internal.cc \
 src/core/lib/compression/compression_internal.h \
-src/core/lib/compression/compression_ruby.cc \
 src/core/lib/compression/message_compress.cc \
 src/core/lib/compression/message_compress.h \
 src/core/lib/compression/stream_compression.cc \
@@ -1073,8 +1070,6 @@
 src/core/lib/gpr/arena.cc \
 src/core/lib/gpr/arena.h \
 src/core/lib/gpr/atm.cc \
-src/core/lib/gpr/avl.cc \
-src/core/lib/gpr/cmdline.cc \
 src/core/lib/gpr/cpu_iphone.cc \
 src/core/lib/gpr/cpu_linux.cc \
 src/core/lib/gpr/cpu_posix.cc \
@@ -1086,6 +1081,7 @@
 src/core/lib/gpr/fork.cc \
 src/core/lib/gpr/fork.h \
 src/core/lib/gpr/host_port.cc \
+src/core/lib/gpr/host_port.h \
 src/core/lib/gpr/log.cc \
 src/core/lib/gpr/log_android.cc \
 src/core/lib/gpr/log_linux.cc \
@@ -1102,25 +1098,24 @@
 src/core/lib/gpr/string_util_windows.cc \
 src/core/lib/gpr/string_windows.cc \
 src/core/lib/gpr/string_windows.h \
-src/core/lib/gpr/subprocess_posix.cc \
-src/core/lib/gpr/subprocess_windows.cc \
 src/core/lib/gpr/sync.cc \
 src/core/lib/gpr/sync_posix.cc \
 src/core/lib/gpr/sync_windows.cc \
-src/core/lib/gpr/thd.cc \
-src/core/lib/gpr/thd_internal.h \
-src/core/lib/gpr/thd_posix.cc \
-src/core/lib/gpr/thd_windows.cc \
 src/core/lib/gpr/time.cc \
 src/core/lib/gpr/time_posix.cc \
 src/core/lib/gpr/time_precise.cc \
 src/core/lib/gpr/time_precise.h \
 src/core/lib/gpr/time_windows.cc \
+src/core/lib/gpr/tls.h \
+src/core/lib/gpr/tls_gcc.h \
+src/core/lib/gpr/tls_msvc.h \
 src/core/lib/gpr/tls_pthread.cc \
+src/core/lib/gpr/tls_pthread.h \
 src/core/lib/gpr/tmpfile.h \
 src/core/lib/gpr/tmpfile_msys.cc \
 src/core/lib/gpr/tmpfile_posix.cc \
 src/core/lib/gpr/tmpfile_windows.cc \
+src/core/lib/gpr/useful.h \
 src/core/lib/gpr/wrap_memcpy.cc \
 src/core/lib/gprpp/README.md \
 src/core/lib/gprpp/abstract.h \
@@ -1134,6 +1129,9 @@
 src/core/lib/gprpp/orphanable.h \
 src/core/lib/gprpp/ref_counted.h \
 src/core/lib/gprpp/ref_counted_ptr.h \
+src/core/lib/gprpp/thd.h \
+src/core/lib/gprpp/thd_posix.cc \
+src/core/lib/gprpp/thd_windows.cc \
 src/core/lib/http/format_request.cc \
 src/core/lib/http/format_request.h \
 src/core/lib/http/httpcli.cc \
@@ -1182,11 +1180,13 @@
 src/core/lib/iomgr/iocp_windows.h \
 src/core/lib/iomgr/iomgr.cc \
 src/core/lib/iomgr/iomgr.h \
+src/core/lib/iomgr/iomgr_custom.cc \
+src/core/lib/iomgr/iomgr_custom.h \
+src/core/lib/iomgr/iomgr_internal.cc \
 src/core/lib/iomgr/iomgr_internal.h \
 src/core/lib/iomgr/iomgr_posix.cc \
 src/core/lib/iomgr/iomgr_posix.h \
 src/core/lib/iomgr/iomgr_uv.cc \
-src/core/lib/iomgr/iomgr_uv.h \
 src/core/lib/iomgr/iomgr_windows.cc \
 src/core/lib/iomgr/is_epollexclusive_available.cc \
 src/core/lib/iomgr/is_epollexclusive_available.h \
@@ -1199,23 +1199,30 @@
 src/core/lib/iomgr/network_status_tracker.h \
 src/core/lib/iomgr/polling_entity.cc \
 src/core/lib/iomgr/polling_entity.h \
+src/core/lib/iomgr/pollset.cc \
 src/core/lib/iomgr/pollset.h \
+src/core/lib/iomgr/pollset_custom.cc \
+src/core/lib/iomgr/pollset_custom.h \
+src/core/lib/iomgr/pollset_set.cc \
 src/core/lib/iomgr/pollset_set.h \
-src/core/lib/iomgr/pollset_set_uv.cc \
+src/core/lib/iomgr/pollset_set_custom.cc \
+src/core/lib/iomgr/pollset_set_custom.h \
 src/core/lib/iomgr/pollset_set_windows.cc \
 src/core/lib/iomgr/pollset_set_windows.h \
 src/core/lib/iomgr/pollset_uv.cc \
-src/core/lib/iomgr/pollset_uv.h \
 src/core/lib/iomgr/pollset_windows.cc \
 src/core/lib/iomgr/pollset_windows.h \
 src/core/lib/iomgr/port.h \
+src/core/lib/iomgr/resolve_address.cc \
 src/core/lib/iomgr/resolve_address.h \
+src/core/lib/iomgr/resolve_address_custom.cc \
+src/core/lib/iomgr/resolve_address_custom.h \
 src/core/lib/iomgr/resolve_address_posix.cc \
-src/core/lib/iomgr/resolve_address_uv.cc \
 src/core/lib/iomgr/resolve_address_windows.cc \
 src/core/lib/iomgr/resource_quota.cc \
 src/core/lib/iomgr/resource_quota.h \
 src/core/lib/iomgr/sockaddr.h \
+src/core/lib/iomgr/sockaddr_custom.h \
 src/core/lib/iomgr/sockaddr_posix.h \
 src/core/lib/iomgr/sockaddr_utils.cc \
 src/core/lib/iomgr/sockaddr_utils.h \
@@ -1234,36 +1241,40 @@
 src/core/lib/iomgr/socket_windows.cc \
 src/core/lib/iomgr/socket_windows.h \
 src/core/lib/iomgr/sys_epoll_wrapper.h \
+src/core/lib/iomgr/tcp_client.cc \
 src/core/lib/iomgr/tcp_client.h \
+src/core/lib/iomgr/tcp_client_custom.cc \
 src/core/lib/iomgr/tcp_client_posix.cc \
 src/core/lib/iomgr/tcp_client_posix.h \
-src/core/lib/iomgr/tcp_client_uv.cc \
 src/core/lib/iomgr/tcp_client_windows.cc \
+src/core/lib/iomgr/tcp_custom.cc \
+src/core/lib/iomgr/tcp_custom.h \
 src/core/lib/iomgr/tcp_posix.cc \
 src/core/lib/iomgr/tcp_posix.h \
+src/core/lib/iomgr/tcp_server.cc \
 src/core/lib/iomgr/tcp_server.h \
+src/core/lib/iomgr/tcp_server_custom.cc \
 src/core/lib/iomgr/tcp_server_posix.cc \
 src/core/lib/iomgr/tcp_server_utils_posix.h \
 src/core/lib/iomgr/tcp_server_utils_posix_common.cc \
 src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc \
 src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc \
-src/core/lib/iomgr/tcp_server_uv.cc \
 src/core/lib/iomgr/tcp_server_windows.cc \
 src/core/lib/iomgr/tcp_uv.cc \
-src/core/lib/iomgr/tcp_uv.h \
 src/core/lib/iomgr/tcp_windows.cc \
 src/core/lib/iomgr/tcp_windows.h \
 src/core/lib/iomgr/time_averaged_stats.cc \
 src/core/lib/iomgr/time_averaged_stats.h \
+src/core/lib/iomgr/timer.cc \
 src/core/lib/iomgr/timer.h \
+src/core/lib/iomgr/timer_custom.cc \
+src/core/lib/iomgr/timer_custom.h \
 src/core/lib/iomgr/timer_generic.cc \
-src/core/lib/iomgr/timer_generic.h \
 src/core/lib/iomgr/timer_heap.cc \
 src/core/lib/iomgr/timer_heap.h \
 src/core/lib/iomgr/timer_manager.cc \
 src/core/lib/iomgr/timer_manager.h \
 src/core/lib/iomgr/timer_uv.cc \
-src/core/lib/iomgr/timer_uv.h \
 src/core/lib/iomgr/udp_server.cc \
 src/core/lib/iomgr/udp_server.h \
 src/core/lib/iomgr/unix_sockets_posix.cc \
@@ -1290,6 +1301,17 @@
 src/core/lib/profiling/timers.h \
 src/core/lib/security/context/security_context.cc \
 src/core/lib/security/context/security_context.h \
+src/core/lib/security/credentials/alts/alts_credentials.cc \
+src/core/lib/security/credentials/alts/alts_credentials.h \
+src/core/lib/security/credentials/alts/check_gcp_environment.cc \
+src/core/lib/security/credentials/alts/check_gcp_environment.h \
+src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc \
+src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc \
+src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc \
+src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc \
+src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc \
+src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h \
+src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc \
 src/core/lib/security/credentials/composite/composite_credentials.cc \
 src/core/lib/security/credentials/composite/composite_credentials.h \
 src/core/lib/security/credentials/credentials.cc \
@@ -1314,17 +1336,19 @@
 src/core/lib/security/credentials/plugin/plugin_credentials.h \
 src/core/lib/security/credentials/ssl/ssl_credentials.cc \
 src/core/lib/security/credentials/ssl/ssl_credentials.h \
+src/core/lib/security/security_connector/alts_security_connector.cc \
+src/core/lib/security/security_connector/alts_security_connector.h \
+src/core/lib/security/security_connector/security_connector.cc \
+src/core/lib/security/security_connector/security_connector.h \
 src/core/lib/security/transport/auth_filters.h \
 src/core/lib/security/transport/client_auth_filter.cc \
-src/core/lib/security/transport/lb_targets_info.cc \
-src/core/lib/security/transport/lb_targets_info.h \
 src/core/lib/security/transport/secure_endpoint.cc \
 src/core/lib/security/transport/secure_endpoint.h \
-src/core/lib/security/transport/security_connector.cc \
-src/core/lib/security/transport/security_connector.h \
 src/core/lib/security/transport/security_handshaker.cc \
 src/core/lib/security/transport/security_handshaker.h \
 src/core/lib/security/transport/server_auth_filter.cc \
+src/core/lib/security/transport/target_authority_table.cc \
+src/core/lib/security/transport/target_authority_table.h \
 src/core/lib/security/transport/tsi_error.cc \
 src/core/lib/security/transport/tsi_error.h \
 src/core/lib/security/util/json_util.cc \
@@ -1335,12 +1359,12 @@
 src/core/lib/slice/percent_encoding.h \
 src/core/lib/slice/slice.cc \
 src/core/lib/slice/slice_buffer.cc \
-src/core/lib/slice/slice_hash_table.cc \
 src/core/lib/slice/slice_hash_table.h \
 src/core/lib/slice/slice_intern.cc \
 src/core/lib/slice/slice_internal.h \
 src/core/lib/slice/slice_string_helpers.cc \
 src/core/lib/slice/slice_string_helpers.h \
+src/core/lib/slice/slice_weak_hash_table.h \
 src/core/lib/surface/README.md \
 src/core/lib/surface/api_trace.cc \
 src/core/lib/surface/api_trace.h \
@@ -1397,6 +1421,8 @@
 src/core/lib/transport/static_metadata.h \
 src/core/lib/transport/status_conversion.cc \
 src/core/lib/transport/status_conversion.h \
+src/core/lib/transport/status_metadata.cc \
+src/core/lib/transport/status_metadata.h \
 src/core/lib/transport/timeout_encoding.cc \
 src/core/lib/transport/timeout_encoding.h \
 src/core/lib/transport/transport.cc \
@@ -1405,10 +1431,62 @@
 src/core/lib/transport/transport_op_string.cc \
 src/core/plugin_registry/grpc_plugin_registry.cc \
 src/core/tsi/README.md \
+src/core/tsi/alts/crypt/aes_gcm.cc \
+src/core/tsi/alts/crypt/gsec.cc \
+src/core/tsi/alts/crypt/gsec.h \
+src/core/tsi/alts/frame_protector/alts_counter.cc \
+src/core/tsi/alts/frame_protector/alts_counter.h \
+src/core/tsi/alts/frame_protector/alts_crypter.cc \
+src/core/tsi/alts/frame_protector/alts_crypter.h \
+src/core/tsi/alts/frame_protector/alts_frame_protector.cc \
+src/core/tsi/alts/frame_protector/alts_frame_protector.h \
+src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc \
+src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h \
+src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc \
+src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc \
+src/core/tsi/alts/frame_protector/frame_handler.cc \
+src/core/tsi/alts/frame_protector/frame_handler.h \
+src/core/tsi/alts/handshaker/alts_handshaker_client.cc \
+src/core/tsi/alts/handshaker/alts_handshaker_client.h \
+src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc \
+src/core/tsi/alts/handshaker/alts_handshaker_service_api.h \
+src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc \
+src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h \
+src/core/tsi/alts/handshaker/alts_tsi_event.cc \
+src/core/tsi/alts/handshaker/alts_tsi_event.h \
+src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc \
+src/core/tsi/alts/handshaker/alts_tsi_handshaker.h \
+src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h \
+src/core/tsi/alts/handshaker/alts_tsi_utils.cc \
+src/core/tsi/alts/handshaker/alts_tsi_utils.h \
+src/core/tsi/alts/handshaker/altscontext.pb.c \
+src/core/tsi/alts/handshaker/altscontext.pb.h \
+src/core/tsi/alts/handshaker/handshaker.pb.c \
+src/core/tsi/alts/handshaker/handshaker.pb.h \
+src/core/tsi/alts/handshaker/transport_security_common.pb.c \
+src/core/tsi/alts/handshaker/transport_security_common.pb.h \
+src/core/tsi/alts/handshaker/transport_security_common_api.cc \
+src/core/tsi/alts/handshaker/transport_security_common_api.h \
+src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc \
+src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h \
+src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc \
+src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h \
+src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h \
+src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc \
+src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h \
+src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc \
+src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h \
+src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc \
+src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h \
 src/core/tsi/alts_transport_security.cc \
 src/core/tsi/alts_transport_security.h \
 src/core/tsi/fake_transport_security.cc \
 src/core/tsi/fake_transport_security.h \
+src/core/tsi/ssl/session_cache/ssl_session.h \
+src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc \
+src/core/tsi/ssl/session_cache/ssl_session_cache.cc \
+src/core/tsi/ssl/session_cache/ssl_session_cache.h \
+src/core/tsi/ssl/session_cache/ssl_session_openssl.cc \
 src/core/tsi/ssl_transport_security.cc \
 src/core/tsi/ssl_transport_security.h \
 src/core/tsi/ssl_types.h \
diff --git a/tools/gce/create_interop_worker.sh b/tools/gce/create_interop_worker.sh
index 3e59dc5..205c0bf 100755
--- a/tools/gce/create_interop_worker.sh
+++ b/tools/gce/create_interop_worker.sh
@@ -20,14 +20,14 @@
 
 set -ex
 
-cd $(dirname $0)
+cd "$(dirname "$0")"
 
 CLOUD_PROJECT=grpc-testing
 ZONE=us-east1-a  # canary gateway is reachable from this zone
 
 INSTANCE_NAME="${1:-grpc-canary-interop2}"
 
-gcloud compute instances create $INSTANCE_NAME \
+gcloud compute instances create "$INSTANCE_NAME" \
     --project="$CLOUD_PROJECT" \
     --zone "$ZONE" \
     --machine-type n1-standard-16 \
@@ -42,9 +42,9 @@
 gcloud compute copy-files \
     --project="$CLOUD_PROJECT" \
     --zone "$ZONE" \
-    jenkins_master.pub linux_worker_init.sh ${INSTANCE_NAME}:~
+    jenkins_master.pub linux_worker_init.sh "${INSTANCE_NAME}":~
 
 gcloud compute ssh \
     --project="$CLOUD_PROJECT" \
     --zone "$ZONE" \
-    $INSTANCE_NAME --command "./linux_worker_init.sh"
+    "$INSTANCE_NAME" --command "./linux_worker_init.sh"
diff --git a/tools/gce/create_linux_kokoro_performance_worker.sh b/tools/gce/create_linux_kokoro_performance_worker.sh
index a25cc5b..d08a1aa 100755
--- a/tools/gce/create_linux_kokoro_performance_worker.sh
+++ b/tools/gce/create_linux_kokoro_performance_worker.sh
@@ -17,7 +17,7 @@
 
 set -ex
 
-cd $(dirname $0)
+cd "$(dirname "$0")"
 
 CLOUD_PROJECT=grpc-testing
 ZONE=us-central1-b  # this zone allows 32core machines
@@ -25,7 +25,7 @@
 INSTANCE_NAME="${1:-grpc-kokoro-performance-server1}"
 MACHINE_TYPE=n1-standard-32
 
-gcloud compute instances create $INSTANCE_NAME \
+gcloud compute instances create "$INSTANCE_NAME" \
     --project="$CLOUD_PROJECT" \
     --zone "$ZONE" \
     --machine-type $MACHINE_TYPE \
@@ -41,9 +41,9 @@
 gcloud compute copy-files \
     --project="$CLOUD_PROJECT" \
     --zone "$ZONE" \
-    kokoro_performance.pub linux_kokoro_performance_worker_init.sh kbuilder@${INSTANCE_NAME}:~
+    kokoro_performance.pub linux_kokoro_performance_worker_init.sh "kbuilder@${INSTANCE_NAME}":~
 
 gcloud compute ssh \
     --project="$CLOUD_PROJECT" \
     --zone "$ZONE" \
-    kbuilder@${INSTANCE_NAME} --command "./linux_kokoro_performance_worker_init.sh"
+    "kbuilder@${INSTANCE_NAME}" --command "./linux_kokoro_performance_worker_init.sh"
diff --git a/tools/gce/create_linux_performance_worker.sh b/tools/gce/create_linux_performance_worker.sh
index e3bc1d5..e9033ec 100755
--- a/tools/gce/create_linux_performance_worker.sh
+++ b/tools/gce/create_linux_performance_worker.sh
@@ -21,7 +21,7 @@
 
 set -ex
 
-cd $(dirname $0)
+cd "$(dirname "$0")"
 
 CLOUD_PROJECT=grpc-testing
 ZONE=us-central1-b  # this zone allows 32core machines
@@ -29,7 +29,7 @@
 INSTANCE_NAME="${1:-grpc-performance-server1}"
 MACHINE_TYPE=n1-standard-32
 
-gcloud compute instances create $INSTANCE_NAME \
+gcloud compute instances create "$INSTANCE_NAME" \
     --project="$CLOUD_PROJECT" \
     --zone "$ZONE" \
     --machine-type $MACHINE_TYPE \
@@ -45,9 +45,9 @@
 gcloud compute copy-files \
     --project="$CLOUD_PROJECT" \
     --zone "$ZONE" \
-    jenkins_master.pub linux_performance_worker_init.sh jenkins@${INSTANCE_NAME}:~
+    jenkins_master.pub linux_performance_worker_init.sh "jenkins@${INSTANCE_NAME}":~
 
 gcloud compute ssh \
     --project="$CLOUD_PROJECT" \
     --zone "$ZONE" \
-    jenkins@${INSTANCE_NAME} --command "./linux_performance_worker_init.sh"
+    "jenkins@${INSTANCE_NAME}" --command "./linux_performance_worker_init.sh"
diff --git a/tools/gce/create_linux_worker.sh b/tools/gce/create_linux_worker.sh
index 8bf44aa..a93d8c5 100755
--- a/tools/gce/create_linux_worker.sh
+++ b/tools/gce/create_linux_worker.sh
@@ -17,14 +17,14 @@
 
 set -ex
 
-cd $(dirname $0)
+cd "$(dirname "$0")"
 
 CLOUD_PROJECT=grpc-testing
 ZONE=us-central1-a
 
 INSTANCE_NAME="${1:-grpc-jenkins-worker1}"
 
-gcloud compute instances create $INSTANCE_NAME \
+gcloud compute instances create "$INSTANCE_NAME" \
     --project="$CLOUD_PROJECT" \
     --zone "$ZONE" \
     --machine-type n1-standard-16 \
@@ -40,9 +40,9 @@
 gcloud compute copy-files \
     --project="$CLOUD_PROJECT" \
     --zone "$ZONE" \
-    jenkins_master.pub linux_worker_init.sh ${INSTANCE_NAME}:~
+    jenkins_master.pub linux_worker_init.sh "${INSTANCE_NAME}":~
 
 gcloud compute ssh \
     --project="$CLOUD_PROJECT" \
     --zone "$ZONE" \
-    $INSTANCE_NAME --command "./linux_worker_init.sh"
+    "$INSTANCE_NAME" --command "./linux_worker_init.sh"
diff --git a/tools/gce/create_windows_debug_worker.sh b/tools/gce/create_windows_debug_worker.sh
index da8050b..6f903b5 100755
--- a/tools/gce/create_windows_debug_worker.sh
+++ b/tools/gce/create_windows_debug_worker.sh
@@ -19,7 +19,7 @@
 
 set -ex
 
-cd $(dirname $0)
+cd "$(dirname "$0")"
 
 CLOUD_PROJECT=grpc-testing
 ZONE=us-central1-b
@@ -34,7 +34,7 @@
 MACHINE_TYPE=n1-standard-8
 TMP_DISK_NAME="$INSTANCE_NAME-temp-disk"
 
-gcloud compute disks create $TMP_DISK_NAME \
+gcloud compute disks create "$TMP_DISK_NAME" \
     --project="$CLOUD_PROJECT" \
     --zone "$ZONE" \
     --image-project google.com:kokoro \
@@ -44,13 +44,13 @@
 echo 'Created scratch disk, waiting for it to become available.'
 sleep 15
 
-gcloud compute instances create $INSTANCE_NAME \
+gcloud compute instances create "$INSTANCE_NAME" \
     --project="$CLOUD_PROJECT" \
     --zone "$ZONE" \
-    --machine-type $MACHINE_TYPE \
+    --machine-type "$MACHINE_TYPE" \
     --image-project google.com:kokoro \
     --image kokoro-win7build-v9-prod-debug \
     --boot-disk-size 500 \
     --boot-disk-type pd-ssd \
     --tags=allow-ssh \
-    --disk auto-delete=yes,boot=no,name=$TMP_DISK_NAME
+    --disk "auto-delete=yes,boot=no,name=$TMP_DISK_NAME"
diff --git a/tools/gce/linux_kokoro_performance_worker_init.sh b/tools/gce/linux_kokoro_performance_worker_init.sh
index 460f639..1f98d24 100755
--- a/tools/gce/linux_kokoro_performance_worker_init.sh
+++ b/tools/gce/linux_kokoro_performance_worker_init.sh
@@ -81,10 +81,11 @@
 # is not available on Ubuntu 16.10, so install from source
 curl -O https://www.python.org/ftp/python/3.4.6/Python-3.4.6.tgz
 tar xzvf Python-3.4.6.tgz
-cd Python-3.4.6
+(
+cd Python-3.4.6 || exit
 ./configure --enable-shared --prefix=/usr/local LDFLAGS="-Wl,--rpath=/usr/local/lib"
 sudo make altinstall
-cd ..
+)
 rm Python-3.4.6.tgz
 
 curl -O https://bootstrap.pypa.io/get-pip.py
@@ -95,6 +96,8 @@
 # Node dependencies (nvm has to be installed under user kbuilder)
 touch .profile
 curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
+# silence shellcheck as it cannot follow the following `source` path statically:
+# shellcheck disable=SC1090
 source ~/.nvm/nvm.sh
 nvm install 0.12 && npm config set cache /tmp/npm-cache
 nvm install 4 && npm config set cache /tmp/npm-cache
@@ -130,6 +133,8 @@
 # Ruby dependencies
 gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
 curl -sSL https://get.rvm.io | bash -s stable --ruby
+# silence shellcheck as it cannot follow the following `source` path statically:
+# shellcheck disable=SC1090
 source ~/.rvm/scripts/rvm
 
 git clone https://github.com/rbenv/rbenv.git ~/.rbenv
@@ -168,7 +173,7 @@
 rm go$GO_VERSION.$OS-$ARCH.tar.gz
 
 # Install perf, to profile benchmarks. (need to get the right linux-tools-<> for kernel version)
-sudo apt-get install -y linux-tools-common linux-tools-generic linux-tools-`uname -r`
+sudo apt-get install -y linux-tools-common linux-tools-generic "linux-tools-$(uname -r)"
 # see http://unix.stackexchange.com/questions/14227/do-i-need-root-admin-permissions-to-run-userspace-perf-tool-perf-events-ar
 echo 0 | sudo tee /proc/sys/kernel/perf_event_paranoid
 # see http://stackoverflow.com/questions/21284906/perf-couldnt-record-kernel-reference-relocation-symbol
@@ -186,7 +191,9 @@
 sudo apt-get install -y python-scipy python-numpy
 
 # Add pubkey of Kokoro driver VM to allow SSH
-cat kokoro_performance.pub | sudo tee --append ~kbuilder/.ssh/authorized_keys
+# silence false-positive shellcheck warning ("< redirect does not affect sudo")
+# shellcheck disable=SC2024
+sudo tee --append ~kbuilder/.ssh/authorized_keys < kokoro_performance.pub
 
 # Restart for VM to pick up kernel update
 echo 'Successfully initialized the linux worker, going for reboot in 10 seconds'
diff --git a/tools/gce/linux_performance_worker_init.sh b/tools/gce/linux_performance_worker_init.sh
index 8d900f1..6f68660 100755
--- a/tools/gce/linux_performance_worker_init.sh
+++ b/tools/gce/linux_performance_worker_init.sh
@@ -81,10 +81,11 @@
 # is not available on Ubuntu 16.10, so install from source
 curl -O https://www.python.org/ftp/python/3.4.6/Python-3.4.6.tgz
 tar xzvf Python-3.4.6.tgz
-cd Python-3.4.6
+(
+cd Python-3.4.6 || exit
 ./configure --enable-shared --prefix=/usr/local LDFLAGS="-Wl,--rpath=/usr/local/lib"
 sudo make altinstall
-cd ..
+)
 rm Python-3.4.6.tgz
 
 curl -O https://bootstrap.pypa.io/get-pip.py
@@ -95,6 +96,8 @@
 # Node dependencies (nvm has to be installed under user jenkins)
 touch .profile
 curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
+# silence shellcheck warning as it cannot follow the `source` path statically:
+# shellcheck disable=SC1090
 source ~/.nvm/nvm.sh
 nvm install 0.12 && npm config set cache /tmp/npm-cache
 nvm install 4 && npm config set cache /tmp/npm-cache
@@ -151,7 +154,7 @@
 rm go$GO_VERSION.$OS-$ARCH.tar.gz
 
 # Install perf, to profile benchmarks. (need to get the right linux-tools-<> for kernel version)
-sudo apt-get install -y linux-tools-common linux-tools-generic linux-tools-`uname -r`
+sudo apt-get install -y linux-tools-common linux-tools-generic "linux-tools-$(uname -r)"
 # see http://unix.stackexchange.com/questions/14227/do-i-need-root-admin-permissions-to-run-userspace-perf-tool-perf-events-ar
 echo 0 | sudo tee /proc/sys/kernel/perf_event_paranoid
 # see http://stackoverflow.com/questions/21284906/perf-couldnt-record-kernel-reference-relocation-symbol
@@ -171,7 +174,9 @@
 # Add pubkey of jenkins@grpc-jenkins-master to authorized keys of jenkins@
 # This needs to happen as the last step to prevent Jenkins master from connecting
 # to a machine that hasn't been properly setup yet.
-cat jenkins_master.pub | sudo tee --append ~jenkins/.ssh/authorized_keys
+# silence false-positive shellcheck warning ("< redirect does not affect sudo")
+# shellcheck disable=SC2024
+sudo tee --append ~jenkins/.ssh/authorized_keys < jenkins_master.pub
 
 # Restart for VM to pick up kernel update
 echo 'Successfully initialized the linux worker, going for reboot in 10 seconds'
diff --git a/tools/gce/linux_worker_init.sh b/tools/gce/linux_worker_init.sh
index a5d2706..0585535 100755
--- a/tools/gce/linux_worker_init.sh
+++ b/tools/gce/linux_worker_init.sh
@@ -66,7 +66,10 @@
 # Add pubkey of jenkins@grpc-jenkins-master to authorized keys of jenkins@
 # This needs to happen as the last step to prevent Jenkins master from connecting
 # to a machine that hasn't been properly setup yet.
-cat jenkins_master.pub | sudo tee --append ~jenkins/.ssh/authorized_keys
+
+# disable superfluous warning by shellcheck:
+# shellcheck disable=SC2024
+sudo tee --append ~jenkins/.ssh/authorized_keys < jenkins_master.pub
 
 # Restart for docker to pick up the config changes.
 echo 'Successfully initialized the linux worker, going for reboot in 10 seconds'
diff --git a/tools/internal_ci/helper_scripts/prepare_build_interop_rc b/tools/internal_ci/helper_scripts/prepare_build_interop_rc
index db978c8..fb0f4b8 100644
--- a/tools/internal_ci/helper_scripts/prepare_build_interop_rc
+++ b/tools/internal_ci/helper_scripts/prepare_build_interop_rc
@@ -27,6 +27,7 @@
 git clone --recursive https://github.com/grpc/grpc-go ./../grpc-go
 git clone --recursive https://github.com/grpc/grpc-java ./../grpc-java
 git clone --recursive https://github.com/grpc/grpc-node ./../grpc-node
+git clone --recursive https://github.com/grpc/grpc-dart ./../grpc-dart
 
 # Download json file.
 mkdir ~/service_account
diff --git a/tools/internal_ci/helper_scripts/prepare_build_linux_rc b/tools/internal_ci/helper_scripts/prepare_build_linux_rc
index 8715d6c..74bbc85 100644
--- a/tools/internal_ci/helper_scripts/prepare_build_linux_rc
+++ b/tools/internal_ci/helper_scripts/prepare_build_linux_rc
@@ -27,11 +27,6 @@
 echo 'DOCKER_OPTS="${DOCKER_OPTS} --registry-mirror=https://mirror.gcr.io"' | sudo tee --append /etc/default/docker
 sudo service docker restart
 
-# Populate xdg-cache-home to workaround https://github.com/grpc/grpc/issues/11968
-sudo mkdir -p /tmp/xdg-cache-home
-PYTHONWARNINGS=ignore XDG_CACHE_HOME=/tmp/xdg-cache-home sudo -E pip install setuptools wheel
-PYTHONWARNINGS=ignore XDG_CACHE_HOME=/tmp/xdg-cache-home sudo -E pip install coverage==4.4 pylint==1.6.5
-
 # Download Docker images from DockerHub
 export DOCKERHUB_ORGANIZATION=grpctesting
 
diff --git a/tools/internal_ci/helper_scripts/prepare_build_macos_interop_rc b/tools/internal_ci/helper_scripts/prepare_build_macos_interop_rc
index 6ecf51d..786cd45 100644
--- a/tools/internal_ci/helper_scripts/prepare_build_macos_interop_rc
+++ b/tools/internal_ci/helper_scripts/prepare_build_macos_interop_rc
@@ -32,6 +32,7 @@
 git clone --recursive https://github.com/grpc/grpc-go ./../grpc-go
 git clone --recursive https://github.com/grpc/grpc-java ./../grpc-java
 git clone --recursive https://github.com/grpc/grpc-node ./../grpc-node
+git clone --recursive https://github.com/grpc/grpc-dart ./../grpc-dart
 
 # Set up Docker for Mac
 docker-machine create -d virtualbox --virtualbox-share-folder "/Users/kbuilder/workspace:" default
diff --git a/tools/dockerfile/distribtest/node_ubuntu1504_x64/Dockerfile b/tools/internal_ci/linux/grpc_android.cfg
similarity index 70%
rename from tools/dockerfile/distribtest/node_ubuntu1504_x64/Dockerfile
rename to tools/internal_ci/linux/grpc_android.cfg
index 399a43a..fb60777 100644
--- a/tools/dockerfile/distribtest/node_ubuntu1504_x64/Dockerfile
+++ b/tools/internal_ci/linux/grpc_android.cfg
@@ -1,4 +1,4 @@
-# Copyright 2016 gRPC authors.
+# Copyright 2018 gRPC authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -12,10 +12,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM ubuntu:15.04
+# Config file for the internal CI (in protobuf text format)
 
-RUN apt-get update && apt-get install -y curl
-
-# Install nvm
-RUN touch .profile
-RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash
\ No newline at end of file
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/linux/grpc_android.sh"
+timeout_mins: 60
diff --git a/tools/internal_ci/linux/grpc_android.sh b/tools/internal_ci/linux/grpc_android.sh
new file mode 100755
index 0000000..c693b77
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_android.sh
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+REPO_ROOT="$(pwd)"
+
+git submodule update --init
+
+# Build protoc and grpc_cpp_plugin. Codegen is not cross-compiled to Android
+make HAS_SYSTEM_PROTOBUF=false
+
+# TODO(ericgribkoff) Remove when this commit (already in master) is included in
+# next protobuf release
+cd third_party/protobuf
+git fetch
+git cherry-pick 7daa320065f3bea2b54bf983337d1724f153422d -m 1
+
+cd ../../examples/android/helloworld
+./gradlew build \
+    "-Pprotoc=${REPO_ROOT}/third_party/protobuf/src/protoc" \
+    "-Pgrpc_cpp_plugin=${REPO_ROOT}/bins/opt/grpc_cpp_plugin"
diff --git a/tools/dockerfile/distribtest/node_ubuntu1504_x64/Dockerfile b/tools/internal_ci/linux/grpc_asan_on_foundry.sh
similarity index 68%
copy from tools/dockerfile/distribtest/node_ubuntu1504_x64/Dockerfile
copy to tools/internal_ci/linux/grpc_asan_on_foundry.sh
index 399a43a..2aebb65 100644
--- a/tools/dockerfile/distribtest/node_ubuntu1504_x64/Dockerfile
+++ b/tools/internal_ci/linux/grpc_asan_on_foundry.sh
@@ -1,4 +1,5 @@
-# Copyright 2016 gRPC authors.
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -12,10 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM ubuntu:15.04
+EXTRA_FLAGS="--copt=-gmlt --strip=never --copt=-fsanitize=address --linkopt=-fsanitize=address --test_timeout=3600"
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
 
-RUN apt-get update && apt-get install -y curl
-
-# Install nvm
-RUN touch .profile
-RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash
\ No newline at end of file
diff --git a/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh b/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh
new file mode 100755
index 0000000..7ec15bf
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh
@@ -0,0 +1,56 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# A temporary solution to give Kokoro credentials. 
+# The file name 4321_grpc-testing-service needs to match auth_credential in 
+# the build config.
+mkdir -p ${KOKORO_KEYSTORE_DIR}
+cp ${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db331.json ${KOKORO_KEYSTORE_DIR}/4321_grpc-testing-service
+
+temp_dir=$(mktemp -d)
+ln -f "${KOKORO_GFILE_DIR}/bazel-canary" ${temp_dir}/bazel
+chmod 755 "${KOKORO_GFILE_DIR}/bazel-canary"
+export PATH="${temp_dir}:${PATH}"
+# This should show ${temp_dir}/bazel
+which bazel
+chmod +x "${KOKORO_GFILE_DIR}/bazel_wrapper.py"
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+# TODO(adelez): implement size for test targets and change test_timeout back
+"${KOKORO_GFILE_DIR}/bazel_wrapper.py" \
+  --host_jvm_args=-Dbazel.DigestFunction=SHA256 \
+  test --jobs="100" \
+  --test_output=errors  \
+  --verbose_failures=true  \
+  --keep_going  \
+  --remote_accept_cached=true  \
+  --spawn_strategy=remote  \
+  --remote_local_fallback=false  \
+  --remote_timeout=3600  \
+  --strategy=Javac=remote  \
+  --strategy=Closure=remote  \
+  --genrule_strategy=remote  \
+  --experimental_strict_action_env=true \
+  --experimental_remote_platform_override='properties:{name:"container-image" value:"docker://gcr.io/cloud-marketplace/google/rbe-debian8@sha256:b2d946c1ddc20af250fe85cf98bd648ac5519131659f7c36e64184b433175a33" }' \
+  --crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/debian8_clang/0.3.0/bazel_0.10.0:toolchain \
+  --define GRPC_PORT_ISOLATED_RUNTIME=1 \
+  $1 \
+  -- //test/...
diff --git a/tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh b/tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh
index c190298..f5111e2 100644
--- a/tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh
+++ b/tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh
@@ -13,45 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-set -ex
+EXTRA_FLAGS="-c dbg --test_timeout=300,450,1200,7200"
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
 
-# A temporary solution to give Kokoro credentials. 
-# The file name 4321_grpc-testing-service needs to match auth_credential in 
-# the build config.
-mkdir -p ${KOKORO_KEYSTORE_DIR}
-cp ${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db331.json ${KOKORO_KEYSTORE_DIR}/4321_grpc-testing-service
-
-mkdir -p /tmpfs/tmp/bazel-canary
-ln -f "${KOKORO_GFILE_DIR}/bazel-canary" /tmpfs/tmp/bazel-canary/bazel
-chmod 755 "${KOKORO_GFILE_DIR}/bazel-canary"
-export PATH="/tmpfs/tmp/bazel-canary:${PATH}"
-# This should show /tmpfs/tmp/bazel-canary/bazel
-which bazel
-chmod +x "${KOKORO_GFILE_DIR}/bazel_wrapper.py"
-
-# change to grpc repo root
-cd $(dirname $0)/../../..
-
-source tools/internal_ci/helper_scripts/prepare_build_linux_rc
-
-# TODO(adelez): implement size for test targets and change test_timeout back
-"${KOKORO_GFILE_DIR}/bazel_wrapper.py" \
-  --host_jvm_args=-Dbazel.DigestFunction=SHA256 \
-  test --jobs="50" \
-  --test_timeout="1200,1200,1200,3600" \
-  --test_output=errors  \
-  --verbose_failures=true  \
-  --keep_going  \
-  --remote_accept_cached=true  \
-  --spawn_strategy=remote  \
-  --remote_local_fallback=false  \
-  --remote_timeout=3600  \
-  --strategy=Javac=remote  \
-  --strategy=Closure=remote  \
-  --genrule_strategy=remote  \
-  --experimental_strict_action_env=true \
-  --experimental_remote_platform_override='properties:{name:"container-image" value:"docker://gcr.io/asci-toolchain/nosla-debian8-clang-fl@sha256:496193842f61c9494be68bd624e47c74d706cabf19a693c4653ffe96a97e43e3" }' \
-  --crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/debian8_clang/0.2.0/bazel_0.7.0:toolchain \
-  --define GRPC_PORT_ISOLATED_RUNTIME=1 \
-  -c dbg \
-  -- //test/...
diff --git a/tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh b/tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh
index a8c5db4..7f3e4cf 100644
--- a/tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh
+++ b/tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh
@@ -13,45 +13,5 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-set -ex
-
-# A temporary solution to give Kokoro credentials. 
-# The file name 4321_grpc-testing-service needs to match auth_credential in 
-# the build config.
-mkdir -p ${KOKORO_KEYSTORE_DIR}
-cp ${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db331.json ${KOKORO_KEYSTORE_DIR}/4321_grpc-testing-service
-
-mkdir -p /tmpfs/tmp/bazel-canary
-ln -f "${KOKORO_GFILE_DIR}/bazel-canary" /tmpfs/tmp/bazel-canary/bazel
-chmod 755 "${KOKORO_GFILE_DIR}/bazel-canary"
-export PATH="/tmpfs/tmp/bazel-canary:${PATH}"
-# This should show /tmpfs/tmp/bazel-canary/bazel
-which bazel
-chmod +x "${KOKORO_GFILE_DIR}/bazel_wrapper.py"
-
-# change to grpc repo root
-cd $(dirname $0)/../../..
-
-source tools/internal_ci/helper_scripts/prepare_build_linux_rc
-
-# TODO(adelez): implement size for test targets and change test_timeout back
-"${KOKORO_GFILE_DIR}/bazel_wrapper.py" \
-  --host_jvm_args=-Dbazel.DigestFunction=SHA256 \
-  test --jobs="50" \
-  --test_timeout="1200,1200,1200,3600" \
-  --test_output=errors  \
-  --verbose_failures=true  \
-  --keep_going  \
-  --remote_accept_cached=true  \
-  --spawn_strategy=remote  \
-  --remote_local_fallback=false  \
-  --remote_timeout=3600  \
-  --strategy=Javac=remote  \
-  --strategy=Closure=remote  \
-  --genrule_strategy=remote  \
-  --experimental_strict_action_env=true \
-  --experimental_remote_platform_override='properties:{name:"container-image" value:"docker://gcr.io/asci-toolchain/nosla-debian8-clang-fl@sha256:496193842f61c9494be68bd624e47c74d706cabf19a693c4653ffe96a97e43e3" }' \
-  --crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/debian8_clang/0.2.0/bazel_0.7.0:toolchain \
-  --define GRPC_PORT_ISOLATED_RUNTIME=1 \
-  -c opt \
-  -- //test/...
+EXTRA_FLAGS="-c opt --test_timeout=300,450,1200,7200"
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
diff --git a/tools/internal_ci/linux/grpc_build_artifacts_extra.cfg b/tools/internal_ci/linux/grpc_build_artifacts_extra.cfg
new file mode 100644
index 0000000..619e3ea
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_build_artifacts_extra.cfg
@@ -0,0 +1,26 @@
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/linux/grpc_build_artifacts_extra.sh"
+timeout_mins: 240
+action {
+  define_artifacts {
+    regex: "**/*sponge_log.xml"
+    regex: "github/grpc/reports/**"
+    regex: "github/grpc/artifacts/**"
+  }
+}
diff --git a/tools/internal_ci/linux/grpc_build_artifacts_extra.sh b/tools/internal_ci/linux/grpc_build_artifacts_extra.sh
new file mode 100755
index 0000000..718123d
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_build_artifacts_extra.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+set +ex
+[[ -s /etc/profile.d/rvm.sh ]] && . /etc/profile.d/rvm.sh
+set -e  # rvm commands are very verbose
+rvm --default use ruby-2.4.1
+set -ex
+
+tools/run_tests/task_runner.py -f artifact linux_extra armv7 -j 6
diff --git a/tools/internal_ci/linux/grpc_build_packages.cfg b/tools/internal_ci/linux/grpc_build_packages.cfg
new file mode 100644
index 0000000..6a4a163
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_build_packages.cfg
@@ -0,0 +1,26 @@
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/linux/grpc_build_packages.sh"
+timeout_mins: 120
+action {
+  define_artifacts {
+    regex: "**/*sponge_log.xml"
+    regex: "github/grpc/reports/**"
+    regex: "github/grpc/artifacts/**"
+  }
+}
diff --git a/tools/internal_ci/linux/grpc_build_packages.sh b/tools/internal_ci/linux/grpc_build_packages.sh
new file mode 100644
index 0000000..9f65d8e
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_build_packages.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+set +ex
+[[ -s /etc/profile.d/rvm.sh ]] && . /etc/profile.d/rvm.sh
+set -e  # rvm commands are very verbose
+rvm --default use ruby-2.4.1
+set -ex
+
+# Move artifacts generated by the previous step in the build chain to a place
+# where they can be accessed from within a docker container that builds
+# the packages
+mv ${KOKORO_GFILE_DIR}/github/grpc/artifacts input_artifacts || true
+ls -R input_artifacts || true
+
+tools/run_tests/task_runner.py -f package linux -j 6
diff --git a/tools/internal_ci/linux/grpc_distribtests.cfg b/tools/internal_ci/linux/grpc_distribtests.cfg
new file mode 100644
index 0000000..0f1d793
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_distribtests.cfg
@@ -0,0 +1,26 @@
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/linux/grpc_distribtests.sh"
+timeout_mins: 120
+action {
+  define_artifacts {
+    regex: "**/*sponge_log.xml"
+    regex: "github/grpc/reports/**"
+    regex: "github/grpc/artifacts/**"
+  }
+}
diff --git a/tools/internal_ci/linux/grpc_distribtests.sh b/tools/internal_ci/linux/grpc_distribtests.sh
new file mode 100644
index 0000000..47e4bf8
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_distribtests.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+set +ex
+[[ -s /etc/profile.d/rvm.sh ]] && . /etc/profile.d/rvm.sh
+set -e  # rvm commands are very verbose
+rvm --default use ruby-2.4.1
+set -ex
+
+# Move packages generated by the previous step in the build chain to a place
+# where they can be accessed from within a docker container that run the
+# distribtests
+mv ${KOKORO_GFILE_DIR}/github/grpc/artifacts input_artifacts || true
+ls -R input_artifacts || true
+
+tools/run_tests/task_runner.py -f distribtest linux -j 6
diff --git a/tools/internal_ci/linux/grpc_msan_on_foundry.sh b/tools/internal_ci/linux/grpc_msan_on_foundry.sh
new file mode 100644
index 0000000..60b30ff
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_msan_on_foundry.sh
@@ -0,0 +1,64 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# A temporary solution to give Kokoro credentials. 
+# The file name 4321_grpc-testing-service needs to match auth_credential in 
+# the build config.
+# TODO: Use keystore.
+mkdir -p ${KOKORO_KEYSTORE_DIR}
+cp ${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db331.json ${KOKORO_KEYSTORE_DIR}/4321_grpc-testing-service
+
+temp_dir=$(mktemp -d)
+ln -f "${KOKORO_GFILE_DIR}/bazel-canary" ${temp_dir}/bazel
+chmod 755 "${KOKORO_GFILE_DIR}/bazel-canary"
+export PATH="${temp_dir}:${PATH}"
+# This should show ${temp_dir}/bazel
+which bazel
+chmod +x "${KOKORO_GFILE_DIR}/bazel_wrapper.py"
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+"${KOKORO_GFILE_DIR}/bazel_wrapper.py" \
+  --host_jvm_args=-Dbazel.DigestFunction=SHA256 \
+  test --jobs="100" \
+  --test_timeout="3600,3600,3600,3600" \
+  --test_output=errors  \
+  --verbose_failures=true  \
+  --keep_going  \
+  --remote_accept_cached=true  \
+  --spawn_strategy=remote  \
+  --remote_local_fallback=false  \
+  --remote_timeout=3600  \
+  --strategy=Javac=remote  \
+  --strategy=Closure=remote  \
+  --genrule_strategy=remote  \
+  --experimental_strict_action_env=true \
+  --experimental_remote_platform_override='properties:{name:"container-image" value:"docker://gcr.io/asci-toolchain/nosla-debian8-clang-msan@sha256:8f381d55c0456fb65821c90ada902c2584977e03a1eaca8fba8ce77e644c775b" }' \
+  --define GRPC_PORT_ISOLATED_RUNTIME=1 \
+  --copt=-gmlt \
+  --strip=never \
+  --cxxopt=--stdlib=libc++ \
+  --copt=-fsanitize=memory \
+  --linkopt=-fsanitize=memory \
+  --copt=-fsanitize-memory-track-origins \
+  --action_env=LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH \
+  --host_crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/debian8_clang/0.3.0/bazel_0.10.0:toolchain \
+  --crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/experimental/debian8_clang/0.3.0/bazel_0.10.0/msan:msan_experimental_toolchain \
+  -- //test/...
diff --git a/tools/internal_ci/linux/grpc_tsan_on_foundry.sh b/tools/internal_ci/linux/grpc_tsan_on_foundry.sh
index 7da537c..aacb1ad 100644
--- a/tools/internal_ci/linux/grpc_tsan_on_foundry.sh
+++ b/tools/internal_ci/linux/grpc_tsan_on_foundry.sh
@@ -13,49 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-set -ex
+EXTRA_FLAGS="--copt=-gmlt --strip=never --copt=-fsanitize=thread --linkopt=-fsanitize=thread --test_timeout=3600"
+github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
 
-# A temporary solution to give Kokoro credentials. 
-# The file name 4321_grpc-testing-service needs to match auth_credential in 
-# the build config.
-# TODO: Use keystore.
-mkdir -p ${KOKORO_KEYSTORE_DIR}
-cp ${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db331.json ${KOKORO_KEYSTORE_DIR}/4321_grpc-testing-service
-
-mkdir -p /tmpfs/tmp/bazel-canary
-ln -f "${KOKORO_GFILE_DIR}/bazel-canary" /tmpfs/tmp/bazel-canary/bazel
-chmod 755 "${KOKORO_GFILE_DIR}/bazel-canary"
-export PATH="/tmpfs/tmp/bazel-canary:${PATH}"
-# This should show /tmpfs/tmp/bazel-canary/bazel
-which bazel
-chmod +x "${KOKORO_GFILE_DIR}/bazel_wrapper.py"
-
-# change to grpc repo root
-cd $(dirname $0)/../../..
-
-source tools/internal_ci/helper_scripts/prepare_build_linux_rc
-
-"${KOKORO_GFILE_DIR}/bazel_wrapper.py" \
-  --host_jvm_args=-Dbazel.DigestFunction=SHA256 \
-  test --jobs="50" \
-  --test_timeout="1500,1500,1500,3600" \
-  --test_output=errors  \
-  --verbose_failures=true  \
-  --keep_going  \
-  --remote_accept_cached=true  \
-  --spawn_strategy=remote  \
-  --remote_local_fallback=false  \
-  --remote_timeout=3600  \
-  --strategy=Javac=remote  \
-  --strategy=Closure=remote  \
-  --genrule_strategy=remote  \
-  --experimental_strict_action_env=true \
-  --experimental_remote_platform_override='properties:{name:"container-image" value:"docker://gcr.io/asci-toolchain/nosla-debian8-clang-fl@sha256:496193842f61c9494be68bd624e47c74d706cabf19a693c4653ffe96a97e43e3" }' \
-  --crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/debian8_clang/0.2.0/bazel_0.7.0:toolchain \
-  --define GRPC_PORT_ISOLATED_RUNTIME=1 \
-  --copt=-gmlt \
-  --strip=never \
-  --copt=-fsanitize=thread \
-  --linkopt=-fsanitize=thread \
-  --test_verbose_timeout_warnings \
-  -- //test/...
diff --git a/tools/internal_ci/linux/grpc_ubsan_on_foundry.sh b/tools/internal_ci/linux/grpc_ubsan_on_foundry.sh
new file mode 100644
index 0000000..a87547d
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_ubsan_on_foundry.sh
@@ -0,0 +1,60 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# A temporary solution to give Kokoro credentials. 
+# The file name 4321_grpc-testing-service needs to match auth_credential in 
+# the build config.
+# TODO: Use keystore.
+mkdir -p ${KOKORO_KEYSTORE_DIR}
+cp ${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db331.json ${KOKORO_KEYSTORE_DIR}/4321_grpc-testing-service
+
+temp_dir=$(mktemp -d)
+ln -f "${KOKORO_GFILE_DIR}/bazel-canary" ${temp_dir}/bazel
+chmod 755 "${KOKORO_GFILE_DIR}/bazel-canary"
+export PATH="${temp_dir}:${PATH}"
+# This should show ${temp_dir}/bazel
+which bazel
+chmod +x "${KOKORO_GFILE_DIR}/bazel_wrapper.py"
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+"${KOKORO_GFILE_DIR}/bazel_wrapper.py" \
+  --host_jvm_args=-Dbazel.DigestFunction=SHA256 \
+  test --jobs="100" \
+  --test_timeout="3600,3600,3600,3600" \
+  --test_output=errors  \
+  --verbose_failures=true  \
+  --keep_going  \
+  --remote_accept_cached=true  \
+  --spawn_strategy=remote  \
+  --remote_local_fallback=false  \
+  --remote_timeout=3600  \
+  --strategy=Javac=remote  \
+  --strategy=Closure=remote  \
+  --genrule_strategy=remote  \
+  --experimental_strict_action_env=true \
+  --experimental_remote_platform_override='properties:{name:"container-image" value:"docker://gcr.io/cloud-marketplace/google/rbe-debian8@sha256:b2d946c1ddc20af250fe85cf98bd648ac5519131659f7c36e64184b433175a33" }' \
+  --define GRPC_PORT_ISOLATED_RUNTIME=1 \
+  --copt=-gmlt \
+  --strip=never \
+  --copt=-fsanitize=undefined \
+  --linkopt=-fsanitize=undefined \
+  --crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/experimental/debian8_clang/0.3.0/bazel_0.10.0/ubsan:ubsan_experimental_toolchain \
+  -- //test/...
diff --git a/tools/internal_ci/macos/grpc_distribtests.cfg b/tools/internal_ci/macos/grpc_distribtests.cfg
new file mode 100644
index 0000000..ae88f39
--- /dev/null
+++ b/tools/internal_ci/macos/grpc_distribtests.cfg
@@ -0,0 +1,27 @@
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/macos/grpc_distribtests.sh"
+gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json"
+timeout_mins: 120
+action {
+  define_artifacts {
+    regex: "**/*sponge_log.xml"
+    regex: "github/grpc/reports/**"
+    regex: "github/grpc/artifacts/**"
+  }
+}
diff --git a/tools/internal_ci/macos/grpc_distribtests.sh b/tools/internal_ci/macos/grpc_distribtests.sh
new file mode 100644
index 0000000..59ea833
--- /dev/null
+++ b/tools/internal_ci/macos/grpc_distribtests.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_macos_rc
+
+# Move packages generated by the previous step in the build chain.
+mv ${KOKORO_GFILE_DIR}/github/grpc/artifacts input_artifacts || true
+ls -R input_artifacts || true
+
+tools/run_tests/task_runner.py -f distribtest macos
diff --git a/tools/internal_ci/windows/grpc_build_packages.bat b/tools/internal_ci/windows/grpc_build_packages.bat
new file mode 100644
index 0000000..23ba365
--- /dev/null
+++ b/tools/internal_ci/windows/grpc_build_packages.bat
@@ -0,0 +1,35 @@
+@rem Copyright 2017 gRPC authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem     http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+
+@rem Move python installation from _32bit to _32bits where they are expected by python artifact builder
+@rem TODO(jtattermusch): get rid of this hack
+rename C:\Python27_32bit Python27_32bits
+rename C:\Python34_32bit Python34_32bits
+rename C:\Python35_32bit Python35_32bits
+rename C:\Python36_32bit Python36_32bits
+
+@rem enter repo root
+cd /d %~dp0\..\..\..
+
+call tools/internal_ci/helper_scripts/prepare_build_windows.bat
+
+@rem Move artifacts generated by the previous step in the build chain.
+powershell -Command "mv %KOKORO_GFILE_DIR%\github\grpc\artifacts input_artifacts"
+dir input_artifacts
+
+python tools/run_tests/task_runner.py -f package windows -j 4 || goto :error
+goto :EOF
+
+:error
+exit /b %errorlevel%
diff --git a/tools/internal_ci/windows/grpc_build_packages.cfg b/tools/internal_ci/windows/grpc_build_packages.cfg
new file mode 100644
index 0000000..65a8b1e
--- /dev/null
+++ b/tools/internal_ci/windows/grpc_build_packages.cfg
@@ -0,0 +1,26 @@
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/windows/grpc_build_packages.bat"
+timeout_mins: 120
+action {
+  define_artifacts {
+    regex: "**/*sponge_log.xml"
+    regex: "github/grpc/reports/**"
+    regex: "github/grpc/artifacts/**"
+  }
+}
diff --git a/tools/internal_ci/windows/grpc_distribtests.bat b/tools/internal_ci/windows/grpc_distribtests.bat
new file mode 100644
index 0000000..d6d50b6
--- /dev/null
+++ b/tools/internal_ci/windows/grpc_distribtests.bat
@@ -0,0 +1,35 @@
+@rem Copyright 2017 gRPC authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem     http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+
+@rem Move python installation from _32bit to _32bits where they are expected by python artifact builder
+@rem TODO(jtattermusch): get rid of this hack
+rename C:\Python27_32bit Python27_32bits
+rename C:\Python34_32bit Python34_32bits
+rename C:\Python35_32bit Python35_32bits
+rename C:\Python36_32bit Python36_32bits
+
+@rem enter repo root
+cd /d %~dp0\..\..\..
+
+call tools/internal_ci/helper_scripts/prepare_build_windows.bat
+
+@rem Move packages generated by the previous step in the build chain.
+powershell -Command "mv %KOKORO_GFILE_DIR%\github\grpc\artifacts input_artifacts"
+dir input_artifacts
+
+python tools/run_tests/task_runner.py -f distribtest windows -j 4 || goto :error
+goto :EOF
+
+:error
+exit /b %errorlevel%
diff --git a/tools/internal_ci/windows/grpc_distribtests.cfg b/tools/internal_ci/windows/grpc_distribtests.cfg
new file mode 100644
index 0000000..1766e60
--- /dev/null
+++ b/tools/internal_ci/windows/grpc_distribtests.cfg
@@ -0,0 +1,26 @@
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/windows/grpc_distribtests.bat"
+timeout_mins: 120
+action {
+  define_artifacts {
+    regex: "**/*sponge_log.xml"
+    regex: "github/grpc/reports/**"
+    regex: "github/grpc/artifacts/**"
+  }
+}
diff --git a/tools/interop_matrix/client_matrix.py b/tools/interop_matrix/client_matrix.py
index 5de705a..aa45f7f 100644
--- a/tools/interop_matrix/client_matrix.py
+++ b/tools/interop_matrix/client_matrix.py
@@ -18,11 +18,12 @@
 
 def get_github_repo(lang):
     return {
-        'go': 'git@github.com:grpc/grpc-go.git',
-        'java': 'git@github.com:grpc/grpc-java.git',
-        'node': 'git@github.com:grpc/grpc-node.git',
+        'dart': 'https://github.com/grpc/grpc-dart.git',
+        'go': 'https://github.com/grpc/grpc-go.git',
+        'java': 'https://github.com/grpc/grpc-java.git',
+        'node': 'https://github.com/grpc/grpc-node.git',
         # all other languages use the grpc.git repo.
-    }.get(lang, 'git@github.com:grpc/grpc.git')
+    }.get(lang, 'https://github.com/grpc/grpc.git')
 
 
 def get_release_tags(lang):
@@ -80,6 +81,12 @@
         {
             'v1.8.0': None
         },
+        {
+            'v1.9.1': None
+        },
+        {
+            'v1.10.0': None
+        },
     ],
     'go': [
         {
@@ -109,6 +116,9 @@
         {
             'v1.9.2': None
         },
+        {
+            'v1.10.0': None
+        },
     ],
     'java': [
         {
@@ -139,7 +149,10 @@
             'v1.8.0': None
         },
         {
-            'v1.9.0': None
+            'v1.9.1': None
+        },
+        {
+            'v1.10.1': None
         },
     ],
     'python': [
@@ -167,6 +180,12 @@
         {
             'v1.8.1': None  # first python 1.8 release is 1.8.1
         },
+        {
+            'v1.9.1': None
+        },
+        {
+            'v1.10.0': None
+        },
     ],
     'node': [
         {
@@ -187,7 +206,19 @@
         {
             'v1.6.6': None
         },
-        #{'v1.7.1': None}, Failing tests
+        # TODO: https://github.com/grpc/grpc-node/issues/235.
+        #{
+        #    'v1.7.2': None
+        #},
+        {
+            'v1.8.4': None
+        },
+        {
+            'v1.9.1': None
+        },
+        {
+            'v1.10.0': None
+        },
     ],
     'ruby': [
         {
@@ -219,6 +250,12 @@
         {
             'v1.8.0': None
         },
+        {
+            'v1.9.1': None
+        },
+        {
+            'v1.10.0': None
+        },
     ],
     'php': [
         {
@@ -245,6 +282,12 @@
         {
             'v1.8.0': None
         },
+        {
+            'v1.9.1': None
+        },
+        {
+            'v1.10.0': None
+        },
     ],
     'csharp': [
         #{'v1.0.1': None},
@@ -269,5 +312,29 @@
         {
             'v1.8.0': None
         },
+        {
+            'v1.9.1': None
+        },
+        {
+            'v1.10.0': None
+        },
     ],
 }
+
+# This matrix lists the version of testcases to use for a release. As new
+# releases come out, some older docker commands for running tests need to be
+# changed, hence the need for specifying which commands to use for a
+# particular version in some cases. If not specified, xxx__master file will be
+# used. For example, all java versions will run the commands in java__master.
+# The testcases files exist under the testcases directory.
+TESTCASES_VERSION_MATRIX = {
+    'node_v1.0.1': 'node__v1.0.1',
+    'node_v1.1.4': 'node__v1.1.4',
+    'node_v1.2.5': 'node__v1.1.4',
+    'node_v1.3.9': 'node__v1.1.4',
+    'node_v1.4.2': 'node__v1.1.4',
+    'node_v1.6.6': 'node__v1.1.4',
+    'ruby_v1.0.1': 'ruby__v1.0.1',
+    'csharp_v1.1.4': 'csharp__v1.1.4',
+    'csharp_v1.2.5': 'csharp__v1.1.4',
+}
diff --git a/tools/interop_matrix/run_interop_matrix_tests.py b/tools/interop_matrix/run_interop_matrix_tests.py
index 3391ef5..57120d0 100755
--- a/tools/interop_matrix/run_interop_matrix_tests.py
+++ b/tools/interop_matrix/run_interop_matrix_tests.py
@@ -59,7 +59,6 @@
     choices=['all', 'master'] + _RELEASES,
     help='Release tags to test.  When testing all '
     'releases defined in client_matrix.py, use "all".')
-
 argp.add_argument(
     '-l',
     '--language',
@@ -67,15 +66,12 @@
     nargs='+',
     default=['all'],
     help='Languages to test')
-
 argp.add_argument(
     '--keep',
     action='store_true',
     help='keep the created local images after finishing the tests.')
-
 argp.add_argument(
     '--report_file', default='report.xml', help='The result file to create.')
-
 argp.add_argument(
     '--allow_flakes',
     default=False,
@@ -89,6 +85,12 @@
     type=str,
     nargs='?',
     help='Upload test results to a specified BQ table.')
+argp.add_argument(
+    '--server_host',
+    default='74.125.206.210',
+    type=str,
+    nargs='?',
+    help='The gateway to backend services.')
 
 args = argp.parse_args()
 
@@ -145,14 +147,17 @@
 # caches test cases (list of JobSpec) loaded from file.  Keyed by lang and runtime.
 def find_test_cases(lang, runtime, release, suite_name):
     """Returns the list of test cases from testcase files per lang/release."""
-    file_tmpl = os.path.join(os.path.dirname(__file__), 'testcases/%s__%s')
-    testcase_release = release
+    testcase_dir = os.path.join(os.path.dirname(__file__), 'testcases')
     filename_prefix = lang
     if lang == 'csharp':
         filename_prefix = runtime
-    if not os.path.exists(file_tmpl % (filename_prefix, release)):
-        testcase_release = 'master'
-    testcases = file_tmpl % (filename_prefix, testcase_release)
+    # Check to see if we need to use a particular version of test cases.
+    lang_version = '%s_%s' % (filename_prefix, release)
+    if lang_version in client_matrix.TESTCASES_VERSION_MATRIX:
+        testcases = os.path.join(
+            testcase_dir, client_matrix.TESTCASES_VERSION_MATRIX[lang_version])
+    else:
+        testcases = os.path.join(testcase_dir, '%s__master' % filename_prefix)
 
     job_spec_list = []
     try:
@@ -166,6 +171,20 @@
                         '--server_host_override=(.*).sandbox.googleapis.com',
                         line)
                     server = m.group(1) if m else 'unknown_server'
+
+                    # If server_host arg is not None, replace the original
+                    # server_host with the one provided or append to the end of
+                    # the command if server_host does not appear originally.
+                    if args.server_host:
+                        if line.find('--server_host=') > -1:
+                            line = re.sub('--server_host=[^ ]*',
+                                          '--server_host=%s' % args.server_host,
+                                          line)
+                        else:
+                            line = '%s --server_host=%s"' % (line[:-1],
+                                                             args.server_host)
+                        print(line)
+
                     spec = jobset.JobSpec(
                         cmdline=line,
                         shortname='%s:%s:%s:%s' % (suite_name, lang, server,
diff --git a/tools/interop_matrix/testcases/csharp__master b/tools/interop_matrix/testcases/csharp__master
index 32f6b38..c3cd6a4 100644
--- a/tools/interop_matrix/testcases/csharp__master
+++ b/tools/interop_matrix/testcases/csharp__master
@@ -1,20 +1,20 @@
 #!/bin/bash
 echo "Testing ${docker_image:=grpc_interop_csharp:a95229ca-d387-4127-ad48-69a7464e23b8}"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
diff --git a/tools/interop_matrix/testcases/csharp__v1.1.4 b/tools/interop_matrix/testcases/csharp__v1.1.4
index 19da788..f4a6fb1 100644
--- a/tools/interop_matrix/testcases/csharp__v1.1.4
+++ b/tools/interop_matrix/testcases/csharp__v1.1.4
@@ -1,20 +1,20 @@
 #!/bin/bash
 echo "Testing ${docker_image:=grpc_interop_csharp:a95229ca-d387-4127-ad48-69a7464e23b8}"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
diff --git a/tools/interop_matrix/testcases/csharp__v1.2.5 b/tools/interop_matrix/testcases/csharp__v1.2.5
deleted file mode 100644
index 19da788..0000000
--- a/tools/interop_matrix/testcases/csharp__v1.2.5
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-echo "Testing ${docker_image:=grpc_interop_csharp:a95229ca-d387-4127-ad48-69a7464e23b8}"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
diff --git a/tools/interop_matrix/testcases/csharpcoreclr__master b/tools/interop_matrix/testcases/csharpcoreclr__master
index 37e4598..aa8b9dd 100644
--- a/tools/interop_matrix/testcases/csharpcoreclr__master
+++ b/tools/interop_matrix/testcases/csharpcoreclr__master
@@ -1,20 +1,20 @@
 #!/bin/bash
 echo "Testing ${docker_image:=grpc_interop_csharpcoreclr:c7fbed09-e4c1-4aab-8dd9-1285b2c9598e}"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.0 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
diff --git a/tools/interop_matrix/testcases/cxx__master b/tools/interop_matrix/testcases/cxx__master
index e0fed53..629da1a 100755
--- a/tools/interop_matrix/testcases/cxx__master
+++ b/tools/interop_matrix/testcases/cxx__master
@@ -1,20 +1,20 @@
 #!/bin/bash
 echo "Testing ${docker_image:=grpc_interop_cxx:78de6f80-524d-4bc9-bfb2-f00c24ceafed}"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "bins/opt/interop_client --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
diff --git a/tools/interop_matrix/testcases/go__master b/tools/interop_matrix/testcases/go__master
index 33b25d6..a7f83ae 100755
--- a/tools/interop_matrix/testcases/go__master
+++ b/tools/interop_matrix/testcases/go__master
@@ -1,20 +1,20 @@
 #!/bin/bash
 echo "Testing ${docker_image:=grpc_interop_go:dd8fbf3a-4964-4387-9997-5dadeea09835}"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /go/src/google.golang.org/grpc/interop/client --net=host $docker_image bash -c "go run client.go --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
diff --git a/tools/interop_matrix/testcases/java__master b/tools/interop_matrix/testcases/java__master
index dbd8727..95a9c28 100755
--- a/tools/interop_matrix/testcases/java__master
+++ b/tools/interop_matrix/testcases/java__master
@@ -1,20 +1,20 @@
 #!/bin/bash
 echo "Testing ${docker_image:=grpc_interop_java:a764b50c-1788-4387-9b9e-5cfa93927006}"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc/../grpc-java --net=host $docker_image bash -c "./run-test-client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
diff --git a/tools/interop_matrix/testcases/node__master b/tools/interop_matrix/testcases/node__master
index 99ea2f0..588ca95 100755
--- a/tools/interop_matrix/testcases/node__master
+++ b/tools/interop_matrix/testcases/node__master
@@ -1,20 +1,20 @@
 #!/bin/bash
 echo "Testing ${docker_image:=grpc_interop_node:1415ecbf-5d0f-423e-8c2c-e0cb6d154e73}"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc-node --net=host $docker_image bash -c "packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh node --require ./test/fixtures/native_native test/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc-node --net=host $docker_image bash -c "packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh node --require ./test/fixtures/native_native test/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc-node --net=host $docker_image bash -c "packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh node --require ./test/fixtures/native_native test/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc-node --net=host $docker_image bash -c "packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh node --require ./test/fixtures/native_native test/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc-node --net=host $docker_image bash -c "packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh node --require ./test/fixtures/native_native test/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc-node --net=host $docker_image bash -c "packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh node --require ./test/fixtures/native_native test/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc-node --net=host $docker_image bash -c "packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh node --require ./test/fixtures/native_native test/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc-node --net=host $docker_image bash -c "packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh node --require ./test/fixtures/native_native test/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc-node --net=host $docker_image bash -c "packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh node --require ./test/fixtures/native_native test/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc-node --net=host $docker_image bash -c "packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh node --require ./test/fixtures/native_native test/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc-node --net=host $docker_image bash -c "packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh node --require ./test/fixtures/native_native test/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc-node --net=host $docker_image bash -c "packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh node --require ./test/fixtures/native_native test/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc-node --net=host $docker_image bash -c "packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh node --require ./test/fixtures/native_native test/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc-node --net=host $docker_image bash -c "packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh node --require ./test/fixtures/native_native test/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc-node --net=host $docker_image bash -c "packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh node --require ./test/fixtures/native_native test/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc-node --net=host $docker_image bash -c "packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh node --require ./test/fixtures/native_native test/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc-node --net=host $docker_image bash -c "packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh node --require ./test/fixtures/native_native test/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc-node --net=host $docker_image bash -c "packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh node --require ./test/fixtures/native_native test/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
diff --git a/tools/interop_matrix/testcases/node__v1.0.1 b/tools/interop_matrix/testcases/node__v1.0.1
index 6faf321..fca9821 100644
--- a/tools/interop_matrix/testcases/node__v1.0.1
+++ b/tools/interop_matrix/testcases/node__v1.0.1
@@ -1,21 +1,21 @@
 #!/bin/bash
 echo "Testing ${docker_image:=grpc_interop_node:a53aa5e3-b548-4566-b5a8-6d15c1315b32}"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_00c688f2-57da-4023-89f3-46b1f7b5869f $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_d86705d8-14ea-4024-90b6-de74d6e8d19c $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_ebaafacd-1d82-4a75-bea1-a5c64e01fcaf $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_5125241a-fbf6-4c1c-895b-026a5a41f02f $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_3d5e5b82-7205-4eba-b775-8122f05a4760 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_16fa0b49-2083-4932-8f26-79cfdffec940 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_23cee670-2d8d-4f5c-8893-c3c43da8b03a $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_7b6a9454-e3b6-4993-b542-468e268930aa $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_5a7109ed-c065-4b62-98f4-b3ed8f385762 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_1e0ba8dd-4dc1-431b-b202-529e7ace5d1d $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_649de56a-e722-4a59-b265-e9c0e871f068 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_8be512a2-5e1c-4858-8cfc-82f99b678b76 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_d19b6333-e528-48b5-8421-2ae3f7ce9dab $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_4749c80a-21c5-4d81-9df5-3c46ba6480cd $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_b7bee545-4857-4269-a1f2-9553dfc7e4b8 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_4e96db87-6f48-426d-a7f0-97f3a5b6b3f4 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_31a1d58c-f8bf-460a-af60-28969ecaaf80 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_ce64b147-bcfa-44b2-a2f7-4a485380ce30 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_00c688f2-57da-4023-89f3-46b1f7b5869f $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_d86705d8-14ea-4024-90b6-de74d6e8d19c $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_ebaafacd-1d82-4a75-bea1-a5c64e01fcaf $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_5125241a-fbf6-4c1c-895b-026a5a41f02f $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_3d5e5b82-7205-4eba-b775-8122f05a4760 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_16fa0b49-2083-4932-8f26-79cfdffec940 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_23cee670-2d8d-4f5c-8893-c3c43da8b03a $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_7b6a9454-e3b6-4993-b542-468e268930aa $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_5a7109ed-c065-4b62-98f4-b3ed8f385762 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_1e0ba8dd-4dc1-431b-b202-529e7ace5d1d $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_649de56a-e722-4a59-b265-e9c0e871f068 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_8be512a2-5e1c-4858-8cfc-82f99b678b76 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_d19b6333-e528-48b5-8421-2ae3f7ce9dab $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_4749c80a-21c5-4d81-9df5-3c46ba6480cd $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_b7bee545-4857-4269-a1f2-9553dfc7e4b8 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_4e96db87-6f48-426d-a7f0-97f3a5b6b3f4 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_31a1d58c-f8bf-460a-af60-28969ecaaf80 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_ce64b147-bcfa-44b2-a2f7-4a485380ce30 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
 
diff --git a/tools/interop_matrix/testcases/node__v1.1.4 b/tools/interop_matrix/testcases/node__v1.1.4
new file mode 100644
index 0000000..99ea2f0
--- /dev/null
+++ b/tools/interop_matrix/testcases/node__v1.1.4
@@ -0,0 +1,20 @@
+#!/bin/bash
+echo "Testing ${docker_image:=grpc_interop_node:1415ecbf-5d0f-423e-8c2c-e0cb6d154e73}"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_nvm.sh node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
diff --git a/tools/interop_matrix/testcases/php__master b/tools/interop_matrix/testcases/php__master
index bce1d30..f99cb17 100755
--- a/tools/interop_matrix/testcases/php__master
+++ b/tools/interop_matrix/testcases/php__master
@@ -1,20 +1,20 @@
 #!/bin/bash
 echo "Testing ${docker_image:=grpc_interop_php:b290f404-9940-4968-8fc2-19f5291c8eb7}"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "src/php/bin/interop_client.sh --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
diff --git a/tools/interop_matrix/testcases/python__master b/tools/interop_matrix/testcases/python__master
index 4a63eae..71ba75e 100755
--- a/tools/interop_matrix/testcases/python__master
+++ b/tools/interop_matrix/testcases/python__master
@@ -1,20 +1,20 @@
 #!/bin/bash
 echo "Testing ${docker_image:=grpc_interop_python:797ca293-94e8-48d4-92e9-a4d52fcfcca9}"
-docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary\""
-docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary\""
-docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong\""
-docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream\""
-docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming\""
-docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming\""
-docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin\""
-docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response\""
-docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server\""
-docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary\""
-docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary\""
-docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong\""
-docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream\""
-docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming\""
-docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming\""
-docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin\""
-docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response\""
-docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server\""
+docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary\""
+docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary\""
+docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong\""
+docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream\""
+docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming\""
+docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming\""
+docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin\""
+docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response\""
+docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server\""
+docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary\""
+docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary\""
+docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong\""
+docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream\""
+docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming\""
+docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming\""
+docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin\""
+docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response\""
+docker run -i --rm=true -e PYTHONPATH=/var/local/git/grpc/src/python/gens -e LD_LIBRARY_PATH=/var/local/git/grpc/libs/opt -w /var/local/git/grpc --net=host $docker_image bash -c "py27/bin/python src/python/grpcio_tests/setup.py run_interop --client --args=\"--server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server\""
diff --git a/tools/interop_matrix/testcases/ruby__master b/tools/interop_matrix/testcases/ruby__master
index 07bfd05..784ba68 100755
--- a/tools/interop_matrix/testcases/ruby__master
+++ b/tools/interop_matrix/testcases/ruby__master
@@ -1,20 +1,20 @@
 #!/bin/bash
 echo "Testing ${docker_image:=grpc_interop_ruby:6bd1f0eb-51a4-4ad8-861c-1cbd7a929f33}"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "tools/run_tests/interop/with_rvm.sh ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
diff --git a/tools/interop_matrix/testcases/ruby__v1.0.1 b/tools/interop_matrix/testcases/ruby__v1.0.1
index effbef1..9966529 100755
--- a/tools/interop_matrix/testcases/ruby__v1.0.1
+++ b/tools/interop_matrix/testcases/ruby__v1.0.1
@@ -1,20 +1,20 @@
 #!/bin/bash
 echo "Testing ${docker_image:=grpc_interop_ruby:6bd1f0eb-51a4-4ad8-861c-1cbd7a929f33}"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc --net=host $docker_image bash -c "source /usr/local/rvm/scripts/rvm && ruby src/ruby/pb/test/client.rb --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
diff --git a/tools/openssl/use_openssl.sh b/tools/openssl/use_openssl.sh
index a97a54b..dea16ca 100755
--- a/tools/openssl/use_openssl.sh
+++ b/tools/openssl/use_openssl.sh
@@ -16,7 +16,7 @@
 
 set -ex
 
-cd $(dirname $0)/../..
+cd "$(dirname "$0")/../.."
 set root=`pwd`
 CC=${CC:-cc}
 
diff --git a/tools/profiling/latency_profile/profile_analyzer.py b/tools/profiling/latency_profile/profile_analyzer.py
index d4d14ef..cdc2f1c 100755
--- a/tools/profiling/latency_profile/profile_analyzer.py
+++ b/tools/profiling/latency_profile/profile_analyzer.py
@@ -184,24 +184,23 @@
 
 def percentile(N, percent, key=lambda x: x):
     """
-    Find the percentile of a list of values.
+    Find the percentile of an already sorted list of values.
 
-    @parameter N - is a list of values. Note N MUST BE already sorted.
-    @parameter percent - a float value from 0.0 to 1.0.
+    @parameter N - is a list of values. MUST be already sorted.
+    @parameter percent - a float value from [0.0,1.0].
     @parameter key - optional key function to compute value from each element of N.
 
     @return - the percentile of the values
     """
     if not N:
         return None
-    k = (len(N) - 1) * percent
-    f = math.floor(k)
-    c = math.ceil(k)
-    if f == c:
-        return key(N[int(k)])
-    d0 = key(N[int(f)]) * (c - k)
-    d1 = key(N[int(c)]) * (k - f)
-    return d0 + d1
+    float_idx = (len(N) - 1) * percent
+    idx = int(float_idx)
+    result = key(N[idx])
+    if idx < len(N) - 1:
+        # interpolate with the next element's value
+        result += (float_idx - idx) * (key(N[idx + 1]) - key(N[idx]))
+    return result
 
 
 def tidy_tag(tag):
diff --git a/tools/run_tests/artifacts/artifact_targets.py b/tools/run_tests/artifacts/artifact_targets.py
index efc4ca0..daa163e 100644
--- a/tools/run_tests/artifacts/artifact_targets.py
+++ b/tools/run_tests/artifacts/artifact_targets.py
@@ -31,7 +31,8 @@
                           timeout_retries=0,
                           timeout_seconds=30 * 60,
                           docker_base_image=None,
-                          extra_docker_args=None):
+                          extra_docker_args=None,
+                          verbose_success=False):
     """Creates jobspec for a task running under docker."""
     environ = environ.copy()
     environ['RUN_COMMAND'] = shell_command
@@ -57,7 +58,8 @@
         shortname='build_artifact.%s' % (name),
         timeout_seconds=timeout_seconds,
         flake_retries=flake_retries,
-        timeout_retries=timeout_retries)
+        timeout_retries=timeout_retries,
+        verbose_success=verbose_success)
     return jobspec
 
 
@@ -69,7 +71,8 @@
                    timeout_retries=0,
                    timeout_seconds=30 * 60,
                    use_workspace=False,
-                   cpu_cost=1.0):
+                   cpu_cost=1.0,
+                   verbose_success=False):
     """Creates jobspec."""
     environ = environ.copy()
     if use_workspace:
@@ -88,7 +91,8 @@
         flake_retries=flake_retries,
         timeout_retries=timeout_retries,
         shell=shell,
-        cpu_cost=cpu_cost)
+        cpu_cost=cpu_cost,
+        verbose_success=verbose_success)
     return jobspec
 
 
@@ -177,7 +181,7 @@
                 self.name,
                 ['tools/run_tests/artifacts/build_artifact_python.sh'],
                 environ=environ,
-                timeout_seconds=60 * 60,
+                timeout_seconds=60 * 60 * 2,
                 use_workspace=True)
 
     def __str__(self):
@@ -317,6 +321,7 @@
                     self.name,
                     ['tools/run_tests/artifacts/build_artifact_protoc.sh'],
                     environ=environ,
+                    timeout_seconds=60 * 60,
                     use_workspace=True)
         else:
             generator = 'Visual Studio 14 2015 Win64' if self.arch == 'x64' else 'Visual Studio 14 2015'
diff --git a/tools/run_tests/artifacts/build_artifact_python.bat b/tools/run_tests/artifacts/build_artifact_python.bat
index 3a05641..d277668 100644
--- a/tools/run_tests/artifacts/build_artifact_python.bat
+++ b/tools/run_tests/artifacts/build_artifact_python.bat
@@ -16,7 +16,8 @@
 set PATH=C:\%1;C:\%1\scripts;C:\msys64\mingw%2\bin;C:\tools\msys64\mingw%2\bin;%PATH%
 
 pip install --upgrade six
-pip install --upgrade setuptools
+@rem some artifacts are broken for setuptools 38.5.0. See https://github.com/grpc/grpc/issues/14317
+pip install --upgrade setuptools==38.2.4
 pip install -rrequirements.txt
 
 set GRPC_PYTHON_BUILD_WITH_CYTHON=1
diff --git a/tools/run_tests/artifacts/build_artifact_python.sh b/tools/run_tests/artifacts/build_artifact_python.sh
index 10d8211..9ea0f05 100755
--- a/tools/run_tests/artifacts/build_artifact_python.sh
+++ b/tools/run_tests/artifacts/build_artifact_python.sh
@@ -35,6 +35,34 @@
 # https://bitbucket.org/pypa/wheel/issues/99/cannot-exclude-directory
 ${SETARCH_CMD} "${PYTHON}" setup.py bdist_wheel
 
+GRPCIO_STRIP_TEMPDIR=$(mktemp -d)
+GRPCIO_TAR_GZ_LIST=( dist/grpcio-*.tar.gz )
+GRPCIO_TAR_GZ=${GRPCIO_TAR_GZ_LIST[0]}
+GRPCIO_STRIPPED_TAR_GZ=$(mktemp -t "XXXXXXXXXX.tar.gz")
+
+clean_non_source_files() {
+( cd "$1"
+  find . -type f \
+    | grep -v '\.c$' | grep -v '\.cc$' | grep -v '\.cpp$' \
+    | grep -v '\.h$' | grep -v '\.hh$' \
+    | grep -v '\.s$' | grep -v '\.py$' \
+    | while read -r file; do
+      rm -f "$file" || true
+    done
+  find . -type d -empty -delete
+)
+}
+
+tar xzf "${GRPCIO_TAR_GZ}" -C "${GRPCIO_STRIP_TEMPDIR}"
+( cd "${GRPCIO_STRIP_TEMPDIR}"
+  find . -type d -name .git -exec rm -fr {} \; || true
+  for dir in */third_party/*; do
+    clean_non_source_files "${dir}" || true
+  done
+  tar czf "${GRPCIO_STRIPPED_TAR_GZ}" -- *
+)
+mv "${GRPCIO_STRIPPED_TAR_GZ}" "${GRPCIO_TAR_GZ}"
+
 # Build gRPC tools package distribution
 "${PYTHON}" tools/distrib/python/make_grpcio_tools.py
 
diff --git a/tools/run_tests/artifacts/build_package_php.sh b/tools/run_tests/artifacts/build_package_php.sh
index 85e4dda..9a8f25a 100755
--- a/tools/run_tests/artifacts/build_package_php.sh
+++ b/tools/run_tests/artifacts/build_package_php.sh
@@ -17,5 +17,10 @@
 
 cd "$(dirname "$0")/../../.."
 
+# All the PHP packages have been built in the artifact phase already
+# and we only collect them here to deliver them to the distribtest phase.
 mkdir -p artifacts/
-cp -r "$EXTERNAL_GIT_ROOT"/platform={windows,linux,macos}/artifacts/php_*/* artifacts/ || true
+# Jenkins flow (deprecated)
+cp -r "${EXTERNAL_GIT_ROOT}"/platform={windows,linux,macos}/artifacts/php_*/* artifacts/ || true
+# Kokoro flow
+cp -r "${EXTERNAL_GIT_ROOT}"/input_artifacts/php_*/* artifacts/ || true
diff --git a/tools/run_tests/artifacts/build_package_python.sh b/tools/run_tests/artifacts/build_package_python.sh
index d596e35..1562788 100755
--- a/tools/run_tests/artifacts/build_package_python.sh
+++ b/tools/run_tests/artifacts/build_package_python.sh
@@ -21,7 +21,10 @@
 
 # All the python packages have been built in the artifact phase already
 # and we only collect them here to deliver them to the distribtest phase.
-cp -r "$EXTERNAL_GIT_ROOT"/platform={windows,linux,macos}/artifacts/python_*/* artifacts/ || true
+# Jenkins flow (deprecated)
+cp -r "${EXTERNAL_GIT_ROOT}"/platform={windows,linux,macos}/artifacts/python_*/* artifacts/ || true
+# Kokoro flow
+cp -r "${EXTERNAL_GIT_ROOT}"/input_artifacts/python_*/* artifacts/ || true
 
 # TODO: all the artifact builder configurations generate a grpcio-VERSION.tar.gz
 # source distribution package, and only one of them will end up
diff --git a/tools/run_tests/artifacts/build_package_ruby.sh b/tools/run_tests/artifacts/build_package_ruby.sh
index 0283c43..05eacd4 100755
--- a/tools/run_tests/artifacts/build_package_ruby.sh
+++ b/tools/run_tests/artifacts/build_package_ruby.sh
@@ -23,7 +23,10 @@
 
 # All the ruby packages have been built in the artifact phase already
 # and we only collect them here to deliver them to the distribtest phase.
-cp -r "$EXTERNAL_GIT_ROOT"/platform={windows,linux,macos}/artifacts/ruby_native_gem_*/* artifacts/ || true
+# Jenkins flow (deprecated)
+cp -r "${EXTERNAL_GIT_ROOT}"/platform={windows,linux,macos}/artifacts/ruby_native_gem_*/* artifacts/ || true
+# Kokoro flow
+cp -r "${EXTERNAL_GIT_ROOT}"/input_artifacts/ruby_native_gem_*/* artifacts/ || true
 
 well_known_protos=( any api compiler/plugin descriptor duration empty field_mask source_context struct timestamp type wrappers )
 
@@ -41,7 +44,12 @@
       ;;
   esac
   for plat in {windows,linux,macos}; do
-    input_dir="$EXTERNAL_GIT_ROOT/platform=${plat}/artifacts/protoc_${plat}_${arch}"
+    if [ "${KOKORO_JOB_NAME}" != "" ]
+    then
+      input_dir="${EXTERNAL_GIT_ROOT}/input_artifacts/protoc_${plat}_${arch}"
+    else
+      input_dir="${EXTERNAL_GIT_ROOT}/platform=${plat}/artifacts/protoc_${plat}_${arch}"
+    fi
     output_dir="$base/src/ruby/tools/bin/${ruby_arch}-${plat}"
     mkdir -p "$output_dir"/google/protobuf
     mkdir -p "$output_dir"/google/protobuf/compiler  # needed for plugin.proto
diff --git a/tools/run_tests/artifacts/distribtest_targets.py b/tools/run_tests/artifacts/distribtest_targets.py
index fdf094c..041faab 100644
--- a/tools/run_tests/artifacts/distribtest_targets.py
+++ b/tools/run_tests/artifacts/distribtest_targets.py
@@ -232,7 +232,7 @@
                 copy_rel_path='test/distrib')
         elif self.platform == 'macos':
             return create_jobspec(
-                self.name, ['test/distrib/php/run_distrib_test.sh'],
+                self.name, ['test/distrib/php/run_distrib_test_macos.sh'],
                 environ={'EXTERNAL_GIT_ROOT': '../../../..'},
                 use_workspace=True)
         else:
@@ -293,8 +293,6 @@
         CSharpDistribTest('linux', 'x86', 'jessie'),
         CSharpDistribTest('linux', 'x64', 'centos7'),
         CSharpDistribTest('linux', 'x64', 'ubuntu1404'),
-        CSharpDistribTest('linux', 'x64', 'ubuntu1504'),
-        CSharpDistribTest('linux', 'x64', 'ubuntu1510'),
         CSharpDistribTest('linux', 'x64', 'ubuntu1604'),
         CSharpDistribTest('linux', 'x64', 'ubuntu1404', use_dotnet_cli=True),
         CSharpDistribTest('macos', 'x86'),
@@ -313,8 +311,6 @@
         PythonDistribTest('linux', 'x64', 'arch'),
         PythonDistribTest('linux', 'x64', 'ubuntu1204'),
         PythonDistribTest('linux', 'x64', 'ubuntu1404'),
-        PythonDistribTest('linux', 'x64', 'ubuntu1504'),
-        PythonDistribTest('linux', 'x64', 'ubuntu1510'),
         PythonDistribTest('linux', 'x64', 'ubuntu1604'),
         RubyDistribTest('linux', 'x64', 'wheezy'),
         RubyDistribTest('linux', 'x64', 'jessie'),
@@ -329,8 +325,6 @@
         RubyDistribTest('linux', 'x64', 'opensuse'),
         RubyDistribTest('linux', 'x64', 'ubuntu1204'),
         RubyDistribTest('linux', 'x64', 'ubuntu1404'),
-        RubyDistribTest('linux', 'x64', 'ubuntu1504'),
-        RubyDistribTest('linux', 'x64', 'ubuntu1510'),
         RubyDistribTest('linux', 'x64', 'ubuntu1604'),
         PHPDistribTest('linux', 'x64', 'jessie'),
         PHPDistribTest('macos', 'x64'),
diff --git a/tools/run_tests/dockerize/build_and_run_docker.sh b/tools/run_tests/dockerize/build_and_run_docker.sh
index b8f0a55..3ea3ca3 100755
--- a/tools/run_tests/dockerize/build_and_run_docker.sh
+++ b/tools/run_tests/dockerize/build_and_run_docker.sh
@@ -58,6 +58,10 @@
   "$@" \
   -e EXTERNAL_GIT_ROOT="/var/local/jenkins/grpc" \
   -e THIS_IS_REALLY_NEEDED='see https://github.com/docker/docker/issues/14203 for why docker is awful' \
+  -e "KOKORO_BUILD_ID=$KOKORO_BUILD_ID" \
+  -e "KOKORO_BUILD_NUMBER=$KOKORO_BUILD_NUMBER" \
+  -e "KOKORO_BUILD_URL=$KOKORO_BUILD_URL" \
+  -e "KOKORO_JOB_NAME=$KOKORO_JOB_NAME" \
   -v "$git_root:/var/local/jenkins/grpc:ro" \
   -w /var/local/git/grpc \
   --name="$CONTAINER_NAME" \
diff --git a/tools/run_tests/dockerize/build_docker_and_run_tests.sh b/tools/run_tests/dockerize/build_docker_and_run_tests.sh
index 8dca05e..21eccba 100755
--- a/tools/run_tests/dockerize/build_docker_and_run_tests.sh
+++ b/tools/run_tests/dockerize/build_docker_and_run_tests.sh
@@ -25,10 +25,6 @@
 # Ensure existence of ccache directory
 mkdir -p /tmp/ccache
 
-# Ensure existence of the home directory for XDG caches (e.g. what pip uses for
-# its cache location now that --download-cache is deprecated).
-mkdir -p /tmp/xdg-cache-home
-
 # Inputs
 # DOCKERFILE_DIR - Directory in which Dockerfile file is located.
 # DOCKER_RUN_SCRIPT - Script to run under docker (relative to grpc repo root)
@@ -61,7 +57,6 @@
   -e "config=$config" \
   -e "arch=$arch" \
   -e CCACHE_DIR=/tmp/ccache \
-  -e XDG_CACHE_HOME=/tmp/xdg-cache-home \
   -e THIS_IS_REALLY_NEEDED='see https://github.com/docker/docker/issues/14203 for why docker is awful' \
   -e HOST_GIT_ROOT="$git_root" \
   -e LOCAL_GIT_ROOT=$docker_instance_git_root \
@@ -79,7 +74,6 @@
   -v "$git_root:$docker_instance_git_root" \
   -v /tmp/ccache:/tmp/ccache \
   -v /tmp/npm-cache:/tmp/npm-cache \
-  -v /tmp/xdg-cache-home:/tmp/xdg-cache-home \
   -w /var/local/git/grpc \
   --name="$CONTAINER_NAME" \
   "$DOCKER_IMAGE_NAME" \
diff --git a/tools/run_tests/dockerize/build_interop_image.sh b/tools/run_tests/dockerize/build_interop_image.sh
index 90605d9..2bef4a3 100755
--- a/tools/run_tests/dockerize/build_interop_image.sh
+++ b/tools/run_tests/dockerize/build_interop_image.sh
@@ -48,6 +48,14 @@
   echo "WARNING: grpc-go not found, it won't be mounted to the docker container."
 fi
 
+echo "GRPC_DART_ROOT: ${GRPC_DART_ROOT:=$(cd ../grpc-dart && pwd)}"
+if [ -n "$GRPC_DART_ROOT" ]
+then
+  MOUNT_ARGS+=" -v $GRPC_DART_ROOT:/var/local/jenkins/grpc-dart:ro"
+else
+  echo "WARNING: grpc-dart not found, it won't be mounted to the docker container."
+fi
+
 echo "GRPC_NODE_ROOT: ${GRPC_NODE_ROOT:=$(cd ../grpc-node && pwd)}"
 if [ -n "$GRPC_NODE_ROOT" ]
 then
diff --git a/tools/run_tests/dockerize/docker_run.sh b/tools/run_tests/dockerize/docker_run.sh
index ac0d09c..e525019 100755
--- a/tools/run_tests/dockerize/docker_run.sh
+++ b/tools/run_tests/dockerize/docker_run.sh
@@ -25,9 +25,8 @@
   # clone gRPC submodules, use data from locally cloned submodules where possible
   # TODO: figure out a way to eliminate this following shellcheck suppressions
   # shellcheck disable=SC2016,SC1004
-  (cd "${EXTERNAL_GIT_ROOT}" && git submodule foreach 'cd /var/local/git/grpc \
-  && git submodule update --init --reference ${EXTERNAL_GIT_ROOT}/${name} \
-  ${name}')
+  (cd "${EXTERNAL_GIT_ROOT}" && git submodule foreach 'git clone ${EXTERNAL_GIT_ROOT}/${name} /var/local/git/grpc/${name}')
+  (cd /var/local/git/grpc && git submodule init)
 else
   mkdir -p "/var/local/git/grpc/$RELATIVE_COPY_PATH"
   cp -r "$EXTERNAL_GIT_ROOT/$RELATIVE_COPY_PATH"/* "/var/local/git/grpc/$RELATIVE_COPY_PATH"
diff --git a/tools/run_tests/dockerize/docker_run_tests.sh b/tools/run_tests/dockerize/docker_run_tests.sh
index df9d3d1..c41734c 100755
--- a/tools/run_tests/dockerize/docker_run_tests.sh
+++ b/tools/run_tests/dockerize/docker_run_tests.sh
@@ -22,18 +22,13 @@
 export ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer
 export PATH=$PATH:/usr/bin/llvm-symbolizer
 
-# Ensure that programs depending on current-user-ownership of cache directories
-# are satisfied (it's being mounted from outside the image).
-chown "$(whoami)" "$XDG_CACHE_HOME"
-
 mkdir -p /var/local/git
-git clone  /var/local/jenkins/grpc /var/local/git/grpc
+git clone /var/local/jenkins/grpc /var/local/git/grpc
 # clone gRPC submodules, use data from locally cloned submodules where possible
 # TODO: figure out a way to eliminate this shellcheck suppression:
-# shellcheck disable=SC2016,SC1004
-(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
-&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
-${name}')
+# shellcheck disable=SC2016
+(cd /var/local/jenkins/grpc/ && git submodule foreach 'git clone /var/local/jenkins/grpc/${name} /var/local/git/grpc/${name}')
+(cd /var/local/git/grpc/ && git submodule init)
 
 mkdir -p reports
 
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 69c178c..fd6c526 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -86,6 +86,22 @@
     "deps": [
       "gpr", 
       "gpr_test_util", 
+      "grpc"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c", 
+    "name": "avl_test", 
+    "src": [
+      "test/core/avl/avl_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
       "grpc", 
       "grpc_test_util", 
       "test_tcp_server"
@@ -140,23 +156,6 @@
     "headers": [], 
     "is_filegroup": false, 
     "language": "c", 
-    "name": "byte_stream_test", 
-    "src": [
-      "test/core/transport/byte_stream_test.cc"
-    ], 
-    "third_party": false, 
-    "type": "target"
-  }, 
-  {
-    "deps": [
-      "gpr", 
-      "gpr_test_util", 
-      "grpc", 
-      "grpc_test_util"
-    ], 
-    "headers": [], 
-    "is_filegroup": false, 
-    "language": "c", 
     "name": "channel_create_test", 
     "src": [
       "test/core/surface/channel_create_test.cc"
@@ -251,6 +250,22 @@
     "deps": [
       "gpr", 
       "gpr_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c", 
+    "name": "cmdline_test", 
+    "src": [
+      "test/core/util/cmdline_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
       "grpc", 
       "grpc_test_util"
     ], 
@@ -595,36 +610,6 @@
     "headers": [], 
     "is_filegroup": false, 
     "language": "c", 
-    "name": "gpr_avl_test", 
-    "src": [
-      "test/core/gpr/avl_test.cc"
-    ], 
-    "third_party": false, 
-    "type": "target"
-  }, 
-  {
-    "deps": [
-      "gpr", 
-      "gpr_test_util"
-    ], 
-    "headers": [], 
-    "is_filegroup": false, 
-    "language": "c", 
-    "name": "gpr_cmdline_test", 
-    "src": [
-      "test/core/gpr/cmdline_test.cc"
-    ], 
-    "third_party": false, 
-    "type": "target"
-  }, 
-  {
-    "deps": [
-      "gpr", 
-      "gpr_test_util"
-    ], 
-    "headers": [], 
-    "is_filegroup": false, 
-    "language": "c", 
     "name": "gpr_cpu_test", 
     "src": [
       "test/core/gpr/cpu_test.cc"
@@ -762,7 +747,7 @@
     "language": "c", 
     "name": "gpr_thd_test", 
     "src": [
-      "test/core/gpr/thd_test.cc"
+      "test/core/gprpp/thd_test.cc"
     ], 
     "third_party": false, 
     "type": "target"
@@ -950,6 +935,7 @@
   }, 
   {
     "deps": [
+      "cmdline", 
       "gpr", 
       "grpc"
     ], 
@@ -1050,6 +1036,7 @@
   }, 
   {
     "deps": [
+      "cmdline", 
       "gpr", 
       "grpc"
     ], 
@@ -1099,6 +1086,7 @@
   }, 
   {
     "deps": [
+      "cmdline", 
       "gpr", 
       "grpc"
     ], 
@@ -1393,7 +1381,9 @@
   {
     "deps": [
       "gpr", 
-      "grpc"
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
     ], 
     "headers": [], 
     "is_filegroup": false, 
@@ -1957,23 +1947,6 @@
     "headers": [], 
     "is_filegroup": false, 
     "language": "c", 
-    "name": "slice_hash_table_test", 
-    "src": [
-      "test/core/slice/slice_hash_table_test.cc"
-    ], 
-    "third_party": false, 
-    "type": "target"
-  }, 
-  {
-    "deps": [
-      "gpr", 
-      "gpr_test_util", 
-      "grpc", 
-      "grpc_test_util"
-    ], 
-    "headers": [], 
-    "is_filegroup": false, 
-    "language": "c", 
     "name": "slice_string_helpers_test", 
     "src": [
       "test/core/slice/slice_string_helpers_test.cc"
@@ -2427,6 +2400,215 @@
   }, 
   {
     "deps": [
+      "alts_test_util", 
+      "gpr", 
+      "grpc"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "alts_counter_test", 
+    "src": [
+      "test/core/tsi/alts/frame_protector/alts_counter_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "alts_test_util", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "alts_crypt_test", 
+    "src": [
+      "test/core/tsi/alts/crypt/aes_gcm_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "alts_test_util", 
+      "gpr", 
+      "grpc"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "alts_crypter_test", 
+    "src": [
+      "test/core/tsi/alts/frame_protector/alts_crypter_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "alts_test_util", 
+      "gpr", 
+      "grpc"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "alts_frame_handler_test", 
+    "src": [
+      "test/core/tsi/alts/frame_protector/frame_handler_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "alts_test_util", 
+      "gpr", 
+      "grpc", 
+      "transport_security_test_lib"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "alts_frame_protector_test", 
+    "src": [
+      "test/core/tsi/alts/frame_protector/alts_frame_protector_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "alts_test_util", 
+      "gpr", 
+      "grpc"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "alts_grpc_record_protocol_test", 
+    "src": [
+      "test/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "alts_test_util", 
+      "gpr", 
+      "grpc"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "alts_handshaker_client_test", 
+    "src": [
+      "test/core/tsi/alts/handshaker/alts_handshaker_client_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "alts_test_util", 
+      "gpr", 
+      "grpc"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "alts_handshaker_service_api_test", 
+    "src": [
+      "test/core/tsi/alts/handshaker/alts_handshaker_service_api_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "alts_test_util", 
+      "gpr", 
+      "grpc"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "alts_iovec_record_protocol_test", 
+    "src": [
+      "test/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "grpc"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "alts_security_connector_test", 
+    "src": [
+      "test/core/security/alts_security_connector_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "alts_test_util", 
+      "gpr", 
+      "grpc"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "alts_tsi_handshaker_test", 
+    "src": [
+      "test/core/tsi/alts/handshaker/alts_tsi_handshaker_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "alts_test_util", 
+      "gpr", 
+      "grpc"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "alts_tsi_utils_test", 
+    "src": [
+      "test/core/tsi/alts/handshaker/alts_tsi_utils_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "alts_test_util", 
+      "gpr", 
+      "grpc"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "alts_zero_copy_grpc_protector_test", 
+    "src": [
+      "test/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
       "gpr", 
       "gpr_test_util", 
       "grpc", 
@@ -2806,6 +2988,23 @@
   {
     "deps": [
       "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "byte_stream_test", 
+    "src": [
+      "test/core/transport/byte_stream_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
       "grpc", 
       "grpc++"
     ], 
@@ -2840,6 +3039,57 @@
       "gpr", 
       "gpr_test_util", 
       "grpc", 
+      "grpc++", 
+      "grpc++_channelz_proto", 
+      "grpc++_test", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "channel_trace_test", 
+    "src": [
+      "test/core/channel/channel_trace_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "grpc"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "check_gcp_environment_linux_test", 
+    "src": [
+      "test/core/security/check_gcp_environment_linux_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "grpc"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "check_gcp_environment_windows_test", 
+    "src": [
+      "test/core/security/check_gcp_environment_windows_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
       "grpc_test_util"
     ], 
     "headers": [], 
@@ -3223,6 +3473,21 @@
   {
     "deps": [
       "gpr", 
+      "grpc"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "grpc_alts_credentials_options_test", 
+    "src": [
+      "test/core/security/grpc_alts_credentials_options_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
       "grpc", 
       "grpc++", 
       "grpc++_proto_reflection_desc_db", 
@@ -3417,19 +3682,18 @@
       "gpr_test_util", 
       "grpc", 
       "grpc++", 
-      "grpc++_test_util", 
+      "grpc++_test", 
       "grpc_test_util"
     ], 
     "headers": [
-      "src/proto/grpc/lb/v1/load_balancer.grpc.pb.h", 
-      "src/proto/grpc/lb/v1/load_balancer.pb.h", 
-      "src/proto/grpc/lb/v1/load_balancer_mock.grpc.pb.h"
+      "test/core/end2end/end2end_tests.h"
     ], 
     "is_filegroup": false, 
     "language": "c++", 
-    "name": "grpclb_test", 
+    "name": "h2_ssl_cert_test", 
     "src": [
-      "test/cpp/grpclb/grpclb_test.cc"
+      "test/core/end2end/end2end_tests.h", 
+      "test/core/end2end/h2_ssl_cert_test.cc"
     ], 
     "third_party": false, 
     "type": "target"
@@ -3448,10 +3712,10 @@
     ], 
     "is_filegroup": false, 
     "language": "c++", 
-    "name": "h2_ssl_cert_test", 
+    "name": "h2_ssl_session_reuse_test", 
     "src": [
       "test/core/end2end/end2end_tests.h", 
-      "test/core/end2end/h2_ssl_cert_test.cc"
+      "test/core/end2end/h2_ssl_session_reuse_test.cc"
     ], 
     "third_party": false, 
     "type": "target"
@@ -3683,13 +3947,15 @@
       "grpc_test_util"
     ], 
     "headers": [
-      "include/grpc++/test/mock_stream.h"
+      "include/grpc++/test/mock_stream.h", 
+      "include/grpcpp/test/mock_stream.h"
     ], 
     "is_filegroup": false, 
     "language": "c++", 
     "name": "mock_test", 
     "src": [
       "include/grpc++/test/mock_stream.h", 
+      "include/grpcpp/test/mock_stream.h", 
       "test/cpp/end2end/mock_test.cc"
     ], 
     "third_party": false, 
@@ -3697,6 +3963,25 @@
   }, 
   {
     "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "nonblocking_test", 
+    "src": [
+      "test/cpp/end2end/nonblocking_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
       "benchmark"
     ], 
     "headers": [], 
@@ -4170,6 +4455,40 @@
       "gpr", 
       "gpr_test_util", 
       "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "slice_hash_table_test", 
+    "src": [
+      "test/core/slice/slice_hash_table_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "slice_weak_hash_table_test", 
+    "src": [
+      "test/core/slice/slice_weak_hash_table_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
       "grpc++_test_util", 
       "grpc_test_util"
     ], 
@@ -4185,18 +4504,28 @@
   }, 
   {
     "deps": [
-      "gpr", 
-      "gpr_test_util", 
-      "grpc", 
-      "grpc++", 
-      "grpc_test_util"
+      "grpc"
     ], 
     "headers": [], 
     "is_filegroup": false, 
     "language": "c++", 
-    "name": "status_test", 
+    "name": "status_metadata_test", 
     "src": [
-      "test/cpp/util/status_test.cc"
+      "test/core/transport/status_metadata_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "grpc"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "status_util_test", 
+    "src": [
+      "test/core/channel/status_util_test.cc"
     ], 
     "third_party": false, 
     "type": "target"
@@ -4323,6 +4652,22 @@
   }, 
   {
     "deps": [
+      "alts_test_util", 
+      "gpr", 
+      "grpc"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "transport_security_common_api_test", 
+    "src": [
+      "test/core/tsi/alts/handshaker/transport_security_common_api_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
       "gpr", 
       "gpr_test_util", 
       "grpc", 
@@ -4453,6 +4798,20 @@
   {
     "deps": [
       "boringssl", 
+      "boringssl_buf_test_lib", 
+      "boringssl_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "boringssl_buf_test", 
+    "src": [], 
+    "third_party": true, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "boringssl", 
       "boringssl_bytestring_test_lib", 
       "boringssl_test_util"
     ], 
@@ -5127,6 +5486,24 @@
     "headers": [], 
     "is_filegroup": false, 
     "language": "c", 
+    "name": "duplicate_header_bad_client_test", 
+    "src": [
+      "test/core/bad_client/tests/duplicate_header.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "bad_client_test", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c", 
     "name": "head_of_line_blocking_bad_client_test", 
     "src": [
       "test/core/bad_client/tests/head_of_line_blocking.cc"
@@ -5991,6 +6368,46 @@
     "deps": [
       "gpr", 
       "gpr_test_util", 
+      "grpc++_test_config", 
+      "grpc++_test_util_unsecure", 
+      "grpc++_unsecure", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "address_sorting_test_unsecure", 
+    "src": [
+      "test/cpp/naming/address_sorting_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_config", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "address_sorting_test", 
+    "src": [
+      "test/cpp/naming/address_sorting_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
       "grpc", 
       "grpc_test_util"
     ], 
@@ -6222,6 +6639,39 @@
     "type": "target"
   }, 
   {
+    "deps": [], 
+    "headers": [
+      "third_party/address_sorting/address_sorting_internal.h", 
+      "third_party/address_sorting/include/address_sorting/address_sorting.h"
+    ], 
+    "is_filegroup": false, 
+    "language": "c", 
+    "name": "address_sorting", 
+    "src": [], 
+    "third_party": false, 
+    "type": "lib"
+  }, 
+  {
+    "deps": [
+      "grpc"
+    ], 
+    "headers": [
+      "test/core/tsi/alts/crypt/gsec_test_util.h", 
+      "test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.h"
+    ], 
+    "is_filegroup": false, 
+    "language": "c", 
+    "name": "alts_test_util", 
+    "src": [
+      "test/core/tsi/alts/crypt/gsec_test_util.cc", 
+      "test/core/tsi/alts/crypt/gsec_test_util.h", 
+      "test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.cc", 
+      "test/core/tsi/alts/handshaker/alts_handshaker_service_api_test_lib.h"
+    ], 
+    "third_party": false, 
+    "type": "lib"
+  }, 
+  {
     "deps": [
       "gpr_base"
     ], 
@@ -6289,8 +6739,16 @@
     "deps": [
       "gpr", 
       "grpc_base", 
+      "grpc_base_headers", 
+      "grpc_deadline_filter", 
+      "grpc_lb_policy_pick_first", 
+      "grpc_max_age_filter", 
+      "grpc_message_size_filter", 
+      "grpc_resolver_dns_native", 
+      "grpc_resolver_sockaddr", 
       "grpc_server_load_reporting", 
       "grpc_transport_chttp2_client_secure", 
+      "grpc_transport_chttp2_server_secure", 
       "grpc_transport_cronet_client_secure"
     ], 
     "headers": [], 
@@ -6442,6 +6900,7 @@
     ], 
     "headers": [
       "include/grpc++/impl/codegen/core_codegen.h", 
+      "include/grpcpp/impl/codegen/core_codegen.h", 
       "src/cpp/client/secure_credentials.h", 
       "src/cpp/common/secure_auth_context.h", 
       "src/cpp/server/secure_server_credentials.h"
@@ -6451,6 +6910,7 @@
     "name": "grpc++", 
     "src": [
       "include/grpc++/impl/codegen/core_codegen.h", 
+      "include/grpcpp/impl/codegen/core_codegen.h", 
       "src/cpp/client/insecure_credentials.cc", 
       "src/cpp/client/secure_credentials.cc", 
       "src/cpp/client/secure_credentials.h", 
@@ -6517,6 +6977,7 @@
     ], 
     "headers": [
       "include/grpc++/support/error_details.h", 
+      "include/grpcpp/support/error_details.h", 
       "src/proto/grpc/status/status.grpc.pb.h", 
       "src/proto/grpc/status/status.pb.h", 
       "src/proto/grpc/status/status_mock.grpc.pb.h"
@@ -6526,6 +6987,7 @@
     "name": "grpc++_error_details", 
     "src": [
       "include/grpc++/support/error_details.h", 
+      "include/grpcpp/support/error_details.h", 
       "src/cpp/util/error_details.cc"
     ], 
     "third_party": false, 
@@ -6559,6 +7021,7 @@
     ], 
     "headers": [
       "include/grpc++/ext/proto_server_reflection_plugin.h", 
+      "include/grpcpp/ext/proto_server_reflection_plugin.h", 
       "src/cpp/ext/proto_server_reflection.h"
     ], 
     "is_filegroup": false, 
@@ -6566,6 +7029,7 @@
     "name": "grpc++_reflection", 
     "src": [
       "include/grpc++/ext/proto_server_reflection_plugin.h", 
+      "include/grpcpp/ext/proto_server_reflection_plugin.h", 
       "src/cpp/ext/proto_server_reflection.cc", 
       "src/cpp/ext/proto_server_reflection.h", 
       "src/cpp/ext/proto_server_reflection_plugin.cc"
@@ -6599,6 +7063,9 @@
       "grpc_test_util"
     ], 
     "headers": [
+      "src/proto/grpc/channelz/channelz.grpc.pb.h", 
+      "src/proto/grpc/channelz/channelz.pb.h", 
+      "src/proto/grpc/channelz/channelz_mock.grpc.pb.h", 
       "src/proto/grpc/health/v1/health.grpc.pb.h", 
       "src/proto/grpc/health/v1/health.pb.h", 
       "src/proto/grpc/health/v1/health_mock.grpc.pb.h", 
@@ -6613,6 +7080,7 @@
       "src/proto/grpc/testing/echo_mock.grpc.pb.h", 
       "test/cpp/end2end/test_service_impl.h", 
       "test/cpp/util/byte_buffer_proto_helper.h", 
+      "test/cpp/util/channel_trace_proto_helper.h", 
       "test/cpp/util/create_test_channel.h", 
       "test/cpp/util/string_ref_helper.h", 
       "test/cpp/util/subprocess.h", 
@@ -6626,6 +7094,8 @@
       "test/cpp/end2end/test_service_impl.h", 
       "test/cpp/util/byte_buffer_proto_helper.cc", 
       "test/cpp/util/byte_buffer_proto_helper.h", 
+      "test/cpp/util/channel_trace_proto_helper.cc", 
+      "test/cpp/util/channel_trace_proto_helper.h", 
       "test/cpp/util/create_test_channel.cc", 
       "test/cpp/util/create_test_channel.h", 
       "test/cpp/util/string_ref_helper.cc", 
@@ -7067,23 +7537,82 @@
       "third_party/boringssl/crypto/cipher_extra/internal.h", 
       "third_party/boringssl/crypto/conf/conf_def.h", 
       "third_party/boringssl/crypto/conf/internal.h", 
-      "third_party/boringssl/crypto/curve25519/internal.h", 
       "third_party/boringssl/crypto/err/internal.h", 
       "third_party/boringssl/crypto/evp/internal.h", 
+      "third_party/boringssl/crypto/fipsmodule/aes/aes.c", 
       "third_party/boringssl/crypto/fipsmodule/aes/internal.h", 
+      "third_party/boringssl/crypto/fipsmodule/aes/key_wrap.c", 
+      "third_party/boringssl/crypto/fipsmodule/aes/mode_wrappers.c", 
+      "third_party/boringssl/crypto/fipsmodule/bn/add.c", 
+      "third_party/boringssl/crypto/fipsmodule/bn/asm/x86_64-gcc.c", 
+      "third_party/boringssl/crypto/fipsmodule/bn/bn.c", 
+      "third_party/boringssl/crypto/fipsmodule/bn/bytes.c", 
+      "third_party/boringssl/crypto/fipsmodule/bn/cmp.c", 
+      "third_party/boringssl/crypto/fipsmodule/bn/ctx.c", 
+      "third_party/boringssl/crypto/fipsmodule/bn/div.c", 
+      "third_party/boringssl/crypto/fipsmodule/bn/exponentiation.c", 
+      "third_party/boringssl/crypto/fipsmodule/bn/gcd.c", 
+      "third_party/boringssl/crypto/fipsmodule/bn/generic.c", 
       "third_party/boringssl/crypto/fipsmodule/bn/internal.h", 
+      "third_party/boringssl/crypto/fipsmodule/bn/jacobi.c", 
+      "third_party/boringssl/crypto/fipsmodule/bn/montgomery.c", 
+      "third_party/boringssl/crypto/fipsmodule/bn/montgomery_inv.c", 
+      "third_party/boringssl/crypto/fipsmodule/bn/mul.c", 
+      "third_party/boringssl/crypto/fipsmodule/bn/prime.c", 
+      "third_party/boringssl/crypto/fipsmodule/bn/random.c", 
+      "third_party/boringssl/crypto/fipsmodule/bn/rsaz_exp.c", 
       "third_party/boringssl/crypto/fipsmodule/bn/rsaz_exp.h", 
+      "third_party/boringssl/crypto/fipsmodule/bn/shift.c", 
+      "third_party/boringssl/crypto/fipsmodule/bn/sqrt.c", 
+      "third_party/boringssl/crypto/fipsmodule/cipher/aead.c", 
+      "third_party/boringssl/crypto/fipsmodule/cipher/cipher.c", 
+      "third_party/boringssl/crypto/fipsmodule/cipher/e_aes.c", 
+      "third_party/boringssl/crypto/fipsmodule/cipher/e_des.c", 
       "third_party/boringssl/crypto/fipsmodule/cipher/internal.h", 
       "third_party/boringssl/crypto/fipsmodule/delocate.h", 
+      "third_party/boringssl/crypto/fipsmodule/des/des.c", 
       "third_party/boringssl/crypto/fipsmodule/des/internal.h", 
+      "third_party/boringssl/crypto/fipsmodule/digest/digest.c", 
+      "third_party/boringssl/crypto/fipsmodule/digest/digests.c", 
       "third_party/boringssl/crypto/fipsmodule/digest/internal.h", 
       "third_party/boringssl/crypto/fipsmodule/digest/md32_common.h", 
+      "third_party/boringssl/crypto/fipsmodule/ec/ec.c", 
+      "third_party/boringssl/crypto/fipsmodule/ec/ec_key.c", 
+      "third_party/boringssl/crypto/fipsmodule/ec/ec_montgomery.c", 
       "third_party/boringssl/crypto/fipsmodule/ec/internal.h", 
+      "third_party/boringssl/crypto/fipsmodule/ec/oct.c", 
+      "third_party/boringssl/crypto/fipsmodule/ec/p224-64.c", 
+      "third_party/boringssl/crypto/fipsmodule/ec/p256-64.c", 
       "third_party/boringssl/crypto/fipsmodule/ec/p256-x86_64-table.h", 
+      "third_party/boringssl/crypto/fipsmodule/ec/p256-x86_64.c", 
       "third_party/boringssl/crypto/fipsmodule/ec/p256-x86_64.h", 
+      "third_party/boringssl/crypto/fipsmodule/ec/simple.c", 
+      "third_party/boringssl/crypto/fipsmodule/ec/util-64.c", 
+      "third_party/boringssl/crypto/fipsmodule/ec/wnaf.c", 
+      "third_party/boringssl/crypto/fipsmodule/ecdsa/ecdsa.c", 
+      "third_party/boringssl/crypto/fipsmodule/hmac/hmac.c", 
+      "third_party/boringssl/crypto/fipsmodule/md4/md4.c", 
+      "third_party/boringssl/crypto/fipsmodule/md5/md5.c", 
+      "third_party/boringssl/crypto/fipsmodule/modes/cbc.c", 
+      "third_party/boringssl/crypto/fipsmodule/modes/cfb.c", 
+      "third_party/boringssl/crypto/fipsmodule/modes/ctr.c", 
+      "third_party/boringssl/crypto/fipsmodule/modes/gcm.c", 
       "third_party/boringssl/crypto/fipsmodule/modes/internal.h", 
+      "third_party/boringssl/crypto/fipsmodule/modes/ofb.c", 
+      "third_party/boringssl/crypto/fipsmodule/modes/polyval.c", 
+      "third_party/boringssl/crypto/fipsmodule/rand/ctrdrbg.c", 
       "third_party/boringssl/crypto/fipsmodule/rand/internal.h", 
+      "third_party/boringssl/crypto/fipsmodule/rand/rand.c", 
+      "third_party/boringssl/crypto/fipsmodule/rand/urandom.c", 
+      "third_party/boringssl/crypto/fipsmodule/rsa/blinding.c", 
       "third_party/boringssl/crypto/fipsmodule/rsa/internal.h", 
+      "third_party/boringssl/crypto/fipsmodule/rsa/padding.c", 
+      "third_party/boringssl/crypto/fipsmodule/rsa/rsa.c", 
+      "third_party/boringssl/crypto/fipsmodule/rsa/rsa_impl.c", 
+      "third_party/boringssl/crypto/fipsmodule/sha/sha1-altivec.c", 
+      "third_party/boringssl/crypto/fipsmodule/sha/sha1.c", 
+      "third_party/boringssl/crypto/fipsmodule/sha/sha256.c", 
+      "third_party/boringssl/crypto/fipsmodule/sha/sha512.c", 
       "third_party/boringssl/crypto/internal.h", 
       "third_party/boringssl/crypto/obj/obj_dat.h", 
       "third_party/boringssl/crypto/pkcs7/internal.h", 
@@ -7168,7 +7697,8 @@
       "third_party/boringssl/include/openssl/x509.h", 
       "third_party/boringssl/include/openssl/x509_vfy.h", 
       "third_party/boringssl/include/openssl/x509v3.h", 
-      "third_party/boringssl/ssl/internal.h"
+      "third_party/boringssl/ssl/internal.h", 
+      "third_party/boringssl/third_party/fiat/internal.h"
     ], 
     "is_filegroup": false, 
     "language": "c", 
@@ -7251,6 +7781,19 @@
     "headers": [], 
     "is_filegroup": false, 
     "language": "c++", 
+    "name": "boringssl_buf_test_lib", 
+    "src": [], 
+    "third_party": true, 
+    "type": "lib"
+  }, 
+  {
+    "deps": [
+      "boringssl", 
+      "boringssl_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
     "name": "boringssl_bytestring_test_lib", 
     "src": [], 
     "third_party": true, 
@@ -8022,6 +8565,21 @@
       "test/core/end2end/tests/request_with_flags.cc", 
       "test/core/end2end/tests/request_with_payload.cc", 
       "test/core/end2end/tests/resource_quota_server.cc", 
+      "test/core/end2end/tests/retry.cc", 
+      "test/core/end2end/tests/retry_cancellation.cc", 
+      "test/core/end2end/tests/retry_disabled.cc", 
+      "test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc", 
+      "test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc", 
+      "test/core/end2end/tests/retry_non_retriable_status.cc", 
+      "test/core/end2end/tests/retry_recv_initial_metadata.cc", 
+      "test/core/end2end/tests/retry_recv_message.cc", 
+      "test/core/end2end/tests/retry_server_pushback_delay.cc", 
+      "test/core/end2end/tests/retry_server_pushback_disabled.cc", 
+      "test/core/end2end/tests/retry_streaming.cc", 
+      "test/core/end2end/tests/retry_streaming_after_commit.cc", 
+      "test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc", 
+      "test/core/end2end/tests/retry_throttled.cc", 
+      "test/core/end2end/tests/retry_too_many_attempts.cc", 
       "test/core/end2end/tests/server_finishes_request.cc", 
       "test/core/end2end/tests/shutdown_finishes_calls.cc", 
       "test/core/end2end/tests/shutdown_finishes_tags.cc", 
@@ -8104,6 +8662,21 @@
       "test/core/end2end/tests/request_with_flags.cc", 
       "test/core/end2end/tests/request_with_payload.cc", 
       "test/core/end2end/tests/resource_quota_server.cc", 
+      "test/core/end2end/tests/retry.cc", 
+      "test/core/end2end/tests/retry_cancellation.cc", 
+      "test/core/end2end/tests/retry_disabled.cc", 
+      "test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc", 
+      "test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc", 
+      "test/core/end2end/tests/retry_non_retriable_status.cc", 
+      "test/core/end2end/tests/retry_recv_initial_metadata.cc", 
+      "test/core/end2end/tests/retry_recv_message.cc", 
+      "test/core/end2end/tests/retry_server_pushback_delay.cc", 
+      "test/core/end2end/tests/retry_server_pushback_disabled.cc", 
+      "test/core/end2end/tests/retry_streaming.cc", 
+      "test/core/end2end/tests/retry_streaming_after_commit.cc", 
+      "test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc", 
+      "test/core/end2end/tests/retry_throttled.cc", 
+      "test/core/end2end/tests/retry_too_many_attempts.cc", 
       "test/core/end2end/tests/server_finishes_request.cc", 
       "test/core/end2end/tests/shutdown_finishes_calls.cc", 
       "test/core/end2end/tests/shutdown_finishes_tags.cc", 
@@ -8125,6 +8698,138 @@
   }, 
   {
     "deps": [
+      "nanopb"
+    ], 
+    "headers": [
+      "src/core/tsi/alts/handshaker/altscontext.pb.h", 
+      "src/core/tsi/alts/handshaker/handshaker.pb.h", 
+      "src/core/tsi/alts/handshaker/transport_security_common.pb.h"
+    ], 
+    "is_filegroup": true, 
+    "language": "c", 
+    "name": "alts_proto", 
+    "src": [
+      "src/core/tsi/alts/handshaker/altscontext.pb.c", 
+      "src/core/tsi/alts/handshaker/altscontext.pb.h", 
+      "src/core/tsi/alts/handshaker/handshaker.pb.c", 
+      "src/core/tsi/alts/handshaker/handshaker.pb.h", 
+      "src/core/tsi/alts/handshaker/transport_security_common.pb.c", 
+      "src/core/tsi/alts/handshaker/transport_security_common.pb.h"
+    ], 
+    "third_party": false, 
+    "type": "filegroup"
+  }, 
+  {
+    "deps": [
+      "alts_util", 
+      "gpr", 
+      "grpc_base", 
+      "grpc_transport_chttp2_client_insecure", 
+      "tsi", 
+      "tsi_interface"
+    ], 
+    "headers": [
+      "src/core/tsi/alts/crypt/gsec.h", 
+      "src/core/tsi/alts/frame_protector/alts_counter.h", 
+      "src/core/tsi/alts/frame_protector/alts_crypter.h", 
+      "src/core/tsi/alts/frame_protector/alts_frame_protector.h", 
+      "src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h", 
+      "src/core/tsi/alts/frame_protector/frame_handler.h", 
+      "src/core/tsi/alts/handshaker/alts_handshaker_client.h", 
+      "src/core/tsi/alts/handshaker/alts_tsi_event.h", 
+      "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h", 
+      "src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h", 
+      "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h", 
+      "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h", 
+      "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h", 
+      "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h", 
+      "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h", 
+      "src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h"
+    ], 
+    "is_filegroup": true, 
+    "language": "c", 
+    "name": "alts_tsi", 
+    "src": [
+      "src/core/tsi/alts/crypt/aes_gcm.cc", 
+      "src/core/tsi/alts/crypt/gsec.cc", 
+      "src/core/tsi/alts/crypt/gsec.h", 
+      "src/core/tsi/alts/frame_protector/alts_counter.cc", 
+      "src/core/tsi/alts/frame_protector/alts_counter.h", 
+      "src/core/tsi/alts/frame_protector/alts_crypter.cc", 
+      "src/core/tsi/alts/frame_protector/alts_crypter.h", 
+      "src/core/tsi/alts/frame_protector/alts_frame_protector.cc", 
+      "src/core/tsi/alts/frame_protector/alts_frame_protector.h", 
+      "src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc", 
+      "src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.h", 
+      "src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc", 
+      "src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc", 
+      "src/core/tsi/alts/frame_protector/frame_handler.cc", 
+      "src/core/tsi/alts/frame_protector/frame_handler.h", 
+      "src/core/tsi/alts/handshaker/alts_handshaker_client.cc", 
+      "src/core/tsi/alts/handshaker/alts_handshaker_client.h", 
+      "src/core/tsi/alts/handshaker/alts_tsi_event.cc", 
+      "src/core/tsi/alts/handshaker/alts_tsi_event.h", 
+      "src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc", 
+      "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h", 
+      "src/core/tsi/alts/handshaker/alts_tsi_handshaker_private.h", 
+      "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc", 
+      "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h", 
+      "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc", 
+      "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h", 
+      "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h", 
+      "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc", 
+      "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h", 
+      "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc", 
+      "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h", 
+      "src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc", 
+      "src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h"
+    ], 
+    "third_party": false, 
+    "type": "filegroup"
+  }, 
+  {
+    "deps": [
+      "alts_proto", 
+      "gpr", 
+      "grpc_base", 
+      "nanopb", 
+      "tsi_interface"
+    ], 
+    "headers": [
+      "src/core/lib/security/credentials/alts/check_gcp_environment.h", 
+      "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h", 
+      "src/core/tsi/alts/handshaker/alts_handshaker_service_api.h", 
+      "src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h", 
+      "src/core/tsi/alts/handshaker/alts_tsi_utils.h", 
+      "src/core/tsi/alts/handshaker/transport_security_common_api.h"
+    ], 
+    "is_filegroup": true, 
+    "language": "c", 
+    "name": "alts_util", 
+    "src": [
+      "src/core/lib/security/credentials/alts/check_gcp_environment.cc", 
+      "src/core/lib/security/credentials/alts/check_gcp_environment.h", 
+      "src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc", 
+      "src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc", 
+      "src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc", 
+      "src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc", 
+      "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc", 
+      "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h", 
+      "src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc", 
+      "src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc", 
+      "src/core/tsi/alts/handshaker/alts_handshaker_service_api.h", 
+      "src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc", 
+      "src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.h", 
+      "src/core/tsi/alts/handshaker/alts_tsi_utils.cc", 
+      "src/core/tsi/alts/handshaker/alts_tsi_utils.h", 
+      "src/core/tsi/alts/handshaker/transport_security_common_api.cc", 
+      "src/core/tsi/alts/handshaker/transport_security_common_api.h"
+    ], 
+    "third_party": false, 
+    "type": "filegroup"
+  }, 
+  {
+    "deps": [
       "gpr", 
       "grpc_base", 
       "nanopb"
@@ -8146,6 +8851,23 @@
     "deps": [
       "gpr_base_headers"
     ], 
+    "headers": [
+      "test/core/util/cmdline.h"
+    ], 
+    "is_filegroup": true, 
+    "language": "c", 
+    "name": "cmdline", 
+    "src": [
+      "test/core/util/cmdline.cc", 
+      "test/core/util/cmdline.h"
+    ], 
+    "third_party": false, 
+    "type": "filegroup"
+  }, 
+  {
+    "deps": [
+      "gpr_base_headers"
+    ], 
     "headers": [], 
     "is_filegroup": true, 
     "language": "c", 
@@ -8154,8 +8876,6 @@
       "src/core/lib/gpr/alloc.cc", 
       "src/core/lib/gpr/arena.cc", 
       "src/core/lib/gpr/atm.cc", 
-      "src/core/lib/gpr/avl.cc", 
-      "src/core/lib/gpr/cmdline.cc", 
       "src/core/lib/gpr/cpu_iphone.cc", 
       "src/core/lib/gpr/cpu_linux.cc", 
       "src/core/lib/gpr/cpu_posix.cc", 
@@ -8176,14 +8896,9 @@
       "src/core/lib/gpr/string_posix.cc", 
       "src/core/lib/gpr/string_util_windows.cc", 
       "src/core/lib/gpr/string_windows.cc", 
-      "src/core/lib/gpr/subprocess_posix.cc", 
-      "src/core/lib/gpr/subprocess_windows.cc", 
       "src/core/lib/gpr/sync.cc", 
       "src/core/lib/gpr/sync_posix.cc", 
       "src/core/lib/gpr/sync_windows.cc", 
-      "src/core/lib/gpr/thd.cc", 
-      "src/core/lib/gpr/thd_posix.cc", 
-      "src/core/lib/gpr/thd_windows.cc", 
       "src/core/lib/gpr/time.cc", 
       "src/core/lib/gpr/time_posix.cc", 
       "src/core/lib/gpr/time_precise.cc", 
@@ -8193,6 +8908,8 @@
       "src/core/lib/gpr/tmpfile_posix.cc", 
       "src/core/lib/gpr/tmpfile_windows.cc", 
       "src/core/lib/gpr/wrap_memcpy.cc", 
+      "src/core/lib/gprpp/thd_posix.cc", 
+      "src/core/lib/gprpp/thd_windows.cc", 
       "src/core/lib/profiling/basic_timers.cc", 
       "src/core/lib/profiling/stap_timers.cc"
     ], 
@@ -8209,44 +8926,41 @@
       "include/grpc/support/atm_gcc_atomic.h", 
       "include/grpc/support/atm_gcc_sync.h", 
       "include/grpc/support/atm_windows.h", 
-      "include/grpc/support/avl.h", 
-      "include/grpc/support/cmdline.h", 
       "include/grpc/support/cpu.h", 
-      "include/grpc/support/host_port.h", 
       "include/grpc/support/log.h", 
       "include/grpc/support/log_windows.h", 
       "include/grpc/support/port_platform.h", 
       "include/grpc/support/string_util.h", 
-      "include/grpc/support/subprocess.h", 
       "include/grpc/support/sync.h", 
       "include/grpc/support/sync_custom.h", 
       "include/grpc/support/sync_generic.h", 
       "include/grpc/support/sync_posix.h", 
       "include/grpc/support/sync_windows.h", 
-      "include/grpc/support/thd.h", 
+      "include/grpc/support/thd_id.h", 
       "include/grpc/support/time.h", 
-      "include/grpc/support/tls.h", 
-      "include/grpc/support/tls_gcc.h", 
-      "include/grpc/support/tls_msvc.h", 
-      "include/grpc/support/tls_pthread.h", 
-      "include/grpc/support/useful.h", 
       "src/core/lib/gpr/arena.h", 
       "src/core/lib/gpr/env.h", 
       "src/core/lib/gpr/fork.h", 
+      "src/core/lib/gpr/host_port.h", 
       "src/core/lib/gpr/mpscq.h", 
       "src/core/lib/gpr/murmur_hash.h", 
       "src/core/lib/gpr/spinlock.h", 
       "src/core/lib/gpr/string.h", 
       "src/core/lib/gpr/string_windows.h", 
-      "src/core/lib/gpr/thd_internal.h", 
       "src/core/lib/gpr/time_precise.h", 
+      "src/core/lib/gpr/tls.h", 
+      "src/core/lib/gpr/tls_gcc.h", 
+      "src/core/lib/gpr/tls_msvc.h", 
+      "src/core/lib/gpr/tls_pthread.h", 
       "src/core/lib/gpr/tmpfile.h", 
+      "src/core/lib/gpr/useful.h", 
       "src/core/lib/gprpp/abstract.h", 
       "src/core/lib/gprpp/atomic.h", 
       "src/core/lib/gprpp/atomic_with_atm.h", 
       "src/core/lib/gprpp/atomic_with_std.h", 
       "src/core/lib/gprpp/manual_constructor.h", 
       "src/core/lib/gprpp/memory.h", 
+      "src/core/lib/gprpp/thd.h", 
       "src/core/lib/profiling/timers.h"
     ], 
     "is_filegroup": true, 
@@ -8258,44 +8972,41 @@
       "include/grpc/support/atm_gcc_atomic.h", 
       "include/grpc/support/atm_gcc_sync.h", 
       "include/grpc/support/atm_windows.h", 
-      "include/grpc/support/avl.h", 
-      "include/grpc/support/cmdline.h", 
       "include/grpc/support/cpu.h", 
-      "include/grpc/support/host_port.h", 
       "include/grpc/support/log.h", 
       "include/grpc/support/log_windows.h", 
       "include/grpc/support/port_platform.h", 
       "include/grpc/support/string_util.h", 
-      "include/grpc/support/subprocess.h", 
       "include/grpc/support/sync.h", 
       "include/grpc/support/sync_custom.h", 
       "include/grpc/support/sync_generic.h", 
       "include/grpc/support/sync_posix.h", 
       "include/grpc/support/sync_windows.h", 
-      "include/grpc/support/thd.h", 
+      "include/grpc/support/thd_id.h", 
       "include/grpc/support/time.h", 
-      "include/grpc/support/tls.h", 
-      "include/grpc/support/tls_gcc.h", 
-      "include/grpc/support/tls_msvc.h", 
-      "include/grpc/support/tls_pthread.h", 
-      "include/grpc/support/useful.h", 
       "src/core/lib/gpr/arena.h", 
       "src/core/lib/gpr/env.h", 
       "src/core/lib/gpr/fork.h", 
+      "src/core/lib/gpr/host_port.h", 
       "src/core/lib/gpr/mpscq.h", 
       "src/core/lib/gpr/murmur_hash.h", 
       "src/core/lib/gpr/spinlock.h", 
       "src/core/lib/gpr/string.h", 
       "src/core/lib/gpr/string_windows.h", 
-      "src/core/lib/gpr/thd_internal.h", 
       "src/core/lib/gpr/time_precise.h", 
+      "src/core/lib/gpr/tls.h", 
+      "src/core/lib/gpr/tls_gcc.h", 
+      "src/core/lib/gpr/tls_msvc.h", 
+      "src/core/lib/gpr/tls_pthread.h", 
       "src/core/lib/gpr/tmpfile.h", 
+      "src/core/lib/gpr/useful.h", 
       "src/core/lib/gprpp/abstract.h", 
       "src/core/lib/gprpp/atomic.h", 
       "src/core/lib/gprpp/atomic_with_atm.h", 
       "src/core/lib/gprpp/atomic_with_std.h", 
       "src/core/lib/gprpp/manual_constructor.h", 
       "src/core/lib/gprpp/memory.h", 
+      "src/core/lib/gprpp/thd.h", 
       "src/core/lib/profiling/timers.h"
     ], 
     "third_party": false, 
@@ -8381,17 +9092,20 @@
     "language": "c", 
     "name": "grpc_base", 
     "src": [
+      "src/core/lib/avl/avl.cc", 
       "src/core/lib/backoff/backoff.cc", 
       "src/core/lib/channel/channel_args.cc", 
       "src/core/lib/channel/channel_stack.cc", 
       "src/core/lib/channel/channel_stack_builder.cc", 
+      "src/core/lib/channel/channel_trace.cc", 
+      "src/core/lib/channel/channel_trace_registry.cc", 
       "src/core/lib/channel/connected_channel.cc", 
       "src/core/lib/channel/handshaker.cc", 
       "src/core/lib/channel/handshaker_factory.cc", 
       "src/core/lib/channel/handshaker_registry.cc", 
+      "src/core/lib/channel/status_util.cc", 
       "src/core/lib/compression/compression.cc", 
       "src/core/lib/compression/compression_internal.cc", 
-      "src/core/lib/compression/compression_ruby.cc", 
       "src/core/lib/compression/message_compress.cc", 
       "src/core/lib/compression/stream_compression.cc", 
       "src/core/lib/compression/stream_compression_gzip.cc", 
@@ -8423,6 +9137,8 @@
       "src/core/lib/iomgr/gethostname_sysconf.cc", 
       "src/core/lib/iomgr/iocp_windows.cc", 
       "src/core/lib/iomgr/iomgr.cc", 
+      "src/core/lib/iomgr/iomgr_custom.cc", 
+      "src/core/lib/iomgr/iomgr_internal.cc", 
       "src/core/lib/iomgr/iomgr_posix.cc", 
       "src/core/lib/iomgr/iomgr_uv.cc", 
       "src/core/lib/iomgr/iomgr_windows.cc", 
@@ -8431,12 +9147,16 @@
       "src/core/lib/iomgr/lockfree_event.cc", 
       "src/core/lib/iomgr/network_status_tracker.cc", 
       "src/core/lib/iomgr/polling_entity.cc", 
-      "src/core/lib/iomgr/pollset_set_uv.cc", 
+      "src/core/lib/iomgr/pollset.cc", 
+      "src/core/lib/iomgr/pollset_custom.cc", 
+      "src/core/lib/iomgr/pollset_set.cc", 
+      "src/core/lib/iomgr/pollset_set_custom.cc", 
       "src/core/lib/iomgr/pollset_set_windows.cc", 
       "src/core/lib/iomgr/pollset_uv.cc", 
       "src/core/lib/iomgr/pollset_windows.cc", 
+      "src/core/lib/iomgr/resolve_address.cc", 
+      "src/core/lib/iomgr/resolve_address_custom.cc", 
       "src/core/lib/iomgr/resolve_address_posix.cc", 
-      "src/core/lib/iomgr/resolve_address_uv.cc", 
       "src/core/lib/iomgr/resolve_address_windows.cc", 
       "src/core/lib/iomgr/resource_quota.cc", 
       "src/core/lib/iomgr/sockaddr_utils.cc", 
@@ -8448,19 +9168,24 @@
       "src/core/lib/iomgr/socket_utils_uv.cc", 
       "src/core/lib/iomgr/socket_utils_windows.cc", 
       "src/core/lib/iomgr/socket_windows.cc", 
+      "src/core/lib/iomgr/tcp_client.cc", 
+      "src/core/lib/iomgr/tcp_client_custom.cc", 
       "src/core/lib/iomgr/tcp_client_posix.cc", 
-      "src/core/lib/iomgr/tcp_client_uv.cc", 
       "src/core/lib/iomgr/tcp_client_windows.cc", 
+      "src/core/lib/iomgr/tcp_custom.cc", 
       "src/core/lib/iomgr/tcp_posix.cc", 
+      "src/core/lib/iomgr/tcp_server.cc", 
+      "src/core/lib/iomgr/tcp_server_custom.cc", 
       "src/core/lib/iomgr/tcp_server_posix.cc", 
       "src/core/lib/iomgr/tcp_server_utils_posix_common.cc", 
       "src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc", 
       "src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc", 
-      "src/core/lib/iomgr/tcp_server_uv.cc", 
       "src/core/lib/iomgr/tcp_server_windows.cc", 
       "src/core/lib/iomgr/tcp_uv.cc", 
       "src/core/lib/iomgr/tcp_windows.cc", 
       "src/core/lib/iomgr/time_averaged_stats.cc", 
+      "src/core/lib/iomgr/timer.cc", 
+      "src/core/lib/iomgr/timer_custom.cc", 
       "src/core/lib/iomgr/timer_generic.cc", 
       "src/core/lib/iomgr/timer_heap.cc", 
       "src/core/lib/iomgr/timer_manager.cc", 
@@ -8481,7 +9206,6 @@
       "src/core/lib/slice/percent_encoding.cc", 
       "src/core/lib/slice/slice.cc", 
       "src/core/lib/slice/slice_buffer.cc", 
-      "src/core/lib/slice/slice_hash_table.cc", 
       "src/core/lib/slice/slice_intern.cc", 
       "src/core/lib/slice/slice_string_helpers.cc", 
       "src/core/lib/surface/api_trace.cc", 
@@ -8512,6 +9236,7 @@
       "src/core/lib/transport/service_config.cc", 
       "src/core/lib/transport/static_metadata.cc", 
       "src/core/lib/transport/status_conversion.cc", 
+      "src/core/lib/transport/status_metadata.cc", 
       "src/core/lib/transport/timeout_encoding.cc", 
       "src/core/lib/transport/transport.cc", 
       "src/core/lib/transport/transport_op_string.cc"
@@ -8529,7 +9254,6 @@
       "include/grpc/byte_buffer.h", 
       "include/grpc/byte_buffer_reader.h", 
       "include/grpc/compression.h", 
-      "include/grpc/compression_ruby.h", 
       "include/grpc/fork.h", 
       "include/grpc/grpc.h", 
       "include/grpc/grpc_posix.h", 
@@ -8539,15 +9263,19 @@
       "include/grpc/slice_buffer.h", 
       "include/grpc/status.h", 
       "include/grpc/support/workaround_list.h", 
+      "src/core/lib/avl/avl.h", 
       "src/core/lib/backoff/backoff.h", 
       "src/core/lib/channel/channel_args.h", 
       "src/core/lib/channel/channel_stack.h", 
       "src/core/lib/channel/channel_stack_builder.h", 
+      "src/core/lib/channel/channel_trace.h", 
+      "src/core/lib/channel/channel_trace_registry.h", 
       "src/core/lib/channel/connected_channel.h", 
       "src/core/lib/channel/context.h", 
       "src/core/lib/channel/handshaker.h", 
       "src/core/lib/channel/handshaker_factory.h", 
       "src/core/lib/channel/handshaker_registry.h", 
+      "src/core/lib/channel/status_util.h", 
       "src/core/lib/compression/algorithm_metadata.h", 
       "src/core/lib/compression/compression_internal.h", 
       "src/core/lib/compression/message_compress.h", 
@@ -8582,9 +9310,9 @@
       "src/core/lib/iomgr/gethostname.h", 
       "src/core/lib/iomgr/iocp_windows.h", 
       "src/core/lib/iomgr/iomgr.h", 
+      "src/core/lib/iomgr/iomgr_custom.h", 
       "src/core/lib/iomgr/iomgr_internal.h", 
       "src/core/lib/iomgr/iomgr_posix.h", 
-      "src/core/lib/iomgr/iomgr_uv.h", 
       "src/core/lib/iomgr/is_epollexclusive_available.h", 
       "src/core/lib/iomgr/load_file.h", 
       "src/core/lib/iomgr/lockfree_event.h", 
@@ -8592,14 +9320,17 @@
       "src/core/lib/iomgr/network_status_tracker.h", 
       "src/core/lib/iomgr/polling_entity.h", 
       "src/core/lib/iomgr/pollset.h", 
+      "src/core/lib/iomgr/pollset_custom.h", 
       "src/core/lib/iomgr/pollset_set.h", 
+      "src/core/lib/iomgr/pollset_set_custom.h", 
       "src/core/lib/iomgr/pollset_set_windows.h", 
-      "src/core/lib/iomgr/pollset_uv.h", 
       "src/core/lib/iomgr/pollset_windows.h", 
       "src/core/lib/iomgr/port.h", 
       "src/core/lib/iomgr/resolve_address.h", 
+      "src/core/lib/iomgr/resolve_address_custom.h", 
       "src/core/lib/iomgr/resource_quota.h", 
       "src/core/lib/iomgr/sockaddr.h", 
+      "src/core/lib/iomgr/sockaddr_custom.h", 
       "src/core/lib/iomgr/sockaddr_posix.h", 
       "src/core/lib/iomgr/sockaddr_utils.h", 
       "src/core/lib/iomgr/sockaddr_windows.h", 
@@ -8611,17 +9342,16 @@
       "src/core/lib/iomgr/sys_epoll_wrapper.h", 
       "src/core/lib/iomgr/tcp_client.h", 
       "src/core/lib/iomgr/tcp_client_posix.h", 
+      "src/core/lib/iomgr/tcp_custom.h", 
       "src/core/lib/iomgr/tcp_posix.h", 
       "src/core/lib/iomgr/tcp_server.h", 
       "src/core/lib/iomgr/tcp_server_utils_posix.h", 
-      "src/core/lib/iomgr/tcp_uv.h", 
       "src/core/lib/iomgr/tcp_windows.h", 
       "src/core/lib/iomgr/time_averaged_stats.h", 
       "src/core/lib/iomgr/timer.h", 
-      "src/core/lib/iomgr/timer_generic.h", 
+      "src/core/lib/iomgr/timer_custom.h", 
       "src/core/lib/iomgr/timer_heap.h", 
       "src/core/lib/iomgr/timer_manager.h", 
-      "src/core/lib/iomgr/timer_uv.h", 
       "src/core/lib/iomgr/udp_server.h", 
       "src/core/lib/iomgr/unix_sockets_posix.h", 
       "src/core/lib/iomgr/wakeup_fd_cv.h", 
@@ -8636,6 +9366,7 @@
       "src/core/lib/slice/slice_hash_table.h", 
       "src/core/lib/slice/slice_internal.h", 
       "src/core/lib/slice/slice_string_helpers.h", 
+      "src/core/lib/slice/slice_weak_hash_table.h", 
       "src/core/lib/surface/api_trace.h", 
       "src/core/lib/surface/call.h", 
       "src/core/lib/surface/call_test_only.h", 
@@ -8660,6 +9391,7 @@
       "src/core/lib/transport/service_config.h", 
       "src/core/lib/transport/static_metadata.h", 
       "src/core/lib/transport/status_conversion.h", 
+      "src/core/lib/transport/status_metadata.h", 
       "src/core/lib/transport/timeout_encoding.h", 
       "src/core/lib/transport/transport.h", 
       "src/core/lib/transport/transport_impl.h"
@@ -8671,7 +9403,6 @@
       "include/grpc/byte_buffer.h", 
       "include/grpc/byte_buffer_reader.h", 
       "include/grpc/compression.h", 
-      "include/grpc/compression_ruby.h", 
       "include/grpc/fork.h", 
       "include/grpc/grpc.h", 
       "include/grpc/grpc_posix.h", 
@@ -8681,15 +9412,19 @@
       "include/grpc/slice_buffer.h", 
       "include/grpc/status.h", 
       "include/grpc/support/workaround_list.h", 
+      "src/core/lib/avl/avl.h", 
       "src/core/lib/backoff/backoff.h", 
       "src/core/lib/channel/channel_args.h", 
       "src/core/lib/channel/channel_stack.h", 
       "src/core/lib/channel/channel_stack_builder.h", 
+      "src/core/lib/channel/channel_trace.h", 
+      "src/core/lib/channel/channel_trace_registry.h", 
       "src/core/lib/channel/connected_channel.h", 
       "src/core/lib/channel/context.h", 
       "src/core/lib/channel/handshaker.h", 
       "src/core/lib/channel/handshaker_factory.h", 
       "src/core/lib/channel/handshaker_registry.h", 
+      "src/core/lib/channel/status_util.h", 
       "src/core/lib/compression/algorithm_metadata.h", 
       "src/core/lib/compression/compression_internal.h", 
       "src/core/lib/compression/message_compress.h", 
@@ -8724,9 +9459,9 @@
       "src/core/lib/iomgr/gethostname.h", 
       "src/core/lib/iomgr/iocp_windows.h", 
       "src/core/lib/iomgr/iomgr.h", 
+      "src/core/lib/iomgr/iomgr_custom.h", 
       "src/core/lib/iomgr/iomgr_internal.h", 
       "src/core/lib/iomgr/iomgr_posix.h", 
-      "src/core/lib/iomgr/iomgr_uv.h", 
       "src/core/lib/iomgr/is_epollexclusive_available.h", 
       "src/core/lib/iomgr/load_file.h", 
       "src/core/lib/iomgr/lockfree_event.h", 
@@ -8734,14 +9469,17 @@
       "src/core/lib/iomgr/network_status_tracker.h", 
       "src/core/lib/iomgr/polling_entity.h", 
       "src/core/lib/iomgr/pollset.h", 
+      "src/core/lib/iomgr/pollset_custom.h", 
       "src/core/lib/iomgr/pollset_set.h", 
+      "src/core/lib/iomgr/pollset_set_custom.h", 
       "src/core/lib/iomgr/pollset_set_windows.h", 
-      "src/core/lib/iomgr/pollset_uv.h", 
       "src/core/lib/iomgr/pollset_windows.h", 
       "src/core/lib/iomgr/port.h", 
       "src/core/lib/iomgr/resolve_address.h", 
+      "src/core/lib/iomgr/resolve_address_custom.h", 
       "src/core/lib/iomgr/resource_quota.h", 
       "src/core/lib/iomgr/sockaddr.h", 
+      "src/core/lib/iomgr/sockaddr_custom.h", 
       "src/core/lib/iomgr/sockaddr_posix.h", 
       "src/core/lib/iomgr/sockaddr_utils.h", 
       "src/core/lib/iomgr/sockaddr_windows.h", 
@@ -8753,17 +9491,16 @@
       "src/core/lib/iomgr/sys_epoll_wrapper.h", 
       "src/core/lib/iomgr/tcp_client.h", 
       "src/core/lib/iomgr/tcp_client_posix.h", 
+      "src/core/lib/iomgr/tcp_custom.h", 
       "src/core/lib/iomgr/tcp_posix.h", 
       "src/core/lib/iomgr/tcp_server.h", 
       "src/core/lib/iomgr/tcp_server_utils_posix.h", 
-      "src/core/lib/iomgr/tcp_uv.h", 
       "src/core/lib/iomgr/tcp_windows.h", 
       "src/core/lib/iomgr/time_averaged_stats.h", 
       "src/core/lib/iomgr/timer.h", 
-      "src/core/lib/iomgr/timer_generic.h", 
+      "src/core/lib/iomgr/timer_custom.h", 
       "src/core/lib/iomgr/timer_heap.h", 
       "src/core/lib/iomgr/timer_manager.h", 
-      "src/core/lib/iomgr/timer_uv.h", 
       "src/core/lib/iomgr/udp_server.h", 
       "src/core/lib/iomgr/unix_sockets_posix.h", 
       "src/core/lib/iomgr/wakeup_fd_cv.h", 
@@ -8778,6 +9515,7 @@
       "src/core/lib/slice/slice_hash_table.h", 
       "src/core/lib/slice/slice_internal.h", 
       "src/core/lib/slice/slice_string_helpers.h", 
+      "src/core/lib/slice/slice_weak_hash_table.h", 
       "src/core/lib/surface/api_trace.h", 
       "src/core/lib/surface/call.h", 
       "src/core/lib/surface/call_test_only.h", 
@@ -8802,6 +9540,7 @@
       "src/core/lib/transport/service_config.h", 
       "src/core/lib/transport/static_metadata.h", 
       "src/core/lib/transport/status_conversion.h", 
+      "src/core/lib/transport/status_metadata.h", 
       "src/core/lib/transport/timeout_encoding.h", 
       "src/core/lib/transport/transport.h", 
       "src/core/lib/transport/transport_impl.h"
@@ -8825,6 +9564,7 @@
       "src/core/ext/filters/client_channel/lb_policy.h", 
       "src/core/ext/filters/client_channel/lb_policy_factory.h", 
       "src/core/ext/filters/client_channel/lb_policy_registry.h", 
+      "src/core/ext/filters/client_channel/method_params.h", 
       "src/core/ext/filters/client_channel/parse_address.h", 
       "src/core/ext/filters/client_channel/proxy_mapper.h", 
       "src/core/ext/filters/client_channel/proxy_mapper_registry.h", 
@@ -8860,6 +9600,8 @@
       "src/core/ext/filters/client_channel/lb_policy_factory.h", 
       "src/core/ext/filters/client_channel/lb_policy_registry.cc", 
       "src/core/ext/filters/client_channel/lb_policy_registry.h", 
+      "src/core/ext/filters/client_channel/method_params.cc", 
+      "src/core/ext/filters/client_channel/method_params.h", 
       "src/core/ext/filters/client_channel/parse_address.cc", 
       "src/core/ext/filters/client_channel/parse_address.h", 
       "src/core/ext/filters/client_channel/proxy_mapper.cc", 
@@ -8868,7 +9610,6 @@
       "src/core/ext/filters/client_channel/proxy_mapper_registry.h", 
       "src/core/ext/filters/client_channel/resolver.cc", 
       "src/core/ext/filters/client_channel/resolver.h", 
-      "src/core/ext/filters/client_channel/resolver_factory.cc", 
       "src/core/ext/filters/client_channel/resolver_factory.h", 
       "src/core/ext/filters/client_channel/resolver_registry.cc", 
       "src/core/ext/filters/client_channel/resolver_registry.h", 
@@ -8967,7 +9708,6 @@
     ], 
     "headers": [
       "src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h", 
-      "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h", 
       "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h", 
       "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h", 
       "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h", 
@@ -8980,7 +9720,6 @@
       "src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc", 
       "src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h", 
       "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc", 
-      "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h", 
       "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.cc", 
       "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h", 
       "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc", 
@@ -9004,7 +9743,6 @@
     ], 
     "headers": [
       "src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h", 
-      "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h", 
       "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h", 
       "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h", 
       "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h", 
@@ -9017,7 +9755,6 @@
       "src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc", 
       "src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h", 
       "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc", 
-      "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h", 
       "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h", 
       "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc", 
       "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc", 
@@ -9196,6 +9933,7 @@
   }, 
   {
     "deps": [
+      "alts_tsi", 
       "gpr", 
       "grpc_base", 
       "grpc_transport_chttp2_alpn", 
@@ -9204,6 +9942,7 @@
     "headers": [
       "include/grpc/grpc_security.h", 
       "src/core/lib/security/context/security_context.h", 
+      "src/core/lib/security/credentials/alts/alts_credentials.h", 
       "src/core/lib/security/credentials/composite/composite_credentials.h", 
       "src/core/lib/security/credentials/credentials.h", 
       "src/core/lib/security/credentials/fake/fake_credentials.h", 
@@ -9215,11 +9954,12 @@
       "src/core/lib/security/credentials/oauth2/oauth2_credentials.h", 
       "src/core/lib/security/credentials/plugin/plugin_credentials.h", 
       "src/core/lib/security/credentials/ssl/ssl_credentials.h", 
+      "src/core/lib/security/security_connector/alts_security_connector.h", 
+      "src/core/lib/security/security_connector/security_connector.h", 
       "src/core/lib/security/transport/auth_filters.h", 
-      "src/core/lib/security/transport/lb_targets_info.h", 
       "src/core/lib/security/transport/secure_endpoint.h", 
-      "src/core/lib/security/transport/security_connector.h", 
       "src/core/lib/security/transport/security_handshaker.h", 
+      "src/core/lib/security/transport/target_authority_table.h", 
       "src/core/lib/security/transport/tsi_error.h", 
       "src/core/lib/security/util/json_util.h"
     ], 
@@ -9231,6 +9971,8 @@
       "src/core/lib/http/httpcli_security_connector.cc", 
       "src/core/lib/security/context/security_context.cc", 
       "src/core/lib/security/context/security_context.h", 
+      "src/core/lib/security/credentials/alts/alts_credentials.cc", 
+      "src/core/lib/security/credentials/alts/alts_credentials.h", 
       "src/core/lib/security/credentials/composite/composite_credentials.cc", 
       "src/core/lib/security/credentials/composite/composite_credentials.h", 
       "src/core/lib/security/credentials/credentials.cc", 
@@ -9255,17 +9997,19 @@
       "src/core/lib/security/credentials/plugin/plugin_credentials.h", 
       "src/core/lib/security/credentials/ssl/ssl_credentials.cc", 
       "src/core/lib/security/credentials/ssl/ssl_credentials.h", 
+      "src/core/lib/security/security_connector/alts_security_connector.cc", 
+      "src/core/lib/security/security_connector/alts_security_connector.h", 
+      "src/core/lib/security/security_connector/security_connector.cc", 
+      "src/core/lib/security/security_connector/security_connector.h", 
       "src/core/lib/security/transport/auth_filters.h", 
       "src/core/lib/security/transport/client_auth_filter.cc", 
-      "src/core/lib/security/transport/lb_targets_info.cc", 
-      "src/core/lib/security/transport/lb_targets_info.h", 
       "src/core/lib/security/transport/secure_endpoint.cc", 
       "src/core/lib/security/transport/secure_endpoint.h", 
-      "src/core/lib/security/transport/security_connector.cc", 
-      "src/core/lib/security/transport/security_connector.h", 
       "src/core/lib/security/transport/security_handshaker.cc", 
       "src/core/lib/security/transport/security_handshaker.h", 
       "src/core/lib/security/transport/server_auth_filter.cc", 
+      "src/core/lib/security/transport/target_authority_table.cc", 
+      "src/core/lib/security/transport/target_authority_table.h", 
       "src/core/lib/security/transport/tsi_error.cc", 
       "src/core/lib/security/transport/tsi_error.h", 
       "src/core/lib/security/util/json_util.cc", 
@@ -9316,6 +10060,7 @@
   }, 
   {
     "deps": [
+      "cmdline", 
       "gpr", 
       "gpr_test_util", 
       "grpc_base", 
@@ -9338,6 +10083,7 @@
       "test/core/util/port.h", 
       "test/core/util/port_server_client.h", 
       "test/core/util/slice_splitter.h", 
+      "test/core/util/subprocess.h", 
       "test/core/util/tracer_util.h", 
       "test/core/util/trickle_endpoint.h"
     ], 
@@ -9376,6 +10122,9 @@
       "test/core/util/port_server_client.h", 
       "test/core/util/slice_splitter.cc", 
       "test/core/util/slice_splitter.h", 
+      "test/core/util/subprocess.h", 
+      "test/core/util/subprocess_posix.cc", 
+      "test/core/util/subprocess_windows.cc", 
       "test/core/util/tracer_util.cc", 
       "test/core/util/tracer_util.h", 
       "test/core/util/trickle_endpoint.cc", 
@@ -9760,6 +10509,8 @@
     "headers": [
       "src/core/tsi/alts_transport_security.h", 
       "src/core/tsi/fake_transport_security.h", 
+      "src/core/tsi/ssl/session_cache/ssl_session.h", 
+      "src/core/tsi/ssl/session_cache/ssl_session_cache.h", 
       "src/core/tsi/ssl_transport_security.h", 
       "src/core/tsi/ssl_types.h", 
       "src/core/tsi/transport_security_grpc.h"
@@ -9772,6 +10523,11 @@
       "src/core/tsi/alts_transport_security.h", 
       "src/core/tsi/fake_transport_security.cc", 
       "src/core/tsi/fake_transport_security.h", 
+      "src/core/tsi/ssl/session_cache/ssl_session.h", 
+      "src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc", 
+      "src/core/tsi/ssl/session_cache/ssl_session_cache.cc", 
+      "src/core/tsi/ssl/session_cache/ssl_session_cache.h", 
+      "src/core/tsi/ssl/session_cache/ssl_session_openssl.cc", 
       "src/core/tsi/ssl_transport_security.cc", 
       "src/core/tsi/ssl_transport_security.h", 
       "src/core/tsi/ssl_types.h", 
@@ -9805,6 +10561,20 @@
     "type": "filegroup"
   }, 
   {
+    "deps": [], 
+    "headers": [
+      "src/proto/grpc/channelz/channelz.grpc.pb.h", 
+      "src/proto/grpc/channelz/channelz.pb.h", 
+      "src/proto/grpc/channelz/channelz_mock.grpc.pb.h"
+    ], 
+    "is_filegroup": true, 
+    "language": "c++", 
+    "name": "grpc++_channelz_proto", 
+    "src": [], 
+    "third_party": false, 
+    "type": "filegroup"
+  }, 
+  {
     "deps": [
       "grpc_codegen"
     ], 
@@ -9838,7 +10608,37 @@
       "include/grpc++/impl/codegen/string_ref.h", 
       "include/grpc++/impl/codegen/stub_options.h", 
       "include/grpc++/impl/codegen/sync_stream.h", 
-      "include/grpc++/impl/codegen/time.h"
+      "include/grpc++/impl/codegen/time.h", 
+      "include/grpcpp/impl/codegen/async_stream.h", 
+      "include/grpcpp/impl/codegen/async_unary_call.h", 
+      "include/grpcpp/impl/codegen/byte_buffer.h", 
+      "include/grpcpp/impl/codegen/call.h", 
+      "include/grpcpp/impl/codegen/call_hook.h", 
+      "include/grpcpp/impl/codegen/channel_interface.h", 
+      "include/grpcpp/impl/codegen/client_context.h", 
+      "include/grpcpp/impl/codegen/client_unary_call.h", 
+      "include/grpcpp/impl/codegen/completion_queue.h", 
+      "include/grpcpp/impl/codegen/completion_queue_tag.h", 
+      "include/grpcpp/impl/codegen/config.h", 
+      "include/grpcpp/impl/codegen/core_codegen_interface.h", 
+      "include/grpcpp/impl/codegen/create_auth_context.h", 
+      "include/grpcpp/impl/codegen/grpc_library.h", 
+      "include/grpcpp/impl/codegen/metadata_map.h", 
+      "include/grpcpp/impl/codegen/method_handler_impl.h", 
+      "include/grpcpp/impl/codegen/rpc_method.h", 
+      "include/grpcpp/impl/codegen/rpc_service_method.h", 
+      "include/grpcpp/impl/codegen/security/auth_context.h", 
+      "include/grpcpp/impl/codegen/serialization_traits.h", 
+      "include/grpcpp/impl/codegen/server_context.h", 
+      "include/grpcpp/impl/codegen/server_interface.h", 
+      "include/grpcpp/impl/codegen/service_type.h", 
+      "include/grpcpp/impl/codegen/slice.h", 
+      "include/grpcpp/impl/codegen/status.h", 
+      "include/grpcpp/impl/codegen/status_code_enum.h", 
+      "include/grpcpp/impl/codegen/string_ref.h", 
+      "include/grpcpp/impl/codegen/stub_options.h", 
+      "include/grpcpp/impl/codegen/sync_stream.h", 
+      "include/grpcpp/impl/codegen/time.h"
     ], 
     "is_filegroup": true, 
     "language": "c++", 
@@ -9873,7 +10673,37 @@
       "include/grpc++/impl/codegen/string_ref.h", 
       "include/grpc++/impl/codegen/stub_options.h", 
       "include/grpc++/impl/codegen/sync_stream.h", 
-      "include/grpc++/impl/codegen/time.h"
+      "include/grpc++/impl/codegen/time.h", 
+      "include/grpcpp/impl/codegen/async_stream.h", 
+      "include/grpcpp/impl/codegen/async_unary_call.h", 
+      "include/grpcpp/impl/codegen/byte_buffer.h", 
+      "include/grpcpp/impl/codegen/call.h", 
+      "include/grpcpp/impl/codegen/call_hook.h", 
+      "include/grpcpp/impl/codegen/channel_interface.h", 
+      "include/grpcpp/impl/codegen/client_context.h", 
+      "include/grpcpp/impl/codegen/client_unary_call.h", 
+      "include/grpcpp/impl/codegen/completion_queue.h", 
+      "include/grpcpp/impl/codegen/completion_queue_tag.h", 
+      "include/grpcpp/impl/codegen/config.h", 
+      "include/grpcpp/impl/codegen/core_codegen_interface.h", 
+      "include/grpcpp/impl/codegen/create_auth_context.h", 
+      "include/grpcpp/impl/codegen/grpc_library.h", 
+      "include/grpcpp/impl/codegen/metadata_map.h", 
+      "include/grpcpp/impl/codegen/method_handler_impl.h", 
+      "include/grpcpp/impl/codegen/rpc_method.h", 
+      "include/grpcpp/impl/codegen/rpc_service_method.h", 
+      "include/grpcpp/impl/codegen/security/auth_context.h", 
+      "include/grpcpp/impl/codegen/serialization_traits.h", 
+      "include/grpcpp/impl/codegen/server_context.h", 
+      "include/grpcpp/impl/codegen/server_interface.h", 
+      "include/grpcpp/impl/codegen/service_type.h", 
+      "include/grpcpp/impl/codegen/slice.h", 
+      "include/grpcpp/impl/codegen/status.h", 
+      "include/grpcpp/impl/codegen/status_code_enum.h", 
+      "include/grpcpp/impl/codegen/string_ref.h", 
+      "include/grpcpp/impl/codegen/stub_options.h", 
+      "include/grpcpp/impl/codegen/sync_stream.h", 
+      "include/grpcpp/impl/codegen/time.h"
     ], 
     "third_party": false, 
     "type": "filegroup"
@@ -9898,13 +10728,15 @@
       "grpc++_config_proto"
     ], 
     "headers": [
-      "include/grpc++/impl/codegen/proto_utils.h"
+      "include/grpc++/impl/codegen/proto_utils.h", 
+      "include/grpcpp/impl/codegen/proto_utils.h"
     ], 
     "is_filegroup": true, 
     "language": "c++", 
     "name": "grpc++_codegen_proto", 
     "src": [
-      "include/grpc++/impl/codegen/proto_utils.h"
+      "include/grpc++/impl/codegen/proto_utils.h", 
+      "include/grpcpp/impl/codegen/proto_utils.h"
     ], 
     "third_party": false, 
     "type": "filegroup"
@@ -9964,6 +10796,51 @@
       "include/grpc++/support/stub_options.h", 
       "include/grpc++/support/sync_stream.h", 
       "include/grpc++/support/time.h", 
+      "include/grpcpp/alarm.h", 
+      "include/grpcpp/channel.h", 
+      "include/grpcpp/client_context.h", 
+      "include/grpcpp/completion_queue.h", 
+      "include/grpcpp/create_channel.h", 
+      "include/grpcpp/create_channel_posix.h", 
+      "include/grpcpp/ext/health_check_service_server_builder_option.h", 
+      "include/grpcpp/generic/async_generic_service.h", 
+      "include/grpcpp/generic/generic_stub.h", 
+      "include/grpcpp/grpcpp.h", 
+      "include/grpcpp/health_check_service_interface.h", 
+      "include/grpcpp/impl/call.h", 
+      "include/grpcpp/impl/channel_argument_option.h", 
+      "include/grpcpp/impl/client_unary_call.h", 
+      "include/grpcpp/impl/codegen/core_codegen.h", 
+      "include/grpcpp/impl/grpc_library.h", 
+      "include/grpcpp/impl/method_handler_impl.h", 
+      "include/grpcpp/impl/rpc_method.h", 
+      "include/grpcpp/impl/rpc_service_method.h", 
+      "include/grpcpp/impl/serialization_traits.h", 
+      "include/grpcpp/impl/server_builder_option.h", 
+      "include/grpcpp/impl/server_builder_plugin.h", 
+      "include/grpcpp/impl/server_initializer.h", 
+      "include/grpcpp/impl/service_type.h", 
+      "include/grpcpp/resource_quota.h", 
+      "include/grpcpp/security/auth_context.h", 
+      "include/grpcpp/security/auth_metadata_processor.h", 
+      "include/grpcpp/security/credentials.h", 
+      "include/grpcpp/security/server_credentials.h", 
+      "include/grpcpp/server.h", 
+      "include/grpcpp/server_builder.h", 
+      "include/grpcpp/server_context.h", 
+      "include/grpcpp/server_posix.h", 
+      "include/grpcpp/support/async_stream.h", 
+      "include/grpcpp/support/async_unary_call.h", 
+      "include/grpcpp/support/byte_buffer.h", 
+      "include/grpcpp/support/channel_arguments.h", 
+      "include/grpcpp/support/config.h", 
+      "include/grpcpp/support/slice.h", 
+      "include/grpcpp/support/status.h", 
+      "include/grpcpp/support/status_code_enum.h", 
+      "include/grpcpp/support/string_ref.h", 
+      "include/grpcpp/support/stub_options.h", 
+      "include/grpcpp/support/sync_stream.h", 
+      "include/grpcpp/support/time.h", 
       "src/cpp/client/create_channel_internal.h", 
       "src/cpp/common/channel_filter.h", 
       "src/cpp/server/dynamic_thread_pool.h", 
@@ -10021,6 +10898,51 @@
       "include/grpc++/support/stub_options.h", 
       "include/grpc++/support/sync_stream.h", 
       "include/grpc++/support/time.h", 
+      "include/grpcpp/alarm.h", 
+      "include/grpcpp/channel.h", 
+      "include/grpcpp/client_context.h", 
+      "include/grpcpp/completion_queue.h", 
+      "include/grpcpp/create_channel.h", 
+      "include/grpcpp/create_channel_posix.h", 
+      "include/grpcpp/ext/health_check_service_server_builder_option.h", 
+      "include/grpcpp/generic/async_generic_service.h", 
+      "include/grpcpp/generic/generic_stub.h", 
+      "include/grpcpp/grpcpp.h", 
+      "include/grpcpp/health_check_service_interface.h", 
+      "include/grpcpp/impl/call.h", 
+      "include/grpcpp/impl/channel_argument_option.h", 
+      "include/grpcpp/impl/client_unary_call.h", 
+      "include/grpcpp/impl/codegen/core_codegen.h", 
+      "include/grpcpp/impl/grpc_library.h", 
+      "include/grpcpp/impl/method_handler_impl.h", 
+      "include/grpcpp/impl/rpc_method.h", 
+      "include/grpcpp/impl/rpc_service_method.h", 
+      "include/grpcpp/impl/serialization_traits.h", 
+      "include/grpcpp/impl/server_builder_option.h", 
+      "include/grpcpp/impl/server_builder_plugin.h", 
+      "include/grpcpp/impl/server_initializer.h", 
+      "include/grpcpp/impl/service_type.h", 
+      "include/grpcpp/resource_quota.h", 
+      "include/grpcpp/security/auth_context.h", 
+      "include/grpcpp/security/auth_metadata_processor.h", 
+      "include/grpcpp/security/credentials.h", 
+      "include/grpcpp/security/server_credentials.h", 
+      "include/grpcpp/server.h", 
+      "include/grpcpp/server_builder.h", 
+      "include/grpcpp/server_context.h", 
+      "include/grpcpp/server_posix.h", 
+      "include/grpcpp/support/async_stream.h", 
+      "include/grpcpp/support/async_unary_call.h", 
+      "include/grpcpp/support/byte_buffer.h", 
+      "include/grpcpp/support/channel_arguments.h", 
+      "include/grpcpp/support/config.h", 
+      "include/grpcpp/support/slice.h", 
+      "include/grpcpp/support/status.h", 
+      "include/grpcpp/support/status_code_enum.h", 
+      "include/grpcpp/support/string_ref.h", 
+      "include/grpcpp/support/stub_options.h", 
+      "include/grpcpp/support/sync_stream.h", 
+      "include/grpcpp/support/time.h", 
       "src/cpp/client/channel_cc.cc", 
       "src/cpp/client/client_context.cc", 
       "src/cpp/client/create_channel.cc", 
@@ -10069,13 +10991,15 @@
   {
     "deps": [], 
     "headers": [
-      "include/grpc++/impl/codegen/config_protobuf.h"
+      "include/grpc++/impl/codegen/config_protobuf.h", 
+      "include/grpcpp/impl/codegen/config_protobuf.h"
     ], 
     "is_filegroup": true, 
     "language": "c++", 
     "name": "grpc++_config_proto", 
     "src": [
-      "include/grpc++/impl/codegen/config_protobuf.h"
+      "include/grpc++/impl/codegen/config_protobuf.h", 
+      "include/grpcpp/impl/codegen/config_protobuf.h"
     ], 
     "third_party": false, 
     "type": "filegroup"
@@ -10101,14 +11025,18 @@
     ], 
     "headers": [
       "include/grpc++/test/mock_stream.h", 
-      "include/grpc++/test/server_context_test_spouse.h"
+      "include/grpc++/test/server_context_test_spouse.h", 
+      "include/grpcpp/test/mock_stream.h", 
+      "include/grpcpp/test/server_context_test_spouse.h"
     ], 
     "is_filegroup": true, 
     "language": "c++", 
     "name": "grpc++_test", 
     "src": [
       "include/grpc++/test/mock_stream.h", 
-      "include/grpc++/test/server_context_test_spouse.h"
+      "include/grpc++/test/server_context_test_spouse.h", 
+      "include/grpcpp/test/mock_stream.h", 
+      "include/grpcpp/test/server_context_test_spouse.h"
     ], 
     "third_party": false, 
     "type": "filegroup"
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index 87c0e26..c2bbf8c 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -108,6 +108,30 @@
     ], 
     "cpu_cost": 1.0, 
     "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c", 
+    "name": "avl_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
     "exclude_iomgrs": [
       "uv"
     ], 
@@ -186,30 +210,6 @@
     "flaky": false, 
     "gtest": false, 
     "language": "c", 
-    "name": "byte_stream_test", 
-    "platforms": [
-      "linux", 
-      "mac", 
-      "posix", 
-      "windows"
-    ], 
-    "uses_polling": false
-  }, 
-  {
-    "args": [], 
-    "benchmark": false, 
-    "ci_platforms": [
-      "linux", 
-      "mac", 
-      "posix", 
-      "windows"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "exclude_iomgrs": [], 
-    "flaky": false, 
-    "gtest": false, 
-    "language": "c", 
     "name": "channel_create_test", 
     "platforms": [
       "linux", 
@@ -300,6 +300,30 @@
       "posix", 
       "windows"
     ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c", 
+    "name": "cmdline_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
     "cpu_cost": 10, 
     "exclude_configs": [], 
     "exclude_iomgrs": [], 
@@ -728,54 +752,6 @@
       "posix", 
       "windows"
     ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "exclude_iomgrs": [], 
-    "flaky": false, 
-    "gtest": false, 
-    "language": "c", 
-    "name": "gpr_avl_test", 
-    "platforms": [
-      "linux", 
-      "mac", 
-      "posix", 
-      "windows"
-    ], 
-    "uses_polling": false
-  }, 
-  {
-    "args": [], 
-    "benchmark": false, 
-    "ci_platforms": [
-      "linux", 
-      "mac", 
-      "posix", 
-      "windows"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "exclude_iomgrs": [], 
-    "flaky": false, 
-    "gtest": false, 
-    "language": "c", 
-    "name": "gpr_cmdline_test", 
-    "platforms": [
-      "linux", 
-      "mac", 
-      "posix", 
-      "windows"
-    ], 
-    "uses_polling": false
-  }, 
-  {
-    "args": [], 
-    "benchmark": false, 
-    "ci_platforms": [
-      "linux", 
-      "mac", 
-      "posix", 
-      "windows"
-    ], 
     "cpu_cost": 30, 
     "exclude_configs": [], 
     "exclude_iomgrs": [], 
@@ -2274,30 +2250,6 @@
     "flaky": false, 
     "gtest": false, 
     "language": "c", 
-    "name": "slice_hash_table_test", 
-    "platforms": [
-      "linux", 
-      "mac", 
-      "posix", 
-      "windows"
-    ], 
-    "uses_polling": false
-  }, 
-  {
-    "args": [], 
-    "benchmark": false, 
-    "ci_platforms": [
-      "linux", 
-      "mac", 
-      "posix", 
-      "windows"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "exclude_iomgrs": [], 
-    "flaky": false, 
-    "gtest": false, 
-    "language": "c", 
     "name": "slice_string_helpers_test", 
     "platforms": [
       "linux", 
@@ -2900,6 +2852,318 @@
     "exclude_configs": [], 
     "exclude_iomgrs": [], 
     "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
+    "name": "alts_counter_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
+    "name": "alts_crypt_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
+    "name": "alts_crypter_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
+    "name": "alts_frame_handler_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
+    "name": "alts_frame_protector_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
+    "name": "alts_grpc_record_protocol_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
+    "name": "alts_handshaker_client_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
+    "name": "alts_handshaker_service_api_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
+    "name": "alts_iovec_record_protocol_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
+    "name": "alts_security_connector_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
+    "name": "alts_tsi_handshaker_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
+    "name": "alts_tsi_utils_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
+    "name": "alts_zero_copy_grpc_protector_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
     "gtest": true, 
     "language": "c++", 
     "name": "async_end2end_test", 
@@ -3328,6 +3592,30 @@
     "flaky": false, 
     "gtest": true, 
     "language": "c++", 
+    "name": "byte_stream_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": true, 
+    "language": "c++", 
     "name": "channel_arguments_test", 
     "platforms": [
       "linux", 
@@ -3376,6 +3664,78 @@
     "flaky": false, 
     "gtest": true, 
     "language": "c++", 
+    "name": "channel_trace_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
+    "name": "check_gcp_environment_linux_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
+    "name": "check_gcp_environment_windows_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": true, 
+    "language": "c++", 
     "name": "chttp2_settings_timeout_test", 
     "platforms": [
       "linux", 
@@ -3806,6 +4166,30 @@
     "exclude_configs": [], 
     "exclude_iomgrs": [], 
     "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
+    "name": "grpc_alts_credentials_options_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
     "gtest": true, 
     "language": "c++", 
     "name": "grpc_tool_test", 
@@ -3878,9 +4262,9 @@
     "exclude_configs": [], 
     "exclude_iomgrs": [], 
     "flaky": false, 
-    "gtest": false, 
+    "gtest": true, 
     "language": "c++", 
-    "name": "grpclb_test", 
+    "name": "h2_ssl_cert_test", 
     "platforms": [
       "linux", 
       "mac", 
@@ -3904,7 +4288,7 @@
     "flaky": false, 
     "gtest": true, 
     "language": "c++", 
-    "name": "h2_ssl_cert_test", 
+    "name": "h2_ssl_session_reuse_test", 
     "platforms": [
       "linux", 
       "mac", 
@@ -4090,6 +4474,30 @@
     "exclude_configs": [], 
     "exclude_iomgrs": [], 
     "flaky": false, 
+    "gtest": true, 
+    "language": "c++", 
+    "name": "nonblocking_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
     "gtest": false, 
     "language": "c++", 
     "name": "noop-benchmark", 
@@ -4465,6 +4873,54 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": true, 
+    "language": "c++", 
+    "name": "slice_hash_table_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": true, 
+    "language": "c++", 
+    "name": "slice_weak_hash_table_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
     "exclude_configs": [
       "tsan"
     ], 
@@ -4495,9 +4951,33 @@
     "exclude_configs": [], 
     "exclude_iomgrs": [], 
     "flaky": false, 
-    "gtest": false, 
+    "gtest": true, 
     "language": "c++", 
-    "name": "status_test", 
+    "name": "status_metadata_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": true, 
+    "language": "c++", 
+    "name": "status_util_test", 
     "platforms": [
       "linux", 
       "mac", 
@@ -4606,6 +5086,30 @@
     "ci_platforms": [
       "linux", 
       "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
+    "name": "transport_security_common_api_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.5, 
@@ -4715,6 +5219,32 @@
     "flaky": false, 
     "gtest": false, 
     "language": "c", 
+    "name": "duplicate_header_bad_client_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c", 
     "name": "head_of_line_blocking_bad_client_test", 
     "platforms": [
       "linux", 
@@ -4980,6 +5510,50 @@
   }, 
   {
     "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": true, 
+    "language": "c++", 
+    "name": "address_sorting_test_unsecure", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": true, 
+    "language": "c++", 
+    "name": "address_sorting_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
     "boringssl": true, 
     "ci_platforms": [
       "linux", 
@@ -5100,6 +5674,32 @@
     "flaky": false, 
     "gtest": true, 
     "language": "c++", 
+    "name": "boringssl_buf_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "args": [], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan", 
+      "ubsan"
+    ], 
+    "flaky": false, 
+    "gtest": true, 
+    "language": "c++", 
     "name": "boringssl_bytestring_test", 
     "platforms": [
       "linux", 
@@ -7270,6 +7870,351 @@
   }, 
   {
     "args": [
+      "retry"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_cancellation"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_initial_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_subsequent_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_non_retriable_status"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_initial_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_message"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_delay"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_after_commit"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_succeeds_before_replay_finished"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_throttled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_too_many_attempts"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "server_finishes_request"
     ], 
     "ci_platforms": [
@@ -8608,6 +9553,351 @@
   }, 
   {
     "args": [
+      "retry"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_cancellation"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_initial_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_subsequent_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_non_retriable_status"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_initial_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_message"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_delay"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_after_commit"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_succeeds_before_replay_finished"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_throttled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_too_many_attempts"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "server_finishes_request"
     ], 
     "ci_platforms": [
@@ -9925,6 +11215,336 @@
   }, 
   {
     "args": [
+      "retry"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_cancellation"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_initial_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_subsequent_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_non_retriable_status"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_initial_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_message"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_delay"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_after_commit"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_succeeds_before_replay_finished"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_throttled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_too_many_attempts"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "server_finishes_request"
     ], 
     "ci_platforms": [
@@ -12467,6 +14087,351 @@
   }, 
   {
     "args": [
+      "retry"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_cancellation"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_initial_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_subsequent_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_non_retriable_status"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_initial_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_message"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_delay"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_after_commit"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_succeeds_before_replay_finished"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_throttled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_too_many_attempts"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "server_finishes_request"
     ], 
     "ci_platforms": [
@@ -13648,6 +15613,291 @@
   }, 
   {
     "args": [
+      "retry"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_cancellation"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_disabled"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_initial_batch"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_subsequent_batch"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_non_retriable_status"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_initial_metadata"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_message"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_delay"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_disabled"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_after_commit"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_succeeds_before_replay_finished"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_throttled"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_too_many_attempts"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "server_finishes_request"
     ], 
     "ci_platforms": [
@@ -14903,6 +17153,351 @@
   }, 
   {
     "args": [
+      "retry"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_cancellation"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_initial_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_subsequent_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_non_retriable_status"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_initial_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_message"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_delay"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_after_commit"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_succeeds_before_replay_finished"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_throttled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_too_many_attempts"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "server_finishes_request"
     ], 
     "ci_platforms": [
@@ -16264,6 +18859,351 @@
   }, 
   {
     "args": [
+      "retry"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_cancellation"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_initial_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_subsequent_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_non_retriable_status"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_initial_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_message"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_delay"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_after_commit"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_succeeds_before_replay_finished"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_throttled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_too_many_attempts"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "server_finishes_request"
     ], 
     "ci_platforms": [
@@ -17689,6 +20629,366 @@
   }, 
   {
     "args": [
+      "retry"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_cancellation"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_initial_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_subsequent_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_non_retriable_status"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_initial_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_message"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_delay"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_after_commit"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_succeeds_before_replay_finished"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_throttled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_too_many_attempts"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "server_finishes_request"
     ], 
     "ci_platforms": [
@@ -19065,6 +22365,351 @@
   }, 
   {
     "args": [
+      "retry"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_cancellation"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_initial_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_subsequent_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_non_retriable_status"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_initial_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_message"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_delay"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_after_commit"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_succeeds_before_replay_finished"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_throttled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_too_many_attempts"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "server_finishes_request"
     ], 
     "ci_platforms": [
@@ -20466,6 +24111,366 @@
   }, 
   {
     "args": [
+      "retry"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_cancellation"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_initial_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_subsequent_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_non_retriable_status"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_initial_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_message"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_delay"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_after_commit"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_succeeds_before_replay_finished"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_throttled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_too_many_attempts"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "server_finishes_request"
     ], 
     "ci_platforms": [
@@ -26744,6 +30749,351 @@
   }, 
   {
     "args": [
+      "retry"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_cancellation"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_initial_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_subsequent_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_non_retriable_status"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_initial_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_message"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_delay"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_after_commit"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_succeeds_before_replay_finished"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_throttled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_too_many_attempts"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "server_finishes_request"
     ], 
     "ci_platforms": [
@@ -29230,6 +33580,351 @@
   }, 
   {
     "args": [
+      "retry"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_cancellation"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_disabled"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_initial_batch"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_subsequent_batch"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_non_retriable_status"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_initial_metadata"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_message"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_delay"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_disabled"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_after_commit"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_succeeds_before_replay_finished"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_throttled"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_too_many_attempts"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "server_finishes_request"
     ], 
     "ci_platforms": [
@@ -31511,6 +36206,351 @@
   }, 
   {
     "args": [
+      "retry"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_cancellation"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_initial_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_subsequent_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_non_retriable_status"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_initial_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_message"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_delay"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_after_commit"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_succeeds_before_replay_finished"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_throttled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_too_many_attempts"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "server_finishes_request"
     ], 
     "ci_platforms": [
@@ -32826,6 +37866,351 @@
   }, 
   {
     "args": [
+      "retry"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_cancellation"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_initial_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_subsequent_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_non_retriable_status"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_initial_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_message"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_delay"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_after_commit"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_succeeds_before_replay_finished"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_throttled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_too_many_attempts"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "server_finishes_request"
     ], 
     "ci_platforms": [
@@ -35337,6 +40722,351 @@
   }, 
   {
     "args": [
+      "retry"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_cancellation"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_initial_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_subsequent_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_non_retriable_status"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_initial_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_message"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_delay"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_after_commit"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_succeeds_before_replay_finished"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_throttled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_too_many_attempts"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "server_finishes_request"
     ], 
     "ci_platforms": [
@@ -36499,6 +42229,291 @@
   }, 
   {
     "args": [
+      "retry"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_cancellation"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_disabled"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_initial_batch"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_subsequent_batch"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_non_retriable_status"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_initial_metadata"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_message"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_delay"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_disabled"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_after_commit"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_succeeds_before_replay_finished"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_throttled"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_too_many_attempts"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "server_finishes_request"
     ], 
     "ci_platforms": [
@@ -37731,6 +43746,351 @@
   }, 
   {
     "args": [
+      "retry"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_cancellation"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_initial_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_subsequent_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_non_retriable_status"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_initial_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_message"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_delay"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_after_commit"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_succeeds_before_replay_finished"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_throttled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_too_many_attempts"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "server_finishes_request"
     ], 
     "ci_platforms": [
@@ -39069,6 +45429,351 @@
   }, 
   {
     "args": [
+      "retry"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_cancellation"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_initial_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_subsequent_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_non_retriable_status"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_initial_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_message"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_delay"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_after_commit"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_succeeds_before_replay_finished"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_throttled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_too_many_attempts"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "server_finishes_request"
     ], 
     "ci_platforms": [
@@ -40470,6 +47175,366 @@
   }, 
   {
     "args": [
+      "retry"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_cancellation"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_initial_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_subsequent_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_non_retriable_status"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_initial_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_message"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_delay"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_after_commit"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_succeeds_before_replay_finished"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_throttled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_too_many_attempts"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "server_finishes_request"
     ], 
     "ci_platforms": [
@@ -41823,6 +48888,351 @@
   }, 
   {
     "args": [
+      "retry"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_cancellation"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_initial_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_subsequent_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_non_retriable_status"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_initial_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_message"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_delay"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_disabled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_after_commit"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_succeeds_before_replay_finished"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_throttled"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_too_many_attempts"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "server_finishes_request"
     ], 
     "ci_platforms": [
@@ -47938,6 +55348,351 @@
   }, 
   {
     "args": [
+      "retry"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_cancellation"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_disabled"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_initial_batch"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_exceeds_buffer_size_in_subsequent_batch"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_non_retriable_status"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_initial_metadata"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_recv_message"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_delay"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_server_pushback_disabled"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_after_commit"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_streaming_succeeds_before_replay_finished"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_throttled"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "retry_too_many_attempts"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "server_finishes_request"
     ], 
     "ci_platforms": [
@@ -51997,6 +59752,3094 @@
   }, 
   {
     "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_1channel_100rpcs_1MB\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": null, \"threads_per_cq\": 0, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_1channel_100rpcs_1MB_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_from_client_1channel_1MB\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": null, \"threads_per_cq\": 0, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING_FROM_CLIENT\", \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_from_client_1channel_1MB_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_75Kqps_600channel_60Krpcs_300Breq_50Bresp\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 16, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"security_params\": null, \"threads_per_cq\": 1, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 50, \"req_size\": 300}}, \"client_channels\": 300, \"threads_per_cq\": 0, \"load_params\": {\"poisson\": {\"offered_load\": 37500}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_75Kqps_600channel_60Krpcs_300Breq_50Bresp_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_ping_pong_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"server_type\": \"ASYNC_GENERIC_SERVER\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0}, \"num_clients\": 1, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 2, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_ping_pong_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_unconstrained_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"server_type\": \"ASYNC_GENERIC_SERVER\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_unconstrained_1mps_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"server_type\": \"ASYNC_GENERIC_SERVER\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"messages_per_stream\": 1, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_1mps_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_unconstrained_10mps_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"server_type\": \"ASYNC_GENERIC_SERVER\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"messages_per_stream\": 10, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_10mps_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_1channel_1MBmsg_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"server_type\": \"ASYNC_GENERIC_SERVER\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_1channel_1MBmsg_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_unconstrained_64KBmsg_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"server_type\": \"ASYNC_GENERIC_SERVER\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 65536, \"req_size\": 65536}}, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 65536, \"req_size\": 65536}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_64KBmsg_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_unconstrained_1cq_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"server_type\": \"ASYNC_GENERIC_SERVER\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 1000000}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 13, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 1000000, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_1cq_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_unconstrained_2waysharedcq_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"server_type\": \"ASYNC_GENERIC_SERVER\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 2}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 2, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_2waysharedcq_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_qps_unconstrained_1cq_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 1000000, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 13, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 1000000, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_1cq_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_qps_unconstrained_2waysharedcq_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 2, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 2, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_2waysharedcq_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_qps_unconstrained_1cq_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 1000000, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 13, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 1000000, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_qps_unconstrained_1cq_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_qps_unconstrained_2waysharedcq_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 2, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 2, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_qps_unconstrained_2waysharedcq_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_one_server_core_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"server_type\": \"ASYNC_GENERIC_SERVER\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 13, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_one_server_core_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_client_sync_server_unary_qps_unconstrained_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0, \"server_type\": \"SYNC_SERVER\"}, \"num_servers\": 1, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 10, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [
+      "poll-cv"
+    ], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_client_sync_server_unary_qps_unconstrained_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_client_unary_1channel_64wide_128Breq_8MBresp_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 8388608, \"req_size\": 128}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_client_unary_1channel_64wide_128Breq_8MBresp_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_client_sync_server_streaming_qps_unconstrained_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0, \"server_type\": \"SYNC_SERVER\"}, \"num_servers\": 1, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 10, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [
+      "poll-cv"
+    ], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_client_sync_server_streaming_qps_unconstrained_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_ping_pong_secure_1MB\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_ping_pong_secure_1MB_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_unary_ping_pong_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"SYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 2, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_unary_ping_pong_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_unary_qps_unconstrained_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 3, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 3, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"SYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 64, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_unary_qps_unconstrained_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_ping_pong_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 2, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_ping_pong_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_qps_unconstrained_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 3, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 3, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_qps_unconstrained_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_ping_pong_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"SYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 2, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_ping_pong_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_qps_unconstrained_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 3, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 3, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"SYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 64, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_qps_unconstrained_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_qps_unconstrained_1mps_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"messages_per_stream\": 1, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"SYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 64, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_qps_unconstrained_1mps_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_qps_unconstrained_10mps_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"messages_per_stream\": 10, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"SYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 64, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_qps_unconstrained_10mps_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_ping_pong_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 2, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_ping_pong_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_qps_unconstrained_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 3, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 3, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_qps_unconstrained_1mps_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"messages_per_stream\": 1, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_1mps_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_qps_unconstrained_10mps_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"messages_per_stream\": 10, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_10mps_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_from_client_ping_pong_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING_FROM_CLIENT\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"SYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 2, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_from_client_ping_pong_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_from_client_qps_unconstrained_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 3, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING_FROM_CLIENT\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 3, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"SYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 64, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_from_client_qps_unconstrained_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_from_client_ping_pong_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING_FROM_CLIENT\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 2, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_from_client_ping_pong_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_from_client_qps_unconstrained_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 3, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING_FROM_CLIENT\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 3, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_from_client_qps_unconstrained_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_from_server_ping_pong_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING_FROM_SERVER\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"SYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 2, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_from_server_ping_pong_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_from_server_qps_unconstrained_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 3, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING_FROM_SERVER\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 3, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"SYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 64, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_from_server_qps_unconstrained_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_from_server_ping_pong_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 0, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING_FROM_SERVER\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 2, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_from_server_ping_pong_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_from_server_qps_unconstrained_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"threads_per_cq\": 3, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING_FROM_SERVER\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 3, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_from_server_qps_unconstrained_secure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_ping_pong_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"server_type\": \"ASYNC_GENERIC_SERVER\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"security_params\": null, \"threads_per_cq\": 0}, \"num_clients\": 1, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 2, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_ping_pong_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_unconstrained_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"server_type\": \"ASYNC_GENERIC_SERVER\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"security_params\": null, \"threads_per_cq\": 0}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_unconstrained_1mps_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"server_type\": \"ASYNC_GENERIC_SERVER\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"security_params\": null, \"threads_per_cq\": 0}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"messages_per_stream\": 1, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_1mps_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_unconstrained_10mps_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"server_type\": \"ASYNC_GENERIC_SERVER\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"security_params\": null, \"threads_per_cq\": 0}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"messages_per_stream\": 10, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_10mps_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_1channel_1MBmsg_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"server_type\": \"ASYNC_GENERIC_SERVER\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"security_params\": null, \"threads_per_cq\": 0}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_1channel_1MBmsg_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_unconstrained_64KBmsg_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"server_type\": \"ASYNC_GENERIC_SERVER\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 65536, \"req_size\": 65536}}, \"security_params\": null, \"threads_per_cq\": 0}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 65536, \"req_size\": 65536}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_64KBmsg_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_unconstrained_1cq_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"server_type\": \"ASYNC_GENERIC_SERVER\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"security_params\": null, \"threads_per_cq\": 1000000}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 13, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 1000000, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_1cq_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_unconstrained_2waysharedcq_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"server_type\": \"ASYNC_GENERIC_SERVER\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"security_params\": null, \"threads_per_cq\": 2}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 2, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_2waysharedcq_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_qps_unconstrained_1cq_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": null, \"threads_per_cq\": 1000000, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 13, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 1000000, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_1cq_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_qps_unconstrained_2waysharedcq_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": null, \"threads_per_cq\": 2, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 2, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_2waysharedcq_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_qps_unconstrained_1cq_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": null, \"threads_per_cq\": 1000000, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 13, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 1000000, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_qps_unconstrained_1cq_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_qps_unconstrained_2waysharedcq_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": null, \"threads_per_cq\": 2, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 2, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_qps_unconstrained_2waysharedcq_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_one_server_core_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"server_type\": \"ASYNC_GENERIC_SERVER\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"security_params\": null, \"threads_per_cq\": 0}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 13, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_one_server_core_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_client_sync_server_unary_qps_unconstrained_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 0, \"server_type\": \"SYNC_SERVER\"}, \"num_servers\": 1, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 10, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [
+      "poll-cv"
+    ], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_client_sync_server_unary_qps_unconstrained_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_client_unary_1channel_64wide_128Breq_8MBresp_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 0, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 8388608, \"req_size\": 128}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_client_unary_1channel_64wide_128Breq_8MBresp_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_client_sync_server_streaming_qps_unconstrained_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 0, \"server_type\": \"SYNC_SERVER\"}, \"num_servers\": 1, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 10, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [
+      "poll-cv"
+    ], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_client_sync_server_streaming_qps_unconstrained_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_ping_pong_insecure_1MB\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 0, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_ping_pong_insecure_1MB_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_unary_ping_pong_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 0, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"SYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 2, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_unary_ping_pong_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_unary_qps_unconstrained_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 3, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 3, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"SYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 64, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_unary_qps_unconstrained_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_ping_pong_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 0, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 2, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_ping_pong_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_qps_unconstrained_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 3, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 3, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_qps_unconstrained_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_ping_pong_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 0, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"SYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 2, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_ping_pong_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_qps_unconstrained_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 3, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 3, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"SYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 64, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_qps_unconstrained_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_qps_unconstrained_1mps_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 0, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"messages_per_stream\": 1, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"SYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 64, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_qps_unconstrained_1mps_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_qps_unconstrained_10mps_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 0, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"messages_per_stream\": 10, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"SYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 64, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_qps_unconstrained_10mps_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_ping_pong_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 0, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 2, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_ping_pong_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_qps_unconstrained_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 3, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 3, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_qps_unconstrained_1mps_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 0, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"messages_per_stream\": 1, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_1mps_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_qps_unconstrained_10mps_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 0, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"messages_per_stream\": 10, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_10mps_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_from_client_ping_pong_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 0, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING_FROM_CLIENT\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"SYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 2, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_from_client_ping_pong_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_from_client_qps_unconstrained_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 3, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING_FROM_CLIENT\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 3, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"SYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 64, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_from_client_qps_unconstrained_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_from_client_ping_pong_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 0, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING_FROM_CLIENT\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 2, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_from_client_ping_pong_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_from_client_qps_unconstrained_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 3, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING_FROM_CLIENT\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 3, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_from_client_qps_unconstrained_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_from_server_ping_pong_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 0, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING_FROM_SERVER\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"SYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 2, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_from_server_ping_pong_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_from_server_qps_unconstrained_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 3, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING_FROM_SERVER\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 3, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"SYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 64, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_from_server_qps_unconstrained_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_from_server_ping_pong_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 0, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"latency\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING_FROM_SERVER\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 2, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_from_server_ping_pong_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_from_server_qps_unconstrained_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"security_params\": null, \"threads_per_cq\": 3, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}, {\"int_value\": 1, \"name\": \"grpc.minimal_stack\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING_FROM_SERVER\", \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"threads_per_cq\": 3, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "auto_timeout_scaling": false, 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "noexcept", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_from_server_qps_unconstrained_insecure_low_thread_count", 
+    "timeout_seconds": 600
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/00.bin"
     ], 
     "ci_platforms": [
@@ -93190,6 +104033,98 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-minimized-api_fuzzer-4774951120797696"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "mac", 
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-minimized-api_fuzzer-4829913342279680"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "mac", 
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-minimized-api_fuzzer-5632636438446080"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "mac", 
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-minimized-api_fuzzer-6192640044302336"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "mac", 
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/crash-0597bbdd657fa4ed14443994c9147a1a7bbc205f"
     ], 
     "ci_platforms": [
@@ -105311,6 +116246,29 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/poc-2d730ebd78b3052e4367ad0d485208dcb205482cbcd6289f17907989b8de1fba"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "mac", 
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/poc-c726ee220e980ed6ad17809fd9efe2844ee61555ac08e4f88afd8901cc2dd53a"
     ], 
     "ci_platforms": [
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index 44a6ec2..ba4ab3b 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -167,6 +167,36 @@
         return 'csharpcoreclr'
 
 
+class DartLanguage:
+
+    def __init__(self):
+        self.client_cwd = '../grpc-dart/interop'
+        self.server_cwd = '../grpc-dart/interop'
+        self.http2_cwd = '../grpc-dart/interop'
+        self.safename = str(self)
+
+    def client_cmd(self, args):
+        return ['dart', 'bin/client.dart'] + args
+
+    def cloud_to_prod_env(self):
+        return {}
+
+    def server_cmd(self, args):
+        return ['dart', 'bin/server.dart'] + args
+
+    def global_env(self):
+        return {}
+
+    def unimplemented_test_cases(self):
+        return _SKIP_COMPRESSION
+
+    def unimplemented_test_cases_server(self):
+        return _SKIP_COMPRESSION
+
+    def __str__(self):
+        return 'dart'
+
+
 class JavaLanguage:
 
     def __init__(self):
@@ -355,6 +385,36 @@
         return 'node'
 
 
+class NodePureJSLanguage:
+
+    def __init__(self):
+        self.client_cwd = '../grpc-node'
+        self.server_cwd = '../grpc-node'
+        self.safename = str(self)
+
+    def client_cmd(self, args):
+        return [
+            'packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh',
+            'node', '--require', './test/fixtures/js_js',
+            'test/interop/interop_client.js'
+        ] + args
+
+    def cloud_to_prod_env(self):
+        return {}
+
+    def global_env(self):
+        return {}
+
+    def unimplemented_test_cases(self):
+        return _SKIP_COMPRESSION + _SKIP_DATA_FRAME_PADDING
+
+    def unimplemented_test_cases_server(self):
+        return []
+
+    def __str__(self):
+        return 'nodepurejs'
+
+
 class PHPLanguage:
 
     def __init__(self):
@@ -524,10 +584,12 @@
     'c++': CXXLanguage(),
     'csharp': CSharpLanguage(),
     'csharpcoreclr': CSharpCoreCLRLanguage(),
+    'dart': DartLanguage(),
     'go': GoLanguage(),
     'java': JavaLanguage(),
     'javaokhttp': JavaOkHttpClient(),
     'node': NodeLanguage(),
+    'nodepurejs': NodePureJSLanguage(),
     'php': PHPLanguage(),
     'php7': PHP7Language(),
     'objc': ObjcLanguage(),
@@ -537,7 +599,8 @@
 
 # languages supported as cloud_to_cloud servers
 _SERVERS = [
-    'c++', 'node', 'csharp', 'csharpcoreclr', 'java', 'go', 'ruby', 'python'
+    'c++', 'node', 'csharp', 'csharpcoreclr', 'java', 'go', 'ruby', 'python',
+    'dart'
 ]
 
 _TEST_CASES = [
@@ -644,7 +707,7 @@
     if test_case in ['jwt_token_creds', 'per_rpc_creds', 'oauth2_auth_token']:
         if language in [
                 'csharp', 'csharpcoreclr', 'node', 'php', 'php7', 'python',
-                'ruby'
+                'ruby', 'nodepurejs'
         ]:
             env['GOOGLE_APPLICATION_CREDENTIALS'] = key_filepath
         else:
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index b751bf9..85c7f5c 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -281,7 +281,7 @@
             self._docker_distro, self._make_options = self._compiler_options(
                 self.args.use_docker, self.args.compiler)
         if args.iomgr_platform == "uv":
-            cflags = '-DGRPC_UV -DGRPC_UV_THREAD_CHECK'
+            cflags = '-DGRPC_UV -DGRPC_CUSTOM_IOMGR_THREAD_CHECK '
             try:
                 cflags += subprocess.check_output(
                     ['pkg-config', '--cflags', 'libuv']).strip() + ' '
diff --git a/tools/run_tests/run_tests_matrix.py b/tools/run_tests/run_tests_matrix.py
index 433137a..1c99e79 100755
--- a/tools/run_tests/run_tests_matrix.py
+++ b/tools/run_tests/run_tests_matrix.py
@@ -37,6 +37,9 @@
 # C++ TSAN takes longer than other sanitizers
 _CPP_TSAN_RUNTESTS_TIMEOUT = 8 * 60 * 60
 
+# Set timeout high for ObjC for Cocoapods to install pods
+_OBJC_RUNTESTS_TIMEOUT = 90 * 60
+
 # Number of jobs assigned to each run_tests.py instance
 _DEFAULT_INNER_JOBS = 2
 
@@ -213,7 +216,8 @@
         platforms=['macos'],
         labels=['basictests', 'multilang'],
         extra_args=extra_args,
-        inner_jobs=inner_jobs)
+        inner_jobs=inner_jobs,
+        timeout_seconds=_OBJC_RUNTESTS_TIMEOUT)
 
     # sanitizers
     test_jobs += _generate_jobs(
diff --git a/tools/run_tests/sanity/check_bazel_workspace.py b/tools/run_tests/sanity/check_bazel_workspace.py
index 62a6229..555149c 100755
--- a/tools/run_tests/sanity/check_bazel_workspace.py
+++ b/tools/run_tests/sanity/check_bazel_workspace.py
@@ -35,6 +35,11 @@
 }
 
 _BAZEL_TOOLCHAINS_DEP_NAME = 'com_github_bazelbuild_bazeltoolchains'
+_TWISTED_TWISTED_DEP_NAME = 'com_github_twisted_twisted'
+_YAML_PYYAML_DEP_NAME = 'com_github_yaml_pyyaml'
+_TWISTED_INCREMENTAL_DEP_NAME = 'com_github_twisted_incremental'
+_ZOPEFOUNDATION_ZOPE_INTERFACE_DEP_NAME = 'com_github_zopefoundation_zope_interface'
+_TWISTED_CONSTANTLY_DEP_NAME = 'com_github_twisted_constantly'
 
 _GRPC_DEP_NAMES = [
     'boringssl',
@@ -46,6 +51,20 @@
     'com_github_cares_cares',
     'com_google_absl',
     _BAZEL_TOOLCHAINS_DEP_NAME,
+    _TWISTED_TWISTED_DEP_NAME,
+    _YAML_PYYAML_DEP_NAME,
+    _TWISTED_INCREMENTAL_DEP_NAME,
+    _ZOPEFOUNDATION_ZOPE_INTERFACE_DEP_NAME,
+    _TWISTED_CONSTANTLY_DEP_NAME,
+]
+
+_GRPC_BAZEL_ONLY_DEPS = [
+    _BAZEL_TOOLCHAINS_DEP_NAME,
+    _TWISTED_TWISTED_DEP_NAME,
+    _YAML_PYYAML_DEP_NAME,
+    _TWISTED_INCREMENTAL_DEP_NAME,
+    _ZOPEFOUNDATION_ZOPE_INTERFACE_DEP_NAME,
+    _TWISTED_CONSTANTLY_DEP_NAME,
 ]
 
 
@@ -70,7 +89,8 @@
         return []
 
     def archive(self, **args):
-        if args['name'] == _BAZEL_TOOLCHAINS_DEP_NAME:
+        assert self.names_and_urls.get(args['name']) is None
+        if args['name'] in _GRPC_BAZEL_ONLY_DEPS:
             self.names_and_urls[args['name']] = 'dont care'
             return
         self.names_and_urls[args['name']] = args['url']
@@ -82,8 +102,10 @@
     eval_state = BazelEvalState(names_and_urls)
     bazel_file = f.read()
 
-# grpc_deps.bzl only defines 'grpc_deps', add this to call it
+# grpc_deps.bzl only defines 'grpc_deps' and 'grpc_test_only_deps', add these
+# lines to call them.
 bazel_file += '\ngrpc_deps()\n'
+bazel_file += '\ngrpc_test_only_deps()\n'
 build_rules = {
     'native': eval_state,
 }
@@ -92,11 +114,12 @@
     assert name in names_and_urls.keys()
 assert len(_GRPC_DEP_NAMES) == len(names_and_urls.keys())
 
-# bazeltoolschains is an exception to this sanity check,
-# we don't require that there is a corresponding git module.
-names_without_bazeltoolchains = names_and_urls.keys()
-names_without_bazeltoolchains.remove(_BAZEL_TOOLCHAINS_DEP_NAME)
-archive_urls = [names_and_urls[name] for name in names_without_bazeltoolchains]
+# There are some "bazel-only" deps that are exceptions to this sanity check,
+# we don't require that there is a corresponding git module for these.
+names_without_bazel_only_deps = names_and_urls.keys()
+for dep_name in _GRPC_BAZEL_ONLY_DEPS:
+    names_without_bazel_only_deps.remove(dep_name)
+archive_urls = [names_and_urls[name] for name in names_without_bazel_only_deps]
 workspace_git_hashes = {
     re.search(git_hash_pattern, url).group()
     for url in archive_urls
diff --git a/tools/run_tests/sanity/check_deprecated_grpc++.py b/tools/run_tests/sanity/check_deprecated_grpc++.py
new file mode 100755
index 0000000..4ec49fa
--- /dev/null
+++ b/tools/run_tests/sanity/check_deprecated_grpc++.py
@@ -0,0 +1,191 @@
+#!/usr/bin/env python
+
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import print_function
+
+import os
+import sys
+
+os.chdir(os.path.join(os.path.dirname(sys.argv[0]), '../../..'))
+
+expected_files = [
+    "include/grpc++/create_channel_posix.h", "include/grpc++/server_builder.h",
+    "include/grpc++/resource_quota.h", "include/grpc++/create_channel.h",
+    "include/grpc++/alarm.h", "include/grpc++/server.h",
+    "include/grpc++/server_context.h", "include/grpc++/client_context.h",
+    "include/grpc++/server_posix.h", "include/grpc++/grpc++.h",
+    "include/grpc++/health_check_service_interface.h",
+    "include/grpc++/completion_queue.h", "include/grpc++/channel.h",
+    "include/grpc++/support/sync_stream.h", "include/grpc++/support/status.h",
+    "include/grpc++/support/config.h",
+    "include/grpc++/support/status_code_enum.h",
+    "include/grpc++/support/byte_buffer.h",
+    "include/grpc++/support/error_details.h",
+    "include/grpc++/support/async_unary_call.h",
+    "include/grpc++/support/channel_arguments.h",
+    "include/grpc++/support/async_stream.h", "include/grpc++/support/slice.h",
+    "include/grpc++/support/stub_options.h",
+    "include/grpc++/support/string_ref.h", "include/grpc++/support/time.h",
+    "include/grpc++/security/auth_metadata_processor.h",
+    "include/grpc++/security/credentials.h",
+    "include/grpc++/security/server_credentials.h",
+    "include/grpc++/security/auth_context.h",
+    "include/grpc++/impl/rpc_method.h",
+    "include/grpc++/impl/server_builder_option.h", "include/grpc++/impl/call.h",
+    "include/grpc++/impl/service_type.h", "include/grpc++/impl/grpc_library.h",
+    "include/grpc++/impl/client_unary_call.h",
+    "include/grpc++/impl/channel_argument_option.h",
+    "include/grpc++/impl/rpc_service_method.h",
+    "include/grpc++/impl/method_handler_impl.h",
+    "include/grpc++/impl/server_builder_plugin.h",
+    "include/grpc++/impl/sync_cxx11.h",
+    "include/grpc++/impl/server_initializer.h",
+    "include/grpc++/impl/serialization_traits.h",
+    "include/grpc++/impl/sync_no_cxx11.h",
+    "include/grpc++/impl/codegen/sync_stream.h",
+    "include/grpc++/impl/codegen/channel_interface.h",
+    "include/grpc++/impl/codegen/config_protobuf.h",
+    "include/grpc++/impl/codegen/status.h",
+    "include/grpc++/impl/codegen/core_codegen.h",
+    "include/grpc++/impl/codegen/config.h",
+    "include/grpc++/impl/codegen/core_codegen_interface.h",
+    "include/grpc++/impl/codegen/status_code_enum.h",
+    "include/grpc++/impl/codegen/metadata_map.h",
+    "include/grpc++/impl/codegen/rpc_method.h",
+    "include/grpc++/impl/codegen/server_context.h",
+    "include/grpc++/impl/codegen/byte_buffer.h",
+    "include/grpc++/impl/codegen/async_unary_call.h",
+    "include/grpc++/impl/codegen/server_interface.h",
+    "include/grpc++/impl/codegen/call.h",
+    "include/grpc++/impl/codegen/client_context.h",
+    "include/grpc++/impl/codegen/service_type.h",
+    "include/grpc++/impl/codegen/grpc_library.h",
+    "include/grpc++/impl/codegen/async_stream.h",
+    "include/grpc++/impl/codegen/slice.h",
+    "include/grpc++/impl/codegen/client_unary_call.h",
+    "include/grpc++/impl/codegen/proto_utils.h",
+    "include/grpc++/impl/codegen/stub_options.h",
+    "include/grpc++/impl/codegen/rpc_service_method.h",
+    "include/grpc++/impl/codegen/method_handler_impl.h",
+    "include/grpc++/impl/codegen/string_ref.h",
+    "include/grpc++/impl/codegen/completion_queue_tag.h",
+    "include/grpc++/impl/codegen/call_hook.h",
+    "include/grpc++/impl/codegen/completion_queue.h",
+    "include/grpc++/impl/codegen/serialization_traits.h",
+    "include/grpc++/impl/codegen/create_auth_context.h",
+    "include/grpc++/impl/codegen/time.h",
+    "include/grpc++/impl/codegen/security/auth_context.h",
+    "include/grpc++/ext/health_check_service_server_builder_option.h",
+    "include/grpc++/ext/proto_server_reflection_plugin.h",
+    "include/grpc++/generic/async_generic_service.h",
+    "include/grpc++/generic/generic_stub.h",
+    "include/grpc++/test/mock_stream.h",
+    "include/grpc++/test/server_context_test_spouse.h"
+]
+
+file_template = '''/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// DEPRECATED: The headers in include/grpc++ are deprecated. Please include the
+// headers in include/grpcpp instead. This header exists only for backwards
+// compatibility.
+
+#ifndef GRPCXX_FILE_PATH_NAME_UPPER
+#define GRPCXX_FILE_PATH_NAME_UPPER
+
+#include <grpcpp/FILE_PATH_NAME_LOWER>
+
+#endif  // GRPCXX_FILE_PATH_NAME_UPPER
+'''
+
+errors = 0
+
+path_files = []
+for root, dirs, files in os.walk('include/grpc++'):
+    for filename in files:
+        path_file = os.path.join(root, filename)
+        path_files.append(path_file)
+
+if path_files.sort() != expected_files.sort():
+    diff_plus = [file for file in path_files if file not in expected_files]
+    diff_minus = [file for file in expected_files if file not in path_files]
+    for file in diff_minus:
+        print('- ', file)
+    for file in diff_plus:
+        print('+ ', file)
+    errors += 1
+
+if errors > 0:
+    sys.exit(errors)
+
+for path_file in expected_files:
+    relative_path_file = path_file.split('/', 2)[2]
+
+    replace_lower = relative_path_file.replace('+', 'p')
+
+    replace_upper = relative_path_file.replace('/', '_')
+    replace_upper = replace_upper.replace('.', '_')
+    replace_upper = replace_upper.upper().replace('+', 'X')
+
+    expected_content = file_template.replace('FILE_PATH_NAME_LOWER',
+                                             replace_lower)
+    expected_content = expected_content.replace('FILE_PATH_NAME_UPPER',
+                                                replace_upper)
+
+    path_file_expected = path_file + '.expected'
+    with open(path_file_expected, "w") as fo:
+        fo.write(expected_content)
+
+    if 0 != os.system('diff %s %s' % (path_file_expected, path_file)):
+        print('Difference found in file:', path_file)
+        errors += 1
+
+    os.remove(path_file_expected)
+
+check_extensions = [".h", ".cc", ".c", ".m"]
+
+for root, dirs, files in os.walk('src'):
+    for filename in files:
+        path_file = os.path.join(root, filename)
+        for ext in check_extensions:
+            if path_file.endswith(ext):
+                try:
+                    with open(path_file, "r") as fi:
+                        content = fi.read()
+                        if '#include <grpc++/' in content:
+                            print(
+                                'Failed: invalid include of deprecated headers in include/grpc++ in %s'
+                                % path_file)
+                            errors += 1
+                except IOError:
+                    pass
+
+sys.exit(errors)
diff --git a/tools/run_tests/sanity/check_port_platform.py b/tools/run_tests/sanity/check_port_platform.py
new file mode 100755
index 0000000..fff828e
--- /dev/null
+++ b/tools/run_tests/sanity/check_port_platform.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python
+
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import sys
+
+os.chdir(os.path.join(os.path.dirname(sys.argv[0]), '../../..'))
+
+
+def check_port_platform_inclusion(directory_root):
+    bad_files = []
+    for root, dirs, files in os.walk(directory_root):
+        for filename in files:
+            path = os.path.join(root, filename)
+            if os.path.splitext(path)[1] not in ['.c', '.cc', '.h']: continue
+            if path in [
+                    os.path.join('include', 'grpc', 'support',
+                                 'port_platform.h'),
+                    os.path.join('include', 'grpc', 'impl', 'codegen',
+                                 'port_platform.h'),
+            ]:
+                continue
+            if filename.endswith('.pb.h') or filename.endswith('.pb.c'):
+                continue
+            with open(path) as f:
+                all_lines_in_file = f.readlines()
+                for index, l in enumerate(all_lines_in_file):
+                    if '#include' in l:
+                        if l not in [
+                                '#include <grpc/support/port_platform.h>\n',
+                                '#include <grpc/impl/codegen/port_platform.h>\n'
+                        ]:
+                            bad_files.append(path)
+                        elif all_lines_in_file[index + 1] != '\n':
+                            # Require a blank line after including port_platform.h in
+                            # order to prevent the formatter from reording it's
+                            # inclusion order upon future changes.
+                            bad_files.append(path)
+                        break
+    return bad_files
+
+
+all_bad_files = []
+all_bad_files += check_port_platform_inclusion(os.path.join('src', 'core'))
+all_bad_files += check_port_platform_inclusion(os.path.join('include', 'grpc'))
+
+if len(all_bad_files) > 0:
+    for f in all_bad_files:
+        print(('port_platform.h is not the first included header or there '
+               'is not a blank line following its inclusion in %s') % f)
+    sys.exit(1)
diff --git a/tools/run_tests/sanity/check_shellcheck.sh b/tools/run_tests/sanity/check_shellcheck.sh
index 64f59cb..b94d822 100755
--- a/tools/run_tests/sanity/check_shellcheck.sh
+++ b/tools/run_tests/sanity/check_shellcheck.sh
@@ -19,6 +19,8 @@
 ROOT="$(dirname "$0")/../../.."
 
 DIRS=(
+    'test'
+    'tools/gce'
     'tools/run_tests'
 )
 
diff --git a/tools/run_tests/sanity/check_submodules.sh b/tools/run_tests/sanity/check_submodules.sh
index bbe32f4..b22bbd6 100755
--- a/tools/run_tests/sanity/check_submodules.sh
+++ b/tools/run_tests/sanity/check_submodules.sh
@@ -27,7 +27,7 @@
 git submodule | awk '{ print $1 }' | sort > "$submodules"
 cat << EOF | awk '{ print $1 }' | sort > "$want_submodules"
  5b7683f49e1e9223cf9927b24f6fd3d6bd82e3f8 third_party/benchmark (v1.2.0)
- 4d7ba4e4e57195fcebdabe01489534b446ad02cb third_party/boringssl (heads/chromium-stable)
+ a20bb7ff8bb5057065a2e7941249773f9676cf45 third_party/boringssl (heads/chromium-stable)
  886e7d75368e3f4fab3f4d0d3584e4abfc557755 third_party/boringssl-with-bazel (version_for_cocoapods_7.0-857-g886e7d7)
  30dbc81fb5ffdc98ea9b14b1918bfe4e8779b26e third_party/gflags (v2.2.0)
  ec44c6c1675c25b9827aacd08c02433cccde7780 third_party/googletest (release-1.8.0)
diff --git a/tools/run_tests/sanity/sanity_tests.yaml b/tools/run_tests/sanity/sanity_tests.yaml
index efdb4d8..a15473d 100644
--- a/tools/run_tests/sanity/sanity_tests.yaml
+++ b/tools/run_tests/sanity/sanity_tests.yaml
@@ -10,6 +10,8 @@
 - script: tools/run_tests/sanity/check_unsecure.sh
 - script: tools/run_tests/sanity/core_banned_functions.py
 - script: tools/run_tests/sanity/core_untyped_structs.sh
+- script: tools/run_tests/sanity/check_deprecated_grpc++.py
+- script: tools/run_tests/sanity/check_port_platform.py
 - script: tools/buildgen/generate_projects.sh -j 3
   cpu_cost: 3
 - script: tools/distrib/check_copyright.py
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
deleted file mode 100644
index fbb9fde..0000000
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ /dev/null
@@ -1,1065 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
-  <ItemGroup Label="ProjectConfigurations">
-    <ProjectConfiguration Include="Debug-DLL|Win32">
-      <Configuration>Debug-DLL</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Debug-DLL|x64">
-      <Configuration>Debug-DLL</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release-DLL|Win32">
-      <Configuration>Release-DLL</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release-DLL|x64">
-      <Configuration>Release-DLL</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Debug|Win32">
-      <Configuration>Debug</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Debug|x64">
-      <Configuration>Debug</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|Win32">
-      <Configuration>Release</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|x64">
-      <Configuration>Release</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-  </ItemGroup>
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</ProjectGuid>
-    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
-    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
-    <PlatformToolset>v100</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
-    <PlatformToolset>v110</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
-    <PlatformToolset>v120</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
-    <PlatformToolset>v140</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Debug-DLL'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Release-DLL'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
-  <ImportGroup Label="ExtensionSettings">
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
-    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
-  </ImportGroup>
-  <PropertyGroup Label="UserMacros" />
-  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
-    <TargetName>grpc</TargetName>
-    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
-    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
-    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
-    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Release'">
-    <TargetName>grpc</TargetName>
-    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
-    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
-    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
-    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
-  </PropertyGroup>
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug-DLL|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug-DLL|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release-DLL|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release-DLL|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-
-  <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer_reader.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\load_reporting.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\slice.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\slice_buffer.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\support\workaround_list.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\gpr_slice.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\gpr_types.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\census.h" />
-  </ItemGroup>
-  <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\stats.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\stats_data.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error_internal.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll1_linux.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_limited_pollers_linux.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_thread_pool_linux.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollex_linux.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollsig_linux.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_uv.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\is_epollexclusive_available.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_uv.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\port.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_factory_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_mutator.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sys_epoll_wrapper.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_uv.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_generic.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_manager.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_uv.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_cv.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_common.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_reader.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_writer.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\b64.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\percent_encoding.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_hash_table.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_internal.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_string_helpers.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call_test_only.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\event_string.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\init.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\error_utils.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\http2_errors.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\service_config.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\status_conversion.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_decoder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_encoder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_transport.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_data.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_goaway.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_ping.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_rst_stream.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_settings.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_window_update.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_encoder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_parser.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\http2_settings.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\internal.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\client\http_client_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\message_compress\message_compress_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\server\http_server_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\context\security_context.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\composite\composite_credentials.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\credentials.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\fake\fake_credentials.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\google_default\google_default_credentials.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\iam\iam_credentials.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\jwt\json_token.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\jwt\jwt_credentials.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\jwt\jwt_verifier.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\oauth2\oauth2_credentials.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\plugin\plugin_credentials.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\ssl\ssl_credentials.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\transport\auth_filters.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\transport\lb_targets_info.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\transport\secure_endpoint.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\transport\security_connector.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\transport\security_handshaker.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\transport\tsi_error.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\util\json_util.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\fake_transport_security.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\gts_transport_security.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\ssl_transport_security.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\ssl_types.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\transport_security.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\transport_security_adapter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\transport_security_interface.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\connector.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_connect_handshaker.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_proxy.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\parse_address.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\retry_throttle.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel_index.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\deadline\deadline_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_transport.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\client_load_reporting_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_channel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_client_stats.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\load_balancer_api.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.h" />
-    <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb.h" />
-    <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_common.h" />
-    <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_decode.h" />
-    <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_encode.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\fake\fake_resolver.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\aggregation.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\base_resources.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\census_interface.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\census_rpc_stats.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\trace_context.pb.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\grpc_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map_internal.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\mlog.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\resource.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\rpc_metric_id.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_context.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_label.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_propagation.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_status.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_string.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\tracing.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_cronet_compression_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_utils.h" />
-  </ItemGroup>
-  <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\stats.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\stats_data.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\parser.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\error.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll1_linux.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_limited_pollers_linux.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_thread_pool_linux.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollex_linux.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollsig_linux.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\is_epollexclusive_available.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_factory_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_mutator.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_linux.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix_common.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix_ifaddrs.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix_noifaddrs.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_generic.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_manager.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix_noop.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_cv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_eventfd.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_nospecial.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_reader.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_string.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_writer.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\b64.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\percent_encoding.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_buffer.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_hash_table.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_intern.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_string_helpers.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\alarm.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer_reader.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_details.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_log_batch.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_ping.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue_factory.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\event_string.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.cc">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\metadata_array.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\server.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\error_utils.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\service_config.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\status_conversion.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\trace.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\secure\server_secure_chttp2.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_decoder.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_encoder.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_plugin.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_transport.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_data.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_goaway.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_ping.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_rst_stream.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_settings.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_window_update.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_encoder.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_parser.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\http2_settings.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\parsing.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_lists.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\writing.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\client\http_client_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\http_filters_plugin.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\message_compress\message_compress_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\server\http_server_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli_security_connector.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\context\security_context.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\composite\composite_credentials.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\credentials.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\credentials_metadata.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\fake\fake_credentials.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\google_default\credentials_generic.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\google_default\google_default_credentials.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\iam\iam_credentials.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\jwt\json_token.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\jwt\jwt_credentials.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\jwt\jwt_verifier.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\oauth2\oauth2_credentials.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\plugin\plugin_credentials.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\ssl\ssl_credentials.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\transport\client_auth_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\transport\lb_targets_info.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\transport\secure_endpoint.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\transport\security_connector.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\transport\security_handshaker.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\transport\server_auth_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\transport\tsi_error.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\util\json_util.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init_secure.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\tsi\fake_transport_security.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\tsi\gts_transport_security.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\tsi\ssl_transport_security.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\tsi\transport_security.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\tsi\transport_security_adapter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\secure\secure_channel_create.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\channel_connectivity.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_factory.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_plugin.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\connector.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_connect_handshaker.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_proxy.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_factory.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_registry.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\parse_address.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper_registry.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_factory.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_registry.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\retry_throttle.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel_index.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\deadline\deadline_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\insecure\server_chttp2.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\insecure\server_chttp2_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_plugin.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_transport.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\client_load_reporting_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_channel_secure.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_client_stats.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\load_balancer_api.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_common.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_decode.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_encode.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\fake\fake_resolver.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\pick_first\pick_first.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\round_robin\round_robin.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\dns_resolver_ares.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper_fallback.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\native\dns_resolver.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\sockaddr\sockaddr_resolver.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\base_resources.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\context.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\gen\trace_context.pb.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\grpc_context.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\grpc_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\grpc_plugin.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\initialize.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\mlog.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\operation.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\placeholders.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\resource.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\trace_context.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\tracing.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_cronet_compression_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_utils.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\plugin_registry\grpc_plugin_registry.c">
-    </ClCompile>
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
-      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
-    </ProjectReference>
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="packages.config" />
-  </ItemGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-  <ImportGroup Label="ExtensionTargets">
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
-  </ImportGroup>
-  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
-    <PropertyGroup>
-      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
-    </PropertyGroup>
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
-  </Target>
-</Project>
-
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
deleted file mode 100644
index 5332066..0000000
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ /dev/null
@@ -1,1759 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
-      <Filter>src\core\lib\compression</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
-      <Filter>src\core\lib\compression</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.c">
-      <Filter>src\core\lib\compression</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\stats.c">
-      <Filter>src\core\lib\debug</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\stats_data.c">
-      <Filter>src\core\lib\debug</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
-      <Filter>src\core\lib\http</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
-      <Filter>src\core\lib\http</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\parser.c">
-      <Filter>src\core\lib\http</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\error.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll1_linux.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_limited_pollers_linux.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_thread_pool_linux.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollex_linux.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollsig_linux.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\is_epollexclusive_available.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_factory_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_mutator.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_linux.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix_common.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix_ifaddrs.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix_noifaddrs.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_generic.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_manager.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix_noop.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_cv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_eventfd.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_nospecial.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json.c">
-      <Filter>src\core\lib\json</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_reader.c">
-      <Filter>src\core\lib\json</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_string.c">
-      <Filter>src\core\lib\json</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_writer.c">
-      <Filter>src\core\lib\json</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\b64.c">
-      <Filter>src\core\lib\slice</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\percent_encoding.c">
-      <Filter>src\core\lib\slice</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice.c">
-      <Filter>src\core\lib\slice</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_buffer.c">
-      <Filter>src\core\lib\slice</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_hash_table.c">
-      <Filter>src\core\lib\slice</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_intern.c">
-      <Filter>src\core\lib\slice</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_string_helpers.c">
-      <Filter>src\core\lib\slice</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\alarm.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer_reader.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_details.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_log_batch.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_ping.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue_factory.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\event_string.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.cc">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\metadata_array.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\server.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\error_utils.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\service_config.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\status_conversion.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\trace.c">
-      <Filter>src\core\lib\debug</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\secure\server_secure_chttp2.c">
-      <Filter>src\core\ext\transport\chttp2\server\secure</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_decoder.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_encoder.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_plugin.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_transport.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_data.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_goaway.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_ping.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_rst_stream.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_settings.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_window_update.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_encoder.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_parser.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\http2_settings.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\parsing.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_lists.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\writing.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.c">
-      <Filter>src\core\ext\transport\chttp2\alpn</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\client\http_client_filter.c">
-      <Filter>src\core\ext\filters\http\client</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\http_filters_plugin.c">
-      <Filter>src\core\ext\filters\http</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\message_compress\message_compress_filter.c">
-      <Filter>src\core\ext\filters\http\message_compress</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\server\http_server_filter.c">
-      <Filter>src\core\ext\filters\http\server</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli_security_connector.c">
-      <Filter>src\core\lib\http</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\context\security_context.c">
-      <Filter>src\core\lib\security\context</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\composite\composite_credentials.c">
-      <Filter>src\core\lib\security\credentials\composite</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\credentials.c">
-      <Filter>src\core\lib\security\credentials</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\credentials_metadata.c">
-      <Filter>src\core\lib\security\credentials</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\fake\fake_credentials.c">
-      <Filter>src\core\lib\security\credentials\fake</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\google_default\credentials_generic.c">
-      <Filter>src\core\lib\security\credentials\google_default</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\google_default\google_default_credentials.c">
-      <Filter>src\core\lib\security\credentials\google_default</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\iam\iam_credentials.c">
-      <Filter>src\core\lib\security\credentials\iam</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\jwt\json_token.c">
-      <Filter>src\core\lib\security\credentials\jwt</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\jwt\jwt_credentials.c">
-      <Filter>src\core\lib\security\credentials\jwt</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\jwt\jwt_verifier.c">
-      <Filter>src\core\lib\security\credentials\jwt</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\oauth2\oauth2_credentials.c">
-      <Filter>src\core\lib\security\credentials\oauth2</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\plugin\plugin_credentials.c">
-      <Filter>src\core\lib\security\credentials\plugin</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials\ssl\ssl_credentials.c">
-      <Filter>src\core\lib\security\credentials\ssl</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\transport\client_auth_filter.c">
-      <Filter>src\core\lib\security\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\transport\lb_targets_info.c">
-      <Filter>src\core\lib\security\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\transport\secure_endpoint.c">
-      <Filter>src\core\lib\security\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\transport\security_connector.c">
-      <Filter>src\core\lib\security\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\transport\security_handshaker.c">
-      <Filter>src\core\lib\security\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\transport\server_auth_filter.c">
-      <Filter>src\core\lib\security\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\transport\tsi_error.c">
-      <Filter>src\core\lib\security\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\util\json_util.c">
-      <Filter>src\core\lib\security\util</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init_secure.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\tsi\fake_transport_security.c">
-      <Filter>src\core\tsi</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\tsi\gts_transport_security.c">
-      <Filter>src\core\tsi</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\tsi\ssl_transport_security.c">
-      <Filter>src\core\tsi</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\tsi\transport_security.c">
-      <Filter>src\core\tsi</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\tsi\transport_security_adapter.c">
-      <Filter>src\core\tsi</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.c">
-      <Filter>src\core\ext\transport\chttp2\server</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\secure\secure_channel_create.c">
-      <Filter>src\core\ext\transport\chttp2\client\secure</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\channel_connectivity.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_factory.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_plugin.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\connector.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_connect_handshaker.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_proxy.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_factory.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_registry.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\parse_address.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper_registry.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_factory.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_registry.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\retry_throttle.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel_index.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\deadline\deadline_filter.c">
-      <Filter>src\core\ext\filters\deadline</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.c">
-      <Filter>src\core\ext\transport\chttp2\client</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\insecure\server_chttp2.c">
-      <Filter>src\core\ext\transport\chttp2\server\insecure</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\insecure\server_chttp2_posix.c">
-      <Filter>src\core\ext\transport\chttp2\server\insecure</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create.c">
-      <Filter>src\core\ext\transport\chttp2\client\insecure</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create_posix.c">
-      <Filter>src\core\ext\transport\chttp2\client\insecure</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_plugin.c">
-      <Filter>src\core\ext\transport\inproc</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_transport.c">
-      <Filter>src\core\ext\transport\inproc</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\client_load_reporting_filter.c">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb.c">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_channel_secure.c">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_client_stats.c">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\load_balancer_api.c">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.c">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_common.c">
-      <Filter>third_party\nanopb</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_decode.c">
-      <Filter>third_party\nanopb</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_encode.c">
-      <Filter>third_party\nanopb</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\fake\fake_resolver.c">
-      <Filter>src\core\ext\filters\client_channel\resolver\fake</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\pick_first\pick_first.c">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\pick_first</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\round_robin\round_robin.c">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\round_robin</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\dns_resolver_ares.c">
-      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver_posix.c">
-      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.c">
-      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper_fallback.c">
-      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\native\dns_resolver.c">
-      <Filter>src\core\ext\filters\client_channel\resolver\dns\native</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\sockaddr\sockaddr_resolver.c">
-      <Filter>src\core\ext\filters\client_channel\resolver\sockaddr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting.c">
-      <Filter>src\core\ext\filters\load_reporting</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting_filter.c">
-      <Filter>src\core\ext\filters\load_reporting</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\base_resources.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\context.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.c">
-      <Filter>src\core\ext\census\gen</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\gen\trace_context.pb.c">
-      <Filter>src\core\ext\census\gen</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\grpc_context.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\grpc_filter.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\grpc_plugin.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\initialize.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\mlog.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\operation.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\placeholders.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\resource.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\trace_context.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\tracing.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.c">
-      <Filter>src\core\ext\filters\max_age</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.c">
-      <Filter>src\core\ext\filters\message_size</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_cronet_compression_filter.c">
-      <Filter>src\core\ext\filters\workarounds</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_utils.c">
-      <Filter>src\core\ext\filters\workarounds</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\plugin_registry\grpc_plugin_registry.c">
-      <Filter>src\core\plugin_registry</Filter>
-    </ClCompile>
-  </ItemGroup>
-  <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer_reader.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_posix.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\load_reporting.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\slice.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\slice_buffer.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\support\workaround_list.h">
-      <Filter>include\grpc\support</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\gpr_slice.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\gpr_types.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\census.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-  </ItemGroup>
-  <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h">
-      <Filter>src\core\lib\compression</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h">
-      <Filter>src\core\lib\compression</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.h">
-      <Filter>src\core\lib\compression</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\stats.h">
-      <Filter>src\core\lib\debug</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\stats_data.h">
-      <Filter>src\core\lib\debug</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h">
-      <Filter>src\core\lib\http</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h">
-      <Filter>src\core\lib\http</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h">
-      <Filter>src\core\lib\http</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error_internal.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll1_linux.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_limited_pollers_linux.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_thread_pool_linux.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollex_linux.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollsig_linux.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_uv.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\is_epollexclusive_available.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_uv.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\port.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_windows.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_factory_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_mutator.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sys_epoll_wrapper.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_uv.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_generic.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_manager.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_uv.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_cv.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json.h">
-      <Filter>src\core\lib\json</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_common.h">
-      <Filter>src\core\lib\json</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_reader.h">
-      <Filter>src\core\lib\json</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_writer.h">
-      <Filter>src\core\lib\json</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\b64.h">
-      <Filter>src\core\lib\slice</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\percent_encoding.h">
-      <Filter>src\core\lib\slice</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_hash_table.h">
-      <Filter>src\core\lib\slice</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_internal.h">
-      <Filter>src\core\lib\slice</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_string_helpers.h">
-      <Filter>src\core\lib\slice</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call_test_only.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue_factory.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\event_string.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\init.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\error_utils.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\http2_errors.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\service_config.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\status_conversion.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h">
-      <Filter>src\core\lib\debug</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_decoder.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_encoder.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_transport.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_data.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_goaway.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_ping.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_rst_stream.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_settings.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_window_update.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_encoder.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_parser.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\http2_settings.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\internal.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.h">
-      <Filter>src\core\ext\transport\chttp2\alpn</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\client\http_client_filter.h">
-      <Filter>src\core\ext\filters\http\client</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\message_compress\message_compress_filter.h">
-      <Filter>src\core\ext\filters\http\message_compress</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\server\http_server_filter.h">
-      <Filter>src\core\ext\filters\http\server</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\context\security_context.h">
-      <Filter>src\core\lib\security\context</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\composite\composite_credentials.h">
-      <Filter>src\core\lib\security\credentials\composite</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\credentials.h">
-      <Filter>src\core\lib\security\credentials</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\fake\fake_credentials.h">
-      <Filter>src\core\lib\security\credentials\fake</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\google_default\google_default_credentials.h">
-      <Filter>src\core\lib\security\credentials\google_default</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\iam\iam_credentials.h">
-      <Filter>src\core\lib\security\credentials\iam</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\jwt\json_token.h">
-      <Filter>src\core\lib\security\credentials\jwt</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\jwt\jwt_credentials.h">
-      <Filter>src\core\lib\security\credentials\jwt</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\jwt\jwt_verifier.h">
-      <Filter>src\core\lib\security\credentials\jwt</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\oauth2\oauth2_credentials.h">
-      <Filter>src\core\lib\security\credentials\oauth2</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\plugin\plugin_credentials.h">
-      <Filter>src\core\lib\security\credentials\plugin</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials\ssl\ssl_credentials.h">
-      <Filter>src\core\lib\security\credentials\ssl</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\transport\auth_filters.h">
-      <Filter>src\core\lib\security\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\transport\lb_targets_info.h">
-      <Filter>src\core\lib\security\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\transport\secure_endpoint.h">
-      <Filter>src\core\lib\security\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\transport\security_connector.h">
-      <Filter>src\core\lib\security\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\transport\security_handshaker.h">
-      <Filter>src\core\lib\security\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\transport\tsi_error.h">
-      <Filter>src\core\lib\security\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\util\json_util.h">
-      <Filter>src\core\lib\security\util</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\fake_transport_security.h">
-      <Filter>src\core\tsi</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\gts_transport_security.h">
-      <Filter>src\core\tsi</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\ssl_transport_security.h">
-      <Filter>src\core\tsi</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\ssl_types.h">
-      <Filter>src\core\tsi</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\transport_security.h">
-      <Filter>src\core\tsi</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\transport_security_adapter.h">
-      <Filter>src\core\tsi</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\transport_security_interface.h">
-      <Filter>src\core\tsi</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.h">
-      <Filter>src\core\ext\transport\chttp2\server</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_factory.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\connector.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_connect_handshaker.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_proxy.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_factory.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_registry.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\parse_address.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper_registry.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_factory.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_registry.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\retry_throttle.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel_index.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\deadline\deadline_filter.h">
-      <Filter>src\core\ext\filters\deadline</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.h">
-      <Filter>src\core\ext\transport\chttp2\client</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_transport.h">
-      <Filter>src\core\ext\transport\inproc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\client_load_reporting_filter.h">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb.h">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_channel.h">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_client_stats.h">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\load_balancer_api.h">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.h">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb.h">
-      <Filter>third_party\nanopb</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_common.h">
-      <Filter>third_party\nanopb</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_decode.h">
-      <Filter>third_party\nanopb</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_encode.h">
-      <Filter>third_party\nanopb</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\fake\fake_resolver.h">
-      <Filter>src\core\ext\filters\client_channel\resolver\fake</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver.h">
-      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.h">
-      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting.h">
-      <Filter>src\core\ext\filters\load_reporting</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting_filter.h">
-      <Filter>src\core\ext\filters\load_reporting</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\aggregation.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\base_resources.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\census_interface.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\census_rpc_stats.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.h">
-      <Filter>src\core\ext\census\gen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\trace_context.pb.h">
-      <Filter>src\core\ext\census\gen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\grpc_filter.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map_internal.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\mlog.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\resource.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\rpc_metric_id.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_context.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_label.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_propagation.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_status.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_string.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\tracing.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.h">
-      <Filter>src\core\ext\filters\max_age</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.h">
-      <Filter>src\core\ext\filters\message_size</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_cronet_compression_filter.h">
-      <Filter>src\core\ext\filters\workarounds</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_utils.h">
-      <Filter>src\core\ext\filters\workarounds</Filter>
-    </ClInclude>
-  </ItemGroup>
-
-  <ItemGroup>
-    <Filter Include="include">
-      <UniqueIdentifier>{968de0a1-346d-b75a-6f19-6a55119b8235}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="include\grpc">
-      <UniqueIdentifier>{880c644d-b84f-cfca-98bd-e145f36232ab}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="include\grpc\impl">
-      <UniqueIdentifier>{38832702-fee1-b2bc-75d3-923e748dcde9}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="include\grpc\impl\codegen">
-      <UniqueIdentifier>{def748f5-ed2a-a9bb-40d9-c31d00f0e13b}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="include\grpc\support">
-      <UniqueIdentifier>{31de82ea-dc6c-73fb-a640-979b8a7b240c}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src">
-      <UniqueIdentifier>{d538af37-07b2-062b-fa2a-d9f882cb2737}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core">
-      <UniqueIdentifier>{ea745680-21ea-9c5e-679b-64dc40562d08}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext">
-      <UniqueIdentifier>{3f32a58f-394f-5f13-06aa-6cc52cc2daaf}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\census">
-      <UniqueIdentifier>{9bf70bd2-f553-11b2-c237-abd148971eea}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\census\gen">
-      <UniqueIdentifier>{4a14dd37-5868-c656-7333-fa80574cbb07}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters">
-      <UniqueIdentifier>{a7cd279d-e0ec-32d3-4cbe-778aba4a0000}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel">
-      <UniqueIdentifier>{d38c43fd-50e4-fba5-59c5-0d4817159aad}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\lb_policy">
-      <UniqueIdentifier>{784368be-88aa-3170-1479-48fdf8fbc7be}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\lb_policy\grpclb">
-      <UniqueIdentifier>{82e39ac8-1993-6894-efed-651068234a28}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\lb_policy\grpclb\proto">
-      <UniqueIdentifier>{ff02fee6-7304-df5f-76a6-008b5a1c7d19}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc">
-      <UniqueIdentifier>{953a74cb-cafd-eedd-8d34-038c28daf188}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb">
-      <UniqueIdentifier>{595a1701-eb5a-e8af-ffa3-f67c0e380894}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1">
-      <UniqueIdentifier>{af8e2597-93ef-1381-d773-082a85e7eaf1}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\lb_policy\pick_first">
-      <UniqueIdentifier>{9a3e8049-bc04-8341-5173-6fe5f8a4465c}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\lb_policy\round_robin">
-      <UniqueIdentifier>{6d3d5842-8257-9c58-7985-75f4d98b7d5c}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\resolver">
-      <UniqueIdentifier>{c9873fec-2f83-0497-6d0a-bd9c1cc63be3}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\resolver\dns">
-      <UniqueIdentifier>{91b79502-da45-f80b-933e-c974b089db5c}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\resolver\dns\c_ares">
-      <UniqueIdentifier>{73d42c09-d1b5-2e4e-ef12-d74d8ee33ac2}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\resolver\dns\native">
-      <UniqueIdentifier>{9b2d7e1f-b78a-2e7a-3000-944e46a5fab9}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\resolver\fake">
-      <UniqueIdentifier>{e75d1482-9a43-5fdf-03a5-e2b2833715fb}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\resolver\sockaddr">
-      <UniqueIdentifier>{bd317dd5-323e-5b27-4c05-d85786be36ab}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\deadline">
-      <UniqueIdentifier>{c8dcda4e-dbaa-1ae8-67a9-0dd26046f652}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\http">
-      <UniqueIdentifier>{2e3ab9f3-39ca-db39-cb3e-2196cbc68098}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\http\client">
-      <UniqueIdentifier>{e4f7616b-2b49-7df9-8ca3-eb7848d4609d}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\http\message_compress">
-      <UniqueIdentifier>{7b595f5a-c5b5-29fe-74c2-5ec5fd5c94d2}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\http\server">
-      <UniqueIdentifier>{a40e82ca-0c04-35b8-898d-7ad5f323d110}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\load_reporting">
-      <UniqueIdentifier>{12559ba7-9445-92ae-0c5a-2d79570d4c9b}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\max_age">
-      <UniqueIdentifier>{5369e83c-4625-fc14-cc40-9db5da3a7af4}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\message_size">
-      <UniqueIdentifier>{5ca3f38c-539f-3c4f-b68c-38b31ba339ba}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\workarounds">
-      <UniqueIdentifier>{2ec64619-e2c4-da0f-c10e-e03f5a151300}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\transport">
-      <UniqueIdentifier>{e3abfd0a-064e-0f2f-c8e8-7c5a7e98142a}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\transport\chttp2">
-      <UniqueIdentifier>{ac42667b-bbba-3571-20bc-7a4240ef26ca}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\transport\chttp2\alpn">
-      <UniqueIdentifier>{ef2aa344-783f-7fbd-c83a-47e2d38db14d}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\transport\chttp2\client">
-      <UniqueIdentifier>{dbffebe0-eebb-577d-1860-ef6837f4cf50}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\transport\chttp2\client\insecure">
-      <UniqueIdentifier>{4e699b02-fae4-dabd-afd2-2e41b05bef0e}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\transport\chttp2\client\secure">
-      <UniqueIdentifier>{e98ed28e-8dc5-3bb4-22a2-8893831a0ab8}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\transport\chttp2\server">
-      <UniqueIdentifier>{1d36fe16-b004-6bee-c661-328234bbb469}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\transport\chttp2\server\insecure">
-      <UniqueIdentifier>{e8539863-6029-cca4-44a9-5481cacf8144}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\transport\chttp2\server\secure">
-      <UniqueIdentifier>{0afa539f-8c83-d4b9-cdea-550091f09638}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\transport\chttp2\transport">
-      <UniqueIdentifier>{6f34254e-e69f-c9b4-156d-5024bade5408}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\transport\inproc">
-      <UniqueIdentifier>{fb9e878e-fc50-40af-7646-074229a9d676}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib">
-      <UniqueIdentifier>{5b2ded3f-84a5-f6b4-2060-286c7d1dc945}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\channel">
-      <UniqueIdentifier>{1931b044-90f3-cd68-b5f8-23be77ca8efc}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\compression">
-      <UniqueIdentifier>{dadf7fe9-3f15-d431-e4f6-f987b090536c}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\debug">
-      <UniqueIdentifier>{19122742-9b92-5b67-9fb9-e552ac62ca5d}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\http">
-      <UniqueIdentifier>{dab8f03a-73de-8cfa-88fb-6e04402efb54}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\iomgr">
-      <UniqueIdentifier>{5468ba38-b8a3-85b1-216f-48a2364e18df}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\json">
-      <UniqueIdentifier>{cb2b0073-f2a7-5c63-d182-8874b24bdf36}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\security">
-      <UniqueIdentifier>{c4661d64-349f-01c1-1ba8-0602f9047595}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\security\context">
-      <UniqueIdentifier>{187b52e3-bc78-6c62-3e68-4eb19a257661}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\security\credentials">
-      <UniqueIdentifier>{c8af33b1-f786-001d-3e92-140872dc9829}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\security\credentials\composite">
-      <UniqueIdentifier>{197ed135-5f84-9f6a-6751-38dc5e9dd38c}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\security\credentials\fake">
-      <UniqueIdentifier>{6d391299-53d7-ee6a-55aa-d4c46cd86e82}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\security\credentials\google_default">
-      <UniqueIdentifier>{412c7418-e90a-de77-5705-7890ba960911}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\security\credentials\iam">
-      <UniqueIdentifier>{718f826c-994b-7dd4-3042-0e999c5c22ba}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\security\credentials\jwt">
-      <UniqueIdentifier>{ab21bcdf-de99-5838-699a-19ecb0c4aa14}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\security\credentials\oauth2">
-      <UniqueIdentifier>{f47a7a32-3166-b899-3622-f062f372feea}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\security\credentials\plugin">
-      <UniqueIdentifier>{46120bcc-03e3-1aaa-fc61-9cef786bd70c}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\security\credentials\ssl">
-      <UniqueIdentifier>{9d7802bc-d459-1a9b-3c97-868cddcca1d1}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\security\transport">
-      <UniqueIdentifier>{b22e611f-8272-9914-24a5-8107ebf51eeb}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\security\util">
-      <UniqueIdentifier>{fcd7b397-aadd-556a-8aae-0cb7c893fbe0}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\slice">
-      <UniqueIdentifier>{aed4de18-0b8a-0fed-6f5b-41ea3442310d}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\surface">
-      <UniqueIdentifier>{a21971fb-304f-da08-b1b2-7bd8df8ac373}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\transport">
-      <UniqueIdentifier>{e9d0d3fc-c100-f3e6-89b8-649f241155bf}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\plugin_registry">
-      <UniqueIdentifier>{02bec99b-ff39-88d7-9dea-e0ff9f4a2701}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\tsi">
-      <UniqueIdentifier>{0b0f9ab1-efa4-7f03-e446-6fb9b5227e84}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="third_party">
-      <UniqueIdentifier>{aaab30a4-2a15-732e-c141-3fbc0f0f5a7a}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="third_party\nanopb">
-      <UniqueIdentifier>{93d6596d-330c-1d27-6f84-3c840e57869e}</UniqueIdentifier>
-    </Filter>
-  </ItemGroup>
-</Project>
-
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
deleted file mode 100644
index 3fd0fb5..0000000
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
+++ /dev/null
@@ -1,632 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup Label="ProjectConfigurations">
-    <ProjectConfiguration Include="Debug|Win32">
-      <Configuration>Debug</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Debug|x64">
-      <Configuration>Debug</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|Win32">
-      <Configuration>Release</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|x64">
-      <Configuration>Release</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-  </ItemGroup>
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</ProjectGuid>
-    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
-    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
-    <PlatformToolset>v100</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
-    <PlatformToolset>v110</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
-    <PlatformToolset>v120</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
-    <PlatformToolset>v140</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
-  <ImportGroup Label="ExtensionSettings">
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
-    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
-  </ImportGroup>
-  <PropertyGroup Label="UserMacros" />
-  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
-    <TargetName>grpc_test_util</TargetName>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Release'">
-    <TargetName>grpc_test_util</TargetName>
-  </PropertyGroup>
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-
-  <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer_reader.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\load_reporting.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\slice.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\slice_buffer.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\support\workaround_list.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\gpr_slice.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\gpr_types.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h" />
-  </ItemGroup>
-  <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\data\ssl_test_data.h" />
-    <ClInclude Include="$(SolutionDir)\..\test\core\security\oauth2_utils.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\fake\fake_resolver.h" />
-    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\cq_verifier.h" />
-    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\fixtures\http_proxy_fixture.h" />
-    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\fixtures\proxy.h" />
-    <ClInclude Include="$(SolutionDir)\..\test\core\iomgr\endpoint_tests.h" />
-    <ClInclude Include="$(SolutionDir)\..\test\core\util\debugger_macros.h" />
-    <ClInclude Include="$(SolutionDir)\..\test\core\util\grpc_profiler.h" />
-    <ClInclude Include="$(SolutionDir)\..\test\core\util\memory_counters.h" />
-    <ClInclude Include="$(SolutionDir)\..\test\core\util\mock_endpoint.h" />
-    <ClInclude Include="$(SolutionDir)\..\test\core\util\parse_hexstring.h" />
-    <ClInclude Include="$(SolutionDir)\..\test\core\util\passthru_endpoint.h" />
-    <ClInclude Include="$(SolutionDir)\..\test\core\util\port.h" />
-    <ClInclude Include="$(SolutionDir)\..\test\core\util\port_server_client.h" />
-    <ClInclude Include="$(SolutionDir)\..\test\core\util\slice_splitter.h" />
-    <ClInclude Include="$(SolutionDir)\..\test\core\util\trickle_endpoint.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\stats.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\stats_data.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error_internal.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll1_linux.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_limited_pollers_linux.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_thread_pool_linux.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollex_linux.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollsig_linux.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_uv.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\is_epollexclusive_available.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_uv.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\port.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_factory_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_mutator.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sys_epoll_wrapper.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_uv.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_generic.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_manager.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_uv.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_cv.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_common.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_reader.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_writer.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\b64.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\percent_encoding.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_hash_table.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_internal.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_string_helpers.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call_test_only.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\event_string.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\init.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\error_utils.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\http2_errors.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\service_config.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\status_conversion.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h" />
-  </ItemGroup>
-  <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\data\client_certs.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\data\server1_cert.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\data\server1_key.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\data\test_root_cert.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\security\oauth2_utils.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\fake\fake_resolver.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\cq_verifier.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\http_proxy_fixture.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\proxy.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\iomgr\endpoint_tests.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\debugger_macros.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\grpc_profiler.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\memory_counters.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\mock_endpoint.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\parse_hexstring.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\passthru_endpoint.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\port.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\port_server_client.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\slice_splitter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\trickle_endpoint.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\stats.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\stats_data.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\parser.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\error.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll1_linux.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_limited_pollers_linux.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_thread_pool_linux.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollex_linux.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollsig_linux.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\is_epollexclusive_available.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_factory_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_mutator.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_linux.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix_common.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix_ifaddrs.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix_noifaddrs.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_generic.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_manager.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix_noop.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_cv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_eventfd.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_nospecial.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_reader.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_string.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_writer.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\b64.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\percent_encoding.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_buffer.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_hash_table.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_intern.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_string_helpers.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\alarm.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer_reader.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_details.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_log_batch.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_ping.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue_factory.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\event_string.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.cc">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\metadata_array.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\server.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\error_utils.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\service_config.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\status_conversion.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\trace.c">
-    </ClCompile>
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
-      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
-    </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
-      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
-    </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
-      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
-    </ProjectReference>
-  </ItemGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-  <ImportGroup Label="ExtensionTargets">
-  </ImportGroup>
-  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
-    <PropertyGroup>
-      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
-    </PropertyGroup>
-  </Target>
-</Project>
-
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
deleted file mode 100644
index d516238..0000000
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
+++ /dev/null
@@ -1,1030 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\data\client_certs.c">
-      <Filter>test\core\end2end\data</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\data\server1_cert.c">
-      <Filter>test\core\end2end\data</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\data\server1_key.c">
-      <Filter>test\core\end2end\data</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\data\test_root_cert.c">
-      <Filter>test\core\end2end\data</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\security\oauth2_utils.c">
-      <Filter>test\core\security</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\fake\fake_resolver.c">
-      <Filter>src\core\ext\filters\client_channel\resolver\fake</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\cq_verifier.c">
-      <Filter>test\core\end2end</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\http_proxy_fixture.c">
-      <Filter>test\core\end2end\fixtures</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\proxy.c">
-      <Filter>test\core\end2end\fixtures</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\iomgr\endpoint_tests.c">
-      <Filter>test\core\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\debugger_macros.c">
-      <Filter>test\core\util</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\grpc_profiler.c">
-      <Filter>test\core\util</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\memory_counters.c">
-      <Filter>test\core\util</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\mock_endpoint.c">
-      <Filter>test\core\util</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\parse_hexstring.c">
-      <Filter>test\core\util</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\passthru_endpoint.c">
-      <Filter>test\core\util</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\port.c">
-      <Filter>test\core\util</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\port_server_client.c">
-      <Filter>test\core\util</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\slice_splitter.c">
-      <Filter>test\core\util</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\util\trickle_endpoint.c">
-      <Filter>test\core\util</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
-      <Filter>src\core\lib\compression</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
-      <Filter>src\core\lib\compression</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.c">
-      <Filter>src\core\lib\compression</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\stats.c">
-      <Filter>src\core\lib\debug</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\stats_data.c">
-      <Filter>src\core\lib\debug</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
-      <Filter>src\core\lib\http</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
-      <Filter>src\core\lib\http</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\parser.c">
-      <Filter>src\core\lib\http</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\error.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll1_linux.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_limited_pollers_linux.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_thread_pool_linux.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollex_linux.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollsig_linux.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\is_epollexclusive_available.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_factory_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_mutator.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_linux.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix_common.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix_ifaddrs.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix_noifaddrs.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_generic.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_manager.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix_noop.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_cv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_eventfd.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_nospecial.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json.c">
-      <Filter>src\core\lib\json</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_reader.c">
-      <Filter>src\core\lib\json</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_string.c">
-      <Filter>src\core\lib\json</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_writer.c">
-      <Filter>src\core\lib\json</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\b64.c">
-      <Filter>src\core\lib\slice</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\percent_encoding.c">
-      <Filter>src\core\lib\slice</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice.c">
-      <Filter>src\core\lib\slice</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_buffer.c">
-      <Filter>src\core\lib\slice</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_hash_table.c">
-      <Filter>src\core\lib\slice</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_intern.c">
-      <Filter>src\core\lib\slice</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_string_helpers.c">
-      <Filter>src\core\lib\slice</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\alarm.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer_reader.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_details.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_log_batch.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_ping.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue_factory.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\event_string.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.cc">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\metadata_array.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\server.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\error_utils.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\service_config.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\status_conversion.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\trace.c">
-      <Filter>src\core\lib\debug</Filter>
-    </ClCompile>
-  </ItemGroup>
-  <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer_reader.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_posix.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\load_reporting.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\slice.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\slice_buffer.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\support\workaround_list.h">
-      <Filter>include\grpc\support</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\gpr_slice.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\gpr_types.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-  </ItemGroup>
-  <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\data\ssl_test_data.h">
-      <Filter>test\core\end2end\data</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\test\core\security\oauth2_utils.h">
-      <Filter>test\core\security</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\fake\fake_resolver.h">
-      <Filter>src\core\ext\filters\client_channel\resolver\fake</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\cq_verifier.h">
-      <Filter>test\core\end2end</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\fixtures\http_proxy_fixture.h">
-      <Filter>test\core\end2end\fixtures</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\fixtures\proxy.h">
-      <Filter>test\core\end2end\fixtures</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\test\core\iomgr\endpoint_tests.h">
-      <Filter>test\core\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\test\core\util\debugger_macros.h">
-      <Filter>test\core\util</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\test\core\util\grpc_profiler.h">
-      <Filter>test\core\util</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\test\core\util\memory_counters.h">
-      <Filter>test\core\util</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\test\core\util\mock_endpoint.h">
-      <Filter>test\core\util</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\test\core\util\parse_hexstring.h">
-      <Filter>test\core\util</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\test\core\util\passthru_endpoint.h">
-      <Filter>test\core\util</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\test\core\util\port.h">
-      <Filter>test\core\util</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\test\core\util\port_server_client.h">
-      <Filter>test\core\util</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\test\core\util\slice_splitter.h">
-      <Filter>test\core\util</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\test\core\util\trickle_endpoint.h">
-      <Filter>test\core\util</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h">
-      <Filter>src\core\lib\compression</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h">
-      <Filter>src\core\lib\compression</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.h">
-      <Filter>src\core\lib\compression</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\stats.h">
-      <Filter>src\core\lib\debug</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\stats_data.h">
-      <Filter>src\core\lib\debug</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h">
-      <Filter>src\core\lib\http</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h">
-      <Filter>src\core\lib\http</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h">
-      <Filter>src\core\lib\http</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error_internal.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll1_linux.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_limited_pollers_linux.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_thread_pool_linux.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollex_linux.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollsig_linux.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_uv.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\is_epollexclusive_available.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_uv.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\port.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_windows.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_factory_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_mutator.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sys_epoll_wrapper.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_uv.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_generic.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_manager.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_uv.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_cv.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json.h">
-      <Filter>src\core\lib\json</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_common.h">
-      <Filter>src\core\lib\json</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_reader.h">
-      <Filter>src\core\lib\json</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_writer.h">
-      <Filter>src\core\lib\json</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\b64.h">
-      <Filter>src\core\lib\slice</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\percent_encoding.h">
-      <Filter>src\core\lib\slice</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_hash_table.h">
-      <Filter>src\core\lib\slice</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_internal.h">
-      <Filter>src\core\lib\slice</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_string_helpers.h">
-      <Filter>src\core\lib\slice</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call_test_only.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue_factory.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\event_string.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\init.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\error_utils.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\http2_errors.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\service_config.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\status_conversion.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h">
-      <Filter>src\core\lib\debug</Filter>
-    </ClInclude>
-  </ItemGroup>
-
-  <ItemGroup>
-    <Filter Include="include">
-      <UniqueIdentifier>{50129440-aff7-7df7-682c-b9671be19a6f}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="include\grpc">
-      <UniqueIdentifier>{d448b078-95a6-6fca-fe4a-8b44dd71f359}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="include\grpc\impl">
-      <UniqueIdentifier>{314a6801-6fe3-9211-33d8-ecf3332c1151}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="include\grpc\impl\codegen">
-      <UniqueIdentifier>{8e97f1e1-f4d1-a56e-0837-7901778fb3b9}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="include\grpc\support">
-      <UniqueIdentifier>{b783a829-3703-129f-39ee-528ac0a06e06}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src">
-      <UniqueIdentifier>{7d107d7c-1da3-9525-3ba1-3a411b552ea8}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core">
-      <UniqueIdentifier>{f7bfac91-5eb2-dea7-4601-6c63edbbf997}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext">
-      <UniqueIdentifier>{5db70e06-741d-708c-bf0a-b59f8ca1f8bd}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters">
-      <UniqueIdentifier>{f0f88514-c2d8-c4c9-c3bd-591682207751}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel">
-      <UniqueIdentifier>{5bb60a9e-156f-e1c8-3b9c-1b23e7992d7a}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\resolver">
-      <UniqueIdentifier>{24a50975-435e-20a5-b0f2-71bc330d0378}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\resolver\fake">
-      <UniqueIdentifier>{9e94ffec-fe00-d132-db50-c4a3c218f102}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib">
-      <UniqueIdentifier>{f4e8c61e-1ca6-0fdd-7b5e-b7f9a30c9a21}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\channel">
-      <UniqueIdentifier>{1cd1503c-bec0-5ade-c75f-aa25c80975ec}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\compression">
-      <UniqueIdentifier>{09632582-2cc3-5618-d673-65d3884f8ce5}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\debug">
-      <UniqueIdentifier>{2c1a72e9-886e-8082-9d2f-0fc9cb3ab996}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\http">
-      <UniqueIdentifier>{4862ecce-fa07-eb5e-5c05-bfa753c8bfe5}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\iomgr">
-      <UniqueIdentifier>{fc7f488e-08b4-8366-3720-1f7ffaa0b0b3}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\json">
-      <UniqueIdentifier>{89bc8f83-e29a-ddab-8f6b-22df11cdc867}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\slice">
-      <UniqueIdentifier>{4d172bbc-20c4-6e7d-872a-2d287b589aa0}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\surface">
-      <UniqueIdentifier>{7f2b7dca-395f-94dd-c9ad-9a286bd9751e}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\transport">
-      <UniqueIdentifier>{5249e884-ea07-6782-531d-ec622c54b9af}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test">
-      <UniqueIdentifier>{a2783de3-4fcf-718d-a859-c2108350ff33}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core">
-      <UniqueIdentifier>{f95a0dc5-2e57-c168-6128-fe07e1bd58a9}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core\end2end">
-      <UniqueIdentifier>{7004f7a6-a821-a581-1df5-94c7d22c6850}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core\end2end\data">
-      <UniqueIdentifier>{c0da5050-98b1-e4af-71a7-6317af6338e0}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core\end2end\fixtures">
-      <UniqueIdentifier>{1daa14ff-cf54-5a38-9104-46ed9882784b}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core\iomgr">
-      <UniqueIdentifier>{d3dce584-6111-9ff2-affe-5933a9291c17}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core\security">
-      <UniqueIdentifier>{b0938b31-f9d5-21d7-de41-08107caafd80}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core\util">
-      <UniqueIdentifier>{6e9f8de1-258c-578f-aa3d-7da9320a3171}</UniqueIdentifier>
-    </Filter>
-  </ItemGroup>
-</Project>
-
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
deleted file mode 100644
index 08c1e78..0000000
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ /dev/null
@@ -1,957 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup Label="ProjectConfigurations">
-    <ProjectConfiguration Include="Debug-DLL|Win32">
-      <Configuration>Debug-DLL</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Debug-DLL|x64">
-      <Configuration>Debug-DLL</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release-DLL|Win32">
-      <Configuration>Release-DLL</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release-DLL|x64">
-      <Configuration>Release-DLL</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Debug|Win32">
-      <Configuration>Debug</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Debug|x64">
-      <Configuration>Debug</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|Win32">
-      <Configuration>Release</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|x64">
-      <Configuration>Release</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-  </ItemGroup>
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}</ProjectGuid>
-    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
-    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
-    <PlatformToolset>v100</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
-    <PlatformToolset>v110</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
-    <PlatformToolset>v120</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
-    <PlatformToolset>v140</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Debug-DLL'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Release-DLL'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
-  <ImportGroup Label="ExtensionSettings">
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
-    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
-  </ImportGroup>
-  <PropertyGroup Label="UserMacros" />
-  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
-    <TargetName>grpc_unsecure</TargetName>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Release'">
-    <TargetName>grpc_unsecure</TargetName>
-  </PropertyGroup>
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug-DLL|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug-DLL|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release-DLL|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release-DLL|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-
-  <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer_reader.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\load_reporting.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\slice.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\slice_buffer.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\support\workaround_list.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\gpr_slice.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\gpr_types.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\census.h" />
-  </ItemGroup>
-  <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\stats.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\stats_data.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error_internal.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll1_linux.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_limited_pollers_linux.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_thread_pool_linux.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollex_linux.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollsig_linux.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_uv.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\is_epollexclusive_available.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_uv.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\port.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_factory_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_mutator.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sys_epoll_wrapper.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_uv.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_generic.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_manager.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_uv.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_cv.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_common.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_reader.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_writer.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\b64.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\percent_encoding.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_hash_table.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_internal.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_string_helpers.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call_test_only.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\event_string.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\init.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\error_utils.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\http2_errors.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\service_config.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\status_conversion.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_decoder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_encoder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_transport.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_data.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_goaway.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_ping.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_rst_stream.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_settings.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_window_update.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_encoder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_parser.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\http2_settings.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\internal.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\client\http_client_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\message_compress\message_compress_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\server\http_server_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\connector.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_connect_handshaker.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_proxy.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\parse_address.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\retry_throttle.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel_index.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\deadline\deadline_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_transport.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\fake\fake_resolver.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\client_load_reporting_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_channel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_client_stats.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\load_balancer_api.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.h" />
-    <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb.h" />
-    <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_common.h" />
-    <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_decode.h" />
-    <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_encode.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\aggregation.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\base_resources.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\census_interface.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\census_rpc_stats.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\trace_context.pb.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\grpc_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map_internal.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\mlog.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\resource.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\rpc_metric_id.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_context.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_label.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_propagation.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_status.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_string.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\tracing.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_cronet_compression_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_utils.h" />
-  </ItemGroup>
-  <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init_unsecure.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\stats.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\stats_data.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\parser.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\error.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll1_linux.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_limited_pollers_linux.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_thread_pool_linux.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollex_linux.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollsig_linux.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\is_epollexclusive_available.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_factory_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_mutator.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_linux.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix_common.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix_ifaddrs.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix_noifaddrs.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_generic.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_manager.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_uv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix_noop.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_cv.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_eventfd.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_nospecial.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_reader.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_string.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_writer.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\b64.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\percent_encoding.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_buffer.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_hash_table.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_intern.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_string_helpers.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\alarm.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer_reader.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_details.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_log_batch.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_ping.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue_factory.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\event_string.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.cc">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\metadata_array.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\server.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\error_utils.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\service_config.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\status_conversion.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\trace.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\insecure\server_chttp2.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\insecure\server_chttp2_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_decoder.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_encoder.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_plugin.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_transport.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_data.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_goaway.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_ping.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_rst_stream.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_settings.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_window_update.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_encoder.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_parser.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\http2_settings.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\parsing.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_lists.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\writing.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\client\http_client_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\http_filters_plugin.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\message_compress\message_compress_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\server\http_server_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\channel_connectivity.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_factory.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_plugin.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\connector.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_connect_handshaker.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_proxy.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_factory.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_registry.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\parse_address.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper_registry.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_factory.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_registry.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\retry_throttle.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel_index.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\deadline\deadline_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_plugin.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_transport.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\dns_resolver_ares.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver_posix.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper_fallback.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\native\dns_resolver.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\sockaddr\sockaddr_resolver.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\fake\fake_resolver.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\client_load_reporting_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_channel.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_client_stats.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\load_balancer_api.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_common.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_decode.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_encode.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\pick_first\pick_first.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\round_robin\round_robin.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\base_resources.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\context.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\gen\trace_context.pb.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\grpc_context.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\grpc_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\grpc_plugin.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\initialize.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\mlog.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\operation.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\placeholders.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\resource.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\trace_context.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\tracing.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_cronet_compression_filter.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_utils.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\plugin_registry\grpc_unsecure_plugin_registry.c">
-    </ClCompile>
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
-      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
-    </ProjectReference>
-  </ItemGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-  <ImportGroup Label="ExtensionTargets">
-  </ImportGroup>
-  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
-    <PropertyGroup>
-      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
-    </PropertyGroup>
-  </Target>
-</Project>
-
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
deleted file mode 100644
index d9a5914..0000000
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ /dev/null
@@ -1,1540 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init_unsecure.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
-      <Filter>src\core\lib\compression</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
-      <Filter>src\core\lib\compression</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.c">
-      <Filter>src\core\lib\compression</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\stats.c">
-      <Filter>src\core\lib\debug</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\stats_data.c">
-      <Filter>src\core\lib\debug</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
-      <Filter>src\core\lib\http</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
-      <Filter>src\core\lib\http</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\parser.c">
-      <Filter>src\core\lib\http</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\error.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll1_linux.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_limited_pollers_linux.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_thread_pool_linux.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollex_linux.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollsig_linux.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\is_epollexclusive_available.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_factory_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_mutator.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_linux.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix_common.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix_ifaddrs.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix_noifaddrs.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_generic.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_manager.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_uv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix_noop.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_cv.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_eventfd.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_nospecial.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.c">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json.c">
-      <Filter>src\core\lib\json</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_reader.c">
-      <Filter>src\core\lib\json</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_string.c">
-      <Filter>src\core\lib\json</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_writer.c">
-      <Filter>src\core\lib\json</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\b64.c">
-      <Filter>src\core\lib\slice</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\percent_encoding.c">
-      <Filter>src\core\lib\slice</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice.c">
-      <Filter>src\core\lib\slice</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_buffer.c">
-      <Filter>src\core\lib\slice</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_hash_table.c">
-      <Filter>src\core\lib\slice</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_intern.c">
-      <Filter>src\core\lib\slice</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\slice\slice_string_helpers.c">
-      <Filter>src\core\lib\slice</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\alarm.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer_reader.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_details.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_log_batch.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_ping.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue_factory.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\event_string.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.cc">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\metadata_array.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\server.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c">
-      <Filter>src\core\lib\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\error_utils.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\service_config.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\status_conversion.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
-      <Filter>src\core\lib\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\trace.c">
-      <Filter>src\core\lib\debug</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\insecure\server_chttp2.c">
-      <Filter>src\core\ext\transport\chttp2\server\insecure</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\insecure\server_chttp2_posix.c">
-      <Filter>src\core\ext\transport\chttp2\server\insecure</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_decoder.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_encoder.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_plugin.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_transport.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_data.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_goaway.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_ping.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_rst_stream.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_settings.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_window_update.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_encoder.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_parser.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\http2_settings.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\parsing.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_lists.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\writing.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.c">
-      <Filter>src\core\ext\transport\chttp2\alpn</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\client\http_client_filter.c">
-      <Filter>src\core\ext\filters\http\client</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\http_filters_plugin.c">
-      <Filter>src\core\ext\filters\http</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\message_compress\message_compress_filter.c">
-      <Filter>src\core\ext\filters\http\message_compress</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\http\server\http_server_filter.c">
-      <Filter>src\core\ext\filters\http\server</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.c">
-      <Filter>src\core\ext\transport\chttp2\server</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create.c">
-      <Filter>src\core\ext\transport\chttp2\client\insecure</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create_posix.c">
-      <Filter>src\core\ext\transport\chttp2\client\insecure</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.c">
-      <Filter>src\core\ext\transport\chttp2\client</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\channel_connectivity.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_factory.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_plugin.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\connector.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_connect_handshaker.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_proxy.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_factory.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_registry.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\parse_address.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper_registry.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_factory.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_registry.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\retry_throttle.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel_index.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.c">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\deadline\deadline_filter.c">
-      <Filter>src\core\ext\filters\deadline</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_plugin.c">
-      <Filter>src\core\ext\transport\inproc</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_transport.c">
-      <Filter>src\core\ext\transport\inproc</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\dns_resolver_ares.c">
-      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver_posix.c">
-      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.c">
-      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper_fallback.c">
-      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\native\dns_resolver.c">
-      <Filter>src\core\ext\filters\client_channel\resolver\dns\native</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\sockaddr\sockaddr_resolver.c">
-      <Filter>src\core\ext\filters\client_channel\resolver\sockaddr</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\fake\fake_resolver.c">
-      <Filter>src\core\ext\filters\client_channel\resolver\fake</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting.c">
-      <Filter>src\core\ext\filters\load_reporting</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting_filter.c">
-      <Filter>src\core\ext\filters\load_reporting</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\client_load_reporting_filter.c">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb.c">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_channel.c">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_client_stats.c">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\load_balancer_api.c">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.c">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_common.c">
-      <Filter>third_party\nanopb</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_decode.c">
-      <Filter>third_party\nanopb</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_encode.c">
-      <Filter>third_party\nanopb</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\pick_first\pick_first.c">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\pick_first</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\round_robin\round_robin.c">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\round_robin</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\base_resources.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\context.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.c">
-      <Filter>src\core\ext\census\gen</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\gen\trace_context.pb.c">
-      <Filter>src\core\ext\census\gen</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\grpc_context.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\grpc_filter.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\grpc_plugin.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\initialize.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\mlog.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\operation.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\placeholders.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\resource.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\trace_context.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\tracing.c">
-      <Filter>src\core\ext\census</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.c">
-      <Filter>src\core\ext\filters\max_age</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.c">
-      <Filter>src\core\ext\filters\message_size</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_cronet_compression_filter.c">
-      <Filter>src\core\ext\filters\workarounds</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_utils.c">
-      <Filter>src\core\ext\filters\workarounds</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\plugin_registry\grpc_unsecure_plugin_registry.c">
-      <Filter>src\core\plugin_registry</Filter>
-    </ClCompile>
-  </ItemGroup>
-  <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer_reader.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_posix.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\load_reporting.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\slice.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\slice_buffer.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\support\workaround_list.h">
-      <Filter>include\grpc\support</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\gpr_slice.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\gpr_types.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\census.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-  </ItemGroup>
-  <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h">
-      <Filter>src\core\lib\compression</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h">
-      <Filter>src\core\lib\compression</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.h">
-      <Filter>src\core\lib\compression</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\stats.h">
-      <Filter>src\core\lib\debug</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\stats_data.h">
-      <Filter>src\core\lib\debug</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h">
-      <Filter>src\core\lib\http</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h">
-      <Filter>src\core\lib\http</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h">
-      <Filter>src\core\lib\http</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error_internal.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll1_linux.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_limited_pollers_linux.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_thread_pool_linux.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollex_linux.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epollsig_linux.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_uv.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\is_epollexclusive_available.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_uv.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\port.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resource_quota.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_windows.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_factory_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_mutator.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sys_epoll_wrapper.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_utils_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_uv.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_generic.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_manager.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_uv.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_cv.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.h">
-      <Filter>src\core\lib\iomgr</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json.h">
-      <Filter>src\core\lib\json</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_common.h">
-      <Filter>src\core\lib\json</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_reader.h">
-      <Filter>src\core\lib\json</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_writer.h">
-      <Filter>src\core\lib\json</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\b64.h">
-      <Filter>src\core\lib\slice</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\percent_encoding.h">
-      <Filter>src\core\lib\slice</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_hash_table.h">
-      <Filter>src\core\lib\slice</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_internal.h">
-      <Filter>src\core\lib\slice</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_string_helpers.h">
-      <Filter>src\core\lib\slice</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call_test_only.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue_factory.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\event_string.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\init.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.h">
-      <Filter>src\core\lib\surface</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\bdp_estimator.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\error_utils.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\http2_errors.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\pid_controller.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\service_config.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\status_conversion.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h">
-      <Filter>src\core\lib\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h">
-      <Filter>src\core\lib\debug</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_decoder.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_encoder.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_transport.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_data.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_goaway.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_ping.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_rst_stream.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_settings.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_window_update.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_encoder.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_parser.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\http2_settings.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\internal.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.h">
-      <Filter>src\core\ext\transport\chttp2\alpn</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\client\http_client_filter.h">
-      <Filter>src\core\ext\filters\http\client</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\message_compress\message_compress_filter.h">
-      <Filter>src\core\ext\filters\http\message_compress</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\http\server\http_server_filter.h">
-      <Filter>src\core\ext\filters\http\server</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.h">
-      <Filter>src\core\ext\transport\chttp2\server</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.h">
-      <Filter>src\core\ext\transport\chttp2\client</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_factory.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\connector.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_connect_handshaker.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_proxy.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_factory.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_registry.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\parse_address.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper_registry.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_factory.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_registry.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\retry_throttle.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel_index.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.h">
-      <Filter>src\core\ext\filters\client_channel</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\deadline\deadline_filter.h">
-      <Filter>src\core\ext\filters\deadline</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_transport.h">
-      <Filter>src\core\ext\transport\inproc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver.h">
-      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.h">
-      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\fake\fake_resolver.h">
-      <Filter>src\core\ext\filters\client_channel\resolver\fake</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting.h">
-      <Filter>src\core\ext\filters\load_reporting</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting_filter.h">
-      <Filter>src\core\ext\filters\load_reporting</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\client_load_reporting_filter.h">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb.h">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_channel.h">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_client_stats.h">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\load_balancer_api.h">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.h">
-      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb.h">
-      <Filter>third_party\nanopb</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_common.h">
-      <Filter>third_party\nanopb</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_decode.h">
-      <Filter>third_party\nanopb</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_encode.h">
-      <Filter>third_party\nanopb</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\aggregation.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\base_resources.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\census_interface.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\census_rpc_stats.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.h">
-      <Filter>src\core\ext\census\gen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\trace_context.pb.h">
-      <Filter>src\core\ext\census\gen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\grpc_filter.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map_internal.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\mlog.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\resource.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\rpc_metric_id.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_context.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_label.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_propagation.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_status.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_string.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\tracing.h">
-      <Filter>src\core\ext\census</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.h">
-      <Filter>src\core\ext\filters\max_age</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.h">
-      <Filter>src\core\ext\filters\message_size</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_cronet_compression_filter.h">
-      <Filter>src\core\ext\filters\workarounds</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_utils.h">
-      <Filter>src\core\ext\filters\workarounds</Filter>
-    </ClInclude>
-  </ItemGroup>
-
-  <ItemGroup>
-    <Filter Include="include">
-      <UniqueIdentifier>{10076c7e-7c8e-8005-0c81-64454af2cbc8}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="include\grpc">
-      <UniqueIdentifier>{77b9717b-b8d8-dd5f-14bb-a3e96809a70a}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="include\grpc\impl">
-      <UniqueIdentifier>{10cfa248-c60f-376f-e7ae-2a7d7d8e81f5}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="include\grpc\impl\codegen">
-      <UniqueIdentifier>{03cc6735-c734-7017-4000-a435f29d55c3}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="include\grpc\support">
-      <UniqueIdentifier>{a553e3dc-8973-1b23-8be4-31852fd9e429}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src">
-      <UniqueIdentifier>{aaf326a1-c884-46ea-875a-cbbd9983e539}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core">
-      <UniqueIdentifier>{88491077-386b-2039-d14c-0c40136b5f7a}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext">
-      <UniqueIdentifier>{82f86e8c-00a4-f566-d235-670fc629798d}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\census">
-      <UniqueIdentifier>{3f21cd12-b8b9-18f8-8780-e21bbe2285d0}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\census\gen">
-      <UniqueIdentifier>{dfe53168-57b0-3ac4-d8ba-07fd958cc8f5}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters">
-      <UniqueIdentifier>{5e37012e-a374-e285-bbda-b0dbe6327663}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel">
-      <UniqueIdentifier>{bb0de45a-745e-8822-7ad5-453f9e060f8c}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\lb_policy">
-      <UniqueIdentifier>{2ac0872e-12dc-0b08-68e0-66829ce8c268}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\lb_policy\grpclb">
-      <UniqueIdentifier>{6cc603b0-7272-0a9f-59c2-5561c1856a6a}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\lb_policy\grpclb\proto">
-      <UniqueIdentifier>{0d3bc4ed-1eea-8b17-c26f-7d87c3dd2220}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc">
-      <UniqueIdentifier>{32d37957-d122-e649-b9c1-3f13f6674479}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb">
-      <UniqueIdentifier>{153a159f-1ba7-aea7-ebed-4f2d9e2e7bb9}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1">
-      <UniqueIdentifier>{f8747b87-02f9-df6c-0eeb-27ab1d037d0c}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\lb_policy\pick_first">
-      <UniqueIdentifier>{4df776ac-ebeb-4933-554e-749a0399ff51}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\lb_policy\round_robin">
-      <UniqueIdentifier>{5244539b-6cec-80c7-61dc-df51e531bedd}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\resolver">
-      <UniqueIdentifier>{663be499-ce6c-8afd-db98-674f26be1149}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\resolver\dns">
-      <UniqueIdentifier>{f6bf03da-fa0d-0c24-bba2-17dc5a3c8fe0}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\resolver\dns\c_ares">
-      <UniqueIdentifier>{54bc0ac2-39c8-dbfd-c5dd-b9fb597dd820}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\resolver\dns\native">
-      <UniqueIdentifier>{55f499bd-ae18-5210-81e1-385c85e60875}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\resolver\fake">
-      <UniqueIdentifier>{7f924133-4a98-87b0-f158-cb64ea91e71a}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\client_channel\resolver\sockaddr">
-      <UniqueIdentifier>{99210f5e-b2a0-ecd1-024f-fc152db68a11}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\deadline">
-      <UniqueIdentifier>{ac374be1-7a3f-14a8-69fe-badac2d9f9ec}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\http">
-      <UniqueIdentifier>{33287f7d-739b-d30d-a9f3-b338103456b0}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\http\client">
-      <UniqueIdentifier>{95cd5972-7339-6f09-2332-e6769b3cba3f}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\http\message_compress">
-      <UniqueIdentifier>{cf8cb886-3020-e143-317e-730ff9bbddc3}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\http\server">
-      <UniqueIdentifier>{2c1e7897-6f69-f8b9-0b90-5c3fae59a48f}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\load_reporting">
-      <UniqueIdentifier>{0aef07b4-39d2-f862-15ac-65b4bf00dabb}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\max_age">
-      <UniqueIdentifier>{d3bc80c1-5f2d-e842-42ac-43d8a6ada8de}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\message_size">
-      <UniqueIdentifier>{8cbe7444-caac-49dc-be89-d4c4d1c7966a}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\filters\workarounds">
-      <UniqueIdentifier>{8bd0612e-bd53-c9e6-7b3c-20937e4e1e9e}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\transport">
-      <UniqueIdentifier>{967c89fe-c97c-27e2-aac0-9ba5854cb5fa}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\transport\chttp2">
-      <UniqueIdentifier>{702829f0-099e-2ab7-6b44-ed7cff3ec083}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\transport\chttp2\alpn">
-      <UniqueIdentifier>{7d4830f7-20db-07d3-c3a9-ecfe63ae1992}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\transport\chttp2\client">
-      <UniqueIdentifier>{0d589e16-e470-4968-318c-796af5a33637}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\transport\chttp2\client\insecure">
-      <UniqueIdentifier>{34dfdc9b-ab97-47f0-c1e1-b2e7381c3de6}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\transport\chttp2\server">
-      <UniqueIdentifier>{81fb55f4-9216-441b-8389-a7120bbcd45e}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\transport\chttp2\server\insecure">
-      <UniqueIdentifier>{3f53dcb6-71d7-28ff-1794-26a08e4601fe}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\transport\chttp2\transport">
-      <UniqueIdentifier>{45b20f28-376c-9dea-1800-8a0193411946}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\ext\transport\inproc">
-      <UniqueIdentifier>{287a62fa-b646-5062-49c4-9e7bd5bc5b96}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib">
-      <UniqueIdentifier>{8bd5b461-bff8-6aa8-b5a6-85da2834eb8a}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\channel">
-      <UniqueIdentifier>{fb964f3d-a59c-a7ba-fee5-6072dbb94a7b}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\compression">
-      <UniqueIdentifier>{b88002e9-185e-4e64-49f5-2d8989ce87f6}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\debug">
-      <UniqueIdentifier>{7f23789d-f18a-2a2d-60fe-a87dc656f539}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\http">
-      <UniqueIdentifier>{748c8078-2027-8641-f485-1d4c66466e79}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\iomgr">
-      <UniqueIdentifier>{bb1a1cf2-6824-08f0-a9bd-3fafcaf13042}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\json">
-      <UniqueIdentifier>{681cdaeb-c47f-8853-d985-bf13c2873947}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\slice">
-      <UniqueIdentifier>{74c81ab7-e329-a362-3890-4c41b90f0511}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\surface">
-      <UniqueIdentifier>{506dc3b3-d884-2b59-0dfa-57ed6affa2d3}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\lib\transport">
-      <UniqueIdentifier>{6c3394d1-27e9-003e-19ed-8116d210f7cc}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\plugin_registry">
-      <UniqueIdentifier>{babf0a90-e934-f599-5475-e6937d9580fe}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="third_party">
-      <UniqueIdentifier>{025c051e-8eba-125b-67f9-173f95176eb2}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="third_party\nanopb">
-      <UniqueIdentifier>{6511f77d-f28c-80e0-0889-8975e688e344}</UniqueIdentifier>
-    </Filter>
-  </ItemGroup>
-</Project>
-
diff --git a/vsprojects/vcxproj/test/grpc_channel_stack_builder_test/grpc_channel_stack_builder_test.vcxproj b/vsprojects/vcxproj/test/grpc_channel_stack_builder_test/grpc_channel_stack_builder_test.vcxproj
deleted file mode 100644
index 23bd953..0000000
--- a/vsprojects/vcxproj/test/grpc_channel_stack_builder_test/grpc_channel_stack_builder_test.vcxproj
+++ /dev/null
@@ -1,199 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
-  <ItemGroup Label="ProjectConfigurations">
-    <ProjectConfiguration Include="Debug|Win32">
-      <Configuration>Debug</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Debug|x64">
-      <Configuration>Debug</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|Win32">
-      <Configuration>Release</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|x64">
-      <Configuration>Release</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-  </ItemGroup>
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>{6B598028-E3EC-17BB-84C0-3DA645FE5379}</ProjectGuid>
-    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
-    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
-    <PlatformToolset>v100</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
-    <PlatformToolset>v110</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
-    <PlatformToolset>v120</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
-    <PlatformToolset>v140</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
-    <ConfigurationType>Application</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
-    <ConfigurationType>Application</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
-  <ImportGroup Label="ExtensionSettings">
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
-    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
-    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
-    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
-  </ImportGroup>
-  <PropertyGroup Label="UserMacros" />
-  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
-    <TargetName>grpc_channel_stack_builder_test</TargetName>
-    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
-    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
-    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
-    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Release'">
-    <TargetName>grpc_channel_stack_builder_test</TargetName>
-    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
-    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
-    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
-    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
-  </PropertyGroup>
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Console</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Console</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Console</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Console</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-
-  <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\channel\channel_stack_builder_test.c">
-    </ClCompile>
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
-      <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
-    </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
-      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
-    </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
-      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
-    </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
-      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
-    </ProjectReference>
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="packages.config" />
-  </ItemGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-  <ImportGroup Label="ExtensionTargets">
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
-  </ImportGroup>
-  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
-    <PropertyGroup>
-      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
-    </PropertyGroup>
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
-  </Target>
-</Project>
-
diff --git a/vsprojects/vcxproj/test/grpc_channel_stack_builder_test/grpc_channel_stack_builder_test.vcxproj.filters b/vsprojects/vcxproj/test/grpc_channel_stack_builder_test/grpc_channel_stack_builder_test.vcxproj.filters
deleted file mode 100644
index 8cc2bc8..0000000
--- a/vsprojects/vcxproj/test/grpc_channel_stack_builder_test/grpc_channel_stack_builder_test.vcxproj.filters
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\channel\channel_stack_builder_test.c">
-      <Filter>test\core\channel</Filter>
-    </ClCompile>
-  </ItemGroup>
-
-  <ItemGroup>
-    <Filter Include="test">
-      <UniqueIdentifier>{bd69a85b-1f5c-2730-decd-705bb45f7ee7}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core">
-      <UniqueIdentifier>{431484ef-eda0-ac61-390d-0bd1840915e2}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core\channel">
-      <UniqueIdentifier>{ad0d36d9-6a99-139d-9f6d-95a3833a5085}</UniqueIdentifier>
-    </Filter>
-  </ItemGroup>
-</Project>
-